Skip to content

Commit f1b95a5

Browse files
committed
handle widened module class in productMirror
1 parent 66187b1 commit f1b95a5

File tree

3 files changed

+41
-10
lines changed

3 files changed

+41
-10
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ object SymUtils:
9494
&& (!ctor.privateWithin.exists || isAccessible(ctor.privateWithin)) // check scope is compatible
9595

9696

97-
val companionMirror = self.useCompanionAsProductMirror
97+
def companionMirror = self.useCompanionAsProductMirror
9898
if (!self.is(CaseClass)) "it is not a case class"
9999
else if (self.is(Abstract)) "it is an abstract class"
100100
else if (self.primaryConstructor.info.paramInfoss.length != 1) "it takes more than one parameter list"

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

+18-9
Original file line numberDiff line numberDiff line change
@@ -310,22 +310,31 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
310310
withNoErrors(mirrorRef.cast(mirrorType))
311311
end makeProductMirror
312312

313+
/** widen TermRef to see if they are an alias to an enum singleton */
314+
def isEnumSingletonRef(tp: Type)(using Context): Boolean = tp match
315+
case tp: TermRef =>
316+
val sym = tp.termSymbol
317+
sym.isEnumCase || (!tp.isOverloaded && isEnumSingletonRef(tp.underlying.widenExpr))
318+
case _ => false
319+
313320
mirroredType match
314321
case AndType(tp1, tp2) =>
315322
orElse(productMirror(tp1, formal, span), productMirror(tp2, formal, span))
316323
case _ =>
317-
if mirroredType.termSymbol.is(CaseVal) then
318-
val module = mirroredType.termSymbol
319-
val modulePath = pathFor(mirroredType).withSpan(span)
320-
if module.info.classSymbol.is(Scala2x) then
321-
val mirrorType = mirrorCore(defn.Mirror_SingletonProxyClass, mirroredType, mirroredType, module.name, formal)
322-
val mirrorRef = New(defn.Mirror_SingletonProxyClass.typeRef, modulePath :: Nil)
324+
val cls = mirroredType.classSymbol
325+
if isEnumSingletonRef(mirroredType) || cls.isAllOf(Case | Module) then
326+
val (singleton, singletonRef) =
327+
if mirroredType.termSymbol.exists then (mirroredType.termSymbol, mirroredType)
328+
else (cls.sourceModule, cls.sourceModule.reachableTermRef)
329+
val singletonPath = pathFor(singletonRef).withSpan(span)
330+
if singleton.info.classSymbol.is(Scala2x) then // could be Scala 3 alias of Scala 2 case object.
331+
val mirrorType = mirrorCore(defn.Mirror_SingletonProxyClass, mirroredType, mirroredType, singleton.name, formal)
332+
val mirrorRef = New(defn.Mirror_SingletonProxyClass.typeRef, singletonPath :: Nil)
323333
withNoErrors(mirrorRef.cast(mirrorType))
324334
else
325-
val mirrorType = mirrorCore(defn.Mirror_SingletonClass, mirroredType, mirroredType, module.name, formal)
326-
withNoErrors(modulePath.cast(mirrorType))
335+
val mirrorType = mirrorCore(defn.Mirror_SingletonClass, mirroredType, mirroredType, singleton.name, formal)
336+
withNoErrors(singletonPath.cast(mirrorType))
327337
else
328-
val cls = mirroredType.classSymbol
329338
val acceptableMsg = whyNotAcceptableType(mirroredType, cls)
330339
if acceptableMsg.isEmpty then
331340
if cls.isGenericProduct then makeProductMirror(cls)

tests/run/i15234.scala

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import scala.deriving.Mirror
2+
3+
package lib {
4+
enum Foo:
5+
case A
6+
7+
case object Bar
8+
}
9+
10+
package app {
11+
object Foo:
12+
val A: lib.Foo.A.type = lib.Foo.A
13+
val Bar: lib.Bar.type = lib.Bar
14+
}
15+
16+
17+
@main def Test =
18+
assert(summon[Mirror.Of[scala.Nil.type]].fromProduct(EmptyTuple) == Nil) // alias scala 2 defined
19+
assert(summon[Mirror.Of[lib.Foo.A.type]].fromProduct(EmptyTuple) == lib.Foo.A) // real mirror
20+
assert(summon[Mirror.Of[lib.Bar.type]].fromProduct(EmptyTuple) == lib.Bar) // real mirror
21+
assert(summon[Mirror.Of[app.Foo.A.type]].fromProduct(EmptyTuple) == lib.Foo.A) // alias mirror
22+
assert(summon[Mirror.Of[app.Bar.type]].fromProduct(EmptyTuple) == lib.Bar) // alias mirror

0 commit comments

Comments
 (0)