Skip to content

Fix #2246: Ensure ScalaTest compiles again #2258

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/Erasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,9 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
assertErased(tree)
tree match {
case res: tpd.This =>
assert(!ExplicitOuter.referencesOuter(ctx.owner.lexicallyEnclosingClass, res),
i"Reference to $res from ${ctx.owner.showLocated}")
assert(
!ExplicitOuter.referencesOuter(ctx.owner.lexicallyEnclosingClass, res),
i"Reference to $res from ${ctx.owner} in ${ctx.owner.ownersIterator.toList}%, %")
case ret: tpd.Return =>
// checked only after erasure, as checking before erasure is complicated
// due presence of type params in returned types
Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,9 @@ object ExplicitOuter {
case _ => false
}
tree match {
case _: This | _: Ident => isOuterRef(tree.tpe)
case _: This | _: Ident =>
tree.symbol.is(InSuperCall) || // symbol in supercalls are lifted to the next outer class
isOuterRef(tree.tpe)
case nw: New =>
val newCls = nw.tpe.classSymbol
isOuterSym(newCls.owner.enclosingClass) ||
Expand Down
68 changes: 39 additions & 29 deletions compiler/src/dotty/tools/dotc/transform/LambdaLift.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,17 @@ import core.Decorators._
import core.StdNames.nme
import core.Names._
import core.NameOps._
import core.NameKinds.ExpandPrefixName
import core.Phases._
import ast.Trees._
import SymUtils._
import ExplicitOuter.outer
import util.Attachment
import util.NameTransformer
import util.Positions._
import collection.{ mutable, immutable }
import collection.mutable.{ HashMap, HashSet, LinkedHashMap, LinkedHashSet, TreeSet }

object LambdaLift {
private val NJ = NameTransformer.NAME_JOIN_STRING
private class NoPath extends Exception
}

Expand Down Expand Up @@ -200,35 +199,44 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
* }
* }
*/
private def markFree(sym: Symbol, enclosure: Symbol)(implicit ctx: Context): Symbol = try {
if (!enclosure.exists) throw new NoPath
if (enclosure == sym.enclosure) NoSymbol
else {
ctx.debuglog(i"mark free: ${sym.showLocated} with owner ${sym.maybeOwner} marked free in $enclosure")
val intermediate =
if (enclosure.is(PackageClass)) enclosure
else markFree(sym, enclosure.enclosure)
narrowLiftedOwner(enclosure, intermediate orElse sym.enclosingClass)
if (!intermediate.isRealClass || enclosure.isConstructor) {
// Constructors and methods nested inside traits get the free variables
// of the enclosing trait or class.
// Conversely, local traits do not get free variables.
if (!enclosure.is(Trait))
if (symSet(free, enclosure).add(sym)) {
changedFreeVars = true
ctx.log(i"$sym is free in $enclosure")
private def markFree(sym: Symbol, enclosure: Symbol)(implicit ctx: Context): Symbol = {
def recur(enclosure: Symbol, inSuper: Boolean): Symbol = try
if (!enclosure.exists) throw new NoPath
else if (enclosure == sym.enclosure) NoSymbol
else {
val intermediate =
if (enclosure.is(PackageClass)) enclosure
else {
val next = enclosure.enclosure
// Skip enclosing class if original enclosure appeared in a super call.
// The original enclosure will be moved out of the class, so cannot see
// any proxies in the class.
if (next.isClass && inSuper) recur(next.enclosure, false)
else recur(next, inSuper)
}
narrowLiftedOwner(enclosure, intermediate orElse sym.enclosingClass)
if (!intermediate.isRealClass || enclosure.isConstructor) {
// Constructors and methods nested inside traits get the free variables
// of the enclosing trait or class.
// Conversely, local traits do not get free variables.
if (!enclosure.is(Trait))
if (symSet(free, enclosure).add(sym)) {
changedFreeVars = true
ctx.log(i"$sym is free in $enclosure")
}
}
if (intermediate.isRealClass) intermediate
else if (enclosure.isRealClass) enclosure
else if (intermediate.isClass) intermediate
else if (enclosure.isClass) enclosure
else NoSymbol
}
if (intermediate.isRealClass) intermediate
else if (enclosure.isRealClass) enclosure
else if (intermediate.isClass) intermediate
else if (enclosure.isClass) enclosure
else NoSymbol
catch {
case ex: NoPath =>
println(i"error lambda lifting ${ctx.compilationUnit}: $sym is not visible from $enclosure")
throw ex
}
} catch {
case ex: NoPath =>
println(i"error lambda lifting ${ctx.compilationUnit}: $sym is not visible from $enclosure")
throw ex
recur(enclosure, enclosure.is(InSuperCall))
}

private def markCalled(callee: Symbol, caller: Symbol)(implicit ctx: Context): Unit = {
Expand Down Expand Up @@ -338,7 +346,9 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform

private def newName(sym: Symbol)(implicit ctx: Context): Name =
if (sym.isAnonymousFunction && sym.owner.is(Method, butNot = Label))
(sym.name ++ NJ ++ sym.owner.name).freshened
sym.name.rewrite {
case name: SimpleTermName => ExpandPrefixName(sym.owner.name.asTermName, name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's kind of weird to use ExpandPrefixName here since this isn't a prefix, isn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but FlatName does not fit either.

}.freshened
else sym.name.freshened

private def generateProxies()(implicit ctx: Context): Unit =
Expand Down
7 changes: 7 additions & 0 deletions tests/pos/t0055.scala → tests/pending/pos/t0055.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,10 @@ class W {
trait Y { def y = () }
}
class Z(r : Any) { def this() = this(null) }

object Test {
def main(args: Array[String]) = {
val w = new W
}

}
15 changes: 15 additions & 0 deletions tests/pos/lambdalift.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,19 @@ object test {
fun("abc")

}

class D(f: Int => Int) { self =>
assert(f(0) == 3)

def g(xxx: Int) = {

class E extends D(y => xxx + y) {
}

new E
}
g(3)
}

new D(y => 3)
}