Rollup merge of #62928 - Centril:recover-parens-around-for-head, r=estebank
Syntax: Recover on `for ( $pat in $expr ) $block` Fixes #62724 by adding some recovery: ``` error: unexpected closing `)` --> $DIR/recover-for-loop-parens-around-head.rs:10:23 | LL | for ( elem in vec ) { | --------------^ | | | opening `(` | help: remove parenthesis in `for` loop: `elem in vec` ``` The last 2 commits are drive-by cleanups. r? @estebank
This commit is contained in:
commit
36029878e7
@ -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 {
|
||||
|
@ -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",
|
||||
|
15
src/test/ui/parser/recover-for-loop-parens-around-head.rs
Normal file
15
src/test/ui/parser/recover-for-loop-parens-around-head.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Here we test that the parser is able to recover in a situation like
|
||||
// `for ( $pat in $expr )` since that is familiar syntax in other languages.
|
||||
// Instead we suggest that the user writes `for $pat in $expr`.
|
||||
|
||||
#![deny(unused)] // Make sure we don't trigger `unused_parens`.
|
||||
|
||||
fn main() {
|
||||
let vec = vec![1, 2, 3];
|
||||
|
||||
for ( elem in vec ) {
|
||||
//~^ ERROR expected one of `)`, `,`, or `@`, found `in`
|
||||
//~| ERROR unexpected closing `)`
|
||||
const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
error: expected one of `)`, `,`, or `@`, found `in`
|
||||
--> $DIR/recover-for-loop-parens-around-head.rs:10:16
|
||||
|
|
||||
LL | for ( elem in vec ) {
|
||||
| ^^ expected one of `)`, `,`, or `@` here
|
||||
|
||||
error: unexpected closing `)`
|
||||
--> $DIR/recover-for-loop-parens-around-head.rs:10:23
|
||||
|
|
||||
LL | for ( elem in vec ) {
|
||||
| --------------^
|
||||
| |
|
||||
| opening `(`
|
||||
| help: remove parenthesis in `for` loop: `elem in vec`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/recover-for-loop-parens-around-head.rs:13:38
|
||||
|
|
||||
LL | const RECOVERY_WITNESS: () = 0;
|
||||
| ^ expected (), found integer
|
||||
|
|
||||
= note: expected type `()`
|
||||
found type `{integer}`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Reference in New Issue
Block a user