Don't lose empty where clause when pretty-printing

Previously, we would parse `struct Foo where;` and `struct Foo;`
identically, leading to an 'empty' `where` clause being omitted during
pretty printing. This will cause us to lose spans when proc-macros
involved, since we will have a collected `where` token that does not
appear in the pretty-printed item.

We now explicitly track the presence of a `where` token during parsing,
so that we can distinguish between `struct Foo where;` and `struct Foo;`
during pretty-printing
This commit is contained in:
Aaron Hill 2020-06-08 21:09:54 -04:00
parent fd4b177aab
commit 0fcea2e423
No known key found for this signature in database
GPG Key ID: B4087E510E98B164
7 changed files with 68 additions and 7 deletions

View File

@ -362,7 +362,11 @@ impl Default for Generics {
fn default() -> Generics {
Generics {
params: Vec::new(),
where_clause: WhereClause { predicates: Vec::new(), span: DUMMY_SP },
where_clause: WhereClause {
has_where_token: false,
predicates: Vec::new(),
span: DUMMY_SP,
},
span: DUMMY_SP,
}
}
@ -371,6 +375,11 @@ fn default() -> Generics {
/// A where-clause in a definition.
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct WhereClause {
/// `true` if we ate a `where` token: this can happen
/// if we parsed no predicates (e.g. `struct Foo where {}
/// This allows us to accurately pretty-print
/// in `nt_to_tokenstream`
pub has_where_token: bool,
pub predicates: Vec<WherePredicate>,
pub span: Span,
}

View File

@ -786,7 +786,7 @@ pub fn noop_visit_generics<T: MutVisitor>(generics: &mut Generics, vis: &mut T)
}
pub fn noop_visit_where_clause<T: MutVisitor>(wc: &mut WhereClause, vis: &mut T) {
let WhereClause { predicates, span } = wc;
let WhereClause { has_where_token: _, predicates, span } = wc;
visit_vec(predicates, |predicate| vis.visit_where_predicate(predicate));
vis.visit_span(span);
}

View File

@ -2593,7 +2593,7 @@ pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::Generic
}
crate fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
if where_clause.predicates.is_empty() {
if where_clause.predicates.is_empty() && !where_clause.has_where_token {
return;
}
@ -2739,7 +2739,11 @@ pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) {
}
let generics = ast::Generics {
params: Vec::new(),
where_clause: ast::WhereClause { predicates: Vec::new(), span: rustc_span::DUMMY_SP },
where_clause: ast::WhereClause {
has_where_token: false,
predicates: Vec::new(),
span: rustc_span::DUMMY_SP,
},
span: rustc_span::DUMMY_SP,
};
let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() };

View File

@ -216,7 +216,11 @@ fn mk_ty_param(
}
fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
Generics { params, where_clause: ast::WhereClause { predicates: Vec::new(), span }, span }
Generics {
params,
where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span },
span,
}
}
/// Lifetimes and bounds on type parameters

View File

@ -157,6 +157,7 @@ pub(super) fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
Ok(ast::Generics {
params,
where_clause: WhereClause {
has_where_token: false,
predicates: Vec::new(),
span: self.prev_token.span.shrink_to_hi(),
},
@ -170,12 +171,16 @@ pub(super) fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
/// where T : Trait<U, V> + 'b, 'a : 'b
/// ```
pub(super) fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> {
let mut where_clause =
WhereClause { predicates: Vec::new(), span: self.prev_token.span.shrink_to_hi() };
let mut where_clause = WhereClause {
has_where_token: false,
predicates: Vec::new(),
span: self.prev_token.span.shrink_to_hi(),
};
if !self.eat_keyword(kw::Where) {
return Ok(where_clause);
}
where_clause.has_where_token = true;
let lo = self.prev_token.span;
// We are considering adding generics to the `where` keyword as an alternative higher-rank

View File

@ -0,0 +1,18 @@
// aux-build:test-macros.rs
extern crate test_macros;
use test_macros::recollect_attr;
#[recollect_attr]
struct FieldStruct where {
field: MissingType1 //~ ERROR cannot find
}
#[recollect_attr]
struct TupleStruct(MissingType2) where; //~ ERROR cannot find
enum MyEnum where {
Variant(MissingType3) //~ ERROR cannot find
}
fn main() {}

View File

@ -0,0 +1,21 @@
error[E0412]: cannot find type `MissingType1` in this scope
--> $DIR/empty-where-clause.rs:8:12
|
LL | field: MissingType1
| ^^^^^^^^^^^^ not found in this scope
error[E0412]: cannot find type `MissingType2` in this scope
--> $DIR/empty-where-clause.rs:12:20
|
LL | struct TupleStruct(MissingType2) where;
| ^^^^^^^^^^^^ not found in this scope
error[E0412]: cannot find type `MissingType3` in this scope
--> $DIR/empty-where-clause.rs:15:13
|
LL | Variant(MissingType3)
| ^^^^^^^^^^^^ not found in this scope
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0412`.