Scala 3 宏如何获取外层作用域变量的初始化体?
问题原因
外层作用域变量无法提取初始化代码的核心原因是Scala 3宏默认不会预加载非局部作用域符号的完整定义树:只有和宏调用处在同一局部展开上下文的符号,symbol.tree才会自带完整的ValDef右值信息,外层作用域、跨编译单元的符号默认只加载签名信息,右值部分为None。
解决方案
调整宏实现,先调用符号的complete()方法强制加载完整定义树,再访问树结构即可:
def extractBodyImpl[T: Type](expr: Expr[T])(using Quotes) = import quotes.reflect._ expr.asTerm.underlyingArgument match case ident @ Ident(_) => val sym = ident.symbol // 强制加载符号的完整源码定义 sym.complete() sym.tree match case ValDef(_,_,rhs) => println(rhs) case DefDef(_,_,_,rhs) => println(rhs) '{ () } inline def extractBody[T](inline expr: T) = ${ extractBodyImpl('expr) }
额外注意事项
- 如果变量定义在和宏调用不同的编译单元,需要将变量声明为
inline val,否则宏无法读取跨编译单元非内联变量的源码级初始化表达式。 - 已经编译成字节码的外部依赖库中的变量,无法通过该方法提取初始化代码,不存在对应的源码树信息。
内容的提问来源于stack exchange,提问作者YuliaSp
相关产品推荐
相关产品推荐

