From 2972bb37b8dc6e64ec31cf9b79245974e30f417b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 22 Mar 2020 06:09:24 +0100 Subject: [PATCH] parse: improve recovery for assoc eq constraints. --- src/librustc_parse/parser/path.rs | 44 ++++++++++++++++++- .../parser/recover-assoc-const-constraint.rs | 7 +++ .../recover-assoc-const-constraint.stderr | 20 +++++++++ .../parser/recover-assoc-eq-missing-term.rs | 6 +++ .../recover-assoc-eq-missing-term.stderr | 17 +++++++ .../recover-assoc-lifetime-constraint.rs | 6 +++ .../recover-assoc-lifetime-constraint.stderr | 12 +++++ 7 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/parser/recover-assoc-const-constraint.rs create mode 100644 src/test/ui/parser/recover-assoc-const-constraint.stderr create mode 100644 src/test/ui/parser/recover-assoc-eq-missing-term.rs create mode 100644 src/test/ui/parser/recover-assoc-eq-missing-term.stderr create mode 100644 src/test/ui/parser/recover-assoc-lifetime-constraint.rs create mode 100644 src/test/ui/parser/recover-assoc-lifetime-constraint.stderr diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index f6d0f27eb18bf..d23adf4ffe395 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -4,6 +4,7 @@ use crate::maybe_whole; use rustc_ast::ast::{self, AngleBracketedArg, AngleBracketedArgs, GenericArg, ParenthesizedArgs}; use rustc_ast::ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode}; use rustc_ast::ast::{Ident, Path, PathSegment, QSelf}; +use rustc_ast::ptr::P; use rustc_ast::token::{self, Token}; use rustc_errors::{pluralize, Applicability, PResult}; use rustc_span::source_map::{BytePos, Span}; @@ -405,7 +406,8 @@ impl<'a> Parser<'a> { let lo = self.token.span; let ident = self.parse_ident()?; let kind = if self.eat(&token::Eq) { - AssocTyConstraintKind::Equality { ty: self.parse_ty()? } + let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?; + AssocTyConstraintKind::Equality { ty } } else if self.eat(&token::Colon) { let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?; AssocTyConstraintKind::Bound { bounds } @@ -427,6 +429,46 @@ impl<'a> Parser<'a> { } } + /// Parse the term to the right of an associated item equality constraint. + /// That is, parse `` in `Item = `. + /// Right now, this only admits types in ``. + fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P> { + let arg = self.parse_generic_arg()?; + let span = ident.span.to(self.prev_token.span); + match arg { + Some(GenericArg::Type(ty)) => return Ok(ty), + Some(GenericArg::Const(expr)) => { + self.struct_span_err(span, "cannot constrain an associated constant to a value") + .span_label(ident.span, "the value constrains this associated constant") + .span_label(expr.value.span, "the value is given in this expression") + .emit(); + } + Some(GenericArg::Lifetime(lt)) => { + self.struct_span_err(span, "associated lifetimes are not supported") + .span_label(lt.ident.span, "the lifetime is given here") + .help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`") + .emit(); + } + None => { + self.struct_span_err(span, "missing type to the right of `=`") + .span_suggestion( + span, + "to constrain the associated type, add a type after `=`", + format!("{} = TheType", ident), + Applicability::HasPlaceholders, + ) + .span_suggestion( + eq, + &format!("remove the `=` if `{}` is a type", ident), + String::new(), + Applicability::MaybeIncorrect, + ) + .emit(); + } + } + Ok(self.mk_ty(span, ast::TyKind::Err)) + } + /// Parse a generic argument in a path segment. /// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`. fn parse_generic_arg(&mut self) -> PResult<'a, Option> { diff --git a/src/test/ui/parser/recover-assoc-const-constraint.rs b/src/test/ui/parser/recover-assoc-const-constraint.rs new file mode 100644 index 0000000000000..06be3cdcc1a95 --- /dev/null +++ b/src/test/ui/parser/recover-assoc-const-constraint.rs @@ -0,0 +1,7 @@ +#[cfg(FALSE)] +fn syntax() { + bar::(); //~ ERROR cannot constrain an associated constant to a value + bar::(); //~ ERROR cannot constrain an associated constant to a value +} + +fn main() {} diff --git a/src/test/ui/parser/recover-assoc-const-constraint.stderr b/src/test/ui/parser/recover-assoc-const-constraint.stderr new file mode 100644 index 0000000000000..bf61720793672 --- /dev/null +++ b/src/test/ui/parser/recover-assoc-const-constraint.stderr @@ -0,0 +1,20 @@ +error: cannot constrain an associated constant to a value + --> $DIR/recover-assoc-const-constraint.rs:3:11 + | +LL | bar::(); + | ----^^^-- + | | | + | | the value is given in this expression + | the value constrains this associated constant + +error: cannot constrain an associated constant to a value + --> $DIR/recover-assoc-const-constraint.rs:4:11 + | +LL | bar::(); + | ----^^^------ + | | | + | | the value is given in this expression + | the value constrains this associated constant + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/recover-assoc-eq-missing-term.rs b/src/test/ui/parser/recover-assoc-eq-missing-term.rs new file mode 100644 index 0000000000000..d800df8236b05 --- /dev/null +++ b/src/test/ui/parser/recover-assoc-eq-missing-term.rs @@ -0,0 +1,6 @@ +#[cfg(FALSE)] +fn syntax() { + bar::(); //~ ERROR missing type to the right of `=` +} + +fn main() {} diff --git a/src/test/ui/parser/recover-assoc-eq-missing-term.stderr b/src/test/ui/parser/recover-assoc-eq-missing-term.stderr new file mode 100644 index 0000000000000..5eb5d6879e907 --- /dev/null +++ b/src/test/ui/parser/recover-assoc-eq-missing-term.stderr @@ -0,0 +1,17 @@ +error: missing type to the right of `=` + --> $DIR/recover-assoc-eq-missing-term.rs:3:11 + | +LL | bar::(); + | ^^^^^^ + | +help: to constrain the associated type, add a type after `=` + | +LL | bar::(); + | ^^^^^^^^^^^^^^ +help: remove the `=` if `Item` is a type + | +LL | bar::(); + | -- + +error: aborting due to previous error + diff --git a/src/test/ui/parser/recover-assoc-lifetime-constraint.rs b/src/test/ui/parser/recover-assoc-lifetime-constraint.rs new file mode 100644 index 0000000000000..558fcdfe1776f --- /dev/null +++ b/src/test/ui/parser/recover-assoc-lifetime-constraint.rs @@ -0,0 +1,6 @@ +#[cfg(FALSE)] +fn syntax() { + bar::(); //~ ERROR associated lifetimes are not supported +} + +fn main() {} diff --git a/src/test/ui/parser/recover-assoc-lifetime-constraint.stderr b/src/test/ui/parser/recover-assoc-lifetime-constraint.stderr new file mode 100644 index 0000000000000..79437533d7c0b --- /dev/null +++ b/src/test/ui/parser/recover-assoc-lifetime-constraint.stderr @@ -0,0 +1,12 @@ +error: associated lifetimes are not supported + --> $DIR/recover-assoc-lifetime-constraint.rs:3:11 + | +LL | bar::(); + | ^^^^^^^-- + | | + | the lifetime is given here + | + = help: if you meant to specify a trait object, write `dyn Trait + 'lifetime` + +error: aborting due to previous error +