Skip to content

Commit 2932804

Browse files
committed
wip
1 parent 36044c4 commit 2932804

2 files changed

Lines changed: 50 additions & 30 deletions

File tree

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ private import codeql.util.Option
55
private import rust
66
private import codeql.rust.internal.PathResolution
77
private import Type
8-
private import Type as T
98
private import TypeAbstraction
109
private import TypeAbstraction as TA
10+
private import Type as T
1111
private import TypeMention
1212
private import codeql.rust.internal.typeinference.DerefChain
1313
private import FunctionType
@@ -2156,7 +2156,7 @@ private TupleType inferArgList(ArgList args, TypePath path) {
21562156
/** Holds if `n` is implicitly dereferenced and/or borrowed. */
21572157
cached
21582158
predicate implicitDerefChainBorrow(Expr e, DerefChain derefChain, boolean borrow) {
2159-
M3::CachedStage::ref() and
2159+
CachedStage::ref() and
21602160
exists(BorrowKind bk |
21612161
any(AssocFunctionResolution::AssocFunctionCall afc)
21622162
.argumentHasImplicitDerefChainBorrow(e, derefChain, bk) and
@@ -2183,7 +2183,7 @@ predicate implicitDerefChainBorrow(Expr e, DerefChain derefChain, boolean borrow
21832183
*/
21842184
cached
21852185
Addressable resolveCallTarget(InvocationExpr call, boolean dispatch) {
2186-
M3::CachedStage::ref() and
2186+
CachedStage::ref() and
21872187
dispatch = false and
21882188
result = call.(NonAssocCallExpr).resolveCallTargetViaPathResolution()
21892189
or
@@ -2203,7 +2203,7 @@ Addressable resolveCallTarget(InvocationExpr call, boolean dispatch) {
22032203
*/
22042204
cached
22052205
StructField resolveStructFieldExpr(FieldExpr fe, DerefChain derefChain) {
2206-
M3::CachedStage::ref() and
2206+
CachedStage::ref() and
22072207
exists(string name, DataType ty |
22082208
ty = getFieldExprLookupType(fe, pragma[only_bind_into](name), derefChain)
22092209
|
@@ -2217,7 +2217,7 @@ StructField resolveStructFieldExpr(FieldExpr fe, DerefChain derefChain) {
22172217
*/
22182218
cached
22192219
TupleField resolveTupleFieldExpr(FieldExpr fe, DerefChain derefChain) {
2220-
M3::CachedStage::ref() and
2220+
CachedStage::ref() and
22212221
exists(int i |
22222222
result =
22232223
getTupleFieldExprLookupType(fe, pragma[only_bind_into](i), derefChain)
@@ -2956,6 +2956,8 @@ private module Input3 implements InputSig3 {
29562956
else prefix2.isEmpty()
29572957
)
29582958
or
2959+
// Rust closure types like `Fn<(A, B) -> C>` are syntactic sugar for `Fn<Args = (A, B), Output = C>`,
2960+
// so in calls to a closure, we consider the entire argument list as a single tuple argument.
29592961
exists(CallExprImpl::DynamicCallExpr dce, TupleType tt, int i |
29602962
n1 = dce.getSyntacticPositionalArgument(i) and
29612963
n2 = dce.getArgList() and

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

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2356,28 +2356,45 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
23562356
class Closure extends Callable, Expr;
23572357

23582358
/**
2359-
* A special pseudo type representing a particular closure parameter.
2359+
* A special pseudo type representing a particular closure parameter without
2360+
* a type annotation.
23602361
*
2361-
* This is needed in cases where the type of a closure parameter must be
2362-
* inferred from the inferred _return type_ of the closure. For example,
2363-
* in
2362+
* For such parameters, we want to infer the type based on the context in which
2363+
* the closure occurs, and while we could do this by assigning the parameter the
2364+
* pseudo type `UnknownType`, this would mean that the parameter type could also
2365+
* be inferred from _within_ the closure body, which we want to avoid.
2366+
*
2367+
* There are two ways for type information to flow contextually into a closure
2368+
* parameter: (A) either by knowing the types of arguments, or (B) by knowing the
2369+
* return type. Only case B makes use of `ClosureParameterPseudoType`s.
2370+
*
2371+
* ### Case A
23642372
*
23652373
* ```rust
23662374
* let c = |x| (x, false);
2367-
* let r: i32 = c(Default::default()).0;
2375+
* let r = c(0);
23682376
* ```
23692377
*
2370-
* We
2378+
* 1. `c` is assigned the type `Fn(UnknownType) -> ...`,
2379+
* 2. since `0` has type `i32`, we can infer the `c` has type `Fn(i32) -> ...`, and
2380+
* 3. using contextual inference, we conclude that `x` has type `i32`.
2381+
*
2382+
* ### Case B
23712383
*
2372-
* 1. assign `x` the pseudo type `T_x`,
2384+
* ```rust
2385+
* let c = |x| (x, false);
2386+
* let r: i32 = c(Default::default()).0;
2387+
* ```
2388+
*
2389+
* 1. `x` is assigned the pseudo type `T_x`,
23732390
* 2. infer that the return type of `c` is `(T_x, bool)` and hence that `c` has type
2374-
* `Fn(<missing>) -> (T_x, bool)`,
2391+
* `Fn(...) -> (T_x, bool)`,
23752392
* 3. this enables us to detect that contextual inference is needed, so we also
2376-
* assign `c` the type `Fn(<missing>) -> (UnknownType, bool)`,
2393+
* assign `c` the type `Fn(...) -> (UnknownType, bool)`,
23772394
* 4. infer that `c(Default::default()).0` must have `UnknownType`,
2378-
* 5. infer, using contextual inference, that `c` has type `Fn(<missing>) -> (i32, bool)`,
2395+
* 5. infer, using contextual inference, that `c` has type `Fn(...) -> (i32, bool)`,
23792396
* and finally
2380-
* 6. since `c` also has type `Fn(<missing>) -> (T_x, bool)`, we conclude that `x` has type
2397+
* 6. since `c` also has type `Fn(...) -> (T_x, bool)`, we conclude that `x` has type
23812398
* `i32` and hence that `c` has type `Fn(i32) -> (i32, bool)`.
23822399
*
23832400
* Note that steps 2, 4, and 5 are standard inference steps.
@@ -3037,11 +3054,8 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
30373054
// steps are reversed in contextual typing
30383055
exists(TypePath path1, AstNode n2, TypePath path2, TypePath suffix |
30393056
result = inferType(n2, path2.appendInverse(suffix)) and
3040-
path = path1.append(suffix)
3041-
|
3057+
path = path1.append(suffix) and
30423058
step(n, path1, n2, path2)
3043-
or
3044-
closureStep(n, path1, n2, path2)
30453059
)
30463060
}
30473061

@@ -3131,47 +3145,51 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
31313145
pragma[nomagic]
31323146
private Type inferClosureParameterTypeCand(AstNode n, TypePath path) {
31333147
result = inferType(n, path) and
3134-
hasClosureParameterPseudoType(n) and
3135-
not result instanceof UnknownType
3148+
hasClosureParameterPseudoType(n)
31363149
}
31373150

31383151
private Type inferClosureParameterPseudoType(AstNode n, TypePath path) {
3139-
// The `case X` comments below refer to the cases in the QL doc for
3140-
// `ClosureParameterPseudoType`.
3152+
// The `step X` comments below refer to the steps for 'Case B' in the
3153+
// QL doc for `ClosureParameterPseudoType`.
31413154
exists(Closure c, Parameter p | p = c.getParameter(_) |
3142-
// case 1
3155+
// step 1
31433156
n = p.getPattern() and
31443157
path.isEmpty() and
31453158
not exists(p.getType()) and
31463159
result.(ClosureParameterPseudoType).getParameter() = p
31473160
or
3148-
// case 3
3161+
// step 3
31493162
hasClosureParameterPseudoType(c, p, path) and
31503163
n = c and
31513164
result instanceof UnknownType
31523165
)
31533166
or
3154-
// case 6
3167+
// step 6
31553168
exists(AstNode n0, TypePath path0 |
31563169
hasClosureParameterPseudoType(n0, path0, n, path) and
3157-
result = inferClosureParameterTypeCand(n0, path0)
3170+
result = inferClosureParameterTypeCand(n0, path0) and
3171+
not (path.isEmpty() and result instanceof UnknownType)
31583172
)
31593173
}
31603174

31613175
Type inferClosureType(AstNode n, TypePath path) {
31623176
result = inferClosureParameterPseudoType(n, path)
31633177
or
3178+
// The `step X` comments below refer to the steps for 'Case A' in the
3179+
// QL doc for `ClosureParameterPseudoType`.
31643180
exists(Closure c, Parameter p |
31653181
p = c.getParameter(_) and
31663182
not exists(p.getType())
31673183
|
3184+
// step 1
31683185
n = c and
31693186
path = getClosureParameterTypePath(p) and
31703187
result instanceof UnknownType
31713188
or
3189+
// step 3
31723190
n = p.getPattern() and
31733191
result = inferType(c, getClosureParameterTypePath(p).appendInverse(path)) and
3174-
not result instanceof UnknownType
3192+
not (path.isEmpty() and result instanceof UnknownType)
31753193
)
31763194
}
31773195
}
@@ -3194,7 +3212,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
31943212
n = decl.getPattern() and
31953213
not exists(decl.getInitializer()) and
31963214
not exists(decl.getType()) and
3197-
not n = any(Parameter p).getPattern() and
3215+
not n = any(Parameter p).getPattern() and // closure parameters are handled in `ClosureTyping`
31983216
path.isEmpty()
31993217
)
32003218
) and

0 commit comments

Comments
 (0)