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

Override added using macro annotation does not get the expected bridge because the symbol isn't entered in the class decls #18806

Closed
smarter opened this issue Oct 31, 2023 · 2 comments · Fixed by #18826

Comments

@smarter
Copy link
Member

smarter commented Oct 31, 2023

Compiler version

Latest main: 58810fd

Minimized code

Macro_1.scala:

import scala.annotation.{experimental, MacroAnnotation}
import scala.quoted._

@experimental
class gen extends MacroAnnotation:
  def transform(using Quotes)(tree: quotes.reflect.Definition): List[quotes.reflect.Definition] =
    import quotes.reflect._
    tree match
      case ClassDef(name, ctr, parents, self, body) =>
        val cls = tree.symbol
        // val meth = cls.methodMember("foo").head
        // val fooTpe = cls.typeRef.memberType(meth)

        val overrideTpe =  MethodType(Nil)(_ => Nil, _ => defn.StringClass.typeRef)

        val fooOverrideSym = Symbol.newMethod(cls, "foo", overrideTpe, Flags.Override, Symbol.noSymbol)

        val fooDef = DefDef(fooOverrideSym, _ => Some(Literal(StringConstant("hi"))))

        val newClassDef = ClassDef.copy(tree)(name, ctr, parents, self, fooDef :: body)
        List(newClassDef)
      case _ =>
        report.error("Annotation only supports `class`")
        List(tree)

Test_2.scala:

class Base:
  def foo(): Object = ???

@gen
class Sub extends Base
// > override def foo(): String = "hi"

@main def Test(): Unit =
  val sub = new Sub
  println(sub.foo())

Output

> scalac -Xcheck-macros Macro_1.scala Test_2.scala
> scala Test
Exception in thread "main" scala.NotImplementedError: an implementation is missing
        at scala.Predef$.$qmark$qmark$qmark(Predef.scala:344)
        at Base.foo(Test_2.scala:2)
        at Test_2$package$.Test(Test_2.scala:14)
        at Test.main(Test_2.scala:12)

Expectation

> scala Test
hi

Analysis

The output from -Xprint:erasure contains:

  class Sub() extends Base() {
    override def foo(): String = "hi"
  }

Notice that the bridge to def foo(): Object is missing. As far as I can tell the issue is that the overridden symbol is never entered into the decls of the enclosing class, so the bridge-generation logic does not even know it exists. Surprisingly -Ycheck:all does not catch this mismatch between decls and trees.

@hamzaremmal
Copy link
Member

@nicolasstucki Should I take over this issue ?

@hamzaremmal
Copy link
Member

Fixed in #18826

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants