diff --git a/compiler/src/dotty/tools/dotc/transform/init/Cache.scala b/compiler/src/dotty/tools/dotc/transform/init/Cache.scala index 14a52d995131..39bf134b0ce3 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Cache.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Cache.scala @@ -85,12 +85,14 @@ class Cache[Config, Res]: * * The algorithmic skeleton is as follows: * + * if don't cache result then + * return eval(expr) * if this.current.contains(config, expr) then * return cached value * else * val assumed = this.last(config, expr) or bottom value if absent * this.current(config, expr) = assumed - * val actual = eval(exp) + * val actual = eval(expr) * * if assumed != actual then * this.changed = true @@ -98,28 +100,31 @@ class Cache[Config, Res]: * */ def cachedEval(config: Config, expr: Tree, cacheResult: Boolean, default: Res)(eval: Tree => Res): Res = - this.get(config, expr) match - case Some(value) => value - case None => - val assumeValue: Res = - this.last.get(config, expr) match - case Some(value) => value - case None => - this.last = this.last.updatedNested(config, expr, default) - default - - this.current = this.current.updatedNested(config, expr, assumeValue) - - val actual = eval(expr) - if actual != assumeValue then - // println("Changed! from = " + assumeValue + ", to = " + actual) - this.changed = true - // TODO: respect cacheResult to reduce cache size - this.current = this.current.updatedNested(config, expr, actual) - // this.current = this.current.removed(config, expr) - end if - - actual + if !cacheResult then + eval(expr) + else + this.get(config, expr) match + case Some(value) => value + case None => + val assumeValue: Res = + this.last.get(config, expr) match + case Some(value) => value + case None => + this.last = this.last.updatedNested(config, expr, default) + default + + this.current = this.current.updatedNested(config, expr, assumeValue) + + val actual = eval(expr) + if actual != assumeValue then + // println("Changed! from = " + assumeValue + ", to = " + actual) + this.changed = true + this.current = this.current.updatedNested(config, expr, actual) + // this.current = this.current.removed(config, expr) + end if + + actual + end if end cachedEval def hasChanged = changed diff --git a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala index 286e3a124d12..82bb45851f72 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala @@ -893,7 +893,7 @@ object Semantic: case Cold => Cold - case ref: Ref => eval(vdef.rhs, ref, enclosingClass) + case ref: Ref => eval(vdef.rhs, ref, enclosingClass, cacheResult = sym.is(Flags.Lazy)) case _ => report.error("[Internal error] unexpected this value when accessing local variable, sym = " + sym.show + ", thisValue = " + thisValue2.show + Trace.show, Trace.position) @@ -989,7 +989,7 @@ object Semantic: val errors = Reporter.stopEarly { val res = { given Trace = Trace.empty - eval(body, thisV, klass) + eval(body, thisV, klass, cacheResult = true) } given Trace = Trace.empty.add(body) res.promote("The function return value is not hot. Found = " + res.show + ".") diff --git a/tests/init/neg/apply2.scala b/tests/init/neg/apply2.scala old mode 100644 new mode 100755 index 83f64a6dd3c7..c6c7fe5fedd2 --- a/tests/init/neg/apply2.scala +++ b/tests/init/neg/apply2.scala @@ -3,8 +3,8 @@ object O: println(n) class B: - val a = A(this) + val a = A(this) // error val b = new B - val n = 10 // error + val n = 10 end O diff --git a/tests/init/pos/self-ref.scala b/tests/init/pos/self-ref.scala new file mode 100644 index 000000000000..1a9f199b9f7a --- /dev/null +++ b/tests/init/pos/self-ref.scala @@ -0,0 +1,9 @@ +class A { + def foo(a: Int) = { + lazy val x: Int = if (a == 0) x else 0 + println(x) + } + foo(0) + + val y = 5 +}