Skip to content

Commit 7707388

Browse files
committed
Refine isGenericSum condition
1 parent 064edf7 commit 7707388

File tree

4 files changed

+67
-5
lines changed

4 files changed

+67
-5
lines changed

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import NameKinds._
1313
import Flags._
1414
import Annotations._
1515
import ValueClasses.isDerivedValueClass
16+
import Decorators._
1617

1718
import language.implicitConversions
1819
import scala.annotation.tailrec
@@ -78,23 +79,34 @@ class SymUtils(val self: Symbol) extends AnyVal {
7879
def isGenericProduct(implicit ctx: Context): Boolean = whyNotGenericProduct.isEmpty
7980

8081
/** Is this a sealed class or trait for which a sum mirror is generated?
81-
* Excluded are
82+
* It must satisfy the following conditions:
83+
* - it has at least one child class or object
84+
* - none of its children are anonymous classes
85+
* - all of its children are addressable through a path from its companion object
86+
* - all of its children are generic products or singletons
8287
*/
8388
def whyNotGenericSum(implicit ctx: Context): String =
8489
if (!self.is(Sealed))
8590
s"it is not a sealed ${if (self.is(Trait)) "trait" else "class"}"
8691
else {
8792
val children = self.children
88-
def problem(child: Symbol) =
93+
val companion = self.linkedClass
94+
def problem(child: Symbol) = {
95+
96+
def isAccessible(sym: Symbol): Boolean =
97+
companion.isContainedIn(sym) || sym.is(Module) && isAccessible(sym.owner)
98+
8999
if (child == self) "it has anonymous or inaccessible subclasses"
100+
else if (!isAccessible(child.owner)) i"its child $child is not accessible"
90101
else if (!child.isClass) ""
91102
else {
92103
val s = child.whyNotGenericProduct
93104
if (s.isEmpty) s
94-
else "its child $child is not a generic product because $s"
105+
else i"its child $child is not a generic product because $s"
95106
}
107+
}
96108
if (children.isEmpty) "it does not have subclasses"
97-
else children.filter(_.isClass).map(problem).find(!_.isEmpty).getOrElse("")
109+
else children.map(problem).find(!_.isEmpty).getOrElse("")
98110
}
99111

100112
def isGenericSum(implicit ctx: Context): Boolean = whyNotGenericSum.isEmpty

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import typer.ProtoTypes.constrained
1212
import ast.untpd
1313
import ValueClasses.isDerivedValueClass
1414
import SymUtils._
15+
import config.Printers.derive
1516

1617
/** Synthetic method implementations for case classes, case objects,
1718
* and value classes.
@@ -419,8 +420,9 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
419420
addMethod(nme.ordinal, MethodType(monoType.typeRef :: Nil, defn.IntType),
420421
ordinalBody(_, _)(_))
421422
}
423+
else if (linked.is(Sealed))
424+
derive.println(i"$linked is not a sum because ${linked.whyNotGenericSum}")
422425
}
423-
424426
cpy.Template(impl)(parents = newParents, body = newBody)
425427
}
426428

tests/run/deriving.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
sealed trait T
2+
object T
3+
4+
case class A(x: Int, y: Int) extends T
5+
case object B extends T
6+
7+
object Test extends App {
8+
9+
case class AA[X >: Null <: AnyRef](x: X, y: X, z: String)
10+
}

tests/run/ordinal-innerclass.scala

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
object Test extends App {
2+
3+
class A {
4+
class B {
5+
object O {
6+
sealed trait T
7+
case class C(x: Int) extends T
8+
object T {
9+
case class D() extends T
10+
}
11+
}
12+
}
13+
}
14+
15+
val a = new A
16+
val b = new a.B
17+
val o = b.O
18+
val sum: deriving.Mirror.Sum { type MonoType = o.T }= o.T.asInstanceOf
19+
assert(sum.ordinal(new o.C(1)) == 0)
20+
assert(sum.ordinal(new o.T.D()) == 1)
21+
22+
object MR {
23+
// from betterFiles/ManagedResource: FM should not be treated as a generic sum
24+
// since its children are not accessible from its companion object. If it was
25+
// treated as a generic sum, ExplicitOuter would crash when compiling the synthesized
26+
// `ordinal` method.
27+
sealed trait FM
28+
object FM {
29+
trait I {
30+
object fm1 extends FM
31+
object fm2 extends FM
32+
}
33+
}
34+
}
35+
36+
trait T1
37+
case class A1() extends T1
38+
}

0 commit comments

Comments
 (0)