Skip to content

Compiler inserting ??? with inline and erased terms #11996

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

Closed
japgolly opened this issue Apr 6, 2021 · 2 comments · Fixed by #12027
Closed

Compiler inserting ??? with inline and erased terms #11996

japgolly opened this issue Apr 6, 2021 · 2 comments · Fixed by #12027

Comments

@japgolly
Copy link
Contributor

japgolly commented Apr 6, 2021

Compiler version

3.0.1-RC1-bin-20210402-775d881-NIGHTLY

Minimized code

final class UnivEq[A]

object UnivEq:
  erased def force[A]: UnivEq[A] =
    compiletime.erasedValue

extension [A](a: A)
  inline def ==*[B >: A](b: B)(using erased UnivEq[B]): Boolean = a == b
  inline def !=*[B >: A](b: B)(using erased UnivEq[B]): Boolean = a != b

case class I(i: Int)

@main def main = {
  def test[A](a: A, b: A): Unit = {
    erased given UnivEq[A] = UnivEq.force[A]
    assert(a ==* a)
    assert(a !=* b)
  }
  println("Test starting...")
  test(I(1), I(2)) // error
  test(1, 2)
  test(true, false)
}

Output

> sbt run

[info] compiling 1 Scala source to ~/scala3bug/sbt/target/scala-3.0.1-RC1/classes ...
[info] done compiling
[info] running main 
Test starting...
[error] (run-main-c) scala.NotImplementedError: an implementation is missing
[error] scala.NotImplementedError: an implementation is missing
[error] 	at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
[error] 	at BUG$package$.test$1(BUG.scala:16)
[error] 	at BUG$package$.main(BUG.scala:20)
[error] 	at main.main(BUG.scala:13)
[error] 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error] 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error] 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error] 	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
[error] stack trace is suppressed; run last Compile / bgRun for the full output
[error] Nonzero exit code: 1
[error] (Compile / run) Nonzero exit code: 1
[error] Total time: 0 s, completed 6 Apr. 2021, 12:04:35 pm

Expectation

No runtime exception should be thrown. The compiler has inserted a ??? somewhere.

@odersky
Copy link
Contributor

odersky commented Apr 6, 2021

I believe the inliner replaces erased definitions with ???. Before inlining:

            final lazy given erased val given_UnivEq_A: UnivEq[A] = 
              UnivEq.force[A]
            if ==*[A](a)[A](a)(given_UnivEq_A).unary_! then 
              scala.runtime.Scala3RunTime.assertFailed()
             else ()

After inlining:

            final lazy given erased def given_UnivEq_A: UnivEq[A] = ???
            if 
              {
                val x$3$proxy1: UnivEq[A] = ???
                (a.==(a):Boolean)
              }.unary_!
             then scala.runtime.Scala3RunTime.assertFailed() else ()

Inliner should keep the erased references so that they can be flagged as errors in erasure.

@nicolasstucki
Copy link
Contributor

x$3$proxy1 should have been marked as erased as it is the proxy of an erased parameter. That would in turn remove the ??? that was left in the bytecode.

nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 8, 2021
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 15, 2021
Instead of erasing an erased term to `???` we erase it to `erasedValue[T]`.
This has 2 advantages, first the term does not lose it's type and second the
term is still marked as erased. The second implies that if there is a bug in
the compiler or a macro where term might end outside an erased context, the
code will not compiler. Currently the code compiles and then throws when
calling the spurious `???`. See scala#11996.
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 15, 2021
Instead of erasing an erased term to `???` we erase it to `erasedValue[T]`.
This has 2 advantages, first the term does not lose it's type and second the
term is still marked as erased. The second implies that if there is a bug in
the compiler or a macro where term might end outside an erased context, the
code will not compiler. Currently the code compiles and then throws when
calling the spurious `???`. See scala#11996.
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 15, 2021
Instead of erasing an erased term to `???` we erase it to `erasedValue[T]`.
This has 2 advantages, first, the term does not lose its type, and second, the
term is still marked as erased. The second implies that if there is a bug in
the compiler or a macro where the term might end outside an erased context, the
code will not compiler. Currently, the code compiles and then throws when
calling the spurious `???`. See scala#11996.
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 15, 2021
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 15, 2021
Instead of erasing an erased term to `???` we erase it to `erasedValue[T]`.
This has 2 advantages, first, the term does not lose its type, and second, the
term is still marked as erased. The second implies that if there is a bug in
the compiler or a macro where the term might end outside an erased context, the
code will not compiler. Currently, the code compiles and then throws when
calling the spurious `???`. See scala#11996.
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 15, 2021
Instead of erasing an erased term to `???` we erase it to `erasedValue[T]`.
This has 2 advantages, first, the term does not lose its type, and second, the
term is still marked as erased. The second implies that if there is a bug in
the compiler or a macro where the term might end outside an erased context, the
code will not compiler. Currently, the code compiles and then throws when
calling the spurious `???`. See scala#11996.
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 15, 2021
Instead of erasing an erased term to `???` we erase it to `erasedValue[T]`.
This has 2 advantages, first, the term does not lose its type, and second, the
term is still marked as erased. The second implies that if there is a bug in
the compiler or a macro where the term might end outside an erased context, the
code will not compiler. Currently, the code compiles and then throws when
calling the spurious `???`. See scala#11996.
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 20, 2021
Instead of erasing an erased term to `???` we erase it to `erasedValue[T]`.
This has 2 advantages, first, the term does not lose its type, and second, the
term is still marked as erased. The second implies that if there is a bug in
the compiler or a macro where the term might end outside an erased context, the
code will not compiler. Currently, the code compiles and then throws when
calling the spurious `???`. See scala#11996.
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Apr 22, 2021
Instead of erasing an erased term to `???` we erase it to `erasedValue[T]`.
This has 2 advantages, first, the term does not lose its type, and second, the
term is still marked as erased. The second implies that if there is a bug in
the compiler or a macro where the term might end outside an erased context, the
code will not compiler. Currently, the code compiles and then throws when
calling the spurious `???`. See scala#11996.
michelou pushed a commit to michelou/scala3 that referenced this issue Apr 27, 2021
Instead of erasing an erased term to `???` we erase it to `erasedValue[T]`.
This has 2 advantages, first, the term does not lose its type, and second, the
term is still marked as erased. The second implies that if there is a bug in
the compiler or a macro where the term might end outside an erased context, the
code will not compiler. Currently, the code compiles and then throws when
calling the spurious `???`. See scala#11996.
@Kordyjan Kordyjan added this to the 3.0.1 milestone Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants