Clojure

Compiler doesn't preserve metadata for LazySeq literals

Details

  • Patch:
    Code and Test
  • Approval:
    Ok

Description

The analyzer in Compiler.java forces evaluation of lazyseq literals, but loses the compile time original metadata of that form, meaning that a type hint will be lost.

Example demonstrating this issue:

user=> (set! *warn-on-reflection* true)
true
user=> (list '.substring (with-meta (concat '(identity) '("foo")) {:tag 'String}) 0)
(.substring (identity "foo") 0)
user=> (eval (list '.substring (with-meta (concat '(identity) '("foo")) {:tag 'String}) 0))
Reflection warning, NO_SOURCE_PATH:6:1 - call to method substring on java.lang.Object can't be resolved (no such method).
"foo"

Forcing the concat call to an ASeq rather than a LazySeq fixes this issue:

user=> (eval (list '.hashCode (with-meta (seq (concat '(identity) '("foo"))) {:tag 'String})))
101574

This ticket blocks http://dev.clojure.org/jira/browse/CLJ-1444 since clojure.core/sequence might return a lazyseq.

This bug affected both tools.analyzer and tools.reader and forced me to commit a fix in tools.reader to work around this issue, see: http://dev.clojure.org/jira/browse/TANAL-99

The proposed patch trivially preserves the form metadata after realizing the lazyseq

Approach: Keep a copy of the original form, and apply its metadata to the realized lazyseq
Patch: clj-1586-2.patch
Screened by: Alex Miller

Activity

Hide
Stuart Halloway added a comment -

Please add a test case.

Show
Stuart Halloway added a comment - Please add a test case.
Hide
Nicola Mometto added a comment -

Updated patch with testcase

Show
Nicola Mometto added a comment - Updated patch with testcase
Hide
Alex Miller added a comment -

clj-1586-2.patch is same as prior, just updated to apply to current master

Show
Alex Miller added a comment - clj-1586-2.patch is same as prior, just updated to apply to current master

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: