Skip to content

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

Closed
@smarter

Description

@smarter

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.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions