diff options
| author | bors <bors@rust-lang.org> | 2019-07-30 03:38:54 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-07-30 03:38:54 +0000 |
| commit | 4eeaaa722d6ac6d24de6e4d3faefb7c44e674b37 (patch) | |
| tree | ed3ee28acaee8ae750947dd3a224d9d1801e713d /src/libsyntax/parse | |
| parent | 04b88a9eba8abbac87eddcb2998beea09589c2c9 (diff) | |
| parent | 91c10f8839156b3c3001271be17995806fb74e06 (diff) | |
| download | rust-4eeaaa722d6ac6d24de6e4d3faefb7c44e674b37.tar.gz rust-4eeaaa722d6ac6d24de6e4d3faefb7c44e674b37.zip | |
Auto merge of #63124 - Centril:rollup-onohtqt, r=Centril
Rollup of 12 pull requests Successful merges: - #61965 (Remove mentions of removed `offset_to` method from `align_offset` docs) - #62928 (Syntax: Recover on `for ( $pat in $expr ) $block`) - #63000 (Impl Debug for Chars) - #63083 (Make generic parameters always use modern hygiene) - #63087 (Add very simple edition check to tidy.) - #63093 (Properly check the defining scope of existential types) - #63096 (Add tests for some `existential_type` ICEs) - #63099 (vxworks: Remove Linux-specific comments.) - #63106 (ci: Skip installing SWIG/xz on OSX ) - #63108 (Add links to None in Option doc) - #63109 (std: Fix a failing `fs` test on Windows) - #63111 (Add syntactic and semantic tests for rest patterns, i.e. `..`) Failed merges: r? @ghost
Diffstat (limited to 'src/libsyntax/parse')
| -rw-r--r-- | src/libsyntax/parse/diagnostics.rs | 118 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 261 |
2 files changed, 217 insertions, 162 deletions
diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 39cb5042fbc..9eb6aa303b0 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -14,7 +14,7 @@ use crate::ThinVec; use crate::util::parser::AssocOp; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_data_structures::fx::FxHashSet; -use syntax_pos::{Span, DUMMY_SP, MultiSpan}; +use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError}; use log::{debug, trace}; use std::mem; @@ -199,6 +199,10 @@ impl<'a> Parser<'a> { &self.sess.span_diagnostic } + crate fn span_to_snippet(&self, span: Span) -> Result<String, SpanSnippetError> { + self.sess.source_map().span_to_snippet(span) + } + crate fn expected_ident_found(&self) -> DiagnosticBuilder<'a> { let mut err = self.struct_span_err( self.token.span, @@ -549,8 +553,10 @@ impl<'a> Parser<'a> { ExprKind::Binary(op, _, _) if op.node.is_comparison() => { // respan to include both operators let op_span = op.span.to(self.token.span); - let mut err = self.diagnostic().struct_span_err(op_span, - "chained comparison operators require parentheses"); + let mut err = self.struct_span_err( + op_span, + "chained comparison operators require parentheses", + ); if op.node == BinOpKind::Lt && *outer_op == AssocOp::Less || // Include `<` to provide this recommendation *outer_op == AssocOp::Greater // even in a case like the following: @@ -717,8 +723,6 @@ impl<'a> Parser<'a> { path.span = ty_span.to(self.prev_span); let ty_str = self - .sess - .source_map() .span_to_snippet(ty_span) .unwrap_or_else(|_| pprust::ty_to_string(&ty)); self.diagnostic() @@ -889,7 +893,7 @@ impl<'a> Parser<'a> { err.span_label(await_sp, "while parsing this incorrect await expression"); err })?; - let expr_str = self.sess.source_map().span_to_snippet(expr.span) + let expr_str = self.span_to_snippet(expr.span) .unwrap_or_else(|_| pprust::expr_to_string(&expr)); let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" }); let sp = lo.to(expr.span); @@ -923,6 +927,48 @@ impl<'a> Parser<'a> { } } + /// Recover a situation like `for ( $pat in $expr )` + /// and suggest writing `for $pat in $expr` instead. + /// + /// This should be called before parsing the `$block`. + crate fn recover_parens_around_for_head( + &mut self, + pat: P<Pat>, + expr: &Expr, + begin_paren: Option<Span>, + ) -> P<Pat> { + match (&self.token.kind, begin_paren) { + (token::CloseDelim(token::Paren), Some(begin_par_sp)) => { + self.bump(); + + let pat_str = self + // Remove the `(` from the span of the pattern: + .span_to_snippet(pat.span.trim_start(begin_par_sp).unwrap()) + .unwrap_or_else(|_| pprust::pat_to_string(&pat)); + + self.struct_span_err(self.prev_span, "unexpected closing `)`") + .span_label(begin_par_sp, "opening `(`") + .span_suggestion( + begin_par_sp.to(self.prev_span), + "remove parenthesis in `for` loop", + format!("{} in {}", pat_str, pprust::expr_to_string(&expr)), + // With e.g. `for (x) in y)` this would replace `(x) in y)` + // with `x) in y)` which is syntactically invalid. + // However, this is prevented before we get here. + Applicability::MachineApplicable, + ) + .emit(); + + // Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint. + pat.and_then(|pat| match pat.node { + PatKind::Paren(pat) => pat, + _ => P(pat), + }) + } + _ => pat, + } + } + crate fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool { self.token.is_ident() && if let ast::ExprKind::Path(..) = node { true } else { false } && @@ -1105,17 +1151,14 @@ impl<'a> Parser<'a> { crate fn check_for_for_in_in_typo(&mut self, in_span: Span) { if self.eat_keyword(kw::In) { // a common typo: `for _ in in bar {}` - let mut err = self.sess.span_diagnostic.struct_span_err( - self.prev_span, - "expected iterable, found keyword `in`", - ); - err.span_suggestion_short( - in_span.until(self.prev_span), - "remove the duplicated `in`", - String::new(), - Applicability::MachineApplicable, - ); - err.emit(); + self.struct_span_err(self.prev_span, "expected iterable, found keyword `in`") + .span_suggestion_short( + in_span.until(self.prev_span), + "remove the duplicated `in`", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); } } @@ -1128,12 +1171,12 @@ impl<'a> Parser<'a> { crate fn eat_incorrect_doc_comment_for_arg_type(&mut self) { if let token::DocComment(_) = self.token.kind { - let mut err = self.diagnostic().struct_span_err( + self.struct_span_err( self.token.span, "documentation comments cannot be applied to a function parameter's type", - ); - err.span_label(self.token.span, "doc comments are not allowed here"); - err.emit(); + ) + .span_label(self.token.span, "doc comments are not allowed here") + .emit(); self.bump(); } else if self.token == token::Pound && self.look_ahead(1, |t| { *t == token::OpenDelim(token::Bracket) @@ -1145,12 +1188,12 @@ impl<'a> Parser<'a> { } let sp = lo.to(self.token.span); self.bump(); - let mut err = self.diagnostic().struct_span_err( + self.struct_span_err( sp, "attributes cannot be applied to a function parameter's type", - ); - err.span_label(sp, "attributes are not allowed here"); - err.emit(); + ) + .span_label(sp, "attributes are not allowed here") + .emit(); } } @@ -1206,18 +1249,19 @@ impl<'a> Parser<'a> { self.expect(&token::Colon)?; let ty = self.parse_ty()?; - let mut err = self.diagnostic().struct_span_err_with_code( - pat.span, - "patterns aren't allowed in methods without bodies", - DiagnosticId::Error("E0642".into()), - ); - err.span_suggestion_short( - pat.span, - "give this argument a name or use an underscore to ignore it", - "_".to_owned(), - Applicability::MachineApplicable, - ); - err.emit(); + self.diagnostic() + .struct_span_err_with_code( + pat.span, + "patterns aren't allowed in methods without bodies", + DiagnosticId::Error("E0642".into()), + ) + .span_suggestion_short( + pat.span, + "give this argument a name or use an underscore to ignore it", + "_".to_owned(), + Applicability::MachineApplicable, + ) + .emit(); // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. let pat = P(Pat { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6cb965bf817..fb5ff7e8f98 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2329,19 +2329,19 @@ impl<'a> Parser<'a> { // This is a struct literal, but we don't can't accept them here let expr = self.parse_struct_expr(lo, path.clone(), attrs.clone()); if let (Ok(expr), false) = (&expr, struct_allowed) { - let mut err = self.diagnostic().struct_span_err( + self.struct_span_err( expr.span, "struct literals are not allowed here", - ); - err.multipart_suggestion( + ) + .multipart_suggestion( "surround the struct literal with parentheses", vec![ (lo.shrink_to_lo(), "(".to_string()), (expr.span.shrink_to_hi(), ")".to_string()), ], Applicability::MachineApplicable, - ); - err.emit(); + ) + .emit(); } return Some(expr); } @@ -2370,18 +2370,18 @@ impl<'a> Parser<'a> { } } if self.token == token::Comma { - let mut err = self.sess.span_diagnostic.mut_span_err( + self.struct_span_err( exp_span.to(self.prev_span), "cannot use a comma after the base struct", - ); - err.span_suggestion_short( + ) + .span_suggestion_short( self.token.span, "remove this comma", String::new(), Applicability::MachineApplicable - ); - err.note("the base struct must always be the last field"); - err.emit(); + ) + .note("the base struct must always be the last field") + .emit(); self.recover_stmt(); } break; @@ -2736,15 +2736,14 @@ impl<'a> Parser<'a> { let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; let span_of_tilde = lo; - let mut err = self.diagnostic() - .struct_span_err(span_of_tilde, "`~` cannot be used as a unary operator"); - err.span_suggestion_short( - span_of_tilde, - "use `!` to perform bitwise negation", - "!".to_owned(), - Applicability::MachineApplicable - ); - err.emit(); + self.struct_span_err(span_of_tilde, "`~` cannot be used as a unary operator") + .span_suggestion_short( + span_of_tilde, + "use `!` to perform bitwise negation", + "!".to_owned(), + Applicability::MachineApplicable + ) + .emit(); (lo.to(span), self.mk_unary(UnOp::Not, e)) } token::BinOp(token::Minus) => { @@ -2792,21 +2791,20 @@ impl<'a> Parser<'a> { if cannot_continue_expr { self.bump(); // Emit the error ... - let mut err = self.diagnostic() - .struct_span_err(self.token.span, - &format!("unexpected {} after identifier", - self.this_token_descr())); - // span the `not` plus trailing whitespace to avoid - // trailing whitespace after the `!` in our suggestion - let to_replace = self.sess.source_map() - .span_until_non_whitespace(lo.to(self.token.span)); - err.span_suggestion_short( - to_replace, + self.struct_span_err( + self.token.span, + &format!("unexpected {} after identifier",self.this_token_descr()) + ) + .span_suggestion_short( + // Span the `not` plus trailing whitespace to avoid + // trailing whitespace after the `!` in our suggestion + self.sess.source_map() + .span_until_non_whitespace(lo.to(self.token.span)), "use `!` to perform logical negation", "!".to_owned(), Applicability::MachineApplicable - ); - err.emit(); + ) + .emit(); // —and recover! (just as if we were in the block // for the `token::Not` arm) let e = self.parse_prefix_expr(None); @@ -2884,7 +2882,7 @@ impl<'a> Parser<'a> { // We've found an expression that would be parsed as a statement, but the next // token implies this should be parsed as an expression. // For example: `if let Some(x) = x { x } else { 0 } / 2` - let mut err = self.sess.span_diagnostic.struct_span_err(self.token.span, &format!( + let mut err = self.struct_span_err(self.token.span, &format!( "expected expression, found `{}`", pprust::token_to_string(&self.token), )); @@ -3072,28 +3070,29 @@ impl<'a> Parser<'a> { // in AST and continue parsing. let msg = format!("`<` is interpreted as a start of generic \ arguments for `{}`, not a {}", path, op_noun); - let mut err = - self.sess.span_diagnostic.struct_span_err(self.token.span, &msg); let span_after_type = parser_snapshot_after_type.token.span; - err.span_label(self.look_ahead(1, |t| t.span).to(span_after_type), - "interpreted as generic arguments"); - err.span_label(self.token.span, format!("not interpreted as {}", op_noun)); - let expr = mk_expr(self, P(Ty { span: path.span, node: TyKind::Path(None, path), id: ast::DUMMY_NODE_ID })); - let expr_str = self.sess.source_map().span_to_snippet(expr.span) - .unwrap_or_else(|_| pprust::expr_to_string(&expr)); - err.span_suggestion( - expr.span, - &format!("try {} the cast value", op_verb), - format!("({})", expr_str), - Applicability::MachineApplicable - ); - err.emit(); + let expr_str = self.span_to_snippet(expr.span) + .unwrap_or_else(|_| pprust::expr_to_string(&expr)); + + self.struct_span_err(self.token.span, &msg) + .span_label( + self.look_ahead(1, |t| t.span).to(span_after_type), + "interpreted as generic arguments" + ) + .span_label(self.token.span, format!("not interpreted as {}", op_noun)) + .span_suggestion( + expr.span, + &format!("try {} the cast value", op_verb), + format!("({})", expr_str), + Applicability::MachineApplicable + ) + .emit(); Ok(expr) } @@ -3276,26 +3275,40 @@ impl<'a> Parser<'a> { } /// Parse a 'for' .. 'in' expression ('for' token already eaten) - fn parse_for_expr(&mut self, opt_label: Option<Label>, - span_lo: Span, - mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { + fn parse_for_expr( + &mut self, + opt_label: Option<Label>, + span_lo: Span, + mut attrs: ThinVec<Attribute> + ) -> PResult<'a, P<Expr>> { // Parse: `for <src_pat> in <src_expr> <src_loop_block>` + // Record whether we are about to parse `for (`. + // This is used below for recovery in case of `for ( $stuff ) $block` + // in which case we will suggest `for $stuff $block`. + let begin_paren = match self.token.kind { + token::OpenDelim(token::Paren) => Some(self.token.span), + _ => None, + }; + let pat = self.parse_top_level_pat()?; if !self.eat_keyword(kw::In) { let in_span = self.prev_span.between(self.token.span); - let mut err = self.sess.span_diagnostic - .struct_span_err(in_span, "missing `in` in `for` loop"); - err.span_suggestion_short( - in_span, "try adding `in` here", " in ".into(), - // has been misleading, at least in the past (closed Issue #48492) - Applicability::MaybeIncorrect - ); - err.emit(); + self.struct_span_err(in_span, "missing `in` in `for` loop") + .span_suggestion_short( + in_span, + "try adding `in` here", " in ".into(), + // has been misleading, at least in the past (closed Issue #48492) + Applicability::MaybeIncorrect + ) + .emit(); } let in_span = self.prev_span; self.check_for_for_in_in_typo(in_span); let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; + + let pat = self.recover_parens_around_for_head(pat, &expr, begin_paren); + let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); @@ -3522,15 +3535,14 @@ impl<'a> Parser<'a> { pats.push(self.parse_top_level_pat()?); if self.token == token::OrOr { - let mut err = self.struct_span_err(self.token.span, - "unexpected token `||` after pattern"); - err.span_suggestion( - self.token.span, - "use a single `|` to specify multiple patterns", - "|".to_owned(), - Applicability::MachineApplicable - ); - err.emit(); + self.struct_span_err(self.token.span, "unexpected token `||` after pattern") + .span_suggestion( + self.token.span, + "use a single `|` to specify multiple patterns", + "|".to_owned(), + Applicability::MachineApplicable + ) + .emit(); self.bump(); } else if self.eat(&token::BinOp(token::Or)) { // This is a No-op. Continue the loop to parse the next @@ -3627,15 +3639,14 @@ impl<'a> Parser<'a> { if self.token == token::DotDotDot { // Issue #46718 // Accept `...` as if it were `..` to avoid further errors - let mut err = self.struct_span_err(self.token.span, - "expected field pattern, found `...`"); - err.span_suggestion( - self.token.span, - "to omit remaining fields, use one fewer `.`", - "..".to_owned(), - Applicability::MachineApplicable - ); - err.emit(); + self.struct_span_err(self.token.span, "expected field pattern, found `...`") + .span_suggestion( + self.token.span, + "to omit remaining fields, use one fewer `.`", + "..".to_owned(), + Applicability::MachineApplicable + ) + .emit(); } self.bump(); // `..` || `...` @@ -3788,7 +3799,7 @@ impl<'a> Parser<'a> { let seq_span = pat.span.to(self.prev_span); let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); - if let Ok(seq_snippet) = self.sess.source_map().span_to_snippet(seq_span) { + if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { err.span_suggestion( seq_span, "try adding parentheses to match on a tuple..", @@ -4137,7 +4148,7 @@ impl<'a> Parser<'a> { let parser_snapshot_after_type = self.clone(); mem::replace(self, parser_snapshot_before_type); - let snippet = self.sess.source_map().span_to_snippet(pat.span).unwrap(); + let snippet = self.span_to_snippet(pat.span).unwrap(); err.span_label(pat.span, format!("while parsing the type for `{}`", snippet)); (Some((parser_snapshot_after_type, colon_sp, err)), None) } @@ -4557,7 +4568,7 @@ impl<'a> Parser<'a> { if self.eat(&token::Semi) { stmt_span = stmt_span.with_hi(self.prev_span.hi()); } - if let Ok(snippet) = self.sess.source_map().span_to_snippet(stmt_span) { + if let Ok(snippet) = self.span_to_snippet(stmt_span) { e.span_suggestion( stmt_span, "try placing this code inside a block", @@ -4730,7 +4741,7 @@ impl<'a> Parser<'a> { lo.to(self.prev_span), "parenthesized lifetime bounds are not supported" ); - if let Ok(snippet) = self.sess.source_map().span_to_snippet(inner_span) { + if let Ok(snippet) = self.span_to_snippet(inner_span) { err.span_suggestion_short( lo.to(self.prev_span), "remove the parentheses", @@ -4788,7 +4799,7 @@ impl<'a> Parser<'a> { let mut new_bound_list = String::new(); if !bounds.is_empty() { let mut snippets = bounds.iter().map(|bound| bound.span()) - .map(|span| self.sess.source_map().span_to_snippet(span)); + .map(|span| self.span_to_snippet(span)); while let Some(Ok(snippet)) = snippets.next() { new_bound_list.push_str(" + "); new_bound_list.push_str(&snippet); @@ -5853,15 +5864,16 @@ impl<'a> Parser<'a> { if let token::DocComment(_) = self.token.kind { if self.look_ahead(1, |tok| tok == &token::CloseDelim(token::Brace)) { - let mut err = self.diagnostic().struct_span_err_with_code( + self.diagnostic().struct_span_err_with_code( self.token.span, "found a documentation comment that doesn't document anything", DiagnosticId::Error("E0584".into()), - ); - err.help("doc comments must come before what they document, maybe a \ + ) + .help( + "doc comments must come before what they document, maybe a \ comment was intended with `//`?", - ); - err.emit(); + ) + .emit(); self.bump(); continue; } @@ -6305,12 +6317,15 @@ impl<'a> Parser<'a> { let sp = path.span; let help_msg = format!("make this visible only to module `{}` with `in`", path); self.expect(&token::CloseDelim(token::Paren))?; // `)` - let mut err = struct_span_err!(self.sess.span_diagnostic, sp, E0704, "{}", msg); - err.help(suggestion); - err.span_suggestion( - sp, &help_msg, format!("in {}", path), Applicability::MachineApplicable - ); - err.emit(); // emit diagnostic, but continue with public visibility + struct_span_err!(self.sess.span_diagnostic, sp, E0704, "{}", msg) + .help(suggestion) + .span_suggestion( + sp, + &help_msg, + format!("in {}", path), + Applicability::MachineApplicable, + ) + .emit(); // emit diagnostic, but continue with public visibility } } @@ -6744,14 +6759,10 @@ impl<'a> Parser<'a> { } ident = Ident::from_str(&fixed_name).with_span_pos(fixed_name_sp); - let mut err = self.struct_span_err(fixed_name_sp, error_msg); - err.span_label(fixed_name_sp, "dash-separated idents are not valid"); - err.multipart_suggestion( - suggestion_msg, - replacement, - Applicability::MachineApplicable, - ); - err.emit(); + self.struct_span_err(fixed_name_sp, error_msg) + .span_label(fixed_name_sp, "dash-separated idents are not valid") + .multipart_suggestion(suggestion_msg, replacement, Applicability::MachineApplicable) + .emit(); } Ok(ident) } @@ -6906,14 +6917,14 @@ impl<'a> Parser<'a> { if !self.eat(&token::Comma) { if self.token.is_ident() && !self.token.is_reserved_ident() { let sp = self.sess.source_map().next_point(self.prev_span); - let mut err = self.struct_span_err(sp, "missing comma"); - err.span_suggestion_short( - sp, - "missing comma", - ",".to_owned(), - Applicability::MaybeIncorrect, - ); - err.emit(); + self.struct_span_err(sp, "missing comma") + .span_suggestion_short( + sp, + "missing comma", + ",".to_owned(), + Applicability::MaybeIncorrect, + ) + .emit(); } else { break; } @@ -6952,15 +6963,16 @@ impl<'a> Parser<'a> { Some(abi) => Ok(Some(abi)), None => { let prev_span = self.prev_span; - let mut err = struct_span_err!( + struct_span_err!( self.sess.span_diagnostic, prev_span, E0703, "invalid ABI: found `{}`", - symbol); - err.span_label(prev_span, "invalid ABI"); - err.help(&format!("valid ABIs: {}", abi::all_names().join(", "))); - err.emit(); + symbol + ) + .span_label(prev_span, "invalid ABI") + .help(&format!("valid ABIs: {}", abi::all_names().join(", "))) + .emit(); Ok(None) } } @@ -7130,16 +7142,15 @@ impl<'a> Parser<'a> { // CONST ITEM if self.eat_keyword(kw::Mut) { let prev_span = self.prev_span; - let mut err = self.diagnostic() - .struct_span_err(prev_span, "const globals cannot be mutable"); - err.span_label(prev_span, "cannot be mutable"); - err.span_suggestion( - const_span, - "you might want to declare a static instead", - "static".to_owned(), - Applicability::MaybeIncorrect, - ); - err.emit(); + self.struct_span_err(prev_span, "const globals cannot be mutable") + .span_label(prev_span, "cannot be mutable") + .span_suggestion( + const_span, + "you might want to declare a static instead", + "static".to_owned(), + Applicability::MaybeIncorrect, + ) + .emit(); } let (ident, item_, extra_attrs) = self.parse_item_const(None)?; let prev_span = self.prev_span; @@ -7407,7 +7418,7 @@ impl<'a> Parser<'a> { sp, &suggestion, format!(" {} ", kw), Applicability::MachineApplicable ); } else { - if let Ok(snippet) = self.sess.source_map().span_to_snippet(ident_sp) { + if let Ok(snippet) = self.span_to_snippet(ident_sp) { err.span_suggestion( full_sp, "if you meant to call a macro, try", |
