From f88c09b2c9069e95b3c1d9c7b6b67a0146aba5c3 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 5 Sep 2018 15:21:01 +0200 Subject: [PATCH 1/3] Do not generate Return nodes for throw expressions Namely throw MatchError --- .../tools/dotc/transform/PatternMatcher.scala | 3 +- .../backend/jvm/DottyBytecodeTests.scala | 45 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index 745c1787f5ed..379bd9f9b1be 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -839,7 +839,8 @@ object PatternMatcher { default } case ResultPlan(tree) => - Return(tree, ref(resultLabel)) + if (tree.symbol eq defn.throwMethod) tree // Namely MatchError + else Return(tree, ref(resultLabel)) } } diff --git a/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala b/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala index fc76948490df..795847f608da 100644 --- a/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala +++ b/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala @@ -401,4 +401,49 @@ class TestBCode extends DottyBytecodeTest { } } + @Test def returnThrowInPatternMatch = { + val source = + """class Test { + | def test(a: Any): Int = { + | a match { + | case _: Test => 1 + | } + | } + |} + """.stripMargin + + checkBCode(source) { dir => + val moduleIn = dir.lookupName("Test.class", directory = false) + val moduleNode = loadClassNode(moduleIn.input) + val method = getMethod(moduleNode, "test") + + val instructions = instructionsFromMethod(method) + val expected = List( + VarOp(Opcodes.ALOAD, 1), + VarOp(Opcodes.ASTORE, 2), + VarOp(Opcodes.ALOAD, 2), + TypeOp(Opcodes.INSTANCEOF, "Test"), + Jump(Opcodes.IFEQ, Label(10)), + VarOp(Opcodes.ALOAD, 2), + TypeOp(Opcodes.CHECKCAST, "Test"), + VarOp(Opcodes.ASTORE, 3), + Op(Opcodes.ICONST_1), + Jump(Opcodes.GOTO, Label(17)), + Label(10), + FrameEntry(1, List("java/lang/Object"), List()), + TypeOp(Opcodes.NEW, "scala/MatchError"), + Op(Opcodes.DUP), + VarOp(Opcodes.ALOAD, 2), + Invoke(Opcodes.INVOKESPECIAL, "scala/MatchError", "", "(Ljava/lang/Object;)V", false), + Op(Opcodes.ATHROW), + Label(17), + FrameEntry(0, List("Test", "java/lang/Object", "java/lang/Object", "Test"), List(1)), + Op(Opcodes.IRETURN) + ) + assert(instructions == expected, + "`test` was not properly generated\n" + diffInstructions(instructions, expected)) + + } + } + } From aabc81bd673988dafe255f636903d0802adbd7ea Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 5 Sep 2018 16:16:51 +0200 Subject: [PATCH 2/3] Make optimiation more general --- .../tools/dotc/transform/PatternMatcher.scala | 2 +- .../backend/jvm/DottyBytecodeTests.scala | 20 +++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index 379bd9f9b1be..c65be2134ba9 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -839,7 +839,7 @@ object PatternMatcher { default } case ResultPlan(tree) => - if (tree.symbol eq defn.throwMethod) tree // Namely MatchError + if (tree.tpe <:< defn.NothingType) tree // Namely MatchError else Return(tree, ref(resultLabel)) } } diff --git a/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala b/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala index 795847f608da..87cfdd764218 100644 --- a/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala +++ b/compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala @@ -406,7 +406,7 @@ class TestBCode extends DottyBytecodeTest { """class Test { | def test(a: Any): Int = { | a match { - | case _: Test => 1 + | case _: Test => ??? | } | } |} @@ -423,22 +423,26 @@ class TestBCode extends DottyBytecodeTest { VarOp(Opcodes.ASTORE, 2), VarOp(Opcodes.ALOAD, 2), TypeOp(Opcodes.INSTANCEOF, "Test"), - Jump(Opcodes.IFEQ, Label(10)), + Jump(Opcodes.IFEQ, Label(11)), VarOp(Opcodes.ALOAD, 2), TypeOp(Opcodes.CHECKCAST, "Test"), VarOp(Opcodes.ASTORE, 3), - Op(Opcodes.ICONST_1), - Jump(Opcodes.GOTO, Label(17)), - Label(10), + Field(Opcodes.GETSTATIC, "scala/Predef$", "MODULE$", "Lscala/Predef$;"), + Invoke(Opcodes.INVOKEVIRTUAL, "scala/Predef$", "$qmark$qmark$qmark", "()Lscala/runtime/Nothing$;", false), + Op(Opcodes.ATHROW), + Label(11), FrameEntry(1, List("java/lang/Object"), List()), TypeOp(Opcodes.NEW, "scala/MatchError"), Op(Opcodes.DUP), VarOp(Opcodes.ALOAD, 2), Invoke(Opcodes.INVOKESPECIAL, "scala/MatchError", "", "(Ljava/lang/Object;)V", false), Op(Opcodes.ATHROW), - Label(17), - FrameEntry(0, List("Test", "java/lang/Object", "java/lang/Object", "Test"), List(1)), - Op(Opcodes.IRETURN) + Label(18), + FrameEntry(0, List(), List("java/lang/Throwable")), + Op(Opcodes.ATHROW), + Label(21), + FrameEntry(4, List(), List("java/lang/Throwable")), + Op(Opcodes.ATHROW) ) assert(instructions == expected, "`test` was not properly generated\n" + diffInstructions(instructions, expected)) From 2873a73b110c8861690c565c1adb4dbd4874cecc Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 5 Sep 2018 17:00:15 +0200 Subject: [PATCH 3/3] Update comment --- compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index c65be2134ba9..0ba4baff45a2 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -839,7 +839,7 @@ object PatternMatcher { default } case ResultPlan(tree) => - if (tree.tpe <:< defn.NothingType) tree // Namely MatchError + if (tree.tpe <:< defn.NothingType) tree // For example MatchError else Return(tree, ref(resultLabel)) } }