I want my procedural macro to replace some BinaryOps with methods. How do I set the spans so that if errors occur my users are not completely confused?
After some looking into rustc
's source, I came to the conclusion that following the "expansion" model produces the best results. So we keep the original Span
but for the expn_id
, which we can get by calling ExtCtxt::backtrace()
.
It appears to be a good idea to set this in both cases outlined in the question. The operator can be seen as expanded into the (function call) path, and the original binary operation expression as expanded into the function call. In code:
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
}
..
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With