Skip to content

Commit b284c6b

Browse files
Not linting irrefutable_let_patterns on let chains
1 parent 9f2ef0f commit b284c6b

File tree

8 files changed

+202
-234
lines changed

8 files changed

+202
-234
lines changed

compiler/rustc_mir_build/src/errors.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -765,22 +765,6 @@ pub(crate) struct LowerRangeBoundMustBeLessThanUpper {
765765
pub(crate) span: Span,
766766
}
767767

768-
#[derive(LintDiagnostic)]
769-
#[diag(mir_build_leading_irrefutable_let_patterns)]
770-
#[note]
771-
#[help]
772-
pub(crate) struct LeadingIrrefutableLetPatterns {
773-
pub(crate) count: usize,
774-
}
775-
776-
#[derive(LintDiagnostic)]
777-
#[diag(mir_build_trailing_irrefutable_let_patterns)]
778-
#[note]
779-
#[help]
780-
pub(crate) struct TrailingIrrefutableLetPatterns {
781-
pub(crate) count: usize,
782-
}
783-
784768
#[derive(LintDiagnostic)]
785769
#[diag(mir_build_bindings_with_variant_name, code = E0170)]
786770
pub(crate) struct BindingsWithVariantName {

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

Lines changed: 6 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,9 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> {
168168
{
169169
let mut chain_refutabilities = Vec::new();
170170
let Ok(()) = self.visit_land(ex, &mut chain_refutabilities) else { return };
171-
// If at least one of the operands is a `let ... = ...`.
172-
if chain_refutabilities.iter().any(|x| x.is_some()) {
173-
self.check_let_chain(chain_refutabilities, ex.span);
171+
// For let chains, don't lint.
172+
if let [Some((_, refutability))] = chain_refutabilities[..] {
173+
self.check_single_let(refutability, ex.span);
174174
}
175175
return;
176176
}
@@ -562,73 +562,16 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
562562
}
563563

564564
#[instrument(level = "trace", skip(self))]
565-
fn check_let_chain(
566-
&mut self,
567-
chain_refutabilities: Vec<Option<(Span, RefutableFlag)>>,
568-
whole_chain_span: Span,
569-
) {
565+
fn check_single_let(&mut self, refutability: RefutableFlag, whole_chain_span: Span) {
570566
assert!(self.let_source != LetSource::None);
571-
572-
if chain_refutabilities.iter().all(|r| matches!(*r, Some((_, Irrefutable)))) {
573-
// The entire chain is made up of irrefutable `let` statements
567+
if matches!(refutability, Irrefutable) {
574568
report_irrefutable_let_patterns(
575569
self.tcx,
576570
self.lint_level,
577571
self.let_source,
578-
chain_refutabilities.len(),
572+
1,
579573
whole_chain_span,
580574
);
581-
return;
582-
}
583-
584-
if let Some(until) =
585-
chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, Irrefutable))))
586-
&& until > 0
587-
{
588-
// The chain has a non-zero prefix of irrefutable `let` statements.
589-
590-
// Check if the let source is while, for there is no alternative place to put a prefix,
591-
// and we shouldn't lint.
592-
// For let guards inside a match, prefixes might use bindings of the match pattern,
593-
// so can't always be moved out.
594-
// For `else if let`, an extra indentation level would be required to move the bindings.
595-
// FIXME: Add checking whether the bindings are actually used in the prefix,
596-
// and lint if they are not.
597-
if !matches!(
598-
self.let_source,
599-
LetSource::WhileLet | LetSource::IfLetGuard | LetSource::ElseIfLet
600-
) {
601-
// Emit the lint
602-
let prefix = &chain_refutabilities[..until];
603-
let span_start = prefix[0].unwrap().0;
604-
let span_end = prefix.last().unwrap().unwrap().0;
605-
let span = span_start.to(span_end);
606-
let count = prefix.len();
607-
self.tcx.emit_node_span_lint(
608-
IRREFUTABLE_LET_PATTERNS,
609-
self.lint_level,
610-
span,
611-
LeadingIrrefutableLetPatterns { count },
612-
);
613-
}
614-
}
615-
616-
if let Some(from) =
617-
chain_refutabilities.iter().rposition(|r| !matches!(*r, Some((_, Irrefutable))))
618-
&& from != (chain_refutabilities.len() - 1)
619-
{
620-
// The chain has a non-empty suffix of irrefutable `let` statements
621-
let suffix = &chain_refutabilities[from + 1..];
622-
let span_start = suffix[0].unwrap().0;
623-
let span_end = suffix.last().unwrap().unwrap().0;
624-
let span = span_start.to(span_end);
625-
let count = suffix.len();
626-
self.tcx.emit_node_span_lint(
627-
IRREFUTABLE_LET_PATTERNS,
628-
self.lint_level,
629-
span,
630-
TrailingIrrefutableLetPatterns { count },
631-
);
632575
}
633576
}
634577

compiler/rustc_mir_transform/src/check_alignment.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ fn insert_alignment_check<'tcx>(
8282

8383
// If this target does not have reliable alignment, further limit the mask by anding it with
8484
// the mask for the highest reliable alignment.
85-
#[allow(irrefutable_let_patterns)]
85+
#[cfg_attr(bootstrap, expect(irrefutable_let_patterns))]
8686
if let max_align = tcx.sess.target.max_reliable_alignment()
8787
&& max_align < Align::MAX
8888
{

src/tools/miri/src/shims/foreign_items.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
900900
// Fallback to shims in submodules.
901901
_ => {
902902
// Math shims
903-
#[expect(irrefutable_let_patterns)]
903+
#[cfg_attr(bootstrap, expect(irrefutable_let_patterns))]
904904
if let res = shims::math::EvalContextExt::emulate_foreign_item_inner(
905905
this, link_name, abi, args, dest,
906906
)? && !matches!(res, EmulateItemResult::NotSupported)
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
//@ edition: 2024
2+
//@ check-pass
3+
4+
#![feature(if_let_guard)]
5+
6+
use std::ops::Range;
7+
8+
fn main() {
9+
let opt = Some(None..Some(1));
10+
11+
if let first = &opt {}
12+
//~^ WARN irrefutable `if let` pattern
13+
14+
if let first = &opt
15+
&& let Some(second) = first
16+
{}
17+
18+
if let first = &opt
19+
&& let (a, b) = (1, 2)
20+
{}
21+
22+
if let first = &opt
23+
&& let None = Some(1)
24+
{}
25+
26+
if 4 * 2 == 0
27+
&& let first = &opt
28+
{}
29+
30+
if let first = &opt
31+
&& let Some(second) = first
32+
&& let None = second.start
33+
&& let v = 0
34+
{}
35+
36+
if let Some(ref first) = opt
37+
&& let second = first
38+
&& let _third = second
39+
{}
40+
41+
if let Range { start: local_start, end: _ } = (None..Some(1))
42+
&& let None = local_start
43+
{}
44+
45+
if let Range { start: local_start, end: _ } = (None..Some(1)) {}
46+
//~^ WARN irrefutable `if let` pattern
47+
48+
if let (a, b, c) = (Some(1), Some(1), Some(1)) {}
49+
//~^ WARN irrefutable `if let` pattern
50+
51+
if let (a, b, c) = (Some(1), Some(1), Some(1))
52+
&& let None = Some(1)
53+
{}
54+
55+
if let Some(ref first) = opt
56+
&& let Range { start: local_start, end: _ } = first
57+
&& let None = local_start
58+
{}
59+
60+
match opt {
61+
Some(ref first) if let second = first => {}
62+
//~^ WARN irrefutable `if let` guard pattern
63+
_ => {}
64+
}
65+
66+
match opt {
67+
Some(ref first)
68+
if let second = first
69+
&& let _third = second
70+
&& let v = 4 + 4 => {}
71+
_ => {}
72+
}
73+
74+
match opt {
75+
Some(ref first)
76+
if let Range { start: local_start, end: _ } = first
77+
&& let None = local_start => {}
78+
_ => {}
79+
}
80+
81+
match opt {
82+
Some(ref first)
83+
if let Range { start: Some(_), end: local_end } = first
84+
&& let v = local_end
85+
&& let w = v => {}
86+
_ => {}
87+
}
88+
89+
while let first = &opt {}
90+
//~^ WARN irrefutable `while let` pattern
91+
92+
while let first = &opt
93+
&& let (a, b) = (1, 2)
94+
{}
95+
96+
while let first = &opt
97+
&& let Some(second) = first
98+
&& let None = second.start
99+
{}
100+
101+
while let Some(ref first) = opt
102+
&& let second = first
103+
&& let _third = second
104+
{}
105+
106+
while let Some(ref first) = opt
107+
&& let Range { start: local_start, end: _ } = first
108+
&& let None = local_start
109+
{}
110+
111+
if opt == Some(None..None) {
112+
} else if let x = opt.clone().map(|_| 1) {
113+
//~^ WARN irrefutable `if let` pattern
114+
}
115+
116+
if opt == Some(None..None) {
117+
} else if let x = opt.clone().map(|_| 1)
118+
&& x == Some(1)
119+
{
120+
}
121+
122+
if opt == Some(None..None) {
123+
} else if opt.is_some()
124+
&& let x = &opt
125+
{
126+
}
127+
128+
if opt == Some(None..None) {
129+
} else {
130+
if let x = opt.clone().map(|_| 1)
131+
&& x == Some(1)
132+
{}
133+
}
134+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
warning: irrefutable `if let` pattern
2+
--> $DIR/irrefutable-in-let-chains.rs:11:8
3+
|
4+
LL | if let first = &opt {}
5+
| ^^^^^^^^^^^^^^^^
6+
|
7+
= note: this pattern will always match, so the `if let` is useless
8+
= help: consider replacing the `if let` with a `let`
9+
= note: `#[warn(irrefutable_let_patterns)]` on by default
10+
11+
warning: irrefutable `if let` pattern
12+
--> $DIR/irrefutable-in-let-chains.rs:45:8
13+
|
14+
LL | if let Range { start: local_start, end: _ } = (None..Some(1)) {}
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
|
17+
= note: this pattern will always match, so the `if let` is useless
18+
= help: consider replacing the `if let` with a `let`
19+
20+
warning: irrefutable `if let` pattern
21+
--> $DIR/irrefutable-in-let-chains.rs:48:8
22+
|
23+
LL | if let (a, b, c) = (Some(1), Some(1), Some(1)) {}
24+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
25+
|
26+
= note: this pattern will always match, so the `if let` is useless
27+
= help: consider replacing the `if let` with a `let`
28+
29+
warning: irrefutable `if let` guard pattern
30+
--> $DIR/irrefutable-in-let-chains.rs:61:28
31+
|
32+
LL | Some(ref first) if let second = first => {}
33+
| ^^^^^^^^^^^^^^^^^^
34+
|
35+
= note: this pattern will always match, so the guard is useless
36+
= help: consider removing the guard and adding a `let` inside the match arm
37+
38+
warning: irrefutable `while let` pattern
39+
--> $DIR/irrefutable-in-let-chains.rs:89:11
40+
|
41+
LL | while let first = &opt {}
42+
| ^^^^^^^^^^^^^^^^
43+
|
44+
= note: this pattern will always match, so the loop will never exit
45+
= help: consider instead using a `loop { ... }` with a `let` inside it
46+
47+
warning: irrefutable `if let` pattern
48+
--> $DIR/irrefutable-in-let-chains.rs:112:15
49+
|
50+
LL | } else if let x = opt.clone().map(|_| 1) {
51+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
52+
|
53+
= note: this pattern will always match, so the `if let` is useless
54+
= help: consider replacing the `if let` with a `let`
55+
56+
warning: 6 warnings emitted
57+

0 commit comments

Comments
 (0)