diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index 7694a7cc240a..39c9aae52207 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -120,8 +120,9 @@ object SymUtils: def useCompanionAsSumMirror(using Context): Boolean = def companionExtendsSum(using Context): Boolean = self.linkedClass.isSubClass(defn.Mirror_SumClass) - self.linkedClass.exists - && !self.is(Scala2x) + !self.is(Scala2x) + && self.linkedClass.exists + && !self.linkedClass.is(Case) && ( // If the sum type is compiled from source, and `self` is a "generic sum" // then its companion object will become a sum mirror in `posttyper`. (This method diff --git a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala index 73fc926b8893..03554cbabea6 100644 --- a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala @@ -307,7 +307,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): .refinedWith(tpnme.MirroredElemTypes, TypeAlias(elemsType)) .refinedWith(tpnme.MirroredElemLabels, TypeAlias(elemsLabels)) val mirrorRef = - if (cls.is(Scala2x)) anonymousMirror(monoType, ExtendsProductMirror, span) + if (cls.is(Scala2x) || cls.linkedClass.is(Case)) anonymousMirror(monoType, ExtendsProductMirror, span) else companionPath(mirroredType, span) mirrorRef.cast(mirrorType) else EmptyTree diff --git a/tests/run/i12919.scala b/tests/run/i12919.scala new file mode 100644 index 000000000000..8a32d16e2977 --- /dev/null +++ b/tests/run/i12919.scala @@ -0,0 +1,20 @@ +case class Normal(value: String) +object Normal + +case class ClassWithCaseCompanion(value: String) +case object ClassWithCaseCompanion + +def instantiate[T](product: Product)(implicit mirror: scala.deriving.Mirror.ProductOf[T]) = + mirror.fromProduct(product) + +@main def Test: Unit = { + assert(instantiate[Normal](Tuple1("a")) == Normal("a")) // works as expected + + assert(instantiate[ClassWithCaseCompanion.type](EmptyTuple) == ClassWithCaseCompanion) // works as expected + + val c = instantiate[ClassWithCaseCompanion](Tuple1("b")) // throws java.lang.ClassCastException: class ClassWithCaseCompanion$ cannot be cast to class ClassWithCaseCompanion + assert(c == ClassWithCaseCompanion("b")) // desired behaviour + + val d = instantiate[ClassWithCaseCompanion.type](EmptyTuple) + assert(d == ClassWithCaseCompanion) +} diff --git a/tests/run/i12919a.scala b/tests/run/i12919a.scala new file mode 100644 index 000000000000..1f7abcfdc4e9 --- /dev/null +++ b/tests/run/i12919a.scala @@ -0,0 +1,18 @@ +import scala.deriving.Mirror + +case class Standalone(i: Int) +object Standalone + +case class WithCompanionCaseClass(i: Int) +case object WithCompanionCaseClass + +@main def Test: Unit = + + val mStandalone = summon[Mirror.ProductOf[Standalone]] + assert(mStandalone eq Standalone) // the companion object is the mirror for the case class + + val mWithCompanion = summon[Mirror.ProductOf[WithCompanionCaseClass]] + assert(mWithCompanion ne WithCompanionCaseClass) // A case object can not be the mirror of a companion case class. + + val mWithCompanionCaseObject = summon[Mirror.ProductOf[WithCompanionCaseClass.type]] + assert(mWithCompanionCaseObject eq WithCompanionCaseClass) // A case object is its own mirror. diff --git a/tests/run/i12919b.scala b/tests/run/i12919b.scala new file mode 100644 index 000000000000..84d9277c0a04 --- /dev/null +++ b/tests/run/i12919b.scala @@ -0,0 +1,17 @@ +import scala.deriving.Mirror + + +sealed trait WithCompanionSealedTrait +case object WithCompanionSealedTrait: + case class FirstChild(x: Int) extends WithCompanionSealedTrait + +@main def Test: Unit = + + val mWithCompanionSum = summon[Mirror.SumOf[WithCompanionSealedTrait]] + assert(mWithCompanionSum.ordinal(WithCompanionSealedTrait.FirstChild(1)) == 0) + assert(mWithCompanionSum ne WithCompanionSealedTrait) // A case object can not be the mirror of a companion case class. + + val mWithCompanionSingleton = summon[Mirror.ProductOf[WithCompanionSealedTrait.type]] + assert(mWithCompanionSingleton.fromProduct(EmptyTuple) == WithCompanionSealedTrait) + assert(mWithCompanionSingleton.isInstanceOf[Mirror.Singleton]) // case object is its own mirror. + assert(mWithCompanionSingleton eq WithCompanionSealedTrait) // case object is its own mirror. diff --git a/tests/run/i15101.scala b/tests/run/i15101.scala new file mode 100644 index 000000000000..3341adb2f962 --- /dev/null +++ b/tests/run/i15101.scala @@ -0,0 +1,10 @@ +trait Encoder[T] +object Encoder: + def derived[T](using scala.deriving.Mirror.Of[T]): Encoder[T] = new Encoder[T] {} + +case object Bar +enum Bar derives Encoder: + case A, B + +@main def Test: Unit = + summon[Encoder[Bar]]