<< Back to previous view

[CLJS-739] fn/recur bug Created: 01/Jan/14  Updated: 20/Apr/15  Resolved: 23/Feb/14

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None

(defn create-functions [arr names]
  (let [name (first names)]
    (if name
      (recur (conj arr (fn [] (println name)))
             (rest names))
(doseq [fn (create-functions [] [:a :b :c :d])] (fn))

Generates the following incorrect code, the local name is not closed over:

cljs_play.let_bug.core.create_functions = function create_functions(arr, names) {
  while (true) {
    var name = cljs.core.first.call(null, names);
    if (cljs.core.truth_(name)) {
      var G__4744 = cljs.core.conj.call(null, arr, function(arr, names) {
        return function() {
          return cljs.core.println.call(null, name);
      }(arr, names));
      var G__4745 = cljs.core.rest.call(null, names);
      arr = G__4744;
      names = G__4745;
    } else {
      return arr;

Comment by David Nolen [ 01/Jan/14 9:43 PM ]

This is because we don't do two passes to determine if a function uses recur. loop/recur works because we know up front.

Comment by David Nolen [ 23/Feb/14 6:04 PM ]

I actually can't reproduce this in master - I've added tests to confirm https://github.com/clojure/clojurescript/commit/aaae2688aa2646bb252a9a4dd321e9fa8dbedb6a

Comment by Mike Fikes [ 20/Apr/15 3:00 PM ]

This can be reproduced in master with Nashorn, but not Node. (To be frank, I don't know whether this is a bug in Nashorn, or is what was being sought above, but commenting here just in case.)

$ rlwrap java -jar cljs.jar -m cljs.repl.nashorn
To quit, type: :cljs/quit
cljs.user=> *clojurescript-version*
cljs.user=> (defn cljs-739 [arr names]
  (let [name (first names)]
    (if name
      (recur (conj arr (fn [] (println name)))
        (rest names))
#<function cljs$user$cljs_739(arr,names){
var name = cljs.core.first.call(null,names);
var G__30 = cljs.core.conj.call(null,arr,((function (arr,names,name){
return (function (){
return cljs.core.println.call(null,name);
var G__31 = cljs.core.rest.call(null,names);
arr = G__30;
names = G__31;
} else {
return arr;
cljs.user=> (with-out-str (doseq [fn (cljs-739 [] [:a :b :c :d])] (fn)))

Node, on the other hand, honors with-out-string semantics by not printing anything and returning the string ":a\n:b\n:c\n:d\n".

Generated at Wed Nov 25 06:23:05 CST 2015 using JIRA 4.4#649-r158309.