Skip to content

Commit

Permalink
Don't re-balance AndTypes arising from supertypes (#20400)
Browse files Browse the repository at this point in the history
#20284 started breaking since we now balance AndTypes to avoid
performance drops. But (re-)balancing an AndType interferes with the
logic that determines which symbol is referred by a super select. This
is fixed by two changes:

 - Form types of super with `AndType` instead of `&`
- Don't simplify types of super since that would rebalance the
underlying AndTypes.

Fixes #20284
  • Loading branch information
odersky authored May 26, 2024
2 parents 7bdeb0b + f0560b2 commit 952b928
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 1 deletion.
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/core/TypeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ object TypeOps:
// Mapping over a skolem creates a new skolem which by definition won't
// be =:= to the original one.
tp
case tp: SuperType =>
// Mapping a supertype might re-balance an AndType which is not permitted since
// we need the original order of parents for current super resolution.
tp
case _ =>
mapOver
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ trait TypeAssigner {
else if (ctx.erasedTypes) cls.info.firstParent.typeConstructor
else {
val ps = cls.classInfo.parents
if (ps.isEmpty) defn.AnyType else ps.reduceLeft((x: Type, y: Type) => x & y)
if ps.isEmpty then defn.AnyType else ps.reduceLeft(AndType(_, _))
}
SuperType(cls.thisType, owntype)

Expand Down
15 changes: 15 additions & 0 deletions tests/run/i20284.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Test 1
D
B
C
A
Test 2
D
B
C
A
Test 3
D
B
C
A
54 changes: 54 additions & 0 deletions tests/run/i20284.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
trait A {
def print: Unit = println("A")
}

trait B extends A {
override def print: Unit = {
println("B")
super.print
}
}

trait C extends A {
override def print: Unit = {
println("C")
super.print
}
}

trait D extends B {
override def print: Unit = {
println("D")
super.print
}
}

trait BB extends B

trait X
trait Y
trait Z

class Test1 extends C with B with BB with D with X with Y with Z:
override def print: Unit = {
println("Test 1")
super.print
}

class Test2 extends C with B with BB with D with X with Y {
override def print: Unit = {
println("Test 2")
super.print
}
}

class Test3 extends X with Y with Z with C with B with BB with D {
override def print: Unit = {
println("Test 3")
super.print
}
}
@main def Test =
new Test1().print
new Test2().print
new Test3().print

0 comments on commit 952b928

Please sign in to comment.