Skip to content

Commit 0d33869

Browse files
committed
Beta-reduce under blocks
`{ ...; (x: T) => f(x) }.apply(y)` is beta-reduced to `{ ...; val x = y; f(x) }`.
1 parent 4411811 commit 0d33869

File tree

3 files changed

+56
-16
lines changed

3 files changed

+56
-16
lines changed

compiler/src/dotty/tools/dotc/transform/BetaReduce.scala

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,22 @@ object BetaReduce:
4848
import ast.tpd._
4949

5050
/** Beta-reduces a call to `fn` with arguments `argSyms` or returns `tree` */
51-
def apply(tree: Apply, fn: Tree, args: List[Tree])(using Context): Tree =
51+
def apply(original: Tree, fn: Tree, args: List[Tree])(using Context): Tree =
5252
fn match
53-
case Typed(expr, _) => BetaReduce(tree, expr, args)
54-
case Block(Nil, expr) => BetaReduce(tree, expr, args)
55-
case Inlined(_, Nil, expr) => BetaReduce(tree, expr, args)
56-
case Block((anonFun: DefDef) :: Nil, closure: Closure) => BetaReduce(anonFun, args)
57-
case _ => tree
53+
case Typed(expr, _) =>
54+
BetaReduce(original, expr, args)
55+
case Block((anonFun: DefDef) :: Nil, closure: Closure) =>
56+
BetaReduce(anonFun, args)
57+
case Block(stats, expr) =>
58+
val tree = BetaReduce(original, expr, args)
59+
if tree eq original then original
60+
else cpy.Block(fn)(stats, tree)
61+
case Inlined(call, bindings, expr) =>
62+
val tree = BetaReduce(original, expr, args)
63+
if tree eq original then original
64+
else cpy.Inlined(fn)(call, bindings, tree)
65+
case _ =>
66+
original
5867
end apply
5968

6069
/** Beta-reduces a call to `ddef` with arguments `argSyms` */

compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -368,14 +368,14 @@ class InlineBytecodeTests extends DottyBytecodeTest {
368368
val instructions = instructionsFromMethod(fun)
369369
val expected =
370370
List(
371-
IntOp(BIPUSH, 10)
372-
, VarOp(ISTORE, 1)
373-
, VarOp(ILOAD, 1)
374-
, Op(ICONST_1)
375-
, Op(IADD)
376-
, VarOp(ISTORE, 1)
377-
, VarOp(ILOAD, 1)
378-
, Op(IRETURN)
371+
IntOp(BIPUSH, 10),
372+
VarOp(ISTORE, 1),
373+
VarOp(ILOAD, 1),
374+
Op(ICONST_1),
375+
Op(IADD),
376+
VarOp(ISTORE, 1),
377+
VarOp(ILOAD, 1),
378+
Op(IRETURN),
379379
)
380380
assert(instructions == expected,
381381
"`f` was not properly inlined in `fun`\n" + diffInstructions(instructions, expected))
@@ -524,4 +524,35 @@ class InlineBytecodeTests extends DottyBytecodeTest {
524524

525525
}
526526
}
527+
528+
@Test def beta_reduce_under_block = {
529+
val source = """class Test:
530+
| def test =
531+
| {
532+
| val a = 3
533+
| (i: Int) => i + a
534+
| }.apply(2)
535+
""".stripMargin
536+
537+
checkBCode(source) { dir =>
538+
val clsIn = dir.lookupName("Test.class", directory = false).input
539+
val clsNode = loadClassNode(clsIn)
540+
541+
val fun = getMethod(clsNode, "test")
542+
val instructions = instructionsFromMethod(fun)
543+
val expected =
544+
List(
545+
Op(ICONST_3),
546+
VarOp(ISTORE, 1),
547+
Op(ICONST_2),
548+
VarOp(ILOAD, 1),
549+
Op(IADD),
550+
Op(IRETURN),
551+
)
552+
553+
assert(instructions == expected,
554+
"`i was not properly beta-reduced in `test`\n" + diffInstructions(instructions, expected))
555+
556+
}
557+
}
527558
}

tests/run-staging/i3876-b.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
6
22
{
33
def f(x: scala.Int): scala.Int = x.+(x)
4-
((`x₂`: scala.Int) => f(`x₂`))
5-
}.apply(3)
4+
f(3)
5+
}

0 commit comments

Comments
 (0)