A name finds one frame; it does not search for one that fits
§4 meets §3, and the answer a reader will assume is the other one. An inner (use-value [s string] ...) shadows an outer (use-value [v i32] ...), so an i32 is refused there and the outer clause that would have taken it is never consulted. Searching outward for a frame whose signature fits would make which restart runs depend on the arguments, which is overload resolution on a dynamic stack. Also: neither of the new guards is a bounds check, so --no-bounds-checks does not remove them. A wrong index is a wrong answer; a transfer into a clause whose parameters were written to a different layout is not.
This commit is contained in:
parent
5184d732c9
commit
7c1fcbff19
11
BUILT.md
11
BUILT.md
@ -1163,6 +1163,17 @@ unfilled, `invoke-restart` marks it filled, and a clause with parameters checks
|
||||
top of `NEXT.md`: the answer is a Flan expression, and there is already something that compiles one against the live
|
||||
program.
|
||||
|
||||
**Lookup stayed by name, and the signature is checked against what it found.** `flan_find_restart` matches the name
|
||||
hash and nothing else, so an inner `(use-value [s string] ...)` shadows an outer `(use-value [v i32] ...)` and an i32
|
||||
is refused there — the outer frame that would have taken it is never consulted. That is §4 read straight ("the first
|
||||
frame offering the name") and it is the thing a reader will assume works the other way, so `restarts.flan` has a case
|
||||
for it. Searching outward for a frame whose signature fits would make which restart runs depend on the arguments,
|
||||
which is overload resolution on a dynamic stack.
|
||||
|
||||
Both of these guards go through `fail_block` unconditionally, unlike the bounds checks: `--no-bounds-checks` does not
|
||||
remove them. A wrong index is a wrong answer, and a transfer into a clause whose parameters were never written, or
|
||||
written to a different layout, is memory corruption.
|
||||
|
||||
`runtime/flan_rt.c` gained two message functions and nothing else. The restart frame's first four fields are the ones C
|
||||
declares and their offsets do not move; everything §3 needed is appended after them, and C never allocates one.
|
||||
|
||||
|
||||
@ -87,6 +87,10 @@ the agent's socket instead.
|
||||
- *An unknown restart name is a hard stop.* No ~find-restart~ to test with.
|
||||
- *So are the wrong arguments*, and for the same reason: nothing static can
|
||||
know what a name will find. The message names both signatures.
|
||||
- *Lookup is by name; the signature is checked after it.* Nothing searches for
|
||||
a frame the arguments would fit. An inner ~(use-value [s string] ...)~
|
||||
shadows an outer ~(use-value [v i32] ...)~, so ~(invoke-restart 'use-value
|
||||
21)~ stops the program even though the outer clause would have taken it.
|
||||
- *No supertype*, so nothing can say "any condition".
|
||||
- *~signal~ cannot hand a value back.* Deliberate (§1).
|
||||
- A condition must be a *struct*. ~return~ is refused inside either form.
|
||||
|
||||
@ -87,6 +87,20 @@
|
||||
(handler-bind [(AssetMissing [c] (invoke-restart 'retry 1))]
|
||||
(supplied n)))
|
||||
|
||||
;;; §4 meets §3: lookup is by *name*, and the signature is checked against
|
||||
;;; whatever that finds. An inner frame offering use-value shadows the outer
|
||||
;;; one, so an i32 is refused here even though the outer clause would have
|
||||
;;; taken it — a name finds one frame, it does not search for a fitting one.
|
||||
(defn shadowed [n i32] i32
|
||||
(restart-case
|
||||
(restart-case (middle n)
|
||||
(use-value [s string] (do (print s) 0)))
|
||||
(use-value [v i32] v)))
|
||||
|
||||
(defn mislaid [n i32] i32
|
||||
(handler-bind [(AssetMissing [c] (invoke-restart 'use-value 21))]
|
||||
(shadowed n)))
|
||||
|
||||
(defn main [args [string]] i32
|
||||
;; One argument selects a trap; none runs the table's case.
|
||||
(if (> (len args) 1)
|
||||
@ -95,6 +109,7 @@
|
||||
(= k 1) (print (mismatched 90))
|
||||
(= k 2) (print (mistyped 91))
|
||||
(= k 3) (print (overfull 92))
|
||||
(= k 4) (print (mislaid 93))
|
||||
:else (println "?"))
|
||||
(return 0)))
|
||||
|
||||
|
||||
@ -298,6 +298,12 @@ let () =
|
||||
"restart use-value takes (i32), given (string)";
|
||||
refuses "arguments given to a restart that takes none" "3"
|
||||
"restart retry takes (), given (i32)";
|
||||
(* §4 meets §3. The name finds the innermost frame offering it and the
|
||||
signature is checked against *that*; nothing searches outward for a
|
||||
frame the arguments would have fitted, and an outer clause that would
|
||||
have taken them is not consulted. *)
|
||||
refuses "a shadowing clause of the same name and a different signature" "4"
|
||||
"restart use-value takes (string), given (i32)";
|
||||
(try Sys.remove exe with Sys_error _ -> ())
|
||||
in
|
||||
restart_mismatch ();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user