-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Rust: Implement support for associated types accessed on type parameters #21273
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
base: main
Are you sure you want to change the base?
Changes from all 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 | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,65 @@ | ||||||
| /** | ||||||
| * Provides classes and helper predicates for associated types. | ||||||
| */ | ||||||
|
|
||||||
| private import rust | ||||||
| private import codeql.rust.internal.PathResolution | ||||||
| private import TypeMention | ||||||
| private import Type | ||||||
| private import TypeInference | ||||||
|
|
||||||
| /** An associated type, that is, a type alias in a trait block. */ | ||||||
| final class AssocType extends TypeAlias { | ||||||
| Trait trait; | ||||||
|
|
||||||
| AssocType() { this = trait.getAssocItemList().getAnAssocItem() } | ||||||
|
|
||||||
| Trait getTrait() { result = trait } | ||||||
|
|
||||||
| string getText() { result = this.getName().getText() } | ||||||
| } | ||||||
|
|
||||||
| /** Gets an associated type of `trait` or of a supertrait of `trait`. */ | ||||||
| AssocType getTraitAssocType(Trait trait) { | ||||||
| result = trait.getSupertrait*().getAssocItemList().getAnAssocItem() | ||||||
| } | ||||||
|
|
||||||
| /** Holds if `path` is of the form `<type as trait>::name` */ | ||||||
| predicate asTraitPath(Path path, TypeRepr typeRepr, Path traitPath, string name) { | ||||||
| exists(PathSegment segment | | ||||||
| segment = path.getQualifier().getSegment() and | ||||||
| typeRepr = segment.getTypeRepr() and | ||||||
| traitPath = segment.getTraitTypeRepr().getPath() and | ||||||
| name = path.getText() | ||||||
| ) | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * Holds if `assoc` is accessed on `tp` in `path`. | ||||||
| * | ||||||
| * That is this is the case when `path` is of the form `<tp as | ||||||
|
||||||
| * That is this is the case when `path` is of the form `<tp as | |
| * That is, this is the case when `path` is of the form `<tp as |
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -8,11 +8,7 @@ private import codeql.rust.elements.internal.generated.Raw | |||||||||||
| private import codeql.rust.elements.internal.generated.Synth | ||||||||||||
| private import codeql.rust.frameworks.stdlib.Stdlib | ||||||||||||
| private import codeql.rust.frameworks.stdlib.Builtins as Builtins | ||||||||||||
|
|
||||||||||||
| /** Gets a type alias of `trait` or of a supertrait of `trait`. */ | ||||||||||||
| private TypeAlias getTraitTypeAlias(Trait trait) { | ||||||||||||
| result = trait.getSupertrait*().getAssocItemList().getAnAssocItem() | ||||||||||||
| } | ||||||||||||
| private import AssociatedTypes | ||||||||||||
|
|
||||||||||||
| /** | ||||||||||||
| * Holds if a dyn trait type for the trait `trait` should have a type parameter | ||||||||||||
|
|
@@ -31,7 +27,7 @@ private TypeAlias getTraitTypeAlias(Trait trait) { | |||||||||||
| */ | ||||||||||||
| private predicate dynTraitTypeParameter(Trait trait, AstNode n) { | ||||||||||||
| trait = any(DynTraitTypeRepr dt).getTrait() and | ||||||||||||
| n = [trait.getGenericParamList().getATypeParam().(AstNode), getTraitTypeAlias(trait)] | ||||||||||||
| n = [trait.getGenericParamList().getATypeParam().(AstNode), getTraitAssocType(trait)] | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| cached | ||||||||||||
|
|
@@ -43,8 +39,11 @@ newtype TType = | |||||||||||
| TNeverType() or | ||||||||||||
| TUnknownType() or | ||||||||||||
| TTypeParamTypeParameter(TypeParam t) or | ||||||||||||
| TAssociatedTypeTypeParameter(Trait trait, TypeAlias typeAlias) { | ||||||||||||
| getTraitTypeAlias(trait) = typeAlias | ||||||||||||
| TAssociatedTypeTypeParameter(Trait trait, AssocType typeAlias) { | ||||||||||||
| getTraitAssocType(trait) = typeAlias | ||||||||||||
| } or | ||||||||||||
| TTypeParamAssociatedTypeTypeParameter(TypeParam tp, AssocType assoc) { | ||||||||||||
| tpAssociatedType(tp, assoc, _) | ||||||||||||
| } or | ||||||||||||
| TDynTraitTypeParameter(Trait trait, AstNode n) { dynTraitTypeParameter(trait, n) } or | ||||||||||||
| TImplTraitTypeParameter(ImplTraitTypeRepr implTrait, TypeParam tp) { | ||||||||||||
|
|
@@ -464,6 +463,52 @@ class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypePara | |||||||||||
| override Location getLocation() { result = typeAlias.getLocation() } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| /** | ||||||||||||
| * A type parameter corresponding to an associated type accessed on a type | ||||||||||||
| * parameter, for example `T::AssociatedType` where `T` is a type parameter. | ||||||||||||
| * | ||||||||||||
| * These type parameters are created when a function signature accesses an | ||||||||||||
| * associated type on a type parameter. For example, in | ||||||||||||
| * ```rust | ||||||||||||
| * fn foo<T: SomeTrait>(arg: T::Assoc) { } | ||||||||||||
| * ``` | ||||||||||||
| * we create a `TypeParamAssociatedTypeTypeParameter` for `Assoc` on `T` and the | ||||||||||||
| * mention `T::Assoc` resolves to this type parameter. If denoting the type | ||||||||||||
| * parameter by `T_Assoc` then the above function is treated as if it was | ||||||||||||
| * ```rust | ||||||||||||
| * fn foo<T: SomeTrait<Assoc = T_Assoc>, T_Assoc>(arg: T_Assoc) { } | ||||||||||||
|
||||||||||||
| * fn foo<T: SomeTrait<Assoc = T_Assoc>, T_Assoc>(arg: T_Assoc) { } | |
| * fn foo<T, T_Assoc>(arg: T_Assoc) | |
| * where | |
| * T: SomeTrait<Assoc = T_Assoc>, | |
| * { } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -6,6 +6,7 @@ private import codeql.rust.frameworks.stdlib.Stdlib | |||||
| private import Type | ||||||
| private import TypeAbstraction | ||||||
| private import TypeInference | ||||||
| private import AssociatedTypes | ||||||
|
|
||||||
| bindingset[trait, name] | ||||||
| pragma[inline_late] | ||||||
|
|
@@ -319,6 +320,22 @@ private module MkTypeMention<getAdditionalPathTypeAtSig/2 getAdditionalPathTypeA | |||||
| tp = TAssociatedTypeTypeParameter(resolved, alias) and | ||||||
| path.isEmpty() | ||||||
| ) | ||||||
| or | ||||||
| // If this path is a type parameter bound, then any associated types | ||||||
| // accessed on the type parameter, that originate from this bound, should | ||||||
| // be instantiated into the bound, as explained in the comment for | ||||||
| // `TypeParamAssociatedTypeTypeParameter`. | ||||||
| // ```rust | ||||||
| // fn foo<T: SomeTrait<Assoc = T_Assoc>, T_Assoc>(arg: T_Assoc) { } | ||||||
|
||||||
| // fn foo<T: SomeTrait<Assoc = T_Assoc>, T_Assoc>(arg: T_Assoc) { } | |
| // fn foo<T_Assoc, T: SomeTrait<Assoc = T_Assoc>>(arg: T_Assoc) { } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -260,13 +260,26 @@ mod type_param_access_associated_type { | |
| ) | ||
| } | ||
|
|
||
| // Associated type accessed on a type parameter of an impl block | ||
| impl<TI> Wrapper<TI> | ||
| where | ||
| TI: GetSet, | ||
| { | ||
| fn extract(&self) -> TI::Output { | ||
| self.0.get() // $ fieldof=Wrapper target=GetSet::get | ||
| } | ||
| } | ||
|
|
||
| pub fn test() { | ||
| let _o1 = tp_with_as(S); // $ target=tp_with_as MISSING: type=_o1:S3 | ||
| let _o2 = tp_without_as(S); // $ target=tp_without_as MISSING: type=_o2:S3 | ||
| let _o1 = tp_with_as(S); // $ target=tp_with_as type=_o1:S3 | ||
| let _o2 = tp_without_as(S); // $ target=tp_without_as type=_o2:S3 | ||
| let ( | ||
| _o3, // $ MISSING: type=_o3:S3 | ||
|
Contributor
Author
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. Note that we still can't infer this type where the associated type, |
||
| _o4, // $ MISSING: type=_o4:bool | ||
| _o4, // $ type=_o4:bool | ||
| ) = tp_assoc_from_supertrait(S); // $ target=tp_assoc_from_supertrait | ||
|
|
||
| let w = Wrapper(S); | ||
| let _extracted = w.extract(); // $ target=extract type=_extracted:S3 | ||
| } | ||
| } | ||
|
|
||
|
|
||
Check warning
Code scanning / CodeQL
Predicates starting with "get" or "as" should return a value Warning