diff --git a/kmir/src/kmir/kdist/mir-semantics/kmir.md b/kmir/src/kmir/kdist/mir-semantics/kmir.md index 4af928fe0..3b79e6c27 100644 --- a/kmir/src/kmir/kdist/mir-semantics/kmir.md +++ b/kmir/src/kmir/kdist/mir-semantics/kmir.md @@ -512,13 +512,51 @@ Therefore a heuristics is used here: andBool lookupTy({pointeeTy(lookupTy(tyOfLocal({LOCALS[CLOSURE]}:>TypedLocal)))}:>Ty) ==K typeInfoVoidType [priority(45), preserves-definedness] + // Closure-call setup for typed closure environments. + // When the closure pointee type is known (`typeInfoFunType`), we still need to unpack + // the second tuple argument into `_2 .. _n` locals. + rule [setupCalleeClosure3]: #setUpCalleeData( + monoItemFn(_, _, someBody(body((FIRST:BasicBlock _) #as BLOCKS, NEWLOCALS, _, _, _, _))), + operandMove(place(local(CLOSURE:Int), .ProjectionElems)) + operandMove(place(local(TUPLE), .ProjectionElems)) + .Operands, + _SPAN + ) + => + #setLocalValue(place(local(1), .ProjectionElems), #incrementRef(getValue(LOCALS, CLOSURE))) + ~> #setTupleArgs(2, getValue(LOCALS, TUPLE)) + ~> #execBlock(FIRST) + // arguments are tuple components, stored as _2 .. _n + ... + + + _ => toKList(BLOCKS) + LOCALS => #reserveFor(NEWLOCALS) + + (ListItem(CALLERFRAME => #updateStackLocal(#updateStackLocal(CALLERFRAME, TUPLE, Moved), CLOSURE, Moved))) + _:List + + ... + + requires 0 <=Int CLOSURE andBool CLOSURE TypedLocal))) + andBool isTypedValue(LOCALS[CLOSURE]) + andBool isRefType(lookupTy(tyOfLocal({LOCALS[CLOSURE]}:>TypedLocal))) + andBool isFunType(#lookupMaybeTy(pointeeTy(lookupTy(tyOfLocal({LOCALS[CLOSURE]}:>TypedLocal))))) + [priority(46), preserves-definedness] + syntax Bool ::= isTupleType ( TypeInfo ) [function, total] | isRefType ( TypeInfo ) [function, total] + | isFunType ( TypeInfo ) [function, total] // ------------------------------------------------------- rule isTupleType(typeInfoTupleType(_, _)) => true rule isTupleType( _ ) => false [owise] rule isRefType(typeInfoRefType(_)) => true rule isRefType( _ ) => false [owise] + rule isFunType(typeInfoFunType(_)) => true + rule isFunType( _ ) => false [owise] syntax KItem ::= #setTupleArgs ( Int , Value ) | #setTupleArgs ( Int , List ) @@ -532,6 +570,12 @@ Therefore a heuristics is used here: => #setLocalValue(place(local(IDX), .ProjectionElems), #incrementRef(VAL)) ~> #setTupleArgs(IDX +Int 1, REST) ... + + // Fallback for closure-call paths where the argument is not wrapped as a tuple. + rule #setTupleArgs(IDX, VAL:Value) + => #setLocalValue(place(local(IDX), .ProjectionElems), #incrementRef(VAL)) + ... + [owise] ``` diff --git a/kmir/src/kmir/kdist/mir-semantics/rt/data.md b/kmir/src/kmir/kdist/mir-semantics/rt/data.md index c093f9ec6..e4f4b0747 100644 --- a/kmir/src/kmir/kdist/mir-semantics/rt/data.md +++ b/kmir/src/kmir/kdist/mir-semantics/rt/data.md @@ -1049,6 +1049,12 @@ Literal arrays are also built using this RValue. ... + rule ARGS:List ~> #mkAggregate(aggregateKindClosure(_CLOSUREDEF, _GENERICARGS)) + => + Aggregate(variantIdx(0), ARGS) + ... + + // #readOperands accumulates a list of `TypedLocal` values from operands syntax KItem ::= #readOperands ( Operands ) diff --git a/kmir/src/tests/integration/data/prove-rs/closure-no-capture.rs b/kmir/src/tests/integration/data/prove-rs/closure-no-capture.rs new file mode 100644 index 000000000..2f7bc948b --- /dev/null +++ b/kmir/src/tests/integration/data/prove-rs/closure-no-capture.rs @@ -0,0 +1,12 @@ +fn apply u8>(f: F, v: u8) -> u8 { + f(v) +} + +fn main() { + let _ = repro(); +} + +fn repro() -> u8 { + let f = |x: u8| x + 1; + apply(f, 41u8) +}