tus*_*ath 1 scala scala-macros scala-quasiquotes scala-3
使用 Scala2,我可以实现宏并使用tq准引用语法生成类型,例如:
q"""
new Foo {
type Bar = ${tq"(..$params)"}
}
"""
Run Code Online (Sandbox Code Playgroud)
我可以用这种语法做两件事 -
Bar基于params.params。如何使用 Scala 3 实现这一目标?
Scala 3 中没有准引号( q"...", tq"...", pq"...", cq"...", fq"...")。感觉就像是 Scala 2.10 中宏的早期:)
Scala 3引用 '{...}(和拼接${...})不仅必须在主代码的编译时(即宏运行时,宏展开时)进行类型检查,而且还必须在宏本身的编译时进行早期类型检查。这类似于Scala 2 中的(reify {...}和)。.splice
new Foo {...}实际上是一个扩展的匿名类的实例Foo。所以请参阅您之前的问题Macro class nameexpansion in Scala 3 , Method Override with Scala 3 Macros
一切都取决于 和 是否Foo静态params已知。如果是这样,那么一切就很容易了:
import scala.quoted.*
trait Foo
inline def doSmth[A](x: Int): Unit = ${doSmthImpl[A]('x)}
def doSmthImpl[A](x: Expr[Int])(using Quotes, Type[A]): Expr[Unit]= {
// import quotes.reflect.*
'{
new Foo {
type Bar = (Double, Boolean)
}
// doing smth with this instance
}
}
Run Code Online (Sandbox Code Playgroud)
或者
val params = Type.of[(Double, Boolean)]
'{
new Foo {
type Bar = $params
}
}
Run Code Online (Sandbox Code Playgroud)
或者
'{
new Foo {
type Bar = params.Underlying
}
}
Run Code Online (Sandbox Code Playgroud)
在评论中@Jasper-MFoo建议当我们有静态但params非静态时如何处理这种情况:
type X
given Type[X] = paramsTypeTree.tpe.asType.asInstanceOf[Type[X]]
'{
new Foo {
type Bar = X
}
}
Run Code Online (Sandbox Code Playgroud)
或者
paramsTypeTree.tpe.asType match {
case '[x] =>
'{
new Foo {
type Bar = x
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在假设它Foo是静态未知的。由于没有准引号,在 Scala 3 中构建树的唯一不同方法是深入到 Tasty反射级别并手动构建树。因此,您可以打印静态类型检查代码树并尝试手动重建它。代码
println('{
new Foo {
type Bar = (Double, Boolean)
}
}.asTerm.underlyingArgument.show
Run Code Online (Sandbox Code Playgroud)
印刷
{
final class $anon() extends App.Foo {
type Bar = scala.Tuple2[scala.Double, scala.Boolean]
}
(new $anon(): App.Foo)
}
Run Code Online (Sandbox Code Playgroud)
和
println('{
new Foo {
type Bar = (Double, Boolean)
}
}.asTerm.underlyingArgument.show(using Printer.TreeStructure))
Run Code Online (Sandbox Code Playgroud)
印刷
Block(
List(ClassDef(
"$anon",
DefDef("<init>", List(TermParamClause(Nil)), Inferred(), None),
List(
Apply(Select(New(Inferred()), "<init>"), Nil),
TypeIdent("Foo")
),
None,
List(TypeDef(
"Bar",
Applied(
Inferred(),
List(TypeIdent("Double"), TypeIdent("Boolean")) // this should be params
)
))
)),
Typed(
Apply(Select(New(TypeIdent("$anon")), "<init>"), Nil),
Inferred()
)
)
Run Code Online (Sandbox Code Playgroud)
这里的另一个复杂之处是 Scala 3 宏接受类型化树并且必须返回类型化树。所以我们也必须处理符号。
实际上,在反射 API 中我可以看到 Symbol.newMethod, Symbol.newClass, Symbol.newVal,Symbol.newBind但没有Symbol.newType。(事实证明,新类型成员的方法没有暴露给反射API,所以我们必须使用内部 dotty.tools.dotc.core.Symbols.newSymbol。)
我可以想象类似的事情
val fooTypeTree = TypeTree.ref(Symbol.classSymbol("mypackage.App.Foo"))
val parents = List(TypeTree.of[AnyRef], fooTypeTree)
def decls(cls: Symbol): List[Symbol] = {
given dotty.tools.dotc.core.Contexts.Context =
quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
import dotty.tools.dotc.core.Decorators.toTypeName
List(dotty.tools.dotc.core.Symbols.newSymbol(
cls.asInstanceOf[dotty.tools.dotc.core.Symbols.Symbol],
"Bar".toTypeName,
Flags.EmptyFlags/*Override*/.asInstanceOf[dotty.tools.dotc.core.Flags.FlagSet],
TypeRepr.of[(Double, Boolean)]/*params*/.asInstanceOf[dotty.tools.dotc.core.Types.Type]
).asInstanceOf[Symbol])
}
val cls = Symbol.newClass(Symbol.spliceOwner, "FooImpl", parents = parents.map(_.tpe), decls, selfType = None)
val typeSym = cls.declaredType("Bar").head
val typeDef = TypeDef(typeSym)
val clsDef = ClassDef(cls, parents, body = List(typeDef))
val newCls = Typed(Apply(Select(New(TypeIdent(cls)), cls.primaryConstructor), Nil), fooTypeTree)
Block(List(clsDef, newCls), '{()}.asTerm).asExprOf[Unit]
//{
// class FooImpl extends java.lang.Object with mypackage.App.Foo {
// type Bar = scala.Tuple2[scala.Double, scala.Boolean]
// }
//
// (new FooImpl(): mypackage.App.Foo)
// ()
//}
package mypackage
object App {
trait Foo
}
Run Code Online (Sandbox Code Playgroud)
Scala 3 宏是def宏,所有生成的定义仅在宏扩展的块内可见。
也许如果在预编译时生成代码就足够了,您可以考虑使用Scalameta。那里有准引号: q"...") ,,,,,,,,,,,,,,,,,,,, 。t"..."p"..."param"..."tparam"..."init"..."self"..."template"..."mod"..."enumerator"..."import"..."importer"..."importee"..."source"..."
| 归档时间: |
|
| 查看次数: |
293 次 |
| 最近记录: |