Rust: Add type inference for closures and calls to first-class functions

This commit is contained in:
Simon Friis Vindum
2025-07-27 21:28:10 +02:00
parent 8c6c28d61f
commit 2c758a9842
5 changed files with 341 additions and 14 deletions

View File

@@ -140,6 +140,26 @@ class FutureTrait extends Trait {
}
}
/**
* The [`FnOnce` trait][1].
*
* [1]: https://doc.rust-lang.org/std/ops/trait.FnOnce.html
*/
class FnOnceTrait extends Trait {
pragma[nomagic]
FnOnceTrait() { this.getCanonicalPath() = "core::ops::function::FnOnce" }
/** Gets the type parameter of this trait. */
TypeParam getTypeParam() { result = this.getGenericParamList().getGenericParam(0) }
/** Gets the `Output` associated type. */
pragma[nomagic]
TypeAlias getOutputType() {
result = this.getAssocItemList().getAnAssocItem() and
result.getName().getText() = "Output"
}
}
/**
* The [`Iterator` trait][1].
*

View File

@@ -383,6 +383,17 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat
prefix2.isEmpty() and
s = getRangeType(n1)
)
or
exists(ClosureExpr ce, int index |
n1 = ce and
n2 = ce.getParam(index).getPat() and
prefix1 = closureParameterPath(ce.getNumberOfParams(), index) and
prefix2.isEmpty()
)
or
n1.(ClosureExpr).getBody() = n2 and
prefix1 = closureReturnPath() and
prefix2.isEmpty()
}
pragma[nomagic]
@@ -1435,6 +1446,120 @@ private Type inferForLoopExprType(AstNode n, TypePath path) {
)
}
/**
* An invoked expression, the target of a call that is either a local variable
* or a non-path expression. This means that the expression denotes a
* first-class function.
*/
final private class InvokedClosureExpr extends Expr {
private CallExpr call;
InvokedClosureExpr() {
call.getFunction() = this and
(not this instanceof PathExpr or this = any(Variable v).getAnAccess())
}
Type getTypeAt(TypePath path) { result = inferType(this, path) }
CallExpr getCall() { result = call }
}
private module InvokedClosureSatisfiesConstraintInput implements
SatisfiesConstraintInputSig<InvokedClosureExpr>
{
predicate relevantConstraint(InvokedClosureExpr term, Type constraint) {
exists(term) and
constraint.(TraitType).getTrait() instanceof FnOnceTrait
}
}
/** Gets the type of `ce` when viewed as an implementation of `FnOnce`. */
private Type invokedClosureFnTypeAt(InvokedClosureExpr ce, TypePath path) {
SatisfiesConstraint<InvokedClosureExpr, InvokedClosureSatisfiesConstraintInput>::satisfiesConstraintType(ce,
_, path, result)
}
/** Gets the path to a closure's return type. */
private TypePath closureReturnPath() {
result = TypePath::singleton(TDynTraitTypeParameter(any(FnOnceTrait t).getOutputType()))
}
/** Gets the path to a closure with arity `arity`s `index`th parameter type. */
private TypePath closureParameterPath(int arity, int index) {
result =
TypePath::cons(TDynTraitTypeParameter(any(FnOnceTrait t).getTypeParam()),
TypePath::singleton(TTupleTypeParameter(arity, index)))
}
/** Gets the path to the return type of the `FnOnce` trait. */
private TypePath fnReturnPath() {
result = TypePath::singleton(TAssociatedTypeTypeParameter(any(FnOnceTrait t).getOutputType()))
}
/**
* Gets the path to the parameter type of the `FnOnce` trait with arity `arity`
* and index `index`.
*/
private TypePath fnParameterPath(int arity, int index) {
result =
TypePath::cons(TTypeParamTypeParameter(any(FnOnceTrait t).getTypeParam()),
TypePath::singleton(TTupleTypeParameter(arity, index)))
}
pragma[nomagic]
private Type inferDynamicCallExprType(Expr n, TypePath path) {
exists(InvokedClosureExpr ce |
// Propagate the function's return type to the call expression
exists(TypePath path0 | result = invokedClosureFnTypeAt(ce, path0) |
n = ce.getCall() and
path = path0.stripPrefix(fnReturnPath())
or
// Propagate the function's parameter type to the arguments
exists(int index |
n = ce.getCall().getArgList().getArg(index) and
path = path0.stripPrefix(fnParameterPath(ce.getCall().getNumberOfArgs(), index))
)
)
or
// _If_ the invoked expression has the type of a closure, then we propagate
// the surrounding types into the closure.
exists(int arity, TypePath path0 |
ce.getTypeAt(TypePath::nil()).(DynTraitType).getTrait() instanceof FnOnceTrait
|
// Propagate the type of arguments to the parameter types of closure
exists(int index |
n = ce and
arity = ce.getCall().getNumberOfArgs() and
result = inferType(ce.getCall().getArg(index), path0) and
path = closureParameterPath(arity, index).append(path0)
)
or
// Propagate the type of the call expression to the return type of the closure
n = ce and
arity = ce.getCall().getNumberOfArgs() and
result = inferType(ce.getCall(), path0) and
path = closureReturnPath().append(path0)
)
)
}
pragma[nomagic]
private Type inferClosureExprType(AstNode n, TypePath path) {
exists(ClosureExpr ce |
n = ce and
path.isEmpty() and
result = TDynTraitType(any(FnOnceTrait t))
or
n = ce and
path = TypePath::singleton(TDynTraitTypeParameter(any(FnOnceTrait t).getTypeParam())) and
result = TTuple(ce.getNumberOfParams())
or
// Propagate return type annotation to body
n = ce.getBody() and
result = ce.getRetType().getTypeRepr().(TypeMention).resolveTypeAt(path)
)
}
pragma[nomagic]
private Type inferCastExprType(CastExpr ce, TypePath path) {
result = ce.getTypeRepr().(TypeMention).resolveTypeAt(path)
@@ -2062,6 +2187,10 @@ private module Cached {
or
result = inferForLoopExprType(n, path)
or
result = inferDynamicCallExprType(n, path)
or
result = inferClosureExprType(n, path)
or
result = inferCastExprType(n, path)
or
result = inferStructPatType(n, path)

View File

@@ -1,6 +1,7 @@
/** Provides classes for representing type mentions, used in type inference. */
private import rust
private import codeql.rust.frameworks.stdlib.Stdlib
private import Type
private import PathResolution
private import TypeInference
@@ -26,6 +27,18 @@ class TupleTypeReprMention extends TypeMention instanceof TupleTypeRepr {
}
}
class ParenthesizedArgListMention extends TypeMention instanceof ParenthesizedArgList {
override Type resolveTypeAt(TypePath path) {
path.isEmpty() and
result = TTuple(super.getNumberOfTypeArgs())
or
exists(TypePath suffix, int index |
result = super.getTypeArg(index).getTypeRepr().(TypeMention).resolveTypeAt(suffix) and
path = TypePath::cons(TTupleTypeParameter(super.getNumberOfTypeArgs(), index), suffix)
)
}
}
class ArrayTypeReprMention extends TypeMention instanceof ArrayTypeRepr {
override Type resolveTypeAt(TypePath path) {
path.isEmpty() and
@@ -215,6 +228,17 @@ class NonAliasPathTypeMention extends PathTypeMention {
.(TraitItemNode)
.getAssocItem(pragma[only_bind_into](name)))
)
or
// Handle the special syntactic sugar for function traits. For now we only
// support `FnOnce` as we can't support the "inherited" associated types of
// `Fn` and `FnMut` yet.
exists(FnOnceTrait t | t = resolved |
tp = TTypeParamTypeParameter(t.getTypeParam()) and
result = this.getSegment().getParenthesizedArgList()
or
tp = TAssociatedTypeTypeParameter(t.getOutputType()) and
result = this.getSegment().getRetType().getTypeRepr()
)
}
Type resolveRootType() {

View File

@@ -6,38 +6,38 @@ mod simple_closures {
let my_closure = |a, b| a && b;
let x: i64 = 1i64; // $ type=x:i64
let add_one = |n| n + 1i64; // $ MISSING: target=add
let _y = add_one(x); // $ MISSING: type=y:i64
let add_one = |n| n + 1i64; // $ target=add
let _y = add_one(x); // $ type=_y:i64
// The type of `x` is inferred from the closure's argument type.
let x = Default::default(); // $ MISSING: type=x:i64 target=default
let x = Default::default(); // $ type=x:i64 target=default
let add_zero = |n: i64| n;
let _y = add_zero(x); // $ MISSING: type=_y:i64
let _y = add_zero(x); // $ type=_y:i64
let _get_bool = || -> bool {
// The return type annotation on the closure lets us infer the type of `b`.
let b = Default::default(); // $ MISSING: type=b:bool target=default
let b = Default::default(); // $ type=b:bool target=default
b
};
// The parameter type of `id` is inferred from the argument.
let id = |b| b; // $ MISSING: type=x:bool
let _b = id(true); // $ MISSING: type=_b:bool
let id = |b| b; // $ type=b:bool
let _b = id(true); // $ type=_b:bool
// The return type of `id2` is inferred from the type of the call expression.
let id2 = |b| b;
let arg = Default::default(); // $ MISSING: target=default type=arg:bool
let _b2: bool = id2(arg); // $ MISSING: type=_b:bool
let arg = Default::default(); // $ target=default type=arg:bool
let _b2: bool = id2(arg); // $ type=_b2:bool
}
}
mod fn_once_trait {
fn return_type<F: FnOnce(bool) -> i64>(f: F) {
let _return = f(true); // $ MISSING: type=_return:i64
let _return = f(true); // $ type=_return:i64
}
fn argument_type<F: FnOnce(bool) -> i64>(f: F) {
let arg = Default::default(); // $ MISSING: type=arg:bool target=default
let arg = Default::default(); // $ target=default type=arg:bool
f(arg);
}
@@ -57,7 +57,7 @@ mod fn_once_trait {
0
}
};
let _r = apply(f, true); // $ target=apply MISSING: type=_r:i64
let _r = apply(f, true); // $ target=apply type=_r:i64
let f = |x| x + 1; // $ MISSING: type=x:i64 target=add
let _r2 = apply_two(f); // $ target=apply_two type=_r2:i64
@@ -70,7 +70,7 @@ mod dyn_fn_once {
}
fn apply_boxed_dyn<A, B>(f: Box<dyn FnOnce(A) -> B>, arg: A) {
let _r1 = apply_boxed(f, arg); // $ target=apply_boxed MISSING: type=_r1:B
let _r2 = apply_boxed(Box::new(|_: i64| true), 3); // $ target=apply_boxed target=new MISSING: type=_r2:bool
let _r1 = apply_boxed(f, arg); // $ target=apply_boxed type=_r1:B
let _r2 = apply_boxed(Box::new(|_: i64| true), 3); // $ target=apply_boxed target=new type=_r2:bool
}
}

View File

@@ -1,4 +1,14 @@
inferType
| closure.rs:6:13:6:22 | my_closure | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:6:13:6:22 | my_closure | dyn(Args) | file://:0:0:0:0 | (T_2) |
| closure.rs:6:13:6:22 | my_closure | dyn(Args).0(2) | {EXTERNAL LOCATION} | bool |
| closure.rs:6:13:6:22 | my_closure | dyn(Args).1(2) | {EXTERNAL LOCATION} | bool |
| closure.rs:6:13:6:22 | my_closure | dyn(Output) | {EXTERNAL LOCATION} | bool |
| closure.rs:6:26:6:38 | \|...\| ... | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:6:26:6:38 | \|...\| ... | dyn(Args) | file://:0:0:0:0 | (T_2) |
| closure.rs:6:26:6:38 | \|...\| ... | dyn(Args).0(2) | {EXTERNAL LOCATION} | bool |
| closure.rs:6:26:6:38 | \|...\| ... | dyn(Args).1(2) | {EXTERNAL LOCATION} | bool |
| closure.rs:6:26:6:38 | \|...\| ... | dyn(Output) | {EXTERNAL LOCATION} | bool |
| closure.rs:6:27:6:27 | a | | {EXTERNAL LOCATION} | bool |
| closure.rs:6:30:6:30 | b | | {EXTERNAL LOCATION} | bool |
| closure.rs:6:33:6:33 | a | | {EXTERNAL LOCATION} | bool |
@@ -6,18 +16,101 @@ inferType
| closure.rs:6:38:6:38 | b | | {EXTERNAL LOCATION} | bool |
| closure.rs:8:13:8:13 | x | | {EXTERNAL LOCATION} | i64 |
| closure.rs:8:22:8:25 | 1i64 | | {EXTERNAL LOCATION} | i64 |
| closure.rs:9:13:9:19 | add_one | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:9:13:9:19 | add_one | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:9:13:9:19 | add_one | dyn(Args).0(1) | {EXTERNAL LOCATION} | i64 |
| closure.rs:9:13:9:19 | add_one | dyn(Output) | {EXTERNAL LOCATION} | i64 |
| closure.rs:9:23:9:34 | \|...\| ... | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:9:23:9:34 | \|...\| ... | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:9:23:9:34 | \|...\| ... | dyn(Args).0(1) | {EXTERNAL LOCATION} | i64 |
| closure.rs:9:23:9:34 | \|...\| ... | dyn(Output) | {EXTERNAL LOCATION} | i64 |
| closure.rs:9:24:9:24 | n | | {EXTERNAL LOCATION} | i64 |
| closure.rs:9:27:9:27 | n | | {EXTERNAL LOCATION} | i64 |
| closure.rs:9:27:9:34 | ... + ... | | {EXTERNAL LOCATION} | i64 |
| closure.rs:9:31:9:34 | 1i64 | | {EXTERNAL LOCATION} | i64 |
| closure.rs:10:13:10:14 | _y | | {EXTERNAL LOCATION} | i64 |
| closure.rs:10:18:10:24 | add_one | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:10:18:10:24 | add_one | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:10:18:10:24 | add_one | dyn(Args).0(1) | {EXTERNAL LOCATION} | i64 |
| closure.rs:10:18:10:24 | add_one | dyn(Output) | {EXTERNAL LOCATION} | i64 |
| closure.rs:10:18:10:27 | add_one(...) | | {EXTERNAL LOCATION} | i64 |
| closure.rs:10:26:10:26 | x | | {EXTERNAL LOCATION} | i64 |
| closure.rs:13:13:13:13 | x | | {EXTERNAL LOCATION} | i64 |
| closure.rs:13:17:13:34 | ...::default(...) | | {EXTERNAL LOCATION} | i64 |
| closure.rs:14:13:14:20 | add_zero | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:14:13:14:20 | add_zero | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:14:13:14:20 | add_zero | dyn(Args).0(1) | {EXTERNAL LOCATION} | i64 |
| closure.rs:14:13:14:20 | add_zero | dyn(Output) | {EXTERNAL LOCATION} | i64 |
| closure.rs:14:24:14:33 | \|...\| n | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:14:24:14:33 | \|...\| n | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:14:24:14:33 | \|...\| n | dyn(Args).0(1) | {EXTERNAL LOCATION} | i64 |
| closure.rs:14:24:14:33 | \|...\| n | dyn(Output) | {EXTERNAL LOCATION} | i64 |
| closure.rs:14:25:14:25 | n | | {EXTERNAL LOCATION} | i64 |
| closure.rs:14:33:14:33 | n | | {EXTERNAL LOCATION} | i64 |
| closure.rs:15:13:15:14 | _y | | {EXTERNAL LOCATION} | i64 |
| closure.rs:15:18:15:25 | add_zero | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:15:18:15:25 | add_zero | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:15:18:15:25 | add_zero | dyn(Args).0(1) | {EXTERNAL LOCATION} | i64 |
| closure.rs:15:18:15:25 | add_zero | dyn(Output) | {EXTERNAL LOCATION} | i64 |
| closure.rs:15:18:15:28 | add_zero(...) | | {EXTERNAL LOCATION} | i64 |
| closure.rs:15:27:15:27 | x | | {EXTERNAL LOCATION} | i64 |
| closure.rs:17:13:17:21 | _get_bool | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:17:13:17:21 | _get_bool | dyn(Args) | file://:0:0:0:0 | () |
| closure.rs:17:13:17:21 | _get_bool | dyn(Output) | {EXTERNAL LOCATION} | bool |
| closure.rs:17:25:21:9 | \|...\| ... | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:17:25:21:9 | \|...\| ... | dyn(Args) | file://:0:0:0:0 | () |
| closure.rs:17:25:21:9 | \|...\| ... | dyn(Output) | {EXTERNAL LOCATION} | bool |
| closure.rs:17:36:21:9 | { ... } | | {EXTERNAL LOCATION} | bool |
| closure.rs:19:17:19:17 | b | | {EXTERNAL LOCATION} | bool |
| closure.rs:19:21:19:38 | ...::default(...) | | {EXTERNAL LOCATION} | bool |
| closure.rs:20:13:20:13 | b | | {EXTERNAL LOCATION} | bool |
| closure.rs:24:13:24:14 | id | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:24:13:24:14 | id | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:24:13:24:14 | id | dyn(Args).0(1) | {EXTERNAL LOCATION} | bool |
| closure.rs:24:13:24:14 | id | dyn(Output) | {EXTERNAL LOCATION} | bool |
| closure.rs:24:18:24:22 | \|...\| b | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:24:18:24:22 | \|...\| b | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:24:18:24:22 | \|...\| b | dyn(Args).0(1) | {EXTERNAL LOCATION} | bool |
| closure.rs:24:18:24:22 | \|...\| b | dyn(Output) | {EXTERNAL LOCATION} | bool |
| closure.rs:24:19:24:19 | b | | {EXTERNAL LOCATION} | bool |
| closure.rs:24:22:24:22 | b | | {EXTERNAL LOCATION} | bool |
| closure.rs:25:13:25:14 | _b | | {EXTERNAL LOCATION} | bool |
| closure.rs:25:18:25:19 | id | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:25:18:25:19 | id | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:25:18:25:19 | id | dyn(Args).0(1) | {EXTERNAL LOCATION} | bool |
| closure.rs:25:18:25:19 | id | dyn(Output) | {EXTERNAL LOCATION} | bool |
| closure.rs:25:18:25:25 | id(...) | | {EXTERNAL LOCATION} | bool |
| closure.rs:25:21:25:24 | true | | {EXTERNAL LOCATION} | bool |
| closure.rs:28:13:28:15 | id2 | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:28:13:28:15 | id2 | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:28:13:28:15 | id2 | dyn(Args).0(1) | {EXTERNAL LOCATION} | bool |
| closure.rs:28:13:28:15 | id2 | dyn(Output) | {EXTERNAL LOCATION} | bool |
| closure.rs:28:19:28:23 | \|...\| b | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:28:19:28:23 | \|...\| b | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:28:19:28:23 | \|...\| b | dyn(Args).0(1) | {EXTERNAL LOCATION} | bool |
| closure.rs:28:19:28:23 | \|...\| b | dyn(Output) | {EXTERNAL LOCATION} | bool |
| closure.rs:28:20:28:20 | b | | {EXTERNAL LOCATION} | bool |
| closure.rs:28:23:28:23 | b | | {EXTERNAL LOCATION} | bool |
| closure.rs:29:13:29:15 | arg | | {EXTERNAL LOCATION} | bool |
| closure.rs:29:19:29:36 | ...::default(...) | | {EXTERNAL LOCATION} | bool |
| closure.rs:30:13:30:15 | _b2 | | {EXTERNAL LOCATION} | bool |
| closure.rs:30:25:30:27 | id2 | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:30:25:30:27 | id2 | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:30:25:30:27 | id2 | dyn(Args).0(1) | {EXTERNAL LOCATION} | bool |
| closure.rs:30:25:30:27 | id2 | dyn(Output) | {EXTERNAL LOCATION} | bool |
| closure.rs:30:25:30:32 | id2(...) | | {EXTERNAL LOCATION} | bool |
| closure.rs:30:29:30:31 | arg | | {EXTERNAL LOCATION} | bool |
| closure.rs:35:44:35:44 | f | | closure.rs:35:20:35:41 | F |
| closure.rs:36:13:36:19 | _return | | {EXTERNAL LOCATION} | i64 |
| closure.rs:36:23:36:23 | f | | closure.rs:35:20:35:41 | F |
| closure.rs:36:23:36:29 | f(...) | | {EXTERNAL LOCATION} | i64 |
| closure.rs:36:25:36:28 | true | | {EXTERNAL LOCATION} | bool |
| closure.rs:39:46:39:46 | f | | closure.rs:39:22:39:43 | F |
| closure.rs:40:13:40:15 | arg | | {EXTERNAL LOCATION} | bool |
| closure.rs:40:19:40:36 | ...::default(...) | | {EXTERNAL LOCATION} | bool |
| closure.rs:41:9:41:9 | f | | closure.rs:39:22:39:43 | F |
| closure.rs:41:9:41:14 | f(...) | | {EXTERNAL LOCATION} | i64 |
| closure.rs:41:11:41:13 | arg | | {EXTERNAL LOCATION} | bool |
| closure.rs:44:39:44:39 | f | | closure.rs:44:20:44:36 | F |
| closure.rs:44:45:44:45 | a | | closure.rs:44:14:44:14 | A |
| closure.rs:44:56:46:5 | { ... } | | closure.rs:44:17:44:17 | B |
@@ -29,18 +122,50 @@ inferType
| closure.rs:49:9:49:9 | f | | closure.rs:48:21:48:43 | ImplTraitTypeRepr |
| closure.rs:49:9:49:12 | f(...) | | {EXTERNAL LOCATION} | i64 |
| closure.rs:49:11:49:11 | 2 | | {EXTERNAL LOCATION} | i32 |
| closure.rs:49:11:49:11 | 2 | | {EXTERNAL LOCATION} | i64 |
| closure.rs:53:13:53:13 | f | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:53:13:53:13 | f | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:53:13:53:13 | f | dyn(Args).0(1) | {EXTERNAL LOCATION} | bool |
| closure.rs:53:13:53:13 | f | dyn(Output) | {EXTERNAL LOCATION} | i32 |
| closure.rs:53:13:53:13 | f | dyn(Output) | {EXTERNAL LOCATION} | i64 |
| closure.rs:53:17:59:9 | \|...\| ... | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:53:17:59:9 | \|...\| ... | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:53:17:59:9 | \|...\| ... | dyn(Args).0(1) | {EXTERNAL LOCATION} | bool |
| closure.rs:53:17:59:9 | \|...\| ... | dyn(Output) | {EXTERNAL LOCATION} | i32 |
| closure.rs:53:17:59:9 | \|...\| ... | dyn(Output) | {EXTERNAL LOCATION} | i64 |
| closure.rs:53:18:53:18 | x | | {EXTERNAL LOCATION} | bool |
| closure.rs:53:34:59:9 | { ... } | | {EXTERNAL LOCATION} | i32 |
| closure.rs:53:34:59:9 | { ... } | | {EXTERNAL LOCATION} | i64 |
| closure.rs:54:13:58:13 | if x {...} else {...} | | {EXTERNAL LOCATION} | i32 |
| closure.rs:54:13:58:13 | if x {...} else {...} | | {EXTERNAL LOCATION} | i64 |
| closure.rs:54:16:54:16 | x | | {EXTERNAL LOCATION} | bool |
| closure.rs:54:18:56:13 | { ... } | | {EXTERNAL LOCATION} | i32 |
| closure.rs:54:18:56:13 | { ... } | | {EXTERNAL LOCATION} | i64 |
| closure.rs:55:17:55:17 | 1 | | {EXTERNAL LOCATION} | i32 |
| closure.rs:55:17:55:17 | 1 | | {EXTERNAL LOCATION} | i64 |
| closure.rs:56:20:58:13 | { ... } | | {EXTERNAL LOCATION} | i32 |
| closure.rs:56:20:58:13 | { ... } | | {EXTERNAL LOCATION} | i64 |
| closure.rs:57:17:57:17 | 0 | | {EXTERNAL LOCATION} | i32 |
| closure.rs:57:17:57:17 | 0 | | {EXTERNAL LOCATION} | i64 |
| closure.rs:60:13:60:14 | _r | | {EXTERNAL LOCATION} | i32 |
| closure.rs:60:13:60:14 | _r | | {EXTERNAL LOCATION} | i64 |
| closure.rs:60:18:60:31 | apply(...) | | {EXTERNAL LOCATION} | i32 |
| closure.rs:60:18:60:31 | apply(...) | | {EXTERNAL LOCATION} | i64 |
| closure.rs:60:24:60:24 | f | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:60:24:60:24 | f | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:60:24:60:24 | f | dyn(Args).0(1) | {EXTERNAL LOCATION} | bool |
| closure.rs:60:24:60:24 | f | dyn(Output) | {EXTERNAL LOCATION} | i32 |
| closure.rs:60:24:60:24 | f | dyn(Output) | {EXTERNAL LOCATION} | i64 |
| closure.rs:60:27:60:30 | true | | {EXTERNAL LOCATION} | bool |
| closure.rs:62:13:62:13 | f | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:62:13:62:13 | f | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:62:17:62:25 | \|...\| ... | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:62:17:62:25 | \|...\| ... | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:62:25:62:25 | 1 | | {EXTERNAL LOCATION} | i32 |
| closure.rs:63:13:63:15 | _r2 | | {EXTERNAL LOCATION} | i64 |
| closure.rs:63:19:63:30 | apply_two(...) | | {EXTERNAL LOCATION} | i64 |
| closure.rs:63:29:63:29 | f | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:63:29:63:29 | f | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:68:54:68:54 | f | | {EXTERNAL LOCATION} | Box |
| closure.rs:68:54:68:54 | f | A | {EXTERNAL LOCATION} | Global |
| closure.rs:68:54:68:54 | f | T | closure.rs:68:26:68:51 | F |
@@ -54,16 +179,35 @@ inferType
| closure.rs:72:30:72:30 | f | | {EXTERNAL LOCATION} | Box |
| closure.rs:72:30:72:30 | f | A | {EXTERNAL LOCATION} | Global |
| closure.rs:72:30:72:30 | f | T | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:72:30:72:30 | f | T.dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:72:30:72:30 | f | T.dyn(Args).0(1) | closure.rs:72:24:72:24 | A |
| closure.rs:72:30:72:30 | f | T.dyn(Output) | closure.rs:72:27:72:27 | B |
| closure.rs:72:58:72:60 | arg | | closure.rs:72:24:72:24 | A |
| closure.rs:73:13:73:15 | _r1 | | closure.rs:72:27:72:27 | B |
| closure.rs:73:19:73:37 | apply_boxed(...) | | closure.rs:72:27:72:27 | B |
| closure.rs:73:31:73:31 | f | | {EXTERNAL LOCATION} | Box |
| closure.rs:73:31:73:31 | f | A | {EXTERNAL LOCATION} | Global |
| closure.rs:73:31:73:31 | f | T | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:73:31:73:31 | f | T.dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:73:31:73:31 | f | T.dyn(Args).0(1) | closure.rs:72:24:72:24 | A |
| closure.rs:73:31:73:31 | f | T.dyn(Output) | closure.rs:72:27:72:27 | B |
| closure.rs:73:34:73:36 | arg | | closure.rs:72:24:72:24 | A |
| closure.rs:74:13:74:15 | _r2 | | {EXTERNAL LOCATION} | bool |
| closure.rs:74:19:74:57 | apply_boxed(...) | | {EXTERNAL LOCATION} | bool |
| closure.rs:74:31:74:53 | ...::new(...) | | {EXTERNAL LOCATION} | Box |
| closure.rs:74:31:74:53 | ...::new(...) | A | {EXTERNAL LOCATION} | Global |
| closure.rs:74:31:74:53 | ...::new(...) | T | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:74:31:74:53 | ...::new(...) | T.dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:74:31:74:53 | ...::new(...) | T.dyn(Args).0(1) | {EXTERNAL LOCATION} | i64 |
| closure.rs:74:31:74:53 | ...::new(...) | T.dyn(Output) | {EXTERNAL LOCATION} | bool |
| closure.rs:74:40:74:52 | \|...\| true | | {EXTERNAL LOCATION} | dyn FnOnce |
| closure.rs:74:40:74:52 | \|...\| true | dyn(Args) | file://:0:0:0:0 | (T_1) |
| closure.rs:74:40:74:52 | \|...\| true | dyn(Args).0(1) | {EXTERNAL LOCATION} | i64 |
| closure.rs:74:40:74:52 | \|...\| true | dyn(Output) | {EXTERNAL LOCATION} | bool |
| closure.rs:74:41:74:41 | _ | | {EXTERNAL LOCATION} | i64 |
| closure.rs:74:49:74:52 | true | | {EXTERNAL LOCATION} | bool |
| closure.rs:74:56:74:56 | 3 | | {EXTERNAL LOCATION} | i32 |
| closure.rs:74:56:74:56 | 3 | | {EXTERNAL LOCATION} | i64 |
| dereference.rs:12:14:12:18 | SelfParam | | file://:0:0:0:0 | & |
| dereference.rs:12:14:12:18 | SelfParam | &T | dereference.rs:4:1:6:1 | MyIntPointer |
| dereference.rs:12:29:14:5 | { ... } | | file://:0:0:0:0 | & |
@@ -2609,6 +2753,8 @@ inferType
| main.rs:1433:17:1433:18 | TryExpr | | {EXTERNAL LOCATION} | Result |
| main.rs:1433:17:1433:18 | TryExpr | T | main.rs:1407:5:1408:14 | S1 |
| main.rs:1433:17:1433:29 | ... .map(...) | | {EXTERNAL LOCATION} | Result |
| main.rs:1433:24:1433:28 | \|...\| s | | {EXTERNAL LOCATION} | dyn FnOnce |
| main.rs:1433:24:1433:28 | \|...\| s | dyn(Args) | file://:0:0:0:0 | (T_1) |
| main.rs:1434:9:1434:22 | ...::Ok(...) | | {EXTERNAL LOCATION} | Result |
| main.rs:1434:9:1434:22 | ...::Ok(...) | E | main.rs:1410:5:1411:14 | S2 |
| main.rs:1434:9:1434:22 | ...::Ok(...) | T | main.rs:1407:5:1408:14 | S1 |
@@ -2625,9 +2771,15 @@ inferType
| main.rs:1440:21:1440:25 | input | T | main.rs:1439:20:1439:27 | T |
| main.rs:1440:21:1440:26 | TryExpr | | main.rs:1439:20:1439:27 | T |
| main.rs:1441:22:1441:38 | ...::Ok(...) | | {EXTERNAL LOCATION} | Result |
| main.rs:1441:22:1441:38 | ...::Ok(...) | E | main.rs:1407:5:1408:14 | S1 |
| main.rs:1441:22:1441:38 | ...::Ok(...) | T | main.rs:1439:20:1439:27 | T |
| main.rs:1441:22:1444:10 | ... .and_then(...) | | {EXTERNAL LOCATION} | Result |
| main.rs:1441:22:1444:10 | ... .and_then(...) | E | main.rs:1407:5:1408:14 | S1 |
| main.rs:1441:33:1441:37 | value | | main.rs:1439:20:1439:27 | T |
| main.rs:1441:49:1444:9 | \|...\| ... | | {EXTERNAL LOCATION} | dyn FnOnce |
| main.rs:1441:49:1444:9 | \|...\| ... | dyn(Args) | file://:0:0:0:0 | (T_1) |
| main.rs:1441:49:1444:9 | \|...\| ... | dyn(Output) | {EXTERNAL LOCATION} | Result |
| main.rs:1441:49:1444:9 | \|...\| ... | dyn(Output).E | main.rs:1407:5:1408:14 | S1 |
| main.rs:1441:53:1444:9 | { ... } | | {EXTERNAL LOCATION} | Result |
| main.rs:1441:53:1444:9 | { ... } | E | main.rs:1407:5:1408:14 | S1 |
| main.rs:1442:22:1442:27 | "{:?}\\n" | | file://:0:0:0:0 | & |
@@ -3874,6 +4026,8 @@ inferType
| main.rs:2231:19:2231:19 | 1 | | {EXTERNAL LOCATION} | i32 |
| main.rs:2231:22:2231:22 | 2 | | {EXTERNAL LOCATION} | i32 |
| main.rs:2231:25:2231:25 | 3 | | {EXTERNAL LOCATION} | i32 |
| main.rs:2231:32:2231:40 | \|...\| ... | | {EXTERNAL LOCATION} | dyn FnOnce |
| main.rs:2231:32:2231:40 | \|...\| ... | dyn(Args) | file://:0:0:0:0 | (T_1) |
| main.rs:2231:40:2231:40 | 1 | | {EXTERNAL LOCATION} | i32 |
| main.rs:2232:13:2232:13 | i | | {EXTERNAL LOCATION} | Item |
| main.rs:2232:13:2232:13 | i | | {EXTERNAL LOCATION} | i32 |