Skip to content

Commit f50529f

Browse files
committed
Fix cyclicity error for self-referential enum case
Fixes #11443 When an enum case references itself in a parent type (e.g., `case Nn extends Opt[Nothing] with Comparable[Nn.type]`), the compiler previously reported a cyclic reference error during type inference. The fix attempts to provide an explicit type annotation (the intersection of all parents) for parameterless enum cases early at desugaring time.
1 parent 23f5e32 commit f50529f

File tree

4 files changed

+20
-7
lines changed

4 files changed

+20
-7
lines changed

compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,15 @@ object DesugarEnums {
289289
val (tag, scaffolding) = nextOrdinal(name, CaseKind.Object, definesLookups)
290290
val impl1 = cpy.Template(impl)(parents = impl.parents :+ scalaRuntimeDot(tpnme.EnumValue), body = Nil)
291291
.withAttachment(ExtendsSingletonMirror, ())
292-
val vdef = ValDef(name, TypeTree(), New(impl1)).withMods(mods.withAddedFlags(EnumValue, span))
292+
293+
/** i11443: Attempt to provide an explicit type annotation for the enum case to allow certain cycles.
294+
* We pick the intersection of all parents, but only if they can be determined to be all types at this point.
295+
* Notably, this doesn't hold if one of the parents is a constructor call (e.g., extends Planet("Pluto")),
296+
* which might involve yet-to-be inferred generic parameters.
297+
*/
298+
val tpt = if impl.parents.forall(_.isType) then impl.parents.reduceLeft(makeAndType(_, _)) else TypeTree()
299+
300+
val vdef = ValDef(name, tpt, New(impl1)).withMods(mods.withAddedFlags(EnumValue, span))
293301
flatTree(vdef :: scaffolding).withSpan(span)
294302
}
295303
}

tests/neg/i6601.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
object GADTs2 {
22
enum Var[G, A] {
33
case Z[A, G]() extends Expr[(A, G), A] // error
4-
case X extends AnyRef // error
4+
case X extends AnyRef // error // error
55
}
66
enum Expr[G, A] {
77
case Lit[G](n: Int) extends Expr[G, Int]
88
// case S[A, G](x:
99
}
1010
enum Covariant[+T] {
11-
case Bottom extends AnyRef // error
11+
case Bottom extends AnyRef // error // error
1212
}
1313
enum Contravariant[-T] {
14-
case Top extends AnyRef // error
14+
case Top extends AnyRef // error // error
1515
}
1616
enum Color {
17-
case Red extends AnyRef // error
17+
case Red extends AnyRef // error // error
1818
}
1919
enum Parameterized[T](x: T) {
20-
case Foo extends AnyRef // error
20+
case Foo extends AnyRef // error // error
2121
}
2222
}

tests/pos/i11443.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
enum Opt[T] {
2+
case Nn extends Opt[Nothing] with Comparable[Nn.type]
3+
4+
def compareTo(nn: Nn.type) = 0
5+
}

tests/warn/i21860.scala renamed to tests/pos/i21860.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ enum Shape extends Figure:
88
case Ellipsis extends Shape
99

1010
def hasCorners(s: Shape): Boolean = s match
11-
case hasCorners: Corners => true // <--- reported as `Unreachable case`
11+
case hasCorners: Corners => true // <--- previously reported as `Unreachable case` (i21860), ok now (i11443)
1212
case _ => false
1313

1414
class Test:

0 commit comments

Comments
 (0)