From 801c70bd0d6f1586e72db6338d74e1c456e39459 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Sun, 20 Sep 2026 22:51:12 +0700 Subject: [PATCH] The LLVM cell declaration for a lifted def initialiser, pinned in the IR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Session hands global/ to the redefinition when a def is re-evaluated, and that target is not a sibling — its fparent is the global — so its cell declaration comes from Emit.redefinition's targets pass, a path no test compiled: the dev-rerun leg runs on x86 merged, which reaches host cells through the GOT and never needed the declaration. reload.flan carries a (def paint i64 7) now and test_reload greps the module text for the cell extern and the hidden body, which is the idiom the file already uses. --- test/programs/reload.flan | 8 ++++++++ test/test_reload.ml | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/test/programs/reload.flan b/test/programs/reload.flan index 6e7579f..6d2b19e 100644 --- a/test/programs/reload.flan +++ b/test/programs/reload.flan @@ -27,6 +27,14 @@ ;;; question. (defonce spare i64) +;;; Unused too, and here for the redefinition-module question a [def] adds: +;;; its initialiser is lifted into [global/paint] whatever it is — a literal +;;; included — so re-evaluating the form republishes that function through +;;; its cell, and [global/paint] is a *non-sibling* target (its parent is the +;;; global, not a function in the form). test_reload greps the module's IR +;;; for the cell declaration that publish needs. +(def paint i64 7) + ;;; Also unused, and for the same reason: a defconst's value and an enum ;;; member are folded into every call site, so a session has to refuse changing ;;; either. Nothing here reads them, so the checker has no opinion and the diff --git a/test/test_reload.ml b/test/test_reload.ml index b2053bc..67366a5 100644 --- a/test/test_reload.ml +++ b/test/test_reload.ml @@ -125,6 +125,21 @@ let () = fail "redefinition's own body is interposable"; if not (has ir2 "@\"flan.cell.helper\" = external global ptr") then fail "redefinition defines a cell instead of using the host's"; + (* A def's lifted initialiser as the target, which is what [Session]'s + [def_inits] hands in when the form is re-evaluated. [global/paint] is + not a sibling — its [fparent] is the global it initialises, not a + function in [fns] — so its cell declaration comes from the targets + pass in [Emit.redefinition]; without that pass the publish store + names a symbol the module never declared and the IR does not compile. + The x86 side needs no twin: it reaches a host cell through the GOT by + name, declared or not. *) + (let irdef = + Emit.redefinition ~dev:true ~known p1 ~fns:[ "global/paint" ] + in + if not (has irdef "@\"flan.cell.global/paint\" = external global ptr") + then fail "a lifted def initialiser's cell is not declared"; + if not (has irdef "define hidden i64 @\"flan.global/paint\"") then + fail "a lifted def initialiser's body is missing or interposable"); (* A name the host has is a symbol; a name it lacks is a registry lookup cached in a module-local slot. Getting this backwards either fails to link or silently gives each module its own copy. *)