From f0560b208cdef274263858cd612e528fbe29bb5b Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 13 May 2024 21:24:40 +0200 Subject: [PATCH] Don't re-balance AndTypes arising from supertypes #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 --- .../src/dotty/tools/dotc/core/TypeOps.scala | 4 ++ .../dotty/tools/dotc/typer/TypeAssigner.scala | 2 +- tests/run/i20284.check | 15 ++++++ tests/run/i20284.scala | 54 +++++++++++++++++++ 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 tests/run/i20284.check create mode 100644 tests/run/i20284.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 1282b77f013e..3bc7a7223abb 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -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 } diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 64722d51708c..2be81a4222cd 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -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) diff --git a/tests/run/i20284.check b/tests/run/i20284.check new file mode 100644 index 000000000000..69e714e43e38 --- /dev/null +++ b/tests/run/i20284.check @@ -0,0 +1,15 @@ +Test 1 +D +B +C +A +Test 2 +D +B +C +A +Test 3 +D +B +C +A diff --git a/tests/run/i20284.scala b/tests/run/i20284.scala new file mode 100644 index 000000000000..a47fda6e1457 --- /dev/null +++ b/tests/run/i20284.scala @@ -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