diff --git a/NEXT.md b/NEXT.md index 3f583d1..f6ce6b0 100644 --- a/NEXT.md +++ b/NEXT.md @@ -477,6 +477,17 @@ vague intention — if it is listed, someone has already established it is real. ### Bugs found and not yet fixed +- **A shadowed restart is offered and cannot be taken.** §4 says lookup takes the *first* frame offering a name, and + `flan_find_restart` does exactly that — so when two frames offer `retry`, the second one is real, is on the list the + break loop prints, and is unreachable. The old `C-c C-b` prompt showed `retry` twice and sent the string either way; + the inner frame took it, silently. `test/programs/restarts.flan`'s own `nested` function is the counterexample, and + it has been there since the transfer landed. The C&R buffer now draws the shadowed row unbracketed and refuses + `RET` on it by name, which stops the lie but does not restore the choice. The fix is to take a restart **by index** + rather than by name — SBCL identifies them positionally for precisely this reason: + - `(:op "restart-at" :index N)` on the daemon, and a matching agent verb. `flan_restart_name(i, &len)` already + walks the stack by index, so resuming by index is that loop plus `flan_break_resume`'s tail. C only, no compiler + work. + - **A restart chosen at a break inside a thunk is accepted, announced, and silently not taken.** Demonstrated. `flan_reload_call` allocates its own `xfer` and discards it on return, so a transfer aimed at a frame below the `flan_agent_poll` C frame unwinds only as far as the thunk. Three statements that the program will resume, none @@ -509,6 +520,22 @@ Sixty mutations, nineteen left the whole suite green. The severe cluster is clos - And a warning: a reader mutation makes the suite **hang** rather than fail. A green run is not the only outcome to plan for in CI. +### Asked for by the editor lanes + +- **`(:op "layout" :type T)` → the struct's fields and their types.** `Tast.structs` is held by the daemon at all + times because it owns the build, and **no running program is involved** — this is the cheapest real win on the + list, and the C&R buffer already draws its result. +- **`(:op "condition")` → the stopped program's condition, rendered.** Two steps: `break_loop` currently does + `(void)condition;` and *discards the pointer*, so stash it beside `condition_name`; then the daemon builds a render + thunk aimed at that address, which is `Session.render` rooted at a `Ptr` instead of an expression. +- **One thing to get right for both:** the type must be an identity the daemon can resolve to a `Tast` type, not a + bare class name. The hook is handed a string, and two packages both declaring `Missing` leave the daemon unable to + pick a layout. A qualified name or a type id. The same wrinkle bites locals later, because DWARF also gives a name. +- **`(:op "backtrace")` is blocked** on frame metadata — unlocked by the DWARF work, then a new agent verb. Locals are + blocked twice: DWARF for the frame layout, *and* the pointer-rooted render thunk. Restart source locations and + arity are blocked too — `flan_restart` carries `prev`, `name_id`, `name` and `namelen`, so both need a new field in + the frame, which means the compiler emitting it. + ### One line away - **`match` over enums.** Fully desugarable, wanted, and blocked only by `Ast.pattern` needing a keyword case, which diff --git a/emacs/flan-mode.el b/emacs/flan-mode.el index c99393b..f494606 100644 --- a/emacs/flan-mode.el +++ b/emacs/flan-mode.el @@ -24,6 +24,11 @@ (autoload 'flan-show-output "flan-dev" nil t) (autoload 'flan-repl "flan-repl" nil t) (autoload 'flan-break "flan-dev" nil t) +;; The two CIDER-shaped buffers. They reach the daemon through an indirection +;; of their own so that fixtures can drive them, so autoloading is all the +;; wiring they need. +(autoload 'flan-inspect "flan-inspect" nil t) +(autoload 'flan-cnr-show "flan-cnr" nil t) (autoload 'flan-doc "flan-dev" nil t) (autoload 'flan-dev "flan-dev" nil t) (autoload 'flan-dev-quit "flan-dev" nil t) @@ -121,7 +126,14 @@ line is off screen." (define-key map (kbd "C-c C-d") #'flan-describe) (define-key map (kbd "C-c C-o") #'flan-show-output) (define-key map (kbd "C-c C-r") #'flan-repl) - (define-key map (kbd "C-c C-b") #'flan-break) + ;; C-c C-b opens the buffer rather than the minibuffer prompt: it shows the + ;; same restarts plus the condition and the stack, and — the reason it + ;; replaces rather than joins — it is the one that refuses a *shadowed* + ;; restart instead of silently invoking a different frame's. flan-break is + ;; still there under C-c C-M-b for the one-key path. + (define-key map (kbd "C-c C-b") #'flan-cnr-show) + (define-key map (kbd "C-c C-M-b") #'flan-break) + (define-key map (kbd "C-c C-i") #'flan-inspect) ;; Help on the name at point. C-c C-d is taken by `flan-describe', which ;; is about the session rather than about a name, and renaming a key that ;; is already documented costs more than it is worth. Not C-c C-h either: