Rust: Improve handling of occurrences of the Self type parameter

This commit is contained in:
Simon Friis Vindum
2025-10-29 10:07:59 +01:00
parent 9ff3c61c6e
commit 9022f996e8
3 changed files with 70 additions and 22 deletions

View File

@@ -151,25 +151,61 @@ class NonAliasPathTypeMention extends PathTypeMention {
result = this.getQualifier().getSegment().getGenericArgList().getTypeArg(i)
}
private TypeMention getPositionalTypeArgument(int i) {
result = this.getPositionalTypeArgument0(i)
/**
* Gets the type mention that instantiates the implicit `Self` type parameter
* for this path, if it occurs in the position of a trait bound.
*/
private TypeMention getSelfTypeParameter() {
exists(ImplItemNode impl | this = impl.getTraitPath() and result = impl.(Impl).getSelfTy())
or
exists(Trait subTrait |
this = subTrait.getATypeBound().getTypeRepr().(PathTypeRepr).getPath() and
result.(SelfTypeParameterMention).getTrait() = subTrait
)
or
exists(TypeParamItemNode tp | this = tp.getABoundPath() and result = tp)
}
private Type getPositionalTypeArgument(int i, TypePath path) {
result = this.getPositionalTypeArgument0(i).resolveTypeAt(path)
or
result = this.getDefaultPositionalTypeArgument(i, path)
}
private Type getDefaultPositionalTypeArgument(int i, TypePath path) {
// If a type argument is not given in the path, then we use the default for
// the type parameter if one exists for the type.
not exists(this.getPositionalTypeArgument0(i)) and
result = this.resolveRootType().getTypeParameterDefault(i) and
// Defaults only apply to type mentions in type annotations
this = any(PathTypeRepr ptp).getPath().getQualifier*()
this = any(PathTypeRepr ptp).getPath().getQualifier*() and
exists(Type ty, TypePath prefix |
ty = this.resolveRootType().getTypeParameterDefault(i).resolveTypeAt(prefix) and
if not ty = TSelfTypeParameter(resolved)
then result = ty and path = prefix
else
// When a default contains an implicit `Self` type parameter, it should
// be substituted for the type that implements the trait.
exists(TypePath suffix |
path = prefix.append(suffix) and
result = this.getSelfTypeParameter().resolveTypeAt(suffix)
)
)
}
/**
* Gets the type for this path for the type parameter `tp` at `path`, when the
* type parameter does not correspond directly to a type mention.
*/
private Type getTypeForTypeParameterAt(TypeParameter tp, TypePath path) {
exists(int i |
result = this.getPositionalTypeArgument(pragma[only_bind_into](i), path) and
tp = this.resolveRootType().getPositionalTypeParameter(pragma[only_bind_into](i))
)
}
/** Gets the type mention in this path for the type parameter `tp`, if any. */
pragma[nomagic]
private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) {
exists(int i |
result = this.getPositionalTypeArgument(pragma[only_bind_into](i)) and
tp = this.resolveRootType().getPositionalTypeParameter(pragma[only_bind_into](i))
)
or
exists(TypeAlias alias |
result = this.getAnAssocTypeArgument(alias) and
tp = TAssociatedTypeTypeParameter(alias)
@@ -237,9 +273,17 @@ class NonAliasPathTypeMention extends PathTypeMention {
typePath.isEmpty() and
result = this.resolveRootType()
or
exists(TypeParameter tp, TypePath suffix |
result = this.getTypeMentionForTypeParameter(tp).resolveTypeAt(suffix) and
typePath = TypePath::cons(tp, suffix)
exists(TypeParameter tp, TypePath suffix | typePath = TypePath::cons(tp, suffix) |
result = this.getTypeForTypeParameterAt(tp, suffix)
or
result = this.getTypeMentionForTypeParameter(tp).resolveTypeAt(suffix)
)
or
// When the path refers to a trait, then the implicit `Self` type parameter
// should be instantiated from the context.
exists(TypePath suffix |
result = this.getSelfTypeParameter().resolveTypeAt(suffix) and
typePath = TypePath::cons(TSelfTypeParameter(resolved), suffix)
)
}
}
@@ -296,6 +340,11 @@ class TraitMention extends TypeMention instanceof TraitItemNode {
typePath.isEmpty() and
result = TTrait(this)
or
// The implicit `Self` type parameter occurs at the `Self` type parameter
// position.
typePath = TypePath::singleton(TSelfTypeParameter(this)) and
result = TSelfTypeParameter(this)
or
exists(TypeAlias alias |
alias = super.getAnAssocItem() and
typePath = TypePath::singleton(result) and

View File

@@ -666,7 +666,7 @@ mod trait_default_self_type_parameter {
// The trait bound on `T` uses the default for `A` which contains `Self`
fn tp_uses_default<S: TraitWithSelfTp>(thing: S) -> i64 {
let _ms = thing.get_a(); // $ target=TraitWithSelfTp::get_a MISSING: type=_ms:T.S
let _ms = thing.get_a(); // $ target=TraitWithSelfTp::get_a type=_ms:T.S
0
}
@@ -675,7 +675,7 @@ mod trait_default_self_type_parameter {
fn get_a_through_tp<S: SubTraitOfTraitWithSelfTp>(thing: &S) {
// `thing` is a `TraitWithSelfTp` through the trait hierarchy
let _ms = get_a(thing); // $ target=get_a MISSING: type=_ms:T.S
let _ms = get_a(thing); // $ target=get_a type=_ms:T.S
}
struct MyStruct {
@@ -693,7 +693,7 @@ mod trait_default_self_type_parameter {
pub fn test() {
let s = MyStruct { value: 0 };
let _ms = get_a(&s); // $ target=get_a MISSING: type=_ms:T.MyStruct
let _ms = get_a(&s); // $ target=get_a type=_ms:T.MyStruct
}
}

View File

@@ -2013,18 +2013,18 @@ inferType
| main.rs:668:44:668:48 | thing | | main.rs:668:24:668:41 | S |
| main.rs:668:61:671:5 | { ... } | | {EXTERNAL LOCATION} | i64 |
| main.rs:669:13:669:15 | _ms | | {EXTERNAL LOCATION} | Option |
| main.rs:669:13:669:15 | _ms | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
| main.rs:669:13:669:15 | _ms | T | main.rs:668:24:668:41 | S |
| main.rs:669:19:669:23 | thing | | main.rs:668:24:668:41 | S |
| main.rs:669:19:669:31 | thing.get_a() | | {EXTERNAL LOCATION} | Option |
| main.rs:669:19:669:31 | thing.get_a() | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
| main.rs:669:19:669:31 | thing.get_a() | T | main.rs:668:24:668:41 | S |
| main.rs:670:9:670:9 | 0 | | {EXTERNAL LOCATION} | i32 |
| main.rs:670:9:670:9 | 0 | | {EXTERNAL LOCATION} | i64 |
| main.rs:676:55:676:59 | thing | | file://:0:0:0:0 | & |
| main.rs:676:55:676:59 | thing | &T | main.rs:676:25:676:52 | S |
| main.rs:678:13:678:15 | _ms | | {EXTERNAL LOCATION} | Option |
| main.rs:678:13:678:15 | _ms | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
| main.rs:678:13:678:15 | _ms | T | main.rs:676:25:676:52 | S |
| main.rs:678:19:678:30 | get_a(...) | | {EXTERNAL LOCATION} | Option |
| main.rs:678:19:678:30 | get_a(...) | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
| main.rs:678:19:678:30 | get_a(...) | T | main.rs:676:25:676:52 | S |
| main.rs:678:25:678:29 | thing | | file://:0:0:0:0 | & |
| main.rs:678:25:678:29 | thing | &T | main.rs:676:25:676:52 | S |
| main.rs:687:18:687:22 | SelfParam | | file://:0:0:0:0 | & |
@@ -2041,9 +2041,9 @@ inferType
| main.rs:695:17:695:37 | MyStruct {...} | | main.rs:681:5:683:5 | MyStruct |
| main.rs:695:35:695:35 | 0 | | {EXTERNAL LOCATION} | i32 |
| main.rs:696:13:696:15 | _ms | | {EXTERNAL LOCATION} | Option |
| main.rs:696:13:696:15 | _ms | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
| main.rs:696:13:696:15 | _ms | T | main.rs:681:5:683:5 | MyStruct |
| main.rs:696:19:696:27 | get_a(...) | | {EXTERNAL LOCATION} | Option |
| main.rs:696:19:696:27 | get_a(...) | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
| main.rs:696:19:696:27 | get_a(...) | T | main.rs:681:5:683:5 | MyStruct |
| main.rs:696:25:696:26 | &s | | file://:0:0:0:0 | & |
| main.rs:696:25:696:26 | &s | &T | main.rs:681:5:683:5 | MyStruct |
| main.rs:696:26:696:26 | s | | main.rs:681:5:683:5 | MyStruct |
@@ -4776,7 +4776,6 @@ inferType
| main.rs:2312:16:2312:21 | self.0 | | main.rs:2307:10:2307:17 | T |
| main.rs:2312:31:2312:35 | other | | main.rs:2305:5:2305:19 | S |
| main.rs:2312:31:2312:35 | other | T | main.rs:2307:10:2307:17 | T |
| main.rs:2312:31:2312:37 | other.0 | | main.rs:2267:5:2272:5 | Self [trait MyAdd] |
| main.rs:2312:31:2312:37 | other.0 | | main.rs:2307:10:2307:17 | T |
| main.rs:2320:19:2320:22 | SelfParam | | main.rs:2305:5:2305:19 | S |
| main.rs:2320:19:2320:22 | SelfParam | T | main.rs:2316:10:2316:17 | T |