Skip to content

fn literals carry source-location metadata that JVM and ClojureCLR strip #53

Description

@skydread1

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions