Piotr Jósiak
Piotr Jósiak

Reputation: 65

Macro compilation error on non-trivial lambda

I wanted to write a macro that will inspect and modify a lamba. For now macro looks like this (it doesn't do any modification):

object Macro {
  def literalInt(c: blackbox.Context)(func: c.Expr[Int => Int]): c.Expr[Int => Int] = {
    import c.universe._

    val Function(params, body) = func.tree

    c.Expr(Function(params, body))
  }
  
  def lit(func: Int => Int): Int => Int = macro literalInt

}

It works fine for trivial lambdas, like:

Macro.lit(_ + 19)

but it fails on

Macro.lit { args =>
    val temp = 10
    args + temp * 2
}

with error:

scalac: Error while emitting App.scala
value temp

Does anyone know what and why is going on?

Upvotes: 0

Views: 123

Answers (1)

Dmytro Mitin
Dmytro Mitin

Reputation: 51658

Read Macrology 201 about owner chain corruptions

https://github.com/scalamacros/macrology201/tree/part1

https://github.com/scalamacros/macrology201/commits/part1 (especially step 21 and thereafter)

An easy workaround to the owner chain corruption problem is erasing the chunk of the symbol table whose corresponding code is undergoing radical transformations. After the symbols in the problematic trees are erased, post-expansion typecheck is going to recreate them from scratch, keeping the symbol table consistent. This is done by a dedicated macro API called c.untypecheck in Scala 2.11* and c.resetLocalAttrs in Scala 2.10.

(*) And Scala 2.12-2.13.

Try to untypecheck incoming trees (in easy cases this should be enough)

def literalInt(c: blackbox.Context)(func: c.Expr[Int => Int]): c.Expr[Int => Int] = {
  import c.universe._

  val Function(params, body) = c.untypecheck(func.tree)

  c.Expr(Function(params, body))
}

Using scala macro to manipulate variable declaration

Macro untypecheck required

What is wrong with this def macro?

How to use a `universe.Tree` created and type-checked in one Scala macro execution, in another macro execution?

Upvotes: 1

Related Questions