aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Petrashko <dark@d-d.me>2015-06-03 18:33:47 +0200
committerDmitry Petrashko <dark@d-d.me>2015-06-03 18:33:47 +0200
commitc0770edba1f5ba85b5a48f2c2ce68704dbe00087 (patch)
tree874c93beea0cb95499420b2f7c29781155d08041
parent57a2a014593278c752fb645f9005ed16b4447242 (diff)
parentbcf70e27e0eef1b55c2e4afd8f680c0351810073 (diff)
downloaddotty-c0770edba1f5ba85b5a48f2c2ce68704dbe00087.tar.gz
dotty-c0770edba1f5ba85b5a48f2c2ce68704dbe00087.tar.bz2
dotty-c0770edba1f5ba85b5a48f2c2ce68704dbe00087.zip
Merge pull request #628 from dotty-staging/fix/initializer-deadlocks
Fix/initializer deadlocks
-rw-r--r--src/dotty/tools/dotc/Compiler.scala2
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala3
-rw-r--r--src/dotty/tools/dotc/transform/ElimStaticThis.scala11
-rw-r--r--src/dotty/tools/dotc/transform/ExplicitOuter.scala5
-rw-r--r--src/dotty/tools/dotc/transform/LambdaLift.scala22
-rw-r--r--tests/pending/pos/lambdalift-1.scala20
-rw-r--r--tests/pos/lambdalift.scala21
-rw-r--r--tests/pos/llift.scala9
-rw-r--r--tests/run/t5375.scala13
-rw-r--r--tests/run/t6052.scala10
-rw-r--r--tests/run/t6260-delambdafy.check1
-rw-r--r--tests/run/t6410.scala12
-rw-r--r--tests/run/t6467.scala12
-rw-r--r--tests/run/t7498.scala10
14 files changed, 77 insertions, 74 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index 41e77c61f..d7ef44144 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -67,8 +67,8 @@ class Compiler {
new Constructors,
new FunctionalInterfaces),
List(new LambdaLift, // in this mini-phase block scopes are incorrect. No phases that rely on scopes should be here
- new Flatten,
new ElimStaticThis,
+ new Flatten,
new RestoreScopes),
List(/*new PrivateToStatic,*/
new ExpandPrivate,
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala
index c1b2e20eb..b00896117 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -231,6 +231,9 @@ object Contexts {
final def withPhase(phase: Phase): Context =
withPhase(phase.id)
+ final def withPhaseNoLater(phase: Phase) =
+ if (ctx.phase.id > phase.id) withPhase(phase) else ctx
+
/** If -Ydebug is on, the top of the stack trace where this context
* was created, otherwise `null`.
*/
diff --git a/src/dotty/tools/dotc/transform/ElimStaticThis.scala b/src/dotty/tools/dotc/transform/ElimStaticThis.scala
index c60990477..7df29b0b0 100644
--- a/src/dotty/tools/dotc/transform/ElimStaticThis.scala
+++ b/src/dotty/tools/dotc/transform/ElimStaticThis.scala
@@ -9,7 +9,6 @@ import dotty.tools.dotc.core.StdNames._
import dotty.tools.dotc.core.SymDenotations.SymDenotation
import TreeTransforms.{MiniPhaseTransform, TransformerInfo}
import dotty.tools.dotc.core.Types.{ThisType, TermRef}
-import Phases.Phase
/** Replace This references to module classes in static methods by global identifiers to the
* corresponding modules.
@@ -18,8 +17,6 @@ class ElimStaticThis extends MiniPhaseTransform {
import ast.tpd._
def phaseName: String = "elimStaticThis"
- override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Flatten])
-
override def transformThis(tree: This)(implicit ctx: Context, info: TransformerInfo): Tree =
if (!tree.symbol.is(Package) && ctx.owner.enclosingMethod.is(JavaStatic)) {
assert(tree.symbol.is(ModuleClass))
@@ -28,12 +25,10 @@ class ElimStaticThis extends MiniPhaseTransform {
else tree
override def transformIdent(tree: tpd.Ident)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
- val meth = ctx.owner.enclosingMethod
- // We cannot use meth.enclosingClass because it skips other static classes,
- // so instead we require this phase to run after Flatten and use meth.owner
- if (meth.is(JavaStatic) && meth.owner.is(ModuleClass)) {
+ if (ctx.owner.enclosingMethod.is(JavaStatic)) {
tree.tpe match {
- case TermRef(thiz: ThisType, _) if (thiz.underlying.typeSymbol == meth.owner) =>
+ case TermRef(thiz: ThisType, _) =>
+ assert(thiz.underlying.typeSymbol.is(ModuleClass))
ref(thiz.underlying.typeSymbol.sourceModule).select(tree.symbol)
case _ => tree
}
diff --git a/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/src/dotty/tools/dotc/transform/ExplicitOuter.scala
index 70a4f299a..0fa429d6e 100644
--- a/src/dotty/tools/dotc/transform/ExplicitOuter.scala
+++ b/src/dotty/tools/dotc/transform/ExplicitOuter.scala
@@ -299,9 +299,10 @@ object ExplicitOuter {
def path(toCls: Symbol): Tree = try {
def loop(tree: Tree): Tree = {
val treeCls = tree.tpe.widen.classSymbol
- ctx.log(i"outer to $toCls of $tree: ${tree.tpe}, looking for ${outerAccName(treeCls.asClass)}")
+ val outerAccessorCtx = ctx.withPhaseNoLater(ctx.lambdaLiftPhase) // lambdalift mangles local class names, which means we cannot reliably find outer acessors anymore
+ ctx.log(i"outer to $toCls of $tree: ${tree.tpe}, looking for ${outerAccName(treeCls.asClass)(outerAccessorCtx)} in $treeCls")
if (treeCls == toCls) tree
- else loop(tree select outerAccessor(treeCls.asClass))
+ else loop(tree select outerAccessor(treeCls.asClass)(outerAccessorCtx))
}
ctx.log(i"computing outerpath to $toCls from ${ctx.outersIterator.map(_.owner).toList}")
loop(This(ctx.owner.enclosingClass.asClass))
diff --git a/src/dotty/tools/dotc/transform/LambdaLift.scala b/src/dotty/tools/dotc/transform/LambdaLift.scala
index 42c6e85af..bffc7458e 100644
--- a/src/dotty/tools/dotc/transform/LambdaLift.scala
+++ b/src/dotty/tools/dotc/transform/LambdaLift.scala
@@ -94,7 +94,7 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
* than the previous value of `liftedowner(sym)`.
*/
def narrowLiftedOwner(sym: Symbol, owner: Symbol)(implicit ctx: Context) = {
- if (sym.owner.isTerm &&
+ if (sym.maybeOwner.isTerm &&
owner.isProperlyContainedIn(liftedOwner(sym)) &&
owner != sym) {
ctx.log(i"narrow lifted $sym to $owner")
@@ -189,10 +189,9 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
val sym = tree.symbol
def narrowTo(thisClass: ClassSymbol) = {
val enclClass = enclosure.enclosingClass
- if (!thisClass.isStaticOwner)
- narrowLiftedOwner(enclosure,
- if (enclClass.isContainedIn(thisClass)) thisClass
- else enclClass) // unknown this reference, play it safe and assume the narrowest possible owner
+ narrowLiftedOwner(enclosure,
+ if (enclClass.isContainedIn(thisClass)) thisClass
+ else enclClass) // unknown this reference, play it safe and assume the narrowest possible owner
}
tree match {
case tree: Ident =>
@@ -210,8 +209,15 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
case tree: This =>
narrowTo(tree.symbol.asClass)
case tree: DefDef =>
- if (sym.owner.isTerm && !sym.is(Label)) liftedOwner(sym) = sym.topLevelClass.owner
- else if (sym.isPrimaryConstructor && sym.owner.owner.isTerm) symSet(called, sym) += sym.owner
+ if (sym.owner.isTerm && !sym.is(Label))
+ liftedOwner(sym) = sym.enclosingClass.topLevelClass
+ // this will make methods in supercall constructors of top-level classes owned
+ // by the enclosing package, which means they will be static.
+ // On the other hand, all other methods will be indirectly owned by their
+ // top-level class. This avoids possible deadlocks when a static method
+ // has to access its enclosing object from the outside.
+ else if (sym.isPrimaryConstructor && sym.owner.owner.isTerm)
+ symSet(called, sym) += sym.owner
case tree: TypeDef =>
if (sym.owner.isTerm) liftedOwner(sym) = sym.topLevelClass.owner
case tree: Template =>
@@ -360,7 +366,7 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
val clazz = sym.enclosingClass
val qual =
if (clazz.isStaticOwner) singleton(clazz.thisType)
- else outer(ctx.withPhase(thisTransform)).path(clazz)
+ else outer.path(clazz)
transformFollowingDeep(qual.select(sym))
}
diff --git a/tests/pending/pos/lambdalift-1.scala b/tests/pending/pos/lambdalift-1.scala
new file mode 100644
index 000000000..269f839d6
--- /dev/null
+++ b/tests/pending/pos/lambdalift-1.scala
@@ -0,0 +1,20 @@
+class Super(x: Int)
+
+class Sub extends Super({
+ def foo3(x: Int) = {
+
+ class C {
+ def this(name: String) = this()
+
+ def bam(y: Int): String => Int = {
+ def baz = x + y
+ z => baz * z.length
+ }
+ }
+
+ val fun = new C("dummy").bam(1)
+ fun("abc")
+
+ }
+ foo3(22)
+})
diff --git a/tests/pos/lambdalift.scala b/tests/pos/lambdalift.scala
index febae6828..33cc2c069 100644
--- a/tests/pos/lambdalift.scala
+++ b/tests/pos/lambdalift.scala
@@ -23,24 +23,3 @@ object test {
}
}
-
-class Super(x: Int)
-
-class Sub extends Super({
- def foo3(x: Int) = {
-
- class C {
- def this(name: String) = this()
-
- def bam(y: Int): String => Int = {
- def baz = x + y
- z => baz * z.length
- }
- }
-
- val fun = new C("dummy").bam(1)
- fun("abc")
-
- }
- foo3(22)
-})
diff --git a/tests/pos/llift.scala b/tests/pos/llift.scala
new file mode 100644
index 000000000..51631ac97
--- /dev/null
+++ b/tests/pos/llift.scala
@@ -0,0 +1,9 @@
+class A {
+ class B {
+ def outer(): Unit = {
+ def inner(): Int = 2
+
+ val fi: Function0[Int] = () => inner()
+ }
+ }
+}
diff --git a/tests/run/t5375.scala b/tests/run/t5375.scala
index 256f5435e..8c2c06fde 100644
--- a/tests/run/t5375.scala
+++ b/tests/run/t5375.scala
@@ -1,11 +1,8 @@
-object Test {
+object Test extends dotty.runtime.LegacyApp {
val foos = (1 to 1000).toSeq
-
- def main(args: Array[String]): Unit = {
- try
- foos.par.map(i => if (i % 37 == 0) sys.error("i div 37") else i)
- catch {
- case ex: RuntimeException => println("Runtime exception")
- }
+ try
+ foos.par.map(i => if (i % 37 == 0) sys.error("i div 37") else i)
+ catch {
+ case ex: RuntimeException => println("Runtime exception")
}
}
diff --git a/tests/run/t6052.scala b/tests/run/t6052.scala
index 15bffc1eb..e740f00e1 100644
--- a/tests/run/t6052.scala
+++ b/tests/run/t6052.scala
@@ -5,7 +5,7 @@
-object Test {
+object Test extends dotty.runtime.LegacyApp {
def seqarr(i: Int) = Array[Int]() ++ (0 until i)
def pararr(i: Int) = seqarr(i).par
@@ -15,9 +15,7 @@ object Test {
assert(gseq == gpar, (gseq, gpar))
}
- def main(args: Array[String]): Unit = {
- for (i <- 0 until 20) check(i, _ > 0)
- for (i <- 0 until 20) check(i, _ % 2)
- for (i <- 0 until 20) check(i, _ % 4)
- }
+ for (i <- 0 until 20) check(i, _ > 0)
+ for (i <- 0 until 20) check(i, _ % 2)
+ for (i <- 0 until 20) check(i, _ % 4)
}
diff --git a/tests/run/t6260-delambdafy.check b/tests/run/t6260-delambdafy.check
index eb7212adc..b3ec1b3cc 100644
--- a/tests/run/t6260-delambdafy.check
+++ b/tests/run/t6260-delambdafy.check
@@ -1,3 +1,4 @@
f(C@2e)
apply
+get$Lambda
diff --git a/tests/run/t6410.scala b/tests/run/t6410.scala
index 51aaad839..0855ffecd 100644
--- a/tests/run/t6410.scala
+++ b/tests/run/t6410.scala
@@ -1,11 +1,9 @@
-object Test {
- def main(args: Array[String]): Unit = {
- val x = collection.parallel.mutable.ParArray.range(1,10) groupBy { _ % 2 } mapValues { _.size }
- println(x)
- val y = collection.parallel.immutable.ParVector.range(1,10) groupBy { _ % 2 } mapValues { _.size }
- println(y)
- }
+object Test extends dotty.runtime.LegacyApp {
+ val x = collection.parallel.mutable.ParArray.range(1,10) groupBy { _ % 2 } mapValues { _.size }
+ println(x)
+ val y = collection.parallel.immutable.ParVector.range(1,10) groupBy { _ % 2 } mapValues { _.size }
+ println(y)
}
diff --git a/tests/run/t6467.scala b/tests/run/t6467.scala
index 048ef25e2..e02fb1669 100644
--- a/tests/run/t6467.scala
+++ b/tests/run/t6467.scala
@@ -6,17 +6,15 @@ import collection._
-object Test {
+object Test extends dotty.runtime.LegacyApp {
def compare(s1: String, s2: String): Unit = {
assert(s1 == s2, s1 + "\nvs.\n" + s2)
}
- def main(args: Array[String]): Unit = {
- compare(List(1, 2, 3, 4).aggregate(new java.lang.StringBuffer)(_ append _, _ append _).toString, "1234")
- compare(List(1, 2, 3, 4).par.aggregate(new java.lang.StringBuffer)(_ append _, _ append _).toString, "1234")
- compare(Seq(0 until 100: _*).aggregate(new java.lang.StringBuffer)(_ append _, _ append _).toString, (0 until 100).mkString)
- compare(Seq(0 until 100: _*).par.aggregate(new java.lang.StringBuffer)(_ append _, _ append _).toString, (0 until 100).mkString)
- }
+ compare(List(1, 2, 3, 4).aggregate(new java.lang.StringBuffer)(_ append _, _ append _).toString, "1234")
+ compare(List(1, 2, 3, 4).par.aggregate(new java.lang.StringBuffer)(_ append _, _ append _).toString, "1234")
+ compare(Seq(0 until 100: _*).aggregate(new java.lang.StringBuffer)(_ append _, _ append _).toString, (0 until 100).mkString)
+ compare(Seq(0 until 100: _*).par.aggregate(new java.lang.StringBuffer)(_ append _, _ append _).toString, (0 until 100).mkString)
}
diff --git a/tests/run/t7498.scala b/tests/run/t7498.scala
index a2555c6b1..cab598405 100644
--- a/tests/run/t7498.scala
+++ b/tests/run/t7498.scala
@@ -5,18 +5,16 @@
-object Test {
+object Test extends dotty.runtime.LegacyApp {
import scala.collection.concurrent.TrieMap
class Collision(val idx: Int) {
override def hashCode = idx % 10
}
- def main(args: Array[String]): Unit = {
- val tm = TrieMap[Collision, Unit]()
- for (i <- 0 until 1000) tm(new Collision(i)) = ()
+ val tm = TrieMap[Collision, Unit]()
+ for (i <- 0 until 1000) tm(new Collision(i)) = ()
- tm.par.foreach(kv => ())
- }
+ tm.par.foreach(kv => ())
}