From 46d84194a46033f945f9cfc7c4f61f52b0c3ae9e Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sat, 8 Feb 2014 09:45:07 +0100 Subject: SI-8245 Fix regression in interplay between lazy val, return In 4c86dbbc492 / SI-6358, synthesis of lazy val accessors trees was moved into the typer phase (in MethodSynthesis). Before that point, the symobl for the accessor *was* created early, but the tree was not. This led to crashes in intervening phases (extensionmethods) as `changeOwner` calls didn't catch the smuggled symbol. Moving the accessor generation forward, however, brought a problem: we now introduce a DefDef around the RHS of the lazy val, but we're not actually guaranteed that the body has already been typechecked. If it happened to be typechecked for the purposes of return type inference, we'll pick up the typechecked tree from `transformed`: // LazyValGetter#derivedTree val rhs1 = transformed.getOrElse(rhs0, rhs0) But if the method had an explicit return type (which must *always* be the case if it contains a `return`!), `rhs0` will be untyped. This leads to, e.g.: def foo(o: Option[Int]): Int = { lazy val i = o.getOrElse(return -1) i + 1 } def foo(o: Option[Int]): Int = { lazy var i$lzy: Int = _; lazy def i: Int = { i$lzy = o.getOrElse(return -1); i$lzy }; i.+(1) }; When this is typechecked, the `return` binds to the closest enclosing `DefDef`, `lazy def i`. This commit changes `Context#enclMethod` to treat `DefDef`s as transparent. `enclMethod` is only used in one other spot that enforces the implementation restriction that "module extending its companion class cannot use default constructor arguments". --- test/files/run/t8245.scala | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 test/files/run/t8245.scala (limited to 'test') diff --git a/test/files/run/t8245.scala b/test/files/run/t8245.scala new file mode 100644 index 0000000000..d44defbb9e --- /dev/null +++ b/test/files/run/t8245.scala @@ -0,0 +1,14 @@ +object Test { + def foo(o: Option[Int]): Int = { + lazy val i: Int = { + def local: Int = {if ("".isEmpty) return 42; -42} + assert(local == 42) + o.getOrElse(return -1) + } + i + 1 + } + + def main(args: Array[String]) { + assert(foo(None) == -1) + } +} -- cgit v1.2.3