about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2021-10-01 09:18:17 -0700
committerGitHub <noreply@github.com>2021-10-01 09:18:17 -0700
commit1708219940806d3620fb1cc10a0a673f7bfbbe45 (patch)
treec123a2b666324698e0d9ff08851503c245e6c0ca
parent6f1e93058137eb606cbee5ef778d30b379903f7c (diff)
parent105b60f2501fac061284ea7f5fbb8fb3f8134a92 (diff)
downloadrust-1708219940806d3620fb1cc10a0a673f7bfbbe45.tar.gz
rust-1708219940806d3620fb1cc10a0a673f7bfbbe45.zip
Rollup merge of #89029 - notriddle:notriddle/issue-89013, r=estebank
feat(rustc_parse): recover from pre-RFC-2000 const generics syntax

Fixes #89013
-rw-r--r--compiler/rustc_hir/src/hir.rs10
-rw-r--r--compiler/rustc_parse/src/parser/path.rs37
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs2
-rw-r--r--src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.rs16
-rw-r--r--src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.stderr14
-rw-r--r--src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs17
-rw-r--r--src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr18
-rw-r--r--src/test/ui/const-generics/parser-error-recovery/issue-89013-type.rs16
-rw-r--r--src/test/ui/const-generics/parser-error-recovery/issue-89013-type.stderr8
-rw-r--r--src/test/ui/const-generics/parser-error-recovery/issue-89013.rs18
-rw-r--r--src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr30
11 files changed, 180 insertions, 6 deletions
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 05b652fd5af..9c275b316c5 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -384,6 +384,16 @@ impl GenericArgs<'_> {
         self.args.iter().any(|arg| matches!(arg, GenericArg::Type(_)))
     }
 
+    pub fn has_err(&self) -> bool {
+        self.args.iter().any(|arg| match arg {
+            GenericArg::Type(ty) => matches!(ty.kind, TyKind::Err),
+            _ => false,
+        }) || self.bindings.iter().any(|arg| match arg.kind {
+            TypeBindingKind::Equality { ty } => matches!(ty.kind, TyKind::Err),
+            _ => false,
+        })
+    }
+
     #[inline]
     pub fn num_type_params(&self) -> usize {
         self.args.iter().filter(|arg| matches!(arg, GenericArg::Type(_))).count()
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 953c6915068..c7d080a80fe 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -495,20 +495,28 @@ impl<'a> Parser<'a> {
             None => {
                 let after_eq = eq.shrink_to_hi();
                 let before_next = self.token.span.shrink_to_lo();
-                self.struct_span_err(after_eq.to(before_next), "missing type to the right of `=`")
-                    .span_suggestion(
+                let mut err = self
+                    .struct_span_err(after_eq.to(before_next), "missing type to the right of `=`");
+                if matches!(self.token.kind, token::Comma | token::Gt) {
+                    err.span_suggestion(
                         self.sess.source_map().next_point(eq).to(before_next),
                         "to constrain the associated type, add a type after `=`",
                         " TheType".to_string(),
                         Applicability::HasPlaceholders,
-                    )
-                    .span_suggestion(
+                    );
+                    err.span_suggestion(
                         eq.to(before_next),
                         &format!("remove the `=` if `{}` is a type", ident),
                         String::new(),
                         Applicability::MaybeIncorrect,
                     )
-                    .emit();
+                } else {
+                    err.span_label(
+                        self.token.span,
+                        &format!("expected type, found {}", super::token_descr(&self.token)),
+                    )
+                };
+                return Err(err);
             }
         }
         Ok(self.mk_ty(span, ast::TyKind::Err))
@@ -572,6 +580,25 @@ impl<'a> Parser<'a> {
                     return self.recover_const_arg(start, err).map(Some);
                 }
             }
+        } else if self.eat_keyword_noexpect(kw::Const) {
+            // Detect and recover from the old, pre-RFC2000 syntax for const generics.
+            let mut err = self.struct_span_err(
+                start,
+                "expected lifetime, type, or constant, found keyword `const`",
+            );
+            if self.check_const_arg() {
+                err.span_suggestion_verbose(
+                    start.until(self.token.span),
+                    "the `const` keyword is only needed in the definition of the type",
+                    String::new(),
+                    Applicability::MaybeIncorrect,
+                );
+                err.emit();
+                GenericArg::Const(self.parse_const_arg()?)
+            } else {
+                let after_kw_const = self.token.span;
+                return self.recover_const_arg(after_kw_const, err).map(Some);
+            }
         } else {
             return Ok(None);
         };
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 27d76a69359..456d3fe7b2f 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -600,7 +600,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     def_id,
                 )
                 .diagnostic()
-                .emit();
+                .emit_unless(gen_args.has_err());
 
                 false
             };
diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.rs b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.rs
new file mode 100644
index 00000000000..99d8e9dea91
--- /dev/null
+++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.rs
@@ -0,0 +1,16 @@
+trait Foo<const N: usize> {
+    fn do_x(&self) -> [u8; N];
+}
+
+struct Bar;
+
+const T: usize = 42;
+
+impl Foo<const 3> for Bar {
+//~^ERROR expected lifetime, type, or constant, found keyword `const`
+    fn do_x(&self) -> [u8; 3] {
+        [0u8; 3]
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.stderr b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.stderr
new file mode 100644
index 00000000000..ddddd86ab9c
--- /dev/null
+++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.stderr
@@ -0,0 +1,14 @@
+error: expected lifetime, type, or constant, found keyword `const`
+  --> $DIR/issue-89013-no-assoc.rs:9:10
+   |
+LL | impl Foo<const 3> for Bar {
+   |          ^^^^^
+   |
+help: the `const` keyword is only needed in the definition of the type
+   |
+LL - impl Foo<const 3> for Bar {
+LL + impl Foo<3> for Bar {
+   | 
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs
new file mode 100644
index 00000000000..19e0f38d320
--- /dev/null
+++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs
@@ -0,0 +1,17 @@
+trait Foo<const N: usize> {
+    fn do_x(&self) -> [u8; N];
+}
+
+struct Bar;
+
+const T: usize = 42;
+
+impl Foo<N = 3> for Bar {
+//~^ ERROR cannot constrain an associated constant to a value
+//~| ERROR associated type bindings are not allowed here
+    fn do_x(&self) -> [u8; 3] {
+        [0u8; 3]
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr
new file mode 100644
index 00000000000..bbca92ad63a
--- /dev/null
+++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr
@@ -0,0 +1,18 @@
+error: cannot constrain an associated constant to a value
+  --> $DIR/issue-89013-no-kw.rs:9:10
+   |
+LL | impl Foo<N = 3> for Bar {
+   |          -^^^-
+   |          |   |
+   |          |   ...cannot be constrained to this value
+   |          this associated constant...
+
+error[E0229]: associated type bindings are not allowed here
+  --> $DIR/issue-89013-no-kw.rs:9:10
+   |
+LL | impl Foo<N = 3> for Bar {
+   |          ^^^^^ associated type not allowed here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0229`.
diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.rs b/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.rs
new file mode 100644
index 00000000000..0ec6762b6e2
--- /dev/null
+++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.rs
@@ -0,0 +1,16 @@
+trait Foo<const N: usize> {
+    fn do_x(&self) -> [u8; N];
+}
+
+struct Bar;
+
+const T: usize = 42;
+
+impl Foo<N = type 3> for Bar {
+//~^ERROR missing type to the right of `=`
+    fn do_x(&self) -> [u8; 3] {
+        [0u8; 3]
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.stderr b/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.stderr
new file mode 100644
index 00000000000..f0d0d90c774
--- /dev/null
+++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.stderr
@@ -0,0 +1,8 @@
+error: missing type to the right of `=`
+  --> $DIR/issue-89013-type.rs:9:13
+   |
+LL | impl Foo<N = type 3> for Bar {
+   |             ^---- expected type, found keyword `type`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs b/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs
new file mode 100644
index 00000000000..ca1158a2f6d
--- /dev/null
+++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs
@@ -0,0 +1,18 @@
+trait Foo<const N: usize> {
+    fn do_x(&self) -> [u8; N];
+}
+
+struct Bar;
+
+const T: usize = 42;
+
+impl Foo<N = const 3> for Bar {
+//~^ ERROR expected lifetime, type, or constant, found keyword `const`
+//~| ERROR cannot constrain an associated constant to a value
+//~| ERROR associated type bindings are not allowed here
+    fn do_x(&self) -> [u8; 3] {
+        [0u8; 3]
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr b/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr
new file mode 100644
index 00000000000..85379d3f06e
--- /dev/null
+++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr
@@ -0,0 +1,30 @@
+error: expected lifetime, type, or constant, found keyword `const`
+  --> $DIR/issue-89013.rs:9:14
+   |
+LL | impl Foo<N = const 3> for Bar {
+   |              ^^^^^
+   |
+help: the `const` keyword is only needed in the definition of the type
+   |
+LL - impl Foo<N = const 3> for Bar {
+LL + impl Foo<N = 3> for Bar {
+   | 
+
+error: cannot constrain an associated constant to a value
+  --> $DIR/issue-89013.rs:9:10
+   |
+LL | impl Foo<N = const 3> for Bar {
+   |          -^^^^^^^^^-
+   |          |         |
+   |          |         ...cannot be constrained to this value
+   |          this associated constant...
+
+error[E0229]: associated type bindings are not allowed here
+  --> $DIR/issue-89013.rs:9:10
+   |
+LL | impl Foo<N = const 3> for Bar {
+   |          ^^^^^^^^^^^ associated type not allowed here
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0229`.