about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-03-22 06:09:24 +0100
committerMazdak Farrokhzad <twingoow@gmail.com>2020-03-27 07:39:15 +0100
commit2972bb37b8dc6e64ec31cf9b79245974e30f417b (patch)
tree87068e3bccc1ef5b8ce1b572b8f68cdd90fb1bae
parentf91de44d073e40d6d4682ad41d61cadcc0fcedeb (diff)
downloadrust-2972bb37b8dc6e64ec31cf9b79245974e30f417b.tar.gz
rust-2972bb37b8dc6e64ec31cf9b79245974e30f417b.zip
parse: improve recovery for assoc eq constraints.
-rw-r--r--src/librustc_parse/parser/path.rs44
-rw-r--r--src/test/ui/parser/recover-assoc-const-constraint.rs7
-rw-r--r--src/test/ui/parser/recover-assoc-const-constraint.stderr20
-rw-r--r--src/test/ui/parser/recover-assoc-eq-missing-term.rs6
-rw-r--r--src/test/ui/parser/recover-assoc-eq-missing-term.stderr17
-rw-r--r--src/test/ui/parser/recover-assoc-lifetime-constraint.rs6
-rw-r--r--src/test/ui/parser/recover-assoc-lifetime-constraint.stderr12
7 files changed, 111 insertions, 1 deletions
diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs
index f6d0f27eb18..d23adf4ffe3 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 `<term>` in `Item = <term>`.
+    /// Right now, this only admits types in `<term>`.
+    fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P<ast::Ty>> {
+        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<GenericArg>> {
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 00000000000..06be3cdcc1a
--- /dev/null
+++ b/src/test/ui/parser/recover-assoc-const-constraint.rs
@@ -0,0 +1,7 @@
+#[cfg(FALSE)]
+fn syntax() {
+    bar::<Item = 42>(); //~ ERROR cannot constrain an associated constant to a value
+    bar::<Item = { 42 }>(); //~ 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 00000000000..bf617207936
--- /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::<Item = 42>();
+   |           ----^^^--
+   |           |      |
+   |           |      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::<Item = { 42 }>();
+   |           ----^^^------
+   |           |      |
+   |           |      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 00000000000..d800df8236b
--- /dev/null
+++ b/src/test/ui/parser/recover-assoc-eq-missing-term.rs
@@ -0,0 +1,6 @@
+#[cfg(FALSE)]
+fn syntax() {
+    bar::<Item = >(); //~ 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 00000000000..5eb5d6879e9
--- /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::<Item = >();
+   |           ^^^^^^
+   |
+help: to constrain the associated type, add a type after `=`
+   |
+LL |     bar::<Item = TheType >();
+   |           ^^^^^^^^^^^^^^
+help: remove the `=` if `Item` is a type
+   |
+LL |     bar::<Item  >();
+   |               --
+
+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 00000000000..558fcdfe177
--- /dev/null
+++ b/src/test/ui/parser/recover-assoc-lifetime-constraint.rs
@@ -0,0 +1,6 @@
+#[cfg(FALSE)]
+fn syntax() {
+    bar::<Item = 'a>(); //~ 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 00000000000..79437533d7c
--- /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::<Item = 'a>();
+   |           ^^^^^^^--
+   |                  |
+   |                  the lifetime is given here
+   |
+   = help: if you meant to specify a trait object, write `dyn Trait + 'lifetime`
+
+error: aborting due to previous error
+