Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions rust/ql/lib/codeql/rust/elements/internal/TraitImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

private import codeql.rust.elements.internal.generated.Trait
private import codeql.rust.internal.PathResolution as PathResolution

/**
* INTERNAL: This module contains the customizable definition of `Trait` and should not
Expand Down Expand Up @@ -67,5 +68,11 @@ module Impl {
* `where` clauses for `Self`.
*/
TypeBound getATypeBound() { result = this.getTypeBound(_) }

/** Gets a direct supertrait of this trait, if any. */
Trait getSupertrait() {
result =
PathResolution::resolvePath(this.getATypeBound().getTypeRepr().(PathTypeRepr).getPath())
}
}
}
73 changes: 48 additions & 25 deletions rust/ql/lib/codeql/rust/internal/typeinference/Type.qll
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@
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()
}

/**
* Holds if a dyn trait type should have a type parameter associated with `n`. A
* dyn trait type inherits the type parameters of the trait it implements. That
* includes the type parameters corresponding to associated types.
* Holds if a dyn trait type for the trait `trait` should have a type parameter
* associated with `n`.
*
* A dyn trait type inherits the type parameters of the trait it implements.
* That includes the type parameters corresponding to associated types.
*
* For instance in
* ```rust
Expand All @@ -24,10 +31,7 @@
*/
private predicate dynTraitTypeParameter(Trait trait, AstNode n) {
trait = any(DynTraitTypeRepr dt).getTrait() and
(
n = trait.getGenericParamList().getATypeParam() or
n = trait.(TraitItemNode).getAnAssocItem().(TypeAlias)
)
n = [trait.getGenericParamList().getATypeParam().(AstNode), getTraitTypeAlias(trait)]
}

cached
Expand All @@ -39,8 +43,10 @@
TNeverType() or
TUnknownType() or
TTypeParamTypeParameter(TypeParam t) or
TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or
TDynTraitTypeParameter(AstNode n) { dynTraitTypeParameter(_, n) } or
TAssociatedTypeTypeParameter(Trait trait, TypeAlias typeAlias) {
getTraitTypeAlias(trait) = typeAlias
} or
TDynTraitTypeParameter(Trait trait, AstNode n) { dynTraitTypeParameter(trait, n) } or
TImplTraitTypeParameter(ImplTraitTypeRepr implTrait, TypeParam tp) {
implTraitTypeParam(implTrait, _, tp)
} or
Expand Down Expand Up @@ -270,17 +276,10 @@
DynTraitType() { this = TDynTraitType(trait) }

override DynTraitTypeParameter getPositionalTypeParameter(int i) {
result = TDynTraitTypeParameter(trait.getGenericParamList().getTypeParam(i))
result.getTypeParam() = trait.getGenericParamList().getTypeParam(i)
}

override TypeParameter getATypeParameter() {
result = super.getATypeParameter()
or
exists(AstNode n |
dynTraitTypeParameter(trait, n) and
result = TDynTraitTypeParameter(n)
)
}
override DynTraitTypeParameter getATypeParameter() { result.getTrait() = trait }

Trait getTrait() { result = trait }

