@@ -904,14 +904,14 @@ private predicate assocFunctionInfo(
904904
905905/**
906906 * 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
908908 * `pos` is `t`.
909909 *
910910 * `blanketPath` points to the type `blanketTypeParam` inside `t`, which
911911 * is the type parameter used in the blanket implementation.
912912 */
913913pragma [ nomagic]
914- private predicate functionInfoBlanket (
914+ private predicate functionInfoBlanketLike (
915915 Function f , string name , int arity , ImplItemNode impl , Trait trait , FunctionPosition pos ,
916916 AssocFunctionType t , TypePath blanketPath , TypeParam blanketTypeParam
917917) {
@@ -1030,19 +1030,20 @@ private module MethodResolution {
10301030
10311031 /**
10321032 * 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`
10341034 * parameter is `selfType`.
10351035 *
10361036 * `blanketPath` points to the type `blanketTypeParam` inside `selfType`, which
10371037 * is the type parameter used in the blanket implementation.
10381038 */
10391039 pragma [ nomagic]
1040- private predicate methodInfoBlanket (
1040+ private predicate methodInfoBlanketLike (
10411041 Method m , string name , int arity , ImplItemNode impl , Trait trait , AssocFunctionType selfType ,
10421042 TypePath blanketPath , TypeParam blanketTypeParam
10431043 ) {
10441044 exists ( FunctionPosition 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
10461047 pos .isSelf ( )
10471048 )
10481049 }
@@ -1116,8 +1117,8 @@ private module MethodResolution {
11161117 }
11171118
11181119 /**
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`.
11211122 *
11221123 * `blanketPath` points to the type `blanketTypeParam` inside `selfType`, which
11231124 * is the type parameter used in the blanket implementation.
@@ -1128,13 +1129,13 @@ private module MethodResolution {
11281129 */
11291130 bindingset [ mc]
11301131 pragma [ inline_late]
1131- private predicate methodCallBlanketCandidate (
1132+ private predicate methodCallBlanketLikeCandidate (
11321133 MethodCall mc , Method m , ImplItemNode impl , AssocFunctionType self , TypePath blanketPath ,
11331134 TypeParam blanketTypeParam
11341135 ) {
11351136 exists ( string name , int arity |
11361137 mc .hasNameAndArity ( name , arity ) and
1137- methodInfoBlanket ( m , name , arity , impl , _, self , blanketPath , blanketTypeParam )
1138+ methodInfoBlanketLike ( m , name , arity , impl , _, self , blanketPath , blanketTypeParam )
11381139 |
11391140 methodCallVisibleImplTraitCandidate ( mc , impl )
11401141 or
@@ -1219,6 +1220,23 @@ private module MethodResolution {
12191220 borrow ) , i , _)
12201221 }
12211222
1223+ /**
1224+ * Holds if the method inside blanket-like implementation `impl` 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 `derefChain` and `borrow` is incompatible with the `self`
1227+ * parameter type, or because the blanket constraint is not satisfied.
1228+ */
1229+ pragma [ nomagic]
1230+ private predicate hasIncompatibleBlanketLikeTarget (
1231+ ImplItemNode impl , string derefChain , boolean borrow
1232+ ) {
1233+ ReceiverIsNotInstantiationOfBlanketLikeSelfParam:: argIsNotInstantiationOf ( MkMethodCallCand ( this ,
1234+ derefChain , borrow ) , impl , _)
1235+ or
1236+ ReceiverSatisfiesBlanketLikeConstraint:: satisfiesNotBlanketConstraint ( MkMethodCallCand ( this ,
1237+ derefChain , borrow ) , impl )
1238+ }
1239+
12221240 /**
12231241 * Same as `getACandidateReceiverTypeAt`, but with traits substituted in for types
12241242 * with trait bounds.
@@ -1237,18 +1255,41 @@ private module MethodResolution {
12371255 isComplexRootStripped ( strippedTypePath , result )
12381256 }
12391257
1240- bindingset [ strippedTypePath , strippedType , derefChain , borrow ]
1241- private predicate hasNoCompatibleTargetCheck (
1258+ bindingset [ derefChain , borrow , strippedTypePath , strippedType ]
1259+ private predicate hasNoCompatibleNonBlanketLikeTargetCheck (
12421260 string derefChain , boolean borrow , TypePath strippedTypePath , Type strippedType
12431261 ) {
1244- // todo: also check that all blanket implementation candidates are incompatible
12451262 forall ( ImplOrTraitItemNode i |
12461263 methodCallNonBlanketCandidate ( this , _, i , _, strippedTypePath , strippedType )
12471264 |
12481265 this .hasIncompatibleTarget ( i , derefChain , borrow )
12491266 )
12501267 }
12511268
1269+ bindingset [ derefChain, borrow, strippedTypePath, strippedType]
1270+ private predicate hasNoCompatibleTargetCheck (
1271+ string derefChain , boolean borrow , TypePath strippedTypePath , Type strippedType
1272+ ) {
1273+ this .hasNoCompatibleNonBlanketLikeTargetCheck ( derefChain , borrow , strippedTypePath ,
1274+ strippedType ) and
1275+ forall ( ImplItemNode i | methodCallBlanketLikeCandidate ( this , _, i , _, _, _) |
1276+ this .hasIncompatibleBlanketLikeTarget ( i , derefChain , borrow )
1277+ )
1278+ }
1279+
1280+ bindingset [ derefChain, borrow, strippedTypePath, strippedType]
1281+ private predicate hasNoCompatibleNonBlanketTargetCheck (
1282+ string derefChain , boolean borrow , TypePath strippedTypePath , Type strippedType
1283+ ) {
1284+ this .hasNoCompatibleNonBlanketLikeTargetCheck ( derefChain , borrow , strippedTypePath ,
1285+ strippedType ) and
1286+ forall ( ImplItemNode i |
1287+ methodCallBlanketLikeCandidate ( this , _, i , _, _, _) and not i .isBlanketImplementation ( )
1288+ |
1289+ this .hasIncompatibleBlanketLikeTarget ( i , derefChain , borrow )
1290+ )
1291+ }
1292+
12521293 /**
12531294 * Holds if the candidate receiver type represented by `derefChain` does not
12541295 * have a matching method target.
@@ -1259,7 +1300,7 @@ private module MethodResolution {
12591300 this .supportsAutoDerefAndBorrow ( )
12601301 or
12611302 // needed for the `hasNoCompatibleTarget` check in
1262- // `SatisfiesBlanketConstraintInput ::hasBlanketCandidate`
1303+ // `ReceiverSatisfiesBlanketLikeConstraintInput ::hasBlanketCandidate`
12631304 derefChain = ""
12641305 ) and
12651306 exists ( TypePath strippedTypePath , Type strippedType |
@@ -1269,6 +1310,26 @@ private module MethodResolution {
12691310 )
12701311 }
12711312
1313+ /**
1314+ * Holds if the candidate receiver type represented by `derefChain` does not have
1315+ * a matching non-blanket method target.
1316+ */
1317+ pragma [ nomagic]
1318+ predicate hasNoCompatibleNonBlanketTargetNoBorrow ( string derefChain ) {
1319+ (
1320+ this .supportsAutoDerefAndBorrow ( )
1321+ or
1322+ // needed for the `hasNoCompatibleTarget` check in
1323+ // `ReceiverSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate`
1324+ derefChain = ""
1325+ ) and
1326+ exists ( TypePath strippedTypePath , Type strippedType |
1327+ not derefChain .matches ( "%.ref" ) and // no need to try a borrow if the last thing we did was a deref
1328+ strippedType = this .getComplexStrippedType ( derefChain , false , strippedTypePath ) and
1329+ this .hasNoCompatibleNonBlanketTargetCheck ( derefChain , false , strippedTypePath , strippedType )
1330+ )
1331+ }
1332+
12721333 /**
12731334 * Holds if the candidate receiver type represented by `derefChain`, followed
12741335 * by a borrow, does not have a matching method target.
@@ -1278,7 +1339,21 @@ private module MethodResolution {
12781339 exists ( TypePath strippedTypePath , Type strippedType |
12791340 this .hasNoCompatibleTargetNoBorrow ( derefChain ) and
12801341 strippedType = this .getComplexStrippedType ( derefChain , true , strippedTypePath ) and
1281- this .hasNoCompatibleTargetCheck ( derefChain , true , strippedTypePath , strippedType )
1342+ this .hasNoCompatibleNonBlanketLikeTargetCheck ( derefChain , true , strippedTypePath ,
1343+ strippedType )
1344+ )
1345+ }
1346+
1347+ /**
1348+ * Holds if the candidate receiver type represented by `derefChain`, followed
1349+ * by a borrow, does not have a matching non-blanket method target.
1350+ */
1351+ pragma [ nomagic]
1352+ predicate hasNoCompatibleNonBlanketTargetBorrow ( string derefChain ) {
1353+ exists ( TypePath strippedTypePath , Type strippedType |
1354+ this .hasNoCompatibleTargetNoBorrow ( derefChain ) and
1355+ strippedType = this .getComplexStrippedType ( derefChain , true , strippedTypePath ) and
1356+ this .hasNoCompatibleNonBlanketTargetCheck ( derefChain , true , strippedTypePath , strippedType )
12821357 )
12831358 }
12841359
@@ -1473,11 +1548,11 @@ private module MethodResolution {
14731548 }
14741549
14751550 pragma [ nomagic]
1476- predicate hasNoCompatibleTarget ( ) {
1477- mc_ .hasNoCompatibleTargetBorrow ( derefChain ) and
1551+ predicate hasNoCompatibleNonBlanketTarget ( ) {
1552+ mc_ .hasNoCompatibleNonBlanketTargetBorrow ( derefChain ) and
14781553 borrow = true
14791554 or
1480- mc_ .hasNoCompatibleTargetNoBorrow ( derefChain ) and
1555+ mc_ .hasNoCompatibleNonBlanketTargetNoBorrow ( derefChain ) and
14811556 borrow = false
14821557 }
14831558
@@ -1558,20 +1633,20 @@ private module MethodResolution {
15581633 Location getLocation ( ) { result = mc_ .getLocation ( ) }
15591634 }
15601635
1561- private module ReceiverSatisfiesBlanketConstraintInput implements
1636+ private module ReceiverSatisfiesBlanketLikeConstraintInput implements
15621637 BlanketImplementation:: SatisfiesBlanketConstraintInputSig< MethodCallCand >
15631638 {
15641639 pragma [ nomagic]
15651640 predicate hasBlanketCandidate (
15661641 MethodCallCand mcc , ImplItemNode impl , TypePath blanketPath , TypeParam blanketTypeParam
15671642 ) {
1568- exists ( MethodCall mc , string name , int arity |
1569- mcc . hasSignature ( mc , _ , _ , name , arity ) and
1570- methodCallBlanketCandidate ( mc , _, impl , _, blanketPath , blanketTypeParam ) and
1643+ exists ( MethodCall mc |
1644+ mc = mcc . getMethodCall ( ) and
1645+ methodCallBlanketLikeCandidate ( mc , _, impl , _, blanketPath , blanketTypeParam ) and
15711646 // Only apply blanket implementations when no other implementations are possible;
15721647 // this is to account for codebases that use the (unstable) specialization feature
15731648 // (https://rust-lang.github.io/rfcs/1210-impl-specialization.html)
1574- mcc .hasNoCompatibleTarget ( )
1649+ ( mcc .hasNoCompatibleNonBlanketTarget ( ) or not impl . isBlanketImplementation ( ) )
15751650 |
15761651 mcc .hasNoBorrow ( )
15771652 or
@@ -1580,9 +1655,9 @@ private module MethodResolution {
15801655 }
15811656 }
15821657
1583- private module ReceiverSatisfiesBlanketConstraint =
1658+ private module ReceiverSatisfiesBlanketLikeConstraint =
15841659 BlanketImplementation:: SatisfiesBlanketConstraint< MethodCallCand ,
1585- ReceiverSatisfiesBlanketConstraintInput > ;
1660+ ReceiverSatisfiesBlanketLikeConstraintInput > ;
15861661
15871662 /**
15881663 * A configuration for matching the type of a receiver against the type of
@@ -1603,8 +1678,8 @@ private module MethodResolution {
16031678 |
16041679 methodCallNonBlanketCandidate ( mc , m , i , selfType , strippedTypePath , strippedType )
16051680 or
1606- methodCallBlanketCandidate ( mc , m , i , selfType , _, _) and
1607- ReceiverSatisfiesBlanketConstraint :: satisfiesBlanketConstraint ( mcc , i )
1681+ methodCallBlanketLikeCandidate ( mc , m , i , selfType , _, _) and
1682+ ReceiverSatisfiesBlanketLikeConstraint :: satisfiesBlanketConstraint ( mcc , i )
16081683 )
16091684 }
16101685
@@ -1629,6 +1704,30 @@ private module MethodResolution {
16291704 private module ReceiverIsInstantiationOfSelfParam =
16301705 ArgIsInstantiationOf< MethodCallCand , ReceiverIsInstantiationOfSelfParamInput > ;
16311706
1707+ /**
1708+ * A configuration for anti-matching the type of a receiver against the type of
1709+ * a `self` parameter belonging to a blanket (like) implementation.
1710+ */
1711+ private module ReceiverIsNotInstantiationOfBlanketLikeSelfParamInput implements
1712+ IsInstantiationOfInputSig< MethodCallCand , AssocFunctionType >
1713+ {
1714+ pragma [ nomagic]
1715+ predicate potentialInstantiationOf (
1716+ MethodCallCand mcc , TypeAbstraction abs , AssocFunctionType constraint
1717+ ) {
1718+ methodCallBlanketLikeCandidate ( mcc .getMethodCall ( ) , _, abs , constraint , _, _) and
1719+ if abs .( Impl ) .hasTrait ( )
1720+ then
1721+ // inherent methods take precedence over trait methods, so only allow
1722+ // trait methods when there are no matching inherent methods
1723+ mcc .hasNoInherentTarget ( )
1724+ else any ( )
1725+ }
1726+ }
1727+
1728+ private module ReceiverIsNotInstantiationOfBlanketLikeSelfParam =
1729+ ArgIsInstantiationOf< MethodCallCand , ReceiverIsNotInstantiationOfBlanketLikeSelfParamInput > ;
1730+
16321731 /**
16331732 * A configuration for matching the type qualifier of a method call
16341733 * against the type being implemented in an `impl` block. For example,
@@ -1682,10 +1781,6 @@ private module MethodResolution {
16821781 ReceiverIsInstantiationOfSelfParamInput:: potentialInstantiationOf0 ( mcc , abs , constraint ) and
16831782 abs = any ( Impl i | not i .hasTrait ( ) )
16841783 }
1685-
1686- predicate relevantConstraint ( AssocFunctionType constraint ) {
1687- methodInfo ( _, _, _, _, constraint , _, _)
1688- }
16891784 }
16901785
16911786 private module ReceiverIsNotInstantiationOfInherentSelfParam =
@@ -1951,37 +2046,37 @@ private module NonMethodResolution {
19512046 }
19522047
19532048 pragma [ nomagic]
1954- private predicate functionInfoBlanketRelevantPos (
2049+ private predicate functionInfoBlanketLikeRelevantPos (
19552050 NonMethodFunction f , string name , int arity , ImplItemNode impl , Trait trait ,
19562051 FunctionPosition pos , AssocFunctionType t , TypePath blanketPath , TypeParam blanketTypeParam
19572052 ) {
1958- functionInfoBlanket ( f , name , arity , impl , trait , pos , t , blanketPath , blanketTypeParam ) and
2053+ functionInfoBlanketLike ( f , name , arity , impl , trait , pos , t , blanketPath , blanketTypeParam ) and
19592054 (
19602055 if pos .isReturn ( )
19612056 then
19622057 // We only check that the context of the call provides relevant type information
19632058 // when no argument can
19642059 not exists ( FunctionPosition pos0 |
1965- functionInfoBlanket ( f , name , arity , impl , trait , pos0 , _, _, _) and
2060+ functionInfoBlanketLike ( f , name , arity , impl , trait , pos0 , _, _, _) and
19662061 not pos0 .isReturn ( )
19672062 )
19682063 else any ( )
19692064 )
19702065 }
19712066
19722067 pragma [ nomagic]
1973- private predicate blanketCallTraitCandidate ( Element fc , Trait trait ) {
2068+ private predicate blanketLikeCallTraitCandidate ( Element fc , Trait trait ) {
19742069 exists ( string name , int arity |
19752070 fc .( NonMethodCall ) .hasNameAndArity ( name , arity ) and
1976- functionInfoBlanketRelevantPos ( _, name , arity , _, trait , _, _, _, _)
2071+ functionInfoBlanketLikeRelevantPos ( _, name , arity , _, trait , _, _, _, _)
19772072 |
19782073 not fc .( Call ) .hasTrait ( )
19792074 or
19802075 trait = fc .( Call ) .getTrait ( )
19812076 )
19822077 }
19832078
1984- private module BlanketTraitIsVisible = TraitIsVisible< blanketCallTraitCandidate / 2 > ;
2079+ private module BlanketTraitIsVisible = TraitIsVisible< blanketLikeCallTraitCandidate / 2 > ;
19852080
19862081 /** A (potential) non-method call, `f(x)`. */
19872082 final class NonMethodCall extends CallExpr {
@@ -2040,13 +2135,13 @@ private module NonMethodResolution {
20402135 }
20412136
20422137 pragma [ nomagic]
2043- predicate resolveCallTargetBlanketCandidate (
2138+ predicate resolveCallTargetBlanketLikeCandidate (
20442139 ImplItemNode impl , FunctionPosition pos , TypePath blanketPath , TypeParam blanketTypeParam
20452140 ) {
20462141 exists ( string name , int arity , Trait trait , AssocFunctionType t |
20472142 this .hasNameAndArity ( name , arity ) and
20482143 exists ( this .getTypeAt ( pos , blanketPath ) ) and
2049- functionInfoBlanketRelevantPos ( _, name , arity , impl , trait , pos , t , blanketPath ,
2144+ functionInfoBlanketLikeRelevantPos ( _, name , arity , impl , trait , pos , t , blanketPath ,
20502145 blanketTypeParam ) and
20512146 BlanketTraitIsVisible:: traitIsVisible ( this , trait )
20522147 )
@@ -2083,7 +2178,7 @@ private module NonMethodResolution {
20832178
20842179 private newtype TCallAndBlanketPos =
20852180 MkCallAndBlanketPos ( NonMethodCall fc , FunctionPosition pos ) {
2086- fc .resolveCallTargetBlanketCandidate ( _, pos , _, _)
2181+ fc .resolveCallTargetBlanketLikeCandidate ( _, pos , _, _)
20872182 }
20882183
20892184 /** A call tagged with a position. */
@@ -2109,7 +2204,7 @@ private module NonMethodResolution {
21092204 ) {
21102205 exists ( NonMethodCall fc , FunctionPosition pos |
21112206 fcp = MkCallAndBlanketPos ( fc , pos ) and
2112- fc .resolveCallTargetBlanketCandidate ( impl , pos , blanketPath , blanketTypeParam )
2207+ fc .resolveCallTargetBlanketLikeCandidate ( impl , pos , blanketPath , blanketTypeParam )
21132208 )
21142209 }
21152210 }
@@ -2132,12 +2227,12 @@ private module NonMethodResolution {
21322227 exists ( FunctionPosition pos |
21332228 ArgSatisfiesBlanketConstraint:: satisfiesBlanketConstraint ( fcp , abs ) and
21342229 fcp = MkCallAndBlanketPos ( _, pos ) and
2135- functionInfoBlanketRelevantPos ( _, _, _, abs , _, pos , constraint , _, _)
2230+ functionInfoBlanketLikeRelevantPos ( _, _, _, abs , _, pos , constraint , _, _)
21362231 )
21372232 }
21382233
21392234 predicate relevantConstraint ( AssocFunctionType constraint ) {
2140- functionInfoBlanketRelevantPos ( _, _, _, _, _, _, constraint , _, _)
2235+ functionInfoBlanketLikeRelevantPos ( _, _, _, _, _, _, constraint , _, _)
21412236 }
21422237 }
21432238
0 commit comments