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 { + fn do_x(&self) -> [u8; N]; +} + +struct Bar; + +const T: usize = 42; + +impl Foo 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 for Bar { + | ^^^^^ + | +help: the `const` keyword is only needed in the definition of the type + | +LL - impl Foo 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 { + fn do_x(&self) -> [u8; N]; +} + +struct Bar; + +const T: usize = 42; + +impl Foo 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 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 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 { + fn do_x(&self) -> [u8; N]; +} + +struct Bar; + +const T: usize = 42; + +impl Foo 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 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 { + fn do_x(&self) -> [u8; N]; +} + +struct Bar; + +const T: usize = 42; + +impl Foo 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 for Bar { + | ^^^^^ + | +help: the `const` keyword is only needed in the definition of the type + | +LL - impl Foo for Bar { +LL + impl Foo for Bar { + | + +error: cannot constrain an associated constant to a value + --> $DIR/issue-89013.rs:9:10 + | +LL | impl Foo 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 for Bar { + | ^^^^^^^^^^^ associated type not allowed here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0229`.