From 1675d88778d0e68e0369b315444bd7741989548e Mon Sep 17 00:00:00 2001 From: Yogthos Date: Wed, 10 Jun 2026 09:22:54 -0400 Subject: [PATCH] core: sq-symbol qualifies unresolved syms against :compile-ns, not the analyzer's ns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit deftype with inline protocol methods failed in compile mode with "Unable to resolve symbol: jolt.analyzer/extend-type". deftype's expander template emits (extend-type ...), but extend-type is defined AFTER deftype in 30-macros — so when the expander compiles at defmacro time, syntax-quote lowering can't resolve it and falls through to current-ns qualification. The analyzer runs interpreted in jolt.analyzer, so ctx-current-ns mid-compile is jolt.analyzer, baking the wrong qualification into the compiled template. Same bug class jolt-265 fixed for resolve-var: read :compile-ns (the namespace being compiled) when set, falling back to ctx-current-ns. Interpret and self-host modes never hit it (interpreted expanders resolve at use time, when extend-type exists) — which is also why no gate test caught it: nothing EVALUATED a deftype-with-inline-methods in compile mode. Two 3-mode conformance cases added. Gate: conformance 271x3, fallback-zero, fixpoint, self-host, sci, staged, suite 4046>=4034, all specs+unit. --- src/jolt/evaluator.janet | 10 +++++++++- test/integration/conformance-test.janet | 5 +++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/jolt/evaluator.janet b/src/jolt/evaluator.janet index dcef376..6441f88 100644 --- a/src/jolt/evaluator.janet +++ b/src/jolt/evaluator.janet @@ -155,7 +155,15 @@ (special-symbol? nm) form (ns-find (ctx-find-ns ctx "clojure.core") nm) {:jolt/type :symbol :ns "clojure.core" :name nm} - {:jolt/type :symbol :ns (ctx-current-ns ctx) :name nm})) + # Unresolved -> qualify to the namespace being COMPILED when set (the + # analyzer runs interpreted in jolt.analyzer, so ctx-current-ns is wrong + # mid-compile — the same seam resolve-var/h-current-ns use). Matters when + # a macro expander's template is lowered while a symbol it references is + # not yet defined (deftype's extend-type, defined later in the same tier): + # it must qualify to the macro's home ns, not jolt.analyzer. + {:jolt/type :symbol + :ns (or (get (ctx :env) :compile-ns) (ctx-current-ns ctx)) + :name nm})) form)) (defn- d-realize diff --git a/test/integration/conformance-test.janet b/test/integration/conformance-test.janet index 31645d8..216fe2f 100644 --- a/test/integration/conformance-test.janet +++ b/test/integration/conformance-test.janet @@ -132,6 +132,11 @@ ["multimethod default" ":def" "(do (defmulti f identity) (defmethod f :default [x] :def) (f 99))"] ["protocol on record" "16" "(do (defprotocol Sh (ar [s])) (defrecord Sq [side] Sh (ar [_] (* side side))) (ar (->Sq 4)))"] ["reify dispatch" "42" "(do (defprotocol P (m [_])) (m (reify P (m [_] 42))))"] + # deftype with INLINE protocol methods (its expansion calls extend-type, which + # is defined AFTER deftype in 30-macros — regression for the sq-symbol + # current-ns-vs-compile-ns qualification bug, jolt-3vh) + ["deftype inline methods" "7" "(do (defprotocol Pi (mi [x])) (deftype Ti [v] Pi (mi [x] v)) (mi (->Ti 7)))"] + ["deftype two protocols" "[1 2]" "(do (defprotocol Pa (ma [x])) (defprotocol Pb (mb [x])) (deftype Tab [a b] Pa (ma [x] a) Pb (mb [x] b)) (let [t (->Tab 1 2)] [(ma t) (mb t)]))"] ### ---- HIGH: aliased namespace calls ---- ["require :as alias" "\"1,2,3\"" "(do (require (quote [clojure.string :as s])) (s/join \",\" [1 2 3]))"]