Skip to content

Commit 0d770c8

Browse files
committed
Rust: Improve handling of type parameters with trait bounds
1 parent aa97bf9 commit 0d770c8

File tree

5 files changed

+82
-19
lines changed

5 files changed

+82
-19
lines changed

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ abstract private class StructOrEnumType extends Type {
8181
)
8282
}
8383

84+
/** Gets all of the fully parametric `impl` blocks that target this type. */
8485
final override ImplMention getABaseTypeMention() {
8586
this.asItemNode() = result.resolveSelfTy() and
8687
result.isFullyParametric()
@@ -153,6 +154,7 @@ class TraitType extends Type, TTrait {
153154
result = trait.getTypeBoundList().getABound().getTypeRepr()
154155
}
155156

157+
/** Gets any of the trait bounds of this trait. */
156158
override TypeMention getABaseTypeMention() { result = this.getABoundMention() }
157159

158160
override string toString() { result = trait.toString() }
@@ -308,11 +310,19 @@ class TypeParamTypeParameter extends TypeParameter, TTypeParamTypeParameter {
308310

309311
TypeParam getTypeParam() { result = typeParam }
310312

311-
override Function getMethod(string name) { result = typeParam.(ItemNode).getASuccessor(name) }
313+
override Function getMethod(string name) {
314+
// NOTE: If the type parameter has trait bounds, then this finds methods
315+
// on the bounding traits.
316+
result = typeParam.(ItemNode).getASuccessor(name)
317+
}
312318

313319
override string toString() { result = typeParam.toString() }
314320

315321
override Location getLocation() { result = typeParam.getLocation() }
322+
323+
final override TypeMention getABaseTypeMention() {
324+
result = typeParam.getTypeBoundList().getABound().getTypeRepr()
325+
}
316326
}
317327

318328
/** An implicit reference type parameter. */

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,10 @@ private Type inferImplicitSelfType(SelfParam self, TypePath path) {
234234
)
235235
}
236236

