Skip to content

Span::resolved_at and Span::located_at to combine behavior of two spans #47149

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 5, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
  • Loading branch information
dtolnay committed Jan 3, 2018
commit 000e907c1fc73ca249252cba3b2c9b1a20de857d
14 changes: 14 additions & 0 deletions src/libproc_macro/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,20 @@ impl Span {
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);
Expand Down