Expand Down Expand Up @@ -427,30 +426,54 @@
* // ...
* }
* ```
* Furthermore, associated types of a supertrait induce a corresponding type
* parameter in any subtraits. E.g., if we have a trait `SubTrait: ATrait` then
* `SubTrait` also has a type parameter for the associated type
* `AssociatedType`.
*/
class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypeParameter {
private Trait trait;
private TypeAlias typeAlias;

AssociatedTypeTypeParameter() { this = TAssociatedTypeTypeParameter(typeAlias) }
AssociatedTypeTypeParameter() { this = TAssociatedTypeTypeParameter(trait, typeAlias) }

TypeAlias getTypeAlias() { result = typeAlias }

/** Gets the trait that contains this associated type declaration. */
TraitItemNode getTrait() { result.getAnAssocItem() = typeAlias }
TraitItemNode getTrait() { result = trait }

override ItemNode getDeclaringItem() { result = this.getTrait() }
/**
* Holds if this associated type type parameter corresponds directly its
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected grammar: 'corresponds directly its trait' should be 'corresponds directly to its trait'.

Suggested change
* Holds if this associated type type parameter corresponds directly its
* Holds if this associated type type parameter corresponds directly to its

Copilot uses AI. Check for mistakes.
* trait, that is, it is not inherited from a supertrait.
*/
predicate isDirect() { trait.(TraitItemNode).getAnAssocItem() = typeAlias }

override ItemNode getDeclaringItem() { result = trait }

override string toString() { result = typeAlias.getName().getText() }
override string toString() {
result = typeAlias.getName().getText() + "[" + trait.getName().toString() + "]"
}

override Location getLocation() { result = typeAlias.getLocation() }
}

/** Gets the associated type type parameter corresponding directly to `typeAlias`. */

Check warning

Code scanning / CodeQL

Comment has repeated word Warning

The comment repeats type.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, but it's the "associated-type" "type-parameter".

AssociatedTypeTypeParameter getAssociatedTypeTypeParameter(TypeAlias typeAlias) {
result.isDirect() and result.getTypeAlias() = typeAlias
}

/** Gets the dyn type type parameter corresponding directly to `typeAlias`. */

Check warning

Code scanning / CodeQL

Comment has repeated word Warning

The comment repeats type.
DynTraitTypeParameter getDynTraitTypeParameter(TypeAlias typeAlias) {
result.getTraitTypeParameter() = getAssociatedTypeTypeParameter(typeAlias)
}

class DynTraitTypeParameter extends TypeParameter, TDynTraitTypeParameter {
private Trait trait;
private AstNode n;

DynTraitTypeParameter() { this = TDynTraitTypeParameter(n) }
DynTraitTypeParameter() { this = TDynTraitTypeParameter(trait, n) }

Trait getTrait() { dynTraitTypeParameter(result, n) }
Trait getTrait() { result = trait }

/** Gets the dyn trait type that this type parameter belongs to. */
DynTraitType getDynTraitType() { result.getTrait() = this.getTrait() }
Expand All @@ -465,7 +488,7 @@
TypeParameter getTraitTypeParameter() {
result.(TypeParamTypeParameter).getTypeParam() = n
or
result.(AssociatedTypeTypeParameter).getTypeAlias() = n
result = TAssociatedTypeTypeParameter(trait, n)
}

private string toStringInner() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ private module Input1 implements InputSig1<Location> {
tp =
rank[result](TypeParameter tp0, int kind, int id1, int id2 |
kind = 1 and
id1 = 0 and
id1 = idOfTypeParameterAstNode(tp0.(DynTraitTypeParameter).getTrait()) and
id2 =
idOfTypeParameterAstNode([
tp0.(DynTraitTypeParameter).getTypeParam().(AstNode),
Expand All @@ -102,10 +102,13 @@ private module Input1 implements InputSig1<Location> {
id2 = idOfTypeParameterAstNode(tp0.(ImplTraitTypeParameter).getTypeParam())
or
kind = 3 and
id1 = idOfTypeParameterAstNode(tp0.(AssociatedTypeTypeParameter).getTrait()) and
id2 = idOfTypeParameterAstNode(tp0.(AssociatedTypeTypeParameter).getTypeAlias())
or
kind = 4 and
id1 = 0 and
exists(AstNode node | id2 = idOfTypeParameterAstNode(node) |
node = tp0.(TypeParamTypeParameter).getTypeParam() or
node = tp0.(AssociatedTypeTypeParameter).getTypeAlias() or
node = tp0.(SelfTypeParameter).getTrait() or
node = tp0.(ImplTraitTypeTypeParameter).getImplTraitTypeRepr()
)
Expand Down Expand Up @@ -3507,12 +3510,12 @@ private DynTraitType getFutureTraitType() { result.getTrait() instanceof FutureT

pragma[nomagic]
private AssociatedTypeTypeParameter getFutureOutputTypeParameter() {
result.getTypeAlias() = any(FutureTrait ft).getOutputType()
result = getAssociatedTypeTypeParameter(any(FutureTrait ft).getOutputType())
}

pragma[nomagic]
private DynTraitTypeParameter getDynFutureOutputTypeParameter() {
result = TDynTraitTypeParameter(any(FutureTrait ft).getOutputType())
result.getTraitTypeParameter() = getFutureOutputTypeParameter()
}

pragma[nomagic]
Expand Down Expand Up @@ -3824,20 +3827,20 @@ private Type invokedClosureFnTypeAt(InvokedClosureExpr ce, TypePath path) {

/** Gets the path to a closure's return type. */
private TypePath closureReturnPath() {
result = TypePath::singleton(TDynTraitTypeParameter(any(FnOnceTrait t).getOutputType()))
result = TypePath::singleton(getDynTraitTypeParameter(any(FnOnceTrait t).getOutputType()))
}

/** Gets the path to a closure with arity `arity`s `index`th parameter type. */
pragma[nomagic]
private TypePath closureParameterPath(int arity, int index) {
result =
TypePath::cons(TDynTraitTypeParameter(any(FnOnceTrait t).getTypeParam()),
TypePath::cons(TDynTraitTypeParameter(_, any(FnOnceTrait t).getTypeParam()),
TypePath::singleton(getTupleTypeParameter(arity, index)))
}

/** Gets the path to the return type of the `FnOnce` trait. */
private TypePath fnReturnPath() {
result = TypePath::singleton(TAssociatedTypeTypeParameter(any(FnOnceTrait t).getOutputType()))
result = TypePath::singleton(getAssociatedTypeTypeParameter(any(FnOnceTrait t).getOutputType()))
}

/**
Expand Down Expand Up @@ -3898,7 +3901,7 @@ private Type inferClosureExprType(AstNode n, TypePath path) {
result = TDynTraitType(any(FnOnceTrait t)) // always exists because of the mention in `builtins/mentions.rs`
or
n = ce and
path = TypePath::singleton(TDynTraitTypeParameter(any(FnOnceTrait t).getTypeParam())) and
path = TypePath::singleton(TDynTraitTypeParameter(_, any(FnOnceTrait t).getTypeParam())) and
result.(TupleType).getArity() = ce.getNumberOfParams()
or
// Propagate return type annotation to body
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ query predicate illFormedTypeMention(TypeMention tm) {
any(PathTypeMention ptm |
exists(ptm.resolvePathTypeAt(TypePath::nil())) and
not exists(ptm.resolveType())
or
ptm.(NonAliasPathTypeMention).getResolved() instanceof TypeAlias
) and
// Only include inconsistencies in the source, as we otherwise get
// inconsistencies from library code in every project.
Expand Down
70 changes: 39 additions & 31 deletions rust/ql/lib/codeql/rust/internal/typeinference/TypeMention.qll
Original file line number Diff line number Diff line change
Expand Up @@ -148,30 +148,11 @@

TypeItemNode getResolved() { result = resolved }

/**
* Gets a type alias with the name `name` of the trait that this path resolves
* to, if any.
*/
pragma[nomagic]
private TypeAlias getResolvedTraitAlias(string name) {
result = resolved.(TraitItemNode).getAnAssocItem() and
name = result.getName().getText()
}

pragma[nomagic]
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method getAssocTypeArg is renamed from returning TypeRepr to returning TypeMention, but the name still suggests it returns a type argument. Consider renaming to getAssocTypeMention or updating the documentation to clarify the return type change.

Suggested change
pragma[nomagic]
pragma[nomagic]
/**
* Gets the associated type argument with the given `name` as a type mention.
*/

Copilot uses AI. Check for mistakes.
private TypeRepr getAssocTypeArg(string name) {
private TypeMention getAssocTypeArg(string name) {
result = this.getSegment().getGenericArgList().getAssocTypeArg(name)
}

/** Gets the type argument for the associated type `alias`, if any. */
pragma[nomagic]
private TypeRepr getAnAssocTypeArgument(TypeAlias alias) {
exists(string name |
alias = this.getResolvedTraitAlias(name) and
result = this.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.
Expand Down Expand Up @@ -239,7 +220,7 @@
tp = TTypeParamTypeParameter(t.getTypeParam()) and
result = s.getParenthesizedArgList().(TypeMention).resolveTypeAt(path)
or
tp = TAssociatedTypeTypeParameter(t.getOutputType()) and
tp = TAssociatedTypeTypeParameter(t, t.getOutputType()) and
(
result = s.getRetType().getTypeRepr().(TypeMention).resolveTypeAt(path)
or
Expand All @@ -249,19 +230,47 @@
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<Assoc=Assoc[Sub]>
// ```
// Where `Assoc` is an associated type of `Super` and `Assoc[Sub]` denotes
// the copy of the type parameter inherited into `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()
)
}

