如何正确处理程序宏中的跨度?

时间:2016-06-02 04:08:30

标签: plugins rust

我希望我的程序宏用方法替换一些BinaryOps。如何设置跨度,以便在发生错误时我的用户不会完全混淆?

1 个答案:

答案 0 :(得分:1)

在研究了rustc的来源之后,我得出的结论是,在“扩展”模型之后产生了最好的结果。因此,我们保留原始Span,但保留expn_id,我们可以通过调用ExtCtxt::backtrace()来获取。{/ p>

在问题中概述的两种情况下设置此类似乎是个好主意。可以看到运算符扩展为(函数调用)路径,并将原始二进制操作表达式扩展为函数调用。在代码中:

match expr.unwrap() {
    ..
    Expr { node: ExprKind::Binary( Spanned { node: Add, span: op }, l, r), span, .. } => {
        let bt = self.cx.backtrace(); // get the expansion ID
        let path = self.cx.path(Span { expn_id: bt, ..op }, vec![crate_name, trait_name, fn_name]);
        let epath = self.cx.expr_path(path); // path expression
        let args_expanded = self.fold_exprs(args);
        self.cx.expr_call(Span { expn_id: bt, ..span }, epath, args_expanded)
        // ^ outer expression
    }
    ..
}