Result type in structural refinement?

This code fails to compile with Result type in structural refinement may not refer to a user-defined value class:

object Repro {
  class Foo {}

  case class Wrapper(val underlying: Int) extends AnyVal

  def main(args: Array[String]): Unit = {
    new Foo {
      val w = Wrapper(1)
    }    
    new Foo {} // Fails to compile if this line is present
  }
}

/*
Compile error:
[error] Result type in structural refinement may not refer to a user-defined value class
[error]       val w = Wrapper(1)
[error]           ^
*/

However, if I remove the second new Foo, then it compiles successfully:

object Repro {
  class Foo {}

  case class Wrapper(val underlying: Int) extends AnyVal

  def main(args: Array[String]): Unit = {
    new Foo {
      val w = Wrapper(1)
    }    
    // new Foo {} // Successfully compiles when this line is removed
  }
}

Why does the second appearance of new Foo cause a compile error? I am using Scala 2.13.14.

That’s a good one. I don’t know that it is intended, but if you omit the unit value, the refinement member is no longer public:

  def main(args: Array[String]): Unit = {
    new Foo {
      val w = Wrapper(1)
    }
    ()
  }

That’s because of the tree shape, which becomes:

class anon { }; { new anon(); () }

due to “value discard”, which could also be called, “insert a unit value”.

The discarded expression is wrapped in a block with the unit value, so the refinement members are overlooked for these checks.

Possibly that is OK, since the result can’t be used in that position anyway.

I verified that this error is still required: it’s really a limitation in how value classes are handled and how members of the refinement class are generated. Without the check, there is a ClassCastException where the boxed type is expected instead of unboxed.

Scala 3 seems to have a different set of limitations and issues.

1 Like