pragma[nomagic]
bindingset[name]
private TypeAlias getResolvedAlias(string name) {
result = resolved.(TraitItemNode).getAssocItem(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 |
result = this.getAnAssocTypeArgument(alias) and
tp = TAssociatedTypeTypeParameter(alias)
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
Expand All @@ -279,9 +288,9 @@
// 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(pragma[only_bind_into](name)) and
alias = impl.getASuccessor(name) and
result = alias.getTypeRepr() and
tp = TAssociatedTypeTypeParameter(this.getResolvedAlias(pragma[only_bind_into](name)))
tp = TAssociatedTypeTypeParameter(resolved, this.getResolvedAlias(name))
)
}

Expand All @@ -299,7 +308,7 @@
or
result = TTypeParamTypeParameter(resolved)
or
result = TAssociatedTypeTypeParameter(resolved)
result = TAssociatedTypeTypeParameter(resolvePath(this.getQualifier()), resolved)
}

override Type resolvePathTypeAt(TypePath typePath) {
Expand Down Expand Up @@ -379,14 +388,13 @@
result = TTrait(this)
or
// The implicit `Self` type parameter occurs at the `Self` type parameter
// position.

Check warning

Code scanning / CodeQL

Omittable 'exists' variable Warning

This exists variable can be omitted by using a don't-care expression
in this argument
.
typePath = TypePath::singleton(TSelfTypeParameter(this)) and
result = TSelfTypeParameter(this)
or
exists(TypeAlias alias |
alias = super.getAnAssocItem() and
typePath = TypePath::singleton(result) and
result = TAssociatedTypeTypeParameter(alias)
result = TAssociatedTypeTypeParameter(this, alias)
)
or
exists(TypeParam tp |
Expand Down Expand Up @@ -540,7 +548,7 @@
// impl<A, B, ..> Trait<A, B, ..> for (dyn Trait)<A, B, ..>
// ```
// To achieve this:
// - `DynTypeAbstraction` is an abstraction over type parameters of the trait.
// - `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.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
multipleResolvedTargets
| main.rs:3087:13:3087:17 | x.f() |
| main.rs:2860:13:2860:17 | x.f() |
Loading
Loading