Skip to content

Commit

Permalink
Rollup merge of rust-lang#47149 - dtolnay:spans, r=jseyfried
Browse files Browse the repository at this point in the history
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.

```rust
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.

Addresses rust-lang#38356 (comment). r? @jseyfried
  • Loading branch information
kennytm authored Jan 4, 2018
2 parents dc8254e + 000e907 commit 8eca1b3
Showing 1 changed file with 14 additions and 0 deletions.
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

0 comments on commit 8eca1b3

Please sign in to comment.