Skip to content

Commit f15f4ce

Browse files
committed
Rust: Type inference 2.0
1 parent fa9d30f commit f15f4ce

18 files changed

Lines changed: 1949 additions & 2064 deletions

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

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import rust
3030
* The `backref` predicate starts with `1 = 1 or` to ensure that the predicate will be optimized down to a constant by the optimizer.
3131
*/
3232
module Stages {
33+
private import codeql.rust.internal.typeinference.TypeInference as TypeInference
34+
3335
/**
3436
* The abstract syntex tree (AST) stage.
3537
*/
@@ -126,35 +128,7 @@ module Stages {
126128
/**
127129
* The type inference stage.
128130
*/
129-
cached
130-
module TypeInferenceStage {
131-
private import codeql.rust.internal.typeinference.Type
132-
private import codeql.rust.internal.typeinference.TypeInference
133-
private import codeql.rust.dataflow.internal.ModelsAsData
134-
135-
/**
136-
* Always holds.
137-
* Ensures that a predicate is evaluated as part of the type inference stage.
138-
*/
139-
cached
140-
predicate ref() { 1 = 1 }
141-
142-
/**
143-
* DO NOT USE!
144-
*
145-
* Contains references to each predicate that use the above `ref` predicate.
146-
*/
147-
cached
148-
predicate backref() {
149-
1 = 1
150-
or
151-
exists(Type t)
152-
or
153-
exists(inferType(_))
154-
or
155-
mayInvokeCallback(_, _)
156-
}
157-
}
131+
module TypeInferenceStage = TypeInference::CachedStage;
158132

159133
/**
160134
* The data flow stage.

rust/ql/lib/codeql/rust/internal/typeinference/BlanketImplementation.qll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,7 @@ module SatisfiesBlanketConstraint<
9696

9797
Type getTypeAt(TypePath path) {
9898
result = at.getTypeAt(blanketPath.appendInverse(path)) and
99-
not result = TNeverType() and
100-
not result = TUnknownType()
99+
not result instanceof PseudoType
101100
}
102101

103102
string toString() { result = at.toString() + " [blanket at " + blanketPath.toString() + "]" }

rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,9 @@ predicate traitTypeParameterOccurrence(
166166
}
167167

168168
pragma[nomagic]
169-
private predicate functionResolutionDependsOnArgumentCand(
170-
ImplItemNode impl, Function f, string functionName, TypeParameter traitTp, FunctionPosition pos,
171-
TypePath path
169+
predicate functionResolutionDependsOnArgumentCand(
170+
ImplItemNode impl, Function f, string functionName, TypeParamTypeParameter traitTp,
171+
FunctionPosition pos, TypePath path
172172
) {
173173
/*
174174
* As seen in the example below, when an implementation has a sibling for a
@@ -199,12 +199,14 @@ private predicate functionResolutionDependsOnArgumentCand(
199199
)
200200
}
201201

202-
private predicate functionResolutionDependsOnPositionalArgumentCand(
203-
ImplItemNode impl, Function f, string functionName, TypeParameter traitTp
202+
pragma[nomagic]
203+
predicate functionResolutionDependsOnPositionalArgumentCand(
204+
ImplItemNode impl, Function f, string functionName, TypeParamTypeParameter traitTp, int pos,
205+
TypePath path
204206
) {
205-
exists(FunctionPosition pos |
206-
functionResolutionDependsOnArgumentCand(impl, f, functionName, traitTp, pos, _) and
207-
pos.isPosition()
207+
exists(FunctionPosition pos0 |
208+
functionResolutionDependsOnArgumentCand(impl, f, functionName, traitTp, pos0, path) and
209+
pos = pos0.asPosition()
208210
)
209211
}
210212

@@ -223,7 +225,7 @@ private Type getAssocFunctionNonTypeParameterTypeAt(
223225
*/
224226
pragma[nomagic]
225227
private predicate hasEquivalentPositionalSibling(
226-
ImplItemNode impl, ImplItemNode sibling, Function f, TypeParameter traitTp
228+
ImplItemNode impl, ImplItemNode sibling, Function f, TypeParamTypeParameter traitTp
227229
) {
228230
exists(string functionName, FunctionPosition pos, TypePath path |
229231
functionResolutionDependsOnArgumentCand(impl, f, functionName, traitTp, pos, path) and
@@ -255,7 +257,7 @@ private predicate hasEquivalentPositionalSibling(
255257
*
256258
* `traitTp` is a type parameter of the trait being implemented by `impl`, and
257259
* we need to check that the type of `f` corresponding to `traitTp` is satisfied
258-
* at any one of the positions `pos` in which that type occurs in `f`.
260+
* at any one of the positions `pos` in which that type occurs at `path` in `f`.
259261
*
260262
* Type parameters that only occur in return positions are only included when
261263
* all other type parameters that occur in a positional position are insufficient
@@ -283,19 +285,20 @@ private predicate hasEquivalentPositionalSibling(
283285
*/
284286
pragma[nomagic]
285287
predicate functionResolutionDependsOnArgument(
286-
ImplItemNode impl, Function f, TypeParameter traitTp, FunctionPosition pos
288+
ImplItemNode impl, Function f, TypeParamTypeParameter traitTp, FunctionPosition pos, TypePath path
287289
) {
288290
exists(string functionName |
289-
functionResolutionDependsOnArgumentCand(impl, f, functionName, traitTp, pos, _)
291+
functionResolutionDependsOnArgumentCand(impl, f, functionName, traitTp, pos, path)
290292
|
291-
if functionResolutionDependsOnPositionalArgumentCand(impl, f, functionName, traitTp)
293+
if functionResolutionDependsOnPositionalArgumentCand(impl, f, functionName, traitTp, _, _)
292294
then any()
293295
else
294296
// `traitTp` only occurs in return position; check that it is indeed needed for disambiguation
295297
exists(ImplItemNode sibling |
296298
implSiblings(_, impl, sibling) and
297-
forall(TypeParameter otherTraitTp |
298-
functionResolutionDependsOnPositionalArgumentCand(impl, f, functionName, otherTraitTp)
299+
forall(TypeParamTypeParameter otherTraitTp |
300+
functionResolutionDependsOnPositionalArgumentCand(impl, f, functionName, otherTraitTp, _,
301+
_)
299302
|
300303
hasEquivalentPositionalSibling(impl, sibling, f, otherTraitTp)
301304
)

rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,7 @@ module ArgIsInstantiationOf<ArgSig Arg, IsInstantiationOfInputSig<Arg, AssocFunc
329329
private class ArgSubst extends ArgFinal {
330330
Type getTypeAt(TypePath path) {
331331
result = substituteLookupTraits0(this.getEnclosingItemNode(), super.getTypeAt(path)) and
332-
not result = TNeverType() and
333-
not result = TUnknownType()
332+
not result instanceof PseudoType
334333
}
335334
}
336335

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

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,13 @@ newtype TType =
3636
TTrait(Trait t) or
3737
TImplTraitType(ImplTraitTypeRepr impl) or
3838
TDynTraitType(Trait t) { t = any(DynTraitTypeRepr dt).getTrait() } or
39-
TNeverType() or
4039
TUnknownType() or
40+
TClosureParameterPseudoType(Param p) {
41+
exists(ClosureExpr ce |
42+
p = ce.getParam(_) and
43+
not p.hasTypeRepr()
44+
)
45+
} or
4146
TTypeParamTypeParameter(TypeParam t) or
4247
TAssociatedTypeTypeParameter(Trait trait, AssocType typeAlias) {
4348
getTraitAssocType(trait) = typeAlias
@@ -326,14 +331,6 @@ TypeParamTypeParameter getSliceTypeParameter() {
326331
result = any(SliceType t).getPositionalTypeParameter(0)
327332
}
328333

329-
class NeverType extends Type, TNeverType {
330-
override TypeParameter getPositionalTypeParameter(int i) { none() }
331-
332-
override string toString() { result = "!" }
333-
334-
override Location getLocation() { result instanceof EmptyLocation }
335-
}
336-
337334
abstract class PtrType extends StructType { }
338335

339336
pragma[nomagic]
@@ -355,6 +352,10 @@ class PtrConstType extends PtrType {
355352
override string toString() { result = "*const" }
356353
}
357354

355+
abstract class PseudoType extends Type {
356+
override TypeParameter getPositionalTypeParameter(int i) { none() }
357+
}
358+
358359
/**
359360
* A special pseudo type used to indicate that the actual type may have to be
360361
* inferred by propagating type information back into call arguments.
@@ -377,14 +378,24 @@ class PtrConstType extends PtrType {
377378
* into call arguments (including method call receivers), in order to avoid
378379
* combinatorial explosions.
379380
*/
380-
class UnknownType extends Type, TUnknownType {
381-
override TypeParameter getPositionalTypeParameter(int i) { none() }
382-
383-
override string toString() { result = "(context typed)" }
381+
class UnknownType extends PseudoType, TUnknownType {
382+
override string toString() { result = "(unknown type)" }
384383

385384
override Location getLocation() { result instanceof EmptyLocation }
386385
}
387386

387+
class ClosureParameterPseudoType extends PseudoType, TClosureParameterPseudoType {
388+
private Param param;
389+
390+
ClosureParameterPseudoType() { this = TClosureParameterPseudoType(param) }
391+
392+
Param getParam() { result = param }
393+
394+
override string toString() { result = "(closure parameter " + param + ")" }
395+
396+
override Location getLocation() { result = param.getLocation() }
397+
}
398+
388399
/** A type parameter. */
389400
abstract class TypeParameter extends Type {
390401
override TypeParameter getPositionalTypeParameter(int i) { none() }

0 commit comments

Comments
 (0)