Skip to content

Commit 31c4c7a

Browse files
committed
WIP: Support non-universal impl blocks
1 parent c11ed6d commit 31c4c7a

File tree

6 files changed

+1827
-1021
lines changed

6 files changed

+1827
-1021
lines changed

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

Lines changed: 28 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,36 @@ 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() + "]" }
413334

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)
335+
override Location getLocation() { result = trait.getLocation() }
336+
}
337+
338+
/** A type abstraction. */
339+
abstract class TypeAbstraction extends AstNode {
340+
abstract TypeParameter getATypeParameter();
341+
}
342+
343+
final class ImplTypeAbstraction extends TypeAbstraction, Impl {
344+
override TypeParamTypeParameter getATypeParameter() {
345+
result.getTypeParam() = this.getGenericParamList().getATypeParam()
418346
}
347+
}
419348

420-
override string toString() { result = "Self [" + trait.toString() + "]" }
349+
final class TraitTypeAbstraction extends TypeAbstraction, Trait {
350+
override TypeParamTypeParameter getATypeParameter() {
351+
result.getTypeParam() = this.getGenericParamList().getATypeParam()
352+
}
353+
}
421354

422-
override Location getLocation() { result = trait.getLocation() }
355+
final class TypeBoundTypeAbstraction extends TypeAbstraction, TypeBound {
356+
override TypeParamTypeParameter getATypeParameter() { none() }
357+
}
358+
359+
final class SelfTypeBoundTypeAbstraction extends TypeAbstraction, Name {
360+
Trait trait;
361+
362+
SelfTypeBoundTypeAbstraction() { trait.getName() = this }
363+
364+
override TypeParamTypeParameter getATypeParameter() { none() }
423365
}

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

Lines changed: 84 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ private module Input1 implements InputSig1<Location> {
1818

1919
class TypeParameter = T::TypeParameter;
2020

21+
class TypeAbstraction = T::TypeAbstraction;
22+
2123
private newtype TTypeArgumentPosition =
2224
// method type parameters are matched by position instead of by type
2325
// parameter entity, to avoid extra recursion through method call resolution
@@ -107,7 +109,46 @@ private module Input2 implements InputSig2 {
107109

108110
class TypeMention = TM::TypeMention;
109111

110-
TypeMention getABaseTypeMention(Type t) { result = t.getABaseTypeMention() }
112+
TypeMention getABaseTypeMention(Type t) {
113+
// Rust does not have subtyping.
114+
none()
115+
}
116+
117+
TypeMention getTypeParameterConstraint(TypeParameter tp) {
118+
result = tp.(TypeParamTypeParameter).getTypeParam().getTypeBoundList().getABound().getTypeRepr()
119+
or
120+
result = tp.(SelfTypeParameter).getTrait()
121+
}
122+
123+
predicate typeSatisfiesConstraint(TypeAbstraction abs, TypeMention sub, TypeMention sup) {
124+
// `impl` blocks implementing traits
125+
exists(Impl impl |
126+
abs = impl and
127+
sub = impl.getSelfTy() and
128+
sup = impl.getTrait()
129+
)
130+
or
131+
// supertraits
132+
exists(Trait trait |
133+
abs = trait and
134+
sub = trait and
135+
sup = trait.getTypeBoundList().getABound().getTypeRepr()
136+
)
137+
or
138+
// trait bounds on type parameters
139+
exists(TypeParam param |
140+
abs = param.getTypeBoundList().getABound() and
141+
sub = param and
142+
sup = param.getTypeBoundList().getABound().getTypeRepr()
143+
)
144+
or
145+
// the implicit `Self` type parameter satisfies the trait
146+
exists(SelfTypeParameterMention self |
147+
abs = self and
148+
sub = self and
149+
sup = self.getTrait()
150+
)
151+
}
111152
}
112153

113154
private module M2 = Make2<Input2>;
@@ -226,7 +267,7 @@ private Type getRefAdjustImplicitSelfType(SelfParam self, TypePath suffix, Type
226267
}
227268

228269
pragma[nomagic]
229-
private Type inferImplSelfType(Impl i, TypePath path) {
270+
private Type resolveImplSelfType(Impl i, TypePath path) {
230271
result = i.getSelfTy().(TypeReprMention).resolveTypeAt(path)
231272
}
232273

@@ -238,7 +279,7 @@ private Type inferImplicitSelfType(SelfParam self, TypePath path) {
238279
self = f.getParamList().getSelfParam() and
239280
result = getRefAdjustImplicitSelfType(self, suffix, t, path)
240281
|
241-
t = inferImplSelfType(i, suffix)
282+
t = resolveImplSelfType(i, suffix)
242283
or
243284
t = TSelfTypeParameter(i) and suffix.isEmpty()
244285
)
@@ -896,34 +937,65 @@ private module Cached {
896937
private import codeql.rust.internal.CachedStages
897938

898939
pragma[inline]
899-
private Type getLookupType(AstNode n) {
940+
private Type inferTypeDeref(AstNode n, TypePath path) {
900941
exists(Type t |
901942
t = inferType(n) and
902943
if t = TRefType()
903944
then
904945
// for reference types, lookup members in the type being referenced
905-
result = inferType(n, TypePath::singleton(TRefTypeParameter()))
906-
else result = t
946+
result = inferType(n, TypePath::cons(TRefTypeParameter(), path))
947+
else result = inferType(n, path)
907948
)
908949
}
909950

910-
pragma[nomagic]
911-
private Type getMethodCallExprLookupType(MethodCallExpr mce, string name) {
912-
result = getLookupType(mce.getReceiver()) and
913-
name = mce.getIdentifier().getText()
951+
private class ReceiverExpr extends Expr {
952+
ReceiverExpr() { any(MethodCallExpr mce).getReceiver() = this }
953+
954+
Type resolveTypeAt(TypePath path) { result = inferTypeDeref(this, path) }
955+
}
956+
957+
bindingset[tp, name]
958+
private Function getTypeParameterMethod(TypeParameter tp, string name) {
959+
result = tp.(TypeParamTypeParameter).getTypeParam().(ItemNode).getASuccessor(name)
960+
or
961+
result = tp.(SelfTypeParameter).getTrait().(ItemNode).getASuccessor(name)
962+
}
963+
964+
/**
965+
* Gets an `impl` block with an implementing type that matches the type of
966+
* `mce`'s receiver.
967+
*/
968+
private predicate methodCallMatchingImpl(ReceiverExpr receiver, string name, Function function) {
969+
exists(MethodCallExpr mce, Impl impl |
970+
mce.getReceiver() = receiver and
971+
mce.getIdentifier().getText() = name and
972+
TypeTreeUtils<ReceiverExpr, TypeMention>::isInstantiationOf(impl, receiver,
973+
impl.getSelfTy().(TypeReprMention)) and
974+
function = impl.(ImplItemNode).getASuccessor(name)
975+
)
914976
}
915977

916978
/**
917979
* Gets a method that the method call `mce` resolves to, if any.
918980
*/
919981
cached
920982
Function resolveMethodCallExpr(MethodCallExpr mce) {
921-
exists(string name | result = getMethodCallExprLookupType(mce, name).getMethod(name))
983+
exists(ReceiverExpr receiver, string name |
984+
mce.getReceiver() = receiver and
985+
mce.getIdentifier().getText() = name
986+
|
987+
// The method comes from an `impl` block targeting the type of `receiver`.
988+
methodCallMatchingImpl(receiver, name, result)
989+
or
990+
// The type of `receiver` is a type parameter and the method comes from a
991+
// trait bound on the type parameter.
992+
result = getTypeParameterMethod(inferTypeDeref(receiver, TypePath::nil()), name)
993+
)
922994
}
923995

924996
pragma[nomagic]
925997
private Type getFieldExprLookupType(FieldExpr fe, string name) {
926-
result = getLookupType(fe.getContainer()) and
998+
result = inferTypeDeref(fe.getContainer(), TypePath::nil()) and
927999
name = fe.getIdentifier().getText()
9281000
}
9291001

0 commit comments

Comments
 (0)