Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ module SatisfiesBlanketConstraint<
}

private module SatisfiesBlanketConstraintInput implements
SatisfiesConstraintInputSig<ArgumentTypeAndBlanketOffset>
SatisfiesTypeInputSig<ArgumentTypeAndBlanketOffset>
{
pragma[nomagic]
additional predicate relevantConstraint(
Expand All @@ -120,7 +120,7 @@ module SatisfiesBlanketConstraint<
}

private module SatisfiesBlanketConstraint =
SatisfiesConstraint<ArgumentTypeAndBlanketOffset, SatisfiesBlanketConstraintInput>;
SatisfiesType<ArgumentTypeAndBlanketOffset, SatisfiesBlanketConstraintInput>;

/**
* Holds if the argument type `at` satisfies the first non-trivial blanket
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,21 @@ private import TypeInference
private import FunctionType

pragma[nomagic]
private Type resolveNonTypeParameterTypeAt(TypeMention tm, TypePath path) {
private Type resolveNonTypeParameterTypeAt(PreTypeMention tm, TypePath path) {
result = tm.getTypeAt(path) and
not result instanceof TypeParameter
}

bindingset[t1, t2]
private predicate typeMentionEqual(TypeMention t1, TypeMention t2) {
private predicate typeMentionEqual(PreTypeMention t1, PreTypeMention t2) {
forex(TypePath path, Type type | resolveNonTypeParameterTypeAt(t1, path) = type |
resolveNonTypeParameterTypeAt(t2, path) = type
)
}

pragma[nomagic]
private predicate implSiblingCandidate(
Impl impl, TraitItemNode trait, Type rootType, TypeMention selfTy
Impl impl, TraitItemNode trait, Type rootType, PreTypeMention selfTy
) {
trait = impl.(ImplItemNode).resolveTraitTy() and
selfTy = impl.getSelfTy() and
Expand All @@ -52,7 +52,7 @@ pragma[inline]
private predicate implSiblings(TraitItemNode trait, Impl impl1, Impl impl2) {
impl1 != impl2 and
(
exists(Type rootType, TypeMention selfTy1, TypeMention selfTy2 |
exists(Type rootType, PreTypeMention selfTy1, PreTypeMention 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
Expand All @@ -76,6 +76,15 @@ private predicate implSiblings(TraitItemNode trait, Impl impl1, Impl impl2) {
pragma[nomagic]
private predicate implHasSibling(ImplItemNode impl, Trait trait) { implSiblings(trait, impl, _) }

pragma[nomagic]
predicate implHasAmbigousSiblingAt(ImplItemNode impl, Trait trait, TypePath path) {
exists(ImplItemNode impl2 |
implSiblings(trait, impl, impl2) and
resolveNonTypeParameterTypeAt(impl.getTraitPath(), path) !=
resolveNonTypeParameterTypeAt(impl2.getTraitPath(), path)
)
}

/**
* Holds if `f` is a function declared inside `trait`, and the type of `f` at
* `pos` and `path` is `traitTp`, which is a type parameter of `trait`.
Expand Down
58 changes: 29 additions & 29 deletions rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ private module Input implements InputSig1<Location>, InputSig2<PreTypeMention> {

class TypeAbstraction = TA::TypeAbstraction;

predicate typeAbstractionHasAmbigousConstraintAt(
TypeAbstraction abs, Type constraint, TypePath path
) {
FunctionOverloading::implHasAmbigousSiblingAt(abs, constraint.(TraitType).getTrait(), path)
}

class TypeArgumentPosition extends TTypeArgumentPosition {
int asMethodTypeArgumentPosition() { this = TMethodTypeArgumentPosition(result) }

Expand Down Expand Up @@ -127,17 +133,15 @@ private module Input implements InputSig1<Location>, InputSig2<PreTypeMention> {

PreTypeMention getABaseTypeMention(Type t) { none() }

Type getATypeParameterConstraint(TypeParameter tp, TypePath path) {
exists(TypeMention tm | result = tm.getTypeAt(path) |
tm = tp.(TypeParamTypeParameter).getTypeParam().getATypeBound().getTypeRepr() or
tm = tp.(SelfTypeParameter).getTrait() or
tm =
tp.(ImplTraitTypeTypeParameter)
.getImplTraitTypeRepr()
.getTypeBoundList()
.getABound()
.getTypeRepr()
)
PreTypeMention getATypeParameterConstraint(TypeParameter tp) {
result = tp.(TypeParamTypeParameter).getTypeParam().getATypeBound().getTypeRepr() or
result = tp.(SelfTypeParameter).getTrait() or
result =
tp.(ImplTraitTypeTypeParameter)
.getImplTraitTypeRepr()
.getTypeBoundList()
.getABound()
.getTypeRepr()
}

/**
Expand Down Expand Up @@ -1126,7 +1130,7 @@ private module ContextTyping {
or
exists(TypeParameter mid |
assocFunctionMentionsTypeParameterAtNonRetPos(i, f, mid) and
tp = getATypeParameterConstraint(mid, _)
tp = getATypeParameterConstraint(mid).getTypeAt(_)
)
}

Expand Down Expand Up @@ -2237,7 +2241,7 @@ private module MethodResolution {
}

private module MethodCallSatisfiesDerefConstraintInput implements
SatisfiesConstraintInputSig<MethodCallDerefCand>
SatisfiesTypeInputSig<MethodCallDerefCand>
{
pragma[nomagic]
predicate relevantConstraint(MethodCallDerefCand mc, Type constraint) {
Expand All @@ -2247,7 +2251,7 @@ private module MethodResolution {
}

private module MethodCallSatisfiesDerefConstraint =
SatisfiesConstraint<MethodCallDerefCand, MethodCallSatisfiesDerefConstraintInput>;
SatisfiesType<MethodCallDerefCand, MethodCallSatisfiesDerefConstraintInput>;

pragma[nomagic]
private AssociatedTypeTypeParameter getDerefTargetTypeParameter() {
Expand Down Expand Up @@ -3683,21 +3687,20 @@ final private class AwaitTarget extends Expr {
Type getTypeAt(TypePath path) { result = inferType(this, path) }
}

private module AwaitSatisfiesConstraintInput implements SatisfiesConstraintInputSig<AwaitTarget> {
private module AwaitSatisfiesTypeInput implements SatisfiesTypeInputSig<AwaitTarget> {
pragma[nomagic]
predicate relevantConstraint(AwaitTarget term, Type constraint) {
exists(term) and
constraint.(TraitType).getTrait() instanceof FutureTrait
}
}

private module AwaitSatisfiesConstraint =
SatisfiesConstraint<AwaitTarget, AwaitSatisfiesConstraintInput>;
private module AwaitSatisfiesType = SatisfiesType<AwaitTarget, AwaitSatisfiesTypeInput>;

pragma[nomagic]
private Type inferAwaitExprType(AstNode n, TypePath path) {
exists(TypePath exprPath |
AwaitSatisfiesConstraint::satisfiesConstraintType(n.(AwaitExpr).getExpr(), _, exprPath, result) and
AwaitSatisfiesType::satisfiesConstraintType(n.(AwaitExpr).getExpr(), _, exprPath, result) and
exprPath.isCons(getFutureOutputTypeParameter(), path)
)
}
Expand Down Expand Up @@ -3876,9 +3879,7 @@ final private class ForIterableExpr extends Expr {
Type getTypeAt(TypePath path) { result = inferType(this, path) }
}

private module ForIterableSatisfiesConstraintInput implements
SatisfiesConstraintInputSig<ForIterableExpr>
{
private module ForIterableSatisfiesTypeInput implements SatisfiesTypeInputSig<ForIterableExpr> {
predicate relevantConstraint(ForIterableExpr term, Type constraint) {
exists(term) and
exists(Trait t | t = constraint.(TraitType).getTrait() |
Expand All @@ -3899,15 +3900,15 @@ private AssociatedTypeTypeParameter getIntoIteratorItemTypeParameter() {
result = getAssociatedTypeTypeParameter(any(IntoIteratorTrait t).getItemType())
}

private module ForIterableSatisfiesConstraint =
SatisfiesConstraint<ForIterableExpr, ForIterableSatisfiesConstraintInput>;
private module ForIterableSatisfiesType =
SatisfiesType<ForIterableExpr, ForIterableSatisfiesTypeInput>;

pragma[nomagic]
private Type inferForLoopExprType(AstNode n, TypePath path) {
// type of iterable -> type of pattern (loop variable)
exists(ForExpr fe, TypePath exprPath, AssociatedTypeTypeParameter tp |
n = fe.getPat() and
ForIterableSatisfiesConstraint::satisfiesConstraintType(fe.getIterable(), _, exprPath, result) and
ForIterableSatisfiesType::satisfiesConstraintType(fe.getIterable(), _, exprPath, result) and
exprPath.isCons(tp, path)
|
tp = getIntoIteratorItemTypeParameter()
Expand All @@ -3933,21 +3934,20 @@ final private class InvokedClosureExpr extends Expr {
CallExpr getCall() { result = call }
}

private module InvokedClosureSatisfiesConstraintInput implements
SatisfiesConstraintInputSig<InvokedClosureExpr>
private module InvokedClosureSatisfiesTypeInput implements SatisfiesTypeInputSig<InvokedClosureExpr>
{
predicate relevantConstraint(InvokedClosureExpr term, Type constraint) {
exists(term) and
constraint.(TraitType).getTrait() instanceof FnOnceTrait
}
}

private module InvokedClosureSatisfiesConstraint =
SatisfiesConstraint<InvokedClosureExpr, InvokedClosureSatisfiesConstraintInput>;
private module InvokedClosureSatisfiesType =
SatisfiesType<InvokedClosureExpr, InvokedClosureSatisfiesTypeInput>;

/** Gets the type of `ce` when viewed as an implementation of `FnOnce`. */
private Type invokedClosureFnTypeAt(InvokedClosureExpr ce, TypePath path) {
InvokedClosureSatisfiesConstraint::satisfiesConstraintType(ce, _, path, result)
InvokedClosureSatisfiesType::satisfiesConstraintType(ce, _, path, result)
}

/**
Expand Down
58 changes: 28 additions & 30 deletions rust/ql/lib/codeql/rust/internal/typeinference/TypeMention.qll
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,16 @@ private module PreTypeMention = MkTypeMention<preGetAdditionalPathTypeAt/2>;

class PreTypeMention = PreTypeMention::TypeMention;

private class TraitOrTmTrait extends AstNode {
Type getTypeAt(TypePath path) {
pathTypeAsTraitAssoc(_, _, this, _, _) and
result = this.(PreTypeMention).getTypeAt(path)
or
result = TTrait(this) and
path.isEmpty()
}
}

/**
* Holds if `path` accesses an associated type `alias` from `trait` on a
* concrete type given by `tm`.
Expand All @@ -705,7 +715,7 @@ class PreTypeMention = PreTypeMention::TypeMention;
* when `path` is of the form `Self::AssocType`.
*/
private predicate pathConcreteTypeAssocType(
Path path, PreTypeMention tm, TraitItemNode trait, AstNode implOrTmTrait, TypeAlias alias
Path path, PreTypeMention tm, TraitItemNode trait, TraitOrTmTrait traitOrTmTrait, TypeAlias alias
) {
exists(Path qualifier |
qualifier = path.getQualifier() and
Expand All @@ -714,57 +724,45 @@ private predicate pathConcreteTypeAssocType(
// path of the form `<Type as Trait>::AssocType`
// ^^^ tm ^^^^^^^^^ name
exists(string name |
pathTypeAsTraitAssoc(path, tm, implOrTmTrait, trait, name) and
pathTypeAsTraitAssoc(path, tm, traitOrTmTrait, trait, name) and
getTraitAssocType(trait, name) = alias
)
or
// path of the form `Self::AssocType` within an `impl` block
// tm ^^^^ ^^^^^^^^^ name
implOrTmTrait =
any(ImplItemNode impl |
alias = resolvePath(path) and
qualifier = impl.getASelfPath() and
tm = impl.(Impl).getSelfTy() and
trait.getAnAssocItem() = alias
)
exists(ImplItemNode impl |
alias = resolvePath(path) and
qualifier = impl.getASelfPath() and
tm = impl.(Impl).getSelfTy() and
trait.getAnAssocItem() = alias and
traitOrTmTrait = trait
)
)
}

private module PathSatisfiesConstraintInput implements SatisfiesConstraintInputSig<PreTypeMention> {
predicate relevantConstraint(PreTypeMention tm, Type constraint) {
pathConcreteTypeAssocType(_, tm, constraint.(TraitType).getTrait(), _, _)
private module PathSatisfiesConstraintInput implements
SatisfiesConstraintInputSig<PreTypeMention, TraitOrTmTrait>
{
predicate relevantConstraint(PreTypeMention tm, TraitOrTmTrait constraint) {
pathConcreteTypeAssocType(_, tm, _, constraint, _)
}
}

private module PathSatisfiesConstraint =
SatisfiesConstraint<PreTypeMention, PathSatisfiesConstraintInput>;
SatisfiesConstraint<PreTypeMention, TraitOrTmTrait, PathSatisfiesConstraintInput>;

/**
* Gets the type of `path` at `typePath` when `path` accesses an associated type
* on a concrete type.
*/
private Type getPathConcreteAssocTypeAt(Path path, TypePath typePath) {
exists(
PreTypeMention tm, ImplItemNode impl, TraitItemNode trait, TraitType t, AstNode implOrTmTrait,
PreTypeMention tm, ImplItemNode impl, TraitItemNode trait, TraitOrTmTrait traitOrTmTrait,
TypeAlias alias, TypePath path0
|
pathConcreteTypeAssocType(path, tm, trait, implOrTmTrait, alias) and
t = TTrait(trait) and
PathSatisfiesConstraint::satisfiesConstraintTypeThrough(tm, impl, t, path0, result) and
pathConcreteTypeAssocType(path, tm, trait, traitOrTmTrait, alias) and
PathSatisfiesConstraint::satisfiesConstraintTypeThrough(tm, impl, traitOrTmTrait, path0, result) and
path0.isCons(TAssociatedTypeTypeParameter(trait, alias), typePath)
|
implOrTmTrait instanceof Impl
or
// When `path` is of the form `<Type as Trait>::AssocType` we need to check
// that `impl` is not more specific than the mentioned trait
implOrTmTrait =
any(PreTypeMention tmTrait |
not exists(TypePath path1, Type t1 |
t1 = impl.getTraitPath().(PreTypeMention).getTypeAt(path1) and
not t1 instanceof TypeParameter and
t1 != tmTrait.getTypeAt(path1)
)
)
)
}

Expand Down
33 changes: 33 additions & 0 deletions rust/ql/test/library-tests/type-inference/overloading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,3 +400,36 @@ mod from_default {
x
}
}

mod trait_bound_impl_overlap {
trait MyTrait<T> {
fn f(&self) -> T;
}

struct S<T>(T);

impl MyTrait<i32> for S<i32> {
fn f(&self) -> i32 {
0
}
}

impl MyTrait<i64> for S<i32> {
fn f(&self) -> i64 {
0
}
}

fn call_f<T1, T2: MyTrait<T1>>(x: T2) -> T1 {
x.f() // $ target=f
}

fn test() {
let x = S(0);
let y = call_f(x); // $ target=call_f type=y:i32
let z: i32 = y;

let x = S(0);
let y = call_f::<i32, _>(x); // $ target=call_f type=y:i32
}
}
Loading
Loading