-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Instantiating a forwarder trait #16366
-
Hi! I'm trying to build a macro that builds a proxy for arbitrary traits. I'm having trouble using the parameters the method is called with.
Here's what the macro looks like:
//> using scala "3.2.1" //> using option "-Ycheck:all" //> using option "-Xcheck-macros" ////> using option "-Xprint:inlining" //> using option "-Xprint-types" import scala.quoted._ import scala.annotation.experimental object macros { trait Proxxy[Alg] { def proxify(fa: Alg): Alg } inline def mkProxy[Alg]: Proxxy[Alg] = ${ mkProxyImpl[Alg] } @experimental def mkProxyImpl[Alg: Type](using Quotes): Expr[Proxxy[Alg]] = { val Typ = Type.of[Alg] import quotes.reflect._ import quotes.reflect.given def instance( fExpr: Expr[Alg] )( using Quotes ): Expr[Alg] = { val par = TypeRepr.of[Alg] def methodSymbols( owner: Symbol ): List[Symbol] = par.typeSymbol.declaredMethods.map { baseMethod => val deff = baseMethod.tree.asInstanceOf[DefDef] val paramVals = deff.paramss.flatMap(_.params.asInstanceOf[List[ValDef]]) Symbol.newMethod( parent = owner, baseMethod.name, TypeRepr.of[Alg].memberType(baseMethod), ) } val cl = Symbol.newClass( Symbol.spliceOwner, "$anon", parents = List( TypeRepr.of[Object], par, ), decls = methodSymbols(_), selfType = None, ) val defs = methodSymbols(cl).map { m => DefDef( m, args => Some { fExpr .asTerm .select(cl.declaredMethod(m.name).head) .appliedToArgss( args.map( _.map { a => // the problematic part, apparently a.asExpr.asTerm } ) ) // should I do this? doesn't seem to have an effect // .changeOwner(m) }, ) } Block( List( ClassDef(cl, Nil, defs) ), New(TypeTree.ref(cl)) .select(cl.primaryConstructor) .appliedToArgs(Nil), ).asExprOf[Alg] } '{ new Proxxy[Alg] { def proxify(fa: Alg): Alg = ${ instance('fa) } } } } }
I'm trying it with this trait:
trait MyAlg { def hello(s: String): Int }
and the error I'm getting is:
Error: Unexpected error when compiling project_466232d218: 'Could not find proxy for s: String in [parameter s, method hello, anonymous class Object with demo.MyAlg {...}, value macro, getter derivedProxy, object demo, package <empty>, package <root>], encl = package <empty>, owners = package <empty>, package <root>; enclosures = package <empty>, package <root>'
I've tried dozens of combinations of moving things around, changing owners, different ways to refer to the parameter, and I keep running into the same issue. I would appreciate any and all help and resources on this.
As you can see, I'm using -Xcheck-macros and -Xcheck:all, but they don't offer any help.
Related: #13571
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 1 comment 3 replies
-
I don't think you should be calling methodSymbols twice, that will create two sets of independent symbols
Beta Was this translation helpful? Give feedback.
All reactions
-
hmm, I guess there's a way I didn't consider before... lemme try that.
Beta Was this translation helpful? Give feedback.
All reactions
-
yeah, that does the trick! Is there something we can do about the error message to make the problem easier to understand?
Beta Was this translation helpful? Give feedback.
All reactions
-
also, are the Symbol.new*** the only impure parts of the reflect API or are there more?
Beta Was this translation helpful? Give feedback.