scala/scala — pull request #3488 by retronym (2014-02-08 09:59:36+00:00)
Title: 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".

Review by @gkossakowski