about summary refs log tree commit diff
path: root/src/libsyntax/parse/parser.rs
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2018-03-02 22:01:23 -0800
committerManish Goregaokar <manishsmail@gmail.com>2018-03-02 22:01:23 -0800
commit8c7c8fb2128f1a50926f507bbdae8f18bcc35ff6 (patch)
tree20ba502eaa34ab419f36f6639e2c0e3afd3c252f /src/libsyntax/parse/parser.rs
parent8bf026df5b44eab313aa8c4ac2d185af8e9dcd41 (diff)
parent24be75d420bf316cb09c179781d6c1c63636fbc1 (diff)
downloadrust-8c7c8fb2128f1a50926f507bbdae8f18bcc35ff6.tar.gz
rust-8c7c8fb2128f1a50926f507bbdae8f18bcc35ff6.zip
Rollup merge of #48338 - estebank:match-missing-comma, r=petrochenkov
Fixes #47311.
r? @nrc
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
-rw-r--r--src/libsyntax/parse/parser.rs152
1 files changed, 121 insertions, 31 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 881e3e412d4..92584f5b519 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -652,9 +652,11 @@ impl<'a> Parser<'a> {
             } else {
                 let token_str = Parser::token_to_string(t);
                 let this_token_str = self.this_token_to_string();
-                Err(self.fatal(&format!("expected `{}`, found `{}`",
-                                   token_str,
-                                   this_token_str)))
+                let mut err = self.fatal(&format!("expected `{}`, found `{}`",
+                                                  token_str,
+                                                  this_token_str));
+                err.span_label(self.span, format!("expected `{}`", token_str));
+                Err(err)
             }
         } else {
             self.expect_one_of(unsafe { slice::from_raw_parts(t, 1) }, &[])
@@ -1172,7 +1174,7 @@ impl<'a> Parser<'a> {
                                      sep: SeqSep,
                                      f: F)
                                      -> PResult<'a, Vec<T>> where
-        F: FnMut(&mut Parser<'a>) -> PResult<'a,  T>,
+        F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     {
         self.expect(bra)?;
         let result = self.parse_seq_to_before_end(ket, sep, f)?;
@@ -1190,7 +1192,7 @@ impl<'a> Parser<'a> {
                            sep: SeqSep,
                            f: F)
                            -> PResult<'a, Spanned<Vec<T>>> where
-        F: FnMut(&mut Parser<'a>) -> PResult<'a,  T>,
+        F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     {
         let lo = self.span;
         self.expect(bra)?;
@@ -1485,7 +1487,10 @@ impl<'a> Parser<'a> {
                 }
                 _ => {
                     let token_str = self.this_token_to_string();
-                    return Err(self.fatal(&format!("expected `;` or `{{`, found `{}`", token_str)));
+                    let mut err = self.fatal(&format!("expected `;` or `{{`, found `{}`",
+                                                      token_str));
+                    err.span_label(self.span, "expected `;` or `{`");
+                    return Err(err);
                 }
             };
             (ident, ast::TraitItemKind::Method(sig, body), generics)
@@ -2216,7 +2221,12 @@ impl<'a> Parser<'a> {
                 TokenTree::Delimited(_, delimited) => Ok((delim, delimited.stream().into())),
                 _ => unreachable!(),
             },
-            _ => Err(self.fatal("expected open delimiter")),
+            _ => {
+                let msg = "expected open delimiter";
+                let mut err = self.fatal(msg);
+                err.span_label(self.span, msg);
+                Err(err)
+            }
         }
     }
 
@@ -2349,7 +2359,10 @@ impl<'a> Parser<'a> {
                     if self.eat_keyword(keywords::Loop) {
                         return self.parse_loop_expr(Some(label), lo, attrs)
                     }
-                    return Err(self.fatal("expected `while`, `for`, or `loop` after a label"))
+                    let msg = "expected `while`, `for`, or `loop` after a label";
+                    let mut err = self.fatal(msg);
+                    err.span_label(self.span, msg);
+                    return Err(err);
                 }
                 if self.eat_keyword(keywords::Loop) {
                     let lo = self.prev_span;
@@ -2408,6 +2421,7 @@ impl<'a> Parser<'a> {
                     // Catch this syntax error here, instead of in `parse_ident`, so
                     // that we can explicitly mention that let is not to be used as an expression
                     let mut db = self.fatal("expected expression, found statement (`let`)");
+                    db.span_label(self.span, "expected expression");
                     db.note("variable declaration using `let` is a statement");
                     return Err(db);
                 } else if self.token.is_path_start() {
@@ -2443,7 +2457,9 @@ impl<'a> Parser<'a> {
                             self.cancel(&mut err);
                             let msg = format!("expected expression, found {}",
                                               self.this_token_descr());
-                            return Err(self.fatal(&msg));
+                            let mut err = self.fatal(&msg);
+                            err.span_label(self.span, "expected expression");
+                            return Err(err);
                         }
                     }
                 }
@@ -2733,7 +2749,9 @@ impl<'a> Parser<'a> {
                              self.look_ahead(1, |t| t.is_ident()) => {
                 self.bump();
                 let name = match self.token { token::Ident(ident) => ident, _ => unreachable!() };
-                self.fatal(&format!("unknown macro variable `{}`", name)).emit();
+                let mut err = self.fatal(&format!("unknown macro variable `{}`", name));
+                err.span_label(self.span, "unknown macro variable");
+                err.emit();
                 return
             }
             token::Interpolated(ref nt) => {
@@ -3212,7 +3230,13 @@ impl<'a> Parser<'a> {
             err.span_label(sp, "expected if condition here");
             return Err(err)
         }
-        let thn = self.parse_block()?;
+        let not_block = self.token != token::OpenDelim(token::Brace);
+        let thn = self.parse_block().map_err(|mut err| {
+            if not_block {
+                err.span_label(lo, "this `if` statement has a condition, but no block");
+            }
+            err
+        })?;
         let mut els: Option<P<Expr>> = None;
         let mut hi = thn.span;
         if self.eat_keyword(keywords::Else) {
@@ -3404,14 +3428,52 @@ impl<'a> Parser<'a> {
         } else {
             None
         };
+        let arrow_span = self.span;
         self.expect(&token::FatArrow)?;
-        let expr = self.parse_expr_res(Restrictions::STMT_EXPR, None)?;
+        let arm_start_span = self.span;
+
+        let expr = self.parse_expr_res(Restrictions::STMT_EXPR, None)
+            .map_err(|mut err| {
+                err.span_label(arrow_span, "while parsing the `match` arm starting here");
+                err
+            })?;
 
         let require_comma = classify::expr_requires_semi_to_be_stmt(&expr)
             && self.token != token::CloseDelim(token::Brace);
 
         if require_comma {
-            self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)])?;
+            let cm = self.sess.codemap();
+            self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)])
+                .map_err(|mut err| {
+                    match (cm.span_to_lines(expr.span), cm.span_to_lines(arm_start_span)) {
+                        (Ok(ref expr_lines), Ok(ref arm_start_lines))
+                        if arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col
+                            && expr_lines.lines.len() == 2
+                            && self.token == token::FatArrow => {
+                            // We check wether there's any trailing code in the parse span, if there
+                            // isn't, we very likely have the following:
+                            //
+                            // X |     &Y => "y"
+                            //   |        --    - missing comma
+                            //   |        |
+                            //   |        arrow_span
+                            // X |     &X => "x"
+                            //   |      - ^^ self.span
+                            //   |      |
+                            //   |      parsed until here as `"y" & X`
+                            err.span_suggestion_short(
+                                cm.next_point(arm_start_span),
+                                "missing a comma here to end this `match` arm",
+                                ",".to_owned()
+                            );
+                        }
+                        _ => {
+                            err.span_label(arrow_span,
+                                           "while parsing the `match` arm starting here");
+                        }
+                    }
+                    err
+                })?;
         } else {
             self.eat(&token::Comma);
         }
@@ -3609,8 +3671,9 @@ impl<'a> Parser<'a> {
                 self.bump();
                 if self.token != token::CloseDelim(token::Brace) {
                     let token_str = self.this_token_to_string();
-                    return Err(self.fatal(&format!("expected `{}`, found `{}`", "}",
-                                       token_str)))
+                    let mut err = self.fatal(&format!("expected `{}`, found `{}`", "}", token_str));
+                    err.span_label(self.span, "expected `}`");
+                    return Err(err);
                 }
                 etc = true;
                 break;
@@ -3721,7 +3784,10 @@ impl<'a> Parser<'a> {
                 self.expect_and()?;
                 let mutbl = self.parse_mutability();
                 if let token::Lifetime(ident) = self.token {
-                    return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident)));
+                    let mut err = self.fatal(&format!("unexpected lifetime `{}` in pattern",
+                                                      ident));
+                    err.span_label(self.span, "unexpected lifetime");
+                    return Err(err);
                 }
                 let subpat = self.parse_pat()?;
                 pat = PatKind::Ref(subpat, mutbl);
@@ -3806,7 +3872,10 @@ impl<'a> Parser<'a> {
                     }
                     token::OpenDelim(token::Brace) => {
                         if qself.is_some() {
-                            return Err(self.fatal("unexpected `{` after qualified path"));
+                            let msg = "unexpected `{` after qualified path";
+                            let mut err = self.fatal(msg);
+                            err.span_label(self.span, msg);
+                            return Err(err);
                         }
                         // Parse struct pattern
                         self.bump();
@@ -3820,7 +3889,10 @@ impl<'a> Parser<'a> {
                     }
                     token::OpenDelim(token::Paren) => {
                         if qself.is_some() {
-                            return Err(self.fatal("unexpected `(` after qualified path"));
+                            let msg = "unexpected `(` after qualified path";
+                            let mut err = self.fatal(msg);
+                            err.span_label(self.span, msg);
+                            return Err(err);
                         }
                         // Parse tuple struct or enum pattern
                         let (fields, ddpos, _) = self.parse_parenthesized_pat_list()?;
@@ -3850,7 +3922,9 @@ impl<'a> Parser<'a> {
                     Err(mut err) => {
                         self.cancel(&mut err);
                         let msg = format!("expected pattern, found {}", self.this_token_descr());
-                        return Err(self.fatal(&msg));
+                        let mut err = self.fatal(&msg);
+                        err.span_label(self.span, "expected pattern");
+                        return Err(err);
                     }
                 }
             }
@@ -4250,9 +4324,11 @@ impl<'a> Parser<'a> {
                         ""
                     };
                     let tok_str = self.this_token_to_string();
-                    return Err(self.fatal(&format!("expected {}`(` or `{{`, found `{}`",
-                                       ident_str,
-                                       tok_str)))
+                    let mut err = self.fatal(&format!("expected {}`(` or `{{`, found `{}`",
+                                                      ident_str,
+                                                      tok_str));
+                    err.span_label(self.span, format!("expected {}`(` or `{{`", ident_str));
+                    return Err(err)
                 },
             };
 
@@ -5559,8 +5635,12 @@ impl<'a> Parser<'a> {
             body
         } else {
             let token_str = self.this_token_to_string();
-            return Err(self.fatal(&format!("expected `where`, `{{`, `(`, or `;` after struct \
-                                            name, found `{}`", token_str)))
+            let mut err = self.fatal(&format!(
+                "expected `where`, `{{`, `(`, or `;` after struct name, found `{}`",
+                token_str
+            ));
+            err.span_label(self.span, "expected `where`, `{`, `(`, or `;` after struct name");
+            return Err(err);
         };
 
         Ok((class_name, ItemKind::Struct(vdata, generics), None))
@@ -5579,8 +5659,10 @@ impl<'a> Parser<'a> {
             VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
         } else {
             let token_str = self.this_token_to_string();
-            return Err(self.fatal(&format!("expected `where` or `{{` after union \
-                                            name, found `{}`", token_str)))
+            let mut err = self.fatal(&format!(
+                "expected `where` or `{{` after union name, found `{}`", token_str));
+            err.span_label(self.span, "expected `where` or `{` after union name");
+            return Err(err);
         };
 
         Ok((class_name, ItemKind::Union(vdata, generics), None))
@@ -5627,9 +5709,10 @@ impl<'a> Parser<'a> {
             self.eat(&token::CloseDelim(token::Brace));
         } else {
             let token_str = self.this_token_to_string();
-            return Err(self.fatal(&format!("expected `where`, or `{{` after struct \
-                                name, found `{}`",
-                                token_str)));
+            let mut err = self.fatal(&format!(
+                    "expected `where`, or `{{` after struct name, found `{}`", token_str));
+            err.span_label(self.span, "expected `where`, or `{` after struct name");
+            return Err(err);
         }
 
         Ok(fields)
@@ -5802,9 +5885,11 @@ impl<'a> Parser<'a> {
         if !self.eat(term) {
             let token_str = self.this_token_to_string();
             let mut err = self.fatal(&format!("expected item, found `{}`", token_str));
-            let msg = "consider removing this semicolon";
             if token_str == ";" {
+                let msg = "consider removing this semicolon";
                 err.span_suggestion_short(self.span, msg, "".to_string());
+            } else {
+                err.span_label(self.span, "expected item");
             }
             return Err(err);
         }
@@ -6961,7 +7046,12 @@ impl<'a> Parser<'a> {
                 self.expect_no_suffix(sp, "string literal", suf);
                 Ok((s, style))
             }
-            _ =>  Err(self.fatal("expected string literal"))
+            _ => {
+                let msg = "expected string literal";
+                let mut err = self.fatal(msg);
+                err.span_label(self.span, msg);
+                Err(err)
+            }
         }
     }
 }