Problem
MAGIC resolves a namespace to a source file in the order .cljr, .clj, .cljc. Stock ClojureCLR uses .cljr, .cljc, .clj (Clojure/Clojure/Lib/RT.cs:3584). When a library ships both foo.clj (JVM-only) and foo.cljc (portable), cljr loads the .cljc and nos loads the .clj, so MAGIC picks the file that cannot work:
$ nos build # src/precedence/demo.cljc and src/precedence/demo.clj both present
Compiling precedence.demo
System.InvalidOperationException: Could not find type java.util.ArrayList during import
The order lives in two places on purpose, since build.clj compiles magic.api before clojure.core: magic-compiler/src/magic/api.clj:37 and magic-compiler/src/stdlib/clojure/core.clj:5971.
Three more places assume .clj is the only source extension, so swapping the order alone is not enough:
magic.api/compile-file hardcodes .clj in the assembly name, so a .cljc namespace emits foo.clj.dll while -load probes foo.cljc.dll and never finds it.
magic-unity's editor hooks match .clj.dll by suffix (PlayerCljAssemblies, StockClojureCoexistence), so a .cljc.dll ships without the IL2CPP AOT workarounds and fails on device rather than in CI.
-load resolves the source file and the compiled assembly with two independent searches and then compares their timestamps, so foo.cljc can be compared against a foo.clj.dll built from a different file. Renaming foo.clj to foo.cljc leaves the old assembly beside it, and a rename does not change the file's mtime, so the stale DLL still wins and the rename silently has no effect.
magic-compiler/test/magic/test/load.clj covers .cljr against each of the other two and nothing covers the pair that differs.
Suggestion
(def ^:private source-extensions [".cljr" ".cljc" ".clj"])
in both files, with a load.clj deftest asserting the .cljc wins when both exist. Both are bootstrap namespaces, so the refresh is bb bootstrap, not bb refresh-stdlib.
Alongside that, derive the assembly name from the resolved source's extension rather than hardcoding .clj, give the editor hooks a single predicate covering all three suffixes, and resolve the source first so the assembly candidate can only be the one built from it.
Problem
MAGIC resolves a namespace to a source file in the order
.cljr,.clj,.cljc. Stock ClojureCLR uses.cljr,.cljc,.clj(Clojure/Clojure/Lib/RT.cs:3584). When a library ships bothfoo.clj(JVM-only) andfoo.cljc(portable),cljrloads the.cljcandnosloads the.clj, so MAGIC picks the file that cannot work:The order lives in two places on purpose, since
build.cljcompilesmagic.apibeforeclojure.core:magic-compiler/src/magic/api.clj:37andmagic-compiler/src/stdlib/clojure/core.clj:5971.Three more places assume
.cljis the only source extension, so swapping the order alone is not enough:magic.api/compile-filehardcodes.cljin the assembly name, so a.cljcnamespace emitsfoo.clj.dllwhile-loadprobesfoo.cljc.dlland never finds it.magic-unity's editor hooks match.clj.dllby suffix (PlayerCljAssemblies,StockClojureCoexistence), so a.cljc.dllships without the IL2CPP AOT workarounds and fails on device rather than in CI.-loadresolves the source file and the compiled assembly with two independent searches and then compares their timestamps, sofoo.cljccan be compared against afoo.clj.dllbuilt from a different file. Renamingfoo.cljtofoo.cljcleaves the old assembly beside it, and a rename does not change the file's mtime, so the stale DLL still wins and the rename silently has no effect.magic-compiler/test/magic/test/load.cljcovers.cljragainst each of the other two and nothing covers the pair that differs.Suggestion
in both files, with a
load.cljdeftest asserting the.cljcwins when both exist. Both are bootstrap namespaces, so the refresh isbb bootstrap, notbb refresh-stdlib.Alongside that, derive the assembly name from the resolved source's extension rather than hardcoding
.clj, give the editor hooks a single predicate covering all three suffixes, and resolve the source first so the assembly candidate can only be the one built from it.