Skip to content

Commit 8c37ee9

Browse files
committed
wip
1 parent 5ff247e commit 8c37ee9

1 file changed

Lines changed: 42 additions & 21 deletions

File tree

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

Lines changed: 42 additions & 21 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 knowning 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`.
23712381
*
2372-
* 1. assign `x` the pseudo type `T_x`,
2382+
* ### Case B
2383+
*
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.
@@ -3131,47 +3148,51 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
31313148
pragma[nomagic]
31323149
private Type inferClosureParameterTypeCand(AstNode n, TypePath path) {
31333150
result = inferType(n, path) and
3134-
hasClosureParameterPseudoType(n) and
3135-
not result instanceof UnknownType
3151+
hasClosureParameterPseudoType(n)
31363152
}
31373153

31383154
private Type inferClosureParameterPseudoType(AstNode n, TypePath path) {
3139-
// The `case X` comments below refer to the cases in the QL doc for
3140-
// `ClosureParameterPseudoType`.
3155+
// The `step X` comments below refer to the steps for 'Case B' in the
3156+
// QL doc for `ClosureParameterPseudoType`.
31413157
exists(Closure c, Parameter p | p = c.getParameter(_) |
3142-
// case 1
3158+
// step 1
31433159
n = p.getPattern() and
31443160
path.isEmpty() and
31453161
not exists(p.getType()) and
31463162
result.(ClosureParameterPseudoType).getParameter() = p
31473163
or
3148-
// case 3
3164+
// step 3
31493165
hasClosureParameterPseudoType(c, p, path) and
31503166
n = c and
31513167
result instanceof UnknownType
31523168
)
31533169
or
3154-
// case 6
3170+
// step 6
31553171
exists(AstNode n0, TypePath path0 |
31563172
hasClosureParameterPseudoType(n0, path0, n, path) and
3157-
result = inferClosureParameterTypeCand(n0, path0)
3173+
result = inferClosureParameterTypeCand(n0, path0) and
3174+
not (path.isEmpty() and result instanceof UnknownType)
31583175
)
31593176
}
31603177

31613178
Type inferClosureType(AstNode n, TypePath path) {
31623179
result = inferClosureParameterPseudoType(n, path)
31633180
or
3181+
// The `step X` comments below refer to the steps for 'Case A' in the
3182+
// QL doc for `ClosureParameterPseudoType`.
31643183
exists(Closure c, Parameter p |
31653184
p = c.getParameter(_) and
31663185
not exists(p.getType())
31673186
|
3187+
// step 1
31683188
n = c and
31693189
path = getClosureParameterTypePath(p) and
31703190
result instanceof UnknownType
31713191
or
3192+
// step 3
31723193
n = p.getPattern() and
31733194
result = inferType(c, getClosureParameterTypePath(p).appendInverse(path)) and
3174-
not result instanceof UnknownType
3195+
not (path.isEmpty() and result instanceof UnknownType)
31753196
)
31763197
}
31773198
}
@@ -3194,7 +3215,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
31943215
n = decl.getPattern() and
31953216
not exists(decl.getInitializer()) and
31963217
not exists(decl.getType()) and
3197-
not n = any(Parameter p).getPattern() and
3218+
not n = any(Parameter p).getPattern() and // closure parameters are handled in `ClosureTyping`
31983219
path.isEmpty()
31993220
)
32003221
) and

0 commit comments

Comments
 (0)