From b189f1fe3f57bf2d7b90987c59a396f7fcd61973 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Fri, 24 Oct 2025 09:12:42 +0200 Subject: [PATCH 1/2] Rust: Refactor using shared constraint satisfaction --- .../codeql/rust/internal/TypeInference.qll | 8 +- .../typeinference/FunctionOverloading.qll | 4 +- .../internal/typeinference/FunctionType.qll | 140 +++++++----------- .../typeinference/internal/TypeInference.qll | 2 +- 4 files changed, 59 insertions(+), 95 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index d550f56b09d4..4a53b5dee8e2 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -896,7 +896,7 @@ private predicate assocFunctionInfo( ) { f = i.getASuccessor(name) and arity = f.getParamList().getNumberOfParams() and - t.appliesTo(f, pos, i) + t.appliesTo(f, i, pos) } /** @@ -1791,7 +1791,7 @@ private module MethodResolution { predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t) { exists(TypePath path, Type t0 | FunctionOverloading::functionResolutionDependsOnArgument(i, f, pos, path, t0) and - t.appliesTo(f, pos, i) and + t.appliesTo(f, i, pos) and // for now, we do not handle ambiguous targets when one of the types it iself // a type parameter; we should be checking the constraints on that type parameter // in this case @@ -2024,7 +2024,7 @@ private module NonMethodResolution { ImplItemNode impl, NonMethodFunction implFunction ) { exists(TypePath path | - assocFunctionTypeAt(implFunction, impl, pos, path, type) and + type = assocFunctionTypeAt(implFunction, impl, pos, path) and implFunction.implements(traitFunction) and FunctionOverloading::traitTypeParameterOccurrence(trait, traitFunction, _, pos, path, _) | @@ -2238,7 +2238,7 @@ private module NonMethodResolution { private module NonMethodArgsAreInstantiationsOfInput implements ArgsAreInstantiationsOfInputSig { predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t) { - t.appliesTo(f, pos, i) and + t.appliesTo(f, i, pos) and ( exists(Type t0 | // for now, we do not handle ambiguous targets when one of the types it iself diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll index d8ca50962a13..9373f62b0e43 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll @@ -79,7 +79,7 @@ predicate traitTypeParameterOccurrence( TypeParameter tp ) { f = trait.getASuccessor(functionName) and - assocFunctionTypeAt(f, trait, pos, path, tp) and + tp = assocFunctionTypeAt(f, trait, pos, path) and tp = trait.(TraitTypeAbstraction).getATypeParameter() } @@ -120,7 +120,7 @@ predicate functionResolutionDependsOnArgument( exists(TraitItemNode trait, string functionName | implHasSibling(impl, trait) and traitTypeParameterOccurrence(trait, _, functionName, pos, path, _) and - assocFunctionTypeAt(f, impl, pos, path, type) and + type = assocFunctionTypeAt(f, impl, pos, path) and f = impl.getASuccessor(functionName) and pos.isPosition() ) diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll index d6cefdb1edca..4c4de4fa767a 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll @@ -72,28 +72,54 @@ module FunctionPositionMatchingInput { } private newtype TAssocFunctionType = - MkAssocFunctionType(Function f, FunctionPosition pos, ImplOrTraitItemNode i) { - f = i.getAnAssocItem() and - exists(pos.getTypeMention(f)) - } or - MkInheritedAssocFunctionType( - Function f, FunctionPosition pos, TypeMention parentMention, TraitItemNode parent, - ImplOrTraitItemNode i - ) { - exists(AssocFunctionType inherited | - inherited.appliesTo(f, pos, parent) and - f = i.getASuccessor(_) + /** An associated function `f` that should be specialized for `i` at `pos`. */ + MkAssocFunctionType(Function f, ImplOrTraitItemNode i, FunctionPosition pos) { + f = i.getASuccessor(_) and exists(pos.getTypeMention(f)) + } + +bindingset[condition, constraint, tp] +private Type traitConstraintTypeAt( + TypeMention condition, TypeMention constraint, TypeParameter tp, TypePath path +) { + BaseTypes::conditionSatisfiesConstraintTypeAt(_, condition, constraint, + TypePath::singleton(tp).appendInverse(path), result) +} + +/** + * Gets if the type of the function `f` when specialized for `i` at position + * `pos` at path `path` + */ +pragma[nomagic] +Type assocFunctionTypeAt(Function f, ImplOrTraitItemNode i, FunctionPosition pos, TypePath path) { + exists(MkAssocFunctionType(f, i, pos)) and + ( + // No specialization needed when the function is directly in the trait or + // impl block or the declared type is not a type parameter + (i.getAnAssocItem() = f or not result instanceof TypeParameter) and + result = pos.getTypeMention(f).resolveTypeAt(path) + or + not i.getAnAssocItem() = f and + exists(TypePath prefix, TypePath suffix, TypeParameter tp | + path = prefix.append(suffix) and + tp = pos.getTypeMention(f).resolveTypeAt(prefix) | - parent = i.(ImplItemNode).resolveTraitTy() and - parentMention = i.(ImplItemNode).getTraitPath() - or - parent = i.(TraitItemNode).resolveBound(parentMention) + if tp = TSelfTypeParameter(_) + then result = resolveImplOrTraitType(i, suffix) + else + exists(TraitItemNode trait, TypeMention condition, TypeMention constraint | + trait.getAnAssocItem() = f and + BaseTypes::rootTypesSatisfaction(_, TTrait(trait), _, condition, constraint) and + result = traitConstraintTypeAt(condition, constraint, tp, suffix) + | + condition = i.(Trait) or condition = i.(Impl).getSelfTy() + ) ) - } + ) +} /** - * The type of an associated function at a given position, when viewed as a member - * of a given trait or `impl` block. + * The type of an associated function at a given position, when its implicit + * `Self` type parameter is specialized to a given trait or `impl` block. * * Example: * @@ -126,64 +152,13 @@ private newtype TAssocFunctionType = * `self4` | `impl T2 for X` | `X` * `self5` | `impl T2 for X` | `X` */ -class AssocFunctionType extends TAssocFunctionType { - private predicate isFunctionType(Function f, FunctionPosition pos, ImplOrTraitItemNode i) { - this = MkAssocFunctionType(f, pos, i) - } - - private predicate isInheritedFunctionType( - Function f, FunctionPosition pos, TypeMention parentMention, TraitItemNode parent, - ImplOrTraitItemNode i - ) { - this = MkInheritedAssocFunctionType(f, pos, parentMention, parent, i) - } - +class AssocFunctionType extends MkAssocFunctionType { /** * Holds if this function type applies to the function `f` at position `pos`, * when viewed as a member of the `impl` or trait item `i`. */ - predicate appliesTo(Function f, FunctionPosition pos, ImplOrTraitItemNode i) { - this.isFunctionType(f, pos, i) - or - this.isInheritedFunctionType(f, pos, _, _, i) - } - - /** Gets the type at the given path. */ - pragma[nomagic] - Type getDeclaredTypeAt(TypePath path) { - exists(Function f, FunctionPosition pos | - this.isFunctionType(f, pos, _) and - result = pos.getTypeMention(f).resolveTypeAt(path) - ) - or - exists( - Function f, FunctionPosition pos, TypeMention parentMention, TraitItemNode parent, - AssocFunctionType parentType, ImplOrTraitItemNode i - | - this.isInheritedFunctionType(f, pos, parentMention, parent, i) and - parentType.appliesTo(f, pos, parent) - | - result = parentType.getDeclaredTypeAt(path) and - not result instanceof TypeParameter - or - exists(TypePath prefix, TypePath suffix | path = prefix.append(suffix) | - parentType.hasSelfTypeParameterAt(prefix) and - result = resolveImplOrTraitType(i, suffix) - or - exists(TypeParameter tp | - tp = parentType.getTypeParameterAt(prefix) and - result = parentMention.resolveTypeAt(TypePath::singleton(tp).appendInverse(suffix)) - ) - ) - ) - } - - pragma[nomagic] - private TypeParameter getTypeParameterAt(TypePath path) { result = this.getDeclaredTypeAt(path) } - - pragma[nomagic] - private predicate hasSelfTypeParameterAt(TypePath path) { - this.getTypeParameterAt(path) = TSelfTypeParameter(_) + predicate appliesTo(Function f, ImplOrTraitItemNode i, FunctionPosition pos) { + this = MkAssocFunctionType(f, i, pos) } /** @@ -196,7 +171,10 @@ class AssocFunctionType extends TAssocFunctionType { * traits when matching. */ Type getTypeAt(TypePath path) { - exists(Type t | t = this.getDeclaredTypeAt(path) | + exists(Function f, FunctionPosition pos, ImplOrTraitItemNode i, Type t | + this.appliesTo(f, i, pos) and + t = assocFunctionTypeAt(f, i, pos, path) + | not t instanceof SelfTypeParameter and result = t or @@ -206,7 +184,7 @@ class AssocFunctionType extends TAssocFunctionType { private TypeMention getTypeMention() { exists(Function f, FunctionPosition pos | - this.appliesTo(f, pos, _) and + this.appliesTo(f, _, pos) and result = pos.getTypeMention(f) ) } @@ -216,20 +194,6 @@ class AssocFunctionType extends TAssocFunctionType { Location getLocation() { result = this.getTypeMention().getLocation() } } -/** - * Holds if the type of the function `f` at position `pos` and path `path` inside - * `i` is `type`. - */ -pragma[nomagic] -predicate assocFunctionTypeAt( - Function f, ImplOrTraitItemNode i, FunctionPosition pos, TypePath path, Type type -) { - exists(AssocFunctionType aft | - aft.appliesTo(f, pos, i) and - type = aft.getDeclaredTypeAt(path) - ) -} - private Trait getALookupTrait(Type t) { result = t.(TypeParamTypeParameter).getTypeParam().(TypeParamItemNode).resolveABound() or diff --git a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll index d1d1b3387070..a827ef3cd792 100644 --- a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll +++ b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll @@ -729,7 +729,7 @@ module Make1 Input1> { } /** Provides logic related to base types. */ - private module BaseTypes { + module BaseTypes { /** * Holds if, when `tm1` is considered an instantiation of `tm2`, then at * the type parameter `tp` it has the type `t` at `path`. From c648aa69b8eace8cd2124e303ad3c3018564f8ac Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 30 Oct 2025 14:28:47 +0100 Subject: [PATCH 2/2] Rust: Rename predicates --- rust/ql/lib/codeql/rust/internal/TypeInference.qll | 2 +- .../rust/internal/typeinference/FunctionOverloading.qll | 4 ++-- .../codeql/rust/internal/typeinference/FunctionType.qll | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 4a53b5dee8e2..a94c893c2198 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -2024,7 +2024,7 @@ private module NonMethodResolution { ImplItemNode impl, NonMethodFunction implFunction ) { exists(TypePath path | - type = assocFunctionTypeAt(implFunction, impl, pos, path) and + type = getAssocFunctionTypeAt(implFunction, impl, pos, path) and implFunction.implements(traitFunction) and FunctionOverloading::traitTypeParameterOccurrence(trait, traitFunction, _, pos, path, _) | diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll index 9373f62b0e43..b58084e31cfb 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll @@ -79,7 +79,7 @@ predicate traitTypeParameterOccurrence( TypeParameter tp ) { f = trait.getASuccessor(functionName) and - tp = assocFunctionTypeAt(f, trait, pos, path) and + tp = getAssocFunctionTypeAt(f, trait, pos, path) and tp = trait.(TraitTypeAbstraction).getATypeParameter() } @@ -120,7 +120,7 @@ predicate functionResolutionDependsOnArgument( exists(TraitItemNode trait, string functionName | implHasSibling(impl, trait) and traitTypeParameterOccurrence(trait, _, functionName, pos, path, _) and - type = assocFunctionTypeAt(f, impl, pos, path) and + type = getAssocFunctionTypeAt(f, impl, pos, path) and f = impl.getASuccessor(functionName) and pos.isPosition() ) diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll index 4c4de4fa767a..789f0ca2e3c1 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll @@ -78,7 +78,7 @@ private newtype TAssocFunctionType = } bindingset[condition, constraint, tp] -private Type traitConstraintTypeAt( +private Type getTraitConstraintTypeAt( TypeMention condition, TypeMention constraint, TypeParameter tp, TypePath path ) { BaseTypes::conditionSatisfiesConstraintTypeAt(_, condition, constraint, @@ -90,7 +90,7 @@ private Type traitConstraintTypeAt( * `pos` at path `path` */ pragma[nomagic] -Type assocFunctionTypeAt(Function f, ImplOrTraitItemNode i, FunctionPosition pos, TypePath path) { +Type getAssocFunctionTypeAt(Function f, ImplOrTraitItemNode i, FunctionPosition pos, TypePath path) { exists(MkAssocFunctionType(f, i, pos)) and ( // No specialization needed when the function is directly in the trait or @@ -109,7 +109,7 @@ Type assocFunctionTypeAt(Function f, ImplOrTraitItemNode i, FunctionPosition pos exists(TraitItemNode trait, TypeMention condition, TypeMention constraint | trait.getAnAssocItem() = f and BaseTypes::rootTypesSatisfaction(_, TTrait(trait), _, condition, constraint) and - result = traitConstraintTypeAt(condition, constraint, tp, suffix) + result = getTraitConstraintTypeAt(condition, constraint, tp, suffix) | condition = i.(Trait) or condition = i.(Impl).getSelfTy() ) @@ -173,7 +173,7 @@ class AssocFunctionType extends MkAssocFunctionType { Type getTypeAt(TypePath path) { exists(Function f, FunctionPosition pos, ImplOrTraitItemNode i, Type t | this.appliesTo(f, i, pos) and - t = assocFunctionTypeAt(f, i, pos, path) + t = getAssocFunctionTypeAt(f, i, pos, path) | not t instanceof SelfTypeParameter and result = t