Skip to content

Commit 6d1e7fa

Browse files
committed
check children are also accessible in mirror
1 parent 62abe60 commit 6d1e7fa

File tree

4 files changed

+25
-9
lines changed

4 files changed

+25
-9
lines changed

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

+9-3
Original file line numberDiff line numberDiff line change
@@ -87,22 +87,28 @@ object SymUtils:
8787

8888
def isGenericProduct(using Context): Boolean = whyNotGenericProduct.isEmpty
8989

90+
def useCompanionAsMirror(using Context): Boolean = self.linkedClass.exists && !self.is(Scala2x)
91+
9092
/** Is this a sealed class or trait for which a sum mirror is generated?
9193
* It must satisfy the following conditions:
9294
* - it has at least one child class or object
9395
* - none of its children are anonymous classes
9496
* - all of its children are addressable through a path from the parent class
97+
* and also the location of the generated mirror.
9598
* - all of its children are generic products or singletons
9699
*/
97-
def whyNotGenericSum(using Context): String =
100+
def whyNotGenericSum(declScope: Symbol)(using Context): String =
98101
if (!self.is(Sealed))
99102
s"it is not a sealed ${self.kindString}"
100103
else {
101104
val children = self.children
105+
val companionMirror = self.useCompanionAsMirror
106+
assert(!(companionMirror && (declScope ne self.linkedClass)))
102107
def problem(child: Symbol) = {
103108

104109
def isAccessible(sym: Symbol): Boolean =
105-
self.isContainedIn(sym) || sym.is(Module) && isAccessible(sym.owner)
110+
(self.isContainedIn(sym) && (companionMirror || declScope.isContainedIn(sym)))
111+
|| sym.is(Module) && isAccessible(sym.owner)
106112

107113
if (child == self) "it has anonymous or inaccessible subclasses"
108114
else if (!isAccessible(child.owner)) i"its child $child is not accessible"
@@ -117,7 +123,7 @@ object SymUtils:
117123
else children.map(problem).find(!_.isEmpty).getOrElse("")
118124
}
119125

120-
def isGenericSum(using Context): Boolean = whyNotGenericSum.isEmpty
126+
def isGenericSum(declScope: Symbol)(using Context): Boolean = whyNotGenericSum(declScope).isEmpty
121127

122128
/** If this is a constructor, its owner: otherwise this. */
123129
final def skipConstructor(using Context): Symbol =

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -584,9 +584,9 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
584584
if (clazz.is(Module)) {
585585
if (clazz.is(Case)) makeSingletonMirror()
586586
else if (linked.isGenericProduct) makeProductMirror(linked)
587-
else if (linked.isGenericSum) makeSumMirror(linked)
587+
else if (linked.isGenericSum(clazz)) makeSumMirror(linked)
588588
else if (linked.is(Sealed))
589-
derive.println(i"$linked is not a sum because ${linked.whyNotGenericSum}")
589+
derive.println(i"$linked is not a sum because ${linked.whyNotGenericSum(clazz)}")
590590
}
591591
else if (impl.removeAttachment(ExtendsSingletonMirror).isDefined)
592592
makeSingletonMirror()

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

+5-4
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,10 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
266266
end productMirror
267267

268268
private def sumMirror(mirroredType: Type, formal: Type, span: Span)(using Context): Tree =
269-
if mirroredType.classSymbol.isGenericSum then
270-
val cls = mirroredType.classSymbol
269+
val cls = mirroredType.classSymbol
270+
val useCompanion = cls.useCompanionAsMirror
271+
272+
if cls.isGenericSum(if useCompanion then cls.linkedClass else ctx.owner) then
271273
val elemLabels = cls.children.map(c => ConstantType(Constant(c.name.toString)))
272274

273275
def solve(sym: Symbol): Type = sym match
@@ -318,8 +320,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
318320
.refinedWith(tpnme.MirroredElemTypes, TypeAlias(elemsType))
319321
.refinedWith(tpnme.MirroredElemLabels, TypeAlias(TypeOps.nestedPairs(elemLabels)))
320322
val mirrorRef =
321-
if cls.linkedClass.exists && !cls.is(Scala2x)
322-
then companionPath(mirroredType, span)
323+
if useCompanion then companionPath(mirroredType, span)
323324
else anonymousMirror(monoType, ExtendsSumMirror, span)
324325
mirrorRef.cast(mirrorType)
325326
else EmptyTree

tests/neg/i10997.scala

+9
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,12 @@ trait Wrapper {
77

88
println(summon[deriving.Mirror.Of[Parent]]) // error
99
}
10+
11+
class ClassWrapper {
12+
sealed trait Base
13+
case class Foo(x: Int) extends Base
14+
}
15+
16+
@main def Test =
17+
val cw = new ClassWrapper()
18+
val mirrorParent = summon[deriving.Mirror.Of[cw.Base]] // error: code gen for Mirror can not access each case

0 commit comments

Comments
 (0)