Skip to content

Commit

Permalink
Avoid name clashes by prefixing all type members with Mirrored
Browse files Browse the repository at this point in the history
We got a community build failure since a companion object acquired
a `Label` type member by auto-generating a `Mirror` parent. To avoid
name clashes (or at least make thme very unlikely), we now systematically
prefix all type fields with  `Mirrored`.

We probably should do something similar to the auto-generated `ordinal`
and `fromProduct` methods.
  • Loading branch information
odersky committed May 22, 2019
1 parent 2a92bab commit efd3473
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 55 deletions.
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -330,20 +330,20 @@ object StdNames {
val Constant: N = "Constant"
val ConstantType: N = "ConstantType"
val doubleHash: N = "doubleHash"
val ElemLabels: N = "ElemLabels"
val ElemTypes: N = "ElemTypes"
val ExistentialTypeTree: N = "ExistentialTypeTree"
val Flag : N = "Flag"
val floatHash: N = "floatHash"
val Ident: N = "Ident"
val Import: N = "Import"
val Label: N = "Label"
val Literal: N = "Literal"
val LiteralAnnotArg: N = "LiteralAnnotArg"
val longHash: N = "longHash"
val MatchCase: N = "MatchCase"
val MirroredElemTypes: N = "MirroredElemTypes"
val MirroredElemLabels: N = "MirroredElemLabels"
val MirroredLabel: N = "MirroredLabel"
val MirroredMonoType: N = "MirroredMonoType"
val Modifiers: N = "Modifiers"
val MonoType: N = "MonoType"
val NestedAnnotArg: N = "NestedAnnotArg"
val NoFlags: N = "NoFlags"
val NoPrefix: N = "NoPrefix"
Expand Down
20 changes: 12 additions & 8 deletions compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -323,14 +323,14 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
* gets the `fromProduct` method:
*
* ```
* def fromProduct(x$0: Product): MonoType =
* def fromProduct(x$0: Product): MirroredMonoType =
* new C[U](
* x$0.productElement(0).asInstanceOf[U],
* x$0.productElement(1).asInstanceOf[Seq[String]]: _*)
* ```
* where
* ```
* type MonoType = C[_]
* type MirroredMonoType = C[_]
* ```
*/
def fromProductBody(caseClass: Symbol, param: Tree)(implicit ctx: Context): Tree = {
Expand Down Expand Up @@ -362,11 +362,11 @@ class SyntheticMembers(thisPhase: DenotTransformer) {

/** For an enum T:
*
* def ordinal(x: MonoType) = x.enumTag
* def ordinal(x: MirroredMonoType) = x.enumTag
*
* For sealed trait with children of normalized types C_1, ..., C_n:
*
* def ordinal(x: MonoType) = x match {
* def ordinal(x: MirroredMonoType) = x match {
* case _: C_1 => 0
* ...
* case _: C_n => n - 1
Expand All @@ -389,9 +389,13 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
}

/** - If `impl` is the companion of a generic sum, add `deriving.Mirror.Sum` parent
* and `MonoType` and `ordinal` members.
* and `MirroredMonoType` and `ordinal` members.
* - If `impl` is the companion of a generic product, add `deriving.Mirror.Product` parent
* and `MonoType` and `fromProduct` members.
* and `MirroredMonoType` and `fromProduct` members.
* - If `impl` is marked with one of the attachments ExtendsSingletonMirror, ExtendsProductMirror,
* or ExtendsSumMirror, remove the attachment and generate the corresponding mirror support,
* On this case the represented class or object is referred to in a pre-existing `MirroredMonoType`
* member of the template.
*/
def addMirrorSupport(impl: Template)(implicit ctx: Context): Template = {
val clazz = ctx.owner.asClass
Expand All @@ -415,11 +419,11 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
}
val linked = clazz.linkedClass
lazy val monoType = {
val existing = clazz.info.member(tpnme.MonoType).symbol
val existing = clazz.info.member(tpnme.MirroredMonoType).symbol
if (existing.exists && !existing.is(Deferred)) existing
else {
val monoType =
ctx.newSymbol(clazz, tpnme.MonoType, Synthetic, TypeAlias(linked.rawTypeRef), coord = clazz.coord)
ctx.newSymbol(clazz, tpnme.MirroredMonoType, Synthetic, TypeAlias(linked.rawTypeRef), coord = clazz.coord)
newBody = newBody :+ TypeDef(monoType).withSpan(ctx.owner.span.focus)
monoType.entered
}
Expand Down
28 changes: 14 additions & 14 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -815,11 +815,11 @@ trait Implicits { self: Typer =>
EmptyTree
}

/** Create an anonymous class `new Object { type MonoType = ... }`
/** Create an anonymous class `new Object { type MirroredMonoType = ... }`
* and mark it with given attachment so that it is made into a mirror at PostTyper.
*/
private def anonymousMirror(monoType: Type, attachment: Property.StickyKey[Unit], span: Span)(implicit ctx: Context) = {
val monoTypeDef = untpd.TypeDef(tpnme.MonoType, untpd.TypeTree(monoType))
val monoTypeDef = untpd.TypeDef(tpnme.MirroredMonoType, untpd.TypeTree(monoType))
val newImpl = untpd.Template(
constr = untpd.emptyConstructor,
parents = untpd.TypeTree(defn.ObjectType) :: Nil,
Expand All @@ -832,14 +832,14 @@ trait Implicits { self: Typer =>

/** The mirror type
*
* <parent> { MonoType = <monoType; Label = <label> }
* <parent> { MirroredMonoType = <monoType; MirroredLabel = <label> }
*/
private def mirrorCore(parent: Type, monoType: Type, label: Name)(implicit ctx: Context) =
parent
.refinedWith(tpnme.MonoType, TypeAlias(monoType))
.refinedWith(tpnme.Label, TypeAlias(ConstantType(Constant(label.toString))))
.refinedWith(tpnme.MirroredMonoType, TypeAlias(monoType))
.refinedWith(tpnme.MirroredLabel, TypeAlias(ConstantType(Constant(label.toString))))

/** An implied instance for a type of the form `Mirror.Product { type MonoType = T }`
/** An implied instance for a type of the form `Mirror.Product { type MirroredMonoType = T }`
* where `T` is a generic product type or a case object or an enum case.
*/
lazy val synthesizedProductMirror: SpecialHandler =
Expand Down Expand Up @@ -868,8 +868,8 @@ trait Implicits { self: Typer =>
val elemLabels = accessors.map(acc => ConstantType(Constant(acc.name.toString)))
val mirrorType =
mirrorCore(defn.Mirror_ProductType, monoType, cls.name)
.refinedWith(tpnme.ElemTypes, TypeAlias(TypeOps.nestedPairs(elemTypes)))
.refinedWith(tpnme.ElemLabels, TypeAlias(TypeOps.nestedPairs(elemLabels)))
.refinedWith(tpnme.MirroredElemTypes, TypeAlias(TypeOps.nestedPairs(elemTypes)))
.refinedWith(tpnme.MirroredElemLabels, TypeAlias(TypeOps.nestedPairs(elemLabels)))
val modul = cls.linkedClass.sourceModule
assert(modul.is(Module))
val mirrorRef =
Expand All @@ -879,18 +879,18 @@ trait Implicits { self: Typer =>
}
else EmptyTree
}
formal.member(tpnme.MonoType).info match {
formal.member(tpnme.MirroredMonoType).info match {
case monoAlias @ TypeAlias(monoType) => mirrorFor(monoType)
case _ => EmptyTree
}
}

/** An implied instance for a type of the form `Mirror.Sum { type MonoType = T }`
/** An implied instance for a type of the form `Mirror.Sum { type MirroredMonoType = T }`
* where `T` is a generic sum type.
*/
lazy val synthesizedSumMirror: SpecialHandler =
(formal: Type, span: Span) => implicit (ctx: Context) =>
formal.member(tpnme.MonoType).info match {
formal.member(tpnme.MirroredMonoType).info match {
case TypeAlias(monoType) if monoType.classSymbol.isGenericSum =>
val cls = monoType.classSymbol
val elemTypes = cls.children.map {
Expand Down Expand Up @@ -925,7 +925,7 @@ trait Implicits { self: Typer =>
}
val mirrorType =
mirrorCore(defn.Mirror_SumType, monoType, cls.name)
.refinedWith(tpnme.ElemTypes, TypeAlias(TypeOps.nestedPairs(elemTypes)))
.refinedWith(tpnme.MirroredElemTypes, TypeAlias(TypeOps.nestedPairs(elemTypes)))
val modul = cls.linkedClass.sourceModule
val mirrorRef =
if (modul.exists && !cls.is(Scala2x)) ref(modul).withSpan(span)
Expand All @@ -935,12 +935,12 @@ trait Implicits { self: Typer =>
EmptyTree
}

/** An implied instance for a type of the form `Mirror { type MonoType = T }`
/** An implied instance for a type of the form `Mirror { type MirroredMonoType = T }`
* where `T` is a generic sum or product or singleton type.
*/
lazy val synthesizedMirror: SpecialHandler =
(formal: Type, span: Span) => implicit (ctx: Context) =>
formal.member(tpnme.MonoType).info match {
formal.member(tpnme.MirroredMonoType).info match {
case monoAlias @ TypeAlias(monoType) =>
if (monoType.termSymbol.is(CaseVal) || monoType.classSymbol.isGenericProduct)
synthesizedProductMirror(formal, span)(ctx)
Expand Down
32 changes: 16 additions & 16 deletions library/src/scala/deriving.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ object deriving {
sealed trait Mirror {

/** The mirrored *-type */
type MonoType
type MirroredMonoType

/** The name of the type */
type Label <: String
type MirroredLabel <: String
}

object Mirror {
Expand All @@ -19,43 +19,43 @@ object deriving {
trait Sum extends Mirror { self =>

/** The types of the alternatives */
type ElemTypes <: Tuple
type MirroredElemTypes <: Tuple

/** The ordinal number of the case class of `x`. For enums, `ordinal(x) == x.ordinal` */
def ordinal(x: MonoType): Int
def ordinal(x: MirroredMonoType): Int
}

/** The Mirror for a product type */
trait Product extends Mirror {

/** The types of the product elements */
type ElemTypes <: Tuple
type MirroredElemTypes <: Tuple

/** The names of the product elements */
type ElemLabels <: Tuple
type MirroredElemLabels <: Tuple

/** Create a new instance of type `T` with elements taken from product `p`. */
def fromProduct(p: scala.Product): MonoType
def fromProduct(p: scala.Product): MirroredMonoType
}

trait Singleton extends Product {
type MonoType = this.type
type ElemTypes = Unit
type ElemLabels = Unit
type MirroredMonoType = this.type
type MirroredElemTypes = Unit
type MirroredElemLabels = Unit
def fromProduct(p: scala.Product) = this
}

/** A proxy for Scala 2 singletons, which do not inherit `Singleton` directly */
class SingletonProxy(val value: AnyRef) extends Product {
type MonoType = value.type
type ElemTypes = Unit
type ElemLabels = Unit
type MirroredMonoType = value.type
type MirroredElemTypes = Unit
type MirroredElemLabels = Unit
def fromProduct(p: scala.Product) = value
}

type Of[T] = Mirror { type MonoType = T }
type ProductOf[T] = Mirror.Product { type MonoType = T }
type SumOf[T] = Mirror.Sum { type MonoType = T }
type Of[T] = Mirror { type MirroredMonoType = T }
type ProductOf[T] = Mirror.Product { type MirroredMonoType = T }
type SumOf[T] = Mirror.Sum { type MirroredMonoType = T }
}

/** Helper class to turn arrays into products */
Expand Down
26 changes: 13 additions & 13 deletions tests/run/typeclass-derivation3.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ object typeclasses {
}

inline def eqlProduct[T](m: Mirror.ProductOf[T])(x: Any, y: Any): Boolean =
eqlElems[m.ElemTypes](0)(x, y)
eqlElems[m.MirroredElemTypes](0)(x, y)

inline def eqlCases[Alts](n: Int)(x: Any, y: Any, ord: Int): Boolean =
inline erasedValue[Alts] match {
case _: (alt *: alts1) =>
if (ord == n)
implicit match {
case m: Mirror.ProductOf[`alt`] => eqlElems[m.ElemTypes](0)(x, y)
case m: Mirror.ProductOf[`alt`] => eqlElems[m.MirroredElemTypes](0)(x, y)
}
else eqlCases[alts1](n + 1)(x, y, ord)
case _: Unit =>
Expand All @@ -65,9 +65,9 @@ object typeclasses {
inline ev match {
case m: Mirror.SumOf[T] =>
val ord = m.ordinal(x)
ord == m.ordinal(y) && eqlCases[m.ElemTypes](0)(x, y, ord)
ord == m.ordinal(y) && eqlCases[m.MirroredElemTypes](0)(x, y, ord)
case m: Mirror.ProductOf[T] =>
eqlElems[m.ElemTypes](0)(x, y)
eqlElems[m.MirroredElemTypes](0)(x, y)
}
}

Expand Down Expand Up @@ -106,7 +106,7 @@ object typeclasses {
case _: (alt *: alts1) =>
if (ord == n)
implicit match {
case m: Mirror.ProductOf[`alt`] => pickleElems[m.ElemTypes](0)(buf, x)
case m: Mirror.ProductOf[`alt`] => pickleElems[m.MirroredElemTypes](0)(buf, x)
}
else pickleCases[alts1](n + 1)(buf, x, ord)
case _: Unit =>
Expand Down Expand Up @@ -141,7 +141,7 @@ object typeclasses {
if (ord == n)
implicit match {
case m: Mirror.ProductOf[`alt` & T] =>
unpickleCase[`alt` & T, m.ElemTypes](buf, m)
unpickleCase[`alt` & T, m.MirroredElemTypes](buf, m)
}
else unpickleCases[T, alts1](n + 1)(buf, ord)
case _: Unit =>
Expand All @@ -154,17 +154,17 @@ object typeclasses {
case m: Mirror.SumOf[T] =>
val ord = m.ordinal(x)
buf += ord
pickleCases[m.ElemTypes](0)(buf, x, ord)
pickleCases[m.MirroredElemTypes](0)(buf, x, ord)
case m: Mirror.ProductOf[T] =>
pickleElems[m.ElemTypes](0)(buf, x)
pickleElems[m.MirroredElemTypes](0)(buf, x)
}
def unpickle(buf: mutable.ListBuffer[Int]): T =
inline ev match {
case m: Mirror.SumOf[T] =>
val ord = nextInt(buf)
unpickleCases[T, m.ElemTypes](0)(buf, ord)
unpickleCases[T, m.MirroredElemTypes](0)(buf, ord)
case m: Mirror.ProductOf[T] =>
unpickleCase[T, m.ElemTypes](buf, m)
unpickleCase[T, m.MirroredElemTypes](buf, m)
}
}

Expand Down Expand Up @@ -201,10 +201,10 @@ object typeclasses {
}

inline def showCase(x: Any, m: Mirror.ProductOf[_]): String = {
val label = constValue[m.Label]
val label = constValue[m.MirroredLabel]
inline m match {
case m: Mirror.Singleton => label
case _ => showElems[m.ElemTypes, m.ElemLabels](0)(x).mkString(s"$label(", ", ", ")")
case _ => showElems[m.MirroredElemTypes, m.MirroredElemLabels](0)(x).mkString(s"$label(", ", ", ")")
}
}

Expand All @@ -226,7 +226,7 @@ object typeclasses {
inline ev match {
case m: Mirror.SumOf[T] =>
val ord = m.ordinal(x)
showCases[m.ElemTypes](0)(x, ord)
showCases[m.MirroredElemTypes](0)(x, ord)
case m: Mirror.ProductOf[T] =>
showCase(x, m)
}
Expand Down

0 comments on commit efd3473

Please sign in to comment.