Skip to content

Commit 8acf9ce

Browse files
committed
Rust: Make trait a base type mention of the self type parameter
1 parent f4105ee commit 8acf9ce

File tree

4 files changed

+126
-296
lines changed

4 files changed

+126
-296
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-48
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 =
@@ -61,12 +82,11 @@ private module Input1 implements InputSig1<Location> {
6182
kind = 0 and
6283
id = 0
6384
or
64-
tp0 instanceof SelfTypeParameter and
65-
kind = 0 and
66-
id = 1
67-
or
68-
id = idOf(tp0.(TypeParamTypeParameter).getTypeParam()) and
69-
kind = 1
85+
kind = 1 and
86+
exists(AstNode node | id = idOf(node) |
87+
node = tp0.(TypeParamTypeParameter).getTypeParam() or
88+
node = tp0.(SelfTypeParameter).getTrait()
89+
)
7090
|
7191
tp0 order by kind, id
7292
)
@@ -211,15 +231,6 @@ private Type inferImplSelfType(Impl i, TypePath path) {
211231
result = i.getSelfTy().(TypeReprMention).resolveTypeAt(path)
212232
}
213233

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-
223234
/** Gets the type at `path` of the implicitly typed `self` parameter. */
224235
pragma[nomagic]
225236
private Type inferImplicitSelfType(SelfParam self, TypePath path) {
@@ -230,7 +241,7 @@ private Type inferImplicitSelfType(SelfParam self, TypePath path) {
230241
|
231242
t = inferImplSelfType(i, suffix)
232243
or
233-
t = inferTraitSelfType(i, suffix)
244+
t = TSelfTypeParameter(i) and suffix.isEmpty()
234245
)
235246
}
236247

@@ -273,8 +284,7 @@ private module StructExprMatchingInput implements MatchingInputSig {
273284
abstract TypeParam getATypeParam();
274285

275286
final TypeParameter getTypeParameter(TypeParameterPosition ppos) {
276-
result.(TypeParamTypeParameter).getTypeParam() = ppos and
277-
ppos = this.getATypeParam()
287+
typeParamMatchPosition(this.getATypeParam(), result, ppos)
278288
}
279289

280290
abstract StructField getField(string name);
@@ -417,12 +427,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
417427
}
418428

419429
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-
}
430+
abstract TypeParameter getTypeParameter(TypeParameterPosition ppos);
426431

427432
pragma[nomagic]
428433
abstract Type getParameterType(DeclarationPosition dpos, TypePath path);
@@ -440,7 +445,9 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
440445
private class TupleStructDecl extends Declaration, Struct {
441446
TupleStructDecl() { this.isTuple() }
442447

443-
override TypeParam getATypeParam() { result = this.getGenericParamList().getATypeParam() }
448+
override TypeParameter getTypeParameter(TypeParameterPosition ppos) {
449+
typeParamMatchPosition(this.getGenericParamList().getATypeParam(), result, ppos)
450+
}
444451

445452
override Type getParameterType(DeclarationPosition dpos, TypePath path) {
446453
exists(int pos |
@@ -461,8 +468,8 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
461468
private class TupleVariantDecl extends Declaration, Variant {
462469
TupleVariantDecl() { this.isTuple() }
463470

464-
override TypeParam getATypeParam() {
465-
result = this.getEnum().getGenericParamList().getATypeParam()
471+
override TypeParameter getTypeParameter(TypeParameterPosition ppos) {
472+
typeParamMatchPosition(this.getEnum().getGenericParamList().getATypeParam(), result, ppos)
466473
}
467474

468475
override Type getParameterType(DeclarationPosition dpos, TypePath path) {
@@ -483,38 +490,36 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
483490
}
484491
}
485492

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

494504
override Type getParameterType(DeclarationPosition dpos, TypePath path) {
495505
exists(Param p, int i, boolean inMethod |
496506
paramPos(this.getParamList(), p, i, inMethod) and
497507
dpos = TPositionalDeclarationPosition(i, inMethod) and
498-
result = inferAnnotatedTypeInclSelf(p.getPat(), path)
508+
result = inferAnnotatedType(p.getPat(), path)
499509
)
500510
or
501511
exists(SelfParam self |
502512
self = pragma[only_bind_into](this.getParamList().getSelfParam()) and
503513
dpos.isSelf()
504514
|
505-
// `self` parameter with type annotation
506-
result = inferAnnotatedTypeInclSelf(self, path)
507-
or
508-
// `self` parameter without type annotation
509-
result = inferImplicitSelfType(self, path)
515+
result = inferAnnotatedType(self, path) // `self` parameter with type annotation
510516
or
511-
// `self` parameter without type annotation should also have the special `Self` type
512-
result = getRefAdjustImplicitSelfType(self, TypePath::nil(), TSelfTypeParameter(), path)
517+
result = inferImplicitSelfType(self, path) // `self` parameter without type annotation
513518
)
514519
}
515520

516521
override Type getReturnType(TypePath path) {
517-
result = this.getRetType().getTypeRepr().(TypeReprMention).resolveTypeAtInclSelf(path)
522+
result = this.getRetType().getTypeRepr().(TypeReprMention).resolveTypeAt(path)
518523
}
519524
}
520525

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

+18-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.getSegment().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().getSegment().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,9 @@ class ImplMention extends TypeMention, ImplItemNode {
171155
)
172156
}
173157
}
158+
159+
class TraitMention extends TypeMention, TraitItemNode {
160+
override TypeMention getTypeArgument(int i) { result = this.getTypeParam(i) }
161+
162+
override Type resolveType() { result = TTrait(this) }
163+
}

0 commit comments

Comments
 (0)