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
4 changed files with 259 additions and 162 deletions
|
@ -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",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue