@@ -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 , FunctionTypePosition 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 ( 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
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
@@ -1190,7 +1191,7 @@ private module MethodResolution {
11901191 or
11911192 this .supportsAutoDerefAndBorrow ( ) and
11921193 exists ( TypePath path0 , Type t0 , string derefChain0 |
1193- this .hasNoCompatibleTarget ( derefChain0 , _) and
1194+ this .hasNoCompatibleTargetBorrow ( derefChain0 , _) and
11941195 t0 = this .getACandidateReceiverTypeAtNoBorrow ( path0 , derefChain0 )
11951196 |
11961197 path0 .isCons ( TRefTypeParameter ( ) , path ) and
@@ -1219,6 +1220,21 @@ private module MethodResolution {
12191220 derefChainBorrow = ";"
12201221 }
12211222
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+
12221238 /**
12231239 * Same as `getACandidateReceiverTypeAt`, but with traits substituted in for types
12241240 * with trait bounds.
@@ -1236,10 +1252,9 @@ private module MethodResolution {
12361252 }
12371253
12381254 bindingset [ strippedTypePath, strippedType, derefChainBorrow]
1239- private predicate hasNoCompatibleTargetCheck (
1255+ private predicate hasNoCompatibleNonBlanketLikeTargetCheck (
12401256 TypePath strippedTypePath , Type strippedType , string derefChainBorrow
12411257 ) {
1242- // todo: also check that all blanket implementation candidates are incompatible
12431258 forall ( ImplOrTraitItemNode i |
12441259 methodCallNonBlanketCandidate ( this , _, i , _, strippedTypePath , strippedType )
12451260 or
@@ -1249,6 +1264,28 @@ private module MethodResolution {
12491264 )
12501265 }
12511266
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+
12521289 /**
12531290 * Holds if the candidate receiver type represented by
12541291 * `derefChainBorrow = derefChain;` does not have a matching method target.
@@ -1259,7 +1296,7 @@ private module MethodResolution {
12591296 this .supportsAutoDerefAndBorrow ( )
12601297 or
12611298 // needed for the `hasNoCompatibleTarget` check in
1262- // `SatisfiesBlanketConstraintInput ::hasBlanketCandidate`
1299+ // `ReceiverSatisfiesBlanketLikeConstraintInput ::hasBlanketCandidate`
12631300 derefChain = ""
12641301 ) and
12651302 exists ( TypePath strippedTypePath , Type strippedType |
@@ -1270,13 +1307,35 @@ private module MethodResolution {
12701307 )
12711308 }
12721309
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+
12731332 /**
12741333 * Holds if the candidate receiver type represented by
12751334 * `derefChainBorrow = derefChain;borrow` does not have a matching method
12761335 * target.
12771336 */
12781337 pragma [ nomagic]
1279- predicate hasNoCompatibleTarget ( string derefChain , string derefChainBorrow ) {
1338+ predicate hasNoCompatibleTargetBorrow ( string derefChain , string derefChainBorrow ) {
12801339 exists ( TypePath strippedTypePath , Type strippedType |
12811340 derefChainBorrow = derefChain + ";borrow" and
12821341 this .hasNoCompatibleTargetNoBorrow ( derefChain , _) and
@@ -1285,6 +1344,21 @@ private module MethodResolution {
12851344 )
12861345 }
12871346
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+
12881362 /**
12891363 * Gets a [candidate receiver type][1] of this method call at `path`.
12901364 *
@@ -1477,10 +1551,10 @@ private module MethodResolution {
14771551 }
14781552
14791553 pragma [ nomagic]
1480- predicate hasNoCompatibleTarget ( ) {
1481- mc_ .hasNoCompatibleTarget ( _, derefChainBorrow )
1554+ predicate hasNoCompatibleNonBlanketTarget ( ) {
1555+ mc_ .hasNoCompatibleNonBlanketTargetBorrow ( _, derefChainBorrow )
14821556 or
1483- mc_ .hasNoCompatibleTargetNoBorrow ( _, derefChainBorrow )
1557+ mc_ .hasNoCompatibleNonBlanketTargetNoBorrow ( _, derefChainBorrow )
14841558 }
14851559
14861560 pragma [ nomagic]
@@ -1563,20 +1637,20 @@ private module MethodResolution {
15631637 Location getLocation ( ) { result = mc_ .getLocation ( ) }
15641638 }
15651639
1566- private module ReceiverSatisfiesBlanketConstraintInput implements
1640+ private module ReceiverSatisfiesBlanketLikeConstraintInput implements
15671641 BlanketImplementation:: SatisfiesBlanketConstraintInputSig< MethodCallCand >
15681642 {
15691643 pragma [ nomagic]
15701644 predicate hasBlanketCandidate (
15711645 MethodCallCand mcc , ImplItemNode impl , TypePath blanketPath , TypeParam blanketTypeParam
15721646 ) {
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
15761650 // Only apply blanket implementations when no other implementations are possible;
15771651 // this is to account for codebases that use the (unstable) specialization feature
15781652 // (https://rust-lang.github.io/rfcs/1210-impl-specialization.html)
1579- mcc .hasNoCompatibleTarget ( )
1653+ ( mcc .hasNoCompatibleNonBlanketTarget ( ) or not impl . isBlanketImplementation ( ) )
15801654 |
15811655 mcc .hasNoBorrow ( )
15821656 or
@@ -1585,9 +1659,9 @@ private module MethodResolution {
15851659 }
15861660 }
15871661
1588- private module ReceiverSatisfiesBlanketConstraint =
1662+ private module ReceiverSatisfiesBlanketLikeConstraint =
15891663 BlanketImplementation:: SatisfiesBlanketConstraint< MethodCallCand ,
1590- ReceiverSatisfiesBlanketConstraintInput > ;
1664+ ReceiverSatisfiesBlanketLikeConstraintInput > ;
15911665
15921666 /**
15931667 * A configuration for matching the type of a receiver against the type of
@@ -1608,8 +1682,8 @@ private module MethodResolution {
16081682 |
16091683 methodCallNonBlanketCandidate ( mc , m , i , selfType , strippedTypePath , strippedType )
16101684 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 )
16131687 )
16141688 }
16151689
@@ -1634,6 +1708,30 @@ private module MethodResolution {
16341708 private module ReceiverIsInstantiationOfSelfParam =
16351709 ArgIsInstantiationOf< MethodCallCand , ReceiverIsInstantiationOfSelfParamInput > ;
16361710
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+
16371735 /**
16381736 * A configuration for matching the type qualifier of a method call
16391737 * against the type being implemented in an `impl` block. For example,
@@ -1687,10 +1785,6 @@ private module MethodResolution {
16871785 ReceiverIsInstantiationOfSelfParamInput:: potentialInstantiationOf0 ( mcc , abs , constraint ) and
16881786 abs = any ( Impl i | not i .hasTrait ( ) )
16891787 }
1690-
1691- predicate relevantConstraint ( AssocFunctionType constraint ) {
1692- methodInfo ( _, _, _, _, constraint , _, _)
1693- }
16941788 }
16951789
16961790 private module ReceiverIsNotInstantiationOfInherentSelfParam =
@@ -1946,18 +2040,18 @@ private module NonMethodResolution {
19462040 }
19472041
19482042 pragma [ nomagic]
1949- private predicate functionInfoBlanketRelevantPos (
2043+ private predicate functionInfoBlanketLikeRelevantPos (
19502044 NonMethodFunction f , string name , int arity , ImplItemNode impl , Trait trait ,
19512045 FunctionTypePosition pos , AssocFunctionType t , TypePath blanketPath , TypeParam blanketTypeParam
19522046 ) {
1953- functionInfoBlanket ( f , name , arity , impl , trait , pos , t , blanketPath , blanketTypeParam ) and
2047+ functionInfoBlanketLike ( f , name , arity , impl , trait , pos , t , blanketPath , blanketTypeParam ) and
19542048 (
19552049 not pos .isReturn ( )
19562050 or
19572051 // We only check that the context of the call provides relevant type information
19582052 // when no argument can
19592053 not exists ( FunctionTypePosition pos0 |
1960- functionInfoBlanket ( f , name , arity , impl , trait , pos0 , _, _, _) and
2054+ functionInfoBlanketLike ( f , name , arity , impl , trait , pos0 , _, _, _) and
19612055 not pos0 .isReturn ( )
19622056 )
19632057 )
@@ -1967,7 +2061,7 @@ private module NonMethodResolution {
19672061 private predicate blanketCallTraitCandidate ( Element fc , Trait trait ) {
19682062 exists ( string name , int arity |
19692063 fc .( NonMethodCall ) .hasNameAndArity ( name , arity ) and
1970- functionInfoBlanketRelevantPos ( _, name , arity , _, trait , _, _, _, _)
2064+ functionInfoBlanketLikeRelevantPos ( _, name , arity , _, trait , _, _, _, _)
19712065 |
19722066 not fc .( Call ) .hasTrait ( )
19732067 or
@@ -2040,7 +2134,7 @@ private module NonMethodResolution {
20402134 exists ( string name , int arity , Trait trait , AssocFunctionType t |
20412135 this .hasNameAndArity ( name , arity ) and
20422136 exists ( this .getTypeAt ( pos , blanketPath ) ) and
2043- functionInfoBlanketRelevantPos ( _, name , arity , impl , trait , pos , t , blanketPath ,
2137+ functionInfoBlanketLikeRelevantPos ( _, name , arity , impl , trait , pos , t , blanketPath ,
20442138 blanketTypeParam ) and
20452139 BlanketTraitIsVisible:: traitIsVisible ( this , trait )
20462140 )
@@ -2126,12 +2220,12 @@ private module NonMethodResolution {
21262220 exists ( FunctionTypePosition pos |
21272221 ArgSatisfiesBlanketConstraint:: satisfiesBlanketConstraint ( fcp , abs ) and
21282222 fcp = MkCallAndBlanketPos ( _, pos ) and
2129- functionInfoBlanketRelevantPos ( _, _, _, abs , _, pos , constraint , _, _)
2223+ functionInfoBlanketLikeRelevantPos ( _, _, _, abs , _, pos , constraint , _, _)
21302224 )
21312225 }
21322226
21332227 predicate relevantConstraint ( AssocFunctionType constraint ) {
2134- functionInfoBlanketRelevantPos ( _, _, _, _, _, _, constraint , _, _)
2228+ functionInfoBlanketLikeRelevantPos ( _, _, _, _, _, _, constraint , _, _)
21352229 }
21362230 }
21372231
0 commit comments