Rollup merge of #127407 - estebank:parser-suggestions, r=oli-obk
Make parse error suggestions verbose and fix spans Go over all structured parser suggestions and make them verbose style. When suggesting to add or remove delimiters, turn them into multiple suggestion parts.
This commit is contained in:
@@ -3,8 +3,8 @@ use super::{
|
||||
BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenType,
|
||||
};
|
||||
use crate::errors::{
|
||||
AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, BadQPathStage2, BadTypePlus,
|
||||
BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained,
|
||||
AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, AwaitSuggestion,
|
||||
BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained,
|
||||
ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces,
|
||||
ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType,
|
||||
DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
|
||||
@@ -566,7 +566,10 @@ impl<'a> Parser<'a> {
|
||||
&& expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Eq)))
|
||||
{
|
||||
// Likely typo: `=` → `==` in let expr or enum item
|
||||
return Err(self.dcx().create_err(UseEqInstead { span: self.token.span }));
|
||||
return Err(self.dcx().create_err(UseEqInstead {
|
||||
span: self.token.span,
|
||||
suggestion: self.token.span.with_lo(self.token.span.lo() + BytePos(1)),
|
||||
}));
|
||||
}
|
||||
|
||||
if self.token.is_keyword(kw::Move) && self.prev_token.is_keyword(kw::Async) {
|
||||
@@ -1151,7 +1154,7 @@ impl<'a> Parser<'a> {
|
||||
// Eat from where we started until the end token so that parsing can continue
|
||||
// as if we didn't have those extra angle brackets.
|
||||
self.eat_to_tokens(end);
|
||||
let span = lo.until(self.token.span);
|
||||
let span = lo.to(self.prev_token.span);
|
||||
|
||||
let num_extra_brackets = number_of_gt + number_of_shr * 2;
|
||||
return Some(self.dcx().emit_err(UnmatchedAngleBrackets { span, num_extra_brackets }));
|
||||
@@ -1539,7 +1542,10 @@ impl<'a> Parser<'a> {
|
||||
|
||||
pub(super) fn maybe_report_ambiguous_plus(&mut self, impl_dyn_multi: bool, ty: &Ty) {
|
||||
if impl_dyn_multi {
|
||||
self.dcx().emit_err(AmbiguousPlus { sum_ty: pprust::ty_to_string(ty), span: ty.span });
|
||||
self.dcx().emit_err(AmbiguousPlus {
|
||||
span: ty.span,
|
||||
suggestion: AddParen { lo: ty.span.shrink_to_lo(), hi: ty.span.shrink_to_hi() },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1604,25 +1610,14 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
self.bump(); // `+`
|
||||
let bounds = self.parse_generic_bounds()?;
|
||||
let _bounds = self.parse_generic_bounds()?;
|
||||
let sum_span = ty.span.to(self.prev_token.span);
|
||||
|
||||
let sub = match &ty.kind {
|
||||
TyKind::Ref(lifetime, mut_ty) => {
|
||||
let sum_with_parens = pprust::to_string(|s| {
|
||||
s.s.word("&");
|
||||
s.print_opt_lifetime(lifetime);
|
||||
s.print_mutability(mut_ty.mutbl, false);
|
||||
s.popen();
|
||||
s.print_type(&mut_ty.ty);
|
||||
if !bounds.is_empty() {
|
||||
s.word(" + ");
|
||||
s.print_type_bounds(&bounds);
|
||||
}
|
||||
s.pclose()
|
||||
});
|
||||
|
||||
BadTypePlusSub::AddParen { sum_with_parens, span: sum_span }
|
||||
TyKind::Ref(_lifetime, mut_ty) => {
|
||||
let lo = mut_ty.ty.span.shrink_to_lo();
|
||||
let hi = self.prev_token.span.shrink_to_hi();
|
||||
BadTypePlusSub::AddParen { suggestion: AddParen { lo, hi } }
|
||||
}
|
||||
TyKind::Ptr(..) | TyKind::BareFn(..) => BadTypePlusSub::ForgotParen { span: sum_span },
|
||||
_ => BadTypePlusSub::ExpectPath { span: sum_span },
|
||||
@@ -1964,18 +1959,14 @@ impl<'a> Parser<'a> {
|
||||
is_question: bool,
|
||||
) -> (Span, ErrorGuaranteed) {
|
||||
let span = lo.to(hi);
|
||||
let applicability = match expr.kind {
|
||||
ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await <expr>?`
|
||||
_ => Applicability::MachineApplicable,
|
||||
};
|
||||
|
||||
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 { "" },
|
||||
suggestion: AwaitSuggestion {
|
||||
removal: lo.until(expr.span),
|
||||
dot_await: expr.span.shrink_to_hi(),
|
||||
question_mark: if is_question { "?" } else { "" },
|
||||
},
|
||||
});
|
||||
|
||||
(span, guar)
|
||||
}
|
||||
|
||||
|
||||
@@ -714,7 +714,7 @@ impl<'a> Parser<'a> {
|
||||
type_err.cancel();
|
||||
self.dcx().emit_err(errors::MalformedLoopLabel {
|
||||
span: label.ident.span,
|
||||
correct_label: label.ident,
|
||||
suggestion: label.ident.span.shrink_to_lo(),
|
||||
});
|
||||
return Ok(expr);
|
||||
}
|
||||
@@ -856,7 +856,7 @@ impl<'a> Parser<'a> {
|
||||
let hi = self.interpolated_or_expr_span(&expr);
|
||||
let span = lo.to(hi);
|
||||
if let Some(lt) = lifetime {
|
||||
self.error_remove_borrow_lifetime(span, lt.ident.span);
|
||||
self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span));
|
||||
}
|
||||
Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))
|
||||
}
|
||||
@@ -1653,6 +1653,7 @@ impl<'a> Parser<'a> {
|
||||
let lo = label_.ident.span;
|
||||
let label = Some(label_);
|
||||
let ate_colon = self.eat(&token::Colon);
|
||||
let tok_sp = self.token.span;
|
||||
let expr = if self.eat_keyword(kw::While) {
|
||||
self.parse_expr_while(label, lo)
|
||||
} else if self.eat_keyword(kw::For) {
|
||||
@@ -1747,7 +1748,7 @@ impl<'a> Parser<'a> {
|
||||
self.dcx().emit_err(errors::RequireColonAfterLabeledExpression {
|
||||
span: expr.span,
|
||||
label: lo,
|
||||
label_end: lo.shrink_to_hi(),
|
||||
label_end: lo.between(tok_sp),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2106,7 +2107,7 @@ impl<'a> Parser<'a> {
|
||||
self.bump();
|
||||
self.dcx().emit_err(errors::FloatLiteralRequiresIntegerPart {
|
||||
span: token.span,
|
||||
correct: pprust::token_to_string(token).into_owned(),
|
||||
suggestion: token.span.shrink_to_lo(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2741,7 +2742,7 @@ impl<'a> Parser<'a> {
|
||||
if !attrs.is_empty()
|
||||
&& let [x0 @ xn] | [x0, .., xn] = &*attrs.take_for_recovery(self.psess)
|
||||
{
|
||||
let attributes = x0.span.to(xn.span);
|
||||
let attributes = x0.span.until(branch_span);
|
||||
let last = xn.span;
|
||||
let ctx = if is_ctx_else { "else" } else { "if" };
|
||||
self.dcx().emit_err(errors::OuterAttributeNotAllowedOnIfElse {
|
||||
|
||||
@@ -2241,9 +2241,13 @@ impl<'a> Parser<'a> {
|
||||
let kw_token = self.token.clone();
|
||||
let kw_str = pprust::token_to_string(&kw_token);
|
||||
let item = self.parse_item(ForceCollect::No)?;
|
||||
let mut item = item.unwrap().span;
|
||||
if self.token == token::Comma {
|
||||
item = item.to(self.token.span);
|
||||
}
|
||||
self.dcx().emit_err(errors::NestedAdt {
|
||||
span: kw_token.span,
|
||||
item: item.unwrap().span,
|
||||
item,
|
||||
kw_str,
|
||||
keyword: keyword.as_str(),
|
||||
});
|
||||
|
||||
@@ -4,11 +4,11 @@ use crate::errors::{
|
||||
DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
|
||||
ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax,
|
||||
InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
|
||||
PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder,
|
||||
TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed,
|
||||
UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat,
|
||||
UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam,
|
||||
UnexpectedVertVertInPattern,
|
||||
ParenRangeSuggestion, PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern,
|
||||
SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
|
||||
TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern,
|
||||
UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
|
||||
UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens,
|
||||
};
|
||||
use crate::parser::expr::{could_be_unclosed_char_literal, LhsExpr};
|
||||
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
||||
@@ -24,7 +24,7 @@ use rustc_errors::{Applicability, Diag, PResult};
|
||||
use rustc_session::errors::ExprParenthesesNeeded;
|
||||
use rustc_span::source_map::{respan, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
use rustc_span::{BytePos, ErrorGuaranteed, Span};
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
|
||||
#[derive(PartialEq, Copy, Clone)]
|
||||
@@ -236,11 +236,15 @@ impl<'a> Parser<'a> {
|
||||
|
||||
if let PatKind::Or(pats) = &pat.kind {
|
||||
let span = pat.span;
|
||||
let pat = pprust::pat_to_string(&pat);
|
||||
let sub = if pats.len() == 1 {
|
||||
Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { span, pat })
|
||||
Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert {
|
||||
span: span.with_hi(span.lo() + BytePos(1)),
|
||||
})
|
||||
} else {
|
||||
Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { span, pat })
|
||||
Some(TopLevelOrPatternNotAllowedSugg::WrapInParens {
|
||||
span,
|
||||
suggestion: WrapInParens { lo: span.shrink_to_lo(), hi: span.shrink_to_hi() },
|
||||
})
|
||||
};
|
||||
|
||||
let err = self.dcx().create_err(match syntax_loc {
|
||||
@@ -599,7 +603,10 @@ impl<'a> Parser<'a> {
|
||||
self.bump(); // `...`
|
||||
|
||||
// The user probably mistook `...` for a rest pattern `..`.
|
||||
self.dcx().emit_err(DotDotDotRestPattern { span: lo });
|
||||
self.dcx().emit_err(DotDotDotRestPattern {
|
||||
span: lo,
|
||||
suggestion: lo.with_lo(lo.hi() - BytePos(1)),
|
||||
});
|
||||
PatKind::Rest
|
||||
}
|
||||
|
||||
@@ -664,8 +671,13 @@ impl<'a> Parser<'a> {
|
||||
_ => return,
|
||||
}
|
||||
|
||||
self.dcx()
|
||||
.emit_err(AmbiguousRangePattern { span: pat.span, pat: pprust::pat_to_string(pat) });
|
||||
self.dcx().emit_err(AmbiguousRangePattern {
|
||||
span: pat.span,
|
||||
suggestion: ParenRangeSuggestion {
|
||||
lo: pat.span.shrink_to_lo(),
|
||||
hi: pat.span.shrink_to_hi(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/// Parse `&pat` / `&mut pat`.
|
||||
@@ -674,8 +686,11 @@ impl<'a> Parser<'a> {
|
||||
if let token::Lifetime(name) = self.token.kind {
|
||||
self.bump(); // `'a`
|
||||
|
||||
self.dcx()
|
||||
.emit_err(UnexpectedLifetimeInPattern { span: self.prev_token.span, symbol: name });
|
||||
self.dcx().emit_err(UnexpectedLifetimeInPattern {
|
||||
span: self.prev_token.span,
|
||||
symbol: name,
|
||||
suggestion: self.prev_token.span.until(self.token.span),
|
||||
});
|
||||
}
|
||||
|
||||
let mutbl = self.parse_mutability();
|
||||
@@ -913,10 +928,13 @@ impl<'a> Parser<'a> {
|
||||
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();
|
||||
let after_pat = span.with_hi(span.hi() - 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(InclusiveRangeNoEnd {
|
||||
span,
|
||||
suggestion: span.with_lo(span.hi() - BytePos(1)),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -258,6 +258,7 @@ impl<'a> Parser<'a> {
|
||||
self.bump(); // bump past the colon
|
||||
self.dcx().emit_err(PathSingleColon {
|
||||
span: self.prev_token.span,
|
||||
suggestion: self.prev_token.span.shrink_to_hi(),
|
||||
type_ascription: self
|
||||
.psess
|
||||
.unstable_features
|
||||
@@ -329,6 +330,7 @@ impl<'a> Parser<'a> {
|
||||
err.cancel();
|
||||
err = self.dcx().create_err(PathSingleColon {
|
||||
span: self.token.span,
|
||||
suggestion: self.prev_token.span.shrink_to_hi(),
|
||||
type_ascription: self
|
||||
.psess
|
||||
.unstable_features
|
||||
|
||||
@@ -430,8 +430,10 @@ impl<'a> Parser<'a> {
|
||||
let eq_consumed = match self.token.kind {
|
||||
token::BinOpEq(..) => {
|
||||
// Recover `let x <op>= 1` as `let x = 1`
|
||||
self.dcx()
|
||||
.emit_err(errors::CompoundAssignmentExpressionInLet { span: self.token.span });
|
||||
self.dcx().emit_err(errors::CompoundAssignmentExpressionInLet {
|
||||
span: self.token.span,
|
||||
suggestion: self.token.span.with_hi(self.token.span.lo() + BytePos(1)),
|
||||
});
|
||||
self.bump();
|
||||
true
|
||||
}
|
||||
@@ -717,7 +719,7 @@ impl<'a> Parser<'a> {
|
||||
e.cancel();
|
||||
self.dcx().emit_err(MalformedLoopLabel {
|
||||
span: label.ident.span,
|
||||
correct_label: label.ident,
|
||||
suggestion: label.ident.span.shrink_to_lo(),
|
||||
});
|
||||
*expr = labeled_expr;
|
||||
break 'break_recover None;
|
||||
|
||||
@@ -209,6 +209,7 @@ impl<'a> Parser<'a> {
|
||||
recover_qpath: RecoverQPath,
|
||||
recover_return_sign: RecoverReturnSign,
|
||||
) -> PResult<'a, FnRetTy> {
|
||||
let lo = self.prev_token.span;
|
||||
Ok(if self.eat(&token::RArrow) {
|
||||
// FIXME(Centril): Can we unconditionally `allow_plus`?
|
||||
let ty = self.parse_ty_common(
|
||||
@@ -224,7 +225,10 @@ impl<'a> Parser<'a> {
|
||||
// Don't `eat` to prevent `=>` from being added as an expected token which isn't
|
||||
// actually expected and could only confuse users
|
||||
self.bump();
|
||||
self.dcx().emit_err(ReturnTypesUseThinArrow { span: self.prev_token.span });
|
||||
self.dcx().emit_err(ReturnTypesUseThinArrow {
|
||||
span: self.prev_token.span,
|
||||
suggestion: lo.between(self.token.span),
|
||||
});
|
||||
let ty = self.parse_ty_common(
|
||||
allow_plus,
|
||||
AllowCVariadic::No,
|
||||
@@ -794,8 +798,11 @@ impl<'a> Parser<'a> {
|
||||
{
|
||||
if self.token.is_keyword(kw::Dyn) {
|
||||
// Account for `&dyn Trait + dyn Other`.
|
||||
self.dcx().emit_err(InvalidDynKeyword { span: self.token.span });
|
||||
self.bump();
|
||||
self.dcx().emit_err(InvalidDynKeyword {
|
||||
span: self.prev_token.span,
|
||||
suggestion: self.prev_token.span.until(self.token.span),
|
||||
});
|
||||
}
|
||||
bounds.push(self.parse_generic_bound()?);
|
||||
if allow_plus == AllowPlus::No || !self.eat_plus() {
|
||||
@@ -861,7 +868,7 @@ impl<'a> Parser<'a> {
|
||||
if has_parens {
|
||||
// FIXME(Centril): Consider not erroring here and accepting `('lt)` instead,
|
||||
// possibly introducing `GenericBound::Paren(P<GenericBound>)`?
|
||||
self.recover_paren_lifetime(lo, lt.ident.span)?;
|
||||
self.recover_paren_lifetime(lo)?;
|
||||
}
|
||||
Ok(bound)
|
||||
}
|
||||
@@ -909,16 +916,12 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
/// Recover on `('lifetime)` with `(` already eaten.
|
||||
fn recover_paren_lifetime(&mut self, lo: Span, lt_span: Span) -> PResult<'a, ()> {
|
||||
fn recover_paren_lifetime(&mut self, lo: Span) -> PResult<'a, ()> {
|
||||
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
|
||||
let span = lo.to(self.prev_token.span);
|
||||
let (sugg, snippet) = if let Ok(snippet) = self.span_to_snippet(lt_span) {
|
||||
(Some(span), snippet)
|
||||
} else {
|
||||
(None, String::new())
|
||||
};
|
||||
let sugg = errors::RemoveParens { lo, hi: self.prev_token.span };
|
||||
|
||||
self.dcx().emit_err(errors::ParenthesizedLifetime { span, sugg, snippet });
|
||||
self.dcx().emit_err(errors::ParenthesizedLifetime { span, sugg });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user