Merge remote-tracking branch 'upstream/main' into addsub

This commit is contained in:
Geoffrey White
2026-01-22 16:03:42 +00:00
370 changed files with 64480 additions and 8879 deletions

View File

@@ -99,10 +99,11 @@ module Impl {
*/
cached
predicate isFromMacroExpansion(AstNode n) {
exists(AstNode macro |
exists(AstNode macro, Location l |
macro = getImmediatelyEnclosingMacroInvocation(n) and
not n = getATokenTreeNode(macro) and
not isAttributeMacroExpansionSourceLocation(macro, n.getLocation())
l = n.getLocation() and
not isAttributeMacroExpansionSourceLocation(macro, l)
)
or
isFromMacroExpansion(pragma[only_bind_into](getImmediatelyEnclosingMacroInvocation(n)))

View File

@@ -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
@@ -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())
}
}
}

View File

@@ -5,7 +5,10 @@
private import rust
private import codeql.rust.Concepts
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowSummary
private import codeql.rust.internal.PathResolution
private import codeql.rust.internal.typeinference.Type
private import codeql.rust.internal.typeinference.TypeMention
/**
* A call to the `starts_with` method on a `Path`.
@@ -19,6 +22,34 @@ private class StartswithCall extends Path::SafeAccessCheck::Range, MethodCall {
}
}
/**
* A flow summary for the [reflexive implementation of the `From` trait][1].
*
* Blanket implementations currently don't have a canonical path, so we cannot
* use models-as-data for this model.
*
* [1]: https://doc.rust-lang.org/std/convert/trait.From.html#impl-From%3CT%3E-for-T
*/
private class ReflexiveFrom extends SummarizedCallable::Range {
ReflexiveFrom() {
exists(ImplItemNode impl |
impl.resolveTraitTy().(Trait).getCanonicalPath() = "core::convert::From" and
this = impl.getAssocItem("from") and
resolvePath(this.getParam(0).getTypeRepr().(PathTypeRepr).getPath()) =
impl.getBlanketImplementationTypeParam()
)
}
override predicate propagatesFlow(
string input, string output, boolean preservesValue, string model
) {
input = "Argument[0]" and
output = "ReturnValue" and
preservesValue = true and
model = "ReflexiveFrom"
}
}
/**
* The [`Option` enum][1].
*
@@ -143,23 +174,48 @@ class FutureTrait extends Trait {
TypeAlias getOutputType() { result = this.(TraitItemNode).getAssocItem("Output") }
}
/** A function trait `FnOnce`, `FnMut`, or `Fn`. */
abstract private class AnyFnTraitImpl extends Trait {
/** Gets the `Args` type parameter of this trait. */
TypeParam getTypeParam() { result = this.getGenericParamList().getGenericParam(0) }
}
final class AnyFnTrait = AnyFnTraitImpl;
/**
* The [`FnOnce` trait][1].
*
* [1]: https://doc.rust-lang.org/std/ops/trait.FnOnce.html
*/
class FnOnceTrait extends Trait {
class FnOnceTrait extends AnyFnTraitImpl {
pragma[nomagic]
FnOnceTrait() { this.getCanonicalPath() = "core::ops::function::FnOnce" }
/** Gets the type parameter of this trait. */
TypeParam getTypeParam() { result = this.getGenericParamList().getGenericParam(0) }
/** Gets the `Output` associated type. */
pragma[nomagic]
TypeAlias getOutputType() { result = this.(TraitItemNode).getAssocItem("Output") }
}
/**
* The [`FnMut` trait][1].
*
* [1]: https://doc.rust-lang.org/std/ops/trait.FnMut.html
*/
class FnMutTrait extends AnyFnTraitImpl {
pragma[nomagic]
FnMutTrait() { this.getCanonicalPath() = "core::ops::function::FnMut" }
}
/**
* The [`Fn` trait][1].
*
* [1]: https://doc.rust-lang.org/std/ops/trait.Fn.html
*/
class FnTrait extends AnyFnTraitImpl {
pragma[nomagic]
FnTrait() { this.getCanonicalPath() = "core::ops::function::Fn" }
}
/**
* The [`Iterator` trait][1].
*

View File

@@ -117,8 +117,6 @@ module SatisfiesBlanketConstraint<
predicate relevantConstraint(ArgumentTypeAndBlanketOffset ato, Type constraint) {
relevantConstraint(ato, _, constraint.(TraitType).getTrait())
}
predicate useUniversalConditions() { none() }
}
private module SatisfiesBlanketConstraint =
@@ -126,7 +124,7 @@ module SatisfiesBlanketConstraint<
/**
* Holds if the argument type `at` satisfies the first non-trivial blanket
* constraint of `impl`.
* constraint of `impl`, or if there are no non-trivial constraints of `impl`.
*/
pragma[nomagic]
predicate satisfiesBlanketConstraint(ArgumentType at, ImplItemNode impl) {
@@ -135,6 +133,11 @@ module SatisfiesBlanketConstraint<
SatisfiesBlanketConstraintInput::relevantConstraint(ato, impl, traitBound) and
SatisfiesBlanketConstraint::satisfiesConstraintType(ato, TTrait(traitBound), _, _)
)
or
exists(TypeParam blanketTypeParam |
hasBlanketCandidate(at, impl, _, blanketTypeParam) and
not hasFirstNonTrivialTraitBound(blanketTypeParam, _)
)
}
/**

View File

@@ -8,6 +8,7 @@
private import rust
private import codeql.rust.internal.PathResolution
private import Type
private import TypeAbstraction
private import TypeMention
private import TypeInference
private import FunctionType
@@ -34,6 +35,12 @@ private predicate implSiblingCandidate(
rootType = selfTy.resolveType()
}
pragma[nomagic]
private predicate blanketImplSiblingCandidate(ImplItemNode impl, Trait trait) {
impl.isBlanketImplementation() and
trait = impl.resolveTraitTy()
}
/**
* Holds if `impl1` and `impl2` are a sibling implementations of `trait`. We
* consider implementations to be siblings if they implement the same trait for
@@ -43,17 +50,22 @@ private predicate implSiblingCandidate(
*/
pragma[inline]
private predicate implSiblings(TraitItemNode trait, Impl impl1, Impl impl2) {
exists(Type rootType, TypeMention selfTy1, TypeMention selfTy2 |
impl1 != impl2 and
implSiblingCandidate(impl1, trait, rootType, selfTy1) and
implSiblingCandidate(impl2, trait, rootType, selfTy2) and
// In principle the second conjunct below should be superflous, but we still
// have ill-formed type mentions for types that we don't understand. For
// those checking both directions restricts further. Note also that we check
// syntactic equality, whereas equality up to renaming would be more
// correct.
typeMentionEqual(selfTy1, selfTy2) and
typeMentionEqual(selfTy2, selfTy1)
impl1 != impl2 and
(
exists(Type rootType, TypeMention selfTy1, TypeMention selfTy2 |
implSiblingCandidate(impl1, trait, rootType, selfTy1) and
implSiblingCandidate(impl2, trait, rootType, selfTy2) and
// In principle the second conjunct below should be superflous, but we still
// have ill-formed type mentions for types that we don't understand. For
// those checking both directions restricts further. Note also that we check
// syntactic equality, whereas equality up to renaming would be more
// correct.
typeMentionEqual(selfTy1, selfTy2) and
typeMentionEqual(selfTy2, selfTy1)
)
or
blanketImplSiblingCandidate(impl1, trait) and
blanketImplSiblingCandidate(impl2, trait)
)
}
@@ -62,7 +74,7 @@ private predicate implSiblings(TraitItemNode trait, Impl impl1, Impl impl2) {
* exists for the same type.
*/
pragma[nomagic]
private predicate implHasSibling(Impl impl, Trait trait) { implSiblings(trait, impl, _) }
private predicate implHasSibling(ImplItemNode impl, Trait trait) { implSiblings(trait, impl, _) }
/**
* Holds if type parameter `tp` of `trait` occurs in the function `f` with the name

View File

@@ -1,8 +1,9 @@
private import rust
private import codeql.rust.internal.PathResolution
private import TypeInference
private import Type
private import TypeAbstraction
private import TypeMention
private import TypeInference
private newtype TFunctionPosition =
TArgumentFunctionPosition(ArgumentPosition pos) or
@@ -355,7 +356,7 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
string toString() { result = call.toString() + " [arg " + pos + "]" }
}
private module ArgIsInstantiationOfInput implements
private module ArgIsInstantiationOfToIndexInput implements
IsInstantiationOfInputSig<CallAndPos, AssocFunctionType>
{
pragma[nomagic]
@@ -388,7 +389,7 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
}
private module ArgIsInstantiationOfToIndex =
ArgIsInstantiationOf<CallAndPos, ArgIsInstantiationOfInput>;
ArgIsInstantiationOf<CallAndPos, ArgIsInstantiationOfToIndexInput>;
pragma[nomagic]
private predicate argsAreInstantiationsOfToIndex(
@@ -412,4 +413,24 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
rnk = max(int r | toCheckRanked(i, f, _, r))
)
}
pragma[nomagic]
private predicate argsAreNotInstantiationsOf0(
Input::Call call, FunctionPosition pos, ImplOrTraitItemNode i
) {
ArgIsInstantiationOfToIndex::argIsNotInstantiationOf(MkCallAndPos(call, pos), i, _, _)
}
/**
* Holds if _some_ argument of `call` has a type that is not an instantiation of the
* type of the corresponding parameter of `f` inside `i`.
*/
pragma[nomagic]
predicate argsAreNotInstantiationsOf(Input::Call call, ImplOrTraitItemNode i, Function f) {
exists(FunctionPosition pos |
argsAreNotInstantiationsOf0(call, pos, i) and
call.hasTargetCand(i, f) and
Input::toCheck(i, f, pos, _)
)
}
}

View File

@@ -9,10 +9,17 @@ private import codeql.rust.elements.internal.generated.Synth
private import codeql.rust.frameworks.stdlib.Stdlib
private import codeql.rust.frameworks.stdlib.Builtins as Builtins
/** Gets a type alias of `trait` or of a supertrait of `trait`. */
private TypeAlias getTraitTypeAlias(Trait trait) {
result = trait.getSupertrait*().getAssocItemList().getAnAssocItem()
}
/**
* 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
@@ -24,10 +31,7 @@ private import codeql.rust.frameworks.stdlib.Builtins as Builtins
*/
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
@@ -39,8 +43,10 @@ newtype TType =
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
@@ -90,6 +96,7 @@ abstract class Type extends TType {
class TupleType extends StructType {
private int arity;
pragma[nomagic]
TupleType() { arity = this.getTypeItem().(Builtins::TupleType).getArity() }
/** Gets the arity of this tuple type. */
@@ -197,6 +204,7 @@ class TraitType extends Type, TTrait {
* Array types like `[i64; 5]` are modeled as normal generic types.
*/
class ArrayType extends StructType {
pragma[nomagic]
ArrayType() { this.getTypeItem() instanceof Builtins::ArrayType }
override string toString() { result = "[;]" }
@@ -210,12 +218,14 @@ TypeParamTypeParameter getArrayTypeParameter() {
abstract class RefType extends StructType { }
class RefMutType extends RefType {
pragma[nomagic]
RefMutType() { this.getTypeItem() instanceof Builtins::RefMutType }
override string toString() { result = "&mut" }
}
class RefSharedType extends RefType {
pragma[nomagic]
RefSharedType() { this.getTypeItem() instanceof Builtins::RefSharedType }
override string toString() { result = "&" }
@@ -270,17 +280,10 @@ class DynTraitType extends Type, TDynTraitType {
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 }
@@ -313,6 +316,7 @@ class ImplTraitReturnType extends ImplTraitType {
* with a single type argument.
*/
class SliceType extends StructType {
pragma[nomagic]
SliceType() { this.getTypeItem() instanceof Builtins::SliceType }
override string toString() { result = "[]" }
@@ -339,12 +343,14 @@ TypeParamTypeParameter getPtrTypeParameter() {
}
class PtrMutType extends PtrType {
pragma[nomagic]
PtrMutType() { this.getTypeItem() instanceof Builtins::PtrMutType }
override string toString() { result = "*mut" }
}
class PtrConstType extends PtrType {
pragma[nomagic]
PtrConstType() { this.getTypeItem() instanceof Builtins::PtrConstType }
override string toString() { result = "*const" }
@@ -427,30 +433,54 @@ class TypeParamTypeParameter extends TypeParameter, TTypeParamTypeParameter {
* // ...
* }
* ```
* 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
* trait, that is, it is not inherited from a supertrait.
*/
predicate isDirect() { trait.(TraitItemNode).getAnAssocItem() = typeAlias }
override string toString() { result = typeAlias.getName().getText() }
override ItemNode getDeclaringItem() { result = trait }
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`. */
AssociatedTypeTypeParameter getAssociatedTypeTypeParameter(TypeAlias typeAlias) {
result.isDirect() and result.getTypeAlias() = typeAlias
}
/** Gets the dyn type type-parameter corresponding directly to `typeAlias`. */
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() }
@@ -465,7 +495,7 @@ class DynTraitTypeParameter extends TypeParameter, TDynTraitTypeParameter {
TypeParameter getTraitTypeParameter() {
result.(TypeParamTypeParameter).getTypeParam() = n
or
result.(AssociatedTypeTypeParameter).getTypeAlias() = n
result = TAssociatedTypeTypeParameter(trait, n)
}
private string toStringInner() {
@@ -546,58 +576,6 @@ class ImplTraitTypeTypeParameter extends ImplTraitType, TypeParameter {
override TypeParameter getPositionalTypeParameter(int i) { none() }
}
/**
* A type abstraction. I.e., a place in the program where type variables are
* introduced.
*
* Example:
* ```rust
* impl<A, B> Foo<A, B> { }
* // ^^^^^^ a type abstraction
* ```
*/
abstract class TypeAbstraction extends AstNode {
abstract TypeParameter getATypeParameter();
}
final class ImplTypeAbstraction extends TypeAbstraction, Impl {
override TypeParamTypeParameter getATypeParameter() {
result.getTypeParam() = this.getGenericParamList().getATypeParam()
}
}
final class DynTypeAbstraction extends TypeAbstraction, DynTraitTypeRepr {
override TypeParameter getATypeParameter() {
result = any(DynTraitTypeParameter tp | tp.getTrait() = this.getTrait()).getTraitTypeParameter()
}
}
final class TraitTypeAbstraction extends TypeAbstraction, Trait {
override TypeParameter getATypeParameter() {
result.(TypeParamTypeParameter).getTypeParam() = this.getGenericParamList().getATypeParam()
or
result.(AssociatedTypeTypeParameter).getTrait() = this
or
result.(SelfTypeParameter).getTrait() = this
}
}
final class TypeBoundTypeAbstraction extends TypeAbstraction, TypeBound {
override TypeParameter getATypeParameter() { none() }
}
final class SelfTypeBoundTypeAbstraction extends TypeAbstraction, Name {
SelfTypeBoundTypeAbstraction() { any(TraitTypeAbstraction trait).getName() = this }
override TypeParameter getATypeParameter() { none() }
}
final class ImplTraitTypeReprAbstraction extends TypeAbstraction, ImplTraitTypeRepr {
override TypeParameter getATypeParameter() {
implTraitTypeParam(this, _, result.(TypeParamTypeParameter).getTypeParam())
}
}
/**
* Holds if `t` is a valid complex [`self` root type][1].
*

View File

@@ -0,0 +1,79 @@
private import rust
private import codeql.rust.elements.internal.generated.Raw
private import codeql.rust.elements.internal.generated.Synth
private import Type
/**
* A type abstraction. I.e., a place in the program where type variables are
* introduced.
*
* Example:
* ```rust
* impl<A, B> Foo<A, B> { }
* // ^^^^^^ a type abstraction
* ```
*/
abstract class TypeAbstraction extends AstNode {
abstract TypeParameter getATypeParameter();
}
final class ImplTypeAbstraction extends TypeAbstraction, Impl {
override TypeParamTypeParameter getATypeParameter() {
result.getTypeParam() = this.getGenericParamList().getATypeParam()
}
}
private predicate idDynTraitTypeRepr(Raw::DynTraitTypeRepr x, Raw::DynTraitTypeRepr y) { x = y }
private predicate idOfDynTraitTypeRepr(Raw::DynTraitTypeRepr x, int y) =
equivalenceRelation(idDynTraitTypeRepr/2)(x, y)
private int idOfDynTraitTypeRepr(DynTraitTypeRepr node) {
idOfDynTraitTypeRepr(Synth::convertAstNodeToRaw(node), result)
}
/** Holds if `dt` is the (arbitrarily chosen) canonical dyn trait type abstraction for `trait`. */
private predicate canonicalDynTraitTypeAbstraction(DynTraitTypeRepr dt) {
exists(Trait trait |
dt = min(DynTraitTypeRepr d | d.getTrait() = trait | d order by idOfDynTraitTypeRepr(d))
)
}
final class DynTypeAbstraction extends TypeAbstraction, DynTraitTypeRepr {
DynTypeAbstraction() {
// We pick a "canonical" `dyn Trait` in order to avoid including multiple
// entries in `conditionSatisfiesConstraint` with the exact same effect when
// `dyn Trait` occurs multiple times for the same trait.
canonicalDynTraitTypeAbstraction(this)
}
override TypeParameter getATypeParameter() {
result = any(DynTraitTypeParameter tp | tp.getTrait() = this.getTrait()).getTraitTypeParameter()
}
}
final class TraitTypeAbstraction extends TypeAbstraction, Trait {
override TypeParameter getATypeParameter() {
result.(TypeParamTypeParameter).getTypeParam() = this.getGenericParamList().getATypeParam()
or
result.(AssociatedTypeTypeParameter).getTrait() = this
or
result.(SelfTypeParameter).getTrait() = this
}
}
final class TypeBoundTypeAbstraction extends TypeAbstraction, TypeBound {
override TypeParameter getATypeParameter() { none() }
}
final class SelfTypeBoundTypeAbstraction extends TypeAbstraction, Name {
SelfTypeBoundTypeAbstraction() { any(TraitTypeAbstraction trait).getName() = this }
override TypeParameter getATypeParameter() { none() }
}
final class ImplTraitTypeReprAbstraction extends TypeAbstraction, ImplTraitTypeRepr {
override TypeParamTypeParameter getATypeParameter() {
exists(TImplTraitTypeParameter(this, result.getTypeParam()))
}
}

View File

@@ -5,6 +5,8 @@ private import codeql.util.Option
private import rust
private import codeql.rust.internal.PathResolution
private import Type
private import TypeAbstraction
private import TypeAbstraction as TA
private import Type as T
private import TypeMention
private import codeql.rust.internal.typeinference.DerefChain
@@ -37,7 +39,7 @@ private module Input1 implements InputSig1<Location> {
class TypeParameter = T::TypeParameter;
class TypeAbstraction = T::TypeAbstraction;
class TypeAbstraction = TA::TypeAbstraction;
class TypeArgumentPosition extends TTypeArgumentPosition {
int asMethodTypeArgumentPosition() { this = TMethodTypeArgumentPosition(result) }
@@ -90,7 +92,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),
@@ -102,10 +104,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()
)
@@ -1284,6 +1289,13 @@ private class BorrowKind extends TBorrowKind {
}
}
// for now, we do not handle ambiguous targets when one of the types is itself
// a constrained type parameter; we should be checking the constraints in this case
private predicate typeCanBeUsedForDisambiguation(Type t) {
not t instanceof TypeParameter or
t.(TypeParamTypeParameter).getTypeParam() = any(TypeParam tp | not tp.hasTypeBound())
}
/**
* Provides logic for resolving calls to methods.
*
@@ -2188,8 +2200,6 @@ private module MethodResolution {
exists(mc) and
constraint.(TraitType).getTrait() instanceof DerefTrait
}
predicate useUniversalConditions() { none() }
}
private module MethodCallSatisfiesDerefConstraint =
@@ -2229,7 +2239,8 @@ private module MethodResolution {
methodCallBlanketLikeCandidate(mc, _, impl, _, blanketPath, blanketTypeParam) and
// Only apply blanket implementations when no other implementations are possible;
// this is to account for codebases that use the (unstable) specialization feature
// (https://rust-lang.github.io/rfcs/1210-impl-specialization.html)
// (https://rust-lang.github.io/rfcs/1210-impl-specialization.html), as well as
// cases where our blanket implementation filtering is not precise enough.
(mcc.hasNoCompatibleNonBlanketTarget() or not impl.isBlanketImplementation())
|
borrow.isNoBorrow()
@@ -2379,10 +2390,7 @@ private module MethodResolution {
exists(TypePath path, Type t0 |
FunctionOverloading::functionResolutionDependsOnArgument(i, f, pos, path, t0) 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
not t0 instanceof TypeParameter
typeCanBeUsedForDisambiguation(t0)
)
}
@@ -2741,7 +2749,7 @@ private module NonMethodResolution {
* Gets the blanket function that this call may resolve to, if any.
*/
pragma[nomagic]
private NonMethodFunction resolveCallTargetBlanketCand(ImplItemNode impl) {
NonMethodFunction resolveCallTargetBlanketCand(ImplItemNode impl) {
exists(string name |
this.hasNameAndArity(pragma[only_bind_into](name), _) and
ArgIsInstantiationOfBlanketParam::argIsInstantiationOf(MkCallAndBlanketPos(this, _), impl, _) and
@@ -2756,12 +2764,11 @@ private module NonMethodResolution {
predicate hasTrait() { exists(this.getTrait()) }
pragma[nomagic]
NonMethodFunction resolveAssocCallTargetCand(ImplItemNode i) {
NonMethodFunction resolveCallTargetNonBlanketCand(ImplItemNode i) {
not this.hasTrait() and
result = this.getPathResolutionResolved() and
result = i.getASuccessor(_)
or
result = this.resolveCallTargetBlanketCand(i)
result = i.getASuccessor(_) and
FunctionOverloading::functionResolutionDependsOnArgument(_, result, _, _, _)
}
AstNode getNodeAt(FunctionPosition pos) {
@@ -2793,6 +2800,21 @@ private module NonMethodResolution {
trait = this.getTrait()
}
/**
* Holds if this call has no compatible non-blanket target, and it has some
* candidate blanket target.
*/
pragma[nomagic]
predicate hasNoCompatibleNonBlanketTarget() {
this.resolveCallTargetBlanketLikeCandidate(_, _, _, _) and
not exists(this.resolveCallTargetViaPathResolution()) and
forall(ImplOrTraitItemNode i, Function f |
this.(NonMethodArgsAreInstantiationsOfNonBlanketInput::Call).hasTargetCand(i, f)
|
NonMethodArgsAreInstantiationsOfNonBlanket::argsAreNotInstantiationsOf(this, i, f)
)
}
/**
* Gets the target of this call, which can be resolved using only path resolution.
*/
@@ -2811,7 +2833,9 @@ private module NonMethodResolution {
result = this.resolveCallTargetBlanketCand(i) and
not FunctionOverloading::functionResolutionDependsOnArgument(_, result, _, _, _)
or
NonMethodArgsAreInstantiationsOf::argsAreInstantiationsOf(this, i, result)
NonMethodArgsAreInstantiationsOfBlanket::argsAreInstantiationsOf(this, i, result)
or
NonMethodArgsAreInstantiationsOfNonBlanket::argsAreInstantiationsOf(this, i, result)
}
pragma[nomagic]
@@ -2850,7 +2874,12 @@ private module NonMethodResolution {
) {
exists(NonMethodCall fc, FunctionPosition pos |
fcp = MkCallAndBlanketPos(fc, pos) and
fc.resolveCallTargetBlanketLikeCandidate(impl, pos, blanketPath, blanketTypeParam)
fc.resolveCallTargetBlanketLikeCandidate(impl, pos, blanketPath, blanketTypeParam) and
// Only apply blanket implementations when no other implementations are possible;
// this is to account for codebases that use the (unstable) specialization feature
// (https://rust-lang.github.io/rfcs/1210-impl-specialization.html), as well as
// cases where our blanket implementation filtering is not precise enough.
(fc.hasNoCompatibleNonBlanketTarget() or not impl.isBlanketImplementation())
)
}
}
@@ -2885,37 +2914,24 @@ private module NonMethodResolution {
private module ArgIsInstantiationOfBlanketParam =
ArgIsInstantiationOf<CallAndBlanketPos, ArgIsInstantiationOfBlanketParamInput>;
private module NonMethodArgsAreInstantiationsOfInput implements ArgsAreInstantiationsOfInputSig {
private module NonMethodArgsAreInstantiationsOfBlanketInput implements
ArgsAreInstantiationsOfInputSig
{
predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t) {
t.appliesTo(f, i, pos) and
(
exists(Type t0 |
// 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
not t0 instanceof TypeParameter
|
FunctionOverloading::functionResolutionDependsOnArgument(i, f, pos, _, t0)
or
traitFunctionDependsOnPos(_, _, pos, t0, i, f)
)
exists(Type t0 | typeCanBeUsedForDisambiguation(t0) |
FunctionOverloading::functionResolutionDependsOnArgument(i, f, pos, _, t0)
or
// match against the trait function itself
exists(Trait trait |
FunctionOverloading::traitTypeParameterOccurrence(trait, f, _, pos, _,
TSelfTypeParameter(trait))
)
traitFunctionDependsOnPos(_, _, pos, t0, i, f)
)
}
class Call extends NonMethodCall {
final class Call extends NonMethodCall {
Type getArgType(FunctionPosition pos, TypePath path) {
result = inferType(this.getNodeAt(pos), path)
}
predicate hasTargetCand(ImplOrTraitItemNode i, Function f) {
f = this.resolveAssocCallTargetCand(i)
or
predicate hasTraitResolvedCand(ImplOrTraitItemNode i, Function f) {
exists(TraitItemNode trait, NonMethodFunction resolved, ImplItemNode i1, Function f1 |
this.hasTraitResolved(trait, resolved) and
traitFunctionDependsOnPos(trait, resolved, _, _, i1, f1)
@@ -2927,11 +2943,45 @@ private module NonMethodResolution {
i = trait
)
}
predicate hasTargetCand(ImplOrTraitItemNode i, Function f) {
f = this.resolveCallTargetBlanketCand(i)
or
this.hasTraitResolvedCand(i, f) and
BlanketImplementation::isBlanketLike(i, _, _)
}
}
}
private module NonMethodArgsAreInstantiationsOf =
ArgsAreInstantiationsOf<NonMethodArgsAreInstantiationsOfInput>;
private module NonMethodArgsAreInstantiationsOfBlanket =
ArgsAreInstantiationsOf<NonMethodArgsAreInstantiationsOfBlanketInput>;
private module NonMethodArgsAreInstantiationsOfNonBlanketInput implements
ArgsAreInstantiationsOfInputSig
{
predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t) {
NonMethodArgsAreInstantiationsOfBlanketInput::toCheck(i, f, pos, t)
or
// match against the trait function itself
t.appliesTo(f, i, pos) and
exists(Trait trait |
FunctionOverloading::traitTypeParameterOccurrence(trait, f, _, pos, _,
TSelfTypeParameter(trait))
)
}
class Call extends NonMethodArgsAreInstantiationsOfBlanketInput::Call {
predicate hasTargetCand(ImplOrTraitItemNode i, Function f) {
f = this.resolveCallTargetNonBlanketCand(i)
or
this.hasTraitResolvedCand(i, f) and
not BlanketImplementation::isBlanketLike(i, _, _)
}
}
}
private module NonMethodArgsAreInstantiationsOfNonBlanket =
ArgsAreInstantiationsOf<NonMethodArgsAreInstantiationsOfNonBlanketInput>;
}
abstract private class TupleLikeConstructor extends Addressable {
@@ -3507,12 +3557,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]
@@ -3561,8 +3611,6 @@ private module AwaitSatisfiesConstraintInput implements SatisfiesConstraintInput
exists(term) and
constraint.(TraitType).getTrait() instanceof FutureTrait
}
predicate useUniversalConditions() { none() }
}
pragma[nomagic]
@@ -3759,18 +3807,16 @@ private module ForIterableSatisfiesConstraintInput implements
t instanceof IntoIteratorTrait
)
}
predicate useUniversalConditions() { none() }
}
pragma[nomagic]
private AssociatedTypeTypeParameter getIteratorItemTypeParameter() {
result.getTypeAlias() = any(IteratorTrait t).getItemType()
result = getAssociatedTypeTypeParameter(any(IteratorTrait t).getItemType())
}
pragma[nomagic]
private AssociatedTypeTypeParameter getIntoIteratorItemTypeParameter() {
result.getTypeAlias() = any(IntoIteratorTrait t).getItemType()
result = getAssociatedTypeTypeParameter(any(IntoIteratorTrait t).getItemType())
}
pragma[nomagic]
@@ -3812,8 +3858,6 @@ private module InvokedClosureSatisfiesConstraintInput implements
exists(term) and
constraint.(TraitType).getTrait() instanceof FnOnceTrait
}
predicate useUniversalConditions() { none() }
}
/** Gets the type of `ce` when viewed as an implementation of `FnOnce`. */
@@ -3822,22 +3866,35 @@ private Type invokedClosureFnTypeAt(InvokedClosureExpr ce, TypePath path) {
_, path, result)
}
/** Gets the path to a closure's return type. */
private TypePath closureReturnPath() {
result = TypePath::singleton(TDynTraitTypeParameter(any(FnOnceTrait t).getOutputType()))
/**
* Gets the root type of a closure.
*
* We model closures as `dyn Fn` trait object types. A closure might implement
* only `Fn`, `FnMut`, or `FnOnce`. But since `Fn` is a subtrait of the others,
* giving closures the type `dyn Fn` works well in practice -- even if not
* entirely accurate.
*/
private DynTraitType closureRootType() {
result = TDynTraitType(any(FnTrait t)) // always exists because of the mention in `builtins/mentions.rs`
}
/** Gets the path to a closure with arity `arity`s `index`th parameter type. */
/** Gets the path to a closure's return type. */
private TypePath closureReturnPath() {
result =
TypePath::singleton(TDynTraitTypeParameter(any(FnTrait t), 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(FnTrait 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()))
}
/**
@@ -3869,9 +3926,7 @@ private Type inferDynamicCallExprType(Expr n, TypePath path) {
or
// _If_ the invoked expression has the type of a closure, then we propagate
// the surrounding types into the closure.
exists(int arity, TypePath path0 |
ce.getTypeAt(TypePath::nil()).(DynTraitType).getTrait() instanceof FnOnceTrait
|
exists(int arity, TypePath path0 | ce.getTypeAt(TypePath::nil()) = closureRootType() |
// Propagate the type of arguments to the parameter types of closure
exists(int index, ArgList args |
n = ce and
@@ -3895,10 +3950,10 @@ private Type inferClosureExprType(AstNode n, TypePath path) {
exists(ClosureExpr ce |
n = ce and
path.isEmpty() and
result = TDynTraitType(any(FnOnceTrait t)) // always exists because of the mention in `builtins/mentions.rs`
result = closureRootType()
or
n = ce and
path = TypePath::singleton(TDynTraitTypeParameter(any(FnOnceTrait t).getTypeParam())) and
path = TypePath::singleton(TDynTraitTypeParameter(_, any(FnTrait t).getTypeParam())) and
result.(TupleType).getArity() = ce.getNumberOfParams()
or
// Propagate return type annotation to body

View File

@@ -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.

View File

@@ -4,6 +4,7 @@ private import rust
private import codeql.rust.internal.PathResolution
private import codeql.rust.frameworks.stdlib.Stdlib
private import Type
private import TypeAbstraction
private import TypeInference
/** An AST node that may mention a type. */
@@ -148,30 +149,11 @@ class NonAliasPathTypeMention extends PathTypeMention {
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]
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.
@@ -231,7 +213,7 @@ class NonAliasPathTypeMention extends PathTypeMention {
// associated types of `Fn` and `FnMut` yet.
//
// [1]: https://doc.rust-lang.org/reference/paths.html#grammar-TypePathFn
exists(FnOnceTrait t, PathSegment s |
exists(AnyFnTrait t, PathSegment s |
t = resolved and
s = this.getSegment() and
s.hasParenthesizedArgList()
@@ -239,7 +221,7 @@ class NonAliasPathTypeMention extends PathTypeMention {
tp = TTypeParamTypeParameter(t.getTypeParam()) and
result = s.getParenthesizedArgList().(TypeMention).resolveTypeAt(path)
or
tp = TAssociatedTypeTypeParameter(t.getOutputType()) and
tp = TAssociatedTypeTypeParameter(t, any(FnOnceTrait tr).getOutputType()) and
(
result = s.getRetType().getTypeRepr().(TypeMention).resolveTypeAt(path)
or
@@ -249,19 +231,47 @@ class NonAliasPathTypeMention extends PathTypeMention {
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 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()
)
}
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
@@ -279,9 +289,9 @@ class NonAliasPathTypeMention extends PathTypeMention {
// 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))
)
}
@@ -299,7 +309,7 @@ class NonAliasPathTypeMention extends PathTypeMention {
or
result = TTypeParamTypeParameter(resolved)
or
result = TAssociatedTypeTypeParameter(resolved)
result = TAssociatedTypeTypeParameter(resolvePath(this.getQualifier()), resolved)
}
override Type resolvePathTypeAt(TypePath typePath) {
@@ -384,9 +394,8 @@ class TraitMention extends TypeMention instanceof TraitItemNode {
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 |
@@ -540,7 +549,7 @@ class DynTraitTypeReprMention extends TypeMention instanceof DynTraitTypeRepr {
// 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.
@@ -555,7 +564,14 @@ class DynTypeBoundListMention extends TypeMention instanceof TypeBoundList {
private Trait trait;
DynTypeBoundListMention() {
exists(DynTraitTypeRepr dyn | this = dyn.getTypeBoundList() and trait = dyn.getTrait())
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 resolveTypeAt(TypePath path) {