Skip to content

TreeMap.transformTree operation not being applied after inlining #13531

@hughsimpson

Description

@hughsimpson

Compiler version

3.0.2

Minimized code

File 1:

package bug

import scala.quoted.*

object Macros { inline def mk[T]: T = ${ MacroImpl.mk[T] } }

object MacroImpl { def mk[T](using Quotes, Type[T]): Expr[T] = new Maker[T].make }

class Maker[T](using Quotes, Type[T]) {
  import quotes.reflect.*

  def make: Expr[T] = new TreeMap {
    override def transformTerm(tree: Term)(owner: Symbol): Term = {
      tree match {
        case Block(stats, Typed(expr, tpt)) =>
          Block.copy(tree)(transformStats(stats)(owner), Typed(expr, TypeTree.of[T]))
        case other => super.transformTerm(tree)(owner)
      }
    }
    override def transformStatement(tree: Statement)(owner: Symbol): Statement = {
      tree match {
        case c @ ClassDef(name, cstr, lsel, self, body) =>
          ClassDef.copy(c)(name, cstr, lsel :+ TypeTree.of[T], self, body)
        case other => super.transformStatement(tree)(owner)
      }
    }
  }.transformTree('{ new {} }.asTerm)(Symbol.spliceOwner).asExprOf[T]
}

File 2:

package bug

import Macros._

trait Foo {}

object M extends App {
  val x = mk[Foo]
}

Output

[info] running bug.M
[error] (run-main-0) java.lang.ExceptionInInitializerError
[error] java.lang.ExceptionInInitializerError
[error] 	at java.base/java.lang.J9VMInternals.ensureError(J9VMInternals.java:184)
[error] 	at java.base/java.lang.J9VMInternals.recordInitializationFailure(J9VMInternals.java:173)
[error] 	at bug.M.main(Main.scala)
[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] Caused by: java.lang.ClassCastException: bug.M$$anon$1 incompatible with bug.Foo
[error] 	at bug.M$.<clinit>(Main.scala:10)
[error] 	at bug.M.main(Main.scala)
[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)

Expectation

My expectation was that I would be able to use this approach to build some stub objects for various traits -- the expr tree certainly looks like what I was hoping for -

{
  final class $anon() extends bug.Foo

  (new $anon(): bug.Foo)
}
  • however it didn't. This is quite possibly not a bug and simply a case of me abusing the API to try to do what was never intended, but it had the feel of one. Attempting to add new statements to the body in a ClassDef.copy call also caused some additional failures, but I've excluded that from this example to keep things more minimal, and in case this isn't a bug but a misunderstanding of the feature.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions