Skip to content

Commit 6b38220

Browse files
committed
Rust: Make impl blocks only give rise to direct trait implementation
1 parent a25ae39 commit 6b38220

File tree

5 files changed

+84
-80
lines changed

5 files changed

+84
-80
lines changed

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

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -179,48 +179,52 @@ private module Input2 implements InputSig2 {
179179
* inference module for more information.
180180
*/
181181
predicate conditionSatisfiesConstraint(
182-
TypeAbstraction abs, TypeMention condition, TypeMention constraint
182+
TypeAbstraction abs, TypeMention condition, TypeMention constraint, boolean transitive
183183
) {
184184
// `impl` blocks implementing traits
185+
transitive = false and
185186
exists(Impl impl |
186187
abs = impl and
187188
condition = impl.getSelfTy() and
188189
constraint = impl.getTrait()
189190
)
190191
or
191-
// supertraits
192-
exists(Trait trait |
193-
abs = trait and
194-
condition = trait and
195-
constraint = trait.getATypeBound().getTypeRepr()
196-
)
197-
or
198-
// trait bounds on type parameters
199-
exists(TypeParam param |
200-
abs = param.getATypeBound() and
201-
condition = param and
202-
constraint = abs.(TypeBound).getTypeRepr()
203-
)
204-
or
205-
// the implicit `Self` type parameter satisfies the trait
206-
exists(SelfTypeParameterMention self |
207-
abs = self and
208-
condition = self and
209-
constraint = self.getTrait()
210-
)
211-
or
212-
exists(ImplTraitTypeRepr impl |
213-
abs = impl and
214-
condition = impl and
215-
constraint = impl.getTypeBoundList().getABound().getTypeRepr()
216-
)
217-
or
218-
// a `dyn Trait` type implements `Trait`. See the comment on
219-
// `DynTypeBoundListMention` for further details.
220-
exists(DynTraitTypeRepr object |
221-
abs = object and
222-
condition = object.getTypeBoundList() and
223-
constraint = object.getTrait()
192+
transitive = true and
193+
(
194+
// supertraits
195+
exists(Trait trait |
196+
abs = trait and
197+
condition = trait and
198+
constraint = trait.getATypeBound().getTypeRepr()
199+
)
200+
or
201+
// trait bounds on type parameters
202+
exists(TypeParam param |
203+
abs = param.getATypeBound() and
204+
condition = param and
205+
constraint = abs.(TypeBound).getTypeRepr()
206+
)
207+
or
208+
// the implicit `Self` type parameter satisfies the trait
209+
exists(SelfTypeParameterMention self |
210+
abs = self and
211+
condition = self and
212+
constraint = self.getTrait()
213+
)
214+
or
215+
exists(ImplTraitTypeRepr impl |
216+
abs = impl and
217+
condition = impl and
218+
constraint = impl.getTypeBoundList().getABound().getTypeRepr()
219+
)
220+
or
221+
// a `dyn Trait` type implements `Trait`. See the comment on
222+
// `DynTypeBoundListMention` for further details.
223+
exists(DynTraitTypeRepr object |
224+
abs = object and
225+
condition = object.getTypeBoundList() and
226+
constraint = object.getTrait()
227+
)
224228
)
225229
}
226230
}
@@ -3307,10 +3311,10 @@ private module Debug {
33073311
}
33083312

33093313
predicate debugConditionSatisfiesConstraint(
3310-
TypeAbstraction abs, TypeMention condition, TypeMention constraint
3314+
TypeAbstraction abs, TypeMention condition, TypeMention constraint, boolean transitive
33113315
) {
33123316
abs = getRelevantLocatable() and
3313-
Input2::conditionSatisfiesConstraint(abs, condition, constraint)
3317+
Input2::conditionSatisfiesConstraint(abs, condition, constraint, transitive)
33143318
}
33153319

33163320
predicate debugInferShorthandSelfType(ShorthandSelfParameterMention self, TypePath path, Type t) {

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

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,24 @@ module FunctionPositionMatchingInput {
7272
}
7373

7474
private newtype TAssocFunctionType =
75-
/** An associated function `f` that should be specialized for `i` at `pos`. */
76-
MkAssocFunctionType(Function f, ImplOrTraitItemNode i, FunctionPosition pos) {
77-
f = i.getASuccessor(_) and exists(pos.getTypeMention(f))
75+
/** An associated function `f` in `parent` should be specialized for `i` at `pos`. */
76+
MkAssocFunctionType(
77+
ImplOrTraitItemNode parent, Function f, ImplOrTraitItemNode i, FunctionPosition pos
78+
) {
79+
parent.getAnAssocItem() = f and
80+
i.getASuccessor(_) = f and
81+
// When `f` is not directly in `i`, the `parent` should be satisfiable
82+
// through `i`. This ensures that `parent` is either a supertrait of `i` or
83+
// `i` in an `impl` block implementing `parent`.
84+
(parent = i or BaseTypes::rootTypesSatisfaction(_, TTrait(parent), i, _, _)) and
85+
exists(pos.getTypeMention(f))
7886
}
7987

80-
bindingset[condition, constraint, tp]
88+
bindingset[abs, constraint, tp]
8189
private Type getTraitConstraintTypeAt(
82-
TypeMention condition, TypeMention constraint, TypeParameter tp, TypePath path
90+
TypeAbstraction abs, TypeMention constraint, TypeParameter tp, TypePath path
8391
) {
84-
BaseTypes::conditionSatisfiesConstraintTypeAt(_, condition, constraint,
92+
BaseTypes::conditionSatisfiesConstraintTypeAt(abs, _, constraint,
8593
TypePath::singleton(tp).appendInverse(path), result)
8694
}
8795

@@ -91,28 +99,19 @@ private Type getTraitConstraintTypeAt(
9199
*/
92100
pragma[nomagic]
93101
Type getAssocFunctionTypeAt(Function f, ImplOrTraitItemNode i, FunctionPosition pos, TypePath path) {
94-
exists(MkAssocFunctionType(f, i, pos)) and
95-
(
102+
exists(ImplOrTraitItemNode parent | exists(MkAssocFunctionType(parent, f, i, pos)) |
96103
// No specialization needed when the function is directly in the trait or
97104
// impl block or the declared type is not a type parameter
98-
(i.getAnAssocItem() = f or not result instanceof TypeParameter) and
105+
(parent = i or not result instanceof TypeParameter) and
99106
result = pos.getTypeMention(f).resolveTypeAt(path)
100107
or
101-
not i.getAnAssocItem() = f and
102-
exists(TypePath prefix, TypePath suffix, TypeParameter tp |
108+
exists(TypePath prefix, TypePath suffix, TypeParameter tp, TypeMention constraint |
109+
BaseTypes::rootTypesSatisfaction(_, TTrait(parent), i, _, constraint) and
103110
path = prefix.append(suffix) and
104-
tp = pos.getTypeMention(f).resolveTypeAt(prefix)
105-
|
111+
tp = pos.getTypeMention(f).resolveTypeAt(prefix) and
106112
if tp = TSelfTypeParameter(_)
107113
then result = resolveImplOrTraitType(i, suffix)
108-
else
109-
exists(TraitItemNode trait, TypeMention condition, TypeMention constraint |
110-
trait.getAnAssocItem() = f and
111-
BaseTypes::rootTypesSatisfaction(_, TTrait(trait), _, condition, constraint) and
112-
result = getTraitConstraintTypeAt(condition, constraint, tp, suffix)
113-
|
114-
condition = i.(Trait) or condition = i.(Impl).getSelfTy()
115-
)
114+
else result = getTraitConstraintTypeAt(i, constraint, tp, suffix)
116115
)
117116
)
118117
}
@@ -134,31 +133,33 @@ Type getAssocFunctionTypeAt(Function f, ImplOrTraitItemNode i, FunctionPosition
134133
* fn m3(self); // self3
135134
* }
136135
*
137-
* impl T2 for X {
136+
* impl T1 for X {
138137
* fn m1(self) { ... } // self4
138+
* }
139139
*
140+
* impl T2 for X {
140141
* fn m3(self) { ... } // self5
141142
* }
142143
* ```
143144
*
144-
* param | `impl` or trait | type
145-
* ------- | --------------- | ----
146-
* `self1` | `trait T1` | `T1`
147-
* `self1` | `trait T2` | `T2`
148-
* `self2` | `trait T1` | `T1`
149-
* `self2` | `trait T2` | `T2`
150-
* `self2` | `impl T2 for X` | `X`
151-
* `self3` | `trait T2` | `T2`
152-
* `self4` | `impl T2 for X` | `X`
153-
* `self5` | `impl T2 for X` | `X`
145+
* f | `impl` or trait | pos | type
146+
* ---- | --------------- | ------ | ----
147+
* `m1` | `trait T1` | `self` | `T1`
148+
* `m1` | `trait T2` | `self` | `T2`
149+
* `m2` | `trait T1` | `self` | `T1`
150+
* `m2` | `trait T2` | `self` | `T2`
151+
* `m2` | `impl T1 for X` | `self` | `X`
152+
* `m3` | `trait T2` | `self` | `T2`
153+
* `m4` | `impl T2 for X` | `self` | `X`
154+
* `m5` | `impl T2 for X` | `self` | `X`
154155
*/
155156
class AssocFunctionType extends MkAssocFunctionType {
156157
/**
157158
* Holds if this function type applies to the function `f` at position `pos`,
158159
* when viewed as a member of the `impl` or trait item `i`.
159160
*/
160161
predicate appliesTo(Function f, ImplOrTraitItemNode i, FunctionPosition pos) {
161-
this = MkAssocFunctionType(f, i, pos)
162+
this = MkAssocFunctionType(_, f, i, pos)
162163
}
163164

164165
/**

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -586,10 +586,10 @@ mod impl_overlap {
586586
println!("{:?}", w.m(x)); // $ target=S3<T>::m
587587
println!("{:?}", S3::m(&w, x)); // $ target=S3<T>::m
588588

589-
S4.m(); // $ target=<S4_as_MyTrait1>::m $ SPURIOUS: target=MyTrait1::m
589+
S4.m(); // $ target=<S4_as_MyTrait1>::m
590590
S4::m(&S4); // $ target=<S4_as_MyTrait1>::m $ SPURIOUS: target=MyTrait1::m
591-
S5(0i32).m(); // $ target=<S5<i32>_as_MyTrait1>::m $ SPURIOUS: target=MyTrait1::m
592-
S5::m(&S5(0i32)); // $ target=<S5<i32>_as_MyTrait1>::m $ SPURIOUS: target=MyTrait1::m
591+
S5(0i32).m(); // $ target=<S5<i32>_as_MyTrait1>::m
592+
S5::m(&S5(0i32)); // $ target=<S5<i32>_as_MyTrait1>::m
593593
S5(true).m(); // $ target=MyTrait1::m
594594
S5::m(&S5(true)); // $ target=MyTrait1::m
595595
}

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5187,7 +5187,6 @@ inferType
51875187
| main.rs:2561:39:2561:39 | 2 | | {EXTERNAL LOCATION} | i32 |
51885188
| main.rs:2561:42:2561:42 | 3 | | {EXTERNAL LOCATION} | i32 |
51895189
| main.rs:2562:13:2562:13 | u | | {EXTERNAL LOCATION} | u16 |
5190-
| main.rs:2562:13:2562:13 | u | | file://:0:0:0:0 | & |
51915190
| main.rs:2562:18:2562:23 | vals4a | | {EXTERNAL LOCATION} | Vec |
51925191
| main.rs:2562:18:2562:23 | vals4a | A | {EXTERNAL LOCATION} | Global |
51935192
| main.rs:2562:18:2562:23 | vals4a | T | {EXTERNAL LOCATION} | u16 |
@@ -5213,7 +5212,6 @@ inferType
52135212
| main.rs:2567:41:2567:41 | 3 | | {EXTERNAL LOCATION} | i32 |
52145213
| main.rs:2568:13:2568:13 | u | | {EXTERNAL LOCATION} | i32 |
52155214
| main.rs:2568:13:2568:13 | u | | {EXTERNAL LOCATION} | u32 |
5216-
| main.rs:2568:13:2568:13 | u | | file://:0:0:0:0 | & |
52175215
| main.rs:2568:18:2568:22 | vals5 | | {EXTERNAL LOCATION} | Vec |
52185216
| main.rs:2568:18:2568:22 | vals5 | A | {EXTERNAL LOCATION} | Global |
52195217
| main.rs:2568:18:2568:22 | vals5 | T | {EXTERNAL LOCATION} | i32 |
@@ -5249,7 +5247,6 @@ inferType
52495247
| main.rs:2574:9:2574:13 | vals7 | T | {EXTERNAL LOCATION} | u8 |
52505248
| main.rs:2574:20:2574:22 | 1u8 | | {EXTERNAL LOCATION} | u8 |
52515249
| main.rs:2575:13:2575:13 | u | | {EXTERNAL LOCATION} | u8 |
5252-
| main.rs:2575:13:2575:13 | u | | file://:0:0:0:0 | & |
52535250
| main.rs:2575:18:2575:22 | vals7 | | {EXTERNAL LOCATION} | Vec |
52545251
| main.rs:2575:18:2575:22 | vals7 | A | {EXTERNAL LOCATION} | Global |
52555252
| main.rs:2575:18:2575:22 | vals7 | T | {EXTERNAL LOCATION} | u8 |

shared/typeinference/codeql/typeinference/internal/TypeInference.qll

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,8 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
450450
* free in `condition` and `constraint`,
451451
* - and for every instantiation of the type parameters from `abs` the
452452
* resulting `condition` satisifies the constraint given by `constraint`.
453+
* - `transitive` corresponds to wether any further constraints satisifed
454+
* through `constraint` also applies to `condition`.
453455
*
454456
* Example in C#:
455457
* ```csharp
@@ -487,7 +489,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
487489
* should be empty.
488490
*/
489491
predicate conditionSatisfiesConstraint(
490-
TypeAbstraction abs, TypeMention condition, TypeMention constraint
492+
TypeAbstraction abs, TypeMention condition, TypeMention constraint, boolean transitive
491493
);
492494
}
493495

@@ -754,13 +756,13 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
754756
private predicate typeCondition(
755757
Type type, TypeAbstraction abs, TypeMentionTypeTree condition
756758
) {
757-
conditionSatisfiesConstraint(abs, condition, _) and
759+
conditionSatisfiesConstraint(abs, condition, _, _) and
758760
type = resolveTypeMentionRoot(condition)
759761
}
760762

761763
pragma[nomagic]
762764
private predicate typeConstraint(Type type, TypeMentionTypeTree constraint) {
763-
conditionSatisfiesConstraint(_, _, constraint) and
765+
conditionSatisfiesConstraint(_, _, constraint, _) and
764766
type = resolveTypeMentionRoot(constraint)
765767
}
766768

@@ -781,12 +783,12 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
781783
TypeAbstraction abs, TypeMention condition, TypeMention constraint, TypePath path, Type t
782784
) {
783785
// base case
784-
conditionSatisfiesConstraint(abs, condition, constraint) and
786+
conditionSatisfiesConstraint(abs, condition, constraint, _) and
785787
constraint.resolveTypeAt(path) = t
786788
or
787789
// recursive case
788790
exists(TypeAbstraction midAbs, TypeMention midConstraint, TypeMention midCondition |
789-
conditionSatisfiesConstraint(abs, condition, midConstraint) and
791+
conditionSatisfiesConstraint(abs, condition, midConstraint, true) and
790792
// NOTE: `midAbs` describe the free type variables in `midCondition`, hence
791793
// we use that for instantiation check.
792794
IsInstantiationOf<TypeMentionTypeTree, TypeMentionTypeTree, IsInstantiationOfInput>::isInstantiationOf(midConstraint,

0 commit comments

Comments
 (0)