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

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

Open
Linyxus opened this issue Apr 26, 2024 · 2 comments · May be fixed by #20305
Open

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

Linyxus opened this issue Apr 26, 2024 · 2 comments · May be fixed by #20305
Assignees
Labels
area:experimental:cc Capture checking related cc-experiment Intended to be merged with cc-experiment branch on origin itype:bug

Comments

@Linyxus
Copy link
Contributor

Linyxus commented Apr 26, 2024

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 Linyxus added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Apr 26, 2024
@Linyxus Linyxus self-assigned this Apr 26, 2024
@Linyxus Linyxus added cc-experiment Intended to be merged with cc-experiment branch on origin area:experimental:cc Capture checking related and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Apr 26, 2024
@Linyxus
Copy link
Contributor Author

Linyxus commented Apr 26, 2024

Minimised from the failing projects in #19939 (comment)

@Linyxus
Copy link
Contributor Author

Linyxus commented Apr 30, 2024

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]) = ???
  }

odersky added a commit that referenced this issue Dec 17, 2024
In a nutshell: when mapping annotated types, we can currently end up
with the same symbol being declared in distinct trees, which crashes the
pickler as it expects each symbol to be declared in a single place. See
#19957 (comment) and
#19957 (comment) for
more context.

This PR ensures that all symbols in annotation trees are different by
creating fresh symbols for all symbols in annotation tree during
`PostTyper`.

In my [previous
attempt](ab70f18)
which was discussed on #19957, I did it in `Annotations.mapWith`. Here,
it's only done once in `PostTyper`, so this is more lightweight.

Fixes #17939, fixes #19846 and fixes (partially?) #20272.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:experimental:cc Capture checking related cc-experiment Intended to be merged with cc-experiment branch on origin itype:bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant