From 8e9b7182f41d03f412b2f2db0c8414f1411aa70c Mon Sep 17 00:00:00 2001 From: odersky Date: Thu, 13 Jul 2023 20:42:43 +0200 Subject: [PATCH 1/2] Refine infoDependsOnPrefix infoDependsOnPrefix now also considers non-final term members. Before 8d65f19 it only considered abstract types. Constructors were classified as non-final, which caused regression. We now exclude constructors specifically. Maybe we should instead classify them as effectively final. Fixes #18160 --- .../src/dotty/tools/dotc/core/Types.scala | 1 + .../tools/dotc/transform/TreeChecker.scala | 2 +- tests/pos/i18160/Test_2.scala | 11 ++++++++ tests/pos/i18160/repro_1.scala | 25 +++++++++++++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i18160/Test_2.scala create mode 100644 tests/pos/i18160/repro_1.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index bb4fd02816a6..81fc28a32fec 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2537,6 +2537,7 @@ object Types { (symd.isAbstractType || symd.isTerm && !symd.flagsUNSAFE.isOneOf(Module | Final | Param) + && !symd.isConstructor && !symd.maybeOwner.isEffectivelyFinal) && prefix.sameThis(symd.maybeOwner.thisType) && refines(givenSelfTypeOrCompleter(prefix.cls), symd.name) diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index e50fb9d8b09c..34b3183a6b15 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -544,7 +544,7 @@ object TreeChecker { val TypeDef(_, impl @ Template(constr, _, _, _)) = cdef: @unchecked assert(cdef.symbol == cls) assert(impl.symbol.owner == cls) - assert(constr.symbol.owner == cls) + assert(constr.symbol.owner == cls, i"constr ${constr.symbol} in $cdef has wrong owner; should be $cls but is ${constr.symbol.owner}") assert(cls.primaryConstructor == constr.symbol, i"mismatch, primary constructor ${cls.primaryConstructor}, in tree = ${constr.symbol}") checkOwner(impl) checkOwner(impl.constr) diff --git a/tests/pos/i18160/Test_2.scala b/tests/pos/i18160/Test_2.scala new file mode 100644 index 000000000000..9ee40c3d37f9 --- /dev/null +++ b/tests/pos/i18160/Test_2.scala @@ -0,0 +1,11 @@ +class SynchronizedReevaluation +class SynchronizedReevaluationApi[Api <: RescalaInterface](val api: Api){ + import api._ + + def SynchronizedReevaluation[A](evt: Event[A])(implicit + turnSource: CreationTicket + ): (SynchronizedReevaluation, Event[A]) = { + val sync = new SynchronizedReevaluation + (sync, evt.map(identity)(turnSource)) + } +} diff --git a/tests/pos/i18160/repro_1.scala b/tests/pos/i18160/repro_1.scala new file mode 100644 index 000000000000..060f2d325d2d --- /dev/null +++ b/tests/pos/i18160/repro_1.scala @@ -0,0 +1,25 @@ +object core { + final class CreationTicket[State[_]] +} + +trait ReadAs[S[_], +A] { type State[V] = S[V] } + +trait EventCompatBundle { + bundle: Operators => + + trait EventCompat[+T] extends ReadAs[State, Option[T]] { + selfType: Event[T] => + final inline def map[B](inline expression: T => B)(implicit ticket: CreationTicket): Event[B] = ??? + } +} + +trait EventBundle extends EventCompatBundle { self: Operators => + trait Event[+T] extends EventCompat[T]: + final override type State[V] = self.State[V] +} +trait Operators extends EventBundle { + type State[_] + type CreationTicket = core.CreationTicket[State] +} +trait RescalaInterface extends Operators + From d2a0b3cd298ec45ef34942b23829f305cfca6d96 Mon Sep 17 00:00:00 2001 From: odersky Date: Thu, 13 Jul 2023 20:53:37 +0200 Subject: [PATCH 2/2] Make constructors effectively final This is mainly a cleanup. --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 1 + compiler/src/dotty/tools/dotc/transform/init/Util.scala | 6 ++---- compiler/src/dotty/tools/dotc/typer/RefChecks.scala | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 988a37be4388..b8c17ff61e9e 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1196,6 +1196,7 @@ object SymDenotations { isOneOf(EffectivelyFinalFlags) || is(Inline, butNot = Deferred) || is(JavaDefinedVal, butNot = Method) + || isConstructor || !owner.isExtensibleClass /** A class is effectively sealed if has the `final` or `sealed` modifier, or it diff --git a/compiler/src/dotty/tools/dotc/transform/init/Util.scala b/compiler/src/dotty/tools/dotc/transform/init/Util.scala index 4e60c1325b09..ba2216504aef 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Util.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Util.scala @@ -75,11 +75,9 @@ object Util: case _ => None - def resolve(cls: ClassSymbol, sym: Symbol)(using Context): Symbol = log("resove " + cls + ", " + sym, printer, (_: Symbol).show) { - if (sym.isEffectivelyFinal || sym.isConstructor) sym + def resolve(cls: ClassSymbol, sym: Symbol)(using Context): Symbol = log("resove " + cls + ", " + sym, printer, (_: Symbol).show): + if sym.isEffectivelyFinal then sym else sym.matchingMember(cls.appliedRef) - } - extension (sym: Symbol) def hasSource(using Context): Boolean = !sym.defTree.isEmpty diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index fe28a8b18833..025eae3606af 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -1689,7 +1689,7 @@ class RefChecks extends MiniPhase { thisPhase => // if (settings.warnNullaryUnit) // checkNullaryMethodReturnType(sym) // if (settings.warnInaccessible) { - // if (!sym.isConstructor && !sym.isEffectivelyFinal && !sym.isSynthetic) + // if (!sym.isEffectivelyFinal && !sym.isSynthetic) // checkAccessibilityOfReferencedTypes(tree) // } // tree match {