From 000e907c1fc73ca249252cba3b2c9b1a20de857d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 2 Jan 2018 23:29:11 -0800 Subject: [PATCH] Span::resolved_at and Span::located_at to combine behavior of two spans Proc macro spans serve two mostly unrelated purposes: controlling name resolution and controlling error messages. It can be useful to mix the name resolution behavior of one span with the line/column error message locations of a different span. In particular, consider the case of a trait brought into scope within the def_site of a custom derive. I want to invoke trait methods on the fields of the user's struct. If the field type does not implement the right trait, I want the error message to underline the corresponding struct field. Generating the method call with the def_site span is not ideal -- it compiles and runs but error messages sadly always point to the derive attribute like we saw with Macros 1.1. ``` | 4 | #[derive(HeapSize)] | ^^^^^^^^ ``` Generating the method call with the same span as the struct field's ident or type is not correct -- it shows the right underlines but fails to resolve to the trait in scope at the def_site. ``` | 7 | bad: std::thread::Thread, | ^^^^^^^^^^^^^^^^^^^^^^^^ ``` The correct span for the method call is one that combines the def_site's name resolution with the struct field's line/column. ``` field.span.resolved_at(Span::def_site()) // equivalently Span::def_site().located_at(field.span) ``` Adding both because which one is more natural will depend on context. --- src/libproc_macro/lib.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 41ccd88b4a8..f2936f2bca8 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -254,6 +254,20 @@ pub fn join(&self, other: Span) -> Option { Some(Span(self.0.to(other.0))) } + /// Creates a new span with the same line/column information as `self` but + /// that resolves symbols as though it were at `other`. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn resolved_at(&self, other: Span) -> Span { + Span(self.0.with_ctxt(other.0.ctxt())) + } + + /// Creates a new span with the same name resolution behavior as `self` but + /// with the line/column information of `other`. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn located_at(&self, other: Span) -> Span { + other.resolved_at(*self) + } + diagnostic_method!(error, Level::Error); diagnostic_method!(warning, Level::Warning); diagnostic_method!(note, Level::Note); -- 2.44.0