From 620d228ffa41d6af05db73f9467ec2d9dcd49276 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Fri, 18 Jul 2025 15:28:42 +0200 Subject: [PATCH 1/5] Rust: Factor out `getTypeMentionForTypeParameter` --- .../lib/codeql/rust/internal/TypeMention.qll | 93 ++++++++++--------- 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/TypeMention.qll b/rust/ql/lib/codeql/rust/internal/TypeMention.qll index 6dd69ef49fc..e0dfa266661 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeMention.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeMention.qll @@ -61,13 +61,14 @@ class PathTypeMention extends TypeMention, Path { 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) { - exists(TraitItemNode trait | - trait = resolved and - result = trait.getAnAssocItem() and - name = result.getName().getText() - ) + result = resolved.(TraitItemNode).getAnAssocItem() and + name = result.getName().getText() } pragma[nomagic] @@ -140,6 +141,48 @@ class PathTypeMention extends TypeMention, Path { ) } + /** Gets the type mention in this path for the type parameter `tp`, if any. */ + pragma[nomagic] + private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) { + not exists(resolved.(TypeAlias).getTypeRepr()) and + ( + exists(int i | + result = this.getPositionalTypeArgument(pragma[only_bind_into](i)) and + tp = this.resolveType().getTypeParameter(pragma[only_bind_into](i)) + ) + or + exists(TypeAlias alias | + result = this.getAnAssocTypeArgument(alias) and + tp = TAssociatedTypeTypeParameter(alias) + ) + 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, AssociatedTypeTypeParameter param, TypeAlias alias, string name | + this = impl.getTraitPath() and + param.getTrait() = resolved and + name = param.getTypeAlias().getName().getText() and + alias = impl.getASuccessor(pragma[only_bind_into](name)) and + result = alias.getTypeRepr() and + tp = + TAssociatedTypeTypeParameter(resolved + .(TraitItemNode) + .getAssocItem(pragma[only_bind_into](name))) + ) + ) + } + override Type resolveTypeAt(TypePath typePath) { result = this.aliasResolveTypeAt(typePath) or @@ -162,45 +205,9 @@ class PathTypeMention extends TypeMention, Path { result = TAssociatedTypeTypeParameter(resolved) ) or - not exists(resolved.(TypeAlias).getTypeRepr()) and - exists(TypeParameter tp, TypeMention arg, TypePath suffix | - result = arg.resolveTypeAt(suffix) and + exists(TypeParameter tp, TypePath suffix | + result = this.getTypeMentionForTypeParameter(tp).resolveTypeAt(suffix) and typePath = TypePath::cons(tp, suffix) - | - exists(int i | - arg = this.getPositionalTypeArgument(pragma[only_bind_into](i)) and - tp = this.resolveType().getTypeParameter(pragma[only_bind_into](i)) - ) - or - exists(TypeAlias alias | - arg = this.getAnAssocTypeArgument(alias) and - tp = TAssociatedTypeTypeParameter(alias) - ) - 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, AssociatedTypeTypeParameter param, TypeAlias alias, string name | - this = impl.getTraitPath() and - param.getTrait() = resolved and - name = param.getTypeAlias().getName().getText() and - alias = impl.getASuccessor(pragma[only_bind_into](name)) and - arg = alias.getTypeRepr() and - tp = - TAssociatedTypeTypeParameter(resolved - .(TraitItemNode) - .getAssocItem(pragma[only_bind_into](name))) - ) ) } } From 0e8c137a98be068dbc42fbe4acbcc255ab023ecf Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Sat, 19 Jul 2025 11:56:42 +0200 Subject: [PATCH 2/5] Rust: Only include paths as type mentions when they're used as such On databend this changes the number of `PathTypeMention`s from 3,777,464 to 3,330,024. Not a huge difference, but there's also downstream predicates that are reduced as well. --- .../ql/lib/codeql/rust/internal/TypeMention.qll | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/TypeMention.qll b/rust/ql/lib/codeql/rust/internal/TypeMention.qll index e0dfa266661..b9f33a68d9d 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeMention.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeMention.qll @@ -50,13 +50,24 @@ class SliceTypeReprMention extends TypeMention instanceof SliceTypeRepr { } } +/** Holds if `path` is used as a type mention during type inference. */ +predicate relevantPathTypeMention(Path path) { + path = + [ + any(PathTypeRepr r).getPath(), + any(StructExpr s).getPath().getQualifier*(), + any(CallExpr ce).getFunction().(PathExpr).getPath().getQualifier*(), + any(StructPat p).getPath(), + any(TupleStructPat p).getPath() + ] +} + class PathTypeMention extends TypeMention, Path { TypeItemNode resolved; PathTypeMention() { - resolved = resolvePath(this) - or - resolved = resolvePath(this).(Variant).getEnum() + relevantPathTypeMention(this) and + resolved = [resolvePath(this), resolvePath(this).(Variant).getEnum().(TypeItemNode)] } TypeItemNode getResolved() { result = resolved } From 804ffdb682ca197e3939a23abcd3218e4301afa0 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Sat, 19 Jul 2025 13:36:28 +0200 Subject: [PATCH 3/5] Rust: Split `PathTypeMention` into an alias and a non-alias subclass --- .../lib/codeql/rust/internal/TypeMention.qll | 133 ++++++++++-------- 1 file changed, 71 insertions(+), 62 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/TypeMention.qll b/rust/ql/lib/codeql/rust/internal/TypeMention.qll index b9f33a68d9d..e19c5fb23d5 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeMention.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeMention.qll @@ -62,12 +62,46 @@ predicate relevantPathTypeMention(Path path) { ] } -class PathTypeMention extends TypeMention, Path { +abstract class PathTypeMention extends TypeMention, Path { + PathTypeMention() { relevantPathTypeMention(this) } +} + +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`. + */ + pragma[nomagic] + override Type resolveTypeAt(TypePath typePath) { + result = rhs.resolveTypeAt(typePath) and + not result = pathGetTypeParameter(resolved, _) + or + exists(TypeParameter tp, TypeMention arg, TypePath prefix, TypePath suffix, int i | + tp = rhs.resolveTypeAt(prefix) and + tp = pathGetTypeParameter(resolved, pragma[only_bind_into](i)) and + arg = this.getSegment().getGenericArgList().getTypeArg(pragma[only_bind_into](i)) and + result = arg.resolveTypeAt(suffix) and + typePath = prefix.append(suffix) + ) + } +} + +class NonAliasPathTypeMention extends PathTypeMention { TypeItemNode resolved; - PathTypeMention() { - relevantPathTypeMention(this) and - resolved = [resolvePath(this), resolvePath(this).(Variant).getEnum().(TypeItemNode)] + NonAliasPathTypeMention() { + resolved = [resolvePath(this), resolvePath(this).(Variant).getEnum().(TypeItemNode)] and + not exists(resolved.(TypeAlias).getTypeRepr()) } TypeItemNode getResolved() { result = resolved } @@ -132,71 +166,46 @@ class PathTypeMention extends TypeMention, Path { this = any(PathTypeRepr ptp).getPath().getQualifier*() } - /** - * Holds if this path resolved to a type alias with a rhs. that has the - * resulting type at `typePath`. - */ - pragma[nomagic] - private Type aliasResolveTypeAt(TypePath typePath) { - exists(TypeAlias alias, TypeMention rhs | alias = resolved and rhs = alias.getTypeRepr() | - result = rhs.resolveTypeAt(typePath) and - not result = pathGetTypeParameter(alias, _) - or - exists(TypeParameter tp, TypeMention arg, TypePath prefix, TypePath suffix, int i | - tp = rhs.resolveTypeAt(prefix) and - tp = pathGetTypeParameter(alias, pragma[only_bind_into](i)) and - arg = this.getSegment().getGenericArgList().getTypeArg(pragma[only_bind_into](i)) and - result = arg.resolveTypeAt(suffix) and - typePath = prefix.append(suffix) - ) - ) - } - /** Gets the type mention in this path for the type parameter `tp`, if any. */ pragma[nomagic] private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) { - not exists(resolved.(TypeAlias).getTypeRepr()) and - ( - exists(int i | - result = this.getPositionalTypeArgument(pragma[only_bind_into](i)) and - tp = this.resolveType().getTypeParameter(pragma[only_bind_into](i)) - ) - or - exists(TypeAlias alias | - result = this.getAnAssocTypeArgument(alias) and - tp = TAssociatedTypeTypeParameter(alias) - ) - 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, AssociatedTypeTypeParameter param, TypeAlias alias, string name | - this = impl.getTraitPath() and - param.getTrait() = resolved and - name = param.getTypeAlias().getName().getText() and - alias = impl.getASuccessor(pragma[only_bind_into](name)) and - result = alias.getTypeRepr() and - tp = - TAssociatedTypeTypeParameter(resolved - .(TraitItemNode) - .getAssocItem(pragma[only_bind_into](name))) - ) + exists(int i | + result = this.getPositionalTypeArgument(pragma[only_bind_into](i)) and + tp = this.resolveType().getTypeParameter(pragma[only_bind_into](i)) + ) + or + exists(TypeAlias alias | + result = this.getAnAssocTypeArgument(alias) and + tp = TAssociatedTypeTypeParameter(alias) + ) + 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, AssociatedTypeTypeParameter param, TypeAlias alias, string name | + this = impl.getTraitPath() and + param.getTrait() = resolved and + name = param.getTypeAlias().getName().getText() and + alias = impl.getASuccessor(pragma[only_bind_into](name)) and + result = alias.getTypeRepr() and + tp = + TAssociatedTypeTypeParameter(resolved + .(TraitItemNode) + .getAssocItem(pragma[only_bind_into](name))) ) } override Type resolveTypeAt(TypePath typePath) { - result = this.aliasResolveTypeAt(typePath) - or typePath.isEmpty() and ( result = TStruct(resolved) From 27e52512852f4ce129779459063e109d6ccca6f0 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Sat, 19 Jul 2025 13:57:31 +0200 Subject: [PATCH 4/5] Rust: Add `resolveRootType` predicate instead of using `resolveType` recursively --- .../lib/codeql/rust/internal/TypeMention.qll | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/TypeMention.qll b/rust/ql/lib/codeql/rust/internal/TypeMention.qll index e19c5fb23d5..20389bb4ae3 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeMention.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeMention.qll @@ -161,7 +161,7 @@ class NonAliasPathTypeMention extends PathTypeMention { // 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.resolveType().getTypeParameterDefault(i) and + result = this.resolveRootType().getTypeParameterDefault(i) and // Defaults only apply to type mentions in type annotations this = any(PathTypeRepr ptp).getPath().getQualifier*() } @@ -171,7 +171,7 @@ class NonAliasPathTypeMention extends PathTypeMention { private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) { exists(int i | result = this.getPositionalTypeArgument(pragma[only_bind_into](i)) and - tp = this.resolveType().getTypeParameter(pragma[only_bind_into](i)) + tp = this.resolveRootType().getTypeParameter(pragma[only_bind_into](i)) ) or exists(TypeAlias alias | @@ -205,25 +205,27 @@ class NonAliasPathTypeMention extends PathTypeMention { ) } + Type resolveRootType() { + result = TStruct(resolved) + or + result = TEnum(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(resolved) + } + override Type resolveTypeAt(TypePath typePath) { typePath.isEmpty() and - ( - result = TStruct(resolved) - or - result = TEnum(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(resolved) - ) + result = this.resolveRootType() or exists(TypeParameter tp, TypePath suffix | result = this.getTypeMentionForTypeParameter(tp).resolveTypeAt(suffix) and From 441cefd0bd41537557e971f1d99ec7118864aba5 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Mon, 21 Jul 2025 08:34:16 +0200 Subject: [PATCH 5/5] Rust: Accept test changes --- .../CONSISTENCY/TypeInferenceConsistency.expected | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 rust/ql/test/query-tests/unusedentities/CONSISTENCY/TypeInferenceConsistency.expected diff --git a/rust/ql/test/query-tests/unusedentities/CONSISTENCY/TypeInferenceConsistency.expected b/rust/ql/test/query-tests/unusedentities/CONSISTENCY/TypeInferenceConsistency.expected deleted file mode 100644 index 56ce1df5c89..00000000000 --- a/rust/ql/test/query-tests/unusedentities/CONSISTENCY/TypeInferenceConsistency.expected +++ /dev/null @@ -1,2 +0,0 @@ -illFormedTypeMention -| main.rs:403:18:403:24 | FuncPtr |