@@ -904,14 +904,14 @@ private predicate assocFunctionInfo(
904
904
905
905
/**
906
906
* Holds if function `f` with the name `name` and the arity `arity` exists in
907
- * blanket implementation `impl` of `trait`, and the type at position
907
+ * blanket (like) implementation `impl` of `trait`, and the type at position
908
908
* `pos` is `t`.
909
909
*
910
910
* `blanketPath` points to the type `blanketTypeParam` inside `t`, which
911
911
* is the type parameter used in the blanket implementation.
912
912
*/
913
913
pragma [ nomagic]
914
- private predicate functionInfoBlanket (
914
+ private predicate functionInfoBlanketLike (
915
915
Function f , string name , int arity , ImplItemNode impl , Trait trait , FunctionTypePosition pos ,
916
916
AssocFunctionType t , TypePath blanketPath , TypeParam blanketTypeParam
917
917
) {
@@ -1030,19 +1030,20 @@ private module MethodResolution {
1030
1030
1031
1031
/**
1032
1032
* Holds if method `m` with the name `name` and the arity `arity` exists in
1033
- * blanket implementation `impl` of `trait`, and the type of the `self`
1033
+ * blanket (like) implementation `impl` of `trait`, and the type of the `self`
1034
1034
* parameter is `selfType`.
1035
1035
*
1036
1036
* `blanketPath` points to the type `blanketTypeParam` inside `selfType`, which
1037
1037
* is the type parameter used in the blanket implementation.
1038
1038
*/
1039
1039
pragma [ nomagic]
1040
- private predicate methodInfoBlanket (
1040
+ private predicate methodInfoBlanketLike (
1041
1041
Method m , string name , int arity , ImplItemNode impl , Trait trait , AssocFunctionType selfType ,
1042
1042
TypePath blanketPath , TypeParam blanketTypeParam
1043
1043
) {
1044
1044
exists ( FunctionTypePosition pos |
1045
- functionInfoBlanket ( m , name , arity , impl , trait , pos , selfType , blanketPath , blanketTypeParam ) and
1045
+ functionInfoBlanketLike ( m , name , arity , impl , trait , pos , selfType , blanketPath ,
1046
+ blanketTypeParam ) and
1046
1047
pos .isSelf ( )
1047
1048
)
1048
1049
}
@@ -1116,8 +1117,8 @@ private module MethodResolution {
1116
1117
}
1117
1118
1118
1119
/**
1119
- * Holds if method call `mc` may target a method in blanket implementation `i`
1120
- * with `self` parameter having type `selfType`.
1120
+ * Holds if method call `mc` may target a method in blanket (like) implementation
1121
+ * `impl` with `self` parameter having type `selfType`.
1121
1122
*
1122
1123
* `blanketPath` points to the type `blanketTypeParam` inside `selfType`, which
1123
1124
* is the type parameter used in the blanket implementation.
@@ -1128,13 +1129,13 @@ private module MethodResolution {
1128
1129
*/
1129
1130
bindingset [ mc]
1130
1131
pragma [ inline_late]
1131
- private predicate methodCallBlanketCandidate (
1132
+ private predicate methodCallBlanketLikeCandidate (
1132
1133
MethodCall mc , Method m , ImplItemNode impl , AssocFunctionType self , TypePath blanketPath ,
1133
1134
TypeParam blanketTypeParam
1134
1135
) {
1135
1136
exists ( string name , int arity |
1136
1137
mc .hasNameAndArity ( name , arity ) and
1137
- methodInfoBlanket ( m , name , arity , impl , _, self , blanketPath , blanketTypeParam )
1138
+ methodInfoBlanketLike ( m , name , arity , impl , _, self , blanketPath , blanketTypeParam )
1138
1139
|
1139
1140
methodCallVisibleImplTraitCandidate ( mc , impl )
1140
1141
or
@@ -1190,7 +1191,7 @@ private module MethodResolution {
1190
1191
or
1191
1192
this .supportsAutoDerefAndBorrow ( ) and
1192
1193
exists ( TypePath path0 , Type t0 , string derefChain0 |
1193
- this .hasNoCompatibleTarget ( derefChain0 , _) and
1194
+ this .hasNoCompatibleTargetBorrow ( derefChain0 , _) and
1194
1195
t0 = this .getACandidateReceiverTypeAtNoBorrow ( path0 , derefChain0 )
1195
1196
|
1196
1197
path0 .isCons ( TRefTypeParameter ( ) , path ) and
@@ -1219,6 +1220,21 @@ private module MethodResolution {
1219
1220
derefChainBorrow = ";"
1220
1221
}
1221
1222
1223
+ /**
1224
+ * Holds if the method inside blanket-like implementation `i` with matching name
1225
+ * and arity can be ruled out as a target of this call, either because the candidate
1226
+ * receiver type represented by `derefChainBorrow` is incompatible with the `self`
1227
+ * parameter type, or because the blanket constraint is not satisfied.
1228
+ */
1229
+ pragma [ nomagic]
1230
+ private predicate hasIncompatibleBlanketLikeTarget ( ImplItemNode i , string derefChainBorrow ) {
1231
+ ReceiverIsNotInstantiationOfBlanketLikeSelfParam:: argIsNotInstantiationOf ( MkMethodCallCand ( this ,
1232
+ derefChainBorrow ) , i , _)
1233
+ or
1234
+ ReceiverSatisfiesBlanketLikeConstraint:: satisfiesNotBlanketConstraint ( MkMethodCallCand ( this ,
1235
+ derefChainBorrow ) , i )
1236
+ }
1237
+
1222
1238
/**
1223
1239
* Same as `getACandidateReceiverTypeAt`, but with traits substituted in for types
1224
1240
* with trait bounds.
@@ -1236,10 +1252,9 @@ private module MethodResolution {
1236
1252
}
1237
1253
1238
1254
bindingset [ strippedTypePath, strippedType, derefChainBorrow]
1239
- private predicate hasNoCompatibleTargetCheck (
1255
+ private predicate hasNoCompatibleNonBlanketLikeTargetCheck (
1240
1256
TypePath strippedTypePath , Type strippedType , string derefChainBorrow
1241
1257
) {
1242
- // todo: also check that all blanket implementation candidates are incompatible
1243
1258
forall ( ImplOrTraitItemNode i |
1244
1259
methodCallNonBlanketCandidate ( this , _, i , _, strippedTypePath , strippedType )
1245
1260
or
@@ -1249,6 +1264,28 @@ private module MethodResolution {
1249
1264
)
1250
1265
}
1251
1266
1267
+ bindingset [ strippedTypePath, strippedType, derefChainBorrow]
1268
+ private predicate hasNoCompatibleTargetCheck (
1269
+ TypePath strippedTypePath , Type strippedType , string derefChainBorrow
1270
+ ) {
1271
+ this .hasNoCompatibleNonBlanketLikeTargetCheck ( strippedTypePath , strippedType , derefChainBorrow ) and
1272
+ forall ( ImplItemNode i | methodCallBlanketLikeCandidate ( this , _, i , _, _, _) |
1273
+ this .hasIncompatibleBlanketLikeTarget ( i , derefChainBorrow )
1274
+ )
1275
+ }
1276
+
1277
+ bindingset [ strippedTypePath, strippedType, derefChainBorrow]
1278
+ private predicate hasNoCompatibleNonBlanketTargetCheck (
1279
+ TypePath strippedTypePath , Type strippedType , string derefChainBorrow
1280
+ ) {
1281
+ this .hasNoCompatibleNonBlanketLikeTargetCheck ( strippedTypePath , strippedType , derefChainBorrow ) and
1282
+ forall ( ImplItemNode i |
1283
+ methodCallBlanketLikeCandidate ( this , _, i , _, _, _) and not i .isBlanketImplementation ( )
1284
+ |
1285
+ this .hasIncompatibleBlanketLikeTarget ( i , derefChainBorrow )
1286
+ )
1287
+ }
1288
+
1252
1289
/**
1253
1290
* Holds if the candidate receiver type represented by
1254
1291
* `derefChainBorrow = derefChain;` does not have a matching method target.
@@ -1259,7 +1296,7 @@ private module MethodResolution {
1259
1296
this .supportsAutoDerefAndBorrow ( )
1260
1297
or
1261
1298
// needed for the `hasNoCompatibleTarget` check in
1262
- // `SatisfiesBlanketConstraintInput ::hasBlanketCandidate`
1299
+ // `ReceiverSatisfiesBlanketLikeConstraintInput ::hasBlanketCandidate`
1263
1300
derefChain = ""
1264
1301
) and
1265
1302
exists ( TypePath strippedTypePath , Type strippedType |
@@ -1270,13 +1307,35 @@ private module MethodResolution {
1270
1307
)
1271
1308
}
1272
1309
1310
+ /**
1311
+ * Holds if the candidate receiver type represented by
1312
+ * `derefChainBorrow = derefChain;` does not have a matching non-blanket
1313
+ * method target.
1314
+ */
1315
+ pragma [ nomagic]
1316
+ predicate hasNoCompatibleNonBlanketTargetNoBorrow ( string derefChain , string derefChainBorrow ) {
1317
+ (
1318
+ this .supportsAutoDerefAndBorrow ( )
1319
+ or
1320
+ // needed for the `hasNoCompatibleTarget` check in
1321
+ // `ReceiverSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate`
1322
+ derefChain = ""
1323
+ ) and
1324
+ exists ( TypePath strippedTypePath , Type strippedType |
1325
+ derefChainBorrow = derefChain + ";" and
1326
+ not derefChain .matches ( "%.ref" ) and // no need to try a borrow if the last thing we did was a deref
1327
+ strippedType = this .getComplexStrippedType ( strippedTypePath , derefChainBorrow ) and
1328
+ this .hasNoCompatibleNonBlanketTargetCheck ( strippedTypePath , strippedType , derefChainBorrow )
1329
+ )
1330
+ }
1331
+
1273
1332
/**
1274
1333
* Holds if the candidate receiver type represented by
1275
1334
* `derefChainBorrow = derefChain;borrow` does not have a matching method
1276
1335
* target.
1277
1336
*/
1278
1337
pragma [ nomagic]
1279
- predicate hasNoCompatibleTarget ( string derefChain , string derefChainBorrow ) {
1338
+ predicate hasNoCompatibleTargetBorrow ( string derefChain , string derefChainBorrow ) {
1280
1339
exists ( TypePath strippedTypePath , Type strippedType |
1281
1340
derefChainBorrow = derefChain + ";borrow" and
1282
1341
this .hasNoCompatibleTargetNoBorrow ( derefChain , _) and
@@ -1285,6 +1344,21 @@ private module MethodResolution {
1285
1344
)
1286
1345
}
1287
1346
1347
+ /**
1348
+ * Holds if the candidate receiver type represented by
1349
+ * `derefChainBorrow = derefChain;borrow` does not have a matching non-blanket
1350
+ * method target.
1351
+ */
1352
+ pragma [ nomagic]
1353
+ predicate hasNoCompatibleNonBlanketTargetBorrow ( string derefChain , string derefChainBorrow ) {
1354
+ exists ( TypePath strippedTypePath , Type strippedType |
1355
+ derefChainBorrow = derefChain + ";borrow" and
1356
+ this .hasNoCompatibleTargetNoBorrow ( derefChain , _) and
1357
+ strippedType = this .getComplexStrippedType ( strippedTypePath , derefChainBorrow ) and
1358
+ this .hasNoCompatibleNonBlanketTargetCheck ( strippedTypePath , strippedType , derefChainBorrow )
1359
+ )
1360
+ }
1361
+
1288
1362
/**
1289
1363
* Gets a [candidate receiver type][1] of this method call at `path`.
1290
1364
*
@@ -1477,10 +1551,10 @@ private module MethodResolution {
1477
1551
}
1478
1552
1479
1553
pragma [ nomagic]
1480
- predicate hasNoCompatibleTarget ( ) {
1481
- mc_ .hasNoCompatibleTarget ( _, derefChainBorrow )
1554
+ predicate hasNoCompatibleNonBlanketTarget ( ) {
1555
+ mc_ .hasNoCompatibleNonBlanketTargetBorrow ( _, derefChainBorrow )
1482
1556
or
1483
- mc_ .hasNoCompatibleTargetNoBorrow ( _, derefChainBorrow )
1557
+ mc_ .hasNoCompatibleNonBlanketTargetNoBorrow ( _, derefChainBorrow )
1484
1558
}
1485
1559
1486
1560
pragma [ nomagic]
@@ -1563,20 +1637,20 @@ private module MethodResolution {
1563
1637
Location getLocation ( ) { result = mc_ .getLocation ( ) }
1564
1638
}
1565
1639
1566
- private module ReceiverSatisfiesBlanketConstraintInput implements
1640
+ private module ReceiverSatisfiesBlanketLikeConstraintInput implements
1567
1641
BlanketImplementation:: SatisfiesBlanketConstraintInputSig< MethodCallCand >
1568
1642
{
1569
1643
pragma [ nomagic]
1570
1644
predicate hasBlanketCandidate (
1571
1645
MethodCallCand mcc , ImplItemNode impl , TypePath blanketPath , TypeParam blanketTypeParam
1572
1646
) {
1573
- exists ( MethodCall mc , string name , int arity |
1574
- mcc . hasSignature ( mc , _ , _ , name , arity ) and
1575
- methodCallBlanketCandidate ( mc , _, impl , _, blanketPath , blanketTypeParam ) and
1647
+ exists ( MethodCall mc |
1648
+ mc = mcc . getMethodCall ( ) and
1649
+ methodCallBlanketLikeCandidate ( mc , _, impl , _, blanketPath , blanketTypeParam ) and
1576
1650
// Only apply blanket implementations when no other implementations are possible;
1577
1651
// this is to account for codebases that use the (unstable) specialization feature
1578
1652
// (https://rust-lang.github.io/rfcs/1210-impl-specialization.html)
1579
- mcc .hasNoCompatibleTarget ( )
1653
+ ( mcc .hasNoCompatibleNonBlanketTarget ( ) or not impl . isBlanketImplementation ( ) )
1580
1654
|
1581
1655
mcc .hasNoBorrow ( )
1582
1656
or
@@ -1585,9 +1659,9 @@ private module MethodResolution {
1585
1659
}
1586
1660
}
1587
1661
1588
- private module ReceiverSatisfiesBlanketConstraint =
1662
+ private module ReceiverSatisfiesBlanketLikeConstraint =
1589
1663
BlanketImplementation:: SatisfiesBlanketConstraint< MethodCallCand ,
1590
- ReceiverSatisfiesBlanketConstraintInput > ;
1664
+ ReceiverSatisfiesBlanketLikeConstraintInput > ;
1591
1665
1592
1666
/**
1593
1667
* A configuration for matching the type of a receiver against the type of
@@ -1608,8 +1682,8 @@ private module MethodResolution {
1608
1682
|
1609
1683
methodCallNonBlanketCandidate ( mc , m , i , selfType , strippedTypePath , strippedType )
1610
1684
or
1611
- methodCallBlanketCandidate ( mc , m , i , selfType , _, _) and
1612
- ReceiverSatisfiesBlanketConstraint :: satisfiesBlanketConstraint ( mcc , i )
1685
+ methodCallBlanketLikeCandidate ( mc , m , i , selfType , _, _) and
1686
+ ReceiverSatisfiesBlanketLikeConstraint :: satisfiesBlanketConstraint ( mcc , i )
1613
1687
)
1614
1688
}
1615
1689
@@ -1634,6 +1708,30 @@ private module MethodResolution {
1634
1708
private module ReceiverIsInstantiationOfSelfParam =
1635
1709
ArgIsInstantiationOf< MethodCallCand , ReceiverIsInstantiationOfSelfParamInput > ;
1636
1710
1711
+ /**
1712
+ * A configuration for anti-matching the type of a receiver against the type of
1713
+ * a `self` parameter belonging to a blanket (like) implementation.
1714
+ */
1715
+ private module ReceiverIsNotInstantiationOfBlanketLikeSelfParamInput implements
1716
+ IsInstantiationOfInputSig< MethodCallCand , AssocFunctionType >
1717
+ {
1718
+ pragma [ nomagic]
1719
+ predicate potentialInstantiationOf (
1720
+ MethodCallCand mcc , TypeAbstraction abs , AssocFunctionType constraint
1721
+ ) {
1722
+ methodCallBlanketLikeCandidate ( mcc .getMethodCall ( ) , _, abs , constraint , _, _) and
1723
+ if abs .( Impl ) .hasTrait ( )
1724
+ then
1725
+ // inherent methods take precedence over trait methods, so only allow
1726
+ // trait methods when there are no matching inherent methods
1727
+ mcc .hasNoInherentTarget ( )
1728
+ else any ( )
1729
+ }
1730
+ }
1731
+
1732
+ private module ReceiverIsNotInstantiationOfBlanketLikeSelfParam =
1733
+ ArgIsInstantiationOf< MethodCallCand , ReceiverIsNotInstantiationOfBlanketLikeSelfParamInput > ;
1734
+
1637
1735
/**
1638
1736
* A configuration for matching the type qualifier of a method call
1639
1737
* against the type being implemented in an `impl` block. For example,
@@ -1687,10 +1785,6 @@ private module MethodResolution {
1687
1785
ReceiverIsInstantiationOfSelfParamInput:: potentialInstantiationOf0 ( mcc , abs , constraint ) and
1688
1786
abs = any ( Impl i | not i .hasTrait ( ) )
1689
1787
}
1690
-
1691
- predicate relevantConstraint ( AssocFunctionType constraint ) {
1692
- methodInfo ( _, _, _, _, constraint , _, _)
1693
- }
1694
1788
}
1695
1789
1696
1790
private module ReceiverIsNotInstantiationOfInherentSelfParam =
@@ -1946,18 +2040,18 @@ private module NonMethodResolution {
1946
2040
}
1947
2041
1948
2042
pragma [ nomagic]
1949
- private predicate functionInfoBlanketRelevantPos (
2043
+ private predicate functionInfoBlanketLikeRelevantPos (
1950
2044
NonMethodFunction f , string name , int arity , ImplItemNode impl , Trait trait ,
1951
2045
FunctionTypePosition pos , AssocFunctionType t , TypePath blanketPath , TypeParam blanketTypeParam
1952
2046
) {
1953
- functionInfoBlanket ( f , name , arity , impl , trait , pos , t , blanketPath , blanketTypeParam ) and
2047
+ functionInfoBlanketLike ( f , name , arity , impl , trait , pos , t , blanketPath , blanketTypeParam ) and
1954
2048
(
1955
2049
not pos .isReturn ( )
1956
2050
or
1957
2051
// We only check that the context of the call provides relevant type information
1958
2052
// when no argument can
1959
2053
not exists ( FunctionTypePosition pos0 |
1960
- functionInfoBlanket ( f , name , arity , impl , trait , pos0 , _, _, _) and
2054
+ functionInfoBlanketLike ( f , name , arity , impl , trait , pos0 , _, _, _) and
1961
2055
not pos0 .isReturn ( )
1962
2056
)
1963
2057
)
@@ -1967,7 +2061,7 @@ private module NonMethodResolution {
1967
2061
private predicate blanketCallTraitCandidate ( Element fc , Trait trait ) {
1968
2062
exists ( string name , int arity |
1969
2063
fc .( NonMethodCall ) .hasNameAndArity ( name , arity ) and
1970
- functionInfoBlanketRelevantPos ( _, name , arity , _, trait , _, _, _, _)
2064
+ functionInfoBlanketLikeRelevantPos ( _, name , arity , _, trait , _, _, _, _)
1971
2065
|
1972
2066
not fc .( Call ) .hasTrait ( )
1973
2067
or
@@ -2040,7 +2134,7 @@ private module NonMethodResolution {
2040
2134
exists ( string name , int arity , Trait trait , AssocFunctionType t |
2041
2135
this .hasNameAndArity ( name , arity ) and
2042
2136
exists ( this .getTypeAt ( pos , blanketPath ) ) and
2043
- functionInfoBlanketRelevantPos ( _, name , arity , impl , trait , pos , t , blanketPath ,
2137
+ functionInfoBlanketLikeRelevantPos ( _, name , arity , impl , trait , pos , t , blanketPath ,
2044
2138
blanketTypeParam ) and
2045
2139
BlanketTraitIsVisible:: traitIsVisible ( this , trait )
2046
2140
)
@@ -2126,12 +2220,12 @@ private module NonMethodResolution {
2126
2220
exists ( FunctionTypePosition pos |
2127
2221
ArgSatisfiesBlanketConstraint:: satisfiesBlanketConstraint ( fcp , abs ) and
2128
2222
fcp = MkCallAndBlanketPos ( _, pos ) and
2129
- functionInfoBlanketRelevantPos ( _, _, _, abs , _, pos , constraint , _, _)
2223
+ functionInfoBlanketLikeRelevantPos ( _, _, _, abs , _, pos , constraint , _, _)
2130
2224
)
2131
2225
}
2132
2226
2133
2227
predicate relevantConstraint ( AssocFunctionType constraint ) {
2134
- functionInfoBlanketRelevantPos ( _, _, _, _, _, _, constraint , _, _)
2228
+ functionInfoBlanketLikeRelevantPos ( _, _, _, _, _, _, constraint , _, _)
2135
2229
}
2136
2230
}
2137
2231
0 commit comments