From 00d4216f7a1989b25f4b216acec9302256460417 Mon Sep 17 00:00:00 2001 From: Ben Elliott Date: Sun, 20 Oct 2019 20:16:27 -0600 Subject: [PATCH] Partial fix for lampepfl#7113: Fix Scala.js codegen for Explicit Returns In order to use an explicit return statement in Scala.js IR, a label must be placed wrapping the whole function body to serve as a jump/break point for all control structures inside the function. While a fresh return label had been generated for such methods (in the LocalNameGenerator), it had not been placed at the top level of its method, and was otherwise unused. This affected the tree created by the TailRec MiniPhase, as well as user-written early return statements. After generating a method's body, if a enclosing return label had been generated, use it to wrap the method body (just as Scala 2's JS codegen does) for such breaks. Enable the tests of ReadersTest.scala of the Scala.js test suite, of which InputStreamReaderTest used a tail-recursive method that depended on this fix. --- compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala | 3 ++- .../src/dotty/tools/backend/sjs/JSEncoding.scala | 12 ++++++++++++ project/Build.scala | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index 55e2473bc405..0398fb121fb5 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -723,9 +723,10 @@ class JSCodeGen()(implicit ctx: Context) { mutable = false, rest = false) } - def genBody() = + def genBody() = localNames.makeLabeledIfRequiresEnclosingReturn(resultIRType) { if (resultIRType == jstpe.NoType) genStat(tree) else genExpr(tree) + } //if (!isScalaJSDefinedJSClass(currentClassSym)) { val flags = js.MemberFlags.empty.withNamespace(namespace) diff --git a/compiler/src/dotty/tools/backend/sjs/JSEncoding.scala b/compiler/src/dotty/tools/backend/sjs/JSEncoding.scala index 38d79db76d2c..97b5e3e47dd1 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSEncoding.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSEncoding.scala @@ -92,6 +92,18 @@ object JSEncoding { returnLabelName = Some(freshName("_return")) js.Ident(returnLabelName.get) } + + /* If this `LocalNameGenerator` has a `returnLabelName` (often added in the + * construction of the `body` argument), wrap the resulting js.Tree to use that label. + */ + def makeLabeledIfRequiresEnclosingReturn(tpe: jstpe.Type)(body: js.Tree)(implicit pos: ir.Position): js.Tree = { + returnLabelName match { + case None => + body + case Some(labelName) => + js.Labeled(js.Ident(labelName), tpe, body) + } + } } private object LocalNameGenerator { diff --git a/project/Build.scala b/project/Build.scala index b0b86a1d3d34..d227cddb3ad4 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -979,7 +979,7 @@ object Build { ( (dir / "shared/src/test/scala/org/scalajs/testsuite/compiler" ** (("*.scala":FileFilter) -- "RegressionTest.scala" -- "ReflectiveCallTest.scala")).get ++ (dir / "shared/src/test/scala/org/scalajs/testsuite/javalib/lang" ** (("*.scala": FileFilter) -- "ClassTest.scala" -- "StringTest.scala")).get - ++ (dir / "shared/src/test/scala/org/scalajs/testsuite/javalib/io" ** (("*.scala": FileFilter) -- "ByteArrayInputStreamTest.scala" -- "ByteArrayOutputStreamTest.scala" -- "DataInputStreamTest.scala" -- "DataOutputStreamTest.scala" -- "InputStreamTest.scala" -- "OutputStreamWriterTest.scala" -- "PrintStreamTest.scala" -- "ReadersTest.scala" -- "CommonStreamsTests.scala")).get + ++ (dir / "shared/src/test/scala/org/scalajs/testsuite/javalib/io" ** (("*.scala": FileFilter) -- "ByteArrayInputStreamTest.scala" -- "ByteArrayOutputStreamTest.scala" -- "DataInputStreamTest.scala" -- "DataOutputStreamTest.scala" -- "InputStreamTest.scala" -- "OutputStreamWriterTest.scala" -- "PrintStreamTest.scala" -- "CommonStreamsTests.scala")).get ++ (dir / "shared/src/test/scala/org/scalajs/testsuite/javalib/math" ** "*.scala").get ++ (dir / "shared/src/test/scala/org/scalajs/testsuite/javalib/net" ** (("*.scala": FileFilter) -- "URITest.scala")).get ++ (dir / "shared/src/test/scala/org/scalajs/testsuite/javalib/security" ** "*.scala").get