From fa59a8ae240fc5d2ce25a6a063067e3e0fd9ff6e Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Mon, 26 Jan 2026 14:55:59 +0100 Subject: [PATCH] Rust: Implement `TypeMention` for paths that access associated types on concrete types --- .../rust/internal/typeinference/Type.qll | 6 +- .../internal/typeinference/TypeInference.qll | 10 +- .../TypeInferenceConsistency.qll | 6 +- .../internal/typeinference/TypeMention.qll | 1200 +++++++++-------- .../type-inference/associated_types.rs | 32 +- .../type-inference/type-inference.expected | 53 + 6 files changed, 728 insertions(+), 579 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/Type.qll b/rust/ql/lib/codeql/rust/internal/typeinference/Type.qll index bf25d96cfa4..983e9a75ee5 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/Type.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/Type.qll @@ -75,7 +75,7 @@ abstract class Type extends TType { abstract TypeParameter getPositionalTypeParameter(int i); /** Gets the default type for the `i`th type parameter, if any. */ - TypeMention getTypeParameterDefault(int i) { none() } + TypeRepr getTypeParameterDefault(int i) { none() } /** * Gets a type parameter of this type. @@ -129,7 +129,7 @@ class DataType extends Type, TDataType { result = TTypeParamTypeParameter(typeItem.getGenericParamList().getTypeParam(i)) } - override TypeMention getTypeParameterDefault(int i) { + override TypeRepr getTypeParameterDefault(int i) { result = typeItem.getGenericParamList().getTypeParam(i).getDefaultType() } @@ -189,7 +189,7 @@ class TraitType extends Type, TTrait { result.(SelfTypeParameter).getTrait() = trait } - override TypeMention getTypeParameterDefault(int i) { + override TypeRepr getTypeParameterDefault(int i) { result = trait.getGenericParamList().getTypeParam(i).getDefaultType() } diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll index b051d60d8b4..e8b5c9c7a19 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll @@ -134,8 +134,8 @@ class TypePath = M1::TypePath; module TypePath = M1::TypePath; -private module Input2 implements InputSig2 { - TypeMention getABaseTypeMention(Type t) { none() } +private module Input2 implements InputSig2 { + PreTypeMention getABaseTypeMention(Type t) { none() } Type getATypeParameterConstraint(TypeParameter tp, TypePath path) { exists(TypeMention tm | result = tm.getTypeAt(path) | @@ -158,7 +158,7 @@ private module Input2 implements InputSig2 { * inference module for more information. */ predicate conditionSatisfiesConstraint( - TypeAbstraction abs, TypeMention condition, TypeMention constraint, boolean transitive + TypeAbstraction abs, PreTypeMention condition, PreTypeMention constraint, boolean transitive ) { // `impl` blocks implementing traits transitive = false and @@ -208,7 +208,7 @@ private module Input2 implements InputSig2 { } } -private module M2 = Make2; +private module M2 = Make2; import M2 @@ -1960,7 +1960,7 @@ private module MethodResolution { pragma[nomagic] predicate hasTypeQualifiedCandidate(ImplItemNode impl) { exists(getCallExprTypeQualifier(this, _)) and - CallExprImpl::getResolvedFunction(this) = impl.getASuccessor(_) + CallExprImpl::getResolvedFunction(this) = impl.getADescendant() } pragma[nomagic] diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInferenceConsistency.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInferenceConsistency.qll index e50c7393f72..8877962ec2d 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInferenceConsistency.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInferenceConsistency.qll @@ -10,7 +10,11 @@ private import TypeInference::Consistency as Consistency import TypeInference::Consistency query predicate illFormedTypeMention(TypeMention tm) { - Consistency::illFormedTypeMention(tm) and + // NOTE: We do not use `illFormedTypeMention` from the shared library as it is + // instantiated with `PreTypeMention` and we are interested in inconsistencies + // for `TypeMention`. + not exists(tm.getTypeAt(TypePath::nil())) and + exists(tm.getLocation()) and // avoid overlap with `PathTypeMention` not tm instanceof PathTypeReprMention and // known limitation for type mentions that would mention an escaping type parameter diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeMention.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeMention.qll index a5a9eae3715..738b823ca10 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeMention.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeMention.qll @@ -7,602 +7,694 @@ private import Type private import TypeAbstraction private import TypeInference -/** An AST node that may mention a type. */ -abstract class TypeMention extends AstNode { - /** Gets the type at `path` that this mention resolves to, if any. */ - pragma[nomagic] - abstract Type getTypeAt(TypePath path); - - /** Gets the type that this node resolves to, if any. */ - pragma[nomagic] - final Type getType() { result = this.getTypeAt(TypePath::nil()) } -} - -class TupleTypeReprMention extends TypeMention instanceof TupleTypeRepr { - override Type getTypeAt(TypePath path) { - path.isEmpty() and - result.(TupleType).getArity() = super.getNumberOfFields() - or - exists(TypePath suffix, int i | - result = super.getField(i).(TypeMention).getTypeAt(suffix) and - path = TypePath::cons(getTupleTypeParameter(super.getNumberOfFields(), i), suffix) - ) - } -} - -class ParenthesizedArgListMention extends TypeMention instanceof ParenthesizedArgList { - override Type getTypeAt(TypePath path) { - path.isEmpty() and - result.(TupleType).getArity() = super.getNumberOfTypeArgs() - or - exists(TypePath suffix, int index | - result = super.getTypeArg(index).getTypeRepr().(TypeMention).getTypeAt(suffix) and - path = TypePath::cons(getTupleTypeParameter(super.getNumberOfTypeArgs(), index), suffix) - ) - } -} - -class ArrayTypeReprMention extends TypeMention instanceof ArrayTypeRepr { - override Type getTypeAt(TypePath path) { - path.isEmpty() and - result instanceof ArrayType - or - exists(TypePath suffix | - result = super.getElementTypeRepr().(TypeMention).getTypeAt(suffix) and - path = TypePath::cons(getArrayTypeParameter(), suffix) - ) - } -} - -class RefTypeReprMention extends TypeMention instanceof RefTypeRepr { - private RefType resolveRootType() { - if super.isMut() then result instanceof RefMutType else result instanceof RefSharedType - } - - override Type getTypeAt(TypePath path) { - path.isEmpty() and result = this.resolveRootType() - or - exists(TypePath suffix | - result = super.getTypeRepr().(TypeMention).getTypeAt(suffix) and - path = TypePath::cons(this.resolveRootType().getPositionalTypeParameter(0), suffix) - ) - } -} - -class SliceTypeReprMention extends TypeMention instanceof SliceTypeRepr { - override Type getTypeAt(TypePath path) { - path.isEmpty() and - result instanceof SliceType - or - exists(TypePath suffix | - result = super.getTypeRepr().(TypeMention).getTypeAt(suffix) and - path = TypePath::cons(getSliceTypeParameter(), suffix) - ) - } -} - -abstract class PathTypeMention extends TypeMention, Path { - abstract Type resolvePathTypeAt(TypePath typePath); - - final override Type getTypeAt(TypePath typePath) { - result = this.resolvePathTypeAt(typePath) and - ( - not result instanceof TypeParameter - or - // Prevent type parameters from escaping their scope - this = result.(TypeParameter).getDeclaringItem().getAChild*().getADescendant() - ) - } -} - -class AliasPathTypeMention extends PathTypeMention { - TypeAlias resolved; - TypeMention rhs; - - AliasPathTypeMention() { - resolved = resolvePath(this) and - rhs = resolved.getTypeRepr() - } - - TypeItemNode getResolved() { result = resolved } - - /** - * Holds if this path resolved to a type alias with a rhs. that has the - * resulting type at `typePath`. - */ - override Type resolvePathTypeAt(TypePath typePath) { - result = rhs.getTypeAt(typePath) and - not result = pathGetTypeParameter(resolved, _) - or - exists(TypeParameter tp, TypeMention arg, TypePath prefix, TypePath suffix, int i | - tp = rhs.getTypeAt(prefix) and - tp = pathGetTypeParameter(resolved, pragma[only_bind_into](i)) and - arg = this.getSegment().getGenericArgList().getTypeArg(pragma[only_bind_into](i)) and - result = arg.getTypeAt(suffix) and - typePath = prefix.append(suffix) - ) - } -} +private signature Type getAdditionalPathTypeAtSig(Path p, TypePath typePath); /** - * Gets the `i`th type argument of `p`. + * Constructing the "type hierarchy" (that is, the trait hierarchy and how types + * implement traits) in the shared type inference library relies on type + * mentions. * - * Takes into account that variants can have type arguments applied to both the - * enum and the variant itself, e.g. `Option::::Some` is valid in addition - * to `Option::Some::`. + * Furthermore, resolving type mentions such as `::AssocType` + * relies on knowing how `Type` implements `Trait`. This makes type mentions and + * the type hierarchy recursively dependent, which causes non-monotonic + * recursion. + * + * To avoid the recursion, we parameterize the `TypeMention` by a predicate for + * resolving "additional" types for paths. A first instantiation uses the empty + * predicate to create `PreTypeMention` which is used to construct the type + * hierarchy. Afterwards, a second instantiation uses a predicate that can + * resolve paths that rely on the type hierarchy to create the actual + * `TypeMention`. */ -TypeMention getPathTypeArgument(Path p, int i) { - result = p.getSegment().getGenericArgList().getTypeArg(i) - or - resolvePath(p) instanceof Variant and - result = p.getQualifier().getSegment().getGenericArgList().getTypeArg(i) -} +private module MkTypeMention { + /** An AST node that may mention a type. */ + abstract private class TypeMentionImpl extends AstNode { + /** Gets the type at `path` that this type mention resolves to, if any. */ + pragma[nomagic] + abstract Type getTypeAt(TypePath path); -class NonAliasPathTypeMention extends PathTypeMention { - TypeItemNode resolved; - - NonAliasPathTypeMention() { - resolved = [resolvePath(this), resolvePath(this).(Variant).getEnum().(TypeItemNode)] and - not exists(resolved.(TypeAlias).getTypeRepr()) and - not this = any(ImplItemNode i).getASelfPath() // handled by `ImplSelfMention` + /** Gets the root type that this type mention resolves to, if any. */ + pragma[nomagic] + final Type getType() { result = this.getTypeAt(TypePath::nil()) } } - TypeItemNode getResolved() { result = resolved } + final class TypeMention = TypeMentionImpl; - pragma[nomagic] - private TypeMention getAssocTypeArg(string name) { - result = this.getSegment().getGenericArgList().getAssocTypeArg(name) - } - - /** - * 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 getSelfTraitBoundArg() { - 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 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(getPathTypeArgument(this, i)) and - // Defaults only apply to type mentions in type annotations - this = any(PathTypeRepr ptp).getPath().getQualifier*() and - exists(Type ty, TypePath prefix | - ty = this.resolveRootType().getTypeParameterDefault(i).getTypeAt(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.getSelfTraitBoundArg().getTypeAt(suffix) - ) - ) - } - - private Type getPositionalTypeArgument(int i, TypePath path) { - result = getPathTypeArgument(this, i).getTypeAt(path) - or - result = this.getDefaultPositionalTypeArgument(i, path) - } - - /** - * 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)) - ) - or - // Handle the special syntactic sugar for function traits. The syntactic - // form is detected by the presence of a parenthesized argument list which - // is a mandatory part of the syntax [1]. - // - // For now we only support `FnOnce` as we can't support the "inherited" - // associated types of `Fn` and `FnMut` yet. - // - // [1]: https://doc.rust-lang.org/reference/paths.html#grammar-TypePathFn - exists(AnyFnTrait t, PathSegment s | - t = resolved and - s = this.getSegment() and - s.hasParenthesizedArgList() - | - tp = TTypeParamTypeParameter(t.getTypeParam()) and - result = s.getParenthesizedArgList().(TypeMention).getTypeAt(path) + class TupleTypeReprMention extends TypeMentionImpl instanceof TupleTypeRepr { + override Type getTypeAt(TypePath path) { + path.isEmpty() and + result.(TupleType).getArity() = super.getNumberOfFields() or - tp = TAssociatedTypeTypeParameter(t, any(FnOnceTrait tr).getOutputType()) and + exists(TypePath suffix, int i | + result = super.getField(i).(TypeMention).getTypeAt(suffix) and + path = TypePath::cons(getTupleTypeParameter(super.getNumberOfFields(), i), suffix) + ) + } + } + + class ParenthesizedArgListMention extends TypeMentionImpl instanceof ParenthesizedArgList { + override Type getTypeAt(TypePath path) { + path.isEmpty() and + result.(TupleType).getArity() = super.getNumberOfTypeArgs() + or + exists(TypePath suffix, int index | + result = super.getTypeArg(index).getTypeRepr().(TypeMention).getTypeAt(suffix) and + path = TypePath::cons(getTupleTypeParameter(super.getNumberOfTypeArgs(), index), suffix) + ) + } + } + + class ArrayTypeReprMention extends TypeMentionImpl instanceof ArrayTypeRepr { + override Type getTypeAt(TypePath path) { + path.isEmpty() and + result instanceof ArrayType + or + exists(TypePath suffix | + result = super.getElementTypeRepr().(TypeMention).getTypeAt(suffix) and + path = TypePath::cons(getArrayTypeParameter(), suffix) + ) + } + } + + class RefTypeReprMention extends TypeMentionImpl instanceof RefTypeRepr { + private RefType resolveRootType() { + if super.isMut() then result instanceof RefMutType else result instanceof RefSharedType + } + + override Type getTypeAt(TypePath path) { + path.isEmpty() and result = this.resolveRootType() + or + exists(TypePath suffix | + result = super.getTypeRepr().(TypeMention).getTypeAt(suffix) and + path = TypePath::cons(this.resolveRootType().getPositionalTypeParameter(0), suffix) + ) + } + } + + class SliceTypeReprMention extends TypeMentionImpl instanceof SliceTypeRepr { + override Type getTypeAt(TypePath path) { + path.isEmpty() and + result instanceof SliceType + or + exists(TypePath suffix | + result = super.getTypeRepr().(TypeMention).getTypeAt(suffix) and + path = TypePath::cons(getSliceTypeParameter(), suffix) + ) + } + } + + abstract class PathTypeMention extends TypeMentionImpl, Path { + abstract Type resolvePathTypeAt(TypePath typePath); + + final override Type getTypeAt(TypePath typePath) { + result = getAdditionalPathTypeAt(this, typePath) + or + result = this.resolvePathTypeAt(typePath) and ( - result = s.getRetType().getTypeRepr().(TypeMention).getTypeAt(path) + not result instanceof TypeParameter or - // When the `-> ...` return type is omitted, it defaults to `()`. - not s.hasRetType() and - result instanceof UnitType and + // Prevent type parameters from escaping their scope + this = result.(TypeParameter).getDeclaringItem().getAChild*().getADescendant() + ) + } + } + + class AdditionalPathTypeMention extends PathTypeMention { + AdditionalPathTypeMention() { exists(getAdditionalPathTypeAt(this, _)) } + + override Type resolvePathTypeAt(TypePath typePath) { + result = getAdditionalPathTypeAt(this, typePath) + } + } + + class AliasPathTypeMention extends PathTypeMention { + TypeAlias resolved; + TypeMention rhs; + + AliasPathTypeMention() { + resolved = resolvePath(this) and + rhs = resolved.getTypeRepr() + } + + TypeItemNode getResolved() { result = resolved } + + /** + * Holds if this path resolved to a type alias with a rhs. that has the + * resulting type at `typePath`. + */ + override Type resolvePathTypeAt(TypePath typePath) { + result = rhs.getTypeAt(typePath) and + not result = pathGetTypeParameter(resolved, _) + or + exists(TypeParameter tp, TypeMention arg, TypePath prefix, TypePath suffix, int i | + tp = rhs.getTypeAt(prefix) and + tp = pathGetTypeParameter(resolved, pragma[only_bind_into](i)) and + arg = this.getSegment().getGenericArgList().getTypeArg(pragma[only_bind_into](i)) and + result = arg.getTypeAt(suffix) and + typePath = prefix.append(suffix) + ) + } + } + + /** + * Gets the `i`th type argument of `p`. + * + * Takes into account that variants can have type arguments applied to both the + * enum and the variant itself, e.g. `Option::::Some` is valid in addition + * to `Option::Some::`. + */ + TypeMention getPathTypeArgument(Path p, int i) { + result = p.getSegment().getGenericArgList().getTypeArg(i) + or + resolvePath(p) instanceof Variant and + result = p.getQualifier().getSegment().getGenericArgList().getTypeArg(i) + } + + class NonAliasPathTypeMention extends PathTypeMention { + TypeItemNode resolved; + + NonAliasPathTypeMention() { + resolved = [resolvePath(this), resolvePath(this).(Variant).getEnum().(TypeItemNode)] and + not exists(resolved.(TypeAlias).getTypeRepr()) and + not exists(getAdditionalPathTypeAt(this, _)) and // handled by `AdditionalPathTypeMention` + not this = any(ImplItemNode i).getASelfPath() // handled by `ImplSelfMention` + } + + TypeItemNode getResolved() { result = resolved } + + pragma[nomagic] + private TypeMention getAssocTypeArg(string name) { + result = this.getSegment().getGenericArgList().getAssocTypeArg(name) + } + + /** + * 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 getSelfTraitBoundArg() { + 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 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(getPathTypeArgument(this, i)) and + // Defaults only apply to type mentions in type annotations + this = any(PathTypeRepr ptp).getPath().getQualifier*() and + exists(Type ty, TypePath prefix | + ty = this.resolveRootType().getTypeParameterDefault(i).(TypeMention).getTypeAt(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.getSelfTraitBoundArg().getTypeAt(suffix) + ) + ) + } + + private Type getPositionalTypeArgument(int i, TypePath path) { + result = getPathTypeArgument(this, i).getTypeAt(path) + or + result = this.getDefaultPositionalTypeArgument(i, path) + } + + /** + * 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)) + ) + or + // Handle the special syntactic sugar for function traits. The syntactic + // form is detected by the presence of a parenthesized argument list which + // is a mandatory part of the syntax [1]. + // + // For now we only support `FnOnce` as we can't support the "inherited" + // associated types of `Fn` and `FnMut` yet. + // + // [1]: https://doc.rust-lang.org/reference/paths.html#grammar-TypePathFn + exists(AnyFnTrait t, PathSegment s | + t = resolved and + s = this.getSegment() and + s.hasParenthesizedArgList() + | + tp = TTypeParamTypeParameter(t.getTypeParam()) and + result = s.getParenthesizedArgList().(TypeMention).getTypeAt(path) + or + tp = TAssociatedTypeTypeParameter(t, any(FnOnceTrait tr).getOutputType()) and + ( + result = s.getRetType().getTypeRepr().(TypeMention).getTypeAt(path) + or + // When the `-> ...` return type is omitted, it defaults to `()`. + not s.hasRetType() and + result instanceof UnitType and + path.isEmpty() + ) + ) + or + // If `path` is the supertrait of a trait block then any associated types + // of the supertrait should be instantiated with the subtrait's + // corresponding copies. + // + // As an example, for + // ```rust + // trait Sub: Super { + // // ^^^^^ this + // ``` + // we do something to the effect of: + // ```rust + // trait Sub: Super + // ``` + // Where `Assoc` is an associated type of `Super` and `Assoc[Sub]` denotes + // the copy of the type parameter inherited by `Sub`. + exists(Trait subtrait, TypeAlias alias | + subtrait.getATypeBound().getTypeRepr().(PathTypeRepr).getPath() = this and + result = TAssociatedTypeTypeParameter(subtrait, alias) and + tp = TAssociatedTypeTypeParameter(resolved, alias) and path.isEmpty() ) - ) - or - // If `path` is the supertrait of a trait block then any associated types - // of the supertrait should be instantiated with the subtrait's - // corresponding copies. - // - // As an example, for - // ```rust - // trait Sub: Super { - // // ^^^^^ this - // ``` - // we do something to the effect of: - // ```rust - // trait Sub: Super - // ``` - // Where `Assoc` is an associated type of `Super` and `Assoc[Sub]` denotes - // the copy of the type parameter inherited by `Sub`. - exists(Trait subtrait, TypeAlias alias | - subtrait.getATypeBound().getTypeRepr().(PathTypeRepr).getPath() = this and - result = TAssociatedTypeTypeParameter(subtrait, alias) and - tp = TAssociatedTypeTypeParameter(resolved, alias) and - path.isEmpty() - ) - } + } - bindingset[name] - private TypeAlias getResolvedAlias(string name) { - result = resolved.(TraitItemNode).getAssocItem(name) - } + bindingset[name] + private TypeAlias getResolvedAlias(string name) { + result = resolved.(TraitItemNode).getAssocItem(name) + } - bindingset[name] - private TypeAlias getResolvedTraitAssocType(string name) { - result = resolved.(TraitItemNode).getASuccessor(name) - } + bindingset[name] + private TypeAlias getResolvedTraitAssocType(string name) { + result = resolved.(TraitItemNode).getASuccessor(name) + } - /** Gets the type mention in this path for the type parameter `tp`, if any. */ - pragma[nomagic] - private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) { - exists(TypeAlias alias, string name | - result = this.getAssocTypeArg(name) and - tp = TAssociatedTypeTypeParameter(resolved, alias) and - alias = this.getResolvedTraitAssocType(name) - ) - or - // If `path` is the trait of an `impl` block then any associated types - // defined in the `impl` block are type arguments to the trait. - // - // For instance, for a trait implementation like this - // ```rust - // impl MyTrait for MyType { - // ^^^^^^^ path - // type AssociatedType = i64 - // ^^^ result - // // ... - // } - // ``` - // the rhs. of the type alias is a type argument to the trait. - exists(ImplItemNode impl, TypeAlias alias, string name | - this = impl.getTraitPath() and - alias = impl.getASuccessor(name) and - result = alias.getTypeRepr() and - tp = TAssociatedTypeTypeParameter(resolved, this.getResolvedAlias(name)) - ) + /** Gets the type mention in this path for the type parameter `tp`, if any. */ + pragma[nomagic] + private TypeMention getTypeMentionImplForTypeParameter(TypeParameter tp) { + exists(TypeAlias alias, string name | + result = this.getAssocTypeArg(name) and + tp = TAssociatedTypeTypeParameter(resolved, alias) and + alias = this.getResolvedTraitAssocType(name) + ) + or + // If `path` is the trait of an `impl` block then any associated types + // defined in the `impl` block are type arguments to the trait. + // + // For instance, for a trait implementation like this + // ```rust + // impl MyTrait for MyType { + // ^^^^^^^ path + // type AssociatedType = i64 + // ^^^ result + // // ... + // } + // ``` + // the rhs. of the type alias is a type argument to the trait. + exists(ImplItemNode impl, TypeAlias alias, string name | + this = impl.getTraitPath() and + alias = impl.getASuccessor(name) and + result = alias.getTypeRepr() and + tp = TAssociatedTypeTypeParameter(resolved, this.getResolvedAlias(name)) + ) + } + + pragma[nomagic] + private Type resolveRootType() { + result = TDataType(resolved) + or + exists(TraitItemNode trait | trait = resolved | + // If this is a `Self` path, then it resolves to the implicit `Self` + // type parameter, otherwise it is a trait bound. + if this = trait.getASelfPath() + then result = TSelfTypeParameter(trait) + else result = TTrait(trait) + ) + or + result = TTypeParamTypeParameter(resolved) + or + // Handles paths of the form `Self::AssocType` within a trait block + result = TAssociatedTypeTypeParameter(resolvePath(this.getQualifier()), resolved) + } + + override Type resolvePathTypeAt(TypePath typePath) { + typePath.isEmpty() and + result = this.resolveRootType() + or + exists(TypeParameter tp, TypePath suffix | typePath = TypePath::cons(tp, suffix) | + result = this.getTypeForTypeParameterAt(tp, suffix) + or + result = this.getTypeMentionImplForTypeParameter(tp).getTypeAt(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.getSelfTraitBoundArg().getTypeAt(suffix) and + typePath = TypePath::cons(TSelfTypeParameter(resolved), suffix) + ) + or + not this.getSegment().hasTraitTypeRepr() and + result = this.getSegment().getTypeRepr().(TypeMention).getTypeAt(typePath) + } } pragma[nomagic] - private Type resolveRootType() { - result = TDataType(resolved) - or - exists(TraitItemNode trait | trait = resolved | - // If this is a `Self` path, then it resolves to the implicit `Self` - // type parameter, otherwise it is a trait bound. - if this = trait.getASelfPath() - then result = TSelfTypeParameter(trait) - else result = TTrait(trait) - ) - or - result = TTypeParamTypeParameter(resolved) - or - result = TAssociatedTypeTypeParameter(resolvePath(this.getQualifier()), resolved) + Type resolveImplSelfTypeAt(Impl i, TypePath path) { + result = i.getSelfTy().(TypeMention).getTypeAt(path) } - override Type resolvePathTypeAt(TypePath typePath) { - typePath.isEmpty() and - result = this.resolveRootType() - or - exists(TypeParameter tp, TypePath suffix | typePath = TypePath::cons(tp, suffix) | - result = this.getTypeForTypeParameterAt(tp, suffix) + class ImplSelfMention extends PathTypeMention { + private ImplItemNode impl; + + ImplSelfMention() { this = impl.getASelfPath() } + + override Type resolvePathTypeAt(TypePath typePath) { + result = resolveImplSelfTypeAt(impl, typePath) + } + } + + class PathTypeReprMention extends TypeMentionImpl, PathTypeRepr { + private PathTypeMention path; + + PathTypeReprMention() { path = this.getPath() } + + override Type getTypeAt(TypePath typePath) { result = path.getTypeAt(typePath) } + } + + class ImplTraitTypeReprMention extends TypeMentionImpl instanceof ImplTraitTypeRepr { + override Type getTypeAt(TypePath typePath) { + typePath.isEmpty() and + result.(ImplTraitType).getImplTraitTypeRepr() = this or - result = this.getTypeMentionForTypeParameter(tp).getTypeAt(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.getSelfTraitBoundArg().getTypeAt(suffix) and - typePath = TypePath::cons(TSelfTypeParameter(resolved), suffix) - ) - or - not this.getSegment().hasTraitTypeRepr() and - result = this.getSegment().getTypeRepr().(TypeMention).getTypeAt(typePath) + exists(ImplTraitTypeParameter tp | + this = tp.getImplTraitTypeRepr() and + typePath = TypePath::singleton(tp) and + result = TTypeParamTypeParameter(tp.getTypeParam()) + ) + } } -} -pragma[nomagic] -Type resolveImplSelfTypeAt(Impl i, TypePath path) { - result = i.getSelfTy().(TypeMention).getTypeAt(path) -} - -class ImplSelfMention extends PathTypeMention { - private ImplItemNode impl; - - ImplSelfMention() { this = impl.getASelfPath() } - - override Type resolvePathTypeAt(TypePath typePath) { - result = resolveImplSelfTypeAt(impl, typePath) + private TypeParameter pathGetTypeParameter(TypeAlias alias, int i) { + result = TTypeParamTypeParameter(alias.getGenericParamList().getTypeParam(i)) } -} -class PathTypeReprMention extends TypeMention, PathTypeRepr { - private PathTypeMention path; - - PathTypeReprMention() { path = this.getPath() } - - override Type getTypeAt(TypePath typePath) { result = path.getTypeAt(typePath) } -} - -class ImplTraitTypeReprMention extends TypeMention instanceof ImplTraitTypeRepr { - override Type getTypeAt(TypePath typePath) { - typePath.isEmpty() and - result.(ImplTraitType).getImplTraitTypeRepr() = this - or - exists(ImplTraitTypeParameter tp | - this = tp.getImplTraitTypeRepr() and - typePath = TypePath::singleton(tp) and - result = TTypeParamTypeParameter(tp.getTypeParam()) - ) + // Used to represent implicit `Self` type arguments in traits and `impl` blocks, + // see `PathMention` for details. + class TypeParamMention extends TypeMentionImpl instanceof TypeParam { + override Type getTypeAt(TypePath typePath) { + typePath.isEmpty() and + result = TTypeParamTypeParameter(this) + } } -} -private TypeParameter pathGetTypeParameter(TypeAlias alias, int i) { - result = TTypeParamTypeParameter(alias.getGenericParamList().getTypeParam(i)) -} - -// Used to represent implicit `Self` type arguments in traits and `impl` blocks, -// see `PathMention` for details. -class TypeParamMention extends TypeMention instanceof TypeParam { - override Type getTypeAt(TypePath typePath) { - typePath.isEmpty() and - result = TTypeParamTypeParameter(this) - } -} - -class TraitMention extends TypeMention instanceof TraitItemNode { - override Type getTypeAt(TypePath typePath) { - 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 | - typePath = TypePath::singleton(result) and - result = TAssociatedTypeTypeParameter(this, alias) - ) - or - exists(TypeParam tp | - tp = super.getTypeParam(_) and - typePath = TypePath::singleton(result) and - result = TTypeParamTypeParameter(tp) - ) - } -} - -// NOTE: Since the implicit type parameter for the self type parameter never -// appears in the AST, we (somewhat arbitrarily) choose the name of a trait as a -// type mention. This works because there is a one-to-one correspondence between -// a trait and its name. -class SelfTypeParameterMention extends TypeMention instanceof Name { - Trait trait; - - SelfTypeParameterMention() { trait.getName() = this } - - Trait getTrait() { result = trait } - - override Type getTypeAt(TypePath typePath) { - typePath.isEmpty() and - result = TSelfTypeParameter(trait) - } -} - -/** - * Gets the type at `path` of the type being implemented in `i`, when - * `i` is an `impl` block, or the synthetic `Self` type parameter when - * `i` is a trait. - */ -pragma[nomagic] -Type resolveImplOrTraitType(ImplOrTraitItemNode i, TypePath path) { - result = resolveImplSelfTypeAt(i, path) - or - result = TSelfTypeParameter(i) and path.isEmpty() -} - -pragma[nomagic] -private ImplOrTraitItemNode getSelfParamEnclosingImplOrTrait(SelfParam self) { - self = result.getAnAssocItem().(Function).getSelfParam() -} - -/** - * An element used to represent the type of a `self` parameter that uses [shorthand - * syntax][1], which is sugar for an explicit annotation. - * - * [1]: https://doc.rust-lang.org/stable/reference/items/associated-items.html#r-associated.fn.method.self-pat-shorthands - */ -class ShorthandSelfParameterMention extends TypeMention instanceof SelfParam { - private ImplOrTraitItemNode encl; - - ShorthandSelfParameterMention() { - not super.hasTypeRepr() and - encl = getSelfParamEnclosingImplOrTrait(this) and - ( - not encl instanceof Impl + class TraitMention extends TypeMentionImpl instanceof TraitItemNode { + override Type getTypeAt(TypePath typePath) { + typePath.isEmpty() and + result = TTrait(this) or - // avoid generating a type mention if the type being implemented does not have a type mention - encl.(Impl).getSelfTy() instanceof TypeMention - ) + // 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 | + typePath = TypePath::singleton(result) and + result = TAssociatedTypeTypeParameter(this, alias) + ) + or + exists(TypeParam tp | + tp = super.getTypeParam(_) and + typePath = TypePath::singleton(result) and + result = TTypeParamTypeParameter(tp) + ) + } } - private Type resolveSelfType(TypePath path) { result = resolveImplOrTraitType(encl, path) } + // NOTE: Since the implicit type parameter for the self type parameter never + // appears in the AST, we (somewhat arbitrarily) choose the name of a trait as a + // type mention. This works because there is a one-to-one correspondence between + // a trait and its name. + class SelfTypeParameterMention extends TypeMentionImpl instanceof Name { + Trait trait; - private RefType resolveSelfRefRootType() { - super.isRef() and - if super.isMut() then result instanceof RefMutType else result instanceof RefSharedType + SelfTypeParameterMention() { trait.getName() = this } + + Trait getTrait() { result = trait } + + override Type getTypeAt(TypePath typePath) { + typePath.isEmpty() and + result = TSelfTypeParameter(trait) + } } - override Type getTypeAt(TypePath typePath) { - // `fn f(&self, ...)` - typePath.isEmpty() and - result = this.resolveSelfRefRootType() + /** + * Gets the type at `path` of the type being implemented in `i`, when + * `i` is an `impl` block, or the synthetic `Self` type parameter when + * `i` is a trait. + */ + pragma[nomagic] + Type resolveImplOrTraitType(ImplOrTraitItemNode i, TypePath path) { + result = resolveImplSelfTypeAt(i, path) or - exists(TypePath suffix | - result = this.resolveSelfType(suffix) and - typePath = TypePath::cons(this.resolveSelfRefRootType().getPositionalTypeParameter(0), suffix) - ) + result = TSelfTypeParameter(i) and path.isEmpty() + } + + pragma[nomagic] + private ImplOrTraitItemNode getSelfParamEnclosingImplOrTrait(SelfParam self) { + self = result.getAnAssocItem().(Function).getSelfParam() + } + + /** + * An element used to represent the type of a `self` parameter that uses [shorthand + * syntax][1], which is sugar for an explicit annotation. + * + * [1]: https://doc.rust-lang.org/stable/reference/items/associated-items.html#r-associated.fn.method.self-pat-shorthands + */ + class ShorthandSelfParameterMention extends TypeMentionImpl instanceof SelfParam { + private ImplOrTraitItemNode encl; + + ShorthandSelfParameterMention() { + not super.hasTypeRepr() and + encl = getSelfParamEnclosingImplOrTrait(this) and + ( + not encl instanceof Impl + or + // avoid generating a type mention if the type being implemented does not have a type mention + encl.(Impl).getSelfTy() instanceof TypeMentionImpl + ) + } + + private Type resolveSelfType(TypePath path) { result = resolveImplOrTraitType(encl, path) } + + private RefType resolveSelfRefRootType() { + super.isRef() and + if super.isMut() then result instanceof RefMutType else result instanceof RefSharedType + } + + override Type getTypeAt(TypePath typePath) { + // `fn f(&self, ...)` + typePath.isEmpty() and + result = this.resolveSelfRefRootType() + or + exists(TypePath suffix | + result = this.resolveSelfType(suffix) and + typePath = + TypePath::cons(this.resolveSelfRefRootType().getPositionalTypeParameter(0), suffix) + ) + or + // `fn f(self, ...)` + not super.isRef() and + result = this.resolveSelfType(typePath) + } + } + + pragma[nomagic] + TypeMention getSelfParamTypeMention(SelfParam self) { + result = self.(ShorthandSelfParameterMention) or - // `fn f(self, ...)` - not super.isRef() and - result = this.resolveSelfType(typePath) + result = self.getTypeRepr() + } + + /** + * An element used to represent the implicit `()` return type of a function. + * + * Since the implicit type does not appear in the AST, we (somewhat arbitrarily) + * choose the name of the function as a type mention. This works because there + * is a one-to-one correspondence between a function and its name. + */ + class ShorthandReturnTypeMention extends TypeMentionImpl instanceof Name { + private Function f; + + ShorthandReturnTypeMention() { + this = f.getName() and + not f.getRetType().hasTypeRepr() + } + + override Type getTypeAt(TypePath typePath) { + typePath.isEmpty() and + result instanceof UnitType + } + } + + pragma[nomagic] + TypeMention getReturnTypeMention(Function f) { + result.(ShorthandReturnTypeMention) = f.getName() + or + result = f.getRetType().getTypeRepr() + } + + class DynTraitTypeReprMention extends TypeMentionImpl instanceof DynTraitTypeRepr { + private DynTraitType dynType; + + DynTraitTypeReprMention() { + // This excludes `DynTraitTypeRepr` elements where `getTrait` is not + // defined, i.e., where path resolution can't find a trait. + dynType.getTrait() = super.getTrait() + } + + override Type getTypeAt(TypePath path) { + path.isEmpty() and + result = dynType + or + exists(DynTraitTypeParameter tp, TypePath path0, TypePath suffix | + dynType = tp.getDynTraitType() and + path = TypePath::cons(tp, suffix) and + result = super.getTypeBoundList().getBound(0).getTypeRepr().(TypeMention).getTypeAt(path0) and + path0.isCons(tp.getTraitTypeParameter(), suffix) + ) + } + } + + // We want a type of the form `dyn Trait` to implement `Trait`. If `Trait` has + // type parameters then `dyn Trait` has equivalent type parameters and the + // implementation should be abstracted over them. + // + // Intuitively we want something to the effect of: + // ``` + // impl Trait for (dyn Trait) + // ``` + // To achieve this: + // - `DynTypeAbstraction` is an abstraction over the type parameters of the trait. + // - `DynTypeBoundListMention` (this class) is a type mention which has `dyn + // Trait` at the root and which for every type parameter of `dyn Trait` has the + // corresponding type parameter of the trait. + // - `TraitMention` (which is used for other things as well) is a type mention + // for the trait applied to its own type parameters. + // + // We arbitrarily use the `TypeBoundList` inside `DynTraitTypeRepr` to encode + // this type mention, since it doesn't syntactically appear in the AST. This + // works because there is a one-to-one correspondence between a trait object and + // its list of type bounds. + class DynTypeBoundListMention extends TypeMentionImpl instanceof TypeBoundList { + private Trait trait; + + DynTypeBoundListMention() { + exists(DynTraitTypeRepr dyn | + // We only need this type mention when the `dyn Trait` is a type + // abstraction, that is, when it's "canonical" and used in + // `conditionSatisfiesConstraint`. + dyn instanceof DynTypeAbstraction and + this = dyn.getTypeBoundList() and + trait = dyn.getTrait() + ) + } + + override Type getTypeAt(TypePath path) { + path.isEmpty() and + result.(DynTraitType).getTrait() = trait + or + exists(DynTraitTypeParameter tp | + trait = tp.getTrait() and + path = TypePath::singleton(tp) and + result = tp.getTraitTypeParameter() + ) + } + } + + class NeverTypeReprMention extends TypeMentionImpl, NeverTypeRepr { + override Type getTypeAt(TypePath path) { result = TNeverType() and path.isEmpty() } + } + + class PtrTypeReprMention extends TypeMentionImpl instanceof PtrTypeRepr { + private PtrType resolveRootType() { + super.isConst() and result instanceof PtrConstType + or + super.isMut() and result instanceof PtrMutType + } + + override Type getTypeAt(TypePath path) { + path.isEmpty() and result = this.resolveRootType() + or + exists(TypePath suffix | + result = super.getTypeRepr().(TypeMention).getTypeAt(suffix) and + path = TypePath::cons(this.resolveRootType().getPositionalTypeParameter(0), suffix) + ) + } } } -pragma[nomagic] -TypeMention getSelfParamTypeMention(SelfParam self) { - result = self.(ShorthandSelfParameterMention) - or - result = self.getTypeRepr() +private Type preGetAdditionalPathTypeAt(Path p, TypePath typePath) { none() } + +private module PreTypeMention = MkTypeMention; + +class PreTypeMention = PreTypeMention::TypeMention; + +/** + * Holds if `path` accesses an associated type `alias` from `trait` on a + * concrete type given by `tm`. + */ +predicate pathConcreteTypeAssocType(Path path, PreTypeMention tm, Trait trait, TypeAlias alias) { + exists(Path qualifier | + qualifier = path.getQualifier() and + not resolvePath(tm.(PathTypeRepr).getPath()) instanceof TypeParam + | + // path of the form `::AssocType` + // ^^^ tm ^^^^^^^^^ name + exists(string name | + name = path.getSegment().getIdentifier().getText() and + tm = qualifier.getSegment().getTypeRepr() and + trait = resolvePath(qualifier.getSegment().getTraitTypeRepr().getPath()) and + trait.(TraitItemNode).getAssocItem(name) = alias + ) + or + // path of the form `Self::AssocType` within an `impl` block + // tm ^^^^ ^^^^^^^^^ name + exists(ImplItemNode impl | + alias = resolvePath(path) and + qualifier = impl.getASelfPath() and + tm = impl.(Impl).getSelfTy() and + trait.(TraitItemNode).getAnAssocItem() = alias + ) + ) +} + +private module PathSatisfiesConstraint implements SatisfiesConstraintInputSig { + predicate relevantConstraint(PreTypeMention tm, Type constraint) { + pathConcreteTypeAssocType(_, tm, constraint.(TraitType).getTrait(), _) + } } /** - * An element used to represent the implicit `()` return type of a function. - * - * Since the implicit type does not appear in the AST, we (somewhat arbitrarily) - * choose the name of the function as a type mention. This works because there - * is a one-to-one correspondence between a function and its name. + * Gets the type of `path` at `typePath` when `path` accesses an associated type + * on a concrete type. */ -class ShorthandReturnTypeMention extends TypeMention instanceof Name { - private Function f; - - ShorthandReturnTypeMention() { - this = f.getName() and - not f.getRetType().hasTypeRepr() - } - - override Type getTypeAt(TypePath typePath) { - typePath.isEmpty() and - result instanceof UnitType - } +private Type getPathConcreteAssocTypeAt(Path path, TypePath typePath) { + exists(PreTypeMention tm, TraitItemNode t, TypeAlias alias, TypePath path0 | + pathConcreteTypeAssocType(path, tm, t, alias) and + SatisfiesConstraint::satisfiesConstraintType(tm, + TTrait(t), path0, result) and + path0.isCons(TAssociatedTypeTypeParameter(t, alias), typePath) + ) } -pragma[nomagic] -TypeMention getReturnTypeMention(Function f) { - result.(ShorthandReturnTypeMention) = f.getName() - or - result = f.getRetType().getTypeRepr() -} - -class DynTraitTypeReprMention extends TypeMention instanceof DynTraitTypeRepr { - private DynTraitType dynType; - - DynTraitTypeReprMention() { - // This excludes `DynTraitTypeRepr` elements where `getTrait` is not - // defined, i.e., where path resolution can't find a trait. - dynType.getTrait() = super.getTrait() - } - - override Type getTypeAt(TypePath path) { - path.isEmpty() and - result = dynType - or - exists(DynTraitTypeParameter tp, TypePath path0, TypePath suffix | - dynType = tp.getDynTraitType() and - path = TypePath::cons(tp, suffix) and - result = super.getTypeBoundList().getBound(0).getTypeRepr().(TypeMention).getTypeAt(path0) and - path0.isCons(tp.getTraitTypeParameter(), suffix) - ) - } -} - -// We want a type of the form `dyn Trait` to implement `Trait`. If `Trait` has -// type parameters then `dyn Trait` has equivalent type parameters and the -// implementation should be abstracted over them. -// -// Intuitively we want something to the effect of: -// ``` -// impl Trait for (dyn Trait) -// ``` -// To achieve this: -// - `DynTypeAbstraction` is an abstraction over the type parameters of the trait. -// - `DynTypeBoundListMention` (this class) is a type mention which has `dyn -// Trait` at the root and which for every type parameter of `dyn Trait` has the -// corresponding type parameter of the trait. -// - `TraitMention` (which is used for other things as well) is a type mention -// for the trait applied to its own type parameters. -// -// We arbitrarily use the `TypeBoundList` inside `DynTraitTypeRepr` to encode -// this type mention, since it doesn't syntactically appear in the AST. This -// works because there is a one-to-one correspondence between a trait object and -// its list of type bounds. -class DynTypeBoundListMention extends TypeMention instanceof TypeBoundList { - private Trait trait; - - DynTypeBoundListMention() { - exists(DynTraitTypeRepr dyn | - // We only need this type mention when the `dyn Trait` is a type - // abstraction, that is, when it's "canonical" and used in - // `conditionSatisfiesConstraint`. - dyn instanceof DynTypeAbstraction and - this = dyn.getTypeBoundList() and - trait = dyn.getTrait() - ) - } - - override Type getTypeAt(TypePath path) { - path.isEmpty() and - result.(DynTraitType).getTrait() = trait - or - exists(DynTraitTypeParameter tp | - trait = tp.getTrait() and - path = TypePath::singleton(tp) and - result = tp.getTraitTypeParameter() - ) - } -} - -class NeverTypeReprMention extends TypeMention, NeverTypeRepr { - override Type getTypeAt(TypePath path) { result = TNeverType() and path.isEmpty() } -} - -class PtrTypeReprMention extends TypeMention instanceof PtrTypeRepr { - private PtrType resolveRootType() { - super.isConst() and result instanceof PtrConstType - or - super.isMut() and result instanceof PtrMutType - } - - override Type getTypeAt(TypePath path) { - path.isEmpty() and result = this.resolveRootType() - or - exists(TypePath suffix | - result = super.getTypeRepr().(TypeMention).getTypeAt(suffix) and - path = TypePath::cons(this.resolveRootType().getPositionalTypeParameter(0), suffix) - ) - } -} +import MkTypeMention diff --git a/rust/ql/test/library-tests/type-inference/associated_types.rs b/rust/ql/test/library-tests/type-inference/associated_types.rs index 332b1d55417..54006d0b3b5 100644 --- a/rust/ql/test/library-tests/type-inference/associated_types.rs +++ b/rust/ql/test/library-tests/type-inference/associated_types.rs @@ -146,10 +146,10 @@ mod concrete_type_access_associated_type { c: as GetSet>::Output, d: as GetSet>::Output, ) { - let _a = a; // $ MISSING: type=_a:S3 - let _b = b; // $ MISSING: type=_b:i32 - let _c = c; // $ MISSING: type=_c:bool - let _d = d; // $ MISSING: type=_d:char + let _a = a; // $ type=_a:S3 + let _b = b; // $ type=_b:i32 + let _c = c; // $ type=_c:bool + let _d = d; // $ type=_d:char } // NOTE: The below seems like it should work, but is currently rejected by @@ -171,24 +171,24 @@ mod concrete_type_access_associated_type { impl Odd { // Odd::proj fn proj(&self) -> ::Output { - let x = Default::default(); // $ MISSING: target=default - x // $ MISSING: type=x:bool + let x = Default::default(); // $ target=default + x // $ type=x:bool } } impl Odd { // Odd::proj fn proj(&self) -> ::Output { - let x = Default::default(); // $ MISSING: target=default - x // $ MISSING: type=x:char + let x = Default::default(); // $ target=default + x // $ type=x:char } } pub fn test() { using_as(S3, 1, true, 'a'); // $ target=using_as - let _a = Odd(42i32).proj(); // $ target=Odd::proj MISSING: type=_a:bool - let _b = Odd(true).proj(); // $ target=Odd::proj MISSING: type=_b:char + let _a = Odd(42i32).proj(); // $ target=Odd::proj type=_a:bool + let _b = Odd(true).proj(); // $ target=Odd::proj type=_b:char } } @@ -266,7 +266,7 @@ mod equality_on_associated_type { T: GetSet, { let _a = x.get(); // $ type=_a:i32 target=GetSet::get - let _b = x.get2(); // $ target=AssocNameClash::get2 MISSING: type=_b:char + let _b = x.get2(); // $ target=AssocNameClash::get2 type=_b:char } } @@ -390,14 +390,14 @@ mod associated_type_in_supertrait { // Odd::get_content fn get_content(&self) -> Self::Output { // let _x = Self::get(self); - Default::default() // $ MISSING: target=default + Default::default() // $ target=default } } impl Subtrait for Odd { // Odd::get_content fn get_content(&self) -> Self::Output { - Default::default() // $ MISSING: target=default + Default::default() // $ target=default } } @@ -412,13 +412,13 @@ mod associated_type_in_supertrait { pub fn test() { let item1 = MyType(42i64); - let _content1 = item1.get_content(); // $ target=MyType::get_content MISSING: type=_content1:i64 + let _content1 = item1.get_content(); // $ target=MyType::get_content type=_content1:i64 let item2 = MyType(true); let _content2 = get_content(&item2); // $ target=get_content MISSING: type=_content2:bool - let _content3 = Odd(42i32).get_content(); // $ target=Odd::get_content MISSING: type=_content3:bool - let _content4 = Odd(true).get_content(); // $ target=Odd::get_content MISSING: type=_content4:char + let _content3 = Odd(42i32).get_content(); // $ target=Odd::get_content type=_content3:bool + let _content4 = Odd(true).get_content(); // $ target=Odd::get_content type=_content4:char } } diff --git a/rust/ql/test/library-tests/type-inference/type-inference.expected b/rust/ql/test/library-tests/type-inference/type-inference.expected index 80ee3a2b1d5..bf56e377021 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -68,13 +68,27 @@ inferCertainType | associated_types.rs:136:18:136:23 | "{:?}\\n" | TRef | {EXTERNAL LOCATION} | str | | associated_types.rs:136:18:136:32 | ...::_print(...) | | {EXTERNAL LOCATION} | () | | associated_types.rs:136:18:136:32 | { ... } | | {EXTERNAL LOCATION} | () | +| associated_types.rs:144:9:144:9 | a | | associated_types.rs:16:1:17:10 | S3 | +| associated_types.rs:145:9:145:9 | b | | {EXTERNAL LOCATION} | i32 | +| associated_types.rs:146:9:146:9 | c | | {EXTERNAL LOCATION} | bool | +| associated_types.rs:147:9:147:9 | d | | {EXTERNAL LOCATION} | char | | associated_types.rs:148:7:153:5 | { ... } | | {EXTERNAL LOCATION} | () | +| associated_types.rs:149:13:149:14 | _a | | associated_types.rs:16:1:17:10 | S3 | +| associated_types.rs:149:18:149:18 | a | | associated_types.rs:16:1:17:10 | S3 | +| associated_types.rs:150:13:150:14 | _b | | {EXTERNAL LOCATION} | i32 | +| associated_types.rs:150:18:150:18 | b | | {EXTERNAL LOCATION} | i32 | +| associated_types.rs:151:13:151:14 | _c | | {EXTERNAL LOCATION} | bool | +| associated_types.rs:151:18:151:18 | c | | {EXTERNAL LOCATION} | bool | +| associated_types.rs:152:13:152:14 | _d | | {EXTERNAL LOCATION} | char | +| associated_types.rs:152:18:152:18 | d | | {EXTERNAL LOCATION} | char | | associated_types.rs:173:17:173:21 | SelfParam | | {EXTERNAL LOCATION} | & | | associated_types.rs:173:17:173:21 | SelfParam | TRef | associated_types.rs:67:1:67:23 | Odd | | associated_types.rs:173:17:173:21 | SelfParam | TRef.OddT | {EXTERNAL LOCATION} | i32 | +| associated_types.rs:173:52:176:9 | { ... } | | {EXTERNAL LOCATION} | bool | | associated_types.rs:181:17:181:21 | SelfParam | | {EXTERNAL LOCATION} | & | | associated_types.rs:181:17:181:21 | SelfParam | TRef | associated_types.rs:67:1:67:23 | Odd | | associated_types.rs:181:17:181:21 | SelfParam | TRef.OddT | {EXTERNAL LOCATION} | bool | +| associated_types.rs:181:52:184:9 | { ... } | | {EXTERNAL LOCATION} | char | | associated_types.rs:187:19:192:5 | { ... } | | {EXTERNAL LOCATION} | () | | associated_types.rs:188:9:188:34 | using_as(...) | | {EXTERNAL LOCATION} | () | | associated_types.rs:188:25:188:28 | true | | {EXTERNAL LOCATION} | bool | @@ -186,15 +200,18 @@ inferCertainType | associated_types.rs:384:24:384:28 | SelfParam | | {EXTERNAL LOCATION} | & | | associated_types.rs:384:24:384:28 | SelfParam | TRef | associated_types.rs:368:5:368:24 | MyType | | associated_types.rs:384:24:384:28 | SelfParam | TRef.T | associated_types.rs:382:10:382:16 | T | +| associated_types.rs:384:47:386:9 | { ... } | | associated_types.rs:382:10:382:16 | T | | associated_types.rs:385:15:385:18 | self | | {EXTERNAL LOCATION} | & | | associated_types.rs:385:15:385:18 | self | TRef | associated_types.rs:368:5:368:24 | MyType | | associated_types.rs:385:15:385:18 | self | TRef.T | associated_types.rs:382:10:382:16 | T | | associated_types.rs:391:24:391:28 | SelfParam | | {EXTERNAL LOCATION} | & | | associated_types.rs:391:24:391:28 | SelfParam | TRef | associated_types.rs:67:1:67:23 | Odd | | associated_types.rs:391:24:391:28 | SelfParam | TRef.OddT | {EXTERNAL LOCATION} | i32 | +| associated_types.rs:391:47:394:9 | { ... } | | {EXTERNAL LOCATION} | bool | | associated_types.rs:399:24:399:28 | SelfParam | | {EXTERNAL LOCATION} | & | | associated_types.rs:399:24:399:28 | SelfParam | TRef | associated_types.rs:67:1:67:23 | Odd | | associated_types.rs:399:24:399:28 | SelfParam | TRef.OddT | {EXTERNAL LOCATION} | bool | +| associated_types.rs:399:47:401:9 | { ... } | | {EXTERNAL LOCATION} | char | | associated_types.rs:404:33:404:36 | item | | {EXTERNAL LOCATION} | & | | associated_types.rs:404:33:404:36 | item | TRef | associated_types.rs:404:20:404:30 | T | | associated_types.rs:405:9:405:12 | item | | {EXTERNAL LOCATION} | & | @@ -4828,24 +4845,48 @@ inferType | associated_types.rs:136:26:136:27 | x6 | | associated_types.rs:13:1:14:10 | S2 | | associated_types.rs:136:26:136:32 | x6.m2() | | associated_types.rs:1:1:2:21 | Wrapper | | associated_types.rs:136:26:136:32 | x6.m2() | A | associated_types.rs:13:1:14:10 | S2 | +| associated_types.rs:144:9:144:9 | a | | associated_types.rs:16:1:17:10 | S3 | +| associated_types.rs:145:9:145:9 | b | | {EXTERNAL LOCATION} | i32 | +| associated_types.rs:146:9:146:9 | c | | {EXTERNAL LOCATION} | bool | +| associated_types.rs:147:9:147:9 | d | | {EXTERNAL LOCATION} | char | | associated_types.rs:148:7:153:5 | { ... } | | {EXTERNAL LOCATION} | () | +| associated_types.rs:149:13:149:14 | _a | | associated_types.rs:16:1:17:10 | S3 | +| associated_types.rs:149:18:149:18 | a | | associated_types.rs:16:1:17:10 | S3 | +| associated_types.rs:150:13:150:14 | _b | | {EXTERNAL LOCATION} | i32 | +| associated_types.rs:150:18:150:18 | b | | {EXTERNAL LOCATION} | i32 | +| associated_types.rs:151:13:151:14 | _c | | {EXTERNAL LOCATION} | bool | +| associated_types.rs:151:18:151:18 | c | | {EXTERNAL LOCATION} | bool | +| associated_types.rs:152:13:152:14 | _d | | {EXTERNAL LOCATION} | char | +| associated_types.rs:152:18:152:18 | d | | {EXTERNAL LOCATION} | char | | associated_types.rs:173:17:173:21 | SelfParam | | {EXTERNAL LOCATION} | & | | associated_types.rs:173:17:173:21 | SelfParam | TRef | associated_types.rs:67:1:67:23 | Odd | | associated_types.rs:173:17:173:21 | SelfParam | TRef.OddT | {EXTERNAL LOCATION} | i32 | +| associated_types.rs:173:52:176:9 | { ... } | | {EXTERNAL LOCATION} | bool | +| associated_types.rs:174:17:174:17 | x | | {EXTERNAL LOCATION} | bool | +| associated_types.rs:174:21:174:38 | ...::default(...) | | {EXTERNAL LOCATION} | bool | +| associated_types.rs:175:13:175:13 | x | | {EXTERNAL LOCATION} | bool | | associated_types.rs:181:17:181:21 | SelfParam | | {EXTERNAL LOCATION} | & | | associated_types.rs:181:17:181:21 | SelfParam | TRef | associated_types.rs:67:1:67:23 | Odd | | associated_types.rs:181:17:181:21 | SelfParam | TRef.OddT | {EXTERNAL LOCATION} | bool | +| associated_types.rs:181:52:184:9 | { ... } | | {EXTERNAL LOCATION} | char | +| associated_types.rs:182:17:182:17 | x | | {EXTERNAL LOCATION} | char | +| associated_types.rs:182:21:182:38 | ...::default(...) | | {EXTERNAL LOCATION} | char | +| associated_types.rs:183:13:183:13 | x | | {EXTERNAL LOCATION} | char | | associated_types.rs:187:19:192:5 | { ... } | | {EXTERNAL LOCATION} | () | | associated_types.rs:188:9:188:34 | using_as(...) | | {EXTERNAL LOCATION} | () | | associated_types.rs:188:18:188:19 | S3 | | associated_types.rs:16:1:17:10 | S3 | | associated_types.rs:188:22:188:22 | 1 | | {EXTERNAL LOCATION} | i32 | | associated_types.rs:188:25:188:28 | true | | {EXTERNAL LOCATION} | bool | | associated_types.rs:188:31:188:33 | 'a' | | {EXTERNAL LOCATION} | char | +| associated_types.rs:190:13:190:14 | _a | | {EXTERNAL LOCATION} | bool | | associated_types.rs:190:18:190:27 | Odd(...) | | associated_types.rs:67:1:67:23 | Odd | | associated_types.rs:190:18:190:27 | Odd(...) | OddT | {EXTERNAL LOCATION} | i32 | +| associated_types.rs:190:18:190:34 | ... .proj() | | {EXTERNAL LOCATION} | bool | | associated_types.rs:190:22:190:26 | 42i32 | | {EXTERNAL LOCATION} | i32 | +| associated_types.rs:191:13:191:14 | _b | | {EXTERNAL LOCATION} | char | | associated_types.rs:191:18:191:26 | Odd(...) | | associated_types.rs:67:1:67:23 | Odd | | associated_types.rs:191:18:191:26 | Odd(...) | OddT | {EXTERNAL LOCATION} | bool | +| associated_types.rs:191:18:191:33 | ... .proj() | | {EXTERNAL LOCATION} | char | | associated_types.rs:191:22:191:25 | true | | {EXTERNAL LOCATION} | bool | | associated_types.rs:199:30:199:34 | thing | | associated_types.rs:199:19:199:27 | T | | associated_types.rs:200:9:200:13 | thing | | associated_types.rs:199:19:199:27 | T | @@ -4900,7 +4941,9 @@ inferType | associated_types.rs:268:13:268:14 | _a | | {EXTERNAL LOCATION} | i32 | | associated_types.rs:268:18:268:18 | x | | associated_types.rs:263:31:263:31 | T | | associated_types.rs:268:18:268:24 | x.get() | | {EXTERNAL LOCATION} | i32 | +| associated_types.rs:269:13:269:14 | _b | | {EXTERNAL LOCATION} | char | | associated_types.rs:269:18:269:18 | x | | associated_types.rs:263:31:263:31 | T | +| associated_types.rs:269:18:269:25 | x.get2() | | {EXTERNAL LOCATION} | char | | associated_types.rs:280:19:280:23 | SelfParam | | {EXTERNAL LOCATION} | & | | associated_types.rs:280:19:280:23 | SelfParam | TRef | associated_types.rs:276:5:287:5 | Self [trait MyTraitAssoc2] | | associated_types.rs:280:26:280:26 | a | | associated_types.rs:280:16:280:16 | A | @@ -5016,9 +5059,13 @@ inferType | associated_types.rs:391:24:391:28 | SelfParam | | {EXTERNAL LOCATION} | & | | associated_types.rs:391:24:391:28 | SelfParam | TRef | associated_types.rs:67:1:67:23 | Odd | | associated_types.rs:391:24:391:28 | SelfParam | TRef.OddT | {EXTERNAL LOCATION} | i32 | +| associated_types.rs:391:47:394:9 | { ... } | | {EXTERNAL LOCATION} | bool | +| associated_types.rs:393:13:393:30 | ...::default(...) | | {EXTERNAL LOCATION} | bool | | associated_types.rs:399:24:399:28 | SelfParam | | {EXTERNAL LOCATION} | & | | associated_types.rs:399:24:399:28 | SelfParam | TRef | associated_types.rs:67:1:67:23 | Odd | | associated_types.rs:399:24:399:28 | SelfParam | TRef.OddT | {EXTERNAL LOCATION} | bool | +| associated_types.rs:399:47:401:9 | { ... } | | {EXTERNAL LOCATION} | char | +| associated_types.rs:400:13:400:30 | ...::default(...) | | {EXTERNAL LOCATION} | char | | associated_types.rs:404:33:404:36 | item | | {EXTERNAL LOCATION} | & | | associated_types.rs:404:33:404:36 | item | TRef | associated_types.rs:404:20:404:30 | T | | associated_types.rs:405:9:405:12 | item | | {EXTERNAL LOCATION} | & | @@ -5038,8 +5085,10 @@ inferType | associated_types.rs:414:21:414:33 | MyType(...) | | associated_types.rs:368:5:368:24 | MyType | | associated_types.rs:414:21:414:33 | MyType(...) | T | {EXTERNAL LOCATION} | i64 | | associated_types.rs:414:28:414:32 | 42i64 | | {EXTERNAL LOCATION} | i64 | +| associated_types.rs:415:13:415:21 | _content1 | | {EXTERNAL LOCATION} | i64 | | associated_types.rs:415:25:415:29 | item1 | | associated_types.rs:368:5:368:24 | MyType | | associated_types.rs:415:25:415:29 | item1 | T | {EXTERNAL LOCATION} | i64 | +| associated_types.rs:415:25:415:43 | item1.get_content() | | {EXTERNAL LOCATION} | i64 | | associated_types.rs:417:13:417:17 | item2 | | associated_types.rs:368:5:368:24 | MyType | | associated_types.rs:417:13:417:17 | item2 | T | {EXTERNAL LOCATION} | bool | | associated_types.rs:417:21:417:32 | MyType(...) | | associated_types.rs:368:5:368:24 | MyType | @@ -5050,11 +5099,15 @@ inferType | associated_types.rs:418:37:418:42 | &item2 | TRef.T | {EXTERNAL LOCATION} | bool | | associated_types.rs:418:38:418:42 | item2 | | associated_types.rs:368:5:368:24 | MyType | | associated_types.rs:418:38:418:42 | item2 | T | {EXTERNAL LOCATION} | bool | +| associated_types.rs:420:13:420:21 | _content3 | | {EXTERNAL LOCATION} | bool | | associated_types.rs:420:25:420:34 | Odd(...) | | associated_types.rs:67:1:67:23 | Odd | | associated_types.rs:420:25:420:34 | Odd(...) | OddT | {EXTERNAL LOCATION} | i32 | +| associated_types.rs:420:25:420:48 | ... .get_content() | | {EXTERNAL LOCATION} | bool | | associated_types.rs:420:29:420:33 | 42i32 | | {EXTERNAL LOCATION} | i32 | +| associated_types.rs:421:13:421:21 | _content4 | | {EXTERNAL LOCATION} | char | | associated_types.rs:421:25:421:33 | Odd(...) | | associated_types.rs:67:1:67:23 | Odd | | associated_types.rs:421:25:421:33 | Odd(...) | OddT | {EXTERNAL LOCATION} | bool | +| associated_types.rs:421:25:421:47 | ... .get_content() | | {EXTERNAL LOCATION} | char | | associated_types.rs:421:29:421:32 | true | | {EXTERNAL LOCATION} | bool | | associated_types.rs:435:16:435:20 | SelfParam | | {EXTERNAL LOCATION} | & | | associated_types.rs:435:16:435:20 | SelfParam | TRef | associated_types.rs:428:5:428:20 | ST |