@@ -859,14 +859,14 @@ private predicate assocFunctionInfo(
859859
860860/**
861861 * Holds if function `f` with the name `name` and the arity `arity` exists in
862- * blanket implementation `impl` of `trait`, and the type at position
862+ * blanket (like) implementation `impl` of `trait`, and the type at position
863863 * `pos` is `t`.
864864 *
865865 * `blanketPath` points to the type `blanketTypeParam` inside `t`, which
866866 * is the type parameter used in the blanket implementation.
867867 */
868868pragma [ nomagic]
869- private predicate functionInfoBlanket (
869+ private predicate functionInfoBlanketLike (
870870 Function f , string name , int arity , ImplItemNode impl , Trait trait , FunctionTypePosition pos ,
871871 AssocFunctionType t , TypePath blanketPath , TypeParam blanketTypeParam
872872) {
@@ -985,19 +985,20 @@ private module MethodResolution {
985985
986986 /**
987987 * Holds if method `m` with the name `name` and the arity `arity` exists in
988- * blanket implementation `impl` of `trait`, and the type of the `self`
988+ * blanket (like) implementation `impl` of `trait`, and the type of the `self`
989989 * parameter is `selfType`.
990990 *
991991 * `blanketPath` points to the type `blanketTypeParam` inside `selfType`, which
992992 * is the type parameter used in the blanket implementation.
993993 */
994994 pragma [ nomagic]
995- private predicate methodInfoBlanket (
995+ private predicate methodInfoBlanketLike (
996996 Method m , string name , int arity , ImplItemNode impl , Trait trait , AssocFunctionType selfType ,
997997 TypePath blanketPath , TypeParam blanketTypeParam
998998 ) {
999999 exists ( FunctionTypePosition pos |
1000- functionInfoBlanket ( m , name , arity , impl , trait , pos , selfType , blanketPath , blanketTypeParam ) and
1000+ functionInfoBlanketLike ( m , name , arity , impl , trait , pos , selfType , blanketPath ,
1001+ blanketTypeParam ) and
10011002 pos .isSelf ( )
10021003 )
10031004 }
@@ -1071,8 +1072,8 @@ private module MethodResolution {
10711072 }
10721073
10731074 /**
1074- * Holds if method call `mc` may target a method in blanket implementation `i`
1075- * with `self` parameter having type `selfType`.
1075+ * Holds if method call `mc` may target a method in blanket (like) implementation
1076+ * `impl` with `self` parameter having type `selfType`.
10761077 *
10771078 * `blanketPath` points to the type `blanketTypeParam` inside `selfType`, which
10781079 * is the type parameter used in the blanket implementation.
@@ -1083,13 +1084,13 @@ private module MethodResolution {
10831084 */
10841085 bindingset [ mc]
10851086 pragma [ inline_late]
1086- private predicate methodCallBlanketCandidate (
1087+ private predicate methodCallBlanketLikeCandidate (
10871088 MethodCall mc , Method m , ImplItemNode impl , AssocFunctionType self , TypePath blanketPath ,
10881089 TypeParam blanketTypeParam
10891090 ) {
10901091 exists ( string name , int arity |
10911092 mc .hasNameAndArity ( name , arity ) and
1092- methodInfoBlanket ( m , name , arity , impl , _, self , blanketPath , blanketTypeParam )
1093+ methodInfoBlanketLike ( m , name , arity , impl , _, self , blanketPath , blanketTypeParam )
10931094 |
10941095 methodCallVisibleImplTraitCandidate ( mc , impl )
10951096 or
@@ -1145,7 +1146,7 @@ private module MethodResolution {
11451146 or
11461147 this .supportsAutoDerefAndBorrow ( ) and
11471148 exists ( TypePath path0 , Type t0 , string derefChain0 |
1148- this .hasNoCompatibleTarget ( derefChain0 , _) and
1149+ this .hasNoCompatibleTargetBorrow ( derefChain0 , _) and
11491150 t0 = this .getACandidateReceiverTypeAtNoBorrow ( path0 , derefChain0 )
11501151 |
11511152 path0 .isCons ( TRefTypeParameter ( ) , path ) and
@@ -1174,6 +1175,21 @@ private module MethodResolution {
11741175 derefChainBorrow = ";"
11751176 }
11761177
1178+ /**
1179+ * Holds if the method inside blanket-like implementation `i` with matching name
1180+ * and arity can be ruled out as a target of this call, either because the candidate
1181+ * receiver type represented by `derefChainBorrow` is incompatible with the `self`
1182+ * parameter type, or because the blanket constraint is not satisfied.
1183+ */
1184+ pragma [ nomagic]
1185+ private predicate hasIncompatibleBlanketLikeTarget ( ImplItemNode i , string derefChainBorrow ) {
1186+ ReceiverIsNotInstantiationOfBlanketLikeSelfParam:: argIsNotInstantiationOf ( MkMethodCallCand ( this ,
1187+ derefChainBorrow ) , i , _)
1188+ or
1189+ ReceiverSatisfiesBlanketLikeConstraint:: satisfiesNotBlanketConstraint ( MkMethodCallCand ( this ,
1190+ derefChainBorrow ) , i )
1191+ }
1192+
11771193 /**
11781194 * Same as `getACandidateReceiverTypeAt`, but with traits substituted in for types
11791195 * with trait bounds.
@@ -1191,10 +1207,9 @@ private module MethodResolution {
11911207 }
11921208
11931209 bindingset [ strippedTypePath, strippedType, derefChainBorrow]
1194- private predicate hasNoCompatibleTargetCheck (
1210+ private predicate hasNoCompatibleNonBlanketLikeTargetCheck (
11951211 TypePath strippedTypePath , Type strippedType , string derefChainBorrow
11961212 ) {
1197- // todo: also check that all blanket implementation candidates are incompatible
11981213 forall ( ImplOrTraitItemNode i |
11991214 methodCallNonBlanketCandidate ( this , _, i , _, strippedTypePath , strippedType )
12001215 or
@@ -1204,6 +1219,28 @@ private module MethodResolution {
12041219 )
12051220 }
12061221
1222+ bindingset [ strippedTypePath, strippedType, derefChainBorrow]
1223+ private predicate hasNoCompatibleTargetCheck (
1224+ TypePath strippedTypePath , Type strippedType , string derefChainBorrow
1225+ ) {
1226+ this .hasNoCompatibleNonBlanketLikeTargetCheck ( strippedTypePath , strippedType , derefChainBorrow ) and
1227+ forall ( ImplItemNode i | methodCallBlanketLikeCandidate ( this , _, i , _, _, _) |
1228+ this .hasIncompatibleBlanketLikeTarget ( i , derefChainBorrow )
1229+ )
1230+ }
1231+
1232+ bindingset [ strippedTypePath, strippedType, derefChainBorrow]
1233+ private predicate hasNoCompatibleNonBlanketTargetCheck (
1234+ TypePath strippedTypePath , Type strippedType , string derefChainBorrow
1235+ ) {
1236+ this .hasNoCompatibleNonBlanketLikeTargetCheck ( strippedTypePath , strippedType , derefChainBorrow ) and
1237+ forall ( ImplItemNode i |
1238+ methodCallBlanketLikeCandidate ( this , _, i , _, _, _) and not i .isBlanketImplementation ( )
1239+ |
1240+ this .hasIncompatibleBlanketLikeTarget ( i , derefChainBorrow )
1241+ )
1242+ }
1243+
12071244 /**
12081245 * Holds if the candidate receiver type represented by
12091246 * `derefChainBorrow = derefChain;` does not have a matching method target.
@@ -1214,7 +1251,7 @@ private module MethodResolution {
12141251 this .supportsAutoDerefAndBorrow ( )
12151252 or
12161253 // needed for the `hasNoCompatibleTarget` check in
1217- // `SatisfiesBlanketConstraintInput ::hasBlanketCandidate`
1254+ // `ReceiverSatisfiesBlanketLikeConstraintInput ::hasBlanketCandidate`
12181255 derefChain = ""
12191256 ) and
12201257 exists ( TypePath strippedTypePath , Type strippedType |
@@ -1225,13 +1262,35 @@ private module MethodResolution {
12251262 )
12261263 }
12271264
1265+ /**
1266+ * Holds if the candidate receiver type represented by
1267+ * `derefChainBorrow = derefChain;` does not have a matching non-blanket
1268+ * method target.
1269+ */
1270+ pragma [ nomagic]
1271+ predicate hasNoCompatibleNonBlanketTargetNoBorrow ( string derefChain , string derefChainBorrow ) {
1272+ (
1273+ this .supportsAutoDerefAndBorrow ( )
1274+ or
1275+ // needed for the `hasNoCompatibleTarget` check in
1276+ // `ReceiverSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate`
1277+ derefChain = ""
1278+ ) and
1279+ exists ( TypePath strippedTypePath , Type strippedType |
1280+ derefChainBorrow = derefChain + ";" and
1281+ not derefChain .matches ( "%.ref" ) and // no need to try a borrow if the last thing we did was a deref
1282+ strippedType = this .getComplexStrippedType ( strippedTypePath , derefChainBorrow ) and
1283+ this .hasNoCompatibleNonBlanketTargetCheck ( strippedTypePath , strippedType , derefChainBorrow )
1284+ )
1285+ }
1286+
12281287 /**
12291288 * Holds if the candidate receiver type represented by
12301289 * `derefChainBorrow = derefChain;borrow` does not have a matching method
12311290 * target.
12321291 */
12331292 pragma [ nomagic]
1234- predicate hasNoCompatibleTarget ( string derefChain , string derefChainBorrow ) {
1293+ predicate hasNoCompatibleTargetBorrow ( string derefChain , string derefChainBorrow ) {
12351294 exists ( TypePath strippedTypePath , Type strippedType |
12361295 derefChainBorrow = derefChain + ";borrow" and
12371296 this .hasNoCompatibleTargetNoBorrow ( derefChain , _) and
@@ -1240,6 +1299,21 @@ private module MethodResolution {
12401299 )
12411300 }
12421301
1302+ /**
1303+ * Holds if the candidate receiver type represented by
1304+ * `derefChainBorrow = derefChain;borrow` does not have a matching non-blanket
1305+ * method target.
1306+ */
1307+ pragma [ nomagic]
1308+ predicate hasNoCompatibleNonBlanketTargetBorrow ( string derefChain , string derefChainBorrow ) {
1309+ exists ( TypePath strippedTypePath , Type strippedType |
1310+ derefChainBorrow = derefChain + ";borrow" and
1311+ this .hasNoCompatibleTargetNoBorrow ( derefChain , _) and
1312+ strippedType = this .getComplexStrippedType ( strippedTypePath , derefChainBorrow ) and
1313+ this .hasNoCompatibleNonBlanketTargetCheck ( strippedTypePath , strippedType , derefChainBorrow )
1314+ )
1315+ }
1316+
12431317 /**
12441318 * Gets a [candidate receiver type][1] of this method call at `path`.
12451319 *
@@ -1432,10 +1506,10 @@ private module MethodResolution {
14321506 }
14331507
14341508 pragma [ nomagic]
1435- predicate hasNoCompatibleTarget ( ) {
1436- mc_ .hasNoCompatibleTarget ( _, derefChainBorrow )
1509+ predicate hasNoCompatibleNonBlanketTarget ( ) {
1510+ mc_ .hasNoCompatibleNonBlanketTargetBorrow ( _, derefChainBorrow )
14371511 or
1438- mc_ .hasNoCompatibleTargetNoBorrow ( _, derefChainBorrow )
1512+ mc_ .hasNoCompatibleNonBlanketTargetNoBorrow ( _, derefChainBorrow )
14391513 }
14401514
14411515 pragma [ nomagic]
@@ -1518,20 +1592,20 @@ private module MethodResolution {
15181592 Location getLocation ( ) { result = mc_ .getLocation ( ) }
15191593 }
15201594
1521- private module ReceiverSatisfiesBlanketConstraintInput implements
1595+ private module ReceiverSatisfiesBlanketLikeConstraintInput implements
15221596 BlanketImplementation:: SatisfiesBlanketConstraintInputSig< MethodCallCand >
15231597 {
15241598 pragma [ nomagic]
15251599 predicate hasBlanketCandidate (
15261600 MethodCallCand mcc , ImplItemNode impl , TypePath blanketPath , TypeParam blanketTypeParam
15271601 ) {
1528- exists ( MethodCall mc , string name , int arity |
1529- mcc . hasSignature ( mc , _ , _ , name , arity ) and
1530- methodCallBlanketCandidate ( mc , _, impl , _, blanketPath , blanketTypeParam ) and
1602+ exists ( MethodCall mc |
1603+ mc = mcc . getMethodCall ( ) and
1604+ methodCallBlanketLikeCandidate ( mc , _, impl , _, blanketPath , blanketTypeParam ) and
15311605 // Only apply blanket implementations when no other implementations are possible;
15321606 // this is to account for codebases that use the (unstable) specialization feature
15331607 // (https://rust-lang.github.io/rfcs/1210-impl-specialization.html)
1534- mcc .hasNoCompatibleTarget ( )
1608+ ( mcc .hasNoCompatibleNonBlanketTarget ( ) or not impl . isBlanketImplementation ( ) )
15351609 |
15361610 mcc .hasNoBorrow ( )
15371611 or
@@ -1540,9 +1614,9 @@ private module MethodResolution {
15401614 }
15411615 }
15421616
1543- private module ReceiverSatisfiesBlanketConstraint =
1617+ private module ReceiverSatisfiesBlanketLikeConstraint =
15441618 BlanketImplementation:: SatisfiesBlanketConstraint< MethodCallCand ,
1545- ReceiverSatisfiesBlanketConstraintInput > ;
1619+ ReceiverSatisfiesBlanketLikeConstraintInput > ;
15461620
15471621 /**
15481622 * A configuration for matching the type of a receiver against the type of
@@ -1563,8 +1637,8 @@ private module MethodResolution {
15631637 |
15641638 methodCallNonBlanketCandidate ( mc , m , i , selfType , strippedTypePath , strippedType )
15651639 or
1566- methodCallBlanketCandidate ( mc , m , i , selfType , _, _) and
1567- ReceiverSatisfiesBlanketConstraint :: satisfiesBlanketConstraint ( mcc , i )
1640+ methodCallBlanketLikeCandidate ( mc , m , i , selfType , _, _) and
1641+ ReceiverSatisfiesBlanketLikeConstraint :: satisfiesBlanketConstraint ( mcc , i )
15681642 )
15691643 }
15701644
@@ -1589,6 +1663,30 @@ private module MethodResolution {
15891663 private module ReceiverIsInstantiationOfSelfParam =
15901664 ArgIsInstantiationOf< MethodCallCand , ReceiverIsInstantiationOfSelfParamInput > ;
15911665
1666+ /**
1667+ * A configuration for anti-matching the type of a receiver against the type of
1668+ * a `self` parameter belonging to a blanket (like) implementation.
1669+ */
1670+ private module ReceiverIsNotInstantiationOfBlanketLikeSelfParamInput implements
1671+ IsInstantiationOfInputSig< MethodCallCand , AssocFunctionType >
1672+ {
1673+ pragma [ nomagic]
1674+ predicate potentialInstantiationOf (
1675+ MethodCallCand mcc , TypeAbstraction abs , AssocFunctionType constraint
1676+ ) {
1677+ methodCallBlanketLikeCandidate ( mcc .getMethodCall ( ) , _, abs , constraint , _, _) and
1678+ if abs .( Impl ) .hasTrait ( )
1679+ then
1680+ // inherent methods take precedence over trait methods, so only allow
1681+ // trait methods when there are no matching inherent methods
1682+ mcc .hasNoInherentTarget ( )
1683+ else any ( )
1684+ }
1685+ }
1686+
1687+ private module ReceiverIsNotInstantiationOfBlanketLikeSelfParam =
1688+ ArgIsInstantiationOf< MethodCallCand , ReceiverIsNotInstantiationOfBlanketLikeSelfParamInput > ;
1689+
15921690 /**
15931691 * A configuration for matching the type qualifier of a method call
15941692 * against the type being implemented in an `impl` block. For example,
@@ -1642,10 +1740,6 @@ private module MethodResolution {
16421740 ReceiverIsInstantiationOfSelfParamInput:: potentialInstantiationOf0 ( mcc , abs , constraint ) and
16431741 abs = any ( Impl i | not i .hasTrait ( ) )
16441742 }
1645-
1646- predicate relevantConstraint ( AssocFunctionType constraint ) {
1647- methodInfo ( _, _, _, _, constraint , _, _)
1648- }
16491743 }
16501744
16511745 private module ReceiverIsNotInstantiationOfInherentSelfParam =
@@ -1901,18 +1995,18 @@ private module NonMethodResolution {
19011995 }
19021996
19031997 pragma [ nomagic]
1904- private predicate functionInfoBlanketRelevantPos (
1998+ private predicate functionInfoBlanketLikeRelevantPos (
19051999 NonMethodFunction f , string name , int arity , ImplItemNode impl , Trait trait ,
19062000 FunctionTypePosition pos , AssocFunctionType t , TypePath blanketPath , TypeParam blanketTypeParam
19072001 ) {
1908- functionInfoBlanket ( f , name , arity , impl , trait , pos , t , blanketPath , blanketTypeParam ) and
2002+ functionInfoBlanketLike ( f , name , arity , impl , trait , pos , t , blanketPath , blanketTypeParam ) and
19092003 (
19102004 not pos .isReturn ( )
19112005 or
19122006 // We only check that the context of the call provides relevant type information
19132007 // when no argument can
19142008 not exists ( FunctionTypePosition pos0 |
1915- functionInfoBlanket ( f , name , arity , impl , trait , pos0 , _, _, _) and
2009+ functionInfoBlanketLike ( f , name , arity , impl , trait , pos0 , _, _, _) and
19162010 not pos0 .isReturn ( )
19172011 )
19182012 )
@@ -1922,7 +2016,7 @@ private module NonMethodResolution {
19222016 private predicate blanketCallTraitCandidate ( Element fc , Trait trait ) {
19232017 exists ( string name , int arity |
19242018 fc .( NonMethodCall ) .hasNameAndArity ( name , arity ) and
1925- functionInfoBlanketRelevantPos ( _, name , arity , _, trait , _, _, _, _)
2019+ functionInfoBlanketLikeRelevantPos ( _, name , arity , _, trait , _, _, _, _)
19262020 |
19272021 not fc .( Call ) .hasTrait ( )
19282022 or
@@ -1998,7 +2092,7 @@ private module NonMethodResolution {
19982092 exists ( string name , int arity , Trait trait , AssocFunctionType t |
19992093 this .hasNameAndArity ( name , arity ) and
20002094 exists ( this .getTypeAt ( pos , blanketPath ) ) and
2001- functionInfoBlanketRelevantPos ( _, name , arity , impl , trait , pos , t , blanketPath ,
2095+ functionInfoBlanketLikeRelevantPos ( _, name , arity , impl , trait , pos , t , blanketPath ,
20022096 blanketTypeParam ) and
20032097 BlanketTraitIsVisible:: traitIsVisible ( this , trait )
20042098 )
@@ -2084,12 +2178,12 @@ private module NonMethodResolution {
20842178 exists ( FunctionTypePosition pos |
20852179 ArgSatisfiesBlanketConstraint:: satisfiesBlanketConstraint ( fcp , abs ) and
20862180 fcp = MkCallAndBlanketPos ( _, pos ) and
2087- functionInfoBlanketRelevantPos ( _, _, _, abs , _, pos , constraint , _, _)
2181+ functionInfoBlanketLikeRelevantPos ( _, _, _, abs , _, pos , constraint , _, _)
20882182 )
20892183 }
20902184
20912185 predicate relevantConstraint ( AssocFunctionType constraint ) {
2092- functionInfoBlanketRelevantPos ( _, _, _, _, _, _, constraint , _, _)
2186+ functionInfoBlanketLikeRelevantPos ( _, _, _, _, _, _, constraint , _, _)
20932187 }
20942188 }
20952189
0 commit comments