From 84732a5811228a966be3634aaf1d435661614c69 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Mon, 16 May 2022 12:57:31 +0200 Subject: [PATCH 1/4] support & in mirrorCompanionRef --- .../tools/dotc/transform/TypeUtils.scala | 5 +++++ tests/neg/i15190.scala | 17 +++++++++++++++++ tests/run/i15190.scala | 19 +++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 tests/neg/i15190.scala create mode 100644 tests/run/i15190.scala diff --git a/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala b/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala index 709635630254..c645f17945fd 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala @@ -92,6 +92,11 @@ object TypeUtils { val r2 = tp2.mirrorCompanionRef assert(r1.symbol == r2.symbol, em"mirrorCompanionRef mismatch for $self: $r1, $r2 did not have the same symbol") r1 + case AndType(tp1, tp2) => + val c1 = tp1.classSymbol + val c2 = tp2.classSymbol + if c1.isSubClass(c2) then tp1.mirrorCompanionRef + else tp2.mirrorCompanionRef // precondition: the parts of the AndType have already been checked to be non-overlapping case self @ TypeRef(prefix, _) if self.symbol.isClass => prefix.select(self.symbol.companionModule).asInstanceOf[TermRef] case self: TypeProxy => diff --git a/tests/neg/i15190.scala b/tests/neg/i15190.scala new file mode 100644 index 000000000000..8a0bb3aa9e17 --- /dev/null +++ b/tests/neg/i15190.scala @@ -0,0 +1,17 @@ +import scala.deriving.Mirror + +trait Mixin +object Mixin + +trait Parent +object Parent + +sealed trait Fruit extends Parent +object Fruit { + case object Apple extends Fruit + case object Orange extends Fruit +} + +@main def Test = { + summon[Mirror.SumOf[Fruit & Mixin]] // error: not a sum type +} diff --git a/tests/run/i15190.scala b/tests/run/i15190.scala new file mode 100644 index 000000000000..09b7a0c1edc8 --- /dev/null +++ b/tests/run/i15190.scala @@ -0,0 +1,19 @@ +import scala.deriving.Mirror + +trait Mixin +object Mixin + +trait Parent +object Parent + +sealed trait Fruit extends Parent +object Fruit { + case object Apple extends Fruit + case object Orange extends Fruit +} + +@main def Test = { + val mFruit = summon[Mirror.SumOf[Fruit & Parent]] + assert(mFruit.ordinal(Fruit.Apple) == 0) + assert(mFruit.ordinal(Fruit.Orange) == 1) +} From 1cbaf7e72dde2e2457dc85427bf354ed6fb886ea Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Mon, 30 May 2022 14:02:09 +0200 Subject: [PATCH 2/4] remove AndType branch in productMirror remove case: OrType is no longer supported --- .../tools/dotc/transform/TypeUtils.scala | 5 - .../dotty/tools/dotc/typer/Synthesizer.scala | 129 +++++++++++------- tests/neg/mirror-synthesis-errors-b.check | 28 ++++ tests/neg/mirror-synthesis-errors-b.scala | 16 +++ 4 files changed, 126 insertions(+), 52 deletions(-) create mode 100644 tests/neg/mirror-synthesis-errors-b.check create mode 100644 tests/neg/mirror-synthesis-errors-b.scala diff --git a/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala b/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala index c645f17945fd..fba81fec632c 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeUtils.scala @@ -87,11 +87,6 @@ object TypeUtils { * of this type, while keeping the same prefix. */ def mirrorCompanionRef(using Context): TermRef = self match { - case OrType(tp1, tp2) => - val r1 = tp1.mirrorCompanionRef - val r2 = tp2.mirrorCompanionRef - assert(r1.symbol == r2.symbol, em"mirrorCompanionRef mismatch for $self: $r1, $r2 did not have the same symbol") - r1 case AndType(tp1, tp2) => val c1 = tp1.classSymbol val c2 = tp2.classSymbol diff --git a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala index baa4ef57acd3..8e298b5f2815 100644 --- a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala @@ -276,16 +276,72 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): case t => mapOver(t) monoMap(mirroredType.resultType) - private def productMirror(mirroredType: Type, formal: Type, span: Span)(using Context): TreeWithErrors = + private[Synthesizer] enum MirrorSource: + case ClassSymbol(cls: Symbol) + case Singleton(tref: TermRef) + + def isSub(that: MirrorSource)(using Context): Boolean = + (this, that) match + case (Singleton(tref), ClassSymbol(cls)) => tref.classSymbol.isSubClass(cls) + case (ClassSymbol(cls1), ClassSymbol(cls2)) => cls1.isSubClass(cls2) + case _ => false // includes that a class is never sub of a singleton + + def debug(using Context): String = this match + case ClassSymbol(cls) => i"$cls" + case Singleton(tref) => i"${tref.termSymbol}" + + object MirrorSource: + def cls(cls: Symbol): MirrorSource = ClassSymbol(cls) + def singleton(tref: TermRef): MirrorSource = Singleton(tref) + + /** widen TermRef to see if they are an alias to an enum singleton or case object */ + private def isEnumOrCaseObjectRef(tp: Type)(using Context): Boolean = tp match + case tp: TermRef => + val sym = tp.termSymbol - def whyNotAcceptableType(tp: Type, cls: Symbol): String = tp match + sym.isEnumCase + || (sym.isClass && sym.isAllOf(Case | Module)) + || (!tp.isOverloaded && isEnumOrCaseObjectRef(tp.underlying.widenExpr)) + case _ => false + + /** A customised version of `Types.classSymbol`, specialised for mirror generation. */ + def reduce(mirroredType: Type)(using Context): Either[String, MirrorSource] = mirroredType match + case tp: TypeRef => + val sym = tp.symbol + if sym.isClass then // direct ref to a class, not an alias + if sym.isAllOf(Case | Module) then + Right(MirrorSource.singleton(sym.sourceModule.reachableTermRef)) // correct widened module ref + else + Right(MirrorSource.cls(sym)) + else + reduce(tp.superType) + case tp: TermRef if isEnumOrCaseObjectRef(tp) => + Right(MirrorSource.singleton(tp)) case tp: HKTypeLambda if tp.resultType.isInstanceOf[HKTypeLambda] => - i"its subpart `$tp` is not a supported kind (either `*` or `* -> *`)" - case tp: TypeProxy => whyNotAcceptableType(tp.underlying, cls) - case OrType(tp1, tp2) => i"its subpart `$tp` is a top-level union type." - case _ => - if tp.classSymbol eq cls then "" - else i"a subpart reduces to the more precise ${tp.classSymbol}, expected $cls" + Left(i"its subpart `$tp` is not a supported kind (either `*` or `* -> *`)") + case tp: TypeProxy => + reduce(tp.underlying) + case tp: ClassInfo => + Right(MirrorSource.cls(tp.cls)) + case tp @ AndType(l, r) => + for + lsrc <- reduce(l) + rsrc <- reduce(r) + res <- locally { + if lsrc.isSub(rsrc) then Right(lsrc) + else if rsrc.isSub(lsrc) then Right(rsrc) + else Left(i"its subpart `$tp` is an intersection of unrelated symbols ${lsrc.debug} and ${rsrc.debug}.") + } + yield + res + case tp: OrType => + Left(i"its subpart `$tp` is a top-level union type.") + case tp => + Left(i"its subpart `$tp` is an unsupported type.") + + end MirrorSource + + private def productMirror(mirroredType: Type, formal: Type, span: Span)(using Context): TreeWithErrors = def makeProductMirror(cls: Symbol): TreeWithErrors = val accessors = cls.caseAccessors.filterNot(_.isAllOf(PrivateLocal)) @@ -309,55 +365,34 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): withNoErrors(mirrorRef.cast(mirrorType)) end makeProductMirror - /** widen TermRef to see if they are an alias to an enum singleton */ - def isEnumSingletonRef(tp: Type)(using Context): Boolean = tp match - case tp: TermRef => - val sym = tp.termSymbol - sym.isEnumCase || (!tp.isOverloaded && isEnumSingletonRef(tp.underlying.widenExpr)) - case _ => false - - mirroredType match - case AndType(tp1, tp2) => - orElse(productMirror(tp1, formal, span), productMirror(tp2, formal, span)) - case _ => - val cls = mirroredType.classSymbol - if isEnumSingletonRef(mirroredType) || cls.isAllOf(Case | Module) then - val (singleton, singletonRef) = - if mirroredType.termSymbol.exists then (mirroredType.termSymbol, mirroredType) - else (cls.sourceModule, cls.sourceModule.reachableTermRef) - val singletonPath = pathFor(singletonRef).withSpan(span) - if singleton.info.classSymbol.is(Scala2x) then // could be Scala 3 alias of Scala 2 case object. - val mirrorType = mirrorCore(defn.Mirror_SingletonProxyClass, mirroredType, mirroredType, singleton.name, formal) + MirrorSource.reduce(mirroredType) match + case Right(msrc) => msrc match + case MirrorSource.Singleton(tref) => + val singleton = tref.termSymbol + val singletonPath = pathFor(tref).withSpan(span) + if tref.classSymbol.is(Scala2x) then // could be Scala 3 alias of Scala 2 case object. + val mirrorType = + mirrorCore(defn.Mirror_SingletonProxyClass, mirroredType, mirroredType, singleton.name, formal) val mirrorRef = New(defn.Mirror_SingletonProxyClass.typeRef, singletonPath :: Nil) withNoErrors(mirrorRef.cast(mirrorType)) else val mirrorType = mirrorCore(defn.Mirror_SingletonClass, mirroredType, mirroredType, singleton.name, formal) withNoErrors(singletonPath.cast(mirrorType)) - else - val acceptableMsg = whyNotAcceptableType(mirroredType, cls) - if acceptableMsg.isEmpty then - if cls.isGenericProduct then makeProductMirror(cls) - else withErrors(i"$cls is not a generic product because ${cls.whyNotGenericProduct}") - else withErrors(i"type `$mirroredType` is not a generic product because $acceptableMsg") + case MirrorSource.ClassSymbol(cls) => + if cls.isGenericProduct then makeProductMirror(cls) + else withErrors(i"$cls is not a generic product because ${cls.whyNotGenericProduct}") + case Left(msg) => + withErrors(i"type `$mirroredType` is not a generic product because $msg") end productMirror private def sumMirror(mirroredType: Type, formal: Type, span: Span)(using Context): TreeWithErrors = - val cls = mirroredType.classSymbol - val clsIsGenericSum = cls.isGenericSum - - def whyNotAcceptableType(tp: Type): String = tp match - case tp: TermRef => i"its subpart `$tp` is a term reference" - case tp: HKTypeLambda if tp.resultType.isInstanceOf[HKTypeLambda] => - i"its subpart `$tp` is not a supported kind (either `*` or `* -> *`)" - case tp: TypeProxy => whyNotAcceptableType(tp.underlying) - case OrType(tp1, tp2) => i"its subpart `$tp` is a top-level union type." - case _ => - if tp.classSymbol eq cls then "" - else i"a subpart reduces to the more precise ${tp.classSymbol}, expected $cls" - + val (acceptableMsg, cls) = MirrorSource.reduce(mirroredType) match + case Right(MirrorSource.Singleton(tp)) => (i"its subpart `$tp` is a term reference", NoSymbol) + case Right(MirrorSource.ClassSymbol(cls)) => ("", cls) + case Left(msg) => (msg, NoSymbol) - val acceptableMsg = whyNotAcceptableType(mirroredType) + val clsIsGenericSum = cls.isGenericSum if acceptableMsg.isEmpty && clsIsGenericSum then val elemLabels = cls.children.map(c => ConstantType(Constant(c.name.toString))) diff --git a/tests/neg/mirror-synthesis-errors-b.check b/tests/neg/mirror-synthesis-errors-b.check new file mode 100644 index 000000000000..57a9aa12651e --- /dev/null +++ b/tests/neg/mirror-synthesis-errors-b.check @@ -0,0 +1,28 @@ +-- Error: tests/neg/mirror-synthesis-errors-b.scala:11:56 -------------------------------------------------------------- +11 |val testA = summon[Mirror.ProductOf[Cns[Int] & Sm[Int]]] // error: unreleated + | ^ + |No given instance of type deriving.Mirror.ProductOf[Cns[Int] & Sm[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Cns[Int] & Sm[Int]]: type `Cns[Int] & Sm[Int]` is not a generic product because its subpart `Cns[Int] & Sm[Int]` is an intersection of unrelated symbols class Cns and class Sm. +-- Error: tests/neg/mirror-synthesis-errors-b.scala:12:56 -------------------------------------------------------------- +12 |val testB = summon[Mirror.ProductOf[Sm[Int] & Cns[Int]]] // error: unreleated + | ^ + |No given instance of type deriving.Mirror.ProductOf[Sm[Int] & Cns[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Sm[Int] & Cns[Int]]: type `Sm[Int] & Cns[Int]` is not a generic product because its subpart `Sm[Int] & Cns[Int]` is an intersection of unrelated symbols class Sm and class Cns. +-- Error: tests/neg/mirror-synthesis-errors-b.scala:13:49 -------------------------------------------------------------- +13 |val testC = summon[Mirror.Of[Cns[Int] & Sm[Int]]] // error: unreleated + | ^ + |No given instance of type deriving.Mirror.Of[Cns[Int] & Sm[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.Of[Cns[Int] & Sm[Int]]: + | * type `Cns[Int] & Sm[Int]` is not a generic product because its subpart `Cns[Int] & Sm[Int]` is an intersection of unrelated symbols class Cns and class Sm. + | * type `Cns[Int] & Sm[Int]` is not a generic sum because its subpart `Cns[Int] & Sm[Int]` is an intersection of unrelated symbols class Cns and class Sm. +-- Error: tests/neg/mirror-synthesis-errors-b.scala:14:49 -------------------------------------------------------------- +14 |val testD = summon[Mirror.Of[Sm[Int] & Cns[Int]]] // error: unreleated + | ^ + |No given instance of type deriving.Mirror.Of[Sm[Int] & Cns[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.Of[Sm[Int] & Cns[Int]]: + | * type `Sm[Int] & Cns[Int]` is not a generic product because its subpart `Sm[Int] & Cns[Int]` is an intersection of unrelated symbols class Sm and class Cns. + | * type `Sm[Int] & Cns[Int]` is not a generic sum because its subpart `Sm[Int] & Cns[Int]` is an intersection of unrelated symbols class Sm and class Cns. +-- Error: tests/neg/mirror-synthesis-errors-b.scala:15:55 -------------------------------------------------------------- +15 |val testE = summon[Mirror.ProductOf[Sm[Int] & Nn.type]] // error: unreleated + | ^ + |No given instance of type deriving.Mirror.ProductOf[Sm[Int] & Nn.type] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Sm[Int] & Nn.type]: type `Sm[Int] & Nn.type` is not a generic product because its subpart `Sm[Int] & Nn.type` is an intersection of unrelated symbols class Sm and object Nn. +-- Error: tests/neg/mirror-synthesis-errors-b.scala:16:55 -------------------------------------------------------------- +16 |val testF = summon[Mirror.ProductOf[Nn.type & Sm[Int]]] // error: unreleated + | ^ + |No given instance of type deriving.Mirror.ProductOf[Nn.type & Sm[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Nn.type & Sm[Int]]: type `Nn.type & Sm[Int]` is not a generic product because its subpart `Nn.type & Sm[Int]` is an intersection of unrelated symbols object Nn and class Sm. diff --git a/tests/neg/mirror-synthesis-errors-b.scala b/tests/neg/mirror-synthesis-errors-b.scala new file mode 100644 index 000000000000..a0d76ddfe5c0 --- /dev/null +++ b/tests/neg/mirror-synthesis-errors-b.scala @@ -0,0 +1,16 @@ +import scala.deriving.Mirror + +sealed trait Lst[+A] // AKA: scala.collection.immutable.List +case class Cns[+A](head: A, tail: Lst[A]) extends Lst[A] +case object Nl extends Lst[Nothing] + +sealed trait Opt[+A] // AKA: scala.Option +case class Sm[+A](value: A) extends Opt[A] +case object Nn extends Opt[Nothing] + +val testA = summon[Mirror.ProductOf[Cns[Int] & Sm[Int]]] // error: unreleated +val testB = summon[Mirror.ProductOf[Sm[Int] & Cns[Int]]] // error: unreleated +val testC = summon[Mirror.Of[Cns[Int] & Sm[Int]]] // error: unreleated +val testD = summon[Mirror.Of[Sm[Int] & Cns[Int]]] // error: unreleated +val testE = summon[Mirror.ProductOf[Sm[Int] & Nn.type]] // error: unreleated +val testF = summon[Mirror.ProductOf[Nn.type & Sm[Int]]] // error: unreleated From 3ea6b24deec8ec76f81820af4a494cdb0975caff Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Mon, 30 May 2022 16:16:46 +0200 Subject: [PATCH 3/4] test more intersections of singletons --- .../dotty/tools/dotc/typer/Synthesizer.scala | 63 +++++++++++-------- tests/neg/mirror-synthesis-errors-b.check | 36 +++++++---- tests/neg/mirror-synthesis-errors-b.scala | 16 +++++ tests/run/i15234.scala | 1 - 4 files changed, 77 insertions(+), 39 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala index 8e298b5f2815..623f2e44071e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala @@ -278,51 +278,62 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): private[Synthesizer] enum MirrorSource: case ClassSymbol(cls: Symbol) - case Singleton(tref: TermRef) + case Singleton(src: Symbol, tref: TermRef) + /** A comparison that chooses the most specific MirrorSource, this is guided by what is necessary for + * `Mirror.Product.fromProduct`. i.e. its result type should be compatible with the erasure of `mirroredType`. + */ def isSub(that: MirrorSource)(using Context): Boolean = (this, that) match - case (Singleton(tref), ClassSymbol(cls)) => tref.classSymbol.isSubClass(cls) + case (Singleton(src, _), ClassSymbol(cls)) => src.info.classSymbol.isSubClass(cls) case (ClassSymbol(cls1), ClassSymbol(cls2)) => cls1.isSubClass(cls2) - case _ => false // includes that a class is never sub of a singleton + case (Singleton(src1, _), Singleton(src2, _)) => src1 eq src2 + case (_: ClassSymbol, _: Singleton) => false def debug(using Context): String = this match case ClassSymbol(cls) => i"$cls" - case Singleton(tref) => i"${tref.termSymbol}" + case Singleton(src, _) => i"$src" object MirrorSource: - def cls(cls: Symbol): MirrorSource = ClassSymbol(cls) - def singleton(tref: TermRef): MirrorSource = Singleton(tref) - - /** widen TermRef to see if they are an alias to an enum singleton or case object */ - private def isEnumOrCaseObjectRef(tp: Type)(using Context): Boolean = tp match - case tp: TermRef => - val sym = tp.termSymbol - - sym.isEnumCase - || (sym.isClass && sym.isAllOf(Case | Module)) - || (!tp.isOverloaded && isEnumOrCaseObjectRef(tp.underlying.widenExpr)) - case _ => false - /** A customised version of `Types.classSymbol`, specialised for mirror generation. */ + /** Reduces a mirroredType to either its most specific ClassSymbol, + * or a TermRef to a singleton value, these are + * the base elements required to generate a mirror. + */ def reduce(mirroredType: Type)(using Context): Either[String, MirrorSource] = mirroredType match case tp: TypeRef => val sym = tp.symbol if sym.isClass then // direct ref to a class, not an alias if sym.isAllOf(Case | Module) then - Right(MirrorSource.singleton(sym.sourceModule.reachableTermRef)) // correct widened module ref + // correct widened module ref. Tested in tests/run/i15234.scala + val singleton = sym.sourceModule + Right(MirrorSource.Singleton(singleton, TermRef(tp.prefix, singleton))) else - Right(MirrorSource.cls(sym)) + Right(MirrorSource.ClassSymbol(sym)) else reduce(tp.superType) - case tp: TermRef if isEnumOrCaseObjectRef(tp) => - Right(MirrorSource.singleton(tp)) + case tp: TermRef => + /** Dealias a path type to extract the underlying definition when it is either + * a singleton enum case or a case object. + */ + def reduceToEnumOrCaseObject(tp: Type)(using Context): Symbol = tp match + case tp: TermRef => + val sym = tp.termSymbol + if sym.isEnumCase || (sym.isClass && sym.isAllOf(Case | Module)) then sym + else if sym.exists && !tp.isOverloaded then reduceToEnumOrCaseObject(tp.underlying.widenExpr) + else NoSymbol + case _ => NoSymbol + + // capture enum singleton types. Tested in tests/run/i15234.scala + val singleton = reduceToEnumOrCaseObject(tp) + if singleton.exists then + Right(MirrorSource.Singleton(singleton, tp)) + else + reduce(tp.underlying) case tp: HKTypeLambda if tp.resultType.isInstanceOf[HKTypeLambda] => Left(i"its subpart `$tp` is not a supported kind (either `*` or `* -> *`)") case tp: TypeProxy => reduce(tp.underlying) - case tp: ClassInfo => - Right(MirrorSource.cls(tp.cls)) case tp @ AndType(l, r) => for lsrc <- reduce(l) @@ -367,8 +378,8 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): MirrorSource.reduce(mirroredType) match case Right(msrc) => msrc match - case MirrorSource.Singleton(tref) => - val singleton = tref.termSymbol + case MirrorSource.Singleton(_, tref) => + val singleton = tref.termSymbol // prefer alias name over the orignal name val singletonPath = pathFor(tref).withSpan(span) if tref.classSymbol.is(Scala2x) then // could be Scala 3 alias of Scala 2 case object. val mirrorType = @@ -388,7 +399,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): private def sumMirror(mirroredType: Type, formal: Type, span: Span)(using Context): TreeWithErrors = val (acceptableMsg, cls) = MirrorSource.reduce(mirroredType) match - case Right(MirrorSource.Singleton(tp)) => (i"its subpart `$tp` is a term reference", NoSymbol) + case Right(MirrorSource.Singleton(_, tp)) => (i"its subpart `$tp` is a term reference", NoSymbol) case Right(MirrorSource.ClassSymbol(cls)) => ("", cls) case Left(msg) => (msg, NoSymbol) diff --git a/tests/neg/mirror-synthesis-errors-b.check b/tests/neg/mirror-synthesis-errors-b.check index 57a9aa12651e..141e5bc99cf0 100644 --- a/tests/neg/mirror-synthesis-errors-b.check +++ b/tests/neg/mirror-synthesis-errors-b.check @@ -1,28 +1,40 @@ --- Error: tests/neg/mirror-synthesis-errors-b.scala:11:56 -------------------------------------------------------------- -11 |val testA = summon[Mirror.ProductOf[Cns[Int] & Sm[Int]]] // error: unreleated +-- Error: tests/neg/mirror-synthesis-errors-b.scala:21:56 -------------------------------------------------------------- +21 |val testA = summon[Mirror.ProductOf[Cns[Int] & Sm[Int]]] // error: unreleated | ^ |No given instance of type deriving.Mirror.ProductOf[Cns[Int] & Sm[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Cns[Int] & Sm[Int]]: type `Cns[Int] & Sm[Int]` is not a generic product because its subpart `Cns[Int] & Sm[Int]` is an intersection of unrelated symbols class Cns and class Sm. --- Error: tests/neg/mirror-synthesis-errors-b.scala:12:56 -------------------------------------------------------------- -12 |val testB = summon[Mirror.ProductOf[Sm[Int] & Cns[Int]]] // error: unreleated +-- Error: tests/neg/mirror-synthesis-errors-b.scala:22:56 -------------------------------------------------------------- +22 |val testB = summon[Mirror.ProductOf[Sm[Int] & Cns[Int]]] // error: unreleated | ^ |No given instance of type deriving.Mirror.ProductOf[Sm[Int] & Cns[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Sm[Int] & Cns[Int]]: type `Sm[Int] & Cns[Int]` is not a generic product because its subpart `Sm[Int] & Cns[Int]` is an intersection of unrelated symbols class Sm and class Cns. --- Error: tests/neg/mirror-synthesis-errors-b.scala:13:49 -------------------------------------------------------------- -13 |val testC = summon[Mirror.Of[Cns[Int] & Sm[Int]]] // error: unreleated +-- Error: tests/neg/mirror-synthesis-errors-b.scala:23:49 -------------------------------------------------------------- +23 |val testC = summon[Mirror.Of[Cns[Int] & Sm[Int]]] // error: unreleated | ^ |No given instance of type deriving.Mirror.Of[Cns[Int] & Sm[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.Of[Cns[Int] & Sm[Int]]: | * type `Cns[Int] & Sm[Int]` is not a generic product because its subpart `Cns[Int] & Sm[Int]` is an intersection of unrelated symbols class Cns and class Sm. | * type `Cns[Int] & Sm[Int]` is not a generic sum because its subpart `Cns[Int] & Sm[Int]` is an intersection of unrelated symbols class Cns and class Sm. --- Error: tests/neg/mirror-synthesis-errors-b.scala:14:49 -------------------------------------------------------------- -14 |val testD = summon[Mirror.Of[Sm[Int] & Cns[Int]]] // error: unreleated +-- Error: tests/neg/mirror-synthesis-errors-b.scala:24:49 -------------------------------------------------------------- +24 |val testD = summon[Mirror.Of[Sm[Int] & Cns[Int]]] // error: unreleated | ^ |No given instance of type deriving.Mirror.Of[Sm[Int] & Cns[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.Of[Sm[Int] & Cns[Int]]: | * type `Sm[Int] & Cns[Int]` is not a generic product because its subpart `Sm[Int] & Cns[Int]` is an intersection of unrelated symbols class Sm and class Cns. | * type `Sm[Int] & Cns[Int]` is not a generic sum because its subpart `Sm[Int] & Cns[Int]` is an intersection of unrelated symbols class Sm and class Cns. --- Error: tests/neg/mirror-synthesis-errors-b.scala:15:55 -------------------------------------------------------------- -15 |val testE = summon[Mirror.ProductOf[Sm[Int] & Nn.type]] // error: unreleated +-- Error: tests/neg/mirror-synthesis-errors-b.scala:25:55 -------------------------------------------------------------- +25 |val testE = summon[Mirror.ProductOf[Sm[Int] & Nn.type]] // error: unreleated | ^ |No given instance of type deriving.Mirror.ProductOf[Sm[Int] & Nn.type] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Sm[Int] & Nn.type]: type `Sm[Int] & Nn.type` is not a generic product because its subpart `Sm[Int] & Nn.type` is an intersection of unrelated symbols class Sm and object Nn. --- Error: tests/neg/mirror-synthesis-errors-b.scala:16:55 -------------------------------------------------------------- -16 |val testF = summon[Mirror.ProductOf[Nn.type & Sm[Int]]] // error: unreleated +-- Error: tests/neg/mirror-synthesis-errors-b.scala:26:55 -------------------------------------------------------------- +26 |val testF = summon[Mirror.ProductOf[Nn.type & Sm[Int]]] // error: unreleated | ^ |No given instance of type deriving.Mirror.ProductOf[Nn.type & Sm[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Nn.type & Sm[Int]]: type `Nn.type & Sm[Int]` is not a generic product because its subpart `Nn.type & Sm[Int]` is an intersection of unrelated symbols object Nn and class Sm. +-- Error: tests/neg/mirror-synthesis-errors-b.scala:27:54 -------------------------------------------------------------- +27 |val testG = summon[Mirror.Of[Foo.A.type & Foo.B.type]] // error: unreleated + | ^ + |No given instance of type deriving.Mirror.Of[(Foo.A : Foo) & (Foo.B : Foo)] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.Of[(Foo.A : Foo) & (Foo.B : Foo)]: + | * type `(Foo.A : Foo) & (Foo.B : Foo)` is not a generic product because its subpart `(Foo.A : Foo) & (Foo.B : Foo)` is an intersection of unrelated symbols value A and value B. + | * type `(Foo.A : Foo) & (Foo.B : Foo)` is not a generic sum because its subpart `(Foo.A : Foo) & (Foo.B : Foo)` is an intersection of unrelated symbols value A and value B. +-- Error: tests/neg/mirror-synthesis-errors-b.scala:28:54 -------------------------------------------------------------- +28 |val testH = summon[Mirror.Of[Foo.B.type & Foo.A.type]] // error: unreleated + | ^ + |No given instance of type deriving.Mirror.Of[(Foo.B : Foo) & (Foo.A : Foo)] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.Of[(Foo.B : Foo) & (Foo.A : Foo)]: + | * type `(Foo.B : Foo) & (Foo.A : Foo)` is not a generic product because its subpart `(Foo.B : Foo) & (Foo.A : Foo)` is an intersection of unrelated symbols value B and value A. + | * type `(Foo.B : Foo) & (Foo.A : Foo)` is not a generic sum because its subpart `(Foo.B : Foo) & (Foo.A : Foo)` is an intersection of unrelated symbols value B and value A. diff --git a/tests/neg/mirror-synthesis-errors-b.scala b/tests/neg/mirror-synthesis-errors-b.scala index a0d76ddfe5c0..620bd4a8c278 100644 --- a/tests/neg/mirror-synthesis-errors-b.scala +++ b/tests/neg/mirror-synthesis-errors-b.scala @@ -8,9 +8,25 @@ sealed trait Opt[+A] // AKA: scala.Option case class Sm[+A](value: A) extends Opt[A] case object Nn extends Opt[Nothing] +enum Foo: + case A, B + +object Bar: + val A: Foo.A.type = Foo.A // alias of Foo.A + type A = Foo.A.type // type alias + +case object Baz +type Baz = Baz.type + val testA = summon[Mirror.ProductOf[Cns[Int] & Sm[Int]]] // error: unreleated val testB = summon[Mirror.ProductOf[Sm[Int] & Cns[Int]]] // error: unreleated val testC = summon[Mirror.Of[Cns[Int] & Sm[Int]]] // error: unreleated val testD = summon[Mirror.Of[Sm[Int] & Cns[Int]]] // error: unreleated val testE = summon[Mirror.ProductOf[Sm[Int] & Nn.type]] // error: unreleated val testF = summon[Mirror.ProductOf[Nn.type & Sm[Int]]] // error: unreleated +val testG = summon[Mirror.Of[Foo.A.type & Foo.B.type]] // error: unreleated +val testH = summon[Mirror.Of[Foo.B.type & Foo.A.type]] // error: unreleated +val testI = summon[Mirror.Of[Foo.A.type & Bar.A.type]] // ok +val testJ = summon[Mirror.Of[Bar.A.type & Foo.A.type]] // ok +val testK = summon[Mirror.Of[Foo.A.type & Bar.A.type & Bar.A]] // ok +val testL = summon[Mirror.Of[Baz & Baz.type]] // ok diff --git a/tests/run/i15234.scala b/tests/run/i15234.scala index 28495e9d011e..650a4974a63e 100644 --- a/tests/run/i15234.scala +++ b/tests/run/i15234.scala @@ -13,7 +13,6 @@ package app { val Bar: lib.Bar.type = lib.Bar } - @main def Test = assert(summon[Mirror.Of[scala.Nil.type]].fromProduct(EmptyTuple) == Nil) // alias scala 2 defined assert(summon[Mirror.Of[lib.Foo.A.type]].fromProduct(EmptyTuple) == lib.Foo.A) // real mirror From 02ed36ce23c79a090b39644329079fd823f38c5c Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Mon, 30 May 2022 17:17:01 +0200 Subject: [PATCH 4/4] address review comments --- .../dotty/tools/dotc/typer/Synthesizer.scala | 8 +++---- tests/neg/mirror-synthesis-errors-b.check | 24 +++++++++---------- tests/run/i15234.scala | 1 + 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala index 623f2e44071e..1267000d9733 100644 --- a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala @@ -290,14 +290,14 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): case (Singleton(src1, _), Singleton(src2, _)) => src1 eq src2 case (_: ClassSymbol, _: Singleton) => false - def debug(using Context): String = this match + def show(using Context): String = this match case ClassSymbol(cls) => i"$cls" case Singleton(src, _) => i"$src" - object MirrorSource: + private[Synthesizer] object MirrorSource: /** Reduces a mirroredType to either its most specific ClassSymbol, - * or a TermRef to a singleton value, these are + * or a TermRef to a singleton value. These are * the base elements required to generate a mirror. */ def reduce(mirroredType: Type)(using Context): Either[String, MirrorSource] = mirroredType match @@ -341,7 +341,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): res <- locally { if lsrc.isSub(rsrc) then Right(lsrc) else if rsrc.isSub(lsrc) then Right(rsrc) - else Left(i"its subpart `$tp` is an intersection of unrelated symbols ${lsrc.debug} and ${rsrc.debug}.") + else Left(i"its subpart `$tp` is an intersection of unrelated definitions ${lsrc.show} and ${rsrc.show}.") } yield res diff --git a/tests/neg/mirror-synthesis-errors-b.check b/tests/neg/mirror-synthesis-errors-b.check index 141e5bc99cf0..ea41d14da296 100644 --- a/tests/neg/mirror-synthesis-errors-b.check +++ b/tests/neg/mirror-synthesis-errors-b.check @@ -1,40 +1,40 @@ -- Error: tests/neg/mirror-synthesis-errors-b.scala:21:56 -------------------------------------------------------------- 21 |val testA = summon[Mirror.ProductOf[Cns[Int] & Sm[Int]]] // error: unreleated | ^ - |No given instance of type deriving.Mirror.ProductOf[Cns[Int] & Sm[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Cns[Int] & Sm[Int]]: type `Cns[Int] & Sm[Int]` is not a generic product because its subpart `Cns[Int] & Sm[Int]` is an intersection of unrelated symbols class Cns and class Sm. + |No given instance of type deriving.Mirror.ProductOf[Cns[Int] & Sm[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Cns[Int] & Sm[Int]]: type `Cns[Int] & Sm[Int]` is not a generic product because its subpart `Cns[Int] & Sm[Int]` is an intersection of unrelated definitions class Cns and class Sm. -- Error: tests/neg/mirror-synthesis-errors-b.scala:22:56 -------------------------------------------------------------- 22 |val testB = summon[Mirror.ProductOf[Sm[Int] & Cns[Int]]] // error: unreleated | ^ - |No given instance of type deriving.Mirror.ProductOf[Sm[Int] & Cns[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Sm[Int] & Cns[Int]]: type `Sm[Int] & Cns[Int]` is not a generic product because its subpart `Sm[Int] & Cns[Int]` is an intersection of unrelated symbols class Sm and class Cns. + |No given instance of type deriving.Mirror.ProductOf[Sm[Int] & Cns[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Sm[Int] & Cns[Int]]: type `Sm[Int] & Cns[Int]` is not a generic product because its subpart `Sm[Int] & Cns[Int]` is an intersection of unrelated definitions class Sm and class Cns. -- Error: tests/neg/mirror-synthesis-errors-b.scala:23:49 -------------------------------------------------------------- 23 |val testC = summon[Mirror.Of[Cns[Int] & Sm[Int]]] // error: unreleated | ^ |No given instance of type deriving.Mirror.Of[Cns[Int] & Sm[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.Of[Cns[Int] & Sm[Int]]: - | * type `Cns[Int] & Sm[Int]` is not a generic product because its subpart `Cns[Int] & Sm[Int]` is an intersection of unrelated symbols class Cns and class Sm. - | * type `Cns[Int] & Sm[Int]` is not a generic sum because its subpart `Cns[Int] & Sm[Int]` is an intersection of unrelated symbols class Cns and class Sm. + | * type `Cns[Int] & Sm[Int]` is not a generic product because its subpart `Cns[Int] & Sm[Int]` is an intersection of unrelated definitions class Cns and class Sm. + | * type `Cns[Int] & Sm[Int]` is not a generic sum because its subpart `Cns[Int] & Sm[Int]` is an intersection of unrelated definitions class Cns and class Sm. -- Error: tests/neg/mirror-synthesis-errors-b.scala:24:49 -------------------------------------------------------------- 24 |val testD = summon[Mirror.Of[Sm[Int] & Cns[Int]]] // error: unreleated | ^ |No given instance of type deriving.Mirror.Of[Sm[Int] & Cns[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.Of[Sm[Int] & Cns[Int]]: - | * type `Sm[Int] & Cns[Int]` is not a generic product because its subpart `Sm[Int] & Cns[Int]` is an intersection of unrelated symbols class Sm and class Cns. - | * type `Sm[Int] & Cns[Int]` is not a generic sum because its subpart `Sm[Int] & Cns[Int]` is an intersection of unrelated symbols class Sm and class Cns. + | * type `Sm[Int] & Cns[Int]` is not a generic product because its subpart `Sm[Int] & Cns[Int]` is an intersection of unrelated definitions class Sm and class Cns. + | * type `Sm[Int] & Cns[Int]` is not a generic sum because its subpart `Sm[Int] & Cns[Int]` is an intersection of unrelated definitions class Sm and class Cns. -- Error: tests/neg/mirror-synthesis-errors-b.scala:25:55 -------------------------------------------------------------- 25 |val testE = summon[Mirror.ProductOf[Sm[Int] & Nn.type]] // error: unreleated | ^ - |No given instance of type deriving.Mirror.ProductOf[Sm[Int] & Nn.type] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Sm[Int] & Nn.type]: type `Sm[Int] & Nn.type` is not a generic product because its subpart `Sm[Int] & Nn.type` is an intersection of unrelated symbols class Sm and object Nn. + |No given instance of type deriving.Mirror.ProductOf[Sm[Int] & Nn.type] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Sm[Int] & Nn.type]: type `Sm[Int] & Nn.type` is not a generic product because its subpart `Sm[Int] & Nn.type` is an intersection of unrelated definitions class Sm and object Nn. -- Error: tests/neg/mirror-synthesis-errors-b.scala:26:55 -------------------------------------------------------------- 26 |val testF = summon[Mirror.ProductOf[Nn.type & Sm[Int]]] // error: unreleated | ^ - |No given instance of type deriving.Mirror.ProductOf[Nn.type & Sm[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Nn.type & Sm[Int]]: type `Nn.type & Sm[Int]` is not a generic product because its subpart `Nn.type & Sm[Int]` is an intersection of unrelated symbols object Nn and class Sm. + |No given instance of type deriving.Mirror.ProductOf[Nn.type & Sm[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Nn.type & Sm[Int]]: type `Nn.type & Sm[Int]` is not a generic product because its subpart `Nn.type & Sm[Int]` is an intersection of unrelated definitions object Nn and class Sm. -- Error: tests/neg/mirror-synthesis-errors-b.scala:27:54 -------------------------------------------------------------- 27 |val testG = summon[Mirror.Of[Foo.A.type & Foo.B.type]] // error: unreleated | ^ |No given instance of type deriving.Mirror.Of[(Foo.A : Foo) & (Foo.B : Foo)] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.Of[(Foo.A : Foo) & (Foo.B : Foo)]: - | * type `(Foo.A : Foo) & (Foo.B : Foo)` is not a generic product because its subpart `(Foo.A : Foo) & (Foo.B : Foo)` is an intersection of unrelated symbols value A and value B. - | * type `(Foo.A : Foo) & (Foo.B : Foo)` is not a generic sum because its subpart `(Foo.A : Foo) & (Foo.B : Foo)` is an intersection of unrelated symbols value A and value B. + | * type `(Foo.A : Foo) & (Foo.B : Foo)` is not a generic product because its subpart `(Foo.A : Foo) & (Foo.B : Foo)` is an intersection of unrelated definitions value A and value B. + | * type `(Foo.A : Foo) & (Foo.B : Foo)` is not a generic sum because its subpart `(Foo.A : Foo) & (Foo.B : Foo)` is an intersection of unrelated definitions value A and value B. -- Error: tests/neg/mirror-synthesis-errors-b.scala:28:54 -------------------------------------------------------------- 28 |val testH = summon[Mirror.Of[Foo.B.type & Foo.A.type]] // error: unreleated | ^ |No given instance of type deriving.Mirror.Of[(Foo.B : Foo) & (Foo.A : Foo)] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.Of[(Foo.B : Foo) & (Foo.A : Foo)]: - | * type `(Foo.B : Foo) & (Foo.A : Foo)` is not a generic product because its subpart `(Foo.B : Foo) & (Foo.A : Foo)` is an intersection of unrelated symbols value B and value A. - | * type `(Foo.B : Foo) & (Foo.A : Foo)` is not a generic sum because its subpart `(Foo.B : Foo) & (Foo.A : Foo)` is an intersection of unrelated symbols value B and value A. + | * type `(Foo.B : Foo) & (Foo.A : Foo)` is not a generic product because its subpart `(Foo.B : Foo) & (Foo.A : Foo)` is an intersection of unrelated definitions value B and value A. + | * type `(Foo.B : Foo) & (Foo.A : Foo)` is not a generic sum because its subpart `(Foo.B : Foo) & (Foo.A : Foo)` is an intersection of unrelated definitions value B and value A. diff --git a/tests/run/i15234.scala b/tests/run/i15234.scala index 650a4974a63e..28495e9d011e 100644 --- a/tests/run/i15234.scala +++ b/tests/run/i15234.scala @@ -13,6 +13,7 @@ package app { val Bar: lib.Bar.type = lib.Bar } + @main def Test = assert(summon[Mirror.Of[scala.Nil.type]].fromProduct(EmptyTuple) == Nil) // alias scala 2 defined assert(summon[Mirror.Of[lib.Foo.A.type]].fromProduct(EmptyTuple) == lib.Foo.A) // real mirror