Welcome! Please see the About page for a little more info on how this works.

0 votes
in Compiler by

Since mismatching recurs (loop locals that have a different inferred type in the loop body vs the loop arg) cause the loop body to be re-analyzed, macroexpansion in the loop body might happen more than once, causing any side effects that happen during macroexpansion to be evaluated potentially multiple times

`
Clojure 1.7.0-master-SNAPSHOT
user=> (defmacro x [] (println "foo"))

'user/x

user=> (fn [] (loop [y 1] (x) (recur (Integer. 1))))
foo
foo

<user$eval6$fn7 user$eval6$fn7@71687585>

`

6 Answers

0 votes
by

Comment made by: jafingerhut

This is not a question about whether the behavior in the description is a bug or not, but rather a curiosity about how often people write macros that have side effects at macroexpansion time. I think the following in Clojure itself do, but there may be others:

  • gen-class, and also ns because it uses gen-class
  • gen-interface, and also definterface because it uses gen-interface
  • clojure.core/compile-if (private) calls eval on its expr arg, but as used now doesn't cause macroexpansion-time side effects
  • doc seems to have one case that prints at macroexpansion time
  • I am not sure whether defprotocol or deftype have macroexpansion time side effects, or whether they are limited to run time
0 votes
by

Comment made by: bronsa

Andy, I don't think there are that many macros that side-effect at macroexpansion time and I haven't discovered this bug in real code but while thinking about how loop locals invalidation was implemented in Compiler.java.

Because there are a really a small number of side-effecting macros, this is unlikely to cause problems in real code, so I changed the priority to minor.

0 votes
by

Comment made by: arcatan

To comment on the real-world significance: Cloverage, the Clojure code coverage tool, heavily relies on side-effecting macros and this bug causes me to regularly get broken coverage results. I've posted about it on (link: https://github.com/cloverage/cloverage/issues/240 text: Cloverage's issue tracker).

0 votes
by

Comment made by: admin

What are "mismatching recurs"? Can that be made more precise? Mismatch in terms of type? arity? target?

0 votes
by
_Comment made by: bronsa_

type mismatches, the example in the ticket shows a local switching from long to Integer



FWIW ‘type mismatch’  is the terminology used in Compiler. java to refer to this situation
0 votes
by
Reference: https://clojure.atlassian.net/browse/CLJ-1407 (reported by bronsa)
...