Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Fix cyclicity error for self-referential enum case #24138

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
bracevac wants to merge 1 commit into scala:main from dotty-staging:ob-fix-11443
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,15 @@ object DesugarEnums {
val (tag, scaffolding) = nextOrdinal(name, CaseKind.Object, definesLookups)
val impl1 = cpy.Template(impl)(parents = impl.parents :+ scalaRuntimeDot(tpnme.EnumValue), body = Nil)
.withAttachment(ExtendsSingletonMirror, ())
val vdef = ValDef(name, TypeTree(), New(impl1)).withMods(mods.withAddedFlags(EnumValue, span))

/** i11443: Attempt to provide an explicit type annotation for the enum case to allow certain cycles.
* We pick the intersection of all parents, but only if they can be determined to be all types at this point.
* Notably, this doesn't hold if one of the parents is a constructor call (e.g., extends Planet("Pluto")),
* which might involve yet-to-be inferred generic parameters.
*/
val tpt = if impl.parents.forall(_.isType) then impl.parents.reduceLeft(makeAndType(_, _)) else TypeTree()

val vdef = ValDef(name, tpt, New(impl1)).withMods(mods.withAddedFlags(EnumValue, span))
Copy link
Member

@noti0na1 noti0na1 Oct 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we always add an explicit type without checking parent types?

sjrd reacted with thumbs up emoji
Copy link
Contributor

@odersky odersky Oct 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No because we have a constructor, not a type when we desugar.

Copy link
Contributor Author

@bracevac bracevac Oct 6, 2025
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The best explicit annotation at this point seems to be the intersection of the parents, but only if all parent trees are known to be types. For example, all bets are off with constructor calls, because we have not yet inferred types.

flatTree(vdef :: scaffolding).withSpan(span)
}
}
Expand Down
10 changes: 5 additions & 5 deletions tests/neg/i6601.scala
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
object GADTs2 {
enum Var[G, A] {
case Z[A, G]() extends Expr[(A, G), A] // error
case X extends AnyRef // error
case X extends AnyRef // error // error
}
enum Expr[G, A] {
case Lit[G](n: Int) extends Expr[G, Int]
// case S[A, G](x:
}
enum Covariant[+T] {
case Bottom extends AnyRef // error
case Bottom extends AnyRef // error // error
}
enum Contravariant[-T] {
case Top extends AnyRef // error
case Top extends AnyRef // error // error
}
enum Color {
case Red extends AnyRef // error
case Red extends AnyRef // error // error
}
enum Parameterized[T](x: T) {
case Foo extends AnyRef // error
case Foo extends AnyRef // error // error
}
}
5 changes: 5 additions & 0 deletions tests/pos/i11443.scala
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
enum Opt[T] {
case Nn extends Opt[Nothing] with Comparable[Nn.type]

def compareTo(nn: Nn.type) = 0
}
2 changes: 1 addition & 1 deletion tests/warn/i21860.scala → tests/pos/i21860.scala
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ enum Shape extends Figure:
case Ellipsis extends Shape

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

class Test:
Expand Down
Loading

AltStyle によって変換されたページ (->オリジナル) /