Skip to content

Commit 05b8f40

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

File tree

6 files changed

+56
-233
lines changed

6 files changed

+56
-233
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+
#[expect(irrefutable_let_patterns)]
8686
if let max_align = tcx.sess.target.max_reliable_alignment()
8787
&& max_align < Align::MAX
8888
{
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//@ check-pass
2+
//@ edition:2024
3+
4+
#![allow(unused)]
5+
6+
enum Outer {
7+
Middle(Middle),
8+
}
9+
enum Middle {
10+
Inner(Inner),
11+
Other(bool),
12+
}
13+
struct Inner {
14+
id: u32,
15+
}
16+
17+
fn test_1(outer: Outer) {
18+
if let Outer::Middle(middle) = outer
19+
&& let Middle::Inner(internal) = middle
20+
&& let Inner { id } = internal
21+
{
22+
println!("{id}");
23+
}
24+
}
25+
26+
fn test_2() -> usize { 42 }
27+
28+
fn test_3() -> Outer {
29+
Outer::Middle(Middle::Inner(Inner { id: 1 }))
30+
}
31+
32+
fn main() {
33+
if let mx = test_2() && mx < usize::MAX {
34+
println!("{mx}");
35+
} else if let x = test_2() && x > 0 {
36+
println!("{x}");
37+
}
38+
39+
while let Outer::Middle(middle) = test_3()
40+
&& let Middle::Inner(inner) = middle
41+
&& let Inner { id } = inner
42+
&& id > 5
43+
{
44+
println!("{id}");
45+
}
46+
}

tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr

Lines changed: 0 additions & 133 deletions
This file was deleted.

tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,29 @@
1-
//@ revisions: allowed disallowed
2-
//@[allowed] check-pass
1+
//@ check-pass
32
//@ edition: 2024
43

54
#![feature(if_let_guard)]
6-
#![cfg_attr(allowed, allow(irrefutable_let_patterns))]
7-
#![cfg_attr(disallowed, deny(irrefutable_let_patterns))]
85

96
use std::ops::Range;
107

118
fn main() {
129
let opt = Some(None..Some(1));
1310

1411
if let first = &opt && let Some(second) = first && let None = second.start {}
15-
//[disallowed]~^ ERROR leading irrefutable pattern in let chain
1612

1713
// No lint as the irrefutable pattern is surrounded by other stuff
1814
if 4 * 2 == 0 && let first = &opt && let Some(second) = first && let None = second.start {}
1915

2016
if let first = &opt && let (a, b) = (1, 2) {}
21-
//[disallowed]~^ ERROR irrefutable `if let` patterns
2217

2318
if let first = &opt && let Some(second) = first && let None = second.start && let v = 0 {}
24-
//[disallowed]~^ ERROR leading irrefutable pattern in let chain
25-
//[disallowed]~^^ ERROR trailing irrefutable pattern in let chain
2619

2720
if let Some(ref first) = opt && let second = first && let _third = second {}
28-
//[disallowed]~^ ERROR trailing irrefutable patterns in let chain
2921

3022
if let Range { start: local_start, end: _ } = (None..Some(1)) && let None = local_start {}
31-
//[disallowed]~^ ERROR leading irrefutable pattern in let chain
3223

3324
if let (a, b, c) = (Some(1), Some(1), Some(1)) && let None = Some(1) {}
34-
//[disallowed]~^ ERROR leading irrefutable pattern in let chain
3525

3626
if let first = &opt && let None = Some(1) {}
37-
//[disallowed]~^ ERROR leading irrefutable pattern in let chain
3827

3928
if let Some(ref first) = opt
4029
&& let Range { start: local_start, end: _ } = first
@@ -43,7 +32,6 @@ fn main() {
4332

4433
match opt {
4534
Some(ref first) if let second = first && let _third = second && let v = 4 + 4 => {},
46-
//[disallowed]~^ ERROR irrefutable `if let` guard patterns
4735
_ => {}
4836
}
4937

@@ -58,7 +46,6 @@ fn main() {
5846
match opt {
5947
Some(ref first) if let Range { start: Some(_), end: local_end } = first
6048
&& let v = local_end && let w = v => {},
61-
//[disallowed]~^ ERROR trailing irrefutable patterns in let chain
6249
_ => {}
6350
}
6451

@@ -67,15 +54,13 @@ fn main() {
6754
while let first = &opt && let Some(second) = first && let None = second.start {}
6855

6956
while let first = &opt && let (a, b) = (1, 2) {}
70-
//[disallowed]~^ ERROR irrefutable `while let` patterns
7157

7258
while let Some(ref first) = opt && let second = first && let _third = second {}
73-
//[disallowed]~^ ERROR trailing irrefutable patterns in let chain
7459

7560
while let Some(ref first) = opt
7661
&& let Range { start: local_start, end: _ } = first
77-
&& let None = local_start {
78-
}
62+
&& let None = local_start
63+
{}
7964

8065
// No error. An extra nesting level would be required for the `else if`.
8166
if opt == Some(None..None) {
@@ -86,13 +71,11 @@ fn main() {
8671
if opt == Some(None..None) {
8772
} else if opt.is_some()
8873
&& let x = &opt
89-
//[disallowed]~^ ERROR trailing irrefutable pattern in let chain
9074
{}
9175

9276
if opt == Some(None..None) {
9377
} else {
9478
if let x = opt.clone().map(|_| 1)
95-
//[disallowed]~^ ERROR leading irrefutable pattern in let chain
9679
&& x == Some(1)
9780
{}
9881
}

0 commit comments

Comments
 (0)