Skip to content

Commit 9dc008b

Browse files
authored
Merge pull request github#19214 from paldepind/rust-ti-associated
Rust: Associated types
2 parents a7943d8 + 48e5b0a commit 9dc008b

File tree

6 files changed

+931
-610
lines changed

6 files changed

+931
-610
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,15 @@ module Impl {
2626
*/
2727
class Trait extends Generated::Trait {
2828
override string toStringImpl() { result = "trait " + this.getName().getText() }
29+
30+
/**
31+
* Gets the number of generic parameters of this trait.
32+
*/
33+
int getNumberOfGenericParams() {
34+
result = this.getGenericParamList().getNumberOfGenericParams()
35+
or
36+
not this.hasGenericParamList() and
37+
result = 0
38+
}
2939
}
3040
}

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

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
private import rust
44
private import PathResolution
5-
private import TypeInference
65
private import TypeMention
76
private import codeql.rust.internal.CachedStages
7+
private import codeql.rust.elements.internal.generated.Raw
8+
private import codeql.rust.elements.internal.generated.Synth
89

910
cached
1011
newtype TType =
@@ -15,6 +16,7 @@ newtype TType =
1516
TArrayType() or // todo: add size?
1617
TRefType() or // todo: add mut?
1718
TTypeParamTypeParameter(TypeParam t) or
19+
TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or
1820
TRefTypeParameter() or
1921
TSelfTypeParameter(Trait t)
2022

