Skip to content

Commit c0770ed

Browse files
committed
Merge pull request #628 from dotty-staging/fix/initializer-deadlocks
Fix/initializer deadlocks
2 parents 57a2a01 + bcf70e2 commit c0770ed

File tree

14 files changed

+77
-74
lines changed

14 files changed

+77
-74
lines changed

src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ class Compiler {
6767
new Constructors,
6868
new FunctionalInterfaces),
6969
List(new LambdaLift, // in this mini-phase block scopes are incorrect. No phases that rely on scopes should be here
70-
new Flatten,
7170
new ElimStaticThis,
71+
new Flatten,
7272
new RestoreScopes),
7373
List(/*new PrivateToStatic,*/
7474
new ExpandPrivate,

src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,9 @@ object Contexts {
231231
final def withPhase(phase: Phase): Context =
232232
withPhase(phase.id)
233233

234+
final def withPhaseNoLater(phase: Phase) =
235+
if (ctx.phase.id > phase.id) withPhase(phase) else ctx
236+
234237
/** If -Ydebug is on, the top of the stack trace where this context
235238
* was created, otherwise `null`.
236239
*/

src/dotty/tools/dotc/transform/ElimStaticThis.scala

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import dotty.tools.dotc.core.StdNames._
99
import dotty.tools.dotc.core.SymDenotations.SymDenotation
1010
import TreeTransforms.{MiniPhaseTransform, TransformerInfo}
1111
import dotty.tools.dotc.core.Types.{ThisType, TermRef}
12-
import Phases.Phase
1312

1413
/** Replace This references to module classes in static methods by global identifiers to the
1514
* corresponding modules.
@@ -18,8 +17,6 @@ class ElimStaticThis extends MiniPhaseTransform {
1817
import ast.tpd._
1918
def phaseName: String = "elimStaticThis"
2019

21-
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Flatten])
22-
2320
override def transformThis(tree: This)(implicit ctx: Context, info: TransformerInfo): Tree =
2421
if (!tree.symbol.is(Package) && ctx.owner.enclosingMethod.is(JavaStatic)) {
2522
assert(tree.symbol.is(ModuleClass))
@@ -28,12 +25,10 @@ class ElimStaticThis extends MiniPhaseTransform {
2825
else tree
2926

3027
override def transformIdent(tree: tpd.Ident)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
31-
val meth = ctx.owner.enclosingMethod
32-
// We cannot use meth.enclosingClass because it skips other static classes,
33-
// so instead we require this phase to run after Flatten and use meth.owner
34-
if (meth.is(JavaStatic) && meth.owner.is(ModuleClass)) {
28+
if (ctx.owner.enclosingMethod.is(JavaStatic)) {
3529
tree.tpe match {
36-
case TermRef(thiz: ThisType, _) if (thiz.underlying.typeSymbol == meth.owner) =>
30+
case TermRef(thiz: ThisType, _) =>
31+
assert(thiz.underlying.typeSymbol.is(ModuleClass))
3732
ref(thiz.underlying.typeSymbol.sourceModule).select(tree.symbol)
3833
case _ => tree
3934
}

src/dotty/tools/dotc/transform/ExplicitOuter.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,9 +299,10 @@ object ExplicitOuter {
299299
def path(toCls: Symbol): Tree = try {
300300
def loop(tree: Tree): Tree = {
301301
val treeCls = tree.tpe.widen.classSymbol
302-
ctx.log(i"outer to $toCls of $tree: ${tree.tpe}, looking for ${outerAccName(treeCls.asClass)}")
302+
val outerAccessorCtx = ctx.withPhaseNoLater(ctx.lambdaLiftPhase) // lambdalift mangles local class names, which means we cannot reliably find outer acessors anymore
303+
ctx.log(i"outer to $toCls of $tree: ${tree.tpe}, looking for ${outerAccName(treeCls.asClass)(outerAccessorCtx)} in $treeCls")
303304
if (treeCls == toCls) tree
304-
else loop(tree select outerAccessor(treeCls.asClass))
305+
else loop(tree select outerAccessor(treeCls.asClass)(outerAccessorCtx))
305306
}
306307
ctx.log(i"computing outerpath to $toCls from ${ctx.outersIterator.map(_.owner).toList}")
307308
loop(This(ctx.owner.enclosingClass.asClass))

src/dotty/tools/dotc/transform/LambdaLift.scala

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
9494
* than the previous value of `liftedowner(sym)`.
9595
*/
9696
def narrowLiftedOwner(sym: Symbol, owner: Symbol)(implicit ctx: Context) = {
97-
if (sym.owner.isTerm &&
97+
if (sym.maybeOwner.isTerm &&
9898
owner.isProperlyContainedIn(liftedOwner(sym)) &&
9999
owner != sym) {
100100
ctx.log(i"narrow lifted $sym to $owner")
@@ -189,10 +189,9 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
189189
val sym = tree.symbol
190190
def narrowTo(thisClass: ClassSymbol) = {
191191
val enclClass = enclosure.enclosingClass
192-
if (!thisClass.isStaticOwner)
193-
narrowLiftedOwner(enclosure,
194-
if (enclClass.isContainedIn(thisClass)) thisClass
195-
else enclClass) // unknown this reference, play it safe and assume the narrowest possible owner
192+
narrowLiftedOwner(enclosure,
193+
if (enclClass.isContainedIn(thisClass)) thisClass
194+
else enclClass) // unknown this reference, play it safe and assume the narrowest possible owner
196195
}
197196
tree match {
198197
case tree: Ident =>
@@ -210,8 +209,15 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
210209
case tree: This =>
211210
narrowTo(tree.symbol.asClass)
212211
case tree: DefDef =>
213-
if (sym.owner.isTerm && !sym.is(Label)) liftedOwner(sym) = sym.topLevelClass.owner
214-
else if (sym.isPrimaryConstructor && sym.owner.owner.isTerm) symSet(called, sym) += sym.owner
212+
if (sym.owner.isTerm && !sym.is(Label))
213+
liftedOwner(sym) = sym.enclosingClass.topLevelClass
214+
// this will make methods in supercall constructors of top-level classes owned
215+
// by the enclosing package, which means they will be static.
216+
// On the other hand, all other methods will be indirectly owned by their
217+
// top-level class. This avoids possible deadlocks when a static method
218+
// has to access its enclosing object from the outside.
219+
else if (sym.isPrimaryConstructor && sym.owner.owner.isTerm)
220+
symSet(called, sym) += sym.owner
215221
case tree: TypeDef =>
216222
if (sym.owner.isTerm) liftedOwner(sym) = sym.topLevelClass.owner
217223
case tree: Template =>
@@ -360,7 +366,7 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
360366
val clazz = sym.enclosingClass
361367
val qual =
362368
if (clazz.isStaticOwner) singleton(clazz.thisType)
363-
else outer(ctx.withPhase(thisTransform)).path(clazz)
369+
else outer.path(clazz)
364370
transformFollowingDeep(qual.select(sym))
365371
}
366372

tests/pending/pos/lambdalift-1.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
class Super(x: Int)
2+
3+
class Sub extends Super({
4+
def foo3(x: Int) = {
5+
6+
class C {
7+
def this(name: String) = this()
8+
9+
def bam(y: Int): String => Int = {
10+
def baz = x + y
11+
z => baz * z.length
12+
}
13+
}
14+
15+
val fun = new C("dummy").bam(1)
16+
fun("abc")
17+
18+
}
19+
foo3(22)
20+
})

tests/pos/lambdalift.scala

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,3 @@ object test {
2323

2424
}
2525
}
26-
27-
class Super(x: Int)
28-
29-
class Sub extends Super({
30-
def foo3(x: Int) = {
31-
32-
class C {
33-
def this(name: String) = this()
34-
35-
def bam(y: Int): String => Int = {
36-
def baz = x + y
37-
z => baz * z.length
38-
}
39-
}
40-
41-
val fun = new C("dummy").bam(1)
42-
fun("abc")
43-
44-
}
45-
foo3(22)
46-
})

tests/pos/llift.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class A {
2+
class B {
3+
def outer(): Unit = {
4+
def inner(): Int = 2
5+
6+
val fi: Function0[Int] = () => inner()
7+
}
8+
}
9+
}

tests/run/t5375.scala

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
object Test {
1+
object Test extends dotty.runtime.LegacyApp {
22
val foos = (1 to 1000).toSeq
3-
4-
def main(args: Array[String]): Unit = {
5-
try
6-
foos.par.map(i => if (i % 37 == 0) sys.error("i div 37") else i)
7-
catch {
8-
case ex: RuntimeException => println("Runtime exception")
9-
}
3+
try
4+
foos.par.map(i => if (i % 37 == 0) sys.error("i div 37") else i)
5+
catch {
6+
case ex: RuntimeException => println("Runtime exception")
107
}
118
}

tests/run/t6052.scala

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66

77

8-
object Test {
8+
object Test extends dotty.runtime.LegacyApp {
99
def seqarr(i: Int) = Array[Int]() ++ (0 until i)
1010
def pararr(i: Int) = seqarr(i).par
1111

@@ -15,9 +15,7 @@ object Test {
1515
assert(gseq == gpar, (gseq, gpar))
1616
}
1717

18-
def main(args: Array[String]): Unit = {
19-
for (i <- 0 until 20) check(i, _ > 0)
20-
for (i <- 0 until 20) check(i, _ % 2)
21-
for (i <- 0 until 20) check(i, _ % 4)
22-
}
18+
for (i <- 0 until 20) check(i, _ > 0)
19+
for (i <- 0 until 20) check(i, _ % 2)
20+
for (i <- 0 until 20) check(i, _ % 4)
2321
}

tests/run/t6260-delambdafy.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
f(C@2e)
22

33
apply
4+
get$Lambda

tests/run/t6410.scala

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11

22

33

4-
object Test {
5-
def main(args: Array[String]): Unit = {
6-
val x = collection.parallel.mutable.ParArray.range(1,10) groupBy { _ % 2 } mapValues { _.size }
7-
println(x)
8-
val y = collection.parallel.immutable.ParVector.range(1,10) groupBy { _ % 2 } mapValues { _.size }
9-
println(y)
10-
}
4+
object Test extends dotty.runtime.LegacyApp {
5+
val x = collection.parallel.mutable.ParArray.range(1,10) groupBy { _ % 2 } mapValues { _.size }
6+
println(x)
7+
val y = collection.parallel.immutable.ParVector.range(1,10) groupBy { _ % 2 } mapValues { _.size }
8+
println(y)
119
}

tests/run/t6467.scala

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,15 @@ import collection._
66

77

88

9-
object Test {
9+
object Test extends dotty.runtime.LegacyApp {
1010

1111
def compare(s1: String, s2: String): Unit = {
1212
assert(s1 == s2, s1 + "\nvs.\n" + s2)
1313
}
1414

15-
def main(args: Array[String]): Unit = {
16-
compare(List(1, 2, 3, 4).aggregate(new java.lang.StringBuffer)(_ append _, _ append _).toString, "1234")
17-
compare(List(1, 2, 3, 4).par.aggregate(new java.lang.StringBuffer)(_ append _, _ append _).toString, "1234")
18-
compare(Seq(0 until 100: _*).aggregate(new java.lang.StringBuffer)(_ append _, _ append _).toString, (0 until 100).mkString)
19-
compare(Seq(0 until 100: _*).par.aggregate(new java.lang.StringBuffer)(_ append _, _ append _).toString, (0 until 100).mkString)
20-
}
15+
compare(List(1, 2, 3, 4).aggregate(new java.lang.StringBuffer)(_ append _, _ append _).toString, "1234")
16+
compare(List(1, 2, 3, 4).par.aggregate(new java.lang.StringBuffer)(_ append _, _ append _).toString, "1234")
17+
compare(Seq(0 until 100: _*).aggregate(new java.lang.StringBuffer)(_ append _, _ append _).toString, (0 until 100).mkString)
18+
compare(Seq(0 until 100: _*).par.aggregate(new java.lang.StringBuffer)(_ append _, _ append _).toString, (0 until 100).mkString)
2119

2220
}

tests/run/t7498.scala

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,16 @@
55

66

77

8-
object Test {
8+
object Test extends dotty.runtime.LegacyApp {
99
import scala.collection.concurrent.TrieMap
1010

1111
class Collision(val idx: Int) {
1212
override def hashCode = idx % 10
1313
}
1414

15-
def main(args: Array[String]): Unit = {
16-
val tm = TrieMap[Collision, Unit]()
17-
for (i <- 0 until 1000) tm(new Collision(i)) = ()
15+
val tm = TrieMap[Collision, Unit]()
16+
for (i <- 0 until 1000) tm(new Collision(i)) = ()
1817

19-
tm.par.foreach(kv => ())
20-
}
18+
tm.par.foreach(kv => ())
2119
}
2220

0 commit comments

Comments
 (0)