237+
/**
238+
* Gets any of the types mentioned in `path` that corresponds to the type
239+
* parameter `tp`.
240+
*/
237241
private TypeMention getExplicitTypeArgMention(Path path, TypeParam tp) {
238242
exists(int i |
239243
result = path.getPart().getGenericArgList().getTypeArg(pragma[only_bind_into](i)) and

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ mod field_access {
3636
let y = GenericThing { a: S };
3737
println!("{:?}", x.a);
3838

39-
// The type of the field `a` can only be infered from the concrete type
39+
// The type of the field `a` can only be inferred from the concrete type
4040
// in the struct declaration.
4141
let x = OptionS {
4242
a: MyOption::MyNone(),
4343
};
4444
println!("{:?}", x.a);
4545

46-
// The type of the field `a` can only be infered from the type argument
46+
// The type of the field `a` can only be inferred from the type argument
4747
let x = GenericThing::<MyOption<S>> {
4848
a: MyOption::MyNone(),
4949
};
@@ -212,23 +212,23 @@ mod type_parameter_bounds {
212212

213213
fn call_first_trait_per_bound<I: Debug, T: SecondTrait<I>>(x: T) {
214214
// The type parameter bound determines which method this call is resolved to.
215-
let s1 = x.method(); // missing type for `s1`
215+
let s1 = x.method();
216216
println!("{:?}", s1);
217217
}
218218

219219
fn call_second_trait_per_bound<I: Debug, T: SecondTrait<I>>(x: T) {
220220
// The type parameter bound determines which method this call is resolved to.
221-
let s2 = x.method(); // missing type for `s2`
221+
let s2 = x.method();
222222
println!("{:?}", s2);
223223
}
224224

225225
fn trait_bound_with_type<T: FirstTrait<S1>>(x: T) {
226-
let s = x.method(); // missing type for `s`
226+
let s = x.method();
227227
println!("{:?}", s);
228228
}
229229

230230
fn trait_per_bound_with_type<T: FirstTrait<S1>>(x: T) {
231-
let s = x.method(); // missing type for `s`
231+
let s = x.method();
232232
println!("{:?}", s);
233233
}
234234

@@ -240,15 +240,15 @@ mod type_parameter_bounds {
240240

241241
fn call_trait_per_bound_with_type_1<T: Pair<S1, S2>>(x: T, y: T) {
242242
// The type in the type parameter bound determines the return type.
243-
let s1 = x.fst(); // missing type for `s1`
244-
let s2 = y.snd(); // missing type for `s2`
243+
let s1 = x.fst();
244+
let s2 = y.snd();
245245
println!("{:?}, {:?}", s1, s2);
246246
}
247247

248248
fn call_trait_per_bound_with_type_2<T2: Debug, T: Pair<S1, T2>>(x: T, y: T) {
249249
// The type in the type parameter bound determines the return type.
250-
let s1 = x.fst(); // missing type for `s1`
251-
let s2 = y.snd(); // missing type for `s2`
250+
let s1 = x.fst();
251+
let s2 = y.snd();
252252
println!("{:?}, {:?}", s1, s2);
253253
}
254254
}
@@ -530,11 +530,11 @@ mod type_aliases {
530530
type AnotherPair<Thr> = PairOption<S2, Thr>;
531531

532532
pub fn f() {
533-
// Type can be infered from the constructor
533+
// Type can be inferred from the constructor
534534
let p1: MyPair = PairOption::PairBoth(S1, S2);
535535
println!("{:?}", p1);
536536

537-
// Type can be only infered from the type alias
537+
// Type can be only inferred from the type alias
538538
let p2: MyPair = PairOption::PairNone(); // types for `Fst` and `Snd` missing
539539
println!("{:?}", p2);
540540

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

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,20 +236,40 @@ inferType
236236
| main.rs:210:19:210:22 | SelfParam | ST | main.rs:209:23:209:24 | ST |
237237
| main.rs:213:64:213:64 | x | | main.rs:209:5:211:5 | trait SecondTrait |
238238
| main.rs:213:64:213:64 | x | | main.rs:213:45:213:61 | T |
239+
| main.rs:213:64:213:64 | x | ST | main.rs:213:35:213:42 | I |
240+
| main.rs:215:13:215:14 | s1 | | main.rs:213:35:213:42 | I |
239241
| main.rs:215:18:215:18 | x | | main.rs:209:5:211:5 | trait SecondTrait |
240242
| main.rs:215:18:215:18 | x | | main.rs:213:45:213:61 | T |
243+
| main.rs:215:18:215:18 | x | ST | main.rs:213:35:213:42 | I |
244+
| main.rs:215:18:215:27 | x.method(...) | | main.rs:213:35:213:42 | I |
245+
| main.rs:216:26:216:27 | s1 | | main.rs:213:35:213:42 | I |
241246
| main.rs:219:65:219:65 | x | | main.rs:209:5:211:5 | trait SecondTrait |
242247
| main.rs:219:65:219:65 | x | | main.rs:219:46:219:62 | T |
248+
| main.rs:219:65:219:65 | x | ST | main.rs:219:36:219:43 | I |
249+
| main.rs:221:13:221:14 | s2 | | main.rs:219:36:219:43 | I |
243250
| main.rs:221:18:221:18 | x | | main.rs:209:5:211:5 | trait SecondTrait |
244251
| main.rs:221:18:221:18 | x | | main.rs:219:46:219:62 | T |
252+
| main.rs:221:18:221:18 | x | ST | main.rs:219:36:219:43 | I |
253+
| main.rs:221:18:221:27 | x.method(...) | | main.rs:219:36:219:43 | I |
254+
| main.rs:222:26:222:27 | s2 | | main.rs:219:36:219:43 | I |
245255
| main.rs:225:49:225:49 | x | | main.rs:205:5:207:5 | trait FirstTrait |
246256
| main.rs:225:49:225:49 | x | | main.rs:225:30:225:46 | T |
257+
| main.rs:225:49:225:49 | x | FT | main.rs:197:5:198:14 | struct S1 |
258+
| main.rs:226:13:226:13 | s | | main.rs:197:5:198:14 | struct S1 |
247259
| main.rs:226:17:226:17 | x | | main.rs:205:5:207:5 | trait FirstTrait |
248260
| main.rs:226:17:226:17 | x | | main.rs:225:30:225:46 | T |
261+
| main.rs:226:17:226:17 | x | FT | main.rs:197:5:198:14 | struct S1 |
262+
| main.rs:226:17:226:26 | x.method(...) | | main.rs:197:5:198:14 | struct S1 |
263+
| main.rs:227:26:227:26 | s | | main.rs:197:5:198:14 | struct S1 |
249264
| main.rs:230:53:230:53 | x | | main.rs:205:5:207:5 | trait FirstTrait |
250265
| main.rs:230:53:230:53 | x | | main.rs:230:34:230:50 | T |
266+
| main.rs:230:53:230:53 | x | FT | main.rs:197:5:198:14 | struct S1 |
267+
| main.rs:231:13:231:13 | s | | main.rs:197:5:198:14 | struct S1 |
251268
| main.rs:231:17:231:17 | x | | main.rs:205:5:207:5 | trait FirstTrait |
252269
| main.rs:231:17:231:17 | x | | main.rs:230:34:230:50 | T |
270+
| main.rs:231:17:231:17 | x | FT | main.rs:197:5:198:14 | struct S1 |
271+
| main.rs:231:17:231:26 | x.method(...) | | main.rs:197:5:198:14 | struct S1 |
272+
| main.rs:232:26:232:26 | s | | main.rs:197:5:198:14 | struct S1 |
253273
| main.rs:236:16:236:19 | SelfParam | | main.rs:235:5:239:5 | trait Pair |
254274
| main.rs:236:16:236:19 | SelfParam | P1 | main.rs:235:16:235:17 | P1 |
255275
| main.rs:236:16:236:19 | SelfParam | P2 | main.rs:235:20:235:21 | P2 |
@@ -258,20 +278,48 @@ inferType
258278
| main.rs:238:16:238:19 | SelfParam | P2 | main.rs:235:20:235:21 | P2 |
259279
| main.rs:241:58:241:58 | x | | main.rs:235:5:239:5 | trait Pair |
260280
| main.rs:241:58:241:58 | x | | main.rs:241:41:241:55 | T |
281+
| main.rs:241:58:241:58 | x | P1 | main.rs:197:5:198:14 | struct S1 |
282+
| main.rs:241:58:241:58 | x | P2 | main.rs:200:5:201:14 | struct S2 |
261283
| main.rs:241:64:241:64 | y | | main.rs:235:5:239:5 | trait Pair |
262284
| main.rs:241:64:241:64 | y | | main.rs:241:41:241:55 | T |
285+
| main.rs:241:64:241:64 | y | P1 | main.rs:197:5:198:14 | struct S1 |
286+
| main.rs:241:64:241:64 | y | P2 | main.rs:200:5:201:14 | struct S2 |
287+
| main.rs:243:13:243:14 | s1 | | main.rs:197:5:198:14 | struct S1 |
263288
| main.rs:243:18:243:18 | x | | main.rs:235:5:239:5 | trait Pair |
264289
| main.rs:243:18:243:18 | x | | main.rs:241:41:241:55 | T |
290+
| main.rs:243:18:243:18 | x | P1 | main.rs:197:5:198:14 | struct S1 |
291+
| main.rs:243:18:243:18 | x | P2 | main.rs:200:5:201:14 | struct S2 |
292+
| main.rs:243:18:243:24 | x.fst(...) | | main.rs:197:5:198:14 | struct S1 |
293+
| main.rs:244:13:244:14 | s2 | | main.rs:200:5:201:14 | struct S2 |
265294
| main.rs:244:18:244:18 | y | | main.rs:235:5:239:5 | trait Pair |
266295
| main.rs:244:18:244:18 | y | | main.rs:241:41:241:55 | T |
296+
| main.rs:244:18:244:18 | y | P1 | main.rs:197:5:198:14 | struct S1 |
297+
| main.rs:244:18:244:18 | y | P2 | main.rs:200:5:201:14 | struct S2 |
298+
| main.rs:244:18:244:24 | y.snd(...) | | main.rs:200:5:201:14 | struct S2 |
299+
| main.rs:245:32:245:33 | s1 | | main.rs:197:5:198:14 | struct S1 |
300+
| main.rs:245:36:245:37 | s2 | | main.rs:200:5:201:14 | struct S2 |
267301
| main.rs:248:69:248:69 | x | | main.rs:235:5:239:5 | trait Pair |
268302
| main.rs:248:69:248:69 | x | | main.rs:248:52:248:66 | T |
303+
| main.rs:248:69:248:69 | x | P1 | main.rs:197:5:198:14 | struct S1 |
304+
| main.rs:248:69:248:69 | x | P2 | main.rs:248:41:248:49 | T2 |
269305
| main.rs:248:75:248:75 | y | | main.rs:235:5:239:5 | trait Pair |
270306
| main.rs:248:75:248:75 | y | | main.rs:248:52:248:66 | T |
307+
| main.rs:248:75:248:75 | y | P1 | main.rs:197:5:198:14 | struct S1 |
308+
| main.rs:248:75:248:75 | y | P2 | main.rs:248:41:248:49 | T2 |
309+
| main.rs:250:13:250:14 | s1 | | main.rs:197:5:198:14 | struct S1 |
271310
| main.rs:250:18:250:18 | x | | main.rs:235:5:239:5 | trait Pair |
272311
| main.rs:250:18:250:18 | x | | main.rs:248:52:248:66 | T |
312+
| main.rs:250:18:250:18 | x | P1 | main.rs:197:5:198:14 | struct S1 |
313+
| main.rs:250:18:250:18 | x | P2 | main.rs:248:41:248:49 | T2 |
314+
| main.rs:250:18:250:24 | x.fst(...) | | main.rs:197:5:198:14 | struct S1 |
315+
| main.rs:251:13:251:14 | s2 | | main.rs:248:41:248:49 | T2 |
273316
| main.rs:251:18:251:18 | y | | main.rs:235:5:239:5 | trait Pair |
274317
| main.rs:251:18:251:18 | y | | main.rs:248:52:248:66 | T |
318+
| main.rs:251:18:251:18 | y | P1 | main.rs:197:5:198:14 | struct S1 |
319+
| main.rs:251:18:251:18 | y | P2 | main.rs:248:41:248:49 | T2 |
320+
| main.rs:251:18:251:24 | y.snd(...) | | main.rs:248:41:248:49 | T2 |
321+
| main.rs:252:32:252:33 | s1 | | main.rs:197:5:198:14 | struct S1 |
322+
| main.rs:252:36:252:37 | s2 | | main.rs:248:41:248:49 | T2 |
275323
| main.rs:268:15:268:18 | SelfParam | | main.rs:267:5:276:5 | trait MyTrait |
276324
| main.rs:268:15:268:18 | SelfParam | A | main.rs:267:19:267:19 | A |
277325
| main.rs:270:15:270:18 | SelfParam | | main.rs:267:5:276:5 | trait MyTrait |

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
254254
module Make2<InputSig2 Input2> {
255255
private import Input2
256256

257+
/** Gets the type at the empty path of `tm`. */
257258
pragma[nomagic]
258259
private Type resolveTypeMentionRoot(TypeMention tm) {
259260
result = tm.resolveTypeAt(TypePath::nil())
@@ -275,7 +276,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
275276
*
276277
* class Mid<T3> : Base<C<T3>> { }
277278
*
278-
* class Sub<T4> : Mid<C<T4>> { }
279+
* class Sub<T4> : Mid<C<T4>> { } // Sub<T4> extends Base<C<C<T4>>
279280
* ```
280281
*
281282
* - `T3` is mentioned at `0.0` for immediate base type mention `Base<C<T3>>`
@@ -334,9 +335,9 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
334335
}
335336

336337
/**
337-
* Holds if `baseMention` is a (transitive) base type mention of `sub`, and
338-
* non-type-parameter `t` is mentioned (implicitly) at `path` inside
339-
* `baseMention`. For example, in
338+
* Holds if `baseMention` is a (transitive) base type mention of `sub`,
339+
* and `t`, which is not a type parameter of `sub`, is mentioned
340+
* (implicitly) at `path` inside `baseMention`. For example, in
340341
*
341342
* ```csharp
342343
* class C<T1> { }
@@ -345,7 +346,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
345346
*
346347
* class Mid<T3> : Base<C<T3>> { }
347348
*
348-
* class Sub<T4> : Mid<C<T4>> { }
349+
* class Sub<T4> : Mid<C<T4>> { } // Sub<T4> extends Base<C<C<T4>>
349350
* ```
350351
*
351352
* - ``C`1`` is mentioned at `0` for immediate base type mention `Base<C<T3>>`
@@ -359,7 +360,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
359360
predicate baseTypeMentionHasNonTypeParameterAt(
360361
Type sub, TypeMention baseMention, TypePath path, Type t
361362
) {
362-
not t instanceof TypeParameter and
363+
not t = sub.getATypeParameter() and
363364
exists(TypeMention immediateBaseMention |
364365
pragma[only_bind_into](immediateBaseMention) =
365366
getABaseTypeMention(pragma[only_bind_into](sub))

0 commit comments

Comments
 (0)