Skip to content

Commit f8b991c

Browse files
committed
Rust: Make trait a base type mention of the self type parameter
1 parent 884c828 commit f8b991c

File tree

4 files changed

+128
-292
lines changed

4 files changed

+128
-292
lines changed

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

+24-11
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ newtype TType =
1616
TRefType() or // todo: add mut?
1717
TTypeParamTypeParameter(TypeParam t) or
1818
TRefTypeParameter() or
19-
TSelfTypeParameter()
19+
TSelfTypeParameter(Trait t)
2020

2121
/**
2222
* A type without type arguments.
@@ -144,9 +144,6 @@ class TraitType extends Type, TTrait {
144144

145145
override TypeParameter getTypeParameter(int i) {
146146
result = TTypeParamTypeParameter(trait.getGenericParamList().getTypeParam(i))
147-
or
148-
result = TSelfTypeParameter() and
149-
i = -1
150147
}
151148

152149
pragma[nomagic]
@@ -226,11 +223,9 @@ class ImplType extends Type, TImpl {
226223

227224
override TypeParameter getTypeParameter(int i) {
228225
result = TTypeParamTypeParameter(impl.getGenericParamList().getTypeParam(i))
229-
or
230-
result = TSelfTypeParameter() and
231-
i = -1
232226
}
233227

228+
/** Get the trait implemented by this `impl` block, if any. */
234229
override TypeMention getABaseTypeMention() { result = impl.getTrait() }
235230

236231
override string toString() { result = impl.toString() }
@@ -334,11 +329,29 @@ class RefTypeParameter extends TypeParameter, TRefTypeParameter {
334329
override Location getLocation() { result instanceof EmptyLocation }
335330
}
336331

337-
/** An implicit `Self` type parameter. */
332+
/**
333+
* The implicit `Self` type parameter of a trait, that refers to the
334+
* implementing type of the trait.
335+
*
336+
* The Rust Reference on the implicit `Self` parameter:
337+
* https://doc.rust-lang.org/reference/items/traits.html#r-items.traits.self-param
338+
*/
338339
class SelfTypeParameter extends TypeParameter, TSelfTypeParameter {
339-
override Function getMethod(string name) { none() }
340+
private Trait trait;
340341

341-
override string toString() { result = "(Self)" }
342+
SelfTypeParameter() { this = TSelfTypeParameter(trait) }
342343

343-
override Location getLocation() { result instanceof EmptyLocation }
344+
Trait getTrait() { result = trait }
345+
346+
override TypeMention getABaseTypeMention() { result = trait }
347+
348+
override Function getMethod(string name) {
349+
// The `Self` type parameter is an implementation of the trait, so it has
350+
// all the trait's methods.
351+
result = trait.(ItemNode).getASuccessor(name)
352+
}
353+
354+
override string toString() { result = "Self [" + trait.toString() + "]" }
355+
356+
override Location getLocation() { result = trait.getLocation() }
344357
}

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

+53-44
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,42 @@ private module Input1 implements InputSig1<Location> {
3838
}
3939
}
4040

41-
class TypeParameterPosition = TypeParam;
41+
private newtype TTypeParameterPosition =
42+
TTypeParamTypeParameterPosition(TypeParam tp) or
43+
TSelfTypeParameterPosition()
44+
45+
class TypeParameterPosition extends TTypeParameterPosition {
46+
TypeParam asTypeParam() { this = TTypeParamTypeParameterPosition(result) }
47+
48+
predicate isSelf() { this = TSelfTypeParameterPosition() }
49+
50+
string toString() {
51+
result = this.asTypeParam().toString()
52+
or
53+
result = "Self" and this.isSelf()
54+
}
55+
}
56+
57+
/** Holds if `typeParam`, `param` and `ppos` all concern the same `TypeParam`. */
58+
additional predicate typeParamMatchPosition(
59+
TypeParam typeParam, TypeParamTypeParameter param, TypeParameterPosition ppos
60+
) {
61+
typeParam = param.getTypeParam() and typeParam = ppos.asTypeParam()
62+
}
4263

4364
bindingset[apos]
4465
bindingset[ppos]
4566
predicate typeArgumentParameterPositionMatch(TypeArgumentPosition apos, TypeParameterPosition ppos) {
46-
apos.asTypeParam() = ppos
67+
apos.asTypeParam() = ppos.asTypeParam()
4768
or
48-
apos.asMethodTypeArgumentPosition() = ppos.getPosition()
69+
apos.asMethodTypeArgumentPosition() = ppos.asTypeParam().getPosition()
4970
}
5071

51-
private predicate id(Raw::TypeParam x, Raw::TypeParam y) { x = y }
72+
private predicate id(Raw::AstNode x, Raw::AstNode y) { x = y }
5273

53-
private predicate idOfRaw(Raw::TypeParam x, int y) = equivalenceRelation(id/2)(x, y)
74+
private predicate idOfRaw(Raw::AstNode x, int y) = equivalenceRelation(id/2)(x, y)
5475

