If a label is placed on the block of a loop instead of the header, suggest moving it to the header.
This commit is contained in:
parent
227690a258
commit
f478853f42
7 changed files with 296 additions and 25 deletions
|
@ -2874,7 +2874,12 @@ impl<'a> Parser<'a> {
|
|||
first_pat
|
||||
}
|
||||
|
||||
pub(crate) fn maybe_recover_unexpected_block_label(&mut self) -> bool {
|
||||
/// If `loop_header` is `Some` and an unexpected block label is encountered,
|
||||
/// it is suggested to be moved just before `loop_header`, else it is suggested to be removed.
|
||||
pub(crate) fn maybe_recover_unexpected_block_label(
|
||||
&mut self,
|
||||
loop_header: Option<Span>,
|
||||
) -> bool {
|
||||
// Check for `'a : {`
|
||||
if !(self.check_lifetime()
|
||||
&& self.look_ahead(1, |t| *t == token::Colon)
|
||||
|
@ -2885,16 +2890,28 @@ impl<'a> Parser<'a> {
|
|||
let label = self.eat_label().expect("just checked if a label exists");
|
||||
self.bump(); // eat `:`
|
||||
let span = label.ident.span.to(self.prev_token.span);
|
||||
self.dcx()
|
||||
let mut diag = self
|
||||
.dcx()
|
||||
.struct_span_err(span, "block label not supported here")
|
||||
.with_span_label(span, "not supported here")
|
||||
.with_tool_only_span_suggestion(
|
||||
.with_span_label(span, "not supported here");
|
||||
if let Some(loop_header) = loop_header {
|
||||
diag.multipart_suggestion(
|
||||
"if you meant to label the loop, move this label before the loop",
|
||||
vec![
|
||||
(label.ident.span.until(self.token.span), String::from("")),
|
||||
(loop_header.shrink_to_lo(), format!("{}: ", label.ident)),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
diag.tool_only_span_suggestion(
|
||||
label.ident.span.until(self.token.span),
|
||||
"remove this block label",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
);
|
||||
}
|
||||
diag.emit();
|
||||
true
|
||||
}
|
||||
|
||||
|
|
|
@ -2286,7 +2286,7 @@ impl<'a> Parser<'a> {
|
|||
});
|
||||
}
|
||||
|
||||
let (attrs, blk) = self.parse_block_common(lo, blk_mode, true)?;
|
||||
let (attrs, blk) = self.parse_block_common(lo, blk_mode, true, None)?;
|
||||
Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs))
|
||||
}
|
||||
|
||||
|
@ -2851,7 +2851,11 @@ impl<'a> Parser<'a> {
|
|||
));
|
||||
}
|
||||
|
||||
let (attrs, loop_block) = self.parse_inner_attrs_and_block()?;
|
||||
let (attrs, loop_block) = self.parse_inner_attrs_and_block(
|
||||
// Only suggest moving erroneous block label to the loop header
|
||||
// if there is not already a label there
|
||||
opt_label.is_none().then_some(lo),
|
||||
)?;
|
||||
|
||||
let kind = ExprKind::ForLoop { pat, iter: expr, body: loop_block, label: opt_label, kind };
|
||||
|
||||
|
@ -2894,11 +2898,17 @@ impl<'a> Parser<'a> {
|
|||
err.span_label(lo, "while parsing the condition of this `while` expression");
|
||||
err
|
||||
})?;
|
||||
let (attrs, body) = self.parse_inner_attrs_and_block().map_err(|mut err| {
|
||||
err.span_label(lo, "while parsing the body of this `while` expression");
|
||||
err.span_label(cond.span, "this `while` condition successfully parsed");
|
||||
err
|
||||
})?;
|
||||
let (attrs, body) = self
|
||||
.parse_inner_attrs_and_block(
|
||||
// Only suggest moving erroneous block label to the loop header
|
||||
// if there is not already a label there
|
||||
opt_label.is_none().then_some(lo),
|
||||
)
|
||||
.map_err(|mut err| {
|
||||
err.span_label(lo, "while parsing the body of this `while` expression");
|
||||
err.span_label(cond.span, "this `while` condition successfully parsed");
|
||||
err
|
||||
})?;
|
||||
|
||||
self.recover_loop_else("while", lo)?;
|
||||
|
||||
|
@ -2912,7 +2922,11 @@ impl<'a> Parser<'a> {
|
|||
/// Parses `loop { ... }` (`loop` token already eaten).
|
||||
fn parse_expr_loop(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
|
||||
let loop_span = self.prev_token.span;
|
||||
let (attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
let (attrs, body) = self.parse_inner_attrs_and_block(
|
||||
// Only suggest moving erroneous block label to the loop header
|
||||
// if there is not already a label there
|
||||
opt_label.is_none().then_some(lo),
|
||||
)?;
|
||||
self.recover_loop_else("loop", lo)?;
|
||||
Ok(self.mk_expr_with_attrs(
|
||||
lo.to(self.prev_token.span),
|
||||
|
@ -2962,7 +2976,7 @@ impl<'a> Parser<'a> {
|
|||
Applicability::MaybeIncorrect, // speculative
|
||||
);
|
||||
}
|
||||
if self.maybe_recover_unexpected_block_label() {
|
||||
if self.maybe_recover_unexpected_block_label(None) {
|
||||
e.cancel();
|
||||
self.bump();
|
||||
} else {
|
||||
|
@ -3376,7 +3390,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Parses a `try {...}` expression (`try` token already eaten).
|
||||
fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> {
|
||||
let (attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
let (attrs, body) = self.parse_inner_attrs_and_block(None)?;
|
||||
if self.eat_keyword(exp!(Catch)) {
|
||||
Err(self.dcx().create_err(errors::CatchAfterTry { span: self.prev_token.span }))
|
||||
} else {
|
||||
|
@ -3424,7 +3438,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
let capture_clause = self.parse_capture_clause()?;
|
||||
let decl_span = lo.to(self.prev_token.span);
|
||||
let (attrs, body) = self.parse_inner_attrs_and_block()?;
|
||||
let (attrs, body) = self.parse_inner_attrs_and_block(None)?;
|
||||
let kind = ExprKind::Gen(capture_clause, body, kind, decl_span);
|
||||
Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
|
||||
}
|
||||
|
|
|
@ -2529,7 +2529,7 @@ impl<'a> Parser<'a> {
|
|||
*sig_hi = self.prev_token.span;
|
||||
(AttrVec::new(), None)
|
||||
} else if self.check(exp!(OpenBrace)) || self.token.is_whole_block() {
|
||||
self.parse_block_common(self.token.span, BlockCheckMode::Default, false)
|
||||
self.parse_block_common(self.token.span, BlockCheckMode::Default, false, None)
|
||||
.map(|(attrs, body)| (attrs, Some(body)))?
|
||||
} else if self.token == token::Eq {
|
||||
// Recover `fn foo() = $expr;`.
|
||||
|
|
|
@ -1374,7 +1374,7 @@ impl<'a> Parser<'a> {
|
|||
self.psess.gated_spans.gate(sym::inline_const_pat, span);
|
||||
}
|
||||
self.expect_keyword(exp!(Const))?;
|
||||
let (attrs, blk) = self.parse_inner_attrs_and_block()?;
|
||||
let (attrs, blk) = self.parse_inner_attrs_and_block(None)?;
|
||||
let anon_const = AnonConst {
|
||||
id: DUMMY_NODE_ID,
|
||||
value: self.mk_expr(blk.span, ExprKind::Block(blk, None)),
|
||||
|
|
|
@ -482,7 +482,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Parses a block. No inner attributes are allowed.
|
||||
pub fn parse_block(&mut self) -> PResult<'a, P<Block>> {
|
||||
let (attrs, block) = self.parse_inner_attrs_and_block()?;
|
||||
let (attrs, block) = self.parse_inner_attrs_and_block(None)?;
|
||||
if let [.., last] = &*attrs {
|
||||
let suggest_to_outer = match &last.kind {
|
||||
ast::AttrKind::Normal(attr) => attr.item.is_valid_for_outer_style(),
|
||||
|
@ -660,22 +660,32 @@ impl<'a> Parser<'a> {
|
|||
Err(self.error_block_no_opening_brace_msg(Cow::from(msg)))
|
||||
}
|
||||
|
||||
/// Parses a block. Inner attributes are allowed.
|
||||
pub(super) fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (AttrVec, P<Block>)> {
|
||||
self.parse_block_common(self.token.span, BlockCheckMode::Default, true)
|
||||
/// Parses a block. Inner attributes are allowed, block labels are not.
|
||||
///
|
||||
/// If `loop_header` is `Some` and an unexpected block label is encountered,
|
||||
/// it is suggested to be moved just before `loop_header`, else it is suggested to be removed.
|
||||
pub(super) fn parse_inner_attrs_and_block(
|
||||
&mut self,
|
||||
loop_header: Option<Span>,
|
||||
) -> PResult<'a, (AttrVec, P<Block>)> {
|
||||
self.parse_block_common(self.token.span, BlockCheckMode::Default, true, loop_header)
|
||||
}
|
||||
|
||||
/// Parses a block. Inner attributes are allowed.
|
||||
/// Parses a block. Inner attributes are allowed, block labels are not.
|
||||
///
|
||||
/// If `loop_header` is `Some` and an unexpected block label is encountered,
|
||||
/// it is suggested to be moved just before `loop_header`, else it is suggested to be removed.
|
||||
pub(super) fn parse_block_common(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
blk_mode: BlockCheckMode,
|
||||
can_be_struct_literal: bool,
|
||||
loop_header: Option<Span>,
|
||||
) -> PResult<'a, (AttrVec, P<Block>)> {
|
||||
maybe_whole!(self, NtBlock, |block| (AttrVec::new(), block));
|
||||
|
||||
let maybe_ident = self.prev_token.clone();
|
||||
self.maybe_recover_unexpected_block_label();
|
||||
self.maybe_recover_unexpected_block_label(loop_header);
|
||||
if !self.eat(exp!(OpenBrace)) {
|
||||
return self.error_block_no_opening_brace();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue