Skip to content

Commit 5f524ef

Browse files
authored
Merge pull request #19372 from paldepind/rust-ti-implementing-type-method
Rust: Support non-universal `impl` blocks
2 parents 9d65b5f + eb5d4ef commit 5f524ef

File tree

14 files changed

+2422
-1328
lines changed

14 files changed

+2422
-1328
lines changed

rust/ql/lib/codeql/rust/elements/internal/MethodCallExprImpl.qll

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@ private import codeql.rust.internal.TypeInference
1414
* be referenced directly.
1515
*/
1616
module Impl {
17-
private predicate isImplFunction(Function f) { f = any(ImplItemNode impl).getAnAssocItem() }
17+
private predicate isInherentImplFunction(Function f) {
18+
f = any(Impl impl | not impl.hasTrait()).(ImplItemNode).getAnAssocItem()
19+
}
20+
21+
private predicate isTraitImplFunction(Function f) {
22+
f = any(Impl impl | impl.hasTrait()).(ImplItemNode).getAnAssocItem()
23+
}
1824

1925
// the following QLdoc is generated: if you need to edit it, do it in the schema file
2026
/**
@@ -25,23 +31,39 @@ module Impl {
2531
* ```
2632
*/
2733
class MethodCallExpr extends Generated::MethodCallExpr {
28-
override Function getStaticTarget() {
34+
private Function getStaticTargetFrom(boolean fromSource) {
2935
result = resolveMethodCallExpr(this) and
36+
(if result.fromSource() then fromSource = true else fromSource = false) and
3037
(
31-
// prioritize `impl` methods first
32-
isImplFunction(result)
38+
// prioritize inherent implementation methods first
39+
isInherentImplFunction(result)
3340
or
34-
not isImplFunction(resolveMethodCallExpr(this)) and
41+
not isInherentImplFunction(resolveMethodCallExpr(this)) and
3542
(
36-
// then trait methods with default implementations
37-
result.hasBody()
43+
// then trait implementation methods
44+
isTraitImplFunction(result)
3845
or
39-
// and finally trait methods without default implementations
40-
not resolveMethodCallExpr(this).hasBody()
46+
not isTraitImplFunction(resolveMethodCallExpr(this)) and
47+
(
48+
// then trait methods with default implementations
49+
result.hasBody()
50+
or
51+
// and finally trait methods without default implementations
52+
not resolveMethodCallExpr(this).hasBody()
53+
)
4154
)
4255
)
4356
}
4457

58+
override Function getStaticTarget() {
59+
// Functions in source code also gets extracted as library code, due to
60+
// this duplication we prioritize functions from source code.
61+
result = this.getStaticTargetFrom(true)
62+
or
63+
not exists(this.getStaticTargetFrom(true)) and
64+
result = this.getStaticTargetFrom(false)
65+
}
66+
4567
private string toStringPart(int index) {
4668
index = 0 and
4769
result = this.getReceiver().toAbbreviatedString()

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

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -446,61 +446,6 @@ class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
446446

447447
TraitItemNode resolveTraitTy() { result = resolvePathFull(this.getTraitPath()) }
448448

449-
pragma[nomagic]
450-
private TypeRepr getASelfTyArg() {
451-
result =
452-
this.getSelfPath().getSegment().getGenericArgList().getAGenericArg().(TypeArg).getTypeRepr()
453-
}
454-
455-
/**
456-
* Holds if this `impl` block is not fully parametric. That is, the implementing
457-
* type is generic and the implementation is not parametrically polymorphic in all
458-
* the implementing type's arguments.
459-
*
460-
* Examples:
461-
*
462-
* ```rust
463-
* impl Foo { ... } // fully parametric
464-
*
465-
* impl<T> Foo<T> { ... } // fully parametric
466-
*
467-
* impl Foo<i64> { ... } // not fully parametric
468-
*
469-
* impl<T> Foo<Foo<T>> { ... } // not fully parametric
470-
*
471-
* impl<T: Trait> Foo<T> { ... } // not fully parametric
472-
*
473-
* impl<T> Foo<T> where T: Trait { ... } // not fully parametric
474-
* ```
475-
*/
476-
pragma[nomagic]
477-
predicate isNotFullyParametric() {
478-
exists(TypeRepr arg | arg = this.getASelfTyArg() |
479-
not exists(resolveTypeParamPathTypeRepr(arg))
480-
or
481-
resolveTypeParamPathTypeRepr(arg).hasTraitBound()
482-
)
483-
}
484-
485-
/**
486-
* Holds if this `impl` block is fully parametric. Examples:
487-
*
488-
* ```rust
489-
* impl Foo { ... } // fully parametric
490-
*
491-
* impl<T> Foo<T> { ... } // fully parametric
492-
*
493-
* impl Foo<i64> { ... } // not fully parametric
494-
*
495-
* impl<T> Foo<Foo<T>> { ... } // not fully parametric
496-
*
497-
* impl<T: Trait> Foo<T> { ... } // not fully parametric
498-
*
499-
* impl<T> Foo<T> where T: Trait { ... } // not fully parametric
500-
* ```
501-
*/
502-
predicate isFullyParametric() { not this.isNotFullyParametric() }
503-
504449
override AssocItemNode getAnAssocItem() { result = super.getAssocItemList().getAnAssocItem() }
505450

506451
override string getName() { result = "(impl)" }

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

Lines changed: 35 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@ newtype TType =
2727
* types, such as traits and implementation blocks.
2828
*/
2929
abstract class Type extends TType {
30-
/** Gets the method `name` belonging to this type, if any. */
31-
pragma[nomagic]
32-
abstract Function getMethod(string name);
33-
3430
/** Gets the struct field `name` belonging to this type, if any. */
3531
pragma[nomagic]
3632
abstract StructField getStructField(string name);
@@ -45,25 +41,6 @@ abstract class Type extends TType {
4541
/** Gets a type parameter of this type. */
4642
final TypeParameter getATypeParameter() { result = this.getTypeParameter(_) }
4743

48-
/**
49-
* Gets an AST node that mentions a base type of this type, if any.
50-
*
51-
* Although Rust doesn't have traditional OOP-style inheritance, we model trait
52-
* bounds and `impl` blocks as base types. Example:
53-
*
54-
* ```rust
55-
* trait T1 {}
56-
*
57-
* trait T2 {}
58-
*
59-
* trait T3 : T1, T2 {}
60-
* // ^^ `this`
61-
* // ^^ `result`
62-
* // ^^ `result`
63-
* ```
64-
*/
65-
abstract TypeMention getABaseTypeMention();
66-
6744
/** Gets a textual representation of this type. */
6845
abstract string toString();
6946

@@ -73,21 +50,6 @@ abstract class Type extends TType {
7350

7451
abstract private class StructOrEnumType extends Type {
7552
abstract ItemNode asItemNode();
76-
77-
final override Function getMethod(string name) {
78-
result = this.asItemNode().getASuccessor(name) and
79-
exists(ImplOrTraitItemNode impl | result = impl.getAnAssocItem() |
80-
impl instanceof Trait
81-
or
82-
impl.(ImplItemNode).isFullyParametric()
83-
)
84-
}
85-
86-
/** Gets all of the fully parametric `impl` blocks that target this type. */
87-
final override ImplMention getABaseTypeMention() {
88-
this.asItemNode() = result.resolveSelfTy() and
89-
result.isFullyParametric()
90-
}
9153
}
9254

9355
/** A struct type. */
@@ -138,8 +100,6 @@ class TraitType extends Type, TTrait {
138100

139101
TraitType() { this = TTrait(trait) }
140102

141-
override Function getMethod(string name) { result = trait.(ItemNode).getASuccessor(name) }
142-
143103
override StructField getStructField(string name) { none() }
144104

145105
override TupleField getTupleField(int i) { none() }
@@ -151,14 +111,6 @@ class TraitType extends Type, TTrait {
151111
any(AssociatedTypeTypeParameter param | param.getTrait() = trait and param.getIndex() = i)
152112
}
153113

154-
pragma[nomagic]
155-
private TypeReprMention getABoundMention() {
156-
result = trait.getTypeBoundList().getABound().getTypeRepr()
157-
}
158-
159-
/** Gets any of the trait bounds of this trait. */
160-
override TypeMention getABaseTypeMention() { result = this.getABoundMention() }
161-
162114
override string toString() { result = trait.toString() }
163115

164116
override Location getLocation() { result = trait.getLocation() }
@@ -220,8 +172,6 @@ class ImplType extends Type, TImpl {
220172

221173
ImplType() { this = TImpl(impl) }
222174

223-
override Function getMethod(string name) { result = impl.(ItemNode).getASuccessor(name) }
224-
225175
override StructField getStructField(string name) { none() }
226176

227177
override TupleField getTupleField(int i) { none() }
@@ -230,9 +180,6 @@ class ImplType extends Type, TImpl {
230180
result = TTypeParamTypeParameter(impl.getGenericParamList().getTypeParam(i))
231181
}
232182

233-
/** Get the trait implemented by this `impl` block, if any. */
234-
override TypeMention getABaseTypeMention() { result = impl.getTrait() }
235-
236183
override string toString() { result = impl.toString() }
237184

238185
override Location getLocation() { result = impl.getLocation() }
@@ -247,8 +194,6 @@ class ImplType extends Type, TImpl {
247194
class ArrayType extends Type, TArrayType {
248195
ArrayType() { this = TArrayType() }
249196

250-
override Function getMethod(string name) { none() }
251-
252197
override StructField getStructField(string name) { none() }
253198

254199
override TupleField getTupleField(int i) { none() }
@@ -257,8 +202,6 @@ class ArrayType extends Type, TArrayType {
257202
none() // todo
258203
}
259204

260-
override TypeMention getABaseTypeMention() { none() }
261-
262205
override string toString() { result = "[]" }
263206

264207
override Location getLocation() { result instanceof EmptyLocation }
@@ -273,8 +216,6 @@ class ArrayType extends Type, TArrayType {
273216
class RefType extends Type, TRefType {
274217
RefType() { this = TRefType() }
275218

276-
override Function getMethod(string name) { none() }
277-
278219
override StructField getStructField(string name) { none() }
279220

280221
override TupleField getTupleField(int i) { none() }
@@ -284,17 +225,13 @@ class RefType extends Type, TRefType {
284225
i = 0
285226
}
286227

287-
override TypeMention getABaseTypeMention() { none() }
288-
289228
override string toString() { result = "&" }
290229

291230
override Location getLocation() { result instanceof EmptyLocation }
292231
}
293232

294233
/** A type parameter. */
295234
abstract class TypeParameter extends Type {
296-
override TypeMention getABaseTypeMention() { none() }
297-
298235
override StructField getStructField(string name) { none() }
299236

300237
override TupleField getTupleField(int i) { none() }
@@ -318,19 +255,9 @@ class TypeParamTypeParameter extends TypeParameter, TTypeParamTypeParameter {
318255

319256
TypeParam getTypeParam() { result = typeParam }
320257

321-
override Function getMethod(string name) {
322-
// NOTE: If the type parameter has trait bounds, then this finds methods
323-
// on the bounding traits.
324-
result = typeParam.(ItemNode).getASuccessor(name)
325-
}
326-
327258
override string toString() { result = typeParam.toString() }
328259

329260
override Location getLocation() { result = typeParam.getLocation() }
330-
331-
final override TypeMention getABaseTypeMention() {
332-
result = typeParam.getTypeBoundList().getABound().getTypeRepr()
333-
}
334261
}
335262

336263
/**
@@ -377,19 +304,13 @@ class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypePara
377304

378305
int getIndex() { traitAliasIndex(_, result, typeAlias) }
379306

380-
override Function getMethod(string name) { none() }
381-
382307
override string toString() { result = typeAlias.getName().getText() }
383308

384309
override Location getLocation() { result = typeAlias.getLocation() }
385-
386-
override TypeMention getABaseTypeMention() { none() }
387310
}
388311

389312
/** An implicit reference type parameter. */
390313
class RefTypeParameter extends TypeParameter, TRefTypeParameter {
391-
override Function getMethod(string name) { none() }
392-
393314
override string toString() { result = "&T" }
394315

395316
override Location getLocation() { result instanceof EmptyLocation }
@@ -409,15 +330,43 @@ class SelfTypeParameter extends TypeParameter, TSelfTypeParameter {
409330

410331
Trait getTrait() { result = trait }
411332

412-
override TypeMention getABaseTypeMention() { result = trait }
333+
override string toString() { result = "Self [" + trait.toString() + "]" }
334+
335+
override Location getLocation() { result = trait.getLocation() }
336+
}
413337

414-
override Function getMethod(string name) {
415-
// The `Self` type parameter is an implementation of the trait, so it has
416-
// all the trait's methods.
417-
result = trait.(ItemNode).getASuccessor(name)
338+
/**
339+
* A type abstraction. I.e., a place in the program where type variables are
340+
* introduced.
341+
*
342+
* Example:
343+
* ```rust
344+
* impl<A, B> Foo<A, B> { }
345+
* // ^^^^^^ a type abstraction
346+
* ```
347+
*/
348+
abstract class TypeAbstraction extends AstNode {
349+
abstract TypeParameter getATypeParameter();
350+
}
351+
352+
final class ImplTypeAbstraction extends TypeAbstraction, Impl {
353+
override TypeParamTypeParameter getATypeParameter() {
354+
result.getTypeParam() = this.getGenericParamList().getATypeParam()
418355
}
356+
}
419357

420-
override string toString() { result = "Self [" + trait.toString() + "]" }
358+
final class TraitTypeAbstraction extends TypeAbstraction, Trait {
359+
override TypeParamTypeParameter getATypeParameter() {
360+
result.getTypeParam() = this.getGenericParamList().getATypeParam()
361+
}
362+
}
421363

422-
override Location getLocation() { result = trait.getLocation() }
364+
final class TypeBoundTypeAbstraction extends TypeAbstraction, TypeBound {
365+
override TypeParamTypeParameter getATypeParameter() { none() }
366+
}
367+
368+
final class SelfTypeBoundTypeAbstraction extends TypeAbstraction, Name {
369+
SelfTypeBoundTypeAbstraction() { any(Trait trait).getName() = this }
370+
371+
override TypeParamTypeParameter getATypeParameter() { none() }
423372
}

0 commit comments

Comments
 (0)