简体   繁体   中英

Inexplicable type mismatch using Scala macros

I'm completely baffled by the following behavior of macros:

The problem: I'm trying to write a query engine for a model built on case classes , where the user only has to specify the fields against which he wishes to match.

The current approach: Currently, I'm doing the lazy thing and just exploiting default Scala pattern matching, using a macro to create the appropriate match statement. The code is the following:

// This is the macro code, defined in project `macros`
import scala.reflect.macros.whitebox

object QueryEngineMacros {
  import scala.language.experimental.macros
  def cimpl(c: whitebox.Context)(cs: c.Expr[CallSite], q: c.Expr[String]): c.Tree = {
    import c.universe._
    val pattern = cq"$q => true"
    q"""$cs match {
      case ${pattern}
      case _ => false
    }"""
  }

  def coincides(cs: CallSite, q: String): Boolean = macro cimpl
}

// This is the engine code, defined in project `queries` (depends on `macros`)
object QueryEngine {
  def apply(q: String, res: ExtractionResult): Seq[CallSite] =
    res.callSites.filter(cs => QueryEngineMacros.coincides(cs, q))
}

The error: This is my first time using Scala macros, but everything seems fine. It doesn't complain about dependencies either. However, I get this error message:

Error:(27, 66) type mismatch;
 found   : String
 required: some.package.CallSite
    res.callSites.filter(cs => QueryEngineMacros.coincides(cs, q))

Does anybody know what could be the cause of this?

EDIT: Typo fix

Sorry but Scala Macros just don't work this way. Yes Scala macros can generate new code but they are run at the compile time. But what you seemingly want is to generate some code in runtime depending on the parameter q you pass to the macro. This is impossible. Particularly the line

val pattern = cq"$q => true"

does not what you expect it to do. What you macro is actually generates is roughly following:

def apply(q: String, res: ExtractionResult): Seq[CallSite] =
    res.callSites.filter(cs => cs match {
       case q => true
       case _ => false
    })

So you try to match cs of type CallSite against q of type String (not the q interpreted as a piece of code!) ie you effectively check if cs is equal to q and the compiler sees that this match is just never true and says this to you in the error.

To sum up: if your q is actually a compile time constant, such macro provides almost no benefits. And if it is a runtime variable - such macro just want help at all.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM