Auto merge of #103431 - Dylan-DPC:rollup-oozfo89, r=Dylan-DPC
Rollup of 6 pull requests Successful merges: - #101293 (Recover when unclosed char literal is parsed as a lifetime in some positions) - #101908 (Suggest let for assignment, and some code refactor) - #103192 (rustdoc: Eliminate uses of `EarlyDocLinkResolver::all_traits`) - #103226 (Check `needs_infer` before `needs_drop` during HIR generator analysis) - #103249 (resolve: Revert "Set effective visibilities for imports more precisely") - #103305 (Move some tests to more reasonable places) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
9be2f35a4c
36 changed files with 542 additions and 265 deletions
|
@ -42,8 +42,10 @@ use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty
|
|||
use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
|
||||
use rustc_ast::{ClosureBinder, StmtKind};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::IntoDiagnostic;
|
||||
use rustc_errors::{Applicability, Diagnostic, PResult};
|
||||
use rustc_errors::{
|
||||
Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult,
|
||||
StashKey,
|
||||
};
|
||||
use rustc_session::errors::ExprParenthesesNeeded;
|
||||
use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
|
||||
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||
|
@ -1513,11 +1515,11 @@ impl<'a> Parser<'a> {
|
|||
/// Parse `'label: $expr`. The label is already parsed.
|
||||
fn parse_labeled_expr(
|
||||
&mut self,
|
||||
label: Label,
|
||||
label_: Label,
|
||||
mut consume_colon: bool,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
let lo = label.ident.span;
|
||||
let label = Some(label);
|
||||
let lo = label_.ident.span;
|
||||
let label = Some(label_);
|
||||
let ate_colon = self.eat(&token::Colon);
|
||||
let expr = if self.eat_keyword(kw::While) {
|
||||
self.parse_while_expr(label, lo)
|
||||
|
@ -1529,6 +1531,19 @@ impl<'a> Parser<'a> {
|
|||
|| self.token.is_whole_block()
|
||||
{
|
||||
self.parse_block_expr(label, lo, BlockCheckMode::Default)
|
||||
} else if !ate_colon
|
||||
&& (matches!(self.token.kind, token::CloseDelim(_) | token::Comma)
|
||||
|| self.token.is_op())
|
||||
{
|
||||
let lit = self.recover_unclosed_char(label_.ident, |self_| {
|
||||
self_.sess.create_err(UnexpectedTokenAfterLabel {
|
||||
span: self_.token.span,
|
||||
remove_label: None,
|
||||
enclose_in_block: None,
|
||||
})
|
||||
});
|
||||
consume_colon = false;
|
||||
Ok(self.mk_expr(lo, ExprKind::Lit(lit)))
|
||||
} else if !ate_colon
|
||||
&& (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
|
||||
{
|
||||
|
@ -1603,6 +1618,39 @@ impl<'a> Parser<'a> {
|
|||
Ok(expr)
|
||||
}
|
||||
|
||||
/// Emit an error when a char is parsed as a lifetime because of a missing quote
|
||||
pub(super) fn recover_unclosed_char(
|
||||
&mut self,
|
||||
lifetime: Ident,
|
||||
err: impl FnOnce(&mut Self) -> DiagnosticBuilder<'a, ErrorGuaranteed>,
|
||||
) -> ast::Lit {
|
||||
if let Some(mut diag) =
|
||||
self.sess.span_diagnostic.steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar)
|
||||
{
|
||||
diag.span_suggestion_verbose(
|
||||
lifetime.span.shrink_to_hi(),
|
||||
"add `'` to close the char literal",
|
||||
"'",
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
} else {
|
||||
err(self)
|
||||
.span_suggestion_verbose(
|
||||
lifetime.span.shrink_to_hi(),
|
||||
"add `'` to close the char literal",
|
||||
"'",
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
ast::Lit {
|
||||
token_lit: token::Lit::new(token::LitKind::Char, lifetime.name, None),
|
||||
kind: ast::LitKind::Char(lifetime.name.as_str().chars().next().unwrap_or('_')),
|
||||
span: lifetime.span,
|
||||
}
|
||||
}
|
||||
|
||||
/// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
|
||||
fn recover_do_catch(&mut self) -> PResult<'a, P<Expr>> {
|
||||
let lo = self.token.span;
|
||||
|
@ -1728,7 +1776,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> {
|
||||
self.parse_opt_lit().ok_or_else(|| {
|
||||
self.parse_opt_lit().ok_or(()).or_else(|()| {
|
||||
if let token::Interpolated(inner) = &self.token.kind {
|
||||
let expr = match inner.as_ref() {
|
||||
token::NtExpr(expr) => Some(expr),
|
||||
|
@ -1740,12 +1788,22 @@ impl<'a> Parser<'a> {
|
|||
let mut err = InvalidInterpolatedExpression { span: self.token.span }
|
||||
.into_diagnostic(&self.sess.span_diagnostic);
|
||||
err.downgrade_to_delayed_bug();
|
||||
return err;
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
let msg = format!("unexpected token: {}", super::token_descr(&self.token));
|
||||
self.struct_span_err(self.token.span, &msg)
|
||||
let token = self.token.clone();
|
||||
let err = |self_: &mut Self| {
|
||||
let msg = format!("unexpected token: {}", super::token_descr(&token));
|
||||
self_.struct_span_err(token.span, &msg)
|
||||
};
|
||||
// On an error path, eagerly consider a lifetime to be an unclosed character lit
|
||||
if self.token.is_lifetime() {
|
||||
let lt = self.expect_lifetime();
|
||||
Ok(self.recover_unclosed_char(lt.ident, err))
|
||||
} else {
|
||||
Err(err(self))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -402,6 +402,25 @@ impl<'a> Parser<'a> {
|
|||
} else {
|
||||
PatKind::Path(qself, path)
|
||||
}
|
||||
} else if matches!(self.token.kind, token::Lifetime(_))
|
||||
// In pattern position, we're totally fine with using "next token isn't colon"
|
||||
// as a heuristic. We could probably just always try to recover if it's a lifetime,
|
||||
// because we never have `'a: label {}` in a pattern position anyways, but it does
|
||||
// keep us from suggesting something like `let 'a: Ty = ..` => `let 'a': Ty = ..`
|
||||
&& !self.look_ahead(1, |token| matches!(token.kind, token::Colon))
|
||||
{
|
||||
// Recover a `'a` as a `'a'` literal
|
||||
let lt = self.expect_lifetime();
|
||||
let lit = self.recover_unclosed_char(lt.ident, |self_| {
|
||||
let expected = expected.unwrap_or("pattern");
|
||||
let msg =
|
||||
format!("expected {}, found {}", expected, super::token_descr(&self_.token));
|
||||
|
||||
let mut err = self_.struct_span_err(self_.token.span, &msg);
|
||||
err.span_label(self_.token.span, format!("expected {}", expected));
|
||||
err
|
||||
});
|
||||
PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit)))
|
||||
} else {
|
||||
// Try to parse everything else as literal with optional minus
|
||||
match self.parse_literal_maybe_minus() {
|
||||
|
@ -799,6 +818,7 @@ impl<'a> Parser<'a> {
|
|||
|| t.kind == token::Dot // e.g. `.5` for recovery;
|
||||
|| t.can_begin_literal_maybe_minus() // e.g. `42`.
|
||||
|| t.is_whole_expr()
|
||||
|| t.is_lifetime() // recover `'a` instead of `'a'`
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue