scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.79k stars 1.04k forks source link

Orphan type parameter references crash pickler in capture checked programs #20272

Open Linyxus opened 4 months ago

Linyxus commented 4 months ago

Compiler version

main

Minimized code

  import language.experimental.captureChecking

  trait Iterable[T] { self: Iterable[T]^ =>
    def map[U](f: T => U): Iterable[U]^{this, f}
  }

  object Test {
    def assertEquals[A, B](a: A, b: B): Boolean = ???

    def foo[T](level: Int, lines: Iterable[T]) =
      lines.map(x => x)

    def bar(messages: Iterable[String]) =
      foo(1, messages)

    val it: Iterable[String] = ???
    val msgs = bar(it)

    assertEquals(msgs, msgs)
  }

Output

error when pickling type T
error when pickling type T -> T
error when pickling tree f
error when pickling tree [this,f : Any @retainsArg]
error when pickling tree [this,f : Any @retainsArg]*
error when pickling tree new _root_.scala.annotation.retains([this,f : Any @retainsArg]*)
error when pickling type Iterable[String]^{this, T -> T}
error when pickling tree Iterable[String]^{this, T -> T}
error when pickling tree Test.assertEquals[Iterable[String]^{this, T -> T}, Iterable[String]^{this, T -> T}]
error when pickling tree Test.assertEquals[Iterable[String]^{this, T -> T}, Iterable[String]^{this, T -> T}](Test.msgs, Test.msgs)
error when pickling tree () extends Object() { this: Test.type =>
  private def writeReplace(): AnyRef = new scala.runtime.ModuleSerializationProxy(classOf[Test.type])
  def assertEquals[A >: Nothing <: Any, B >: Nothing <: Any](a: A, b: B): Boolean = ???
  def foo[T >: Nothing <: Any](level: Int, lines: Iterable[T]): Iterable[T]^{} =
    lines.map[T](
      {
        def $anonfun(x: T): T = x
        closure($anonfun)
      }
    )
  def bar(messages: Iterable[String]): Iterable[String]^{} = Test.foo[String](1, messages)
  val it: Iterable[String] = ???
  val msgs: Iterable[String]^{} = Test.bar(Test.it)
  Test.assertEquals[Iterable[String]^{this, T -> T}, Iterable[String]^{this, T -> T}](Test.msgs, Test.msgs)
}
...

Expectation

It should at least not crash.

Linyxus commented 4 months ago

Minimised from the failing projects in https://github.com/scala/scala3/pull/19939#issuecomment-2051527673

Linyxus commented 4 months ago

Another case with overriden methods:

  import language.experimental.captureChecking

  trait Iterable[T] { self: Iterable[T]^ =>
    def map[U](f: T => U): Iterable[U]^{this, f}
  }

  object Test {
    def foo[T](level: Int, lines: Iterable[T]) =
      lines.map(x => x)

    class Bar:
      def bar(messages: Iterable[String]) =
        foo(1, messages)
    class Baz extends Bar:
      override def bar(messages: Iterable[String]) = ???
  }