Skip to content

Commit ac07464

Browse files
authored
Merge pull request #22655 from hvitved/type-inference/unified-prep
Type inference: Generalize interface in preparation for Unified
2 parents d7bdf26 + 6a12dab commit ac07464

2 files changed

Lines changed: 111 additions & 23 deletions

File tree

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2917,7 +2917,9 @@ private module Input3 implements InputSig3 {
29172917
)
29182918
}
29192919

2920-
class Closure extends Expr, Callable instanceof Rust::ClosureExpr { }
2920+
class Closure extends Expr, Callable instanceof Rust::ClosureExpr {
2921+
Expr getDefiningExpr() { result = this }
2922+
}
29212923

29222924
class ClosureParameterPseudoType extends T::ClosureParameterPseudoType {
29232925
Parameter getParameter() { result = this.getParam() }

‎shared/typeinference/codeql/typeinference/internal/TypeInference.qll‎

Lines changed: 108 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,14 @@ signature module InputSig1<LocationSig Location> {
7979
* For example `int` or ``IEnumerable`1``.
8080
*/
8181
class Type {
82-
/** Gets a type parameter of this type, if any. */
82+
/** Gets the `i`th positional type parameter of this type, if any. */
83+
TypeParameter getPositionalTypeParameter(int i);
84+
85+
/**
86+
* Gets a type parameter of this type, if any.
87+
*
88+
* This may include non-positional type parameters as well.
89+
*/
8390
TypeParameter getATypeParameter();
8491

8592
/** Gets a textual representation of this type. */
@@ -2080,7 +2087,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
20802087
* item in Rust.
20812088
*/
20822089
class Variable {
2083-
/** Gets the AST node that defines this variable. */
2090+
/** Gets the AST node that defines this variable, if any. */
20842091
AstNode getDefiningNode();
20852092

20862093
/** Gets an access to this variable. */
@@ -2094,7 +2101,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
20942101
}
20952102

20962103
/** A declaration. */
2097-
class Declaration extends AstNode {
2104+
class Declaration {
20982105
/**
20992106
* Gets the type mention of the entity that contains this declaration, if any.
21002107
*
@@ -2127,6 +2134,12 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
21272134
* a function.
21282135
*/
21292136
TypeMention getType();
2137+
2138+
/** Gets a textual representation of this declaration. */
2139+
string toString();
2140+
2141+
/** Gets the location of this declaration. */
2142+
Location getLocation();
21302143
}
21312144

21322145
/**
@@ -2206,6 +2219,12 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
22062219
/** A parameter. */
22072220
class Parameter extends VariableDeclaration;
22082221

2222+
/**
2223+
* Holds if `p` is an implicit parameter declaration corresponding
2224+
* to variable `v`.
2225+
*/
2226+
default predicate implicitParameterDecl(Parameter p, Variable v) { none() }
2227+
22092228
/** A callable. This may include for example variant constructors. */
22102229
class Callable extends Declaration {
22112230
/**
@@ -2407,7 +2426,10 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
24072426
}
24082427

24092428
/** A closure/lambda expression. */
2410-
class Closure extends Callable, Expr;
2429+
class Closure extends Callable {
2430+
/** Gets the expression that defines this closure (typically the entity itself). */
2431+
Expr getDefiningExpr();
2432+
}
24112433

24122434
/**
24132435
* A special pseudo type representing a particular closure parameter without
@@ -2523,12 +2545,14 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
25232545
module Make3<InputSig3 Input3> {
25242546
private import Input3
25252547

2526-
private predicate closureStep(AstNode pattern, TypePath prefix1, Closure c, TypePath prefix2) {
2527-
exists(Parameter p |
2548+
pragma[nomagic]
2549+
private predicate closureStep(AstNode pattern, TypePath prefix1, Expr c, TypePath prefix2) {
2550+
exists(Closure c0, Parameter p |
25282551
pattern = p.getPattern() and
2529-
p = c.getParameter(_) and
2552+
p = c0.getParameter(_) and
25302553
prefix1.isEmpty() and
2531-
prefix2 = getClosureParameterTypePath(p)
2554+
prefix2 = getClosureParameterTypePath(p) and
2555+
c = c0.getDefiningExpr()
25322556
)
25332557
}
25342558

@@ -2552,10 +2576,16 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
25522576
tm = decl.getType() and
25532577
n = decl.getPattern()
25542578
)
2579+
or
2580+
exists(Parameter p, Variable v |
2581+
implicitParameterDecl(p, v) and
2582+
result = p.getType().getTypeAt(path) and
2583+
n = v.getAnAccess()
2584+
)
25552585
)
25562586
or
25572587
exists(Closure c, TypePath suffix |
2558-
n = c and
2588+
n = c.getDefiningExpr() and
25592589
result = getCallableReturnType(c, suffix) and
25602590
path = getClosureReturnTypePath(c).append(suffix)
25612591
)
@@ -2654,8 +2684,11 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
26542684
or
26552685
result = inferLogicalOperationType(n, path)
26562686
or
2657-
result = getClosureType(n) and
2658-
path.isEmpty()
2687+
exists(Closure c |
2688+
n = c.getDefiningExpr() and
2689+
result = getClosureType(c) and
2690+
path.isEmpty()
2691+
)
26592692
or
26602693
infersCertainTypeAt(n, path, result.getATypeParameter())
26612694
) and
@@ -2748,9 +2781,9 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
27482781
or
27492782
exists(Closure c |
27502783
n1 = c.getBody() and
2751-
n2 = c and
2784+
n2 = c.getDefiningExpr() and
27522785
prefix1.isEmpty() and
2753-
prefix2 = getClosureReturnTypePath(n2)
2786+
prefix2 = getClosureReturnTypePath(c)
27542787
)
27552788
}
27562789

@@ -2764,7 +2797,10 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
27642797
or
27652798
closureStep(n2, prefix2, n, prefix1) and
27662799
// prevent closure parameter pseudo types from escaping the closure
2767-
not result.(ClosureParameterPseudoType).getParameter() = n.(Closure).getParameter(_)
2800+
not exists(Closure c |
2801+
n = c.getDefiningExpr() and
2802+
result.(ClosureParameterPseudoType).getParameter() = c.getParameter(_)
2803+
)
27682804
)
27692805
}
27702806

@@ -3115,7 +3151,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
31153151
}
31163152

31173153
pragma[nomagic]
3118-
private predicate hasUnknownTypeAt(AstNode n, TypePath path) {
3154+
predicate hasUnknownTypeAt(AstNode n, TypePath path) {
31193155
inferType(n, path) instanceof UnknownType
31203156
}
31213157

@@ -3248,8 +3284,8 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
32483284
result.(ClosureParameterPseudoType).getParameter() = p
32493285
or
32503286
// step 3
3251-
hasClosureParameterPseudoType(c, path, p) and
3252-
n = c and
3287+
hasClosureParameterPseudoType(n, path, p) and
3288+
n = c.getDefiningExpr() and
32533289
result instanceof UnknownType
32543290
)
32553291
or
@@ -3266,23 +3302,64 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
32663302
or
32673303
// The `step X` comments below refer to the steps for 'Case A' in the
32683304
// QL doc for `ClosureParameterPseudoType`.
3269-
exists(Closure c, Parameter p |
3305+
exists(Closure c, Parameter p, Expr def |
32703306
p = c.getParameter(_) and
3271-
not exists(p.getType())
3307+
not exists(p.getType()) and
3308+
def = c.getDefiningExpr()
32723309
|
32733310
// step 1
3274-
n = c and
3311+
n = def and
32753312
path = getClosureParameterTypePath(p) and
32763313
result instanceof UnknownType
32773314
or
32783315
// step 3
32793316
n = p.getPattern() and
3280-
result = inferType(c, getClosureParameterTypePath(p).appendInverse(path)) and
3317+
result = inferType(def, getClosureParameterTypePath(p).appendInverse(path)) and
32813318
not (path.isEmpty() and result instanceof UnknownType)
32823319
)
32833320
}
32843321
}
32853322

3323+
/**
3324+
* Holds if `n` has unknown type at `prefix`, but is still able to
3325+
* infer a known type at `suffix` for the `i`th type parameter of whatever
3326+
* the unknown type is.
3327+
*
3328+
* For example, in
3329+
*
3330+
* ```rust
3331+
* let mut x: Unresolvable<i32> = ...;
3332+
*
3333+
* x = resolvable(...);
3334+
* ```
3335+
*
3336+
* even though the root type is unresolvable at the declaration, we are still
3337+
* able to infer that the first type argument is `i32`. We can then combine this
3338+
* information with later inferred type information.
3339+
*/
3340+
pragma[nomagic]
3341+
private predicate infersUnknownTypeArg(
3342+
AstNode n, TypePath prefix, int i, TypePath suffix, Type t
3343+
) {
3344+
exists(TypeParameter tp, TypePath suffix0 |
3345+
ContextualTyping::hasUnknownTypeAt(n, prefix) and
3346+
suffix0.isCons(tp, suffix) and
3347+
tp = any(UnknownType ut).getPositionalTypeParameter(i) and
3348+
t = inferType(n, prefix.appendInverse(suffix0)) and
3349+
not t instanceof UnknownType
3350+
)
3351+
}
3352+
3353+
pragma[nomagic]
3354+
private predicate infersKnownAndUnknownType(AstNode n, TypePath path, int i, TypeParameter tp) {
3355+
ContextualTyping::hasUnknownTypeAt(n, path) and
3356+
exists(Type t |
3357+
t = inferType(n, path) and
3358+
not t instanceof UnknownType and
3359+
tp = t.getPositionalTypeParameter(i)
3360+
)
3361+
}
3362+
32863363
/**
32873364
* Gets an inferred candidate type of `n` at `path`.
32883365
*
@@ -3314,6 +3391,12 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
33143391
result instanceof UnknownType
33153392
or
33163393
result = ContextualTyping::inferTypeContextual(n, path)
3394+
or
3395+
exists(TypePath prefix, int i, TypePath suffix, TypeParameter tp |
3396+
infersUnknownTypeArg(n, prefix, i, suffix, result) and
3397+
infersKnownAndUnknownType(n, prefix, i, tp) and
3398+
path = prefix.append(TypePath::cons(tp, suffix))
3399+
)
33173400
}
33183401

33193402
/**
@@ -3337,7 +3420,10 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
33373420
result instanceof ClosureParameterPseudoType
33383421
) and
33393422
// prevent closure parameter pseudo types from escaping from the closure
3340-
not result.(ClosureParameterPseudoType).getParameter() = n.(Closure).getParameter(_)
3423+
not exists(Closure c |
3424+
n = c.getDefiningExpr() and
3425+
result.(ClosureParameterPseudoType).getParameter() = c.getParameter(_)
3426+
)
33413427
or
33423428
// If `n` has an explicitly unknown type at `prefix` and at the same time a certain
33433429
// type at `prefix.suffix`, then extend the unknown type information to any path

0 commit comments

Comments
 (0)