Scala 3 macro Found: (x$1 : x$1².reflect.Symbol) Required: quoted.Quotes

Viewed 93
def printParamsImpl[A](using Quotes, Type[A]): Expr[() => Unit] = {
  import quotes.reflect._
    TypeRepr.of[A].typeSymbol.declaredMethods.collect {
      case m if m.paramSymss.size == 1 =>
        val params = m.paramSymss.head
        val paramNames = {
          val exprList = params.map {  p =>
            Expr(p.name)
          }
          Expr.ofList(exprList)
        }
    
        '{ 
          println(${paramNames})
        }
    }

The above code complains

Found:    (x$1 : x$1².reflect.Symbol)
Required: quoted.Quotes

where:    x$1  is a parameter in an anonymous function in method printParamsImpl
          x$1² is a parameter in method printParamsImpl

Just don't know what the error message means.

See Live Demo

1 Answers

The error seems to originate in the use of scala.quoted.quotes, which looks like this:

transparent inline def quotes(using inline q: Quotes): q.type = q

This appears to work, because you have (using Quotes). But, it doesn't seem to be able to assign a stable single type (the q.type) because the Quotes isn't named.

If you change it to (using q: Quotes), and then import q.reflect._, then this particular error goes away (though it then reveals some other errors in the example).

Here's a finished example which does what I think you were trying to do:

  def printParamsImpl[A](using q: Quotes)(using Type[A]): Expr[() => Unit] = {
    import q.reflect._
    
    val paramNames = Expr.ofList {
      // In each declared method, get a list of the names of each parameter in the first parameter list.
      // Flatten those into a single list of String expressions
      TypeRepr.of[A].typeSymbol.declaredMethods.collect {
        case m if m.paramSymss.size == 1 =>
          val params = m.paramSymss.head
          params.map {  p =>
            Literal(StringConstant(p.name)).asExprOf[String]
          }
      }.flatten
    }

    '{
    () => println(${paramNames})
    }
  }

  inline def foo[A]: () => Unit = ${printParamsImpl[A]}

A Scastie of this is here, but it still won't run – you can't invoke a macro in the same compilation unit as it's defined.

But, if you make a project with the definition under main sources, and the invocation under test sources (say, in an App object), you'll be able to run it with sbt test:run (since the main and test sources are separate compilation runs).

Related