Details
-
Type:
Defect
-
Status:
Open
-
Priority:
Major
-
Resolution: Unresolved
-
Affects Version/s: Approved Backlog
-
Fix Version/s: Release 1.6
-
Component/s: None
-
Labels:None
-
Environment:Clojure commit 9052ca1854b7b6202dba21fe2a45183a4534c501, version 1.3.0-master-SNAPSHOT
-
Approval:Vetted
Description
(set! *warn-on-reflection* true)
(fn [] (loop [b 0] (recur (loop [a 1] a))))
Generates the following warnings:
recur arg for primitive local: b is not matching primitive, had: Object, needed: long Auto-boxing loop arg: b
This is interesting for several reasons. For one, if the arg to recur is a let form, there is no warning:
(fn [] (loop [b 0] (recur (let [a 1] a))))
Also, the compiler appears to understand the return type of loop forms just fine:
(use '[clojure.contrib.repl-utils :only [expression-info]])
(expression-info '(loop [a 1] a))
;=> {:class long, :primitive? true}
The problem can of course be worked around using an explicit cast on the loop form:
(fn [] (loop [b 0] (recur (long (loop [a 1] a)))))
Reported by leafw in IRC: http://clojure-log.n01se.net/date/2011-01-03.html#10:31
loops in expression context are lifted into fns because else Hotspot doesn't optimize them.
This causes several problems:
Adressing all those problems isn't easy.
One can compute the type of the loop and emit a type hint but it works only with reference types. To make it works with primitive, primitie fns aren't enough since they return only long/double: you have to add explicit casts.
So solving the first two points can be done in a rather lccal way.
The two other points require more impacting changes, the goal would be to emit a method rather than a fn. So it means at the very least changing ObjExpr and adding a new subclassof ObjMethod.
[1] beware of
CLJ-1111when testing.- type inference doesn't propagate outside of the loop[1]
- the return value is never a primitive
- mutable fields are inaccessible
- surprise allocation of one closure objects each time the loop is entered.
Adressing all those problems isn't easy. One can compute the type of the loop and emit a type hint but it works only with reference types. To make it works with primitive, primitie fns aren't enough since they return only long/double: you have to add explicit casts. So solving the first two points can be done in a rather lccal way. The two other points require more impacting changes, the goal would be to emit a method rather than a fn. So it means at the very least changing ObjExpr and adding a new subclassof ObjMethod. [1] beware ofCLJ-1111when testing.