about summary refs log tree commit diff
path: root/compiler/rustc_parse/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-01-23 06:27:21 +0000
committerbors <bors@rust-lang.org>2021-01-23 06:27:21 +0000
commit1986b58c646a9523d0a8a0fa8a0bd20492e7795d (patch)
tree4fbb2a16a834aad3b18a2a07b445c6ee8d8f3d29 /compiler/rustc_parse/src
parentfe0fa59b50313b30e3bfcf1e3e5e1a71fa3a849d (diff)
parent3ba6cf13f42250c1d0d3bab206e37e93df0582c4 (diff)
downloadrust-1986b58c646a9523d0a8a0fa8a0bd20492e7795d.tar.gz
rust-1986b58c646a9523d0a8a0fa8a0bd20492e7795d.zip
Auto merge of #80065 - b-naber:parse-angle-arg-diagnostics, r=petrochenkov
Improve diagnostics when parsing angle args

https://github.com/rust-lang/rust/pull/79266 introduced parsing of generic arguments in associated type constraints, this however resulted in possibly very confusing error messages in cases in which closing angle brackets were missing such as in `Vec<(u32, _, _) = vec![]`, which outputs an incorrectly parsed equality constraint error, as noted by `@cynecx.`

This PR tries to provide better error messages in such cases.

r? `@petrochenkov`
Diffstat (limited to 'compiler/rustc_parse/src')
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs21
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs2
-rw-r--r--compiler/rustc_parse/src/parser/path.rs55
3 files changed, 28 insertions, 50 deletions
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 35435baea70..f2fcce5c226 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -2,14 +2,13 @@ use super::ty::AllowPlus;
 use super::TokenType;
 use super::{BlockMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType};
 
+use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Lit, LitKind, TokenKind};
 use rustc_ast::util::parser::AssocOp;
-use rustc_ast::{
-    self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode,
-    Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item, ItemKind, Mutability, Param, Pat,
-    PatKind, Path, PathSegment, QSelf, Ty, TyKind,
-};
+use rustc_ast::{AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec};
+use rustc_ast::{BinOpKind, BindingMode, Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item};
+use rustc_ast::{ItemKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Ty, TyKind};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{pluralize, struct_span_err};
@@ -220,6 +219,7 @@ impl<'a> Parser<'a> {
         edible: &[TokenKind],
         inedible: &[TokenKind],
     ) -> PResult<'a, bool /* recovered */> {
+        debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible);
         fn tokens_to_string(tokens: &[TokenType]) -> String {
             let mut i = tokens.iter();
             // This might be a sign we need a connect method on `Iterator`.
@@ -245,6 +245,7 @@ impl<'a> Parser<'a> {
             .collect::<Vec<_>>();
         expected.sort_by_cached_key(|x| x.to_string());
         expected.dedup();
+
         let expect = tokens_to_string(&expected[..]);
         let actual = super::token_descr(&self.token);
         let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
@@ -270,6 +271,16 @@ impl<'a> Parser<'a> {
         };
         self.last_unexpected_token_span = Some(self.token.span);
         let mut err = self.struct_span_err(self.token.span, &msg_exp);
+
+        // Add suggestion for a missing closing angle bracket if '>' is included in expected_tokens
+        // there are unclosed angle brackets
+        if self.unmatched_angle_bracket_count > 0
+            && self.token.kind == TokenKind::Eq
+            && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Gt)))
+        {
+            err.span_label(self.prev_token.span, "maybe try to close unmatched angle bracket");
+        }
+
         let sp = if self.token == token::Eof {
             // This is EOF; don't want to point at the following char, but rather the last token.
             self.prev_token.span
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index b332005ca74..f11c6591de9 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -277,7 +277,7 @@ impl TokenCursor {
     }
 }
 
-#[derive(Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq)]
 enum TokenType {
     Token(TokenKind),
     Keyword(Symbol),
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index dd36122f6a1..4234740b2b1 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -185,7 +185,6 @@ impl<'a> Parser<'a> {
 
     pub(super) fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> {
         let ident = self.parse_path_segment_ident()?;
-
         let is_args_start = |token: &Token| {
             matches!(
                 token.kind,
@@ -420,7 +419,10 @@ impl<'a> Parser<'a> {
         match arg {
             Some(arg) => {
                 if self.check(&token::Colon) | self.check(&token::Eq) {
-                    let (ident, gen_args) = self.get_ident_from_generic_arg(arg, lo)?;
+                    let (ident, gen_args) = match self.get_ident_from_generic_arg(arg) {
+                        Ok(ident_gen_args) => ident_gen_args,
+                        Err(arg) => return Ok(Some(AngleBracketedArg::Arg(arg))),
+                    };
                     let kind = if self.eat(&token::Colon) {
                         // Parse associated type constraint bound.
 
@@ -561,50 +563,15 @@ impl<'a> Parser<'a> {
     fn get_ident_from_generic_arg(
         &self,
         gen_arg: GenericArg,
-        lo: Span,
-    ) -> PResult<'a, (Ident, Option<GenericArgs>)> {
-        let gen_arg_span = gen_arg.span();
-        match gen_arg {
-            GenericArg::Type(t) => match t.into_inner().kind {
-                ast::TyKind::Path(qself, mut path) => {
-                    if let Some(qself) = qself {
-                        let mut err = self.struct_span_err(
-                            gen_arg_span,
-                            "qualified paths cannot be used in associated type constraints",
-                        );
-                        err.span_label(
-                            qself.path_span,
-                            "not allowed in associated type constraints",
-                        );
-                        return Err(err);
-                    }
-                    if path.segments.len() == 1 {
-                        let path_seg = path.segments.remove(0);
-                        let ident = path_seg.ident;
-                        let gen_args = path_seg.args.map(|args| args.into_inner());
-                        return Ok((ident, gen_args));
-                    }
-                    let err = self.struct_span_err(
-                        path.span,
-                        "paths with multiple segments cannot be used in associated type constraints",
-                    );
-                    return Err(err);
-                }
-                _ => {
-                    let span = lo.to(self.prev_token.span);
-                    let err = self.struct_span_err(
-                        span,
-                        "only path types can be used in associated type constraints",
-                    );
-                    return Err(err);
+    ) -> Result<(Ident, Option<GenericArgs>), GenericArg> {
+        if let GenericArg::Type(ty) = &gen_arg {
+            if let ast::TyKind::Path(qself, path) = &ty.kind {
+                if qself.is_none() && path.segments.len() == 1 {
+                    let seg = &path.segments[0];
+                    return Ok((seg.ident, seg.args.as_deref().cloned()));
                 }
-            },
-            _ => {
-                let span = lo.to(self.prev_token.span);
-                let err = self
-                    .struct_span_err(span, "only types can be used in associated type constraints");
-                return Err(err);
             }
         }
+        Err(gen_arg)
     }
 }