Skip to content

Commit

Permalink
Parse and suggest moving where clauses after equals for type aliases
Browse files Browse the repository at this point in the history
  • Loading branch information
jackh726 committed Dec 28, 2021
1 parent e95e084 commit 4391a11
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 28 deletions.
56 changes: 28 additions & 28 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2780,34 +2780,34 @@ impl<'a> State<'a> {
self.word_space(",");
}

match *predicate {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
ref bound_generic_params,
ref bounded_ty,
ref bounds,
..
}) => {
self.print_formal_generic_params(bound_generic_params);
self.print_type(bounded_ty);
self.print_type_bounds(":", bounds);
}
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
ref lifetime,
ref bounds,
..
}) => {
self.print_lifetime_bounds(*lifetime, bounds);
}
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
ref lhs_ty,
ref rhs_ty,
..
}) => {
self.print_type(lhs_ty);
self.space();
self.word_space("=");
self.print_type(rhs_ty);
}
self.print_where_predicate(predicate);
}
}

pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
match predicate {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
bound_generic_params,
bounded_ty,
bounds,
..
}) => {
self.print_formal_generic_params(bound_generic_params);
self.print_type(bounded_ty);
self.print_type_bounds(":", bounds);
}
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
lifetime,
bounds,
..
}) => {
self.print_lifetime_bounds(*lifetime, bounds);
}
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
self.print_type(lhs_ty);
self.space();
self.word_space("=");
self.print_type(rhs_ty);
}
}
}
Expand Down
53 changes: 53 additions & 0 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,44 @@ impl<'a> Parser<'a> {
))
}

/// Emits an error that the where clause at the end of a type alias is not
/// allowed and suggests moving it.
fn error_ty_alias_where(
&self,
before_where_clause_present: bool,
before_where_clause_span: Span,
after_predicates: &[WherePredicate],
after_where_clause_span: Span,
) {
let mut err =
self.struct_span_err(after_where_clause_span, "where clause not allowed here");
if !after_predicates.is_empty() {
let mut state = crate::pprust::State::new();
if !before_where_clause_present {
state.space();
state.word_space("where");
} else {
state.word_space(",");
}
let mut first = true;
for p in after_predicates.iter() {
if !first {
state.word_space(",");
}
first = false;
state.print_where_predicate(p);
}
let suggestion = state.s.eof();
err.span_suggestion(
before_where_clause_span.shrink_to_hi(),
"move it here",
suggestion,
Applicability::MachineApplicable,
);
}
err.emit()
}

/// Parses a `type` alias with the following grammar:
/// ```
/// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ;
Expand All @@ -806,9 +844,24 @@ impl<'a> Parser<'a> {
// Parse optional colon and param bounds.
let bounds =
if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() };

generics.where_clause = self.parse_where_clause()?;

let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };

if self.token.is_keyword(kw::Where) {
let after_where_clause = self.parse_where_clause()?;

self.error_ty_alias_where(
generics.where_clause.has_where_token,
generics.where_clause.span,
&after_where_clause.predicates,
after_where_clause.span,
);

generics.where_clause.predicates.extend(after_where_clause.predicates.into_iter());
}

self.expect_semi()?;

Ok((ident, ItemKind::TyAlias(Box::new(TyAlias { defaultness, generics, bounds, ty }))))
Expand Down
37 changes: 37 additions & 0 deletions src/test/ui/parser/type-alias-where.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// check-fail

#![feature(generic_associated_types)]

// Fine, but lints as unused
type Foo where u32: Copy = ();
// Not fine.
type Bar = () where u32: Copy;
//~^ ERROR where clause not allowed here
type Baz = () where;
//~^ ERROR where clause not allowed here

trait Trait {
// Fine.
type Assoc where u32: Copy;
// Fine.
type Assoc2 where u32: Copy, i32: Copy;
}

impl Trait for u32 {
// Fine.
type Assoc where u32: Copy = ();
// Not fine, suggests moving `i32: Copy`
type Assoc2 where u32: Copy = () where i32: Copy;
//~^ ERROR where clause not allowed here
}

impl Trait for i32 {
// Not fine, suggests moving `u32: Copy`
type Assoc = () where u32: Copy;
//~^ ERROR where clause not allowed here
// Not fine, suggests moving both.
type Assoc2 = () where u32: Copy, i32: Copy;
//~^ ERROR where clause not allowed here
}

fn main() {}
40 changes: 40 additions & 0 deletions src/test/ui/parser/type-alias-where.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
error: where clause not allowed here
--> $DIR/type-alias-where.rs:8:15
|
LL | type Bar = () where u32: Copy;
| - ^^^^^^^^^^^^^^^
| |
| help: move it here: `where u32: Copy`

error: where clause not allowed here
--> $DIR/type-alias-where.rs:10:15
|
LL | type Baz = () where;
| ^^^^^

error: where clause not allowed here
--> $DIR/type-alias-where.rs:24:38
|
LL | type Assoc2 where u32: Copy = () where i32: Copy;
| - ^^^^^^^^^^^^^^^
| |
| help: move it here: `, i32: Copy`

error: where clause not allowed here
--> $DIR/type-alias-where.rs:30:21
|
LL | type Assoc = () where u32: Copy;
| - ^^^^^^^^^^^^^^^
| |
| help: move it here: `where u32: Copy`

error: where clause not allowed here
--> $DIR/type-alias-where.rs:33:22
|
LL | type Assoc2 = () where u32: Copy, i32: Copy;
| - ^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| help: move it here: `where u32: Copy, i32: Copy`

error: aborting due to 5 previous errors

0 comments on commit 4391a11

Please sign in to comment.