A handler's capture is the non-escaping kind
The refusal said milestone 5, which lumped it in with escaping closures - and plan.org has just deferred those until a concrete use case appears. A handler frame does not outlive the function that pushed it, so what a handler clause needs is spec-memory.md's case 2, a non-escaping fn capturing by value into a stack environment, which is settled rather than deferred. Worth recording before anyone schedules it, because open decision #5 says in as many words that without this conditions are not worth building, and the deferral it just received does not apply to it.
This commit is contained in:
parent
5980b5b60f
commit
c322ef60bf
16
NEXT.md
16
NEXT.md
@ -923,10 +923,18 @@ Three decisions worth keeping:
|
|||||||
Which gives the two refusals, both by the house rule rather than by accident:
|
Which gives the two refusals, both by the house rule rather than by accident:
|
||||||
|
|
||||||
- **A handler cannot see the establishing function's locals.** That is a
|
- **A handler cannot see the establishing function's locals.** That is a
|
||||||
closure with an explicit environment — milestone 5's work — so a reference to
|
closure with an explicit environment, so a reference to one is refused *for
|
||||||
one is refused *for that reason* rather than reported as an unknown name.
|
that reason* rather than reported as an unknown name. Globals and the
|
||||||
Globals and the condition are in scope, which is what the accumulation case
|
condition are in scope, which is what the accumulation case needs.
|
||||||
needs.
|
|
||||||
|
What it needs is narrower than it looks, and worth getting right before
|
||||||
|
anyone schedules it: a handler frame does not outlive the function that
|
||||||
|
established it, so this is spec-memory.md's **case 2** — a non-escaping `fn`
|
||||||
|
capturing by value into a stack environment — and *not* the escaping closure
|
||||||
|
that plan.org's open decision #5 defers until a concrete use case. Case 2 is
|
||||||
|
settled, and #5 says in as many words that without it "conditions are not
|
||||||
|
worth building". So the biggest usability limit in conditions is not behind
|
||||||
|
the thing that was just deferred.
|
||||||
- **`return` inside a `handler-bind` body is refused.** The frames are popped
|
- **`return` inside a `handler-bind` body is refused.** The frames are popped
|
||||||
on the way out and an early exit would leave them on the stack pointing into
|
on the way out and an early exit would leave them on the stack pointing into
|
||||||
a function that has gone. Same shape as `defer` inside a block.
|
a function that has gone. Same shape as `defer` inside a block.
|
||||||
|
|||||||
14
lib/check.ml
14
lib/check.ml
@ -126,9 +126,11 @@ let lookup ctx name = List.assoc_opt name ctx.scope
|
|||||||
|
|
||||||
(* A handler clause is lifted into a function of its own, so the establishing
|
(* A handler clause is lifted into a function of its own, so the establishing
|
||||||
function's locals are simply not there. Capturing them is a closure with an
|
function's locals are simply not there. Capturing them is a closure with an
|
||||||
explicit environment — milestone 5's work — and until it exists a reference
|
explicit environment — spec-memory.md's case 2, a non-escaping [fn] capturing
|
||||||
to one is refused for the reason it is really refused for, rather than as a
|
by value into a stack environment, since a handler frame does not outlive the
|
||||||
name nobody has heard of. *)
|
function that pushed it — and until that exists a reference to one is refused
|
||||||
|
for the reason it is really refused for, rather than as a name nobody has
|
||||||
|
heard of. *)
|
||||||
let captured ctx loc name =
|
let captured ctx loc name =
|
||||||
if ctx.in_handler && List.mem_assoc name ctx.outer then
|
if ctx.in_handler && List.mem_assoc name ctx.outer then
|
||||||
raise
|
raise
|
||||||
@ -539,9 +541,9 @@ and block ctx ?want loc body =
|
|||||||
function of its own and reached through a pointer.
|
function of its own and reached through a pointer.
|
||||||
|
|
||||||
Which means it cannot see the establishing function's locals. Capturing them
|
Which means it cannot see the establishing function's locals. Capturing them
|
||||||
is a closure with an explicit environment, which is real work and is
|
is a closure with an explicit environment — the non-escaping kind, captured
|
||||||
milestone 5's; until then a reference to one is rejected by name rather than
|
by value onto this frame — and until that exists a reference to one is
|
||||||
silently resolving to something else. Globals and the condition itself are
|
rejected by name rather than silently resolving to something else. Globals and the condition itself are
|
||||||
in scope, which is enough for the accumulation case §1 is about.
|
in scope, which is enough for the accumulation case §1 is about.
|
||||||
|
|
||||||
The body may not [return] either. The frames are pushed and popped around
|
The body may not [return] either. The frames are pushed and popped around
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user