From 50b1c127623797753c44bba01ca75a7682d8c88b Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Mon, 14 Dec 2020 14:01:17 +0100 Subject: [PATCH 1/3] Fix #10769: change synthesized type in def ordinal As pointed out by @smarter in #10769, for the following code: package stm trait STMLike[F[_]] { import Internals._ sealed abstract class Txn[+A] {} object Txn { def abort[A](e: Throwable): Txn[A] = Abort(e) } object Internals { case class Abort(error: Throwable) extends Txn[Nothing] } } The compiler synthesized the following code for the object `Txn`: object Txn { type MirroredMonoType = STMLike.this.Txn[?] def ordinal(x: Txn.MirroredMonoType): Int = x match { case _:stm.STMLike.Internals.Abort => 0 } def abort[A](e: Throwable): Txn[A] = Abort(e) } In the method `ordinal`, the type for `Internals.Abort` is TypeRef(ThisType(TypeRef(ThisType(TypeRef(ThisType(TypeRef(NoPrefix,module class stm)),trait STMLike)),module class Internals$)),class Abort) This type is incorrect, as we are not in the object `Internals`. The explicit outer can only handle such types if it's static. In this case, the object is not static, thus it crashes the explicit outer. Co-authored-by: Guillaume Martres --- .../tools/dotc/core/SymDenotations.scala | 27 +++++++++++++++++++ .../dotty/tools/dotc/transform/SymUtils.scala | 6 ++--- .../dotc/transform/SyntheticMembers.scala | 4 +-- tests/pos/i10769.scala | 21 +++++++++++++++ 4 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 tests/pos/i10769.scala diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index a5bf09325c29..a647aec74423 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1410,6 +1410,33 @@ object SymDenotations { def namedType(using Context): NamedType = if (isType) typeRef else termRef + /** The typeRef where `pre.O$.this` is changed to `pre.O.type` if `O` is a non-static object + * + * This is required to avoid owner crash in ExplicitOuter. + * See tests/pos/i10769.scala + */ + def reachableTypeRef(using Context) = + TypeRef(owner.reachableThisType, symbol) + + /** The termRef where `pre.O$.this` is changed to `pre.O.type` if `O` is a non-static object + * + * This is required to avoid owner crash in ExplicitOuter. + * See tests/pos/i10769.scala + */ + def reachableTermRef(using Context) = + TermRef(owner.reachableThisType, symbol) + + /** The thisType where `pre.O$.this` is changed to `pre.O.type` if `O` is a non-static object */ + def reachableThisType(using Context): Type = + if this.is(Package) then + symbol.thisType + else if this.isTerm then + NoPrefix + else if this.is(Module) then + TermRef(owner.reachableThisType, this.sourceModule) + else + ThisType.raw(TypeRef(owner.reachableThisType, symbol.asType)) + /** The variance of this type parameter or type member as a subset of * {Covariant, Contravariant} */ diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index ecea13e5b8ee..c2377467a226 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -223,9 +223,9 @@ object SymUtils: else owner.isLocal } - /** The typeRef with wildcard arguments for each type parameter */ - def rawTypeRef(using Context) = - self.typeRef.appliedTo(self.typeParams.map(_ => TypeBounds.emptyPolyKind)) + /** The reachable typeRef with wildcard arguments for each type parameter */ + def reachableRawTypeRef(using Context) = + self.reachableTypeRef.appliedTo(self.typeParams.map(_ => TypeBounds.emptyPolyKind)) /** Is symbol a quote operation? */ def isQuote(using Context): Boolean = diff --git a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala index 22841a5cf1a0..558122b52865 100644 --- a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala +++ b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala @@ -521,7 +521,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) { else { val cases = for ((child, idx) <- cls.children.zipWithIndex) yield { - val patType = if (child.isTerm) child.termRef else child.rawTypeRef + val patType = if (child.isTerm) child.reachableTermRef else child.reachableRawTypeRef val pat = Typed(untpd.Ident(nme.WILDCARD).withType(patType), TypeTree(patType)) CaseDef(pat, EmptyTree, Literal(Constant(idx))) } @@ -563,7 +563,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) { if (existing.exists && !existing.is(Deferred)) existing else { val monoType = - newSymbol(clazz, tpnme.MirroredMonoType, Synthetic, TypeAlias(linked.rawTypeRef), coord = clazz.coord) + newSymbol(clazz, tpnme.MirroredMonoType, Synthetic, TypeAlias(linked.reachableRawTypeRef), coord = clazz.coord) newBody = newBody :+ TypeDef(monoType).withSpan(ctx.owner.span.focus) monoType.entered } diff --git a/tests/pos/i10769.scala b/tests/pos/i10769.scala new file mode 100644 index 000000000000..2e097460b5bf --- /dev/null +++ b/tests/pos/i10769.scala @@ -0,0 +1,21 @@ +package stm + +trait STMLike[F[_]] { + import Internals._ + + sealed abstract class Txn[+A] {} + + object Txn { + def abort[A](e: Throwable): Txn[A] = Abort(e) + } + + object Internals { + case class Abort(error: Throwable) extends Txn[Nothing] + case object Noop extends Txn[Nothing] + } + + class Foo { + case class Abort(error: Throwable) extends Txn[Nothing] + case object Noop extends Txn[Nothing] + } +} From 67c3acf3514b50548a536200e648489605523ba0 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Wed, 6 Jan 2021 16:52:35 +0100 Subject: [PATCH 2/3] Add test case The first test ensures that the mirror is generated. The second test will not have mirrors generated. --- tests/pos/i10769.scala | 5 ----- tests/pos/i10769b.scala | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 tests/pos/i10769b.scala diff --git a/tests/pos/i10769.scala b/tests/pos/i10769.scala index 2e097460b5bf..5c63d2c807d0 100644 --- a/tests/pos/i10769.scala +++ b/tests/pos/i10769.scala @@ -13,9 +13,4 @@ trait STMLike[F[_]] { case class Abort(error: Throwable) extends Txn[Nothing] case object Noop extends Txn[Nothing] } - - class Foo { - case class Abort(error: Throwable) extends Txn[Nothing] - case object Noop extends Txn[Nothing] - } } diff --git a/tests/pos/i10769b.scala b/tests/pos/i10769b.scala new file mode 100644 index 000000000000..2e097460b5bf --- /dev/null +++ b/tests/pos/i10769b.scala @@ -0,0 +1,21 @@ +package stm + +trait STMLike[F[_]] { + import Internals._ + + sealed abstract class Txn[+A] {} + + object Txn { + def abort[A](e: Throwable): Txn[A] = Abort(e) + } + + object Internals { + case class Abort(error: Throwable) extends Txn[Nothing] + case object Noop extends Txn[Nothing] + } + + class Foo { + case class Abort(error: Throwable) extends Txn[Nothing] + case object Noop extends Txn[Nothing] + } +} From f81004922d85e942757cf01e4d9a91bd031f11e5 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Thu, 7 Jan 2021 18:15:06 +0100 Subject: [PATCH 3/3] Address review Co-authored-by: Guillaume Martres smarter@ubuntu.com --- .../src/dotty/tools/dotc/core/SymDenotations.scala | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index a647aec74423..12a1dc697cc4 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1410,7 +1410,8 @@ object SymDenotations { def namedType(using Context): NamedType = if (isType) typeRef else termRef - /** The typeRef where `pre.O$.this` is changed to `pre.O.type` if `O` is a non-static object + /** Like typeRef, but objects in the prefix are represented by their singleton type, + * this means we output `pre.O.member` rather than `pre.O$.this.member`. * * This is required to avoid owner crash in ExplicitOuter. * See tests/pos/i10769.scala @@ -1418,7 +1419,8 @@ object SymDenotations { def reachableTypeRef(using Context) = TypeRef(owner.reachableThisType, symbol) - /** The termRef where `pre.O$.this` is changed to `pre.O.type` if `O` is a non-static object + /** Like termRef, but objects in the prefix are represented by their singleton type, + * this means we output `pre.O.member` rather than `pre.O$.this.member`. * * This is required to avoid owner crash in ExplicitOuter. * See tests/pos/i10769.scala @@ -1426,7 +1428,9 @@ object SymDenotations { def reachableTermRef(using Context) = TermRef(owner.reachableThisType, symbol) - /** The thisType where `pre.O$.this` is changed to `pre.O.type` if `O` is a non-static object */ + /** Like thisType, but objects in the type are represented by their singleton type, + * this means we output `pre.O.member` rather than `pre.O$.this.member`. + */ def reachableThisType(using Context): Type = if this.is(Package) then symbol.thisType