From 4391a11537ce38c919058c292e91f059d658da94 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Mon, 20 Dec 2021 09:10:10 -0500 Subject: [PATCH] Parse and suggest moving where clauses after equals for type aliases --- compiler/rustc_ast_pretty/src/pprust/state.rs | 56 +++++++++---------- compiler/rustc_parse/src/parser/item.rs | 53 ++++++++++++++++++ src/test/ui/parser/type-alias-where.rs | 37 ++++++++++++ src/test/ui/parser/type-alias-where.stderr | 40 +++++++++++++ 4 files changed, 158 insertions(+), 28 deletions(-) create mode 100644 src/test/ui/parser/type-alias-where.rs create mode 100644 src/test/ui/parser/type-alias-where.stderr diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 6c5b38bc4bb..4464b5eee96 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -2780,34 +2780,34 @@ pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::Generic 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); } } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 618aa3fd002..d335ef8788b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -794,6 +794,44 @@ fn parse_assoc_item( )) } + /// 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}? ";" ; @@ -806,9 +844,24 @@ fn parse_type_alias(&mut self, defaultness: Defaultness) -> PResult<'a, ItemInfo // 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 })))) diff --git a/src/test/ui/parser/type-alias-where.rs b/src/test/ui/parser/type-alias-where.rs new file mode 100644 index 00000000000..a9fa23dd95e --- /dev/null +++ b/src/test/ui/parser/type-alias-where.rs @@ -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() {} diff --git a/src/test/ui/parser/type-alias-where.stderr b/src/test/ui/parser/type-alias-where.stderr new file mode 100644 index 00000000000..7ab0b28c864 --- /dev/null +++ b/src/test/ui/parser/type-alias-where.stderr @@ -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 + -- 2.44.0