@@ -1227,11 +1227,126 @@ private Function getTypeParameterMethod(TypeParameter tp, string name) {
12271227 result = getMethodSuccessor ( tp .( ImplTraitTypeTypeParameter ) .getImplTraitTypeRepr ( ) , name )
12281228}
12291229
1230+ bindingset [ t1, t2]
1231+ private predicate typeMentionEqual ( TypeMention t1 , TypeMention t2 ) {
1232+ forex ( TypePath path , Type type | t1 .resolveTypeAt ( path ) = type | t2 .resolveTypeAt ( path ) = type )
1233+ }
1234+
1235+ pragma [ nomagic]
1236+ private predicate implSiblingCandidate (
1237+ Impl impl , TraitItemNode trait , Type rootType , TypeMention selfTy
1238+ ) {
1239+ trait = impl .( ImplItemNode ) .resolveTraitTy ( ) and
1240+ not exists ( impl .getAttributeMacroExpansion ( ) ) and
1241+ // We use this for resolving methods, so exclude traits that do not have methods.
1242+ exists ( Function f | f = trait .getASuccessor ( _) and f .getParamList ( ) .hasSelfParam ( ) ) and
1243+ selfTy = impl .getSelfTy ( ) and
1244+ rootType = selfTy .resolveType ( )
1245+ }
1246+
1247+ /**
1248+ * Holds if `impl1` and `impl2` are a sibling implementations of `trait`. We
1249+ * consider implementations to be siblings if they implement the same trait for
1250+ * the same type. In that case `Self` is the same type in both implementations,
1251+ * and method calls to the implementations cannot be resolved unambiguously
1252+ * based only on the receiver type.
1253+ */
1254+ pragma [ inline]
1255+ private predicate implSiblings ( TraitItemNode trait , Impl impl1 , Impl impl2 ) {
1256+ exists ( Type rootType , TypeMention selfTy1 , TypeMention selfTy2 |
1257+ impl1 != impl2 and
1258+ implSiblingCandidate ( impl1 , trait , rootType , selfTy1 ) and
1259+ implSiblingCandidate ( impl2 , trait , rootType , selfTy2 ) and
1260+ // In principle the second conjunct below should be superflous, but we still
1261+ // have ill-formed type mentions for types that we don't understand. For
1262+ // those checking both directions restricts further. Note also that we check
1263+ // syntactic equality, whereas equality up to renaming would be more
1264+ // correct.
1265+ typeMentionEqual ( selfTy1 , selfTy2 ) and
1266+ typeMentionEqual ( selfTy2 , selfTy1 )
1267+ )
1268+ }
1269+
1270+ /**
1271+ * Holds if `impl` is an implementation of `trait` and if another implementation
1272+ * exists for the same type.
1273+ */
1274+ pragma [ nomagic]
1275+ private predicate implHasSibling ( Impl impl , Trait trait ) { implSiblings ( trait , impl , _) }
1276+
1277+ /**
1278+ * Holds if a type parameter of `trait` occurs in the method with the name
1279+ * `methodName` at the `pos`th parameter at `path`.
1280+ */
1281+ bindingset [ trait]
1282+ pragma [ inline_late]
1283+ private predicate traitTypeParameterOccurrence (
1284+ TraitItemNode trait , string methodName , int pos , TypePath path
1285+ ) {
1286+ exists ( Function f | f = trait .getASuccessor ( methodName ) |
1287+ f .getParam ( pos ) .getTypeRepr ( ) .( TypeMention ) .resolveTypeAt ( path ) =
1288+ trait .( TraitTypeAbstraction ) .getATypeParameter ( )
1289+ )
1290+ }
1291+
1292+ bindingset [ f, pos, path]
1293+ pragma [ inline_late]
1294+ private predicate methodTypeAtPath ( Function f , int pos , TypePath path , Type type ) {
1295+ f .getParam ( pos ) .getTypeRepr ( ) .( TypeMention ) .resolveTypeAt ( path ) = type
1296+ }
1297+
1298+ /**
1299+ * Holds if resolving the method in `impl` with the name `methodName` requires
1300+ * inspecting the types of applied _arguments_ in order to determine whether it
1301+ * is the correct resolution.
1302+ */
1303+ private predicate methodResolutionDependsOnArgument (
1304+ Impl impl , string methodName , int pos , TypePath path , Type type
1305+ ) {
1306+ /*
1307+ * As seen in the example below, when an implementation has a sibling for a
1308+ * trait we find occurrences of a type parameter of the trait in a method
1309+ * signature in the trait. We then find the type given in the implementation
1310+ * at the same position, which is a position that might disambiguate the
1311+ * method from its siblings.
1312+ *
1313+ * ```rust
1314+ * trait MyTrait<T> {
1315+ * fn method(&self, value: Foo<T>) -> Self;
1316+ * // ^^^^^^^^^^^^^ `pos` = 0
1317+ * // ^ `path` = "T"
1318+ * }
1319+ * impl MyAdd<i64> for i64 {
1320+ * fn method(&self, value: i64) -> Self { ... }
1321+ * // ^^^ `type` = i64
1322+ * }
1323+ * ```
1324+ *
1325+ * Note that we only check the root type symbol at the position. If the type
1326+ * at that position is a type constructor (for instance `Vec<..>`) then
1327+ * inspecting the entire type tree could be necessary to disambiguate the
1328+ * method. In that case we will still resolve several methods.
1329+ */
1330+
1331+ exists ( TraitItemNode trait |
1332+ implHasSibling ( impl , trait ) and
1333+ traitTypeParameterOccurrence ( trait , methodName , pos , path ) and
1334+ methodTypeAtPath ( getMethodSuccessor ( impl , methodName ) , pos , path , type )
1335+ )
1336+ }
1337+
12301338/** Gets a method from an `impl` block that matches the method call `mc`. */
12311339private Function getMethodFromImpl ( MethodCall mc ) {
12321340 exists ( Impl impl |
12331341 IsInstantiationOf< MethodCall , IsInstantiationOfInput > :: isInstantiationOf ( mc , impl , _) and
12341342 result = getMethodSuccessor ( impl , mc .getMethodName ( ) )
1343+ |
1344+ not methodResolutionDependsOnArgument ( impl , _, _, _, _)
1345+ or
1346+ exists ( int pos , TypePath path , Type type |
1347+ methodResolutionDependsOnArgument ( impl , mc .getMethodName ( ) , pos , path , type ) and
1348+ inferType ( mc .getArgument ( pos ) , path ) = type
1349+ )
12351350 )
12361351}
12371352
0 commit comments