From 41e98161c5a5d58f50fdc86d3725bd10fa6d08ee Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Thu, 29 Aug 2024 23:35:21 +0200 Subject: [PATCH] Fix bug in capture analysis of closures --- .../tools/dotc/transform/init/Objects.scala | 9 ++++--- tests/init-global/pos/footprint2.scala | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 tests/init-global/pos/footprint2.scala diff --git a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala index fe5fce2e1c11..a9cbf01c1523 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala @@ -255,6 +255,7 @@ class Objects(using Context @constructorOnly): case vdef: ValDef => val sym = vdef.symbol if sym.isLocal then defs += sym + traverseChildren(vdef.rhs) case _ => traverseChildren(tree) @@ -680,8 +681,10 @@ class Objects(using Context @constructorOnly): val changeSetBefore = Heap.getChangeSet() // Only perform footprint optimization for method context val footprint = - if ctx == EvalContext.Method then Heap.footprint(Heap.getHeapData(), thisV, env, State.currentObjectRef) - else heapBefore + if ctx == EvalContext.Method then + Heap.footprint(Heap.getHeapData(), thisV, env, State.currentObjectRef) + else + heapBefore val config = Config(thisV, env, footprint) Heap.update(footprint, changeSet = Set.empty) @@ -1267,7 +1270,7 @@ class Objects(using Context @constructorOnly): * @param klass The enclosing class where the expression is located. * @param ctx The context where `eval` is called. */ - def eval(expr: Tree, thisV: ThisValue, klass: ClassSymbol, ctx: EvalContext = EvalContext.Other): Contextual[Value] = log("evaluating " + expr.show + ", this = " + thisV.show + ", regions = " + Regions.show + " in " + klass.show, printer, (_: Value).show) { + def eval(expr: Tree, thisV: ThisValue, klass: ClassSymbol, ctx: EvalContext = EvalContext.Other): Contextual[Value] = log("evaluating " + expr.show + ", this = " + thisV.show + ", heap size = " + Heap.getHeapData().size + " in " + klass.show, printer, (_: Value).show) { cache.cachedEval(thisV, expr, ctx) { expr => cases(expr, thisV, klass) } } diff --git a/tests/init-global/pos/footprint2.scala b/tests/init-global/pos/footprint2.scala new file mode 100644 index 000000000000..dc88896b7929 --- /dev/null +++ b/tests/init-global/pos/footprint2.scala @@ -0,0 +1,26 @@ +class BreakControl extends Throwable + +object Breaks: + private val breakException = new BreakControl + + def breakable(op: => Unit): Unit = + try op catch { case ex: BreakControl if ex eq breakException => } + + def break(): Nothing = throw breakException + +object A: + val n = foo("hello") + def foo(s: String): Int = + val len = s.length + var i = 0 + + while (i < len) { + Breaks.breakable { + val c = s.charAt(i) + + if c == '\n' then Breaks.break() + } + i += 1 + } + + i