Problem
(meta (fn [] 1)) returns the reader's source-location map on MAGIC, where JVM and ClojureCLR return nil. User-supplied metadata is kept on all three; only source-location keys differ.
(meta (fn [] 1))
;; MAGIC => {:line 1, :column 8, :source-span {...}}
;; JVM / ClojureCLR => nil
(meta ^{:foo true} (fn [] 1)) ; all platforms => {:foo true}
MAGIC wraps a fn literal in a :with-meta node carrying the form's source-location metadata, so the compiled fn is a distinct wrapper object (clojure.lang.AFunction+MetaWrapper under eval, an inline withMeta call in direct-linked output) rather than the bare fn. That has two costs: (meta some-fn) diverges from JVM/CLR, and the wrapper is a different object than the fn's own this, which is one of the ways a named fn's self-reference loses identity (related to #52).
Root cause: the analyzer keeps the full source-location metadata on fn nodes. magic-compiler/src/magic/analyzer/untyped_passes.clj maybe-elide-meta only removes metadata when *elide-meta* is set (production pins it false), and it is all-or-nothing rather than source-location-specific.
Suggestion
Mirror what ClojureCLR's FnExpr.Parse does: strip the source-location keys (:line, :column, :source-span, :file, and the return-type tag) from a fn's metadata, then wrap it only if user-supplied metadata remains. A fn with nothing but source-location keys then compiles unwrapped, matching (meta (fn [] 1)) => nil.
This stripping is independent of *elide-meta* (which governs def/Var metadata, not fn source-info), so it should always run. Besides aligning (meta ...) with JVM/CLR, it drops the per-fn-literal wrapper allocation and removes one source of fn-identity divergence.
Problem
(meta (fn [] 1))returns the reader's source-location map on MAGIC, where JVM and ClojureCLR returnnil. User-supplied metadata is kept on all three; only source-location keys differ.MAGIC wraps a fn literal in a
:with-metanode carrying the form's source-location metadata, so the compiled fn is a distinct wrapper object (clojure.lang.AFunction+MetaWrapperunder eval, an inlinewithMetacall in direct-linked output) rather than the bare fn. That has two costs:(meta some-fn)diverges from JVM/CLR, and the wrapper is a different object than the fn's ownthis, which is one of the ways a named fn's self-reference loses identity (related to #52).Root cause: the analyzer keeps the full source-location metadata on fn nodes.
magic-compiler/src/magic/analyzer/untyped_passes.cljmaybe-elide-metaonly removes metadata when*elide-meta*is set (production pins it false), and it is all-or-nothing rather than source-location-specific.Suggestion
Mirror what ClojureCLR's
FnExpr.Parsedoes: strip the source-location keys (:line,:column,:source-span,:file, and the return-type tag) from a fn's metadata, then wrap it only if user-supplied metadata remains. A fn with nothing but source-location keys then compiles unwrapped, matching(meta (fn [] 1)) => nil.This stripping is independent of
*elide-meta*(which governs def/Var metadata, not fn source-info), so it should always run. Besides aligning(meta ...)with JVM/CLR, it drops the per-fn-literal wrapper allocation and removes one source of fn-identity divergence.