-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Rust: Improve handling of Self type parameter
#20707
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would move this up before |
||
| // 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) | ||
| ) | ||
|
Comment on lines
181
to
189
|
||
| ) | ||
| } | ||
|
|
||
| /** Gets the type mention in this path for the type parameter `tp`, if any. */ | ||
| pragma[nomagic] | ||
| private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) { | ||
| /** | ||
| * 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)) and | ||
| result = this.getPositionalTypeArgument(pragma[only_bind_into](i), path) and | ||
| tp = this.resolveRootType().getPositionalTypeParameter(pragma[only_bind_into](i)) | ||
| ) | ||
| or | ||
| } | ||
|
|
||
| /** Gets the type mention in this path for the type parameter `tp`, if any. */ | ||
| pragma[nomagic] | ||
| private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) { | ||
| 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 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -652,6 +652,51 @@ mod type_parameter_bounds { | |
| } | ||
| } | ||
|
|
||
| mod trait_default_self_type_parameter { | ||
| // A trait with a type parameter that defaults to `Self`. | ||
| // trait TraitWithSelfTp<A = Self> { | ||
|
||
| trait TraitWithSelfTp<A = Option<Self>> { | ||
| // TraitWithSelfTp::get_a | ||
| fn get_a(&self) -> A; | ||
| } | ||
|
|
||
| fn get_a<A, T: TraitWithSelfTp<A>>(thing: &T) -> A { | ||
| thing.get_a() // $ target=TraitWithSelfTp::get_a | ||
| } | ||
|
|
||
| // 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 type=_ms:T.S | ||
| 0 | ||
| } | ||
|
|
||
| // The supertrait uses the default for `A` which contains `Self` | ||
| trait SubTraitOfTraitWithSelfTp: TraitWithSelfTp + Sized {} | ||
|
|
||
| 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 type=_ms:T.S | ||
| } | ||
|
|
||
| struct MyStruct { | ||
| value: i32, | ||
| } | ||
|
|
||
| // The implementing trait uses the default for `A` which contains `Self` | ||
| impl TraitWithSelfTp for MyStruct { | ||
| fn get_a(&self) -> Option<Self> { | ||
| Some(MyStruct { value: self.value }) // $ fieldof=MyStruct | ||
| } | ||
| } | ||
|
|
||
| impl SubTraitOfTraitWithSelfTp for MyStruct {} | ||
|
|
||
| pub fn test() { | ||
| let s = MyStruct { value: 0 }; | ||
| let _ms = get_a(&s); // $ target=get_a type=_ms:T.MyStruct | ||
| } | ||
| } | ||
|
|
||
| mod function_trait_bounds { | ||
| #[derive(Debug, Clone, Copy)] | ||
| struct MyThing<T> { | ||
|
|
@@ -2753,6 +2798,7 @@ fn main() { | |
| method_impl::g(method_impl::Foo {}, method_impl::Foo {}); // $ target=g | ||
| method_non_parametric_impl::f(); // $ target=f | ||
| method_non_parametric_trait_impl::f(); // $ target=f | ||
| trait_default_self_type_parameter::test(); // $ target=test | ||
| function_trait_bounds::f(); // $ target=f | ||
| associated_type_in_trait::f(); // $ target=f | ||
| generic_enum::f(); // $ target=f | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getSelfTraitBoundArg?