@@ -144,6 +146,9 @@ class TraitType extends Type, TTrait {
144146

145147
override TypeParameter getTypeParameter(int i) {
146148
result = TTypeParamTypeParameter(trait.getGenericParamList().getTypeParam(i))
149+
or
150+
result =
151+
any(AssociatedTypeTypeParameter param | param.getTrait() = trait and param.getIndex() = i)
147152
}
148153

149154
pragma[nomagic]
@@ -297,6 +302,14 @@ abstract class TypeParameter extends Type {
297302
override TypeParameter getTypeParameter(int i) { none() }
298303
}
299304

305+
private class RawTypeParameter = @type_param or @trait or @type_alias;
306+
307+
private predicate id(RawTypeParameter x, RawTypeParameter y) { x = y }
308+
309+
private predicate idOfRaw(RawTypeParameter x, int y) = equivalenceRelation(id/2)(x, y)
310+
311+
int idOfTypeParameterAstNode(AstNode node) { idOfRaw(Synth::convertAstNodeToRaw(node), result) }
312+
300313
/** A type parameter from source code. */
301314
class TypeParamTypeParameter extends TypeParameter, TTypeParamTypeParameter {
302315
private TypeParam typeParam;
@@ -320,6 +333,59 @@ class TypeParamTypeParameter extends TypeParameter, TTypeParamTypeParameter {
320333
}
321334
}
322335

336+
/**
337+
* Gets the type alias that is the `i`th type parameter of `trait`. Type aliases
338+
* are numbered consecutively but in arbitrary order, starting from the index
339+
* following the last ordinary type parameter.
340+
*/
341+
predicate traitAliasIndex(Trait trait, int i, TypeAlias typeAlias) {
342+
typeAlias =
343+
rank[i + 1 - trait.getNumberOfGenericParams()](TypeAlias alias |
344+
trait.(TraitItemNode).getADescendant() = alias
345+
|
346+
alias order by idOfTypeParameterAstNode(alias)
347+
)
348+
}
349+
350+
/**
351+
* A type parameter corresponding to an associated type in a trait.
352+
*
353+
* We treat associated type declarations in traits as type parameters. E.g., a
354+
* trait such as
355+
* ```rust
356+
* trait ATrait {
357+
* type AssociatedType;
358+
* // ...
359+
* }
360+
* ```
361+
* is treated as if it was
362+
* ```rust
363+
* trait ATrait<AssociatedType> {
364+
* // ...
365+
* }
366+
* ```
367+
*/
368+
class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypeParameter {
369+
private TypeAlias typeAlias;
370+
371+
AssociatedTypeTypeParameter() { this = TAssociatedTypeTypeParameter(typeAlias) }
372+
373+
TypeAlias getTypeAlias() { result = typeAlias }
374+
375+
/** Gets the trait that contains this associated type declaration. */
376+
TraitItemNode getTrait() { result.getAnAssocItem() = typeAlias }
377+
378+
int getIndex() { traitAliasIndex(_, result, typeAlias) }
379+
380+
override Function getMethod(string name) { none() }
381+
382+
override string toString() { result = typeAlias.getName().getText() }
383+
384+
override Location getLocation() { result = typeAlias.getLocation() }
385+
386+
override TypeMention getABaseTypeMention() { none() }
387+
}
388+
323389
/** An implicit reference type parameter. */
324390
class RefTypeParameter extends TypeParameter, TRefTypeParameter {
325391
override Function getMethod(string name) { none() }

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

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,21 @@ private module Input1 implements InputSig1<Location> {
4040

4141
private newtype TTypeParameterPosition =
4242
TTypeParamTypeParameterPosition(TypeParam tp) or
43-
TSelfTypeParameterPosition()
43+
TImplicitTypeParameterPosition()
4444

4545
class TypeParameterPosition extends TTypeParameterPosition {
4646
TypeParam asTypeParam() { this = TTypeParamTypeParameterPosition(result) }
4747

48-
predicate isSelf() { this = TSelfTypeParameterPosition() }
48+
/**
49+
* Holds if this is the implicit type parameter position used to represent
50+
* parameters that are never passed explicitly as arguments.
51+
*/
52+
predicate isImplicit() { this = TImplicitTypeParameterPosition() }
4953

5054
string toString() {
5155
result = this.asTypeParam().toString()
5256
or
53-
result = "Self" and this.isSelf()
57+
result = "Implicit" and this.isImplicit()
5458
}
5559
}
5660

@@ -69,15 +73,6 @@ private module Input1 implements InputSig1<Location> {
6973
apos.asMethodTypeArgumentPosition() = ppos.asTypeParam().getPosition()
7074
}
7175

72-
/** A raw AST node that might correspond to a type parameter. */
73-
private class RawTypeParameter = @type_param or @trait;
74-
75-
private predicate id(RawTypeParameter x, RawTypeParameter y) { x = y }
76-
77-
private predicate idOfRaw(RawTypeParameter x, int y) = equivalenceRelation(id/2)(x, y)
78-
79-
private int idOf(AstNode node) { idOfRaw(Synth::convertAstNodeToRaw(node), result) }
80-
8176
int getTypeParameterId(TypeParameter tp) {
8277
tp =
8378
rank[result](TypeParameter tp0, int kind, int id |
@@ -86,8 +81,9 @@ private module Input1 implements InputSig1<Location> {
8681
id = 0
8782
or
8883
kind = 1 and
89-
exists(AstNode node | id = idOf(node) |
84+
exists(AstNode node | id = idOfTypeParameterAstNode(node) |
9085
node = tp0.(TypeParamTypeParameter).getTypeParam() or
86+
node = tp0.(AssociatedTypeTypeParameter).getTypeAlias() or
9187
node = tp0.(SelfTypeParameter).getTrait()
9288
)
9389
|
@@ -500,7 +496,10 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
500496
exists(TraitItemNode trait | this = trait.getAnAssocItem() |
501497
typeParamMatchPosition(trait.getTypeParam(_), result, ppos)
502498
or
503-
ppos.isSelf() and result = TSelfTypeParameter(trait)
499+
ppos.isImplicit() and result = TSelfTypeParameter(trait)
500+
or
501+
ppos.isImplicit() and
502+
result.(AssociatedTypeTypeParameter).getTrait() = trait
504503
)
505504
}
506505

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

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,27 @@ class NonAliasPathMention extends PathMention {
9595
this = node.getASelfPath() and
9696
result = node.(ImplItemNode).getSelfPath().getSegment().getGenericArgList().getTypeArg(i)
9797
)
98+
or
99+
// If `this` is the trait of an `impl` block then any associated types
100+
// defined in the `impl` block are type arguments to the trait.
101+
//
102+
// For instance, for a trait implementation like this
103+
// ```rust
104+
// impl MyTrait for MyType {
105+
// ^^^^^^^ this
106+
// type AssociatedType = i64
107+
// ^^^ result
108+
// // ...
109+
// }
110+
// ```
111+
// the rhs. of the type alias is a type argument to the trait.
112+
exists(ImplItemNode impl, AssociatedTypeTypeParameter param, TypeAlias alias |
113+
this = impl.getTraitPath() and
114+
param.getTrait() = resolvePath(this) and
115+
alias = impl.getASuccessor(param.getTypeAlias().getName().getText()) and
116+
result = alias.getTypeRepr() and
117+
param.getIndex() = i
118+
)
98119
}
99120

100121
override Type resolveType() {
@@ -113,7 +134,11 @@ class NonAliasPathMention extends PathMention {
113134
or
114135
result = TTypeParamTypeParameter(i)
115136
or
116-
result = i.(TypeAlias).getTypeRepr().(TypeReprMention).resolveType()
137+
exists(TypeAlias alias | alias = i |
138+
result.(AssociatedTypeTypeParameter).getTypeAlias() = alias
139+
or
140+
result = alias.getTypeRepr().(TypeReprMention).resolveType()
141+
)
117142
)
118143
}
119144
}
@@ -153,6 +178,17 @@ class TypeParamMention extends TypeMention, TypeParam {
153178
override Type resolveType() { result = TTypeParamTypeParameter(this) }
154179
}
155180

181+
// Used to represent implicit type arguments for associated types in traits.
182+
class TypeAliasMention extends TypeMention, TypeAlias {
183+
private Type t;
184+
185+
TypeAliasMention() { t = TAssociatedTypeTypeParameter(this) }
186+
187+
override TypeReprMention getTypeArgument(int i) { none() }
188+
189+
override Type resolveType() { result = t }
190+
}
191+
156192
/**
157193
* Holds if the `i`th type argument of `selfPath`, belonging to `impl`, resolves
158194
* to type parameter `tp`.
@@ -204,7 +240,11 @@ class ImplMention extends TypeMention, ImplItemNode {
204240
}
205241

206242
class TraitMention extends TypeMention, TraitItemNode {
207-
override TypeMention getTypeArgument(int i) { result = this.getTypeParam(i) }
243+
override TypeMention getTypeArgument(int i) {
244+
result = this.getTypeParam(i)
245+
or
246+
traitAliasIndex(this, i, result)
247+
}
208248

209249
override Type resolveType() { result = TTrait(this) }
210250
}

0 commit comments

Comments
 (0)