Rust 过程宏排错:输入、展开路径与trait失败
此页以Report派生为例。工程未执行,以下错误文字是源码约定的预期,不是捕获的真实编译输出。先判断错误来自宏输入检查、生成代码的名称解析还是类型检查,再改动对应层;不要因为出现derive报错就重写整个宏。
过程宏错误阶段
过程宏错误阶段依次可分为依赖解析、输入解析、展开生成、名称解析与trait检查。依赖无法获取时没有进入宏;非法Rust语法由parse_macro_input或编译器先报;不支持的enum由expand拒绝;runtime路径不存在属于生成代码的名称问题;Display不满足属于trait约束。先确认阶段能避免把网络失败误判为字段配置错误。
恢复时缩小到consumer中的一个结构体,保留derive、helper、字段类型和Cargo别名。先排除拼写与路径问题,再检查生成impl的约束。未来若选择宏展开工具,须另行记录其安装和执行事实;本批没有运行展开器,也没有展开输出文件可作证据。
属性错误定位
属性错误定位靠错误key与字面量span:重复rename应定位第二个rename,未知flatten应提示字段只支持skip/rename,skip与rename冲突应关联字段。看到这些错误后先修正输入契约,不应删去错误检查让宏默默接受含糊配置。结构级和字段级report选项互不通用,crate放在字段上同样拒绝。
“支持only”信息说明允许语法;syn的字符串/路径解析错误说明值的形状不合法。#[report(skip = true)]不是本例布尔选项语法;skip是独立标志,多余token会被解析过程拒绝。重复项检查跨属性累计,不能靠拆行规避。
Display约束失败
Display约束失败时检查非skip字段完整类型与where谓词,不能只看类型参数T。Vec和Option并不会自动因为内部T可显示就获得Display;本例不擅自改成Debug。选择为业务newtype实现Display、改字段类型或明确skip,并确认输出仍满足业务要求。
对于具体Vec<u8>字段,生成where条件也不能使标准库凭空拥有该实现;编译器会拒绝相应实现。对于泛型T,派生impl仅适用于满足Display的T;若结构还声明T: Clone,调用者必须同时满足两个约束。宏生成不是无条件为所有实例提供报告。
重命名与路径失败
重命名与路径失败先比对Cargo别名和显式crate路径。consumer只拥有renamed_report依赖时,默认report_runtime不能解析;补report(crate = "::renamed_report"),并确认facade确实再导出Report trait和derive。路径字符串可以解析但缺少trait时仍会失败,不能把Path解析成功当作名称解析成功。
如果调用模块定义了自己的String或Vec,生成的绝对std路径仍指向标准库。本例内部rows局部变量不会重命名用户字段;若另扩展宏生成模块级helper,需重新审查名称碰撞。路径卫生是生成代码的设计责任,不是quote自动提供的保证。
compile_fail负例审阅
compile_fail负例审阅不能只看测试通过,因为任何编译失败都可能满足这类断言。逐块核对期望原因与定位:enum、tuple、重复rename、冲突、未知key、空标签、重名标签应在宏验证阶段失败;Vec字段应在Display约束失败;缺override应在runtime名称解析失败;非法path应在syn解析失败。
属性负例都提供正确的runtime路径覆盖,以减少路径错误掩盖预期失败的机会;只有专门检查缺少override的负例省略它。即便如此,仍需人工核对真实原因,或建立只匹配关键原因的独立诊断测试。未实际取得工具链输出前,不提交手写trybuild stderr冒充快照。本例提供轻量契约,诊断稳定性尚待真实执行验证。
排错练习
从工程中复制compile_fail重复rename负例,故意删去正确的crate覆盖属性,再删掉宏里的重复检测。此时负例仍可能显示“通过”。请给出最可能的路径,并写出你会先恢复哪一行输入来验证假设。另说明为什么不应仅凭这个现象断言宏仍正确拒绝重复配置。
参考解答
展开假阳性排查
负例没有显式runtime覆盖,删掉检查后可能生成默认report_runtime路径,consumer只有renamed_report别名,于是仍然编译失败。先在derive后加入#[report(crate = "::renamed_report")],保留原来的重复rename,再观察真实诊断;若错误消失,说明检测确已被破坏。compile_fail只检查失败这一事实,不自动证明失败来自原定原因。
资料
诊断机制核对syn::Error、quote_spanned与rustdoc compile_fail说明。完整输入和未来命令在工程页。
继续阅读
- 排错
- 排错
- 排错