55-
private int idOf(TypeParam node) { idOfRaw(Synth::convertAstNodeToRaw(node), result) }
76+
private int idOf(AstNode node) { idOfRaw(Synth::convertAstNodeToRaw(node), result) }
5677

5778
int getTypeParameterId(TypeParameter tp) {
5879
tp =
@@ -65,8 +86,11 @@ private module Input1 implements InputSig1<Location> {
6586
kind = 0 and
6687
id = 1
6788
or
68-
id = idOf(tp0.(TypeParamTypeParameter).getTypeParam()) and
69-
kind = 1
89+
kind = 1 and
90+
exists(AstNode node | id = idOf(node) |
91+
node = tp0.(TypeParamTypeParameter).getTypeParam() or
92+
node = tp0.(SelfTypeParameter).getTrait()
93+
)
7094
|
7195
tp0 order by kind, id
7296
)
@@ -211,15 +235,6 @@ private Type inferImplSelfType(Impl i, TypePath path) {
211235
result = i.getSelfTy().(TypeReprMention).resolveTypeAt(path)
212236
}
213237

214-
pragma[nomagic]
215-
private Type inferTraitSelfType(Trait t, TypePath path) {
216-
result = TTrait(t) and
217-
path.isEmpty()
218-
or
219-
result = TTypeParamTypeParameter(t.getGenericParamList().getATypeParam()) and
220-
path = TypePath::singleton(result)
221-
}
222-
223238
/** Gets the type at `path` of the implicitly typed `self` parameter. */
224239
pragma[nomagic]
225240
private Type inferImplicitSelfType(SelfParam self, TypePath path) {
@@ -230,7 +245,7 @@ private Type inferImplicitSelfType(SelfParam self, TypePath path) {
230245
|
231246
t = inferImplSelfType(i, suffix)
232247
or
233-
t = inferTraitSelfType(i, suffix)
248+
t = TSelfTypeParameter(i) and suffix.isEmpty()
234249
)
235250
}
236251

@@ -273,8 +288,7 @@ private module StructExprMatchingInput implements MatchingInputSig {
273288
abstract TypeParam getATypeParam();
274289

275290
final TypeParameter getTypeParameter(TypeParameterPosition ppos) {
276-
result.(TypeParamTypeParameter).getTypeParam() = ppos and
277-
ppos = this.getATypeParam()
291+
typeParamMatchPosition(this.getATypeParam(), result, ppos)
278292
}
279293

280294
abstract StructField getField(string name);
@@ -417,12 +431,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
417431
}
418432

419433
abstract class Declaration extends AstNode {
420-
abstract TypeParam getATypeParam();
421-
422-
final TypeParameter getTypeParameter(TypeParameterPosition ppos) {
423-
result.(TypeParamTypeParameter).getTypeParam() = ppos and
424-
ppos = this.getATypeParam()
425-
}
434+
abstract TypeParameter getTypeParameter(TypeParameterPosition ppos);
426435

427436
pragma[nomagic]
428437
abstract Type getParameterType(DeclarationPosition dpos, TypePath path);
@@ -440,7 +449,9 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
440449
private class TupleStructDecl extends Declaration, Struct {
441450
TupleStructDecl() { this.isTuple() }
442451

443-
override TypeParam getATypeParam() { result = this.getGenericParamList().getATypeParam() }
452+
override TypeParameter getTypeParameter(TypeParameterPosition ppos) {
453+
typeParamMatchPosition(this.getGenericParamList().getATypeParam(), result, ppos)
454+
}
444455

445456
override Type getParameterType(DeclarationPosition dpos, TypePath path) {
446457
exists(int pos |
@@ -461,8 +472,8 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
461472
private class TupleVariantDecl extends Declaration, Variant {
462473
TupleVariantDecl() { this.isTuple() }
463474

464-
override TypeParam getATypeParam() {
465-
result = this.getEnum().getGenericParamList().getATypeParam()
475+
override TypeParameter getTypeParameter(TypeParameterPosition ppos) {
476+
typeParamMatchPosition(this.getEnum().getGenericParamList().getATypeParam(), result, ppos)
466477
}
467478

468479
override Type getParameterType(DeclarationPosition dpos, TypePath path) {
@@ -483,38 +494,36 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
483494
}
484495
}
485496

486-
pragma[nomagic]
487-
private Type inferAnnotatedTypeInclSelf(AstNode n, TypePath path) {
488-
result = getTypeAnnotation(n).resolveTypeAtInclSelf(path)
489-
}
490-
491497
private class FunctionDecl extends Declaration, Function {
492-
override TypeParam getATypeParam() { result = this.getGenericParamList().getATypeParam() }
498+
override TypeParameter getTypeParameter(TypeParameterPosition ppos) {
499+
typeParamMatchPosition(this.getGenericParamList().getATypeParam(), result, ppos)
500+
or
501+
exists(TraitItemNode trait | this = trait.getAnAssocItem() |
502+
typeParamMatchPosition(trait.getTypeParam(_), result, ppos)
503+
or
504+
ppos.isSelf() and result = TSelfTypeParameter(trait)
505+
)
506+
}
493507

494508
override Type getParameterType(DeclarationPosition dpos, TypePath path) {
495509
exists(Param p, int i, boolean inMethod |
496510
paramPos(this.getParamList(), p, i, inMethod) and
497511
dpos = TPositionalDeclarationPosition(i, inMethod) and
498-
result = inferAnnotatedTypeInclSelf(p.getPat(), path)
512+
result = inferAnnotatedType(p.getPat(), path)
499513
)
500514
or
501515
exists(SelfParam self |
502516
self = pragma[only_bind_into](this.getParamList().getSelfParam()) and
503517
dpos.isSelf()
504518
|
505-
// `self` parameter with type annotation
506-
result = inferAnnotatedTypeInclSelf(self, path)
507-
or
508-
// `self` parameter without type annotation
509-
result = inferImplicitSelfType(self, path)
519+
result = inferAnnotatedType(self, path) // `self` parameter with type annotation
510520
or
511-
// `self` parameter without type annotation should also have the special `Self` type
512-
result = getRefAdjustImplicitSelfType(self, TypePath::nil(), TSelfTypeParameter(), path)
521+
result = inferImplicitSelfType(self, path) // `self` parameter without type annotation
513522
)
514523
}
515524

516525
override Type getReturnType(TypePath path) {
517-
result = this.getRetType().getTypeRepr().(TypeReprMention).resolveTypeAtInclSelf(path)
526+
result = this.getRetType().getTypeRepr().(TypeReprMention).resolveTypeAt(path)
518527
}
519528
}
520529

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

+20-28
Original file line numberDiff line numberDiff line change
@@ -29,27 +29,6 @@ abstract class TypeMention extends AstNode {
2929

3030
/** Gets the type that the sub mention at `path` resolves to, if any. */
3131
Type resolveTypeAt(TypePath path) { result = this.getMentionAt(path).resolveType() }
32-
33-
/**
34-
* Like `resolveTypeAt`, but also resolves `Self` mentions to the implicit
35-
* `Self` type parameter.
36-
*
37-
* This is only needed when resolving types for calls to methods; inside the
38-
* methods themselves, `Self` only resolves to the relevant trait or type
39-
* being implemented.
40-
*/
41-
final Type resolveTypeAtInclSelf(TypePath path) {
42-
result = this.resolveTypeAt(path)
43-
or
44-
exists(TypeMention tm, ImplOrTraitItemNode node |
45-
tm = this.getMentionAt(path) and
46-
result = TSelfTypeParameter()
47-
|
48-
tm = node.getASelfPath()
49-
or
50-
tm.(PathTypeRepr).getPath() = node.getASelfPath()
51-
)
52-
}
5332
}
5433

5534
class TypeReprMention extends TypeMention, TypeRepr {
@@ -80,22 +59,21 @@ class PathMention extends TypeMention, Path {
8059
override TypeMention getTypeArgument(int i) {
8160
result = this.getPart().getGenericArgList().getTypeArg(i)
8261
or
83-
// `Self` paths inside traits and `impl` blocks have implicit type arguments
84-
// that are the type parameters of the trait or impl. For example, in
62+
// `Self` paths inside `impl` blocks have implicit type arguments that are
63+
// the type parameters of the `impl` block. For example, in
8564
//
8665
// ```rust
87-
// impl Foo<T> {
66+
// impl<T> Foo<T> {
8867
// fn m(self) -> Self {
8968
// self
9069
// }
9170
// }
9271
// ```
9372
//
9473
// the `Self` return type is shorthand for `Foo<T>`.
95-
exists(ImplOrTraitItemNode node | this = node.getASelfPath() |
74+
exists(ImplItemNode node |
75+
this = node.getASelfPath() and
9676
result = node.(ImplItemNode).getSelfPath().getPart().getGenericArgList().getTypeArg(i)
97-
or
98-
result = node.(Trait).getGenericParamList().getTypeParam(i)
9977
)
10078
}
10179

@@ -105,7 +83,13 @@ class PathMention extends TypeMention, Path {
10583
or
10684
result = TEnum(i)
10785
or
108-
result = TTrait(i)
86+
exists(TraitItemNode trait | trait = i |
87+
// If this is a `Self` path, then it resolves to the implicit `Self`
88+
// type parameter, otherwise it is a trait bound.
89+
if this = trait.getASelfPath()
90+
then result = TSelfTypeParameter(trait)
91+
else result = TTrait(trait)
92+
)
10993
or
11094
result = TTypeParamTypeParameter(i)
11195
or
@@ -171,3 +155,11 @@ class ImplMention extends TypeMention, ImplItemNode {
171155
)
172156
}
173157
}
158+
159+
class TraitMention extends TypeMention, TraitItemNode {
160+
override TypeMention getTypeArgument(int i) {
161+
result = this.getTypeParam(i)
162+
}
163+
164+
override Type resolveType() { result = TTrait(this) }
165+
}

0 commit comments

Comments
 (0)