about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2021-12-29 10:17:08 +0100
committerGitHub <noreply@github.com>2021-12-29 10:17:08 +0100
commitbee14712ab2993c0c6a8af9c72dbfa9b149b7f8d (patch)
tree610e13cbefe6dfbb2fbb5b9a0e6688acf4172fd1
parente31314307f09cef0989e2e052b1cad75d0a9e723 (diff)
parent4391a11537ce38c919058c292e91f059d658da94 (diff)
downloadrust-bee14712ab2993c0c6a8af9c72dbfa9b149b7f8d.tar.gz
rust-bee14712ab2993c0c6a8af9c72dbfa9b149b7f8d.zip
Rollup merge of #92118 - jackh726:type-alias-position-error, r=petrochenkov
Parse and suggest moving where clauses after equals for type aliases

~Mostly the same as #90076, but doesn't make any syntax changes.~ Whether or not we want to land the syntax changes, we should  parse the invalid where clause position and suggest moving.

r? `@nikomatsakis`
cc `@petrochenkov` you might have thoughts on implementation
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs56
-rw-r--r--compiler/rustc_parse/src/parser/item.rs53
-rw-r--r--src/test/ui/parser/type-alias-where.rs37
-rw-r--r--src/test/ui/parser/type-alias-where.stderr40
4 files changed, 158 insertions, 28 deletions
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 @@ 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);
             }
         }
     }
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 @@ 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}? ";" ;
@@ -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 }))))
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
+