Add ErrorGuaranteed
to ast::ExprKind::Err
This commit is contained in:
parent
a3fce72a27
commit
c440a5b814
37 changed files with 660 additions and 602 deletions
|
@ -744,7 +744,8 @@ impl<'a> Parser<'a> {
|
|||
Err(err)
|
||||
}
|
||||
|
||||
pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) {
|
||||
/// The user has written `#[attr] expr` which is unsupported. (#106020)
|
||||
pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) -> ErrorGuaranteed {
|
||||
// Missing semicolon typo error.
|
||||
let span = self.prev_token.span.shrink_to_hi();
|
||||
let mut err = self.dcx().create_err(ExpectedSemi {
|
||||
|
@ -787,6 +788,8 @@ impl<'a> Parser<'a> {
|
|||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
||||
// Special handling for `#[cfg(...)]` chains
|
||||
let mut snapshot = self.create_snapshot_for_diagnostic();
|
||||
if let [attr] = &expr.attrs[..]
|
||||
&& let ast::AttrKind::Normal(attr_kind) = &attr.kind
|
||||
|
@ -799,7 +802,7 @@ impl<'a> Parser<'a> {
|
|||
Err(inner_err) => {
|
||||
err.cancel();
|
||||
inner_err.cancel();
|
||||
return;
|
||||
return self.dcx().span_delayed_bug(expr.span, "not a tail expression");
|
||||
}
|
||||
}
|
||||
&& let ast::AttrKind::Normal(next_attr_kind) = next_attr.kind
|
||||
|
@ -812,7 +815,7 @@ impl<'a> Parser<'a> {
|
|||
Err(inner_err) => {
|
||||
err.cancel();
|
||||
inner_err.cancel();
|
||||
return;
|
||||
return self.dcx().span_delayed_bug(expr.span, "not a tail expression");
|
||||
}
|
||||
};
|
||||
// We have for sure
|
||||
|
@ -845,7 +848,7 @@ impl<'a> Parser<'a> {
|
|||
);
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
err.emit()
|
||||
}
|
||||
|
||||
fn check_too_many_raw_str_terminators(&mut self, err: &mut DiagnosticBuilder<'_>) -> bool {
|
||||
|
@ -921,10 +924,10 @@ impl<'a> Parser<'a> {
|
|||
// fn foo() -> Foo { Path {
|
||||
// field: value,
|
||||
// } }
|
||||
err.delay_as_bug();
|
||||
let guar = err.delay_as_bug();
|
||||
self.restore_snapshot(snapshot);
|
||||
let mut tail = self.mk_block(
|
||||
thin_vec![self.mk_stmt_err(expr.span)],
|
||||
thin_vec![self.mk_stmt_err(expr.span, guar)],
|
||||
s,
|
||||
lo.to(self.prev_token.span),
|
||||
);
|
||||
|
@ -990,7 +993,7 @@ impl<'a> Parser<'a> {
|
|||
decl_hi: Span,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
err.span_label(lo.to(decl_hi), "while parsing the body of this closure");
|
||||
match before.kind {
|
||||
let guar = match before.kind {
|
||||
token::OpenDelim(Delimiter::Brace)
|
||||
if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) =>
|
||||
{
|
||||
|
@ -1004,8 +1007,9 @@ impl<'a> Parser<'a> {
|
|||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.emit();
|
||||
let guar = err.emit();
|
||||
self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]);
|
||||
guar
|
||||
}
|
||||
token::OpenDelim(Delimiter::Parenthesis)
|
||||
if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) =>
|
||||
|
@ -1022,7 +1026,7 @@ impl<'a> Parser<'a> {
|
|||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.emit();
|
||||
err.emit()
|
||||
}
|
||||
_ if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => {
|
||||
// We don't have a heuristic to correctly identify where the block
|
||||
|
@ -1035,8 +1039,8 @@ impl<'a> Parser<'a> {
|
|||
return Err(err);
|
||||
}
|
||||
_ => return Err(err),
|
||||
}
|
||||
Ok(self.mk_expr_err(lo.to(self.token.span)))
|
||||
};
|
||||
Ok(self.mk_expr_err(lo.to(self.token.span), guar))
|
||||
}
|
||||
|
||||
/// Eats and discards tokens until one of `kets` is encountered. Respects token trees,
|
||||
|
@ -1214,7 +1218,7 @@ impl<'a> Parser<'a> {
|
|||
&mut self,
|
||||
mut e: DiagnosticBuilder<'a>,
|
||||
expr: &mut P<Expr>,
|
||||
) -> PResult<'a, ()> {
|
||||
) -> PResult<'a, ErrorGuaranteed> {
|
||||
if let ExprKind::Binary(binop, _, _) = &expr.kind
|
||||
&& let ast::BinOpKind::Lt = binop.node
|
||||
&& self.eat(&token::Comma)
|
||||
|
@ -1239,9 +1243,9 @@ impl<'a> Parser<'a> {
|
|||
// The subsequent expression is valid. Mark
|
||||
// `expr` as erroneous and emit `e` now, but
|
||||
// return `Ok` so parsing can continue.
|
||||
e.emit();
|
||||
*expr = self.mk_expr_err(expr.span.to(self.prev_token.span));
|
||||
return Ok(());
|
||||
let guar = e.emit();
|
||||
*expr = self.mk_expr_err(expr.span.to(self.prev_token.span), guar);
|
||||
return Ok(guar);
|
||||
}
|
||||
Err(err) => {
|
||||
err.cancel();
|
||||
|
@ -1393,7 +1397,8 @@ impl<'a> Parser<'a> {
|
|||
outer_op.node,
|
||||
);
|
||||
|
||||
let mk_err_expr = |this: &Self, span| Ok(Some(this.mk_expr(span, ExprKind::Err)));
|
||||
let mk_err_expr =
|
||||
|this: &Self, span, guar| Ok(Some(this.mk_expr(span, ExprKind::Err(guar))));
|
||||
|
||||
match &inner_op.kind {
|
||||
ExprKind::Binary(op, l1, r1) if op.node.is_comparison() => {
|
||||
|
@ -1443,11 +1448,11 @@ impl<'a> Parser<'a> {
|
|||
match self.parse_expr() {
|
||||
Ok(_) => {
|
||||
// 99% certain that the suggestion is correct, continue parsing.
|
||||
self.dcx().emit_err(err);
|
||||
let guar = self.dcx().emit_err(err);
|
||||
// FIXME: actually check that the two expressions in the binop are
|
||||
// paths and resynthesize new fn call expression instead of using
|
||||
// `ExprKind::Err` placeholder.
|
||||
mk_err_expr(self, inner_op.span.to(self.prev_token.span))
|
||||
mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar)
|
||||
}
|
||||
Err(expr_err) => {
|
||||
expr_err.cancel();
|
||||
|
@ -1471,11 +1476,11 @@ impl<'a> Parser<'a> {
|
|||
match self.consume_fn_args() {
|
||||
Err(()) => Err(self.dcx().create_err(err)),
|
||||
Ok(()) => {
|
||||
self.dcx().emit_err(err);
|
||||
let guar = self.dcx().emit_err(err);
|
||||
// FIXME: actually check that the two expressions in the binop are
|
||||
// paths and resynthesize new fn call expression instead of using
|
||||
// `ExprKind::Err` placeholder.
|
||||
mk_err_expr(self, inner_op.span.to(self.prev_token.span))
|
||||
mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1492,8 +1497,8 @@ impl<'a> Parser<'a> {
|
|||
let recovered = self
|
||||
.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
|
||||
if matches!(recovered, Recovered::Yes) {
|
||||
self.dcx().emit_err(err);
|
||||
mk_err_expr(self, inner_op.span.to(self.prev_token.span))
|
||||
let guar = self.dcx().emit_err(err);
|
||||
mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar)
|
||||
} else {
|
||||
// These cases cause too many knock-down errors, bail out (#61329).
|
||||
Err(self.dcx().create_err(err))
|
||||
|
@ -1502,9 +1507,9 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
let recover =
|
||||
self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
|
||||
self.dcx().emit_err(err);
|
||||
let guar = self.dcx().emit_err(err);
|
||||
if matches!(recover, Recovered::Yes) {
|
||||
return mk_err_expr(self, inner_op.span.to(self.prev_token.span));
|
||||
return mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -1925,8 +1930,8 @@ impl<'a> Parser<'a> {
|
|||
} else {
|
||||
self.recover_await_prefix(await_sp)?
|
||||
};
|
||||
let sp = self.error_on_incorrect_await(lo, hi, &expr, is_question);
|
||||
let expr = self.mk_expr(lo.to(sp), ExprKind::Err);
|
||||
let (sp, guar) = self.error_on_incorrect_await(lo, hi, &expr, is_question);
|
||||
let expr = self.mk_expr_err(lo.to(sp), guar);
|
||||
self.maybe_recover_from_bad_qpath(expr)
|
||||
}
|
||||
|
||||
|
@ -1955,21 +1960,27 @@ impl<'a> Parser<'a> {
|
|||
Ok((expr.span, expr, is_question))
|
||||
}
|
||||
|
||||
fn error_on_incorrect_await(&self, lo: Span, hi: Span, expr: &Expr, is_question: bool) -> Span {
|
||||
fn error_on_incorrect_await(
|
||||
&self,
|
||||
lo: Span,
|
||||
hi: Span,
|
||||
expr: &Expr,
|
||||
is_question: bool,
|
||||
) -> (Span, ErrorGuaranteed) {
|
||||
let span = lo.to(hi);
|
||||
let applicability = match expr.kind {
|
||||
ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await <expr>?`
|
||||
_ => Applicability::MachineApplicable,
|
||||
};
|
||||
|
||||
self.dcx().emit_err(IncorrectAwait {
|
||||
let guar = self.dcx().emit_err(IncorrectAwait {
|
||||
span,
|
||||
sugg_span: (span, applicability),
|
||||
expr: self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(expr)),
|
||||
question_mark: if is_question { "?" } else { "" },
|
||||
});
|
||||
|
||||
span
|
||||
(span, guar)
|
||||
}
|
||||
|
||||
/// If encountering `future.await()`, consumes and emits an error.
|
||||
|
@ -2013,8 +2024,8 @@ impl<'a> Parser<'a> {
|
|||
);
|
||||
}
|
||||
err.span_suggestion(lo.shrink_to_lo(), format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#", Applicability::MachineApplicable);
|
||||
err.emit();
|
||||
Ok(self.mk_expr_err(lo.to(hi)))
|
||||
let guar = err.emit();
|
||||
Ok(self.mk_expr_err(lo.to(hi), guar))
|
||||
} else {
|
||||
Err(self.expected_expression_found()) // The user isn't trying to invoke the try! macro
|
||||
}
|
||||
|
@ -2059,10 +2070,10 @@ impl<'a> Parser<'a> {
|
|||
lo: Span,
|
||||
err: PErr<'a>,
|
||||
) -> P<Expr> {
|
||||
err.emit();
|
||||
let guar = err.emit();
|
||||
// Recover from parse error, callers expect the closing delim to be consumed.
|
||||
self.consume_block(delim, ConsumeClosingDelim::Yes);
|
||||
self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err)
|
||||
self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err(guar))
|
||||
}
|
||||
|
||||
/// Eats tokens until we can be relatively sure we reached the end of the
|
||||
|
@ -2549,9 +2560,10 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
_ => None,
|
||||
};
|
||||
self.dcx().emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg });
|
||||
let guar =
|
||||
self.dcx().emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg });
|
||||
|
||||
let value = self.mk_expr_err(param.span());
|
||||
let value = self.mk_expr_err(param.span(), guar);
|
||||
Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }))
|
||||
}
|
||||
|
||||
|
@ -2630,8 +2642,8 @@ impl<'a> Parser<'a> {
|
|||
"=",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
let value = self.mk_expr_err(start.to(expr.span));
|
||||
err.emit();
|
||||
let guar = err.emit();
|
||||
let value = self.mk_expr_err(start.to(expr.span), guar);
|
||||
return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }));
|
||||
} else if token::Colon == snapshot.token.kind
|
||||
&& expr.span.lo() == snapshot.token.span.hi()
|
||||
|
@ -2701,8 +2713,8 @@ impl<'a> Parser<'a> {
|
|||
vec![(span.shrink_to_lo(), "{ ".to_string()), (span.shrink_to_hi(), " }".to_string())],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
let value = self.mk_expr_err(span);
|
||||
err.emit();
|
||||
let guar = err.emit();
|
||||
let value = self.mk_expr_err(span, guar);
|
||||
GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
|
|||
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||
use rustc_span::source_map::{self, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{BytePos, Pos, Span};
|
||||
use rustc_span::{BytePos, ErrorGuaranteed, Pos, Span};
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
|
||||
/// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression
|
||||
|
@ -131,9 +131,9 @@ impl<'a> Parser<'a> {
|
|||
if self.may_recover() && self.look_ahead(1, |t| t == &token::Comma) =>
|
||||
{
|
||||
// Special-case handling of `foo(_, _, _)`
|
||||
err.emit();
|
||||
let guar = err.emit();
|
||||
self.bump();
|
||||
Ok(self.mk_expr(self.prev_token.span, ExprKind::Err))
|
||||
Ok(self.mk_expr(self.prev_token.span, ExprKind::Err(guar)))
|
||||
}
|
||||
_ => Err(err),
|
||||
},
|
||||
|
@ -667,8 +667,8 @@ impl<'a> Parser<'a> {
|
|||
let (span, _) = self.parse_expr_prefix_common(box_kw)?;
|
||||
let inner_span = span.with_lo(box_kw.hi());
|
||||
let code = self.sess.source_map().span_to_snippet(inner_span).unwrap();
|
||||
self.dcx().emit_err(errors::BoxSyntaxRemoved { span: span, code: code.trim() });
|
||||
Ok((span, ExprKind::Err))
|
||||
let guar = self.dcx().emit_err(errors::BoxSyntaxRemoved { span: span, code: code.trim() });
|
||||
Ok((span, ExprKind::Err(guar)))
|
||||
}
|
||||
|
||||
fn is_mistaken_not_ident_negation(&self) -> bool {
|
||||
|
@ -860,7 +860,7 @@ impl<'a> Parser<'a> {
|
|||
ExprKind::MethodCall(_) => "a method call",
|
||||
ExprKind::Call(_, _) => "a function call",
|
||||
ExprKind::Await(_, _) => "`.await`",
|
||||
ExprKind::Err => return Ok(with_postfix),
|
||||
ExprKind::Err(_) => return Ok(with_postfix),
|
||||
_ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"),
|
||||
}
|
||||
);
|
||||
|
@ -1315,7 +1315,7 @@ impl<'a> Parser<'a> {
|
|||
let fields: Vec<_> =
|
||||
fields.into_iter().filter(|field| !field.is_shorthand).collect();
|
||||
|
||||
if !fields.is_empty() &&
|
||||
let guar = if !fields.is_empty() &&
|
||||
// `token.kind` should not be compared here.
|
||||
// This is because the `snapshot.token.kind` is treated as the same as
|
||||
// that of the open delim in `TokenTreesReader::parse_token_tree`, even
|
||||
|
@ -1338,11 +1338,11 @@ impl<'a> Parser<'a> {
|
|||
.collect(),
|
||||
},
|
||||
})
|
||||
.emit();
|
||||
.emit()
|
||||
} else {
|
||||
err.emit();
|
||||
}
|
||||
Ok(self.mk_expr_err(span))
|
||||
err.emit()
|
||||
};
|
||||
Ok(self.mk_expr_err(span, guar))
|
||||
}
|
||||
Ok(_) => Err(err),
|
||||
Err(err2) => {
|
||||
|
@ -1684,13 +1684,13 @@ impl<'a> Parser<'a> {
|
|||
&& (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
|
||||
{
|
||||
// We're probably inside of a `Path<'a>` that needs a turbofish
|
||||
self.dcx().emit_err(errors::UnexpectedTokenAfterLabel {
|
||||
let guar = self.dcx().emit_err(errors::UnexpectedTokenAfterLabel {
|
||||
span: self.token.span,
|
||||
remove_label: None,
|
||||
enclose_in_block: None,
|
||||
});
|
||||
consume_colon = false;
|
||||
Ok(self.mk_expr_err(lo))
|
||||
Ok(self.mk_expr_err(lo, guar))
|
||||
} else {
|
||||
let mut err = errors::UnexpectedTokenAfterLabel {
|
||||
span: self.token.span,
|
||||
|
@ -2039,7 +2039,7 @@ impl<'a> Parser<'a> {
|
|||
) -> PResult<'a, L> {
|
||||
if let token::Interpolated(nt) = &self.token.kind
|
||||
&& let token::NtExpr(e) | token::NtLiteral(e) = &nt.0
|
||||
&& matches!(e.kind, ExprKind::Err)
|
||||
&& matches!(e.kind, ExprKind::Err(_))
|
||||
{
|
||||
let mut err = self
|
||||
.dcx()
|
||||
|
@ -2207,7 +2207,7 @@ impl<'a> Parser<'a> {
|
|||
let mut snapshot = self.create_snapshot_for_diagnostic();
|
||||
match snapshot.parse_expr_array_or_repeat(Delimiter::Brace) {
|
||||
Ok(arr) => {
|
||||
self.dcx().emit_err(errors::ArrayBracketsInsteadOfSpaces {
|
||||
let guar = self.dcx().emit_err(errors::ArrayBracketsInsteadOfSpaces {
|
||||
span: arr.span,
|
||||
sub: errors::ArrayBracketsInsteadOfSpacesSugg {
|
||||
left: lo,
|
||||
|
@ -2216,7 +2216,7 @@ impl<'a> Parser<'a> {
|
|||
});
|
||||
|
||||
self.restore_snapshot(snapshot);
|
||||
Some(self.mk_expr_err(arr.span))
|
||||
Some(self.mk_expr_err(arr.span, guar))
|
||||
}
|
||||
Err(e) => {
|
||||
e.cancel();
|
||||
|
@ -2370,7 +2370,10 @@ impl<'a> Parser<'a> {
|
|||
// It is likely that the closure body is a block but where the
|
||||
// braces have been removed. We will recover and eat the next
|
||||
// statements later in the parsing process.
|
||||
body = self.mk_expr_err(body.span);
|
||||
body = self.mk_expr_err(
|
||||
body.span,
|
||||
self.dcx().span_delayed_bug(body.span, "recovered a closure body as a block"),
|
||||
);
|
||||
}
|
||||
|
||||
let body_span = body.span;
|
||||
|
@ -2485,7 +2488,7 @@ impl<'a> Parser<'a> {
|
|||
ExprKind::Binary(Spanned { span: binop_span, .. }, _, right)
|
||||
if let ExprKind::Block(_, None) = right.kind =>
|
||||
{
|
||||
this.dcx().emit_err(errors::IfExpressionMissingThenBlock {
|
||||
let guar = this.dcx().emit_err(errors::IfExpressionMissingThenBlock {
|
||||
if_span: lo,
|
||||
missing_then_block_sub:
|
||||
errors::IfExpressionMissingThenBlockSub::UnfinishedCondition(
|
||||
|
@ -2493,14 +2496,14 @@ impl<'a> Parser<'a> {
|
|||
),
|
||||
let_else_sub: None,
|
||||
});
|
||||
std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi()))
|
||||
std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi(), guar))
|
||||
}
|
||||
ExprKind::Block(_, None) => {
|
||||
this.dcx().emit_err(errors::IfExpressionMissingCondition {
|
||||
let guar = this.dcx().emit_err(errors::IfExpressionMissingCondition {
|
||||
if_span: lo.with_neighbor(cond.span).shrink_to_hi(),
|
||||
block_span: self.sess.source_map().start_point(cond_span),
|
||||
});
|
||||
std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi()))
|
||||
std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi(), guar))
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
|
@ -2520,14 +2523,14 @@ impl<'a> Parser<'a> {
|
|||
let let_else_sub = matches!(cond.kind, ExprKind::Let(..))
|
||||
.then(|| errors::IfExpressionLetSomeSub { if_span: lo.until(cond_span) });
|
||||
|
||||
self.dcx().emit_err(errors::IfExpressionMissingThenBlock {
|
||||
let guar = self.dcx().emit_err(errors::IfExpressionMissingThenBlock {
|
||||
if_span: lo,
|
||||
missing_then_block_sub: errors::IfExpressionMissingThenBlockSub::AddThenBlock(
|
||||
cond_span.shrink_to_hi(),
|
||||
),
|
||||
let_else_sub,
|
||||
});
|
||||
self.mk_block_err(cond_span.shrink_to_hi())
|
||||
self.mk_block_err(cond_span.shrink_to_hi(), guar)
|
||||
}
|
||||
} else {
|
||||
let attrs = self.parse_outer_attributes()?; // For recovery.
|
||||
|
@ -2797,9 +2800,10 @@ impl<'a> Parser<'a> {
|
|||
&& !matches!(self.token.kind, token::OpenDelim(Delimiter::Brace))
|
||||
&& self.may_recover()
|
||||
{
|
||||
self.dcx()
|
||||
let guar = self
|
||||
.dcx()
|
||||
.emit_err(errors::MissingExpressionInForLoop { span: expr.span.shrink_to_lo() });
|
||||
let err_expr = self.mk_expr(expr.span, ExprKind::Err);
|
||||
let err_expr = self.mk_expr(expr.span, ExprKind::Err(guar));
|
||||
let block = self.mk_block(thin_vec![], BlockCheckMode::Default, self.prev_token.span);
|
||||
return Ok(self.mk_expr(
|
||||
lo.to(self.prev_token.span),
|
||||
|
@ -2924,7 +2928,7 @@ impl<'a> Parser<'a> {
|
|||
attrs: Default::default(),
|
||||
pat: self.mk_pat(span, ast::PatKind::Err(guar)),
|
||||
guard: None,
|
||||
body: Some(self.mk_expr_err(span)),
|
||||
body: Some(self.mk_expr_err(span, guar)),
|
||||
span,
|
||||
id: DUMMY_NODE_ID,
|
||||
is_placeholder: false,
|
||||
|
@ -2959,7 +2963,7 @@ impl<'a> Parser<'a> {
|
|||
let err = |this: &Parser<'_>, stmts: Vec<ast::Stmt>| {
|
||||
let span = stmts[0].span.to(stmts[stmts.len() - 1].span);
|
||||
|
||||
this.dcx().emit_err(errors::MatchArmBodyWithoutBraces {
|
||||
let guar = this.dcx().emit_err(errors::MatchArmBodyWithoutBraces {
|
||||
statements: span,
|
||||
arrow: arrow_span,
|
||||
num_statements: stmts.len(),
|
||||
|
@ -2972,7 +2976,7 @@ impl<'a> Parser<'a> {
|
|||
errors::MatchArmBodyWithoutBracesSugg::UseComma { semicolon: semi_sp }
|
||||
},
|
||||
});
|
||||
this.mk_expr_err(span)
|
||||
this.mk_expr_err(span, guar)
|
||||
};
|
||||
// We might have either a `,` -> `;` typo, or a block without braces. We need
|
||||
// a more subtle parsing strategy.
|
||||
|
@ -3433,14 +3437,20 @@ impl<'a> Parser<'a> {
|
|||
pth: ast::Path,
|
||||
recover: bool,
|
||||
close_delim: Delimiter,
|
||||
) -> PResult<'a, (ThinVec<ExprField>, ast::StructRest, bool)> {
|
||||
) -> PResult<
|
||||
'a,
|
||||
(
|
||||
ThinVec<ExprField>,
|
||||
ast::StructRest,
|
||||
Option<ErrorGuaranteed>, /* async blocks are forbidden in Rust 2015 */
|
||||
),
|
||||
> {
|
||||
let mut fields = ThinVec::new();
|
||||
let mut base = ast::StructRest::None;
|
||||
let mut recover_async = false;
|
||||
let mut recovered_async = None;
|
||||
let in_if_guard = self.restrictions.contains(Restrictions::IN_IF_GUARD);
|
||||
|
||||
let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| {
|
||||
recover_async = true;
|
||||
let async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| {
|
||||
errors::AsyncBlockIn2015 { span }.add_to_diagnostic(e);
|
||||
errors::HelpUseLatestEdition::new().add_to_diagnostic(e);
|
||||
};
|
||||
|
@ -3465,9 +3475,34 @@ impl<'a> Parser<'a> {
|
|||
break;
|
||||
}
|
||||
|
||||
let recovery_field = self.find_struct_error_after_field_looking_code();
|
||||
// Peek the field's ident before parsing its expr in order to emit better diagnostics.
|
||||
let peek = self
|
||||
.token
|
||||
.ident()
|
||||
.filter(|(ident, is_raw)| {
|
||||
(!ident.is_reserved() || matches!(is_raw, IdentIsRaw::Yes))
|
||||
&& self.look_ahead(1, |tok| *tok == token::Colon)
|
||||
})
|
||||
.map(|(ident, _)| ident);
|
||||
|
||||
// We still want a field even if its expr didn't parse.
|
||||
let field_ident = |this: &Self, guar: ErrorGuaranteed| {
|
||||
peek.map(|ident| {
|
||||
let span = ident.span;
|
||||
ExprField {
|
||||
ident,
|
||||
span,
|
||||
expr: this.mk_expr_err(span, guar),
|
||||
is_shorthand: false,
|
||||
attrs: AttrVec::new(),
|
||||
id: DUMMY_NODE_ID,
|
||||
is_placeholder: false,
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let parsed_field = match self.parse_expr_field() {
|
||||
Ok(f) => Some(f),
|
||||
Ok(f) => Ok(f),
|
||||
Err(mut e) => {
|
||||
if pth == kw::Async {
|
||||
async_block_err(&mut e, pth.span);
|
||||
|
@ -3499,7 +3534,10 @@ impl<'a> Parser<'a> {
|
|||
return Err(e);
|
||||
}
|
||||
|
||||
e.emit();
|
||||
let guar = e.emit();
|
||||
if pth == kw::Async {
|
||||
recovered_async = Some(guar);
|
||||
}
|
||||
|
||||
// If the next token is a comma, then try to parse
|
||||
// what comes next as additional fields, rather than
|
||||
|
@ -3511,18 +3549,20 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
None
|
||||
Err(guar)
|
||||
}
|
||||
};
|
||||
|
||||
let is_shorthand = parsed_field.as_ref().is_some_and(|f| f.is_shorthand);
|
||||
let is_shorthand = parsed_field.as_ref().is_ok_and(|f| f.is_shorthand);
|
||||
// A shorthand field can be turned into a full field with `:`.
|
||||
// We should point this out.
|
||||
self.check_or_expected(!is_shorthand, TokenType::Token(token::Colon));
|
||||
|
||||
match self.expect_one_of(&[token::Comma], &[token::CloseDelim(close_delim)]) {
|
||||
Ok(_) => {
|
||||
if let Some(f) = parsed_field.or(recovery_field) {
|
||||
if let Some(f) =
|
||||
parsed_field.or_else(|guar| field_ident(self, guar).ok_or(guar)).ok()
|
||||
{
|
||||
// Only include the field if there's no parse error for the field name.
|
||||
fields.push(f);
|
||||
}
|
||||
|
@ -3532,8 +3572,7 @@ impl<'a> Parser<'a> {
|
|||
async_block_err(&mut e, pth.span);
|
||||
} else {
|
||||
e.span_label(pth.span, "while parsing this struct");
|
||||
if let Some(f) = recovery_field {
|
||||
fields.push(f);
|
||||
if peek.is_some() {
|
||||
e.span_suggestion(
|
||||
self.prev_token.span.shrink_to_hi(),
|
||||
"try adding a comma",
|
||||
|
@ -3545,13 +3584,18 @@ impl<'a> Parser<'a> {
|
|||
if !recover {
|
||||
return Err(e);
|
||||
}
|
||||
e.emit();
|
||||
let guar = e.emit();
|
||||
if pth == kw::Async {
|
||||
recovered_async = Some(guar);
|
||||
} else if let Some(f) = field_ident(self, guar) {
|
||||
fields.push(f);
|
||||
}
|
||||
self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
|
||||
self.eat(&token::Comma);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((fields, base, recover_async))
|
||||
Ok((fields, base, recovered_async))
|
||||
}
|
||||
|
||||
/// Precondition: already parsed the '{'.
|
||||
|
@ -3562,39 +3606,18 @@ impl<'a> Parser<'a> {
|
|||
recover: bool,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
let lo = pth.span;
|
||||
let (fields, base, recover_async) =
|
||||
let (fields, base, recovered_async) =
|
||||
self.parse_struct_fields(pth.clone(), recover, Delimiter::Brace)?;
|
||||
let span = lo.to(self.token.span);
|
||||
self.expect(&token::CloseDelim(Delimiter::Brace))?;
|
||||
let expr = if recover_async {
|
||||
ExprKind::Err
|
||||
let expr = if let Some(guar) = recovered_async {
|
||||
ExprKind::Err(guar)
|
||||
} else {
|
||||
ExprKind::Struct(P(ast::StructExpr { qself, path: pth, fields, rest: base }))
|
||||
};
|
||||
Ok(self.mk_expr(span, expr))
|
||||
}
|
||||
|
||||
/// Use in case of error after field-looking code: `S { foo: () with a }`.
|
||||
fn find_struct_error_after_field_looking_code(&self) -> Option<ExprField> {
|
||||
match self.token.ident() {
|
||||
Some((ident, is_raw))
|
||||
if (matches!(is_raw, IdentIsRaw::Yes) || !ident.is_reserved())
|
||||
&& self.look_ahead(1, |t| *t == token::Colon) =>
|
||||
{
|
||||
Some(ast::ExprField {
|
||||
ident,
|
||||
span: self.token.span,
|
||||
expr: self.mk_expr_err(self.token.span),
|
||||
is_shorthand: false,
|
||||
attrs: AttrVec::new(),
|
||||
id: DUMMY_NODE_ID,
|
||||
is_placeholder: false,
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn recover_struct_comma_after_dotdot(&mut self, span: Span) {
|
||||
if self.token != token::Comma {
|
||||
return;
|
||||
|
@ -3718,8 +3741,8 @@ impl<'a> Parser<'a> {
|
|||
limits: RangeLimits,
|
||||
) -> ExprKind {
|
||||
if end.is_none() && limits == RangeLimits::Closed {
|
||||
self.inclusive_range_with_incorrect_end();
|
||||
ExprKind::Err
|
||||
let guar = self.inclusive_range_with_incorrect_end();
|
||||
ExprKind::Err(guar)
|
||||
} else {
|
||||
ExprKind::Range(start, end, limits)
|
||||
}
|
||||
|
@ -3756,8 +3779,8 @@ impl<'a> Parser<'a> {
|
|||
self.mk_expr_with_attrs(span, kind, AttrVec::new())
|
||||
}
|
||||
|
||||
pub(super) fn mk_expr_err(&self, span: Span) -> P<Expr> {
|
||||
self.mk_expr(span, ExprKind::Err)
|
||||
pub(super) fn mk_expr_err(&self, span: Span, guar: ErrorGuaranteed) -> P<Expr> {
|
||||
self.mk_expr(span, ExprKind::Err(guar))
|
||||
}
|
||||
|
||||
/// Create expression span ensuring the span of the parent node
|
||||
|
@ -3949,7 +3972,7 @@ impl MutVisitor for CondChecker<'_> {
|
|||
| ExprKind::Become(_)
|
||||
| ExprKind::IncludedBytes(_)
|
||||
| ExprKind::FormatArgs(_)
|
||||
| ExprKind::Err
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::Dummy => {
|
||||
// These would forbid any let expressions they contain already.
|
||||
}
|
||||
|
|
|
@ -2328,11 +2328,11 @@ impl<'a> Parser<'a> {
|
|||
let _ = self.parse_expr()?;
|
||||
self.expect_semi()?; // `;`
|
||||
let span = eq_sp.to(self.prev_token.span);
|
||||
self.dcx().emit_err(errors::FunctionBodyEqualsExpr {
|
||||
let guar = self.dcx().emit_err(errors::FunctionBodyEqualsExpr {
|
||||
span,
|
||||
sugg: errors::FunctionBodyEqualsExprSugg { eq: eq_sp, semi: self.prev_token.span },
|
||||
});
|
||||
(AttrVec::new(), Some(self.mk_block_err(span)))
|
||||
(AttrVec::new(), Some(self.mk_block_err(span, guar)))
|
||||
} else {
|
||||
let expected = if req_body {
|
||||
&[token::OpenDelim(Delimiter::Brace)][..]
|
||||
|
|
|
@ -566,7 +566,7 @@ impl<'a> Parser<'a> {
|
|||
match self.parse_literal_maybe_minus() {
|
||||
Ok(begin) => {
|
||||
let begin = match self.maybe_recover_trailing_expr(begin.span, false) {
|
||||
Some(_) => self.mk_expr_err(begin.span),
|
||||
Some(guar) => self.mk_expr_err(begin.span, guar),
|
||||
None => begin,
|
||||
};
|
||||
|
||||
|
@ -719,7 +719,7 @@ impl<'a> Parser<'a> {
|
|||
self.parse_pat_range_begin_with(begin.clone(), form)
|
||||
}
|
||||
// recover ranges with parentheses around the `(start)..`
|
||||
PatKind::Err(_)
|
||||
PatKind::Err(guar)
|
||||
if self.may_recover()
|
||||
&& let Some(form) = self.parse_range_end() =>
|
||||
{
|
||||
|
@ -731,7 +731,7 @@ impl<'a> Parser<'a> {
|
|||
},
|
||||
});
|
||||
|
||||
self.parse_pat_range_begin_with(self.mk_expr(pat.span, ExprKind::Err), form)
|
||||
self.parse_pat_range_begin_with(self.mk_expr_err(pat.span, *guar), form)
|
||||
}
|
||||
|
||||
// (pat) with optional parentheses
|
||||
|
@ -886,7 +886,7 @@ impl<'a> Parser<'a> {
|
|||
Ok(PatKind::Range(Some(begin), end, re))
|
||||
}
|
||||
|
||||
pub(super) fn inclusive_range_with_incorrect_end(&mut self) {
|
||||
pub(super) fn inclusive_range_with_incorrect_end(&mut self) -> ErrorGuaranteed {
|
||||
let tok = &self.token;
|
||||
let span = self.prev_token.span;
|
||||
// If the user typed "..==" instead of "..=", we want to give them
|
||||
|
@ -905,15 +905,13 @@ impl<'a> Parser<'a> {
|
|||
let _ = self.parse_pat_range_end().map_err(|e| e.cancel());
|
||||
}
|
||||
|
||||
self.dcx().emit_err(InclusiveRangeExtraEquals { span: span_with_eq });
|
||||
self.dcx().emit_err(InclusiveRangeExtraEquals { span: span_with_eq })
|
||||
}
|
||||
token::Gt if no_space => {
|
||||
let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi();
|
||||
self.dcx().emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span, after_pat });
|
||||
}
|
||||
_ => {
|
||||
self.dcx().emit_err(InclusiveRangeNoEnd { span });
|
||||
self.dcx().emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span, after_pat })
|
||||
}
|
||||
_ => self.dcx().emit_err(InclusiveRangeNoEnd { span }),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -987,7 +985,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
Ok(match recovered {
|
||||
Some(_) => self.mk_expr_err(bound.span),
|
||||
Some(guar) => self.mk_expr_err(bound.span, guar),
|
||||
None => bound,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Stmt};
|
|||
use rustc_ast::{StmtKind, DUMMY_NODE_ID};
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::{BytePos, Span};
|
||||
use rustc_span::{BytePos, ErrorGuaranteed, Span};
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::mem;
|
||||
|
@ -610,9 +610,9 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
err.emit();
|
||||
let guar = err.emit();
|
||||
self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
|
||||
Some(self.mk_stmt_err(self.token.span))
|
||||
Some(self.mk_stmt_err(self.token.span, guar))
|
||||
}
|
||||
Ok(stmt) => stmt,
|
||||
Err(err) => return Err(err),
|
||||
|
@ -651,10 +651,10 @@ impl<'a> Parser<'a> {
|
|||
.contains(&self.token.kind) =>
|
||||
{
|
||||
// The user has written `#[attr] expr` which is unsupported. (#106020)
|
||||
self.attr_on_non_tail_expr(&expr);
|
||||
let guar = self.attr_on_non_tail_expr(&expr);
|
||||
// We already emitted an error, so don't emit another type error
|
||||
let sp = expr.span.to(self.prev_token.span);
|
||||
*expr = self.mk_expr_err(sp);
|
||||
*expr = self.mk_expr_err(sp, guar);
|
||||
}
|
||||
|
||||
// Expression without semicolon.
|
||||
|
@ -666,10 +666,18 @@ impl<'a> Parser<'a> {
|
|||
let expect_result =
|
||||
self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]);
|
||||
|
||||
// Try to both emit a better diagnostic, and avoid further errors by replacing
|
||||
// the `expr` with `ExprKind::Err`.
|
||||
let replace_with_err = 'break_recover: {
|
||||
match expect_result {
|
||||
// Recover from parser, skip type error to avoid extra errors.
|
||||
Ok(Recovered::Yes) => true,
|
||||
Ok(Recovered::No) => None,
|
||||
Ok(Recovered::Yes) => {
|
||||
// Skip type error to avoid extra errors.
|
||||
let guar = self
|
||||
.dcx()
|
||||
.span_delayed_bug(self.prev_token.span, "expected `;` or `}`");
|
||||
Some(guar)
|
||||
}
|
||||
Err(e) => {
|
||||
if self.recover_colon_as_semi() {
|
||||
// recover_colon_as_semi has already emitted a nicer error.
|
||||
|
@ -677,7 +685,7 @@ impl<'a> Parser<'a> {
|
|||
add_semi_to_stmt = true;
|
||||
eat_semi = false;
|
||||
|
||||
break 'break_recover false;
|
||||
break 'break_recover None;
|
||||
}
|
||||
|
||||
match &expr.kind {
|
||||
|
@ -705,13 +713,13 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
match self.parse_expr_labeled(label, false) {
|
||||
Ok(labeled_expr) => {
|
||||
e.delay_as_bug();
|
||||
e.cancel();
|
||||
self.dcx().emit_err(MalformedLoopLabel {
|
||||
span: label.ident.span,
|
||||
correct_label: label.ident,
|
||||
});
|
||||
*expr = labeled_expr;
|
||||
break 'break_recover false;
|
||||
break 'break_recover None;
|
||||
}
|
||||
Err(err) => {
|
||||
err.cancel();
|
||||
|
@ -723,26 +731,26 @@ impl<'a> Parser<'a> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
if let Err(e) =
|
||||
self.check_mistyped_turbofish_with_multiple_type_params(e, expr)
|
||||
{
|
||||
if recover.no() {
|
||||
return Err(e);
|
||||
}
|
||||
e.emit();
|
||||
self.recover_stmt();
|
||||
}
|
||||
let res =
|
||||
self.check_mistyped_turbofish_with_multiple_type_params(e, expr);
|
||||
|
||||
true
|
||||
Some(if recover.no() {
|
||||
res?
|
||||
} else {
|
||||
res.unwrap_or_else(|e| {
|
||||
let guar = e.emit();
|
||||
self.recover_stmt();
|
||||
guar
|
||||
})
|
||||
})
|
||||
}
|
||||
Ok(Recovered::No) => false,
|
||||
}
|
||||
};
|
||||
|
||||
if replace_with_err {
|
||||
if let Some(guar) = replace_with_err {
|
||||
// We already emitted an error, so don't emit another type error
|
||||
let sp = expr.span.to(self.prev_token.span);
|
||||
*expr = self.mk_expr_err(sp);
|
||||
*expr = self.mk_expr_err(sp, guar);
|
||||
}
|
||||
}
|
||||
StmtKind::Expr(_) | StmtKind::MacCall(_) => {}
|
||||
|
@ -791,11 +799,11 @@ impl<'a> Parser<'a> {
|
|||
Stmt { id: DUMMY_NODE_ID, kind, span }
|
||||
}
|
||||
|
||||
pub(super) fn mk_stmt_err(&self, span: Span) -> Stmt {
|
||||
self.mk_stmt(span, StmtKind::Expr(self.mk_expr_err(span)))
|
||||
pub(super) fn mk_stmt_err(&self, span: Span, guar: ErrorGuaranteed) -> Stmt {
|
||||
self.mk_stmt(span, StmtKind::Expr(self.mk_expr_err(span, guar)))
|
||||
}
|
||||
|
||||
pub(super) fn mk_block_err(&self, span: Span) -> P<Block> {
|
||||
self.mk_block(thin_vec![self.mk_stmt_err(span)], BlockCheckMode::Default, span)
|
||||
pub(super) fn mk_block_err(&self, span: Span, guar: ErrorGuaranteed) -> P<Block> {
|
||||
self.mk_block(thin_vec![self.mk_stmt_err(span, guar)], BlockCheckMode::Default, span)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue