Skip to content

Commit 06a8f22

Browse files
authored
Merge pull request #14986 from dotty-staging/fix-12919
2 parents 2309212 + 6841f9c commit 06a8f22

File tree

6 files changed

+69
-3
lines changed

6 files changed

+69
-3
lines changed

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,9 @@ object SymUtils:
120120
def useCompanionAsSumMirror(using Context): Boolean =
121121
def companionExtendsSum(using Context): Boolean =
122122
self.linkedClass.isSubClass(defn.Mirror_SumClass)
123-
self.linkedClass.exists
124-
&& !self.is(Scala2x)
123+
!self.is(Scala2x)
124+
&& self.linkedClass.exists
125+
&& !self.linkedClass.is(Case)
125126
&& (
126127
// If the sum type is compiled from source, and `self` is a "generic sum"
127128
// then its companion object will become a sum mirror in `posttyper`. (This method

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
307307
.refinedWith(tpnme.MirroredElemTypes, TypeAlias(elemsType))
308308
.refinedWith(tpnme.MirroredElemLabels, TypeAlias(elemsLabels))
309309
val mirrorRef =
310-
if (cls.is(Scala2x)) anonymousMirror(monoType, ExtendsProductMirror, span)
310+
if (cls.is(Scala2x) || cls.linkedClass.is(Case)) anonymousMirror(monoType, ExtendsProductMirror, span)
311311
else companionPath(mirroredType, span)
312312
mirrorRef.cast(mirrorType)
313313
else EmptyTree

tests/run/i12919.scala

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
case class Normal(value: String)
2+
object Normal
3+
4+
case class ClassWithCaseCompanion(value: String)
5+
case object ClassWithCaseCompanion
6+
7+
def instantiate[T](product: Product)(implicit mirror: scala.deriving.Mirror.ProductOf[T]) =
8+
mirror.fromProduct(product)
9+
10+
@main def Test: Unit = {
11+
assert(instantiate[Normal](Tuple1("a")) == Normal("a")) // works as expected
12+
13+
assert(instantiate[ClassWithCaseCompanion.type](EmptyTuple) == ClassWithCaseCompanion) // works as expected
14+
15+
val c = instantiate[ClassWithCaseCompanion](Tuple1("b")) // throws java.lang.ClassCastException: class ClassWithCaseCompanion$ cannot be cast to class ClassWithCaseCompanion
16+
assert(c == ClassWithCaseCompanion("b")) // desired behaviour
17+
18+
val d = instantiate[ClassWithCaseCompanion.type](EmptyTuple)
19+
assert(d == ClassWithCaseCompanion)
20+
}

tests/run/i12919a.scala

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import scala.deriving.Mirror
2+
3+
case class Standalone(i: Int)
4+
object Standalone
5+
6+
case class WithCompanionCaseClass(i: Int)
7+
case object WithCompanionCaseClass
8+
9+
@main def Test: Unit =
10+
11+
val mStandalone = summon[Mirror.ProductOf[Standalone]]
12+
assert(mStandalone eq Standalone) // the companion object is the mirror for the case class
13+
14+
val mWithCompanion = summon[Mirror.ProductOf[WithCompanionCaseClass]]
15+
assert(mWithCompanion ne WithCompanionCaseClass) // A case object can not be the mirror of a companion case class.
16+
17+
val mWithCompanionCaseObject = summon[Mirror.ProductOf[WithCompanionCaseClass.type]]
18+
assert(mWithCompanionCaseObject eq WithCompanionCaseClass) // A case object is its own mirror.

tests/run/i12919b.scala

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import scala.deriving.Mirror
2+
3+
4+
sealed trait WithCompanionSealedTrait
5+
case object WithCompanionSealedTrait:
6+
case class FirstChild(x: Int) extends WithCompanionSealedTrait
7+
8+
@main def Test: Unit =
9+
10+
val mWithCompanionSum = summon[Mirror.SumOf[WithCompanionSealedTrait]]
11+
assert(mWithCompanionSum.ordinal(WithCompanionSealedTrait.FirstChild(1)) == 0)
12+
assert(mWithCompanionSum ne WithCompanionSealedTrait) // A case object can not be the mirror of a companion case class.
13+
14+
val mWithCompanionSingleton = summon[Mirror.ProductOf[WithCompanionSealedTrait.type]]
15+
assert(mWithCompanionSingleton.fromProduct(EmptyTuple) == WithCompanionSealedTrait)
16+
assert(mWithCompanionSingleton.isInstanceOf[Mirror.Singleton]) // case object is its own mirror.
17+
assert(mWithCompanionSingleton eq WithCompanionSealedTrait) // case object is its own mirror.

tests/run/i15101.scala

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
trait Encoder[T]
2+
object Encoder:
3+
def derived[T](using scala.deriving.Mirror.Of[T]): Encoder[T] = new Encoder[T] {}
4+
5+
case object Bar
6+
enum Bar derives Encoder:
7+
case A, B
8+
9+
@main def Test: Unit =
10+
summon[Encoder[Bar]]

0 commit comments

Comments
 (0)