From 15ec5b6fcb7895fb5c373ff6ac51155887f8acd5 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Fri, 25 Feb 2022 11:13:40 -0500 Subject: [PATCH] Fix safe-init error in DesugarEnums When bootstrapping the compiler with the `-Ysafe-init` flag, we would get the following error: ``` [error] -- Error: /Users/********/dotty/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala:20:39 [error] 20 | val Simple, Object, Class: Value = Value [error] | ^^^^^ [error] |Calling the external method method Value may cause initialization errors. ``` This error orginates from the Scala 2 `Enumeration` class definition. In order to circumvent this issue, we instead define `CaseKind` using a Scala 3 enum. While this does require enum comparisons using `<` or `<=` to explicitly compare the `ordinal` of the enum variant, it also eliminates the initialization error. Review by @liufengyun --- .../dotty/tools/dotc/ast/DesugarEnums.scala | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala index b86d87a41889..096a885dcf32 100644 --- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala +++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala @@ -16,21 +16,20 @@ import scala.annotation.internal.sharable object DesugarEnums { import untpd._ - @sharable object CaseKind extends Enumeration { - val Simple, Object, Class: Value = Value - } + enum CaseKind: + case Simple, Object, Class - final case class EnumConstraints(minKind: CaseKind.Value, maxKind: CaseKind.Value, enumCases: List[(Int, RefTree)]): - require(minKind <= maxKind && !(cached && enumCases.isEmpty)) + final case class EnumConstraints(minKind: CaseKind, maxKind: CaseKind, enumCases: List[(Int, RefTree)]): + require(minKind.ordinal <= maxKind.ordinal && !(cached && enumCases.isEmpty)) def requiresCreator = minKind == CaseKind.Simple - def isEnumeration = maxKind < CaseKind.Class - def cached = minKind < CaseKind.Class + def isEnumeration = maxKind.ordinal < CaseKind.Class.ordinal + def cached = minKind.ordinal < CaseKind.Class.ordinal end EnumConstraints /** Attachment containing the number of enum cases, the smallest kind that was seen so far, * and a list of all the value cases with their ordinals. */ - val EnumCaseCount: Property.Key[(Int, CaseKind.Value, CaseKind.Value, List[(Int, TermName)])] = Property.Key() + val EnumCaseCount: Property.Key[(Int, CaseKind, CaseKind, List[(Int, TermName)])] = Property.Key() /** Attachment signalling that when this definition is desugared, it should add any additional * lookup methods for enums. @@ -249,11 +248,11 @@ object DesugarEnums { * - scaffolding containing the necessary definitions for singleton enum cases * unless that scaffolding was already generated by a previous call to `nextEnumKind`. */ - def nextOrdinal(name: Name, kind: CaseKind.Value, definesLookups: Boolean)(using Context): (Int, List[Tree]) = { + def nextOrdinal(name: Name, kind: CaseKind, definesLookups: Boolean)(using Context): (Int, List[Tree]) = { val (ordinal, seenMinKind, seenMaxKind, seenCases) = ctx.tree.removeAttachment(EnumCaseCount).getOrElse((0, CaseKind.Class, CaseKind.Simple, Nil)) - val minKind = if kind < seenMinKind then kind else seenMinKind - val maxKind = if kind > seenMaxKind then kind else seenMaxKind + val minKind = if kind.ordinal < seenMinKind.ordinal then kind else seenMinKind + val maxKind = if kind.ordinal > seenMaxKind.ordinal then kind else seenMaxKind val cases = name match case name: TermName => (ordinal, name) :: seenCases case _ => seenCases