@@ -901,14 +901,14 @@ private predicate assocFunctionInfo(
901901
902902/**
903903 * Holds if function `f` with the name `name` and the arity `arity` exists in
904- * blanket implementation `impl` of `trait`, and the type at position
904+ * blanket (like) implementation `impl` of `trait`, and the type at position
905905 * `pos` is `t`.
906906 *
907907 * `blanketPath` points to the type `blanketTypeParam` inside `t`, which
908908 * is the type parameter used in the blanket implementation.
909909 */
910910pragma [ nomagic]
911- private predicate functionInfoBlanket (
911+ private predicate functionInfoBlanketLike (
912912 Function f , string name , int arity , ImplItemNode impl , Trait trait , FunctionPosition pos ,
913913 AssocFunctionType t , TypePath blanketPath , TypeParam blanketTypeParam
914914) {
@@ -1027,19 +1027,20 @@ private module MethodResolution {
10271027
10281028 /**
10291029 * Holds if method `m` with the name `name` and the arity `arity` exists in
1030- * blanket implementation `impl` of `trait`, and the type of the `self`
1030+ * blanket (like) implementation `impl` of `trait`, and the type of the `self`
10311031 * parameter is `selfType`.
10321032 *
10331033 * `blanketPath` points to the type `blanketTypeParam` inside `selfType`, which
10341034 * is the type parameter used in the blanket implementation.
10351035 */
10361036 pragma [ nomagic]
1037- private predicate methodInfoBlanket (
1037+ private predicate methodInfoBlanketLike (
10381038 Method m , string name , int arity , ImplItemNode impl , Trait trait , AssocFunctionType selfType ,
10391039 TypePath blanketPath , TypeParam blanketTypeParam
10401040 ) {
10411041 exists ( FunctionPosition pos |
1042- functionInfoBlanket ( m , name , arity , impl , trait , pos , selfType , blanketPath , blanketTypeParam ) and
1042+ functionInfoBlanketLike ( m , name , arity , impl , trait , pos , selfType , blanketPath ,
1043+ blanketTypeParam ) and
10431044 pos .isSelf ( )
10441045 )
10451046 }
@@ -1113,8 +1114,8 @@ private module MethodResolution {
11131114 }
11141115
11151116 /**
1116- * Holds if method call `mc` may target a method in blanket implementation `i`
1117- * with `self` parameter having type `selfType`.
1117+ * Holds if method call `mc` may target a method in blanket (like) implementation
1118+ * `impl` with `self` parameter having type `selfType`.
11181119 *
11191120 * `blanketPath` points to the type `blanketTypeParam` inside `selfType`, which
11201121 * is the type parameter used in the blanket implementation.
@@ -1125,13 +1126,13 @@ private module MethodResolution {
11251126 */
11261127 bindingset [ mc]
11271128 pragma [ inline_late]
1128- private predicate methodCallBlanketCandidate (
1129+ private predicate methodCallBlanketLikeCandidate (
11291130 MethodCall mc , Method m , ImplItemNode impl , AssocFunctionType self , TypePath blanketPath ,
11301131 TypeParam blanketTypeParam
11311132 ) {
11321133 exists ( string name , int arity |
11331134 mc .hasNameAndArity ( name , arity ) and
1134- methodInfoBlanket ( m , name , arity , impl , _, self , blanketPath , blanketTypeParam )
1135+ methodInfoBlanketLike ( m , name , arity , impl , _, self , blanketPath , blanketTypeParam )
11351136 |
11361137 methodCallVisibleImplTraitCandidate ( mc , impl )
11371138 or
@@ -1216,6 +1217,23 @@ private module MethodResolution {
12161217 borrow ) , i , _)
12171218 }
12181219
1220+ /**
1221+ * Holds if the method inside blanket-like implementation `impl` with matching name
1222+ * and arity can be ruled out as a target of this call, either because the candidate
1223+ * receiver type represented by `derefChain` and `borrow` is incompatible with the `self`
1224+ * parameter type, or because the blanket constraint is not satisfied.
1225+ */
1226+ pragma [ nomagic]
1227+ private predicate hasIncompatibleBlanketLikeTarget (
1228+ ImplItemNode impl , string derefChain , boolean borrow
1229+ ) {
1230+ ReceiverIsNotInstantiationOfBlanketLikeSelfParam:: argIsNotInstantiationOf ( MkMethodCallCand ( this ,
1231+ derefChain , borrow ) , impl , _)
1232+ or
1233+ ReceiverSatisfiesBlanketLikeConstraint:: satisfiesNotBlanketConstraint ( MkMethodCallCand ( this ,
1234+ derefChain , borrow ) , impl )
1235+ }
1236+
12191237 /**
12201238 * Same as `getACandidateReceiverTypeAt`, but with traits substituted in for types
12211239 * with trait bounds.
@@ -1234,18 +1252,41 @@ private module MethodResolution {
12341252 isComplexRootStripped ( strippedTypePath , result )
12351253 }
12361254
1237- bindingset [ strippedTypePath , strippedType , derefChain , borrow ]
1238- private predicate hasNoCompatibleTargetCheck (
1255+ bindingset [ derefChain , borrow , strippedTypePath , strippedType ]
1256+ private predicate hasNoCompatibleNonBlanketLikeTargetCheck (
12391257 string derefChain , boolean borrow , TypePath strippedTypePath , Type strippedType
12401258 ) {
1241- // todo: also check that all blanket implementation candidates are incompatible
12421259 forall ( ImplOrTraitItemNode i |
12431260 methodCallNonBlanketCandidate ( this , _, i , _, strippedTypePath , strippedType )
12441261 |
12451262 this .hasIncompatibleTarget ( i , derefChain , borrow )
12461263 )
12471264 }
12481265
1266+ bindingset [ derefChain, borrow, strippedTypePath, strippedType]
1267+ private predicate hasNoCompatibleTargetCheck (
1268+ string derefChain , boolean borrow , TypePath strippedTypePath , Type strippedType
1269+ ) {
1270+ this .hasNoCompatibleNonBlanketLikeTargetCheck ( derefChain , borrow , strippedTypePath ,
1271+ strippedType ) and
1272+ forall ( ImplItemNode i | methodCallBlanketLikeCandidate ( this , _, i , _, _, _) |
1273+ this .hasIncompatibleBlanketLikeTarget ( i , derefChain , borrow )
1274+ )
1275+ }
1276+
1277+ bindingset [ derefChain, borrow, strippedTypePath, strippedType]
1278+ private predicate hasNoCompatibleNonBlanketTargetCheck (
1279+ string derefChain , boolean borrow , TypePath strippedTypePath , Type strippedType
1280+ ) {
1281+ this .hasNoCompatibleNonBlanketLikeTargetCheck ( derefChain , borrow , strippedTypePath ,
1282+ strippedType ) and
1283+ forall ( ImplItemNode i |
1284+ methodCallBlanketLikeCandidate ( this , _, i , _, _, _) and not i .isBlanketImplementation ( )
1285+ |
1286+ this .hasIncompatibleBlanketLikeTarget ( i , derefChain , borrow )
1287+ )
1288+ }
1289+
12491290 /**
12501291 * Holds if the candidate receiver type represented by `derefChain` does not
12511292 * have a matching method target.
@@ -1256,7 +1297,7 @@ private module MethodResolution {
12561297 this .supportsAutoDerefAndBorrow ( )
12571298 or
12581299 // needed for the `hasNoCompatibleTarget` check in
1259- // `SatisfiesBlanketConstraintInput ::hasBlanketCandidate`
1300+ // `ReceiverSatisfiesBlanketLikeConstraintInput ::hasBlanketCandidate`
12601301 derefChain = ""
12611302 ) and
12621303 exists ( TypePath strippedTypePath , Type strippedType |
@@ -1266,6 +1307,26 @@ private module MethodResolution {
12661307 )
12671308 }
12681309
1310+ /**
1311+ * Holds if the candidate receiver type represented by `derefChain` does not have
1312+ * a matching non-blanket method target.
1313+ */
1314+ pragma [ nomagic]
1315+ predicate hasNoCompatibleNonBlanketTargetNoBorrow ( string derefChain ) {
1316+ (
1317+ this .supportsAutoDerefAndBorrow ( )
1318+ or
1319+ // needed for the `hasNoCompatibleTarget` check in
1320+ // `ReceiverSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate`
1321+ derefChain = ""
1322+ ) and
1323+ exists ( TypePath strippedTypePath , Type strippedType |
1324+ not derefChain .matches ( "%.ref" ) and // no need to try a borrow if the last thing we did was a deref
1325+ strippedType = this .getComplexStrippedType ( derefChain , false , strippedTypePath ) and
1326+ this .hasNoCompatibleNonBlanketTargetCheck ( derefChain , false , strippedTypePath , strippedType )
1327+ )
1328+ }
1329+
12691330 /**
12701331 * Holds if the candidate receiver type represented by `derefChain`, followed
12711332 * by a borrow, does not have a matching method target.
@@ -1275,7 +1336,21 @@ private module MethodResolution {
12751336 exists ( TypePath strippedTypePath , Type strippedType |
12761337 this .hasNoCompatibleTargetNoBorrow ( derefChain ) and
12771338 strippedType = this .getComplexStrippedType ( derefChain , true , strippedTypePath ) and
1278- this .hasNoCompatibleTargetCheck ( derefChain , true , strippedTypePath , strippedType )
1339+ this .hasNoCompatibleNonBlanketLikeTargetCheck ( derefChain , true , strippedTypePath ,
1340+ strippedType )
1341+ )
1342+ }
1343+
1344+ /**
1345+ * Holds if the candidate receiver type represented by `derefChain`, followed
1346+ * by a borrow, does not have a matching non-blanket method target.
1347+ */
1348+ pragma [ nomagic]
1349+ predicate hasNoCompatibleNonBlanketTargetBorrow ( string derefChain ) {
1350+ exists ( TypePath strippedTypePath , Type strippedType |
1351+ this .hasNoCompatibleTargetNoBorrow ( derefChain ) and
1352+ strippedType = this .getComplexStrippedType ( derefChain , true , strippedTypePath ) and
1353+ this .hasNoCompatibleNonBlanketTargetCheck ( derefChain , true , strippedTypePath , strippedType )
12791354 )
12801355 }
12811356
@@ -1470,11 +1545,11 @@ private module MethodResolution {
14701545 }
14711546
14721547 pragma [ nomagic]
1473- predicate hasNoCompatibleTarget ( ) {
1474- mc_ .hasNoCompatibleTargetBorrow ( derefChain ) and
1548+ predicate hasNoCompatibleNonBlanketTarget ( ) {
1549+ mc_ .hasNoCompatibleNonBlanketTargetBorrow ( derefChain ) and
14751550 borrow = true
14761551 or
1477- mc_ .hasNoCompatibleTargetNoBorrow ( derefChain ) and
1552+ mc_ .hasNoCompatibleNonBlanketTargetNoBorrow ( derefChain ) and
14781553 borrow = false
14791554 }
14801555
@@ -1555,20 +1630,20 @@ private module MethodResolution {
15551630 Location getLocation ( ) { result = mc_ .getLocation ( ) }
15561631 }
15571632
1558- private module ReceiverSatisfiesBlanketConstraintInput implements
1633+ private module ReceiverSatisfiesBlanketLikeConstraintInput implements
15591634 BlanketImplementation:: SatisfiesBlanketConstraintInputSig< MethodCallCand >
15601635 {
15611636 pragma [ nomagic]
15621637 predicate hasBlanketCandidate (
15631638 MethodCallCand mcc , ImplItemNode impl , TypePath blanketPath , TypeParam blanketTypeParam
15641639 ) {
1565- exists ( MethodCall mc , string name , int arity |
1566- mcc . hasSignature ( mc , _ , _ , name , arity ) and
1567- methodCallBlanketCandidate ( mc , _, impl , _, blanketPath , blanketTypeParam ) and
1640+ exists ( MethodCall mc |
1641+ mc = mcc . getMethodCall ( ) and
1642+ methodCallBlanketLikeCandidate ( mc , _, impl , _, blanketPath , blanketTypeParam ) and
15681643 // Only apply blanket implementations when no other implementations are possible;
15691644 // this is to account for codebases that use the (unstable) specialization feature
15701645 // (https://rust-lang.github.io/rfcs/1210-impl-specialization.html)
1571- mcc .hasNoCompatibleTarget ( )
1646+ ( mcc .hasNoCompatibleNonBlanketTarget ( ) or not impl . isBlanketImplementation ( ) )
15721647 |
15731648 mcc .hasNoBorrow ( )
15741649 or
@@ -1577,9 +1652,9 @@ private module MethodResolution {
15771652 }
15781653 }
15791654
1580- private module ReceiverSatisfiesBlanketConstraint =
1655+ private module ReceiverSatisfiesBlanketLikeConstraint =
15811656 BlanketImplementation:: SatisfiesBlanketConstraint< MethodCallCand ,
1582- ReceiverSatisfiesBlanketConstraintInput > ;
1657+ ReceiverSatisfiesBlanketLikeConstraintInput > ;
15831658
15841659 /**
15851660 * A configuration for matching the type of a receiver against the type of
@@ -1600,8 +1675,8 @@ private module MethodResolution {
16001675 |
16011676 methodCallNonBlanketCandidate ( mc , m , i , selfType , strippedTypePath , strippedType )
16021677 or
1603- methodCallBlanketCandidate ( mc , m , i , selfType , _, _) and
1604- ReceiverSatisfiesBlanketConstraint :: satisfiesBlanketConstraint ( mcc , i )
1678+ methodCallBlanketLikeCandidate ( mc , m , i , selfType , _, _) and
1679+ ReceiverSatisfiesBlanketLikeConstraint :: satisfiesBlanketConstraint ( mcc , i )
16051680 )
16061681 }
16071682
@@ -1626,6 +1701,30 @@ private module MethodResolution {
16261701 private module ReceiverIsInstantiationOfSelfParam =
16271702 ArgIsInstantiationOf< MethodCallCand , ReceiverIsInstantiationOfSelfParamInput > ;
16281703
1704+ /**
1705+ * A configuration for anti-matching the type of a receiver against the type of
1706+ * a `self` parameter belonging to a blanket (like) implementation.
1707+ */
1708+ private module ReceiverIsNotInstantiationOfBlanketLikeSelfParamInput implements
1709+ IsInstantiationOfInputSig< MethodCallCand , AssocFunctionType >
1710+ {
1711+ pragma [ nomagic]
1712+ predicate potentialInstantiationOf (
1713+ MethodCallCand mcc , TypeAbstraction abs , AssocFunctionType constraint
1714+ ) {
1715+ methodCallBlanketLikeCandidate ( mcc .getMethodCall ( ) , _, abs , constraint , _, _) and
1716+ if abs .( Impl ) .hasTrait ( )
1717+ then
1718+ // inherent methods take precedence over trait methods, so only allow
1719+ // trait methods when there are no matching inherent methods
1720+ mcc .hasNoInherentTarget ( )
1721+ else any ( )
1722+ }
1723+ }
1724+
1725+ private module ReceiverIsNotInstantiationOfBlanketLikeSelfParam =
1726+ ArgIsInstantiationOf< MethodCallCand , ReceiverIsNotInstantiationOfBlanketLikeSelfParamInput > ;
1727+
16291728 /**
16301729 * A configuration for matching the type qualifier of a method call
16311730 * against the type being implemented in an `impl` block. For example,
@@ -1679,10 +1778,6 @@ private module MethodResolution {
16791778 ReceiverIsInstantiationOfSelfParamInput:: potentialInstantiationOf0 ( mcc , abs , constraint ) and
16801779 abs = any ( Impl i | not i .hasTrait ( ) )
16811780 }
1682-
1683- predicate relevantConstraint ( AssocFunctionType constraint ) {
1684- methodInfo ( _, _, _, _, constraint , _, _)
1685- }
16861781 }
16871782
16881783 private module ReceiverIsNotInstantiationOfInherentSelfParam =
@@ -1948,37 +2043,37 @@ private module NonMethodResolution {
19482043 }
19492044
19502045 pragma [ nomagic]
1951- private predicate functionInfoBlanketRelevantPos (
2046+ private predicate functionInfoBlanketLikeRelevantPos (
19522047 NonMethodFunction f , string name , int arity , ImplItemNode impl , Trait trait ,
19532048 FunctionPosition pos , AssocFunctionType t , TypePath blanketPath , TypeParam blanketTypeParam
19542049 ) {
1955- functionInfoBlanket ( f , name , arity , impl , trait , pos , t , blanketPath , blanketTypeParam ) and
2050+ functionInfoBlanketLike ( f , name , arity , impl , trait , pos , t , blanketPath , blanketTypeParam ) and
19562051 (
19572052 if pos .isReturn ( )
19582053 then
19592054 // We only check that the context of the call provides relevant type information
19602055 // when no argument can
19612056 not exists ( FunctionPosition pos0 |
1962- functionInfoBlanket ( f , name , arity , impl , trait , pos0 , _, _, _) and
2057+ functionInfoBlanketLike ( f , name , arity , impl , trait , pos0 , _, _, _) and
19632058 not pos0 .isReturn ( )
19642059 )
19652060 else any ( )
19662061 )
19672062 }
19682063
19692064 pragma [ nomagic]
1970- private predicate blanketCallTraitCandidate ( Element fc , Trait trait ) {
2065+ private predicate blanketLikeCallTraitCandidate ( Element fc , Trait trait ) {
19712066 exists ( string name , int arity |
19722067 fc .( NonMethodCall ) .hasNameAndArity ( name , arity ) and
1973- functionInfoBlanketRelevantPos ( _, name , arity , _, trait , _, _, _, _)
2068+ functionInfoBlanketLikeRelevantPos ( _, name , arity , _, trait , _, _, _, _)
19742069 |
19752070 not fc .( Call ) .hasTrait ( )
19762071 or
19772072 trait = fc .( Call ) .getTrait ( )
19782073 )
19792074 }
19802075
1981- private module BlanketTraitIsVisible = TraitIsVisible< blanketCallTraitCandidate / 2 > ;
2076+ private module BlanketTraitIsVisible = TraitIsVisible< blanketLikeCallTraitCandidate / 2 > ;
19822077
19832078 /** A (potential) non-method call, `f(x)`. */
19842079 final class NonMethodCall extends CallExpr {
@@ -2037,13 +2132,13 @@ private module NonMethodResolution {
20372132 }
20382133
20392134 pragma [ nomagic]
2040- predicate resolveCallTargetBlanketCandidate (
2135+ predicate resolveCallTargetBlanketLikeCandidate (
20412136 ImplItemNode impl , FunctionPosition pos , TypePath blanketPath , TypeParam blanketTypeParam
20422137 ) {
20432138 exists ( string name , int arity , Trait trait , AssocFunctionType t |
20442139 this .hasNameAndArity ( name , arity ) and
20452140 exists ( this .getTypeAt ( pos , blanketPath ) ) and
2046- functionInfoBlanketRelevantPos ( _, name , arity , impl , trait , pos , t , blanketPath ,
2141+ functionInfoBlanketLikeRelevantPos ( _, name , arity , impl , trait , pos , t , blanketPath ,
20472142 blanketTypeParam ) and
20482143 BlanketTraitIsVisible:: traitIsVisible ( this , trait )
20492144 )
@@ -2080,7 +2175,7 @@ private module NonMethodResolution {
20802175
20812176 private newtype TCallAndBlanketPos =
20822177 MkCallAndBlanketPos ( NonMethodCall fc , FunctionPosition pos ) {
2083- fc .resolveCallTargetBlanketCandidate ( _, pos , _, _)
2178+ fc .resolveCallTargetBlanketLikeCandidate ( _, pos , _, _)
20842179 }
20852180
20862181 /** A call tagged with a position. */
@@ -2106,7 +2201,7 @@ private module NonMethodResolution {
21062201 ) {
21072202 exists ( NonMethodCall fc , FunctionPosition pos |
21082203 fcp = MkCallAndBlanketPos ( fc , pos ) and
2109- fc .resolveCallTargetBlanketCandidate ( impl , pos , blanketPath , blanketTypeParam )
2204+ fc .resolveCallTargetBlanketLikeCandidate ( impl , pos , blanketPath , blanketTypeParam )
21102205 )
21112206 }
21122207 }
@@ -2129,12 +2224,12 @@ private module NonMethodResolution {
21292224 exists ( FunctionPosition pos |
21302225 ArgSatisfiesBlanketConstraint:: satisfiesBlanketConstraint ( fcp , abs ) and
21312226 fcp = MkCallAndBlanketPos ( _, pos ) and
2132- functionInfoBlanketRelevantPos ( _, _, _, abs , _, pos , constraint , _, _)
2227+ functionInfoBlanketLikeRelevantPos ( _, _, _, abs , _, pos , constraint , _, _)
21332228 )
21342229 }
21352230
21362231 predicate relevantConstraint ( AssocFunctionType constraint ) {
2137- functionInfoBlanketRelevantPos ( _, _, _, _, _, _, constraint , _, _)
2232+ functionInfoBlanketLikeRelevantPos ( _, _, _, _, _, _, constraint , _, _)
21382233 }
21392234 }
21402235
0 commit comments