I am trying to define a Selectable
“dynamically” using the AST. My first attempt resulted in an error regarding overriding methods. I found out that the method names were incorrect. I have since deleted that post because now I have another error.
My current test is as follows:
package examples.instantiate
package test
import scala.annotation.experimental
@experimental
@main
def InstantiateYVals: Unit =
val myCommand = MyMacroYVals.client[Int](1)
val x = myCommand.field
val y = myCommand.selectDynamic("field")
val z = myCommand.applyDynamic("field")()
println("Vals 2")
A get the same error on all three calls:
[error] -- Error: /home/hmf/VSCodeProjects/sploty/meta/src/examples/instantiate/InstantiateYVals.scala:34:25
[error] 34 | val x = myCommand.field
[error] | ^
[error] |Sequence argument type annotation `*` cannot be used here:
[error] |it is not the only argument to be passed to the corresponding repeated parameter Any*
[error] -- Error: /home/hmf/VSCodeProjects/sploty/meta/src/examples/instantiate/InstantiateYVals.scala:35:34
[error] 35 | val y = myCommand.selectDynamic("field")
[error] | ^^^^^^^
[error] |Sequence argument type annotation `*` cannot be used here:
[error] |it is not the only argument to be passed to the corresponding repeated parameter Any*
[error] -- Error: /home/hmf/VSCodeProjects/sploty/meta/src/examples/instantiate/InstantiateYVals.scala:36:41
[error] 36 | val z = myCommand.applyDynamic("field")()
[error] | ^
[error] |Sequence argument type annotation `*` cannot be used here:
[error] |it is not the only argument to be passed to the corresponding repeated parameter Any*
[error] three errors found
The types and code seem to be correct. Here is the output of the macro function:
clsDefY
class Struct extends java.lang.Object with scala.Selectable {
val field: scala.Int = 1
final def selectDynamic(name: scala.Predef.String): scala.Any = {
scala.Predef.println(_root_.scala.StringContext.apply("Calling selectDynamic(?)").s())
-102
}
def applyDynamic(`name₂`: scala.Predef.String)(args: scala.collection.immutable.Seq[scala.Any] @scala.annotation.internal.Repeated): scala.Any = {
scala.Predef.println(_root_.scala.StringContext.apply("Calling applyDynamic(?)").s())
-103
}
}
newClsY
(new Struct(): Struct)
[Y] --->
Struct
resultY
{
class Struct extends java.lang.Object with scala.Selectable {
val field: scala.Int = 1
final def selectDynamic(name: scala.Predef.String): scala.Any = {
scala.Predef.println(_root_.scala.StringContext.apply("Calling selectDynamic(?)").s())
-102
}
def applyDynamic(`name₂`: scala.Predef.String)(args: scala.collection.immutable.Seq[scala.Any] @scala.annotation.internal.Repeated): scala.Any = {
scala.Predef.println(_root_.scala.StringContext.apply("Calling applyDynamic(?)").s())
-103
}
}
(new Struct(): Struct)
}
Below I provide the code I used for the test. Can anyone see the error I am making? Basically I use SelectableYBase
to extract the method type and symbol to construct the new class. I may be messing up here.
TIA
package examples.instantiate
import scala.annotation.experimental
import scala.quoted.*
@experimental
object MyMacroYVals:
trait SelectableYBase extends scala.Selectable:
final def selectDynamic(name: String): Any =
println(s"selectDynamic($name)")
100
def applyDynamic(name: String)(args: Any*): Any =
println(s"selectDynamic($name)(${args.mkString(",")})")
100
transparent inline def client[I](r: I): Any = ${MyMacroYVals.clientImpl[I]('r)}
def clientImpl[I: Type](r: Expr[I])(using Quotes): Expr[Any] =
import quotes.reflect.*
val selectable = TypeTree.of[scala.Selectable]
// selectDynamic
val apiTypeApply = TypeRepr.of[SelectableYBase]
assert(apiTypeApply.dealias.typeSymbol.isClassDef && apiTypeApply.dealias.classSymbol.isDefined)
val clssSym = apiTypeApply.dealias.classSymbol.get
val selectName = "selectDynamic"
val selectMethods = clssSym.declaredMethod(selectName)
assert(selectMethods.nonEmpty)
val selectMethod = selectMethods.head
val selectMethodInfo = selectMethod.info
val selectMethodType = selectMethodInfo match
case r:MethodType =>
val rtt = Inferred(r)
r
case _ => report.errorAndAbort("Expected a method type")
def selectDynamicY(parent: Symbol) =
Symbol.newMethod(parent,
selectName,
selectMethodType
)
// applyDynamic
val applyName = "applyDynamic"
val applyMethods = clssSym.declaredMethod(applyName)
assert(applyMethods.nonEmpty)
val applyMethod = applyMethods.head
val applyMethodInfo = applyMethod.info
val applyMethodType = applyMethodInfo match
case r:MethodType =>
val rtt = Inferred(r)
r
case _ => report.errorAndAbort("Expected a method type")
def applyDynamicY(parent: Symbol) =
Symbol.newMethod(parent,
applyName,
applyMethodType
)
// First parent must be a class
val parentsY = List(TypeTree.of[Object], selectable)
def declsX(cls: Symbol): List[Symbol] =
List(
Symbol.newVal(cls, "field", TypeRepr.of[I], Flags.Inline, Symbol.noSymbol ),
selectDynamicY(cls),
applyDynamicY(cls)
)
val clsX = Symbol.newClass(Symbol.spliceOwner, "Struct", parents = parentsY.map(_.tpe), declsX, selfType = None)
// Defining methods
val selectDef = DefDef(selectMethod,
argss =>
val nameTree = argss(0)(0)
val name = nameTree.asExprOf[String]
val code = '{
// val n = $name
// println(s"Calling selectDynamic($n)")
println(s"Calling selectDynamic(?)")
-102
}
Some(code.asTerm)
)
val applyDef = DefDef(applyMethod,
argss =>
val nameTree = argss(0)(0)
val name = nameTree.asExprOf[String]
val code = '{
// val n = $name
// println(s"Calling applyDynamic($n)")
println(s"Calling applyDynamic(?)")
-103
}
Some(code.asTerm)
)
// Defining value members
val fieldSymbol = clsX.declaredField("field")
val fieldValue = r.asTerm
val fieldDef2: ValDef = ValDef.apply(fieldSymbol, Some(fieldValue))
// adding methods and value
val clsDefY = ClassDef(clsX, parentsY, body = List(fieldDef2, selectDef, applyDef))
println("clsDefY")
println(clsDefY.show)
val xx = clsX.info.typeSymbol.typeRef
val yy = TypeTree.ref(clsX.info.typeSymbol)
val newClsX = Typed(Apply(Select(New(TypeIdent(clsX)), clsX.primaryConstructor), Nil), yy)
println("newClsY")
println(newClsX.show)
val typ1 = clsX.info
val tt = yy.tpe
val ttt = yy.tpe.asType
val blk = ttt match
case '[t] =>
println("[Y] ---> ")
println(Type.show[t])
Block(List(clsDefY), newClsX).asExprOf[t]
val resultY = blk
println("resultY")
println(resultY.show)
resultY
end MyMacroYVals