Skip to content

Commit d484926

Browse files
authored
Merge pull request #15006 from dotty-staging/fix-14025
2 parents 9c4fa55 + 042ed56 commit d484926

File tree

7 files changed

+88
-24
lines changed

7 files changed

+88
-24
lines changed

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

+9-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import Contexts._
99
import Symbols._
1010
import Names.Name
1111

12+
import dotty.tools.dotc.core.Decorators.*
13+
1214
object TypeUtils {
1315
/** A decorator that provides methods on types
1416
* that are needed in the transformer pipeline.
@@ -84,11 +86,16 @@ object TypeUtils {
8486
/** The TermRef referring to the companion of the underlying class reference
8587
* of this type, while keeping the same prefix.
8688
*/
87-
def companionRef(using Context): TermRef = self match {
89+
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
8895
case self @ TypeRef(prefix, _) if self.symbol.isClass =>
8996
prefix.select(self.symbol.companionModule).asInstanceOf[TermRef]
9097
case self: TypeProxy =>
91-
self.underlying.companionRef
98+
self.underlying.mirrorCompanionRef
9299
}
93100

94101
/** Is this type a methodic type that takes implicit parameters (both old and new) at some point? */

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

+35-22
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
249249

250250
/** A path referencing the companion of class type `clsType` */
251251
private def companionPath(clsType: Type, span: Span)(using Context) =
252-
val ref = pathFor(clsType.companionRef)
252+
val ref = pathFor(clsType.mirrorCompanionRef)
253253
assert(ref.symbol.is(Module) && (clsType.classSymbol.is(ModuleClass) || (ref.symbol.companionClass == clsType.classSymbol)))
254254
ref.withSpan(span)
255255

@@ -275,6 +275,36 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
275275
monoMap(mirroredType.resultType)
276276

277277
private def productMirror(mirroredType: Type, formal: Type, span: Span)(using Context): Tree =
278+
279+
/** do all parts match the class symbol? */
280+
def acceptable(tp: Type, cls: Symbol): Boolean = tp match
281+
case tp: HKTypeLambda if tp.resultType.isInstanceOf[HKTypeLambda] => false
282+
case tp: TypeProxy => acceptable(tp.underlying, cls)
283+
case OrType(tp1, tp2) => acceptable(tp1, cls) && acceptable(tp2, cls)
284+
case _ => tp.classSymbol eq cls
285+
286+
def makeProductMirror(cls: Symbol): Tree =
287+
val accessors = cls.caseAccessors.filterNot(_.isAllOf(PrivateLocal))
288+
val elemLabels = accessors.map(acc => ConstantType(Constant(acc.name.toString)))
289+
val nestedPairs = TypeOps.nestedPairs(accessors.map(mirroredType.resultType.memberInfo(_).widenExpr))
290+
val (monoType, elemsType) = mirroredType match
291+
case mirroredType: HKTypeLambda =>
292+
(mkMirroredMonoType(mirroredType), mirroredType.derivedLambdaType(resType = nestedPairs))
293+
case _ =>
294+
(mirroredType, nestedPairs)
295+
val elemsLabels = TypeOps.nestedPairs(elemLabels)
296+
checkRefinement(formal, tpnme.MirroredElemTypes, elemsType, span)
297+
checkRefinement(formal, tpnme.MirroredElemLabels, elemsLabels, span)
298+
val mirrorType =
299+
mirrorCore(defn.Mirror_ProductClass, monoType, mirroredType, cls.name, formal)
300+
.refinedWith(tpnme.MirroredElemTypes, TypeAlias(elemsType))
301+
.refinedWith(tpnme.MirroredElemLabels, TypeAlias(elemsLabels))
302+
val mirrorRef =
303+
if (cls.is(Scala2x) || cls.linkedClass.is(Case)) anonymousMirror(monoType, ExtendsProductMirror, span)
304+
else companionPath(mirroredType, span)
305+
mirrorRef.cast(mirrorType)
306+
end makeProductMirror
307+
278308
mirroredType match
279309
case AndType(tp1, tp2) =>
280310
productMirror(tp1, formal, span).orElse(productMirror(tp2, formal, span))
@@ -289,28 +319,10 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
289319
else
290320
val mirrorType = mirrorCore(defn.Mirror_SingletonClass, mirroredType, mirroredType, module.name, formal)
291321
modulePath.cast(mirrorType)
292-
else if mirroredType.classSymbol.isGenericProduct then
322+
else
293323
val cls = mirroredType.classSymbol
294-
val accessors = cls.caseAccessors.filterNot(_.isAllOf(PrivateLocal))
295-
val elemLabels = accessors.map(acc => ConstantType(Constant(acc.name.toString)))
296-
val nestedPairs = TypeOps.nestedPairs(accessors.map(mirroredType.resultType.memberInfo(_).widenExpr))
297-
val (monoType, elemsType) = mirroredType match
298-
case mirroredType: HKTypeLambda =>
299-
(mkMirroredMonoType(mirroredType), mirroredType.derivedLambdaType(resType = nestedPairs))
300-
case _ =>
301-
(mirroredType, nestedPairs)
302-
val elemsLabels = TypeOps.nestedPairs(elemLabels)
303-
checkRefinement(formal, tpnme.MirroredElemTypes, elemsType, span)
304-
checkRefinement(formal, tpnme.MirroredElemLabels, elemsLabels, span)
305-
val mirrorType =
306-
mirrorCore(defn.Mirror_ProductClass, monoType, mirroredType, cls.name, formal)
307-
.refinedWith(tpnme.MirroredElemTypes, TypeAlias(elemsType))
308-
.refinedWith(tpnme.MirroredElemLabels, TypeAlias(elemsLabels))
309-
val mirrorRef =
310-
if (cls.is(Scala2x) || cls.linkedClass.is(Case)) anonymousMirror(monoType, ExtendsProductMirror, span)
311-
else companionPath(mirroredType, span)
312-
mirrorRef.cast(mirrorType)
313-
else EmptyTree
324+
if acceptable(mirroredType, cls) && cls.isGenericProduct then makeProductMirror(cls)
325+
else EmptyTree
314326
end productMirror
315327

316328
private def sumMirror(mirroredType: Type, formal: Type, span: Span)(using Context): Tree =
@@ -319,6 +331,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
319331

320332
def acceptable(tp: Type): Boolean = tp match
321333
case tp: TermRef => false
334+
case tp: HKTypeLambda if tp.resultType.isInstanceOf[HKTypeLambda] => false
322335
case tp: TypeProxy => acceptable(tp.underlying)
323336
case OrType(tp1, tp2) => acceptable(tp1) && acceptable(tp2)
324337
case _ => tp.classSymbol eq cls

tests/neg/i14025.check

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- Error: tests/neg/i14025.scala:1:88 ----------------------------------------------------------------------------------
2+
1 |val foo = summon[deriving.Mirror.Product { type MirroredType = [X] =>> [Y] =>> (X, Y) }] // error
3+
| ^
4+
|no given instance of type deriving.Mirror.Product{MirroredType[X] = [Y] =>> (X, Y)} was found for parameter x of method summon in object Predef
5+
-- Error: tests/neg/i14025.scala:2:90 ----------------------------------------------------------------------------------
6+
2 |val bar = summon[deriving.Mirror.Sum { type MirroredType = [X] =>> [Y] =>> List[(X, Y)] }] // error
7+
| ^
8+
|no given instance of type deriving.Mirror.Sum{MirroredType[X] = [Y] =>> List[(X, Y)]} was found for parameter x of method summon in object Predef

tests/neg/i14025.scala

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
val foo = summon[deriving.Mirror.Product { type MirroredType = [X] =>> [Y] =>> (X, Y) }] // error
2+
val bar = summon[deriving.Mirror.Sum { type MirroredType = [X] =>> [Y] =>> List[(X, Y)] }] // error

tests/neg/i14823.check

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- Error: tests/neg/i14823.scala:8:50 ----------------------------------------------------------------------------------
2+
8 |val baz = summon[Mirror.Of[SubA[Int] | SubB[Int]]] // error
3+
| ^
4+
|no given instance of type deriving.Mirror.Of[SubA[Int] | SubB[Int]] was found for parameter x of method summon in object Predef

tests/neg/i14823.scala

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import deriving.Mirror
2+
3+
case class Cov[+T]()
4+
5+
class SubA[+T]() extends Cov[T]
6+
class SubB[+T]() extends Cov[T]
7+
8+
val baz = summon[Mirror.Of[SubA[Int] | SubB[Int]]] // error
9+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
10+
// this should fail because:
11+
// 1) SubA and SubB are not individually product types
12+
// 2) SubA and SubB are different classes

tests/pos/i14823.scala

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import deriving.Mirror
2+
3+
object MirrorK1:
4+
type Of[F[_]] = Mirror { type MirroredType[A] = F[A] }
5+
6+
sealed trait Box[T]
7+
object Box
8+
9+
case class Child[T]() extends Box[T]
10+
11+
sealed abstract class Foo[T]
12+
object Foo {
13+
case class A[T]() extends Foo[T]
14+
}
15+
16+
val foo = summon[Mirror.Of[Box[Int] | Box[Int]]]
17+
val bar = summon[MirrorK1.Of[[X] =>> Box[Int] | Box[Int]]]
18+
def baz = summon[deriving.Mirror.Of[Foo[String] | Foo[String]]]

0 commit comments

Comments
 (0)