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