Rollup merge of #89029 - notriddle:notriddle/issue-89013, r=estebank

feat(rustc_parse): recover from pre-RFC-2000 const generics syntax

Fixes #89013
This commit is contained in:
Manish Goregaokar 2021-10-01 09:18:17 -07:00 committed by GitHub
commit 1708219940
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 180 additions and 6 deletions

View File

@ -384,6 +384,16 @@ pub fn has_type_params(&self) -> bool {
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()

View File

@ -495,20 +495,28 @@ fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P
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 @@ pub(super) fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
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);
};

View File

@ -600,7 +600,7 @@ pub(crate) fn check_generic_arg_count(
def_id,
)
.diagnostic()
.emit();
.emit_unless(gen_args.has_err());
false
};

View File

@ -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() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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`.