由Ambrose Bonnaire-Sergeant (@ambrosebs)发现。
给定这个复杂的示例
(let [f +
p (promise)
d (delay (f) @@p)]
(deliver p d)
@d)
执行时失败
1. Unhandled java.lang.NullPointerException
Cannot invoke "clojure.lang.IFn.invoke()" because "this.f" is null
在两种情况下都会出现相同的错误
(let [f +
p (promise)
d (lazy-seq (f) (first @p))]
(deliver p d)
(first d))
这两种情况的原因都是,局部变量清除在初次调用后立即将 this.f = null;
赋值,因此当递归调用再次到达 (f)
时,引用已经为空。
(binding [*compiler-options* {:disable-locals-clearing false}]
(clj-java-decompiler.core/decompile
(defn repro []
(let [f +
p (promise)
d (delay (f) @@p)]
(deliver p d)
@d))))
=>
@Override
public Object invoke() {
final Object f = this.f;
this.f = null;
((IFn)f).invoke();
final IFn fn = (IFn)__deref.getRawRoot();
final IFn fn2 = (IFn)__deref.getRawRoot();
final Object p = this.p;
this.p = null;
final Object invoke = fn2.invoke(p);
this = null;
return fn.invoke(invoke);
}
这是否是错误或未定义的行为?