diff --git a/FIX.org b/FIX.org index 6012c98..d14c581 100644 --- a/FIX.org +++ b/FIX.org @@ -156,9 +156,19 @@ against 985ms on LLVM. arena does not make safe — and that a Map has no operation answering *where* a value lives, which is what reading an arena-parsed EDN document back would need. Both were relayed to the arena agent. -- [Tast.Addr (Tast.Pfield ...)] on an Option fails in both backends. The - working route is [Prim (AddrOf, [Field ...])]. Found by the drop lane, not - fixed. +- [Tast.Addr (Tast.Pfield ...)] on an Option: closed, and closed as + unreachable rather than fixed. Nothing in the source language builds it. + [.field] goes through [struct_target], which admits a struct and a pointer + to one and refuses everything else by name with a location — "(Option Point) + is not a struct, so it has no fields" — so [(addr (.x o))] never reaches a + place for [addr] to take. The node the drop lane hit was one the compiler + built for itself. Two rows in test_flan.ml pin the refusal, on the bare field + and on the address of one. + What is still asymmetric, and is a note rather than a bug: [x86.ml]'s + [field_loc] does lay out an Option's tag and value, and [emit.ml]'s [place] + admits only a named struct. Neither is reachable, so neither is tested, and + growing the LLVM side to match would be untestable code written to balance a + path nothing takes. - Re-run still does not work under --two-process: a finished child is genuinely gone. It now works under --x86 because --x86 runs merged. - sand.flan still holds an uncommitted experiment line that is refused with a diff --git a/test/test_flan.ml b/test/test_flan.ml index 4091203..73c4091 100644 --- a/test/test_flan.ml +++ b/test/test_flan.ml @@ -912,6 +912,22 @@ let () = (defn f [s [u8]] i32 (let [c (Cursor {.src s})] (g (addr c))))"); rejects_check "addr of a non-place" "(defn f [] () (addr (+ 1 2)))" ~needle:"addr takes the address of a place"; + (* An Option's two fields exist in both backends' layouts — the tag and the + value — and the structural printer reads the tag through them. What has no + spelling in the source language is reaching one: [match] and [some] are + how an Option is opened, and a (.field o) that read the value of a None + would be reading storage the tag says is not there. FIX.org recorded + [Addr (Pfield ...)] on an Option as a hole in both backends; this is the + pair of rows that says the hole has no door — the refusal is the field + access itself, so (addr ...) never gets a place to take the address of. *) + rejects_check "a field of an Option" + "(defstruct Point [x i32 y i32])\n\ + (defn f [o (Option Point)] i32 (.x o))" + ~needle:"(Option Point) is not a struct, so it has no fields"; + rejects_check "the address of a field of an Option" + "(defstruct Point [x i32 y i32])\n\ + (defn f [o (Option Point)] (Ptr i32) (addr (.x o)))" + ~needle:"(Option Point) is not a struct, so it has no fields"; (* ── Option, some, match ───────────────────────────────────────── *) accepts "some unwraps in an Option-returning function"