Skip to content

Commit 7f122f8

Browse files
committed
Rust: Only infer types from trait bounds when their implementation is unambiguous
1 parent 5c458ce commit 7f122f8

File tree

7 files changed

+227
-133
lines changed

7 files changed

+227
-133
lines changed

rust/ql/lib/codeql/rust/internal/typeinference/BlanketImplementation.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ module SatisfiesBlanketConstraint<
100100
}
101101

102102
private module SatisfiesBlanketConstraintInput implements
103-
SatisfiesConstraintInputSig<ArgumentTypeAndBlanketOffset>
103+
SatisfiesTypeInputSig<ArgumentTypeAndBlanketOffset>
104104
{
105105
pragma[nomagic]
106106
additional predicate relevantConstraint(
@@ -120,7 +120,7 @@ module SatisfiesBlanketConstraint<
120120
}
121121

122122
private module SatisfiesBlanketConstraint =
123-
SatisfiesConstraint<ArgumentTypeAndBlanketOffset, SatisfiesBlanketConstraintInput>;
123+
SatisfiesType<ArgumentTypeAndBlanketOffset, SatisfiesBlanketConstraintInput>;
124124

125125
/**
126126
* Holds if the argument type `at` satisfies the first non-trivial blanket

rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,21 @@ private import TypeInference
1414
private import FunctionType
1515

1616
pragma[nomagic]
17-
private Type resolveNonTypeParameterTypeAt(TypeMention tm, TypePath path) {
17+
private Type resolveNonTypeParameterTypeAt(PreTypeMention tm, TypePath path) {
1818
result = tm.getTypeAt(path) and
1919
not result instanceof TypeParameter
2020
}
2121

2222
bindingset[t1, t2]
23-
private predicate typeMentionEqual(TypeMention t1, TypeMention t2) {
23+
private predicate typeMentionEqual(PreTypeMention t1, PreTypeMention t2) {
2424
forex(TypePath path, Type type | resolveNonTypeParameterTypeAt(t1, path) = type |
2525
resolveNonTypeParameterTypeAt(t2, path) = type
2626
)
2727
}
2828

2929
pragma[nomagic]
3030
private predicate implSiblingCandidate(
31-
Impl impl, TraitItemNode trait, Type rootType, TypeMention selfTy
31+
Impl impl, TraitItemNode trait, Type rootType, PreTypeMention selfTy
3232
) {
3333
trait = impl.(ImplItemNode).resolveTraitTy() and
3434
selfTy = impl.getSelfTy() and
@@ -52,7 +52,7 @@ pragma[inline]
5252
private predicate implSiblings(TraitItemNode trait, Impl impl1, Impl impl2) {
5353
impl1 != impl2 and
5454
(
55-
exists(Type rootType, TypeMention selfTy1, TypeMention selfTy2 |
55+
exists(Type rootType, PreTypeMention selfTy1, PreTypeMention selfTy2 |
5656
implSiblingCandidate(impl1, trait, rootType, selfTy1) and
5757
implSiblingCandidate(impl2, trait, rootType, selfTy2) and
5858
// In principle the second conjunct below should be superflous, but we still
@@ -76,6 +76,15 @@ private predicate implSiblings(TraitItemNode trait, Impl impl1, Impl impl2) {
7676
pragma[nomagic]
7777
private predicate implHasSibling(ImplItemNode impl, Trait trait) { implSiblings(trait, impl, _) }
7878

79+
pragma[nomagic]
80+
predicate implHasAmbigousSiblingAt(ImplItemNode impl, Trait trait, TypePath path) {
81+
exists(ImplItemNode impl2 |
82+
implSiblings(trait, impl, impl2) and
83+
resolveNonTypeParameterTypeAt(impl.getTraitPath(), path) !=
84+
resolveNonTypeParameterTypeAt(impl2.getTraitPath(), path)
85+
)
86+
}
87+
7988
/**
8089
* Holds if `f` is a function declared inside `trait`, and the type of `f` at
8190
* `pos` and `path` is `traitTp`, which is a type parameter of `trait`.

rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ private module Input implements InputSig1<Location>, InputSig2<PreTypeMention> {
4141

4242
class TypeAbstraction = TA::TypeAbstraction;
4343

44+
predicate typeAbstractionHasAmbigousConstraintAt(
45+
TypeAbstraction abs, Type constraint, TypePath path
46+
) {
47+
FunctionOverloading::implHasAmbigousSiblingAt(abs, constraint.(TraitType).getTrait(), path)
48+
}
49+
4450
class TypeArgumentPosition extends TTypeArgumentPosition {
4551
int asMethodTypeArgumentPosition() { this = TMethodTypeArgumentPosition(result) }
4652

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

128134
PreTypeMention getABaseTypeMention(Type t) { none() }
129135

130-
Type getATypeParameterConstraint(TypeParameter tp, TypePath path) {
131-
exists(TypeMention tm | result = tm.getTypeAt(path) |
132-
tm = tp.(TypeParamTypeParameter).getTypeParam().getATypeBound().getTypeRepr() or
133-
tm = tp.(SelfTypeParameter).getTrait() or
134-
tm =
135-
tp.(ImplTraitTypeTypeParameter)
136-
.getImplTraitTypeRepr()
137-
.getTypeBoundList()
138-
.getABound()
139-
.getTypeRepr()
140-
)
136+
PreTypeMention getATypeParameterConstraint(TypeParameter tp) {
137+
result = tp.(TypeParamTypeParameter).getTypeParam().getATypeBound().getTypeRepr() or
138+
result = tp.(SelfTypeParameter).getTrait() or
139+
result =
140+
tp.(ImplTraitTypeTypeParameter)
141+
.getImplTraitTypeRepr()
142+
.getTypeBoundList()
143+
.getABound()
144+
.getTypeRepr()
141145
}
142146

143147
/**
@@ -1126,7 +1130,7 @@ private module ContextTyping {
11261130
or
11271131
exists(TypeParameter mid |
11281132
assocFunctionMentionsTypeParameterAtNonRetPos(i, f, mid) and
1129-
tp = getATypeParameterConstraint(mid, _)
1133+
tp = getATypeParameterConstraint(mid).getTypeAt(_)
11301134
)
11311135
}
11321136

@@ -2237,7 +2241,7 @@ private module MethodResolution {
22372241
}
22382242

22392243
private module MethodCallSatisfiesDerefConstraintInput implements
2240-
SatisfiesConstraintInputSig<MethodCallDerefCand>
2244+
SatisfiesTypeInputSig<MethodCallDerefCand>
22412245
{
22422246
pragma[nomagic]
22432247
predicate relevantConstraint(MethodCallDerefCand mc, Type constraint) {
@@ -2247,7 +2251,7 @@ private module MethodResolution {
22472251
}
22482252

22492253
private module MethodCallSatisfiesDerefConstraint =
2250-
SatisfiesConstraint<MethodCallDerefCand, MethodCallSatisfiesDerefConstraintInput>;
2254+
SatisfiesType<MethodCallDerefCand, MethodCallSatisfiesDerefConstraintInput>;
22512255

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

3686-
private module AwaitSatisfiesConstraintInput implements SatisfiesConstraintInputSig<AwaitTarget> {
3690+
private module AwaitSatisfiesTypeInput implements SatisfiesTypeInputSig<AwaitTarget> {
36873691
pragma[nomagic]
36883692
predicate relevantConstraint(AwaitTarget term, Type constraint) {
36893693
exists(term) and
36903694
constraint.(TraitType).getTrait() instanceof FutureTrait
36913695
}
36923696
}
36933697

3694-
private module AwaitSatisfiesConstraint =
3695-
SatisfiesConstraint<AwaitTarget, AwaitSatisfiesConstraintInput>;
3698+
private module AwaitSatisfiesType = SatisfiesType<AwaitTarget, AwaitSatisfiesTypeInput>;
36963699

36973700
pragma[nomagic]
36983701
private Type inferAwaitExprType(AstNode n, TypePath path) {
36993702
exists(TypePath exprPath |
3700-
AwaitSatisfiesConstraint::satisfiesConstraintType(n.(AwaitExpr).getExpr(), _, exprPath, result) and
3703+
AwaitSatisfiesType::satisfiesConstraintType(n.(AwaitExpr).getExpr(), _, exprPath, result) and
37013704
exprPath.isCons(getFutureOutputTypeParameter(), path)
37023705
)
37033706
}
@@ -3876,9 +3879,7 @@ final private class ForIterableExpr extends Expr {
38763879
Type getTypeAt(TypePath path) { result = inferType(this, path) }
38773880
}
38783881

3879-
private module ForIterableSatisfiesConstraintInput implements
3880-
SatisfiesConstraintInputSig<ForIterableExpr>
3881-
{
3882+
private module ForIterableSatisfiesTypeInput implements SatisfiesTypeInputSig<ForIterableExpr> {
38823883
predicate relevantConstraint(ForIterableExpr term, Type constraint) {
38833884
exists(term) and
38843885
exists(Trait t | t = constraint.(TraitType).getTrait() |
@@ -3899,15 +3900,15 @@ private AssociatedTypeTypeParameter getIntoIteratorItemTypeParameter() {
38993900
result = getAssociatedTypeTypeParameter(any(IntoIteratorTrait t).getItemType())
39003901
}
39013902

3902-
private module ForIterableSatisfiesConstraint =
3903-
SatisfiesConstraint<ForIterableExpr, ForIterableSatisfiesConstraintInput>;
3903+
private module ForIterableSatisfiesType =
3904+
SatisfiesType<ForIterableExpr, ForIterableSatisfiesTypeInput>;
39043905

39053906
pragma[nomagic]
39063907
private Type inferForLoopExprType(AstNode n, TypePath path) {
39073908
// type of iterable -> type of pattern (loop variable)
39083909
exists(ForExpr fe, TypePath exprPath, AssociatedTypeTypeParameter tp |
39093910
n = fe.getPat() and
3910-
ForIterableSatisfiesConstraint::satisfiesConstraintType(fe.getIterable(), _, exprPath, result) and
3911+
ForIterableSatisfiesType::satisfiesConstraintType(fe.getIterable(), _, exprPath, result) and
39113912
exprPath.isCons(tp, path)
39123913
|
39133914
tp = getIntoIteratorItemTypeParameter()
@@ -3933,21 +3934,20 @@ final private class InvokedClosureExpr extends Expr {
39333934
CallExpr getCall() { result = call }
39343935
}
39353936

3936-
private module InvokedClosureSatisfiesConstraintInput implements
3937-
SatisfiesConstraintInputSig<InvokedClosureExpr>
3937+
private module InvokedClosureSatisfiesTypeInput implements SatisfiesTypeInputSig<InvokedClosureExpr>
39383938
{
39393939
predicate relevantConstraint(InvokedClosureExpr term, Type constraint) {
39403940
exists(term) and
39413941
constraint.(TraitType).getTrait() instanceof FnOnceTrait
39423942
}
39433943
}
39443944

3945-
private module InvokedClosureSatisfiesConstraint =
3946-
SatisfiesConstraint<InvokedClosureExpr, InvokedClosureSatisfiesConstraintInput>;
3945+
private module InvokedClosureSatisfiesType =
3946+
SatisfiesType<InvokedClosureExpr, InvokedClosureSatisfiesTypeInput>;
39473947

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

39533953
/**

rust/ql/lib/codeql/rust/internal/typeinference/TypeMention.qll

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,16 @@ private module PreTypeMention = MkTypeMention<preGetAdditionalPathTypeAt/2>;
696696

697697
class PreTypeMention = PreTypeMention::TypeMention;
698698

699+
private class TraitOrTmTrait extends AstNode {
700+
Type getTypeAt(TypePath path) {
701+
pathTypeAsTraitAssoc(_, _, this, _, _) and
702+
result = this.(PreTypeMention).getTypeAt(path)
703+
or
704+
result = TTrait(this) and
705+
path.isEmpty()
706+
}
707+
}
708+
699709
/**
700710
* Holds if `path` accesses an associated type `alias` from `trait` on a
701711
* concrete type given by `tm`.
@@ -705,7 +715,7 @@ class PreTypeMention = PreTypeMention::TypeMention;
705715
* when `path` is of the form `Self::AssocType`.
706716
*/
707717
private predicate pathConcreteTypeAssocType(
708-
Path path, PreTypeMention tm, TraitItemNode trait, AstNode implOrTmTrait, TypeAlias alias
718+
Path path, PreTypeMention tm, TraitItemNode trait, TraitOrTmTrait traitOrTmTrait, TypeAlias alias
709719
) {
710720
exists(Path qualifier |
711721
qualifier = path.getQualifier() and
@@ -714,57 +724,45 @@ private predicate pathConcreteTypeAssocType(
714724
// path of the form `<Type as Trait>::AssocType`
715725
// ^^^ tm ^^^^^^^^^ name
716726
exists(string name |
717-
pathTypeAsTraitAssoc(path, tm, implOrTmTrait, trait, name) and
727+
pathTypeAsTraitAssoc(path, tm, traitOrTmTrait, trait, name) and
718728
getTraitAssocType(trait, name) = alias
719729
)
720730
or
721731
// path of the form `Self::AssocType` within an `impl` block
722732
// tm ^^^^ ^^^^^^^^^ name
723-
implOrTmTrait =
724-
any(ImplItemNode impl |
725-
alias = resolvePath(path) and
726-
qualifier = impl.getASelfPath() and
727-
tm = impl.(Impl).getSelfTy() and
728-
trait.getAnAssocItem() = alias
729-
)
733+
exists(ImplItemNode impl |
734+
alias = resolvePath(path) and
735+
qualifier = impl.getASelfPath() and
736+
tm = impl.(Impl).getSelfTy() and
737+
trait.getAnAssocItem() = alias and
738+
traitOrTmTrait = trait
739+
)
730740
)
731741
}
732742

733-
private module PathSatisfiesConstraintInput implements SatisfiesConstraintInputSig<PreTypeMention> {
734-
predicate relevantConstraint(PreTypeMention tm, Type constraint) {
735-
pathConcreteTypeAssocType(_, tm, constraint.(TraitType).getTrait(), _, _)
743+
private module PathSatisfiesConstraintInput implements
744+
SatisfiesConstraintInputSig<PreTypeMention, TraitOrTmTrait>
745+
{
746+
predicate relevantConstraint(PreTypeMention tm, TraitOrTmTrait constraint) {
747+
pathConcreteTypeAssocType(_, tm, _, constraint, _)
736748
}
737749
}
738750

739751
private module PathSatisfiesConstraint =
740-
SatisfiesConstraint<PreTypeMention, PathSatisfiesConstraintInput>;
752+
SatisfiesConstraint<PreTypeMention, TraitOrTmTrait, PathSatisfiesConstraintInput>;
741753

742754
/**
743755
* Gets the type of `path` at `typePath` when `path` accesses an associated type
744756
* on a concrete type.
745757
*/
746758
private Type getPathConcreteAssocTypeAt(Path path, TypePath typePath) {
747759
exists(
748-
PreTypeMention tm, ImplItemNode impl, TraitItemNode trait, TraitType t, AstNode implOrTmTrait,
760+
PreTypeMention tm, ImplItemNode impl, TraitItemNode trait, TraitOrTmTrait traitOrTmTrait,
749761
TypeAlias alias, TypePath path0
750762
|
751-
pathConcreteTypeAssocType(path, tm, trait, implOrTmTrait, alias) and
752-
t = TTrait(trait) and
753-
PathSatisfiesConstraint::satisfiesConstraintTypeThrough(tm, impl, t, path0, result) and
763+
pathConcreteTypeAssocType(path, tm, trait, traitOrTmTrait, alias) and
764+
PathSatisfiesConstraint::satisfiesConstraintTypeThrough(tm, impl, traitOrTmTrait, path0, result) and
754765
path0.isCons(TAssociatedTypeTypeParameter(trait, alias), typePath)
755-
|
756-
implOrTmTrait instanceof Impl
757-
or
758-
// When `path` is of the form `<Type as Trait>::AssocType` we need to check
759-
// that `impl` is not more specific than the mentioned trait
760-
implOrTmTrait =
761-
any(PreTypeMention tmTrait |
762-
not exists(TypePath path1, Type t1 |
763-
t1 = impl.getTraitPath().(PreTypeMention).getTypeAt(path1) and
764-
not t1 instanceof TypeParameter and
765-
t1 != tmTrait.getTypeAt(path1)
766-
)
767-
)
768766
)
769767
}
770768

rust/ql/test/library-tests/type-inference/overloading.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ mod trait_bound_impl_overlap {
426426

427427
fn test() {
428428
let x = S(0);
429-
let y = call_f(x); // $ target=call_f type=y:i32 $ SPURIOUS: type=y:i64
429+
let y = call_f(x); // $ target=call_f type=y:i32
430430
let z: i32 = y;
431431

432432
let x = S(0);

rust/ql/test/library-tests/type-inference/type-inference.expected

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12716,14 +12716,11 @@ inferType
1271612716
| overloading.rs:428:17:428:20 | S(...) | T | {EXTERNAL LOCATION} | i32 |
1271712717
| overloading.rs:428:19:428:19 | 0 | | {EXTERNAL LOCATION} | i32 |
1271812718
| overloading.rs:429:13:429:13 | y | | {EXTERNAL LOCATION} | i32 |
12719-
| overloading.rs:429:13:429:13 | y | | {EXTERNAL LOCATION} | i64 |
1272012719
| overloading.rs:429:17:429:25 | call_f(...) | | {EXTERNAL LOCATION} | i32 |
12721-
| overloading.rs:429:17:429:25 | call_f(...) | | {EXTERNAL LOCATION} | i64 |
1272212720
| overloading.rs:429:24:429:24 | x | | overloading.rs:409:5:409:19 | S |
1272312721
| overloading.rs:429:24:429:24 | x | T | {EXTERNAL LOCATION} | i32 |
1272412722
| overloading.rs:430:13:430:13 | z | | {EXTERNAL LOCATION} | i32 |
1272512723
| overloading.rs:430:22:430:22 | y | | {EXTERNAL LOCATION} | i32 |
12726-
| overloading.rs:430:22:430:22 | y | | {EXTERNAL LOCATION} | i64 |
1272712724
| overloading.rs:432:13:432:13 | x | | overloading.rs:409:5:409:19 | S |
1272812725
| overloading.rs:432:13:432:13 | x | T | {EXTERNAL LOCATION} | i32 |
1272912726
| overloading.rs:432:17:432:20 | S(...) | | overloading.rs:409:5:409:19 | S |

0 commit comments

Comments
 (0)