Skip to content

Possible bug in tasty reflection regarding matching of trees #12253

@wookievx

Description

@wookievx

Compiler version

3.0.0-RC3

Minimized example

I am attempting to extract name of the selected field from lambda expression (to create lens-like functionality). I am attempting to remove layers of inlined because of the passing of the lambda as an inline parameter multiple times

//macros definition
import scala.quoted.{given, *}
import deriving.*,  compiletime.*

object MacroUtils:
  transparent inline def extracNameFromSelector[To, T](inline code: To => T) = ${extractNameFromSelectorImpl('code)}

  def extractNameFromSelectorImpl[To: Type, T: Type](code: Expr[To => T])(using Quotes): Expr[String] = 
    import quotes.reflect.*
    val extractors = new Extractors
    code.asTerm match
     case extractors.InlinedLambda(_, Select(_, name)) => Expr(name)
     case t => report.throwError(s"Illegal argument to extractor: ${code.show}, in tasty: $t")

  class Extractors(using val quotes: Quotes):
    //attempt to strip away consecutive inlines in AST and extract only final lambda
    import quotes.reflect.*

    object InlinedLambda:
      def unapply(arg: Term): Option[(List[ValDef], Term)] = 
        arg match
          case Inlined(_, _, Lambda(vals, term)) => Some((vals, term))
          case Inlined(_, _, nested) => InlinedLambda.unapply(nested)
          case t => None
    end InlinedLambda

  end Extractors
end MacroUtils

object Usage:
  case class Bar(x: Int, y: String, z: (Double, Double))
  MacroUtils.extractNameFromSelector[Bar, String](_.y + "abc")
end Usage

Full example can be found here:

https://github.com/wookievx/chimney/blob/chimney3/chimney3/src/test/scala/io/scalaland/chimney/TransformerDslSpec.scala#L69

Output

When attempting to compile Usage I get the following compilation exception:

  • "java.lang.ClassCastException: dotty.tools.dotc.ast.Trees$Apply cannot be cast to dotty.tools.dotc.ast.Trees$Select"

When macro is invoked with correct lambda body (for example: _.y), the following error is reported in the macro instead (but name extraction works fine):

  • (at line case extractors.InlinedLambda(, Select(, name)): "the type test for extractors.quotes.reflect.Term cannot be checked at runtime"

I am suspecting that I messed-up imports and I am using wrong extractors (via importing quotes.reflect multiple times or something like that)

Expectation

I am trying to provide nice error message in case passed lambda expression is incorrect (which should be matched correctly given my understanding of quotes.reflect extractors) and also avoid this warning, which hints that for some reason some unsound pattern matching is taking place in macro implementation.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions