Skip to content

Commit 330e1b2

Browse files
committed
remove AndType branch in productMirror
remove case: OrType is no longer supported
1 parent 84732a5 commit 330e1b2

File tree

4 files changed

+127
-52
lines changed

4 files changed

+127
-52
lines changed

compiler/src/dotty/tools/dotc/transform/TypeUtils.scala

-5
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,6 @@ object TypeUtils {
8787
* of this type, while keeping the same prefix.
8888
*/
8989
def mirrorCompanionRef(using Context): TermRef = self match {
90-
case OrType(tp1, tp2) =>
91-
val r1 = tp1.mirrorCompanionRef
92-
val r2 = tp2.mirrorCompanionRef
93-
assert(r1.symbol == r2.symbol, em"mirrorCompanionRef mismatch for $self: $r1, $r2 did not have the same symbol")
94-
r1
9590
case AndType(tp1, tp2) =>
9691
val c1 = tp1.classSymbol
9792
val c2 = tp2.classSymbol

compiler/src/dotty/tools/dotc/typer/Synthesizer.scala

+83-47
Original file line numberDiff line numberDiff line change
@@ -276,16 +276,73 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
276276
case t => mapOver(t)
277277
monoMap(mirroredType.resultType)
278278

279-
private def productMirror(mirroredType: Type, formal: Type, span: Span)(using Context): TreeWithErrors =
279+
private[Synthesizer] enum MirrorSource:
280+
case ClassSymbol(cls: Symbol)
281+
case Singleton(tref: TermRef)
282+
283+
def isSub(that: MirrorSource)(using Context): Boolean =
284+
(this, that) match
285+
case (Singleton(tref), ClassSymbol(cls)) => tref.classSymbol.isSubClass(cls)
286+
case (ClassSymbol(cls1), ClassSymbol(cls2)) => cls1.isSubClass(cls2)
287+
case (_: ClassSymbol, _: Singleton) => false
288+
case _ => false // includes that a class is never sub of a singleton
289+
290+
def debug(using Context): String = this match
291+
case ClassSymbol(cls) => i"$cls"
292+
case Singleton(tref) => i"${tref.termSymbol}"
293+
294+
object MirrorSource:
295+
def cls(cls: Symbol): MirrorSource = ClassSymbol(cls)
296+
def singleton(tref: TermRef): MirrorSource = Singleton(tref)
297+
298+
/** widen TermRef to see if they are an alias to an enum singleton or case object */
299+
private def isEnumOrCaseObjectRef(tp: Type)(using Context): Boolean = tp match
300+
case tp: TermRef =>
301+
val sym = tp.termSymbol
280302

281-
def whyNotAcceptableType(tp: Type, cls: Symbol): String = tp match
303+
sym.isEnumCase
304+
|| (sym.isClass && sym.isAllOf(Case | Module))
305+
|| (!tp.isOverloaded && isEnumOrCaseObjectRef(tp.underlying.widenExpr))
306+
case _ => false
307+
308+
/** A customised version of `Types.classSymbol`, specialised for mirror generation. */
309+
def reduce(mirroredType: Type)(using Context): Either[String, MirrorSource] = mirroredType match
310+
case tp: TypeRef =>
311+
val sym = tp.symbol
312+
if sym.isClass then // direct ref to a class, not an alias
313+
if sym.isAllOf(Case | Module) then
314+
Right(MirrorSource.singleton(sym.sourceModule.reachableTermRef)) // correct widened module ref
315+
else
316+
Right(MirrorSource.cls(sym))
317+
else
318+
reduce(tp.superType)
319+
case tp: TermRef if isEnumOrCaseObjectRef(tp) =>
320+
Right(MirrorSource.singleton(tp))
282321
case tp: HKTypeLambda if tp.resultType.isInstanceOf[HKTypeLambda] =>
283-
i"its subpart `$tp` is not a supported kind (either `*` or `* -> *`)"
284-
case tp: TypeProxy => whyNotAcceptableType(tp.underlying, cls)
285-
case OrType(tp1, tp2) => i"its subpart `$tp` is a top-level union type."
286-
case _ =>
287-
if tp.classSymbol eq cls then ""
288-
else i"a subpart reduces to the more precise ${tp.classSymbol}, expected $cls"
322+
Left(i"its subpart `$tp` is not a supported kind (either `*` or `* -> *`)")
323+
case tp: TypeProxy =>
324+
reduce(tp.underlying)
325+
case tp: ClassInfo =>
326+
Right(MirrorSource.cls(tp.cls))
327+
case AndType(l, r) =>
328+
for
329+
lsrc <- reduce(l)
330+
rsrc <- reduce(r)
331+
res <- locally {
332+
if lsrc.isSub(rsrc) then Right(lsrc)
333+
else if rsrc.isSub(lsrc) then Right(rsrc)
334+
else Left(i"${lsrc.debug} and ${rsrc.debug} are unrelated")
335+
}
336+
yield
337+
res
338+
case tp: OrType =>
339+
Left(i"its subpart `$tp` is a top-level union type.")
340+
case tp =>
341+
Left(i"its subpart `$tp` is an unsupported type.")
342+
343+
end MirrorSource
344+
345+
private def productMirror(mirroredType: Type, formal: Type, span: Span)(using Context): TreeWithErrors =
289346

290347
def makeProductMirror(cls: Symbol): TreeWithErrors =
291348
val accessors = cls.caseAccessors.filterNot(_.isAllOf(PrivateLocal))
@@ -309,55 +366,34 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
309366
withNoErrors(mirrorRef.cast(mirrorType))
310367
end makeProductMirror
311368

312-
/** widen TermRef to see if they are an alias to an enum singleton */
313-
def isEnumSingletonRef(tp: Type)(using Context): Boolean = tp match
314-
case tp: TermRef =>
315-
val sym = tp.termSymbol
316-
sym.isEnumCase || (!tp.isOverloaded && isEnumSingletonRef(tp.underlying.widenExpr))
317-
case _ => false
318-
319-
mirroredType match
320-
case AndType(tp1, tp2) =>
321-
orElse(productMirror(tp1, formal, span), productMirror(tp2, formal, span))
322-
case _ =>
323-
val cls = mirroredType.classSymbol
324-
if isEnumSingletonRef(mirroredType) || cls.isAllOf(Case | Module) then
325-
val (singleton, singletonRef) =
326-
if mirroredType.termSymbol.exists then (mirroredType.termSymbol, mirroredType)
327-
else (cls.sourceModule, cls.sourceModule.reachableTermRef)
328-
val singletonPath = pathFor(singletonRef).withSpan(span)
329-
if singleton.info.classSymbol.is(Scala2x) then // could be Scala 3 alias of Scala 2 case object.
330-
val mirrorType = mirrorCore(defn.Mirror_SingletonProxyClass, mirroredType, mirroredType, singleton.name, formal)
369+
MirrorSource.reduce(mirroredType) match
370+
case Right(msrc) => msrc match
371+
case MirrorSource.Singleton(tref) =>
372+
val singleton = tref.termSymbol
373+
val singletonPath = pathFor(tref).withSpan(span)
374+
if tref.classSymbol.is(Scala2x) then // could be Scala 3 alias of Scala 2 case object.
375+
val mirrorType =
376+
mirrorCore(defn.Mirror_SingletonProxyClass, mirroredType, mirroredType, singleton.name, formal)
331377
val mirrorRef = New(defn.Mirror_SingletonProxyClass.typeRef, singletonPath :: Nil)
332378
withNoErrors(mirrorRef.cast(mirrorType))
333379
else
334380
val mirrorType = mirrorCore(defn.Mirror_SingletonClass, mirroredType, mirroredType, singleton.name, formal)
335381
withNoErrors(singletonPath.cast(mirrorType))
336-
else
337-
val acceptableMsg = whyNotAcceptableType(mirroredType, cls)
338-
if acceptableMsg.isEmpty then
339-
if cls.isGenericProduct then makeProductMirror(cls)
340-
else withErrors(i"$cls is not a generic product because ${cls.whyNotGenericProduct}")
341-
else withErrors(i"type `$mirroredType` is not a generic product because $acceptableMsg")
382+
case MirrorSource.ClassSymbol(cls) =>
383+
if cls.isGenericProduct then makeProductMirror(cls)
384+
else withErrors(i"$cls is not a generic product because ${cls.whyNotGenericProduct}")
385+
case Left(msg) =>
386+
withErrors(i"type `$mirroredType` is not a generic product because $msg")
342387
end productMirror
343388

344389
private def sumMirror(mirroredType: Type, formal: Type, span: Span)(using Context): TreeWithErrors =
345390

346-
val cls = mirroredType.classSymbol
347-
val clsIsGenericSum = cls.isGenericSum
348-
349-
def whyNotAcceptableType(tp: Type): String = tp match
350-
case tp: TermRef => i"its subpart `$tp` is a term reference"
351-
case tp: HKTypeLambda if tp.resultType.isInstanceOf[HKTypeLambda] =>
352-
i"its subpart `$tp` is not a supported kind (either `*` or `* -> *`)"
353-
case tp: TypeProxy => whyNotAcceptableType(tp.underlying)
354-
case OrType(tp1, tp2) => i"its subpart `$tp` is a top-level union type."
355-
case _ =>
356-
if tp.classSymbol eq cls then ""
357-
else i"a subpart reduces to the more precise ${tp.classSymbol}, expected $cls"
358-
391+
val (acceptableMsg, cls) = MirrorSource.reduce(mirroredType) match
392+
case Right(MirrorSource.Singleton(tp)) => (i"its subpart `$tp` is a term reference", NoSymbol)
393+
case Right(MirrorSource.ClassSymbol(cls)) => ("", cls)
394+
case Left(msg) => (msg, NoSymbol)
359395

360-
val acceptableMsg = whyNotAcceptableType(mirroredType)
396+
val clsIsGenericSum = cls.isGenericSum
361397

362398
if acceptableMsg.isEmpty && clsIsGenericSum then
363399
val elemLabels = cls.children.map(c => ConstantType(Constant(c.name.toString)))
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-- Error: tests/neg/mirror-synthesis-errors-b.scala:11:55 --------------------------------------------------------------
2+
11 |val testA = summon[Mirror.ProductOf[Cs[Int] & Sm[Int]]] // error: unreleated
3+
| ^
4+
|No given instance of type deriving.Mirror.ProductOf[Cs[Int] & Sm[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Cs[Int] & Sm[Int]]: type `Cs[Int] & Sm[Int]` is not a generic product because class Cs and class Sm are unrelated
5+
-- Error: tests/neg/mirror-synthesis-errors-b.scala:12:55 --------------------------------------------------------------
6+
12 |val testB = summon[Mirror.ProductOf[Sm[Int] & Cs[Int]]] // error: unreleated
7+
| ^
8+
|No given instance of type deriving.Mirror.ProductOf[Sm[Int] & Cs[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.ProductOf[Sm[Int] & Cs[Int]]: type `Sm[Int] & Cs[Int]` is not a generic product because class Sm and class Cs are unrelated
9+
-- Error: tests/neg/mirror-synthesis-errors-b.scala:13:48 --------------------------------------------------------------
10+
13 |val testC = summon[Mirror.Of[Cs[Int] & Sm[Int]]] // error: unreleated
11+
| ^
12+
|No given instance of type deriving.Mirror.Of[Cs[Int] & Sm[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.Of[Cs[Int] & Sm[Int]]:
13+
| * type `Cs[Int] & Sm[Int]` is not a generic product because class Cs and class Sm are unrelated
14+
| * type `Cs[Int] & Sm[Int]` is not a generic sum because class Cs and class Sm are unrelated
15+
-- Error: tests/neg/mirror-synthesis-errors-b.scala:14:48 --------------------------------------------------------------
16+
14 |val testD = summon[Mirror.Of[Sm[Int] & Cs[Int]]] // error: unreleated
17+
| ^
18+
|No given instance of type deriving.Mirror.Of[Sm[Int] & Cs[Int]] was found for parameter x of method summon in object Predef. Failed to synthesize an instance of type deriving.Mirror.Of[Sm[Int] & Cs[Int]]:
19+
| * type `Sm[Int] & Cs[Int]` is not a generic product because class Sm and class Cs are unrelated
20+
| * type `Sm[Int] & Cs[Int]` is not a generic sum because class Sm and class Cs are unrelated
21+
-- Error: tests/neg/mirror-synthesis-errors-b.scala:15:55 --------------------------------------------------------------
22+
15 |val testE = summon[Mirror.ProductOf[Sm[Int] & Nn.type]] // error: unreleated
23+
| ^
24+
|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 class Sm and object Nn are unrelated
25+
-- Error: tests/neg/mirror-synthesis-errors-b.scala:16:55 --------------------------------------------------------------
26+
16 |val testF = summon[Mirror.ProductOf[Nn.type & Sm[Int]]] // error: unreleated
27+
| ^
28+
|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 object Nn and class Sm are unrelated
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import scala.deriving.Mirror
2+
3+
sealed trait Lst[+A] // AKA: scala.collection.immutable.List
4+
case class Cs[+A](head: A, tail: Lst[A]) extends Lst[A]
5+
case object Nl extends Lst[Nothing]
6+
7+
sealed trait Opt[+A] // AKA: scala.Option
8+
case class Sm[+A](value: A) extends Opt[A]
9+
case object Nn extends Opt[Nothing]
10+
11+
val testA = summon[Mirror.ProductOf[Cs[Int] & Sm[Int]]] // error: unreleated
12+
val testB = summon[Mirror.ProductOf[Sm[Int] & Cs[Int]]] // error: unreleated
13+
val testC = summon[Mirror.Of[Cs[Int] & Sm[Int]]] // error: unreleated
14+
val testD = summon[Mirror.Of[Sm[Int] & Cs[Int]]] // error: unreleated
15+
val testE = summon[Mirror.ProductOf[Sm[Int] & Nn.type]] // error: unreleated
16+
val testF = summon[Mirror.ProductOf[Nn.type & Sm[Int]]] // error: unreleated

0 commit comments

Comments
 (0)