Auto merge of #94987 - Dylan-DPC:rollup-5tssuhi, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - #94868 (Format core and std macro rules, removing needless surrounding blocks) - #94951 (Extend the irrefutable_let_patterns lint to let chains) - #94955 (Refactor: Use `format_args_capture` in some parts of `rustc_parse`) - #94957 (Improve the explanation about the behaviour of read_line) - #94974 (Ensure that `let_else` does not interact with `let_chains`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
a2af9cf1cf
19 changed files with 650 additions and 151 deletions
|
@ -158,7 +158,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
|
|||
self.check_patterns(pat, Refutable);
|
||||
let mut cx = self.new_cx(scrutinee.hir_id);
|
||||
let tpat = self.lower_pattern(&mut cx, pat, &mut false);
|
||||
check_let_reachability(&mut cx, pat.hir_id, tpat, span);
|
||||
self.check_let_reachability(&mut cx, pat.hir_id, tpat, span);
|
||||
}
|
||||
|
||||
fn check_match(
|
||||
|
@ -176,7 +176,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
|
|||
if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard {
|
||||
self.check_patterns(pat, Refutable);
|
||||
let tpat = self.lower_pattern(&mut cx, pat, &mut false);
|
||||
check_let_reachability(&mut cx, pat.hir_id, tpat, tpat.span());
|
||||
self.check_let_reachability(&mut cx, pat.hir_id, tpat, tpat.span());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,6 +224,157 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_let_reachability(
|
||||
&mut self,
|
||||
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||
pat_id: HirId,
|
||||
pat: &'p DeconstructedPat<'p, 'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
if self.check_let_chain(cx, pat_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if is_let_irrefutable(cx, pat_id, pat) {
|
||||
irrefutable_let_pattern(cx.tcx, pat_id, span);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_let_chain(&mut self, cx: &mut MatchCheckCtxt<'p, 'tcx>, pat_id: HirId) -> bool {
|
||||
let hir = self.tcx.hir();
|
||||
let parent = hir.get_parent_node(pat_id);
|
||||
|
||||
// First, figure out if the given pattern is part of a let chain,
|
||||
// and if so, obtain the top node of the chain.
|
||||
let mut top = parent;
|
||||
let mut part_of_chain = false;
|
||||
loop {
|
||||
let new_top = hir.get_parent_node(top);
|
||||
if let hir::Node::Expr(
|
||||
hir::Expr {
|
||||
kind: hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, lhs, rhs),
|
||||
..
|
||||
},
|
||||
..,
|
||||
) = hir.get(new_top)
|
||||
{
|
||||
// If this isn't the first iteration, we need to check
|
||||
// if there is a let expr before us in the chain, so
|
||||
// that we avoid doubly checking the let chain.
|
||||
|
||||
// The way a chain of &&s is encoded is ((let ... && let ...) && let ...) && let ...
|
||||
// as && is left-to-right associative. Thus, we need to check rhs.
|
||||
if part_of_chain && matches!(rhs.kind, hir::ExprKind::Let(..)) {
|
||||
return true;
|
||||
}
|
||||
// If there is a let at the lhs, and we provide the rhs, we don't do any checking either.
|
||||
if !part_of_chain && matches!(lhs.kind, hir::ExprKind::Let(..)) && rhs.hir_id == top
|
||||
{
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// We've reached the top.
|
||||
break;
|
||||
}
|
||||
|
||||
// Since this function is called within a let context, it is reasonable to assume that any parent
|
||||
// `&&` infers a let chain
|
||||
part_of_chain = true;
|
||||
top = new_top;
|
||||
}
|
||||
if !part_of_chain {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Second, obtain the refutabilities of all exprs in the chain,
|
||||
// and record chain members that aren't let exprs.
|
||||
let mut chain_refutabilities = Vec::new();
|
||||
let hir::Node::Expr(top_expr) = hir.get(top) else {
|
||||
// We ensure right above that it's an Expr
|
||||
unreachable!()
|
||||
};
|
||||
let mut cur_expr = top_expr;
|
||||
loop {
|
||||
let mut add = |expr: &hir::Expr<'tcx>| {
|
||||
let refutability = match expr.kind {
|
||||
hir::ExprKind::Let(hir::Let { pat, init, span, .. }) => {
|
||||
let mut ncx = self.new_cx(init.hir_id);
|
||||
let tpat = self.lower_pattern(&mut ncx, pat, &mut false);
|
||||
|
||||
let refutable = !is_let_irrefutable(&mut ncx, pat.hir_id, tpat);
|
||||
Some((*span, refutable))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
chain_refutabilities.push(refutability);
|
||||
};
|
||||
if let hir::Expr {
|
||||
kind: hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, lhs, rhs),
|
||||
..
|
||||
} = cur_expr
|
||||
{
|
||||
add(rhs);
|
||||
cur_expr = lhs;
|
||||
} else {
|
||||
add(cur_expr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
chain_refutabilities.reverse();
|
||||
|
||||
// Third, emit the actual warnings.
|
||||
|
||||
if chain_refutabilities.iter().all(|r| matches!(*r, Some((_, false)))) {
|
||||
// The entire chain is made up of irrefutable `let` statements
|
||||
let let_source = let_source_parent(self.tcx, top, None);
|
||||
irrefutable_let_patterns(
|
||||
cx.tcx,
|
||||
top,
|
||||
let_source,
|
||||
chain_refutabilities.len(),
|
||||
top_expr.span,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
let lint_affix = |affix: &[Option<(Span, bool)>], kind, suggestion| {
|
||||
let span_start = affix[0].unwrap().0;
|
||||
let span_end = affix.last().unwrap().unwrap().0;
|
||||
let span = span_start.to(span_end);
|
||||
let cnt = affix.len();
|
||||
cx.tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, top, span, |lint| {
|
||||
let s = pluralize!(cnt);
|
||||
let mut diag = lint.build(&format!("{kind} irrefutable pattern{s} in let chain"));
|
||||
diag.note(&format!(
|
||||
"{these} pattern{s} will always match",
|
||||
these = pluralize!("this", cnt),
|
||||
));
|
||||
diag.help(&format!(
|
||||
"consider moving {} {suggestion}",
|
||||
if cnt > 1 { "them" } else { "it" }
|
||||
));
|
||||
diag.emit()
|
||||
});
|
||||
};
|
||||
if let Some(until) = chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) && until > 0 {
|
||||
// The chain has a non-zero prefix of irrefutable `let` statements.
|
||||
|
||||
// Check if the let source is while, for there is no alternative place to put a prefix,
|
||||
// and we shouldn't lint.
|
||||
let let_source = let_source_parent(self.tcx, top, None);
|
||||
if !matches!(let_source, LetSource::WhileLet) {
|
||||
// Emit the lint
|
||||
let prefix = &chain_refutabilities[..until];
|
||||
lint_affix(prefix, "leading", "outside of the construct");
|
||||
}
|
||||
}
|
||||
if let Some(from) = chain_refutabilities.iter().rposition(|r| !matches!(*r, Some((_, false)))) && from != (chain_refutabilities.len() - 1) {
|
||||
// The chain has a non-empty suffix of irrefutable `let` statements
|
||||
let suffix = &chain_refutabilities[from + 1..];
|
||||
lint_affix(suffix, "trailing", "into the body");
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>) {
|
||||
let mut cx = self.new_cx(pat.hir_id);
|
||||
|
||||
|
@ -453,6 +604,17 @@ fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<
|
|||
}
|
||||
|
||||
fn irrefutable_let_pattern(tcx: TyCtxt<'_>, id: HirId, span: Span) {
|
||||
let source = let_source(tcx, id);
|
||||
irrefutable_let_patterns(tcx, id, source, 1, span);
|
||||
}
|
||||
|
||||
fn irrefutable_let_patterns(
|
||||
tcx: TyCtxt<'_>,
|
||||
id: HirId,
|
||||
source: LetSource,
|
||||
count: usize,
|
||||
span: Span,
|
||||
) {
|
||||
macro_rules! emit_diag {
|
||||
(
|
||||
$lint:expr,
|
||||
|
@ -460,14 +622,15 @@ fn irrefutable_let_pattern(tcx: TyCtxt<'_>, id: HirId, span: Span) {
|
|||
$note_sufix:expr,
|
||||
$help_sufix:expr
|
||||
) => {{
|
||||
let mut diag = $lint.build(concat!("irrefutable ", $source_name, " pattern"));
|
||||
diag.note(concat!("this pattern will always match, so the ", $note_sufix));
|
||||
let s = pluralize!(count);
|
||||
let these = pluralize!("this", count);
|
||||
let mut diag = $lint.build(&format!("irrefutable {} pattern{s}", $source_name));
|
||||
diag.note(&format!("{these} pattern{s} will always match, so the {}", $note_sufix));
|
||||
diag.help(concat!("consider ", $help_sufix));
|
||||
diag.emit()
|
||||
}};
|
||||
}
|
||||
|
||||
let source = let_source(tcx, id);
|
||||
let span = match source {
|
||||
LetSource::LetElse(span) => span,
|
||||
_ => span,
|
||||
|
@ -511,16 +674,11 @@ fn irrefutable_let_pattern(tcx: TyCtxt<'_>, id: HirId, span: Span) {
|
|||
});
|
||||
}
|
||||
|
||||
fn check_let_reachability<'p, 'tcx>(
|
||||
fn is_let_irrefutable<'p, 'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||
pat_id: HirId,
|
||||
pat: &'p DeconstructedPat<'p, 'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
if is_let_chain(cx.tcx, pat_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
) -> bool {
|
||||
let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }];
|
||||
let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty());
|
||||
|
||||
|
@ -529,10 +687,9 @@ fn check_let_reachability<'p, 'tcx>(
|
|||
// `is_uninhabited` check.
|
||||
report_arm_reachability(&cx, &report);
|
||||
|
||||
if report.non_exhaustiveness_witnesses.is_empty() {
|
||||
// The match is exhaustive, i.e. the `if let` pattern is irrefutable.
|
||||
irrefutable_let_pattern(cx.tcx, pat_id, span);
|
||||
}
|
||||
// If the list of witnesses is empty, the match is exhaustive,
|
||||
// i.e. the `if let` pattern is irrefutable.
|
||||
report.non_exhaustiveness_witnesses.is_empty()
|
||||
}
|
||||
|
||||
/// Report unreachable arms, if any.
|
||||
|
@ -941,13 +1098,19 @@ fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource {
|
|||
let hir = tcx.hir();
|
||||
|
||||
let parent = hir.get_parent_node(pat_id);
|
||||
let_source_parent(tcx, parent, Some(pat_id))
|
||||
}
|
||||
|
||||
fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option<HirId>) -> LetSource {
|
||||
let hir = tcx.hir();
|
||||
|
||||
let parent_node = hir.get(parent);
|
||||
|
||||
match parent_node {
|
||||
hir::Node::Arm(hir::Arm {
|
||||
guard: Some(hir::Guard::IfLet(&hir::Pat { hir_id, .. }, _)),
|
||||
..
|
||||
}) if hir_id == pat_id => {
|
||||
}) if Some(hir_id) == pat_id => {
|
||||
return LetSource::IfLetGuard;
|
||||
}
|
||||
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Let(..), span, .. }) => {
|
||||
|
@ -980,21 +1143,3 @@ fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource {
|
|||
|
||||
LetSource::GenericLet
|
||||
}
|
||||
|
||||
// Since this function is called within a let context, it is reasonable to assume that any parent
|
||||
// `&&` infers a let chain
|
||||
fn is_let_chain(tcx: TyCtxt<'_>, pat_id: HirId) -> bool {
|
||||
let hir = tcx.hir();
|
||||
let parent = hir.get_parent_node(pat_id);
|
||||
let parent_parent = hir.get_parent_node(parent);
|
||||
matches!(
|
||||
hir.get(parent_parent),
|
||||
hir::Node::Expr(
|
||||
hir::Expr {
|
||||
kind: hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, ..),
|
||||
..
|
||||
},
|
||||
..
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -139,7 +139,7 @@ impl<'a> Parser<'a> {
|
|||
Ok(attr::mk_attr_from_item(item, None, style, attr_sp))
|
||||
} else {
|
||||
let token_str = pprust::token_to_string(&this.token);
|
||||
let msg = &format!("expected `#`, found `{}`", token_str);
|
||||
let msg = &format!("expected `#`, found `{token_str}`");
|
||||
Err(this.struct_span_err(this.token.span, msg))
|
||||
}
|
||||
})
|
||||
|
@ -421,7 +421,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
let found = pprust::token_to_string(&self.token);
|
||||
let msg = format!("expected unsuffixed literal or identifier, found `{}`", found);
|
||||
let msg = format!("expected unsuffixed literal or identifier, found `{found}`");
|
||||
Err(self.struct_span_err(self.token.span, &msg))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -327,8 +327,8 @@ impl<'a> Parser<'a> {
|
|||
expect.clone()
|
||||
};
|
||||
(
|
||||
format!("expected one of {}, found {}", expect, actual),
|
||||
(self.prev_token.span.shrink_to_hi(), format!("expected one of {}", short_expect)),
|
||||
format!("expected one of {expect}, found {actual}"),
|
||||
(self.prev_token.span.shrink_to_hi(), format!("expected one of {short_expect}")),
|
||||
)
|
||||
} else if expected.is_empty() {
|
||||
(
|
||||
|
@ -337,8 +337,8 @@ impl<'a> Parser<'a> {
|
|||
)
|
||||
} else {
|
||||
(
|
||||
format!("expected {}, found {}", expect, actual),
|
||||
(self.prev_token.span.shrink_to_hi(), format!("expected {}", expect)),
|
||||
format!("expected {expect}, found {actual}"),
|
||||
(self.prev_token.span.shrink_to_hi(), format!("expected {expect}")),
|
||||
)
|
||||
};
|
||||
self.last_unexpected_token_span = Some(self.token.span);
|
||||
|
@ -421,7 +421,7 @@ impl<'a> Parser<'a> {
|
|||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.note(&format!("the raw string started with {} `#`s", n_hashes));
|
||||
err.note(&format!("the raw string started with {n_hashes} `#`s"));
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
|
@ -1191,7 +1191,7 @@ impl<'a> Parser<'a> {
|
|||
_ => None,
|
||||
};
|
||||
if let Some(name) = previous_item_kind_name {
|
||||
err.help(&format!("{} declarations are not followed by a semicolon", name));
|
||||
err.help(&format!("{name} declarations are not followed by a semicolon"));
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
|
@ -1226,12 +1226,12 @@ impl<'a> Parser<'a> {
|
|||
"expected `{}`, found {}",
|
||||
token_str,
|
||||
match (&self.token.kind, self.subparser_name) {
|
||||
(token::Eof, Some(origin)) => format!("end of {}", origin),
|
||||
(token::Eof, Some(origin)) => format!("end of {origin}"),
|
||||
_ => this_token_str,
|
||||
},
|
||||
);
|
||||
let mut err = self.struct_span_err(sp, &msg);
|
||||
let label_exp = format!("expected `{}`", token_str);
|
||||
let label_exp = format!("expected `{token_str}`");
|
||||
match self.recover_closing_delimiter(&[t.clone()], err) {
|
||||
Err(e) => err = e,
|
||||
Ok(recovered) => {
|
||||
|
@ -1368,7 +1368,7 @@ impl<'a> Parser<'a> {
|
|||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
err.span_suggestion(lo.shrink_to_lo(), &format!("{}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax", prefix), "r#".to_string(), Applicability::MachineApplicable);
|
||||
err.span_suggestion(lo.shrink_to_lo(), &format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#".to_string(), Applicability::MachineApplicable);
|
||||
err.emit();
|
||||
Ok(self.mk_expr_err(lo.to(hi)))
|
||||
} else {
|
||||
|
@ -1504,7 +1504,7 @@ impl<'a> Parser<'a> {
|
|||
delim.retain(|c| c != '`');
|
||||
err.span_suggestion_short(
|
||||
self.prev_token.span.shrink_to_hi(),
|
||||
&format!("`{}` may belong here", delim),
|
||||
&format!("`{delim}` may belong here"),
|
||||
delim,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
@ -1698,7 +1698,7 @@ impl<'a> Parser<'a> {
|
|||
(
|
||||
ident,
|
||||
"self: ".to_string(),
|
||||
format!("{}: &{}TypeName", ident, mutab),
|
||||
format!("{ident}: &{mutab}TypeName"),
|
||||
"_: ".to_string(),
|
||||
pat.span.shrink_to_lo(),
|
||||
pat.span,
|
||||
|
@ -1826,7 +1826,7 @@ impl<'a> Parser<'a> {
|
|||
let (span, msg) = match (&self.token.kind, self.subparser_name) {
|
||||
(&token::Eof, Some(origin)) => {
|
||||
let sp = self.sess.source_map().next_point(self.prev_token.span);
|
||||
(sp, format!("expected expression, found end of {}", origin))
|
||||
(sp, format!("expected expression, found end of {origin}"))
|
||||
}
|
||||
_ => (
|
||||
self.token.span,
|
||||
|
@ -1975,8 +1975,8 @@ impl<'a> Parser<'a> {
|
|||
(ty_generics, self.sess.source_map().span_to_snippet(param.span()))
|
||||
{
|
||||
let (span, sugg) = match &generics.params[..] {
|
||||
[] => (generics.span, format!("<{}>", snippet)),
|
||||
[.., generic] => (generic.span().shrink_to_hi(), format!(", {}", snippet)),
|
||||
[] => (generics.span, format!("<{snippet}>")),
|
||||
[.., generic] => (generic.span().shrink_to_hi(), format!(", {snippet}")),
|
||||
};
|
||||
err.multipart_suggestion(
|
||||
"`const` parameters must be declared for the `impl`",
|
||||
|
|
|
@ -223,7 +223,7 @@ impl<'a> Parser<'a> {
|
|||
AssocOp::NotEqual => "!=",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.struct_span_err(sp, &format!("invalid comparison operator `{}=`", sugg))
|
||||
self.struct_span_err(sp, &format!("invalid comparison operator `{sugg}=`"))
|
||||
.span_suggestion_short(
|
||||
sp,
|
||||
&format!("`{s}=` is not a valid comparison operator, use `{s}`", s = sugg),
|
||||
|
@ -441,10 +441,10 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Error on `and` and `or` suggesting `&&` and `||` respectively.
|
||||
fn error_bad_logical_op(&self, bad: &str, good: &str, english: &str) {
|
||||
self.struct_span_err(self.token.span, &format!("`{}` is not a logical operator", bad))
|
||||
self.struct_span_err(self.token.span, &format!("`{bad}` is not a logical operator"))
|
||||
.span_suggestion_short(
|
||||
self.token.span,
|
||||
&format!("use `{}` to perform logical {}", good, english),
|
||||
&format!("use `{good}` to perform logical {english}"),
|
||||
good.to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
|
@ -766,9 +766,9 @@ impl<'a> Parser<'a> {
|
|||
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_label(self.token.span, format!("not interpreted as {op_noun}"))
|
||||
.multipart_suggestion(
|
||||
&format!("try {} the cast value", op_verb),
|
||||
&format!("try {op_verb} the cast value"),
|
||||
vec![
|
||||
(expr.span.shrink_to_lo(), "(".to_string()),
|
||||
(expr.span.shrink_to_hi(), ")".to_string()),
|
||||
|
@ -970,7 +970,7 @@ impl<'a> Parser<'a> {
|
|||
fn error_unexpected_after_dot(&self) {
|
||||
// FIXME Could factor this out into non_fatal_unexpected or something.
|
||||
let actual = pprust::token_to_string(&self.token);
|
||||
self.struct_span_err(self.token.span, &format!("unexpected token: `{}`", actual)).emit();
|
||||
self.struct_span_err(self.token.span, &format!("unexpected token: `{actual}`")).emit();
|
||||
}
|
||||
|
||||
// We need an identifier or integer, but the next token is a float.
|
||||
|
@ -1151,7 +1151,7 @@ impl<'a> Parser<'a> {
|
|||
mem::replace(err, replacement_err).cancel();
|
||||
|
||||
err.multipart_suggestion(
|
||||
&format!("if `{}` is a struct, use braces as delimiters", name),
|
||||
&format!("if `{name}` is a struct, use braces as delimiters"),
|
||||
vec![
|
||||
(open_paren, " { ".to_string()),
|
||||
(close_paren, " }".to_string()),
|
||||
|
@ -1159,7 +1159,7 @@ impl<'a> Parser<'a> {
|
|||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.multipart_suggestion(
|
||||
&format!("if `{}` is a function, use the arguments directly", name),
|
||||
&format!("if `{name}` is a function, use the arguments directly"),
|
||||
fields
|
||||
.into_iter()
|
||||
.map(|field| (field.span.until(field.expr.span), String::new()))
|
||||
|
@ -1776,9 +1776,9 @@ impl<'a> Parser<'a> {
|
|||
)
|
||||
.emit();
|
||||
} else {
|
||||
let msg = format!("invalid suffix `{}` for number literal", suf);
|
||||
let msg = format!("invalid suffix `{suf}` for number literal");
|
||||
self.struct_span_err(span, &msg)
|
||||
.span_label(span, format!("invalid suffix `{}`", suf))
|
||||
.span_label(span, format!("invalid suffix `{suf}`"))
|
||||
.help("the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)")
|
||||
.emit();
|
||||
}
|
||||
|
@ -1791,9 +1791,9 @@ impl<'a> Parser<'a> {
|
|||
let msg = format!("invalid width `{}` for float literal", &suf[1..]);
|
||||
self.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit();
|
||||
} else {
|
||||
let msg = format!("invalid suffix `{}` for float literal", suf);
|
||||
let msg = format!("invalid suffix `{suf}` for float literal");
|
||||
self.struct_span_err(span, &msg)
|
||||
.span_label(span, format!("invalid suffix `{}`", suf))
|
||||
.span_label(span, format!("invalid suffix `{suf}`"))
|
||||
.help("valid suffixes are `f32` and `f64`")
|
||||
.emit();
|
||||
}
|
||||
|
@ -1805,7 +1805,7 @@ impl<'a> Parser<'a> {
|
|||
2 => "binary",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.struct_span_err(span, &format!("{} float literal is not supported", descr))
|
||||
self.struct_span_err(span, &format!("{descr} float literal is not supported"))
|
||||
.span_label(span, "not supported")
|
||||
.emit();
|
||||
}
|
||||
|
@ -1825,7 +1825,7 @@ impl<'a> Parser<'a> {
|
|||
let mut err = self
|
||||
.sess
|
||||
.span_diagnostic
|
||||
.struct_span_warn(sp, &format!("suffixes on {} are invalid", kind));
|
||||
.struct_span_warn(sp, &format!("suffixes on {kind} are invalid"));
|
||||
err.note(&format!(
|
||||
"`{}` is *temporarily* accepted on tuple index fields as it was \
|
||||
incorrectly accepted on stable for a few releases",
|
||||
|
@ -1842,10 +1842,10 @@ impl<'a> Parser<'a> {
|
|||
);
|
||||
err
|
||||
} else {
|
||||
self.struct_span_err(sp, &format!("suffixes on {} are invalid", kind))
|
||||
self.struct_span_err(sp, &format!("suffixes on {kind} are invalid"))
|
||||
.forget_guarantee()
|
||||
};
|
||||
err.span_label(sp, format!("invalid suffix `{}`", suf));
|
||||
err.span_label(sp, format!("invalid suffix `{suf}`"));
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
@ -2211,7 +2211,7 @@ impl<'a> Parser<'a> {
|
|||
let ctx = if is_ctx_else { "else" } else { "if" };
|
||||
self.struct_span_err(last, "outer attributes are not allowed on `if` and `else` branches")
|
||||
.span_label(branch_span, "the attributes are attached to this branch")
|
||||
.span_label(ctx_span, format!("the branch belongs to this `{}`", ctx))
|
||||
.span_label(ctx_span, format!("the branch belongs to this `{ctx}`"))
|
||||
.span_suggestion(
|
||||
span,
|
||||
"remove the attributes",
|
||||
|
@ -2391,7 +2391,7 @@ impl<'a> Parser<'a> {
|
|||
err.span_label(arrow_span, "while parsing the `match` arm starting here");
|
||||
if stmts.len() > 1 {
|
||||
err.multipart_suggestion(
|
||||
&format!("surround the statement{} with a body", s),
|
||||
&format!("surround the statement{s} with a body"),
|
||||
vec![
|
||||
(span.shrink_to_lo(), "{ ".to_string()),
|
||||
(span.shrink_to_hi(), " }".to_string()),
|
||||
|
|
|
@ -66,7 +66,7 @@ impl<'a> Parser<'a> {
|
|||
if !self.eat(term) {
|
||||
let token_str = super::token_descr(&self.token);
|
||||
if !self.maybe_consume_incorrect_semicolon(&items) {
|
||||
let msg = &format!("expected item, found {}", token_str);
|
||||
let msg = &format!("expected item, found {token_str}");
|
||||
let mut err = self.struct_span_err(self.token.span, msg);
|
||||
err.span_label(self.token.span, "expected item");
|
||||
return Err(err);
|
||||
|
@ -163,9 +163,9 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
let vs = pprust::vis_to_string(&vis);
|
||||
let vs = vs.trim_end();
|
||||
self.struct_span_err(vis.span, &format!("visibility `{}` is not followed by an item", vs))
|
||||
self.struct_span_err(vis.span, &format!("visibility `{vs}` is not followed by an item"))
|
||||
.span_label(vis.span, "the visibility")
|
||||
.help(&format!("you likely meant to define an item, e.g., `{} fn foo() {{}}`", vs))
|
||||
.help(&format!("you likely meant to define an item, e.g., `{vs} fn foo() {{}}`"))
|
||||
.emit();
|
||||
}
|
||||
|
||||
|
@ -327,7 +327,7 @@ impl<'a> Parser<'a> {
|
|||
if self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) {
|
||||
// possible public struct definition where `struct` was forgotten
|
||||
let ident = self.parse_ident().unwrap();
|
||||
let msg = format!("add `struct` here to parse `{}` as a public struct", ident);
|
||||
let msg = format!("add `struct` here to parse `{ident}` as a public struct");
|
||||
let mut err = self.struct_span_err(sp, "missing `struct` for struct definition");
|
||||
err.span_suggestion_short(
|
||||
sp,
|
||||
|
@ -355,16 +355,16 @@ impl<'a> Parser<'a> {
|
|||
("fn` or `struct", "function or struct", true)
|
||||
};
|
||||
|
||||
let msg = format!("missing `{}` for {} definition", kw, kw_name);
|
||||
let msg = format!("missing `{kw}` for {kw_name} definition");
|
||||
let mut err = self.struct_span_err(sp, &msg);
|
||||
if !ambiguous {
|
||||
self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
|
||||
let suggestion =
|
||||
format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name);
|
||||
format!("add `{kw}` here to parse `{ident}` as a public {kw_name}");
|
||||
err.span_suggestion_short(
|
||||
sp,
|
||||
&suggestion,
|
||||
format!(" {} ", kw),
|
||||
format!(" {kw} "),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if let Ok(snippet) = self.span_to_snippet(ident_sp) {
|
||||
|
@ -393,12 +393,12 @@ impl<'a> Parser<'a> {
|
|||
} else {
|
||||
("fn` or `struct", "function or struct", true)
|
||||
};
|
||||
let msg = format!("missing `{}` for {} definition", kw, kw_name);
|
||||
let msg = format!("missing `{kw}` for {kw_name} definition");
|
||||
let mut err = self.struct_span_err(sp, &msg);
|
||||
if !ambiguous {
|
||||
err.span_suggestion_short(
|
||||
sp,
|
||||
&format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name),
|
||||
&format!("add `{kw}` here to parse `{ident}` as a public {kw_name}"),
|
||||
format!(" {} ", kw),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
@ -1031,8 +1031,8 @@ impl<'a> Parser<'a> {
|
|||
fn error_bad_item_kind<T>(&self, span: Span, kind: &ItemKind, ctx: &str) -> Option<T> {
|
||||
let span = self.sess.source_map().guess_head_span(span);
|
||||
let descr = kind.descr();
|
||||
self.struct_span_err(span, &format!("{} is not supported in {}", descr, ctx))
|
||||
.help(&format!("consider moving the {} out to a nearby module scope", descr))
|
||||
self.struct_span_err(span, &format!("{descr} is not supported in {ctx}"))
|
||||
.help(&format!("consider moving the {descr} out to a nearby module scope"))
|
||||
.emit();
|
||||
None
|
||||
}
|
||||
|
@ -1161,11 +1161,11 @@ impl<'a> Parser<'a> {
|
|||
Some(Mutability::Not) => "static",
|
||||
None => "const",
|
||||
};
|
||||
let mut err = self.struct_span_err(id.span, &format!("missing type for `{}` item", kind));
|
||||
let mut err = self.struct_span_err(id.span, &format!("missing type for `{kind}` item"));
|
||||
err.span_suggestion(
|
||||
id.span,
|
||||
"provide a type for the item",
|
||||
format!("{}: <type>", id),
|
||||
format!("{id}: <type>"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
err.stash(id.span, StashKey::ItemNoType);
|
||||
|
@ -1282,8 +1282,7 @@ impl<'a> Parser<'a> {
|
|||
} else {
|
||||
let token_str = super::token_descr(&self.token);
|
||||
let msg = &format!(
|
||||
"expected `where`, `{{`, `(`, or `;` after struct name, found {}",
|
||||
token_str
|
||||
"expected `where`, `{{`, `(`, or `;` after struct name, found {token_str}"
|
||||
);
|
||||
let mut err = self.struct_span_err(self.token.span, msg);
|
||||
err.span_label(self.token.span, "expected `where`, `{`, `(`, or `;` after struct name");
|
||||
|
@ -1310,7 +1309,7 @@ impl<'a> Parser<'a> {
|
|||
VariantData::Struct(fields, recovered)
|
||||
} else {
|
||||
let token_str = super::token_descr(&self.token);
|
||||
let msg = &format!("expected `where` or `{{` after union name, found {}", token_str);
|
||||
let msg = &format!("expected `where` or `{{` after union name, found {token_str}");
|
||||
let mut err = self.struct_span_err(self.token.span, msg);
|
||||
err.span_label(self.token.span, "expected `where` or `{` after union name");
|
||||
return Err(err);
|
||||
|
@ -1591,7 +1590,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
let mut err = self.struct_span_err(
|
||||
lo.to(self.prev_token.span),
|
||||
&format!("functions are not allowed in {} definitions", adt_ty),
|
||||
&format!("functions are not allowed in {adt_ty} definitions"),
|
||||
);
|
||||
err.help("unlike in C++, Java, and C#, functions are declared in `impl` blocks");
|
||||
err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information");
|
||||
|
@ -1706,7 +1705,7 @@ impl<'a> Parser<'a> {
|
|||
let vstr = pprust::vis_to_string(vis);
|
||||
let vstr = vstr.trim_end();
|
||||
if macro_rules {
|
||||
let msg = format!("can't qualify macro_rules invocation with `{}`", vstr);
|
||||
let msg = format!("can't qualify macro_rules invocation with `{vstr}`");
|
||||
self.struct_span_err(vis.span, &msg)
|
||||
.span_suggestion(
|
||||
vis.span,
|
||||
|
@ -1723,7 +1722,7 @@ impl<'a> Parser<'a> {
|
|||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.help(&format!("try adjusting the macro to put `{}` inside the invocation", vstr))
|
||||
.help(&format!("try adjusting the macro to put `{vstr}` inside the invocation"))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
@ -1781,11 +1780,11 @@ impl<'a> Parser<'a> {
|
|||
|
||||
self.struct_span_err(
|
||||
kw_token.span,
|
||||
&format!("`{}` definition cannot be nested inside `{}`", kw_str, keyword),
|
||||
&format!("`{kw_str}` definition cannot be nested inside `{keyword}`"),
|
||||
)
|
||||
.span_suggestion(
|
||||
item.unwrap().span,
|
||||
&format!("consider creating a new `{}` definition instead of nesting", kw_str),
|
||||
&format!("consider creating a new `{kw_str}` definition instead of nesting"),
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
|
@ -2045,11 +2044,11 @@ impl<'a> Parser<'a> {
|
|||
|
||||
err.span_suggestion(
|
||||
self.token.uninterpolated_span(),
|
||||
&format!("`{}` already used earlier, remove this one", original_kw),
|
||||
&format!("`{original_kw}` already used earlier, remove this one"),
|
||||
"".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.span_note(original_sp, &format!("`{}` first seen here", original_kw));
|
||||
.span_note(original_sp, &format!("`{original_kw}` first seen here"));
|
||||
}
|
||||
// The keyword has not been seen yet, suggest correct placement in the function front matter
|
||||
else if let Some(WrongKw::Misplaced(correct_pos_sp)) = wrong_kw {
|
||||
|
@ -2060,8 +2059,8 @@ impl<'a> Parser<'a> {
|
|||
|
||||
err.span_suggestion(
|
||||
correct_pos_sp.to(misplaced_qual_sp),
|
||||
&format!("`{}` must come before `{}`", misplaced_qual, current_qual),
|
||||
format!("{} {}", misplaced_qual, current_qual),
|
||||
&format!("`{misplaced_qual}` must come before `{current_qual}`"),
|
||||
format!("{misplaced_qual} {current_qual}"),
|
||||
Applicability::MachineApplicable,
|
||||
).note("keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`");
|
||||
}
|
||||
|
@ -2084,8 +2083,8 @@ impl<'a> Parser<'a> {
|
|||
if matches!(orig_vis.kind, VisibilityKind::Inherited) {
|
||||
err.span_suggestion(
|
||||
sp_start.to(self.prev_token.span),
|
||||
&format!("visibility `{}` must come before `{}`", vs, snippet),
|
||||
format!("{} {}", vs, snippet),
|
||||
&format!("visibility `{vs}` must come before `{snippet}`"),
|
||||
format!("{vs} {snippet}"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ macro_rules! panic {
|
|||
#[cfg_attr(not(test), rustc_diagnostic_item = "assert_eq_macro")]
|
||||
#[allow_internal_unstable(core_panic)]
|
||||
macro_rules! assert_eq {
|
||||
($left:expr, $right:expr $(,)?) => ({
|
||||
($left:expr, $right:expr $(,)?) => {
|
||||
match (&$left, &$right) {
|
||||
(left_val, right_val) => {
|
||||
if !(*left_val == *right_val) {
|
||||
|
@ -46,8 +46,8 @@ macro_rules! assert_eq {
|
|||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
($left:expr, $right:expr, $($arg:tt)+) => ({
|
||||
};
|
||||
($left:expr, $right:expr, $($arg:tt)+) => {
|
||||
match (&$left, &$right) {
|
||||
(left_val, right_val) => {
|
||||
if !(*left_val == *right_val) {
|
||||
|
@ -59,7 +59,7 @@ macro_rules! assert_eq {
|
|||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts that two expressions are not equal to each other (using [`PartialEq`]).
|
||||
|
@ -84,7 +84,7 @@ macro_rules! assert_eq {
|
|||
#[cfg_attr(not(test), rustc_diagnostic_item = "assert_ne_macro")]
|
||||
#[allow_internal_unstable(core_panic)]
|
||||
macro_rules! assert_ne {
|
||||
($left:expr, $right:expr $(,)?) => ({
|
||||
($left:expr, $right:expr $(,)?) => {
|
||||
match (&$left, &$right) {
|
||||
(left_val, right_val) => {
|
||||
if *left_val == *right_val {
|
||||
|
@ -96,8 +96,8 @@ macro_rules! assert_ne {
|
|||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
($left:expr, $right:expr, $($arg:tt)+) => ({
|
||||
};
|
||||
($left:expr, $right:expr, $($arg:tt)+) => {
|
||||
match (&($left), &($right)) {
|
||||
(left_val, right_val) => {
|
||||
if *left_val == *right_val {
|
||||
|
@ -109,7 +109,7 @@ macro_rules! assert_ne {
|
|||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts that an expression matches any of the given patterns.
|
||||
|
@ -142,7 +142,7 @@ macro_rules! assert_ne {
|
|||
#[allow_internal_unstable(core_panic)]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
pub macro assert_matches {
|
||||
($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => ({
|
||||
($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => {
|
||||
match $left {
|
||||
$( $pattern )|+ $( if $guard )? => {}
|
||||
ref left_val => {
|
||||
|
@ -153,8 +153,8 @@ pub macro assert_matches {
|
|||
);
|
||||
}
|
||||
}
|
||||
}),
|
||||
($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )?, $($arg:tt)+) => ({
|
||||
},
|
||||
($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )?, $($arg:tt)+) => {
|
||||
match $left {
|
||||
$( $pattern )|+ $( if $guard )? => {}
|
||||
ref left_val => {
|
||||
|
@ -165,7 +165,7 @@ pub macro assert_matches {
|
|||
);
|
||||
}
|
||||
}
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
/// Asserts that a boolean expression is `true` at runtime.
|
||||
|
@ -214,7 +214,11 @@ pub macro assert_matches {
|
|||
#[rustc_diagnostic_item = "debug_assert_macro"]
|
||||
#[allow_internal_unstable(edition_panic)]
|
||||
macro_rules! debug_assert {
|
||||
($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert!($($arg)*); })
|
||||
($($arg:tt)*) => {
|
||||
if $crate::cfg!(debug_assertions) {
|
||||
$crate::assert!($($arg)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts that two expressions are equal to each other.
|
||||
|
@ -240,7 +244,11 @@ macro_rules! debug_assert {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "debug_assert_eq_macro")]
|
||||
macro_rules! debug_assert_eq {
|
||||
($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_eq!($($arg)*); })
|
||||
($($arg:tt)*) => {
|
||||
if $crate::cfg!(debug_assertions) {
|
||||
$crate::assert_eq!($($arg)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts that two expressions are not equal to each other.
|
||||
|
@ -266,7 +274,11 @@ macro_rules! debug_assert_eq {
|
|||
#[stable(feature = "assert_ne", since = "1.13.0")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "debug_assert_ne_macro")]
|
||||
macro_rules! debug_assert_ne {
|
||||
($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_ne!($($arg)*); })
|
||||
($($arg:tt)*) => {
|
||||
if $crate::cfg!(debug_assertions) {
|
||||
$crate::assert_ne!($($arg)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts that an expression matches any of the given patterns.
|
||||
|
@ -305,7 +317,9 @@ macro_rules! debug_assert_ne {
|
|||
#[allow_internal_unstable(assert_matches)]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
pub macro debug_assert_matches($($arg:tt)*) {
|
||||
if $crate::cfg!(debug_assertions) { $crate::assert_matches::assert_matches!($($arg)*); }
|
||||
if $crate::cfg!(debug_assertions) {
|
||||
$crate::assert_matches::assert_matches!($($arg)*);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the given expression matches any of the given patterns.
|
||||
|
@ -331,7 +345,7 @@ macro_rules! matches {
|
|||
$( $pattern )|+ $( if $guard )? => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Unwraps a result or propagates its error.
|
||||
|
@ -482,7 +496,9 @@ macro_rules! r#try {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "write_macro")]
|
||||
macro_rules! write {
|
||||
($dst:expr, $($arg:tt)*) => ($dst.write_fmt($crate::format_args!($($arg)*)))
|
||||
($dst:expr, $($arg:tt)*) => {
|
||||
$dst.write_fmt($crate::format_args!($($arg)*))
|
||||
};
|
||||
}
|
||||
|
||||
/// Write formatted data into a buffer, with a newline appended.
|
||||
|
@ -534,12 +550,12 @@ macro_rules! write {
|
|||
#[cfg_attr(not(test), rustc_diagnostic_item = "writeln_macro")]
|
||||
#[allow_internal_unstable(format_args_nl)]
|
||||
macro_rules! writeln {
|
||||
($dst:expr $(,)?) => (
|
||||
($dst:expr $(,)?) => {
|
||||
$crate::write!($dst, "\n")
|
||||
);
|
||||
($dst:expr, $($arg:tt)*) => (
|
||||
};
|
||||
($dst:expr, $($arg:tt)*) => {
|
||||
$dst.write_fmt($crate::format_args_nl!($($arg)*))
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/// Indicates unreachable code.
|
||||
|
@ -683,8 +699,12 @@ macro_rules! unreachable {
|
|||
#[cfg_attr(not(test), rustc_diagnostic_item = "unimplemented_macro")]
|
||||
#[allow_internal_unstable(core_panic)]
|
||||
macro_rules! unimplemented {
|
||||
() => ($crate::panicking::panic("not implemented"));
|
||||
($($arg:tt)+) => ($crate::panic!("not implemented: {}", $crate::format_args!($($arg)+)));
|
||||
() => {
|
||||
$crate::panicking::panic("not implemented")
|
||||
};
|
||||
($($arg:tt)+) => {
|
||||
$crate::panic!("not implemented: {}", $crate::format_args!($($arg)+))
|
||||
};
|
||||
}
|
||||
|
||||
/// Indicates unfinished code.
|
||||
|
@ -746,8 +766,12 @@ macro_rules! unimplemented {
|
|||
#[cfg_attr(not(test), rustc_diagnostic_item = "todo_macro")]
|
||||
#[allow_internal_unstable(core_panic)]
|
||||
macro_rules! todo {
|
||||
() => ($crate::panicking::panic("not yet implemented"));
|
||||
($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", $crate::format_args!($($arg)+)));
|
||||
() => {
|
||||
$crate::panicking::panic("not yet implemented")
|
||||
};
|
||||
($($arg:tt)+) => {
|
||||
$crate::panic!("not yet implemented: {}", $crate::format_args!($($arg)+))
|
||||
};
|
||||
}
|
||||
|
||||
/// Definitions of built-in macros.
|
||||
|
|
|
@ -2110,7 +2110,8 @@ pub trait BufRead: Read {
|
|||
}
|
||||
|
||||
/// Read all bytes until a newline (the `0xA` byte) is reached, and append
|
||||
/// them to the provided buffer.
|
||||
/// them to the provided buffer. You do not need to clear the buffer before
|
||||
/// appending.
|
||||
///
|
||||
/// This function will read bytes from the underlying stream until the
|
||||
/// newline delimiter (the `0xA` byte) or EOF is found. Once found, all bytes
|
||||
|
|
|
@ -60,7 +60,9 @@ macro_rules! panic {
|
|||
#[cfg_attr(not(test), rustc_diagnostic_item = "print_macro")]
|
||||
#[allow_internal_unstable(print_internals)]
|
||||
macro_rules! print {
|
||||
($($arg:tt)*) => ($crate::io::_print($crate::format_args!($($arg)*)));
|
||||
($($arg:tt)*) => {
|
||||
$crate::io::_print($crate::format_args!($($arg)*))
|
||||
};
|
||||
}
|
||||
|
||||
/// Prints to the standard output, with a newline.
|
||||
|
@ -94,10 +96,12 @@ macro_rules! print {
|
|||
#[cfg_attr(not(test), rustc_diagnostic_item = "println_macro")]
|
||||
#[allow_internal_unstable(print_internals, format_args_nl)]
|
||||
macro_rules! println {
|
||||
() => ($crate::print!("\n"));
|
||||
($($arg:tt)*) => ({
|
||||
$crate::io::_print($crate::format_args_nl!($($arg)*));
|
||||
})
|
||||
() => {
|
||||
$crate::print!("\n")
|
||||
};
|
||||
($($arg:tt)*) => {
|
||||
$crate::io::_print($crate::format_args_nl!($($arg)*))
|
||||
};
|
||||
}
|
||||
|
||||
/// Prints to the standard error.
|
||||
|
@ -126,7 +130,9 @@ macro_rules! println {
|
|||
#[cfg_attr(not(test), rustc_diagnostic_item = "eprint_macro")]
|
||||
#[allow_internal_unstable(print_internals)]
|
||||
macro_rules! eprint {
|
||||
($($arg:tt)*) => ($crate::io::_eprint($crate::format_args!($($arg)*)));
|
||||
($($arg:tt)*) => {
|
||||
$crate::io::_eprint($crate::format_args!($($arg)*))
|
||||
};
|
||||
}
|
||||
|
||||
/// Prints to the standard error, with a newline.
|
||||
|
@ -155,10 +161,12 @@ macro_rules! eprint {
|
|||
#[cfg_attr(not(test), rustc_diagnostic_item = "eprintln_macro")]
|
||||
#[allow_internal_unstable(print_internals, format_args_nl)]
|
||||
macro_rules! eprintln {
|
||||
() => ($crate::eprint!("\n"));
|
||||
($($arg:tt)*) => ({
|
||||
$crate::io::_eprint($crate::format_args_nl!($($arg)*));
|
||||
})
|
||||
() => {
|
||||
$crate::eprint!("\n")
|
||||
};
|
||||
($($arg:tt)*) => {
|
||||
$crate::io::_eprint($crate::format_args_nl!($($arg)*))
|
||||
};
|
||||
}
|
||||
|
||||
/// Prints and returns the value of a given expression for quick and dirty
|
||||
|
|
|
@ -9,5 +9,5 @@ extern crate std;
|
|||
// pp-exact:dollar-crate.pp
|
||||
|
||||
fn main() {
|
||||
{ ::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"], &[])); };
|
||||
::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"], &[]));
|
||||
}
|
||||
|
|
|
@ -116,8 +116,8 @@
|
|||
116| 1|
|
||||
117| 1| let
|
||||
118| 1| _unused_closure
|
||||
119| | =
|
||||
120| | |
|
||||
119| 1| =
|
||||
120| 1| |
|
||||
121| | mut countdown
|
||||
122| | |
|
||||
123| 0| {
|
||||
|
@ -173,7 +173,7 @@
|
|||
169| | ;
|
||||
170| |
|
||||
171| 1| let short_used_not_covered_closure_line_break_no_block_embedded_branch =
|
||||
172| | | _unused_arg: u8 |
|
||||
172| 1| | _unused_arg: u8 |
|
||||
173| 0| println!(
|
||||
174| 0| "not called: {}",
|
||||
175| 0| if is_true { "check" } else { "me" }
|
||||
|
@ -191,7 +191,7 @@
|
|||
187| | ;
|
||||
188| |
|
||||
189| 1| let short_used_covered_closure_line_break_no_block_embedded_branch =
|
||||
190| 1| | _unused_arg: u8 |
|
||||
190| | | _unused_arg: u8 |
|
||||
191| 1| println!(
|
||||
192| 1| "not called: {}",
|
||||
193| 1| if is_true { "check" } else { "me" }
|
||||
|
|
|
@ -5,5 +5,5 @@ LL | println!("Hello, World!");
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: expanding `println! { "Hello, World!" }`
|
||||
= note: to `{ $crate :: io :: _print($crate :: format_args_nl! ("Hello, World!")) ; }`
|
||||
= note: to `$crate :: io :: _print($crate :: format_args_nl! ("Hello, World!"))`
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// See `mir_drop_order.rs` for more information
|
||||
|
||||
#![feature(let_chains)]
|
||||
#![allow(irrefutable_let_patterns)]
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::panic;
|
||||
|
|
|
@ -45,7 +45,7 @@ LL | fn main() {}
|
|||
|
|
||||
::: $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
|
|
||||
LL | ($left:expr, $right:expr $(,)?) => ({
|
||||
LL | ($left:expr, $right:expr $(,)?) => {
|
||||
| ---------- while parsing argument for this `expr` macro fragment
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
|
|
@ -12,7 +12,7 @@ LL | struct Foo(isize, isize);
|
|||
= note: the matched value is of type `Foo`
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL ~ Foo(2, b) => println!("{}", b)
|
||||
LL ~ Foo(2, b) => println!("{}", b),
|
||||
LL + Foo(_, _) => todo!()
|
||||
|
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(let_chains)]
|
||||
#![allow(irrefutable_let_patterns)]
|
||||
|
||||
fn main() {
|
||||
let first = Some(1);
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
#![feature(let_chains, let_else)]
|
||||
|
||||
fn main() {
|
||||
let opt = Some(1i32);
|
||||
|
||||
let Some(n) = opt else {
|
||||
return;
|
||||
};
|
||||
let Some(n) = opt && n == 1 else {
|
||||
//~^ ERROR a `&&` expression cannot be directly assigned in `let...else`
|
||||
//~| ERROR mismatched types
|
||||
//~| ERROR mismatched types
|
||||
return;
|
||||
};
|
||||
let Some(n) = opt && let another = n else {
|
||||
//~^ ERROR a `&&` expression cannot be directly assigned in `let...else`
|
||||
//~| ERROR `let` expressions are not supported here
|
||||
//~| ERROR mismatched types
|
||||
//~| ERROR mismatched types
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(n) = opt else {
|
||||
//~^ ERROR missing condition for `if` expression
|
||||
return;
|
||||
};
|
||||
if let Some(n) = opt && n == 1 else {
|
||||
//~^ ERROR missing condition for `if` expression
|
||||
return;
|
||||
};
|
||||
if let Some(n) = opt && let another = n else {
|
||||
//~^ ERROR missing condition for `if` expression
|
||||
return;
|
||||
};
|
||||
|
||||
{
|
||||
while let Some(n) = opt else {
|
||||
//~^ ERROR expected `{`, found keyword `else`
|
||||
return;
|
||||
};
|
||||
}
|
||||
{
|
||||
while let Some(n) = opt && n == 1 else {
|
||||
//~^ ERROR expected `{`, found keyword `else`
|
||||
return;
|
||||
};
|
||||
}
|
||||
{
|
||||
while let Some(n) = opt && let another = n else {
|
||||
//~^ ERROR expected `{`, found keyword `else`
|
||||
return;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
error: a `&&` expression cannot be directly assigned in `let...else`
|
||||
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:9:19
|
||||
|
|
||||
LL | let Some(n) = opt && n == 1 else {
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
help: wrap the expression in parentheses
|
||||
|
|
||||
LL | let Some(n) = (opt && n == 1) else {
|
||||
| + +
|
||||
|
||||
error: a `&&` expression cannot be directly assigned in `let...else`
|
||||
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:19
|
||||
|
|
||||
LL | let Some(n) = opt && let another = n else {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: wrap the expression in parentheses
|
||||
|
|
||||
LL | let Some(n) = (opt && let another = n) else {
|
||||
| + +
|
||||
|
||||
error: missing condition for `if` expression
|
||||
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:23:7
|
||||
|
|
||||
LL | if let Some(n) = opt else {
|
||||
| ^ expected if condition here
|
||||
|
||||
error: missing condition for `if` expression
|
||||
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:27:7
|
||||
|
|
||||
LL | if let Some(n) = opt && n == 1 else {
|
||||
| ^ expected if condition here
|
||||
|
||||
error: missing condition for `if` expression
|
||||
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:31:7
|
||||
|
|
||||
LL | if let Some(n) = opt && let another = n else {
|
||||
| ^ expected if condition here
|
||||
|
||||
error: expected `{`, found keyword `else`
|
||||
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:37:33
|
||||
|
|
||||
LL | while let Some(n) = opt else {
|
||||
| ----- ----------------- ^^^^ expected `{`
|
||||
| | |
|
||||
| | this `while` condition successfully parsed
|
||||
| while parsing the body of this `while` expression
|
||||
|
||||
error: expected `{`, found keyword `else`
|
||||
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:43:43
|
||||
|
|
||||
LL | while let Some(n) = opt && n == 1 else {
|
||||
| ----- --------------------------- ^^^^ expected `{`
|
||||
| | |
|
||||
| | this `while` condition successfully parsed
|
||||
| while parsing the body of this `while` expression
|
||||
|
||||
error: expected `{`, found keyword `else`
|
||||
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:49:52
|
||||
|
|
||||
LL | while let Some(n) = opt && let another = n else {
|
||||
| ----- ------------------------------------ ^^^^ expected `{`
|
||||
| | |
|
||||
| | this `while` condition successfully parsed
|
||||
| while parsing the body of this `while` expression
|
||||
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:26
|
||||
|
|
||||
LL | let Some(n) = opt && let another = n else {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly in conditions of `if` and `while` expressions
|
||||
= note: as well as when nested within `&&` and parentheses in those conditions
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:9:19
|
||||
|
|
||||
LL | let Some(n) = opt && n == 1 else {
|
||||
| ^^^ expected `bool`, found enum `Option`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found enum `Option<i32>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:9:9
|
||||
|
|
||||
LL | let Some(n) = opt && n == 1 else {
|
||||
| ^^^^^^^ ------------- this expression has type `bool`
|
||||
| |
|
||||
| expected `bool`, found enum `Option`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found enum `Option<_>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:19
|
||||
|
|
||||
LL | let Some(n) = opt && let another = n else {
|
||||
| ^^^ expected `bool`, found enum `Option`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found enum `Option<i32>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:9
|
||||
|
|
||||
LL | let Some(n) = opt && let another = n else {
|
||||
| ^^^^^^^ ---------------------- this expression has type `bool`
|
||||
| |
|
||||
| expected `bool`, found enum `Option`
|
||||
|
|
||||
= note: expected type `bool`
|
||||
found enum `Option<_>`
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
|
@ -0,0 +1,115 @@
|
|||
error: leading irrefutable pattern in let chain
|
||||
--> $DIR/irrefutable-lets.rs:13:8
|
||||
|
|
||||
LL | if let first = &opt && let Some(ref second) = first && let None = second.start {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/irrefutable-lets.rs:6:30
|
||||
|
|
||||
LL | #![cfg_attr(disallowed, deny(irrefutable_let_patterns))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: this pattern will always match
|
||||
= help: consider moving it outside of the construct
|
||||
|
||||
error: irrefutable `if let` patterns
|
||||
--> $DIR/irrefutable-lets.rs:19:8
|
||||
|
|
||||
LL | if let first = &opt && let (a, b) = (1, 2) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: these patterns will always match, so the `if let` is useless
|
||||
= help: consider replacing the `if let` with a `let`
|
||||
|
||||
error: leading irrefutable pattern in let chain
|
||||
--> $DIR/irrefutable-lets.rs:22:8
|
||||
|
|
||||
LL | if let first = &opt && let Some(ref second) = first && let None = second.start && let v = 0 {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this pattern will always match
|
||||
= help: consider moving it outside of the construct
|
||||
|
||||
error: trailing irrefutable pattern in let chain
|
||||
--> $DIR/irrefutable-lets.rs:22:87
|
||||
|
|
||||
LL | if let first = &opt && let Some(ref second) = first && let None = second.start && let v = 0 {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this pattern will always match
|
||||
= help: consider moving it into the body
|
||||
|
||||
error: trailing irrefutable patterns in let chain
|
||||
--> $DIR/irrefutable-lets.rs:26:37
|
||||
|
|
||||
LL | if let Some(ref first) = opt && let second = first && let _third = second {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: these patterns will always match
|
||||
= help: consider moving them into the body
|
||||
|
||||
error: leading irrefutable pattern in let chain
|
||||
--> $DIR/irrefutable-lets.rs:29:8
|
||||
|
|
||||
LL | if let Range { start: local_start, end: _ } = (None..Some(1)) && let None = local_start {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this pattern will always match
|
||||
= help: consider moving it outside of the construct
|
||||
|
||||
error: leading irrefutable pattern in let chain
|
||||
--> $DIR/irrefutable-lets.rs:32:8
|
||||
|
|
||||
LL | if let (a, b, c) = (Some(1), Some(1), Some(1)) && let None = Some(1) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this pattern will always match
|
||||
= help: consider moving it outside of the construct
|
||||
|
||||
error: leading irrefutable pattern in let chain
|
||||
--> $DIR/irrefutable-lets.rs:35:8
|
||||
|
|
||||
LL | if let first = &opt && let None = Some(1) {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this pattern will always match
|
||||
= help: consider moving it outside of the construct
|
||||
|
||||
error: irrefutable `let` patterns
|
||||
--> $DIR/irrefutable-lets.rs:44:28
|
||||
|
|
||||
LL | Some(ref first) if let second = first && let _third = second && let v = 4 + 4 => {},
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: these patterns will always match, so the `let` is useless
|
||||
= help: consider removing `let`
|
||||
|
||||
error: leading irrefutable pattern in let chain
|
||||
--> $DIR/irrefutable-lets.rs:50:28
|
||||
|
|
||||
LL | Some(ref first) if let Range { start: local_start, end: _ } = first
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this pattern will always match
|
||||
= help: consider moving it outside of the construct
|
||||
|
||||
error: irrefutable `while let` patterns
|
||||
--> $DIR/irrefutable-lets.rs:59:11
|
||||
|
|
||||
LL | while let first = &opt && let (a, b) = (1, 2) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: these patterns will always match, so the loop will never exit
|
||||
= help: consider instead using a `loop { ... }` with a `let` inside it
|
||||
|
||||
error: trailing irrefutable patterns in let chain
|
||||
--> $DIR/irrefutable-lets.rs:62:40
|
||||
|
|
||||
LL | while let Some(ref first) = opt && let second = first && let _third = second {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: these patterns will always match
|
||||
= help: consider moving them into the body
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
|
|
@ -1,35 +1,67 @@
|
|||
// check-pass
|
||||
// revisions: allowed disallowed
|
||||
//[allowed] check-pass
|
||||
|
||||
#![feature(if_let_guard, let_chains)]
|
||||
#![cfg_attr(allowed, allow(irrefutable_let_patterns))]
|
||||
#![cfg_attr(disallowed, deny(irrefutable_let_patterns))]
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
fn main() {
|
||||
let opt = Some(None..Some(1));
|
||||
|
||||
if let first = &opt && let Some(ref second) = first && let None = second.start {
|
||||
}
|
||||
if let Some(ref first) = opt && let second = first && let _third = second {
|
||||
}
|
||||
if let first = &opt && let Some(ref second) = first && let None = second.start {}
|
||||
//[disallowed]~^ ERROR leading irrefutable pattern in let chain
|
||||
|
||||
// No lint as the irrefutable pattern is surrounded by other stuff
|
||||
if 4 * 2 == 0 && let first = &opt && let Some(ref second) = first && let None = second.start {}
|
||||
|
||||
if let first = &opt && let (a, b) = (1, 2) {}
|
||||
//[disallowed]~^ ERROR irrefutable `if let` patterns
|
||||
|
||||
if let first = &opt && let Some(ref second) = first && let None = second.start && let v = 0 {}
|
||||
//[disallowed]~^ ERROR leading irrefutable pattern in let chain
|
||||
//[disallowed]~^^ ERROR trailing irrefutable pattern in let chain
|
||||
|
||||
if let Some(ref first) = opt && let second = first && let _third = second {}
|
||||
//[disallowed]~^ ERROR trailing irrefutable patterns in let chain
|
||||
|
||||
if let Range { start: local_start, end: _ } = (None..Some(1)) && let None = local_start {}
|
||||
//[disallowed]~^ ERROR leading irrefutable pattern in let chain
|
||||
|
||||
if let (a, b, c) = (Some(1), Some(1), Some(1)) && let None = Some(1) {}
|
||||
//[disallowed]~^ ERROR leading irrefutable pattern in let chain
|
||||
|
||||
if let first = &opt && let None = Some(1) {}
|
||||
//[disallowed]~^ ERROR leading irrefutable pattern in let chain
|
||||
|
||||
if let Some(ref first) = opt
|
||||
&& let Range { start: local_start, end: _ } = first
|
||||
&& let None = local_start {
|
||||
}
|
||||
|
||||
match opt {
|
||||
Some(ref first) if let second = first && let _third = second => {},
|
||||
Some(ref first) if let second = first && let _third = second && let v = 4 + 4 => {},
|
||||
//[disallowed]~^ ERROR irrefutable `let` patterns
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match opt {
|
||||
Some(ref first) if let Range { start: local_start, end: _ } = first
|
||||
//[disallowed]~^ ERROR leading irrefutable pattern in let chain
|
||||
&& let None = local_start => {},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
while let first = &opt && let Some(ref second) = first && let None = second.start {
|
||||
}
|
||||
while let Some(ref first) = opt && let second = first && let _third = second {
|
||||
}
|
||||
// No error, despite the prefix being irrefutable
|
||||
while let first = &opt && let Some(ref second) = first && let None = second.start {}
|
||||
|
||||
while let first = &opt && let (a, b) = (1, 2) {}
|
||||
//[disallowed]~^ ERROR irrefutable `while let` patterns
|
||||
|
||||
while let Some(ref first) = opt && let second = first && let _third = second {}
|
||||
//[disallowed]~^ ERROR trailing irrefutable patterns in let chain
|
||||
|
||||
while let Some(ref first) = opt
|
||||
&& let Range { start: local_start, end: _ } = first
|
||||
&& let None = local_start {
|
||||
|
|
Loading…
Add table
Reference in a new issue