Skip to content
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

Inner enum declarations cause initialization-checker error #14460

Closed
Xavientois opened this issue Feb 12, 2022 · 5 comments · Fixed by #14794 or #14916
Closed

Inner enum declarations cause initialization-checker error #14460

Xavientois opened this issue Feb 12, 2022 · 5 comments · Fixed by #14794 or #14916

Comments

@Xavientois
Copy link
Contributor

Compiler version

3.1.2-RC1

Minimized code

class Outer:
    enum MyEnum {
        case Case
    }

Output

-- Error: tests/init/pos/inner-enum.scala:3:8 --------------------------------------------------------------------------
3 |        case Case
  |        ^
  |        Cannot prove that the value is fully initialized. May only use initialized value as method arguments.
  |
  |        The unsafe promotion may cause the following problem:
  |        Access non-initialized value $values. Calling trace:
  |         -> case Case	[ inner-enum.scala:3 ]

Expectation

When compiling with the -Ysafe-init flag this declaration should pass.

@Xavientois Xavientois added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Feb 12, 2022
@Xavientois
Copy link
Contributor Author

This error appears to originate from the de-sugared code where the $values field of the enum's companion object is accessed

@Xavientois
Copy link
Contributor Author

I plan to try to find a fix for this

@liufengyun liufengyun added area:initialization and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Feb 12, 2022
@odersky odersky assigned olhotak and Xavientois and unassigned olhotak Feb 21, 2022
@Xavientois
Copy link
Contributor Author

Here is the de-sugared code for the above example:

package dotty.tools.dotc {
  @SourceFile("compiler/src/dotty/tools/dotc/MyOuter.scala") class MyOuter()
     extends
   Object() {
    @Child[(dotty.tools.dotc.MyOuter.MyEnum.Case : MyOuter.this.MyEnum)] sealed
      abstract
     class MyEnum() extends Object(), scala.reflect.Enum {}
    final lazy module val MyEnum: MyOuter.this.MyEnum =
      new MyOuter.this.MyEnum()
    final module class MyEnum() extends AnyRef(), scala.deriving.Mirror.Sum {
      case val Case: MyOuter.this.MyEnum = this.$new(0, "Case")
      private[this] val $values: Array[MyOuter.this.MyEnum] =
        Array.apply[MyOuter.this.MyEnum]([this.Case : MyOuter.this.MyEnum])(
          scala.reflect.ClassTag.apply[MyOuter.this.MyEnum](
            classOf[MyOuter.this.MyEnum]
          )
        )
      def values: Array[MyOuter.this.MyEnum] = this.$values.clone()
      def valueOf($name: String): MyOuter.this.MyEnum =
        $name match
          {
            case "Case" => this.Case
            case _ =>
              throw
                new IllegalArgumentException("enum case not found: ".+($name))
          }
      private[this] def $new(_$ordinal: Int, $name: String): MyOuter.this.MyEnum
         =
      {
        final class $anon() extends MyOuter.this.MyEnum(), runtime.EnumValue,
          scala.deriving.Mirror.Singleton
         {
          private def readResolve(): AnyRef =
            MyOuter.this.MyEnum.this.fromOrdinal(this.ordinal)
          override def productPrefix: String = $name
          override def toString(): String = $name
          override def ordinal: Int = _$ordinal
        }
        new
          MyOuter.this.MyEnum with runtime.EnumValue with
            scala.deriving.Mirror.Singleton
           {...}
        ():MyOuter.this.MyEnum & runtime.EnumValue
      }
      def fromOrdinal(ordinal: Int): MyOuter.this.MyEnum =
        try this.$values.apply(ordinal) catch
          {
            case _ => throw new NoSuchElementException(ordinal.toString())
          }
      type MirroredMonoType = MyOuter.this.MyEnum
      def ordinal(x$0: dotty.tools.dotc.MyOuter.MyEnum.MirroredMonoType): Int =
        x$0.ordinal
    }
  }
}

Further investigation indicates that this error comes from the definition of readResolve in the class $anon defined within $new. This method is not explicitly called anywhere in the generated code, but readResolve is used for serialization.

@liufengyun
Copy link
Contributor

enum Color:
  case Red, Blue

Desugars to:

  @SourceFile("examples/Enum.scala") @Child[(Color.Blue : Color)] @Child[
    (Color.Red : Color)
  ] sealed abstract class Color() extends Object(), scala.reflect.Enum {}
  final lazy module val Color: Color = new Color()
  @SourceFile("examples/Enum.scala") final module class Color() extends Object()
    ,
  scala.deriving.Mirror.Sum {
    private def writeReplace(): Object =
      new scala.runtime.ModuleSerializationProxy(classOf[Color])
    case <static> val Red: Color = Color.$new(0, "Red")
    case <static> val Blue: Color = Color.$new(1, "Blue")
    private val $values: Color[] =
      Array.apply(
        scala.runtime.ScalaRunTime.wrapRefArray([this.Red,this.Blue : Color])
      , scala.reflect.ClassTag.apply(classOf[Color])).asInstanceOf[Color[]]
    def values(): Color[] = Color.$values.clone().asInstanceOf[Color[]]
    def valueOf($name: String): Color =
      matchResult1[Color]:
        {
          case val x1: String = $name
          if "Red".==(x1) then return[matchResult1] this.Red else ()
          if "Blue".==(x1) then return[matchResult1] this.Blue else ()
          throw new IllegalArgumentException("enum case not found: ".+($name))
        }
    private def $new(_$ordinal: Int, $name: String): Color =
      {
        final class $anon() extends Color(), scala.runtime.EnumValue,
          scala.deriving.Mirror.Singleton
         {
          private def readResolve(): Object = Color.fromOrdinal(this.ordinal())
          override def productPrefix(): String = $name
          override def toString(): String = $name
          override def ordinal(): Int = _$ordinal
          def fromProduct(p: Product): Object = this.fromProduct(p)
        }
        new
          Color with scala.runtime.EnumValue with
            scala.deriving.Mirror.Singleton
           {...}
        ():Color
      }
    def fromOrdinal(ordinal: Int): Color =
      try Color.$values.[]apply(ordinal) catch
        {
          case _ =>
            throw
              new java.util.NoSuchElementException(
                scala.Int.box(ordinal).toString()
              )
        }
    def ordinal(x$0: Color): Int = x$0.ordinal()
    def ordinal(x: Object): Int = this.ordinal(x.asInstanceOf[Color])
  }

Xavientois added a commit to Xavientois/dotty that referenced this issue Mar 22, 2022
Closes scala#14460

Allow cold arguments to be passed if the parameter is `!Matchable` and the method is global static.
Xavientois added a commit to Xavientois/dotty that referenced this issue Mar 22, 2022
Closes scala#14460

Allow cold arguments to be passed if the parameter is `!Matchable` and the method is global static.
Xavientois added a commit to Xavientois/dotty that referenced this issue Mar 22, 2022
Closes scala#14460

Allow cold arguments to be passed if the parameter is `!Matchable` and the method is global static.
Xavientois added a commit that referenced this issue Mar 27, 2022
Closes #14460, #14751

Do not ensure that elements in a SeqLiteral are Hot.

Review by @liufengyun
Xavientois added a commit that referenced this issue Mar 28, 2022
Closes #14460, #14751

Do not ensure that elements in a SeqLiteral are Hot.

Review by @liufengyun
Xavientois added a commit that referenced this issue Apr 4, 2022
Closes #14460, #14751

Do not ensure that elements in a SeqLiteral are Hot.

Review by @liufengyun
Xavientois added a commit that referenced this issue Apr 4, 2022
Closes #14460, #14751

Do not ensure that elements in a SeqLiteral are Hot.

Review by @liufengyun
Xavientois added a commit that referenced this issue Apr 4, 2022
Closes #14460, #14751

Do not ensure that elements in a SeqLiteral are Hot.

Review by @liufengyun
Xavientois added a commit that referenced this issue Apr 4, 2022
Closes #14460, #14751

Do not ensure that elements in a SeqLiteral are Hot.

Review by @liufengyun
Xavientois added a commit that referenced this issue Apr 5, 2022
Closes #14460, #14751

Do not ensure that elements in a SeqLiteral are Hot.

Review by @liufengyun
Xavientois added a commit that referenced this issue Apr 5, 2022
Closes #14460, #14751

Do not ensure that elements in a SeqLiteral are Hot.

Review by @liufengyun
@liufengyun
Copy link
Contributor

This is not yet fixed, will be in #14751.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment