Skip to content

Commit 345e149

Browse files
committed
Point at const definition when used instead of a binding in a let statement
After: ``` error[E0005]: refutable pattern in local binding --> $DIR/bad-pattern.rs:19:13 | LL | const PAT: u32 = 0; | -------------- missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable ... LL | let PAT = v1; | ^^^ | | | pattern `1_u32..=u32::MAX` not covered | help: introduce a variable instead: `PAT_var` | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `u32` ``` Before: ``` error[E0005]: refutable pattern in local binding --> $DIR/bad-pattern.rs:19:13 | LL | let PAT = v1; | ^^^ | | | pattern `1_u32..=u32::MAX` not covered | missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable | help: introduce a variable instead: `PAT_var` | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `u32` ```
1 parent e8c698b commit 345e149

File tree

18 files changed

+78
-28
lines changed

18 files changed

+78
-28
lines changed

compiler/rustc_middle/src/thir.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,7 @@ impl<'tcx> Pat<'tcx> {
640640
| Range(..)
641641
| Binding { subpattern: None, .. }
642642
| Constant { .. }
643+
| NamedConstant { .. }
643644
| Error(_) => {}
644645
AscribeUserType { subpattern, .. }
645646
| Binding { subpattern: Some(subpattern), .. }
@@ -788,6 +789,12 @@ pub enum PatKind<'tcx> {
788789
value: mir::Const<'tcx>,
789790
},
790791

792+
/// Same as `Constant`, but that came from a `const` that we can point at in diagnostics.
793+
NamedConstant {
794+
value: mir::Const<'tcx>,
795+
span: Span,
796+
},
797+
791798
/// Inline constant found while lowering a pattern.
792799
InlineConstant {
793800
/// [LocalDefId] of the constant, we need this so that we have a
@@ -1084,8 +1091,8 @@ mod size_asserts {
10841091
static_assert_size!(Block, 48);
10851092
static_assert_size!(Expr<'_>, 64);
10861093
static_assert_size!(ExprKind<'_>, 40);
1087-
static_assert_size!(Pat<'_>, 64);
1088-
static_assert_size!(PatKind<'_>, 48);
1094+
static_assert_size!(Pat<'_>, 72);
1095+
static_assert_size!(PatKind<'_>, 56);
10891096
static_assert_size!(Stmt<'_>, 48);
10901097
static_assert_size!(StmtKind<'_>, 48);
10911098
// tidy-alphabetical-end

compiler/rustc_middle/src/thir/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
246246
visitor.visit_pat(&subpattern.pattern);
247247
}
248248
}
249-
Constant { value: _ } => {}
249+
Constant { value: _ } | NamedConstant { value: _, span: _ } => {}
250250
InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern),
251251
Range(_) => {}
252252
Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {

compiler/rustc_mir_build/src/build/custom/parse/instruction.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,9 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
144144
let mut targets = Vec::new();
145145
for arm in rest {
146146
let arm = &self.thir[*arm];
147-
let PatKind::Constant { value } = arm.pattern.kind else {
147+
let (PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ }) =
148+
arm.pattern.kind
149+
else {
148150
return Err(ParseError {
149151
span: arm.pattern.span,
150152
item_description: format!("{:?}", arm.pattern.kind),

compiler/rustc_mir_build/src/build/matches/match_pair.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,9 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
129129
}
130130
}
131131

132-
PatKind::Constant { value } => TestCase::Constant { value },
132+
PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ } => {
133+
TestCase::Constant { value }
134+
}
133135

134136
PatKind::AscribeUserType {
135137
ascription: thir::Ascription { ref annotation, variance },

compiler/rustc_mir_build/src/build/matches/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
882882
}
883883

884884
PatKind::Constant { .. }
885+
| PatKind::NamedConstant { .. }
885886
| PatKind::Range { .. }
886887
| PatKind::Wild
887888
| PatKind::Never

compiler/rustc_mir_build/src/check_unsafety.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
316316
PatKind::Binding { .. }
317317
// match is conditional on having this value
318318
| PatKind::Constant { .. }
319+
| PatKind::NamedConstant { .. }
319320
| PatKind::Variant { .. }
320321
| PatKind::Leaf { .. }
321322
| PatKind::Deref { .. }

compiler/rustc_mir_build/src/errors.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -860,8 +860,10 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
860860
pub(crate) uncovered: Uncovered,
861861
#[subdiagnostic]
862862
pub(crate) inform: Option<Inform>,
863+
#[label(mir_build_confused)]
864+
pub(crate) interpreted_as_const: Option<Span>,
863865
#[subdiagnostic]
864-
pub(crate) interpreted_as_const: Option<InterpretedAsConst>,
866+
pub(crate) interpreted_as_const_sugg: Option<InterpretedAsConst>,
865867
#[subdiagnostic]
866868
pub(crate) adt_defined_here: Option<AdtDefinedHere<'tcx>>,
867869
#[note(mir_build_privately_uninhabited)]
@@ -913,7 +915,6 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> {
913915
code = "{variable}_var",
914916
applicability = "maybe-incorrect"
915917
)]
916-
#[label(mir_build_confused)]
917918
pub(crate) struct InterpretedAsConst {
918919
#[primary_span]
919920
pub(crate) span: Span,

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -668,8 +668,20 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
668668
let mut let_suggestion = None;
669669
let mut misc_suggestion = None;
670670
let mut interpreted_as_const = None;
671+
let mut interpreted_as_const_sugg = None;
671672

672-
if let PatKind::Constant { .. }
673+
if let PatKind::NamedConstant { span, .. }
674+
| PatKind::AscribeUserType {
675+
subpattern: box Pat { kind: PatKind::NamedConstant { span, .. }, .. },
676+
..
677+
} = pat.kind
678+
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
679+
{
680+
// When we encounter a constant as the binding name, point at the `const` definition.
681+
interpreted_as_const = Some(span);
682+
interpreted_as_const_sugg =
683+
Some(InterpretedAsConst { span: pat.span, variable: snippet });
684+
} else if let PatKind::Constant { .. }
673685
| PatKind::AscribeUserType {
674686
subpattern: box Pat { kind: PatKind::Constant { .. }, .. },
675687
..
@@ -683,7 +695,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
683695
start_span: pat.span.shrink_to_lo(),
684696
});
685697
} else if snippet.chars().all(|c| c.is_alphanumeric() || c == '_') {
686-
interpreted_as_const =
698+
interpreted_as_const = Some(pat.span);
699+
interpreted_as_const_sugg =
687700
Some(InterpretedAsConst { span: pat.span, variable: snippet });
688701
}
689702
}
@@ -733,6 +746,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
733746
uncovered: Uncovered::new(pat.span, &cx, witnesses),
734747
inform,
735748
interpreted_as_const,
749+
interpreted_as_const_sugg,
736750
witness_1_is_privately_uninhabited,
737751
_p: (),
738752
pattern_ty,

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
157157
}
158158
kind => (kind, None, None),
159159
};
160-
let value = if let PatKind::Constant { value } = kind {
160+
let value = if let PatKind::Constant { value }
161+
| PatKind::NamedConstant { value, span: _ } = kind
162+
{
161163
value
162164
} else {
163165
let msg = format!(
@@ -560,9 +562,15 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
560562
_ => return pat_from_kind(self.lower_variant_or_leaf(res, id, span, ty, vec![])),
561563
};
562564

565+
// HERE
563566
let args = self.typeck_results.node_args(id);
564567
let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
565-
let pattern = self.const_to_pat(c, ty, id, span);
568+
let def_span = self.tcx.def_span(def_id);
569+
let mut pattern = self.const_to_pat(c, ty, id, span);
570+
if let PatKind::Constant { value } = pattern.kind {
571+
pattern.kind = PatKind::NamedConstant { value, span: def_span };
572+
}
573+
tracing::info!("pattern {pattern:#?} {c:?} {ty:?} {id:?}");
566574

567575
if !is_associated_const {
568576
return pattern;

compiler/rustc_mir_build/src/thir/print.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
702702
self.print_pat(subpattern, depth_lvl + 2);
703703
print_indented!(self, "}", depth_lvl + 1);
704704
}
705-
PatKind::Constant { value } => {
705+
PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ } => {
706706
print_indented!(self, "Constant {", depth_lvl + 1);
707707
print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
708708
print_indented!(self, "}", depth_lvl + 1);

compiler/rustc_pattern_analysis/src/rustc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
536536
),
537537
}
538538
}
539-
PatKind::Constant { value } => {
539+
PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ } => {
540540
match ty.kind() {
541541
ty::Bool => {
542542
ctor = match value.try_eval_bool(cx.tcx, cx.param_env) {

compiler/rustc_ty_utils/src/consts.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,9 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
370370
}
371371

372372
match pat.kind {
373-
thir::PatKind::Constant { value } => value.has_non_region_param(),
373+
thir::PatKind::Constant { value } | thir::PatKind::NamedConstant { value, span: _ } => {
374+
value.has_non_region_param()
375+
}
374376
thir::PatKind::Range(box thir::PatRange { lo, hi, .. }) => {
375377
lo.has_non_region_param() || hi.has_non_region_param()
376378
}

tests/ui/closures/2229_closure_analysis/bad-pattern.stderr

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,13 @@ LL | if let Refutable::A = v3 { todo!() };
9797
error[E0005]: refutable pattern in local binding
9898
--> $DIR/bad-pattern.rs:19:13
9999
|
100+
LL | const PAT: u32 = 0;
101+
| -------------- missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable
102+
...
100103
LL | let PAT = v1;
101104
| ^^^
102105
| |
103106
| pattern `1_u32..=u32::MAX` not covered
104-
| missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable
105107
| help: introduce a variable instead: `PAT_var`
106108
|
107109
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
mod foo {
22
pub const b: u8 = 2;
3+
//~^ missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
34
pub const d: u8 = 2;
5+
//~^ missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
46
}
57

68
use foo::b as c;
79
use foo::d;
810

911
const a: u8 = 2;
12+
//~^ missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
1013

1114
fn main() {
1215
let a = 4;
1316
//~^ ERROR refutable pattern in local binding
1417
//~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
15-
//~| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
1618
//~| HELP introduce a variable instead
1719
let c = 4;
1820
//~^ ERROR refutable pattern in local binding
1921
//~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
20-
//~| missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
2122
//~| HELP introduce a variable instead
2223
let d = 4;
2324
//~^ ERROR refutable pattern in local binding
2425
//~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
25-
//~| missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
2626
//~| HELP introduce a variable instead
2727
fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115).
2828
}

tests/ui/consts/const-pattern-irrefutable.stderr

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,45 @@
11
error[E0005]: refutable pattern in local binding
2-
--> $DIR/const-pattern-irrefutable.rs:12:9
2+
--> $DIR/const-pattern-irrefutable.rs:15:9
33
|
4+
LL | const a: u8 = 2;
5+
| ----------- missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
6+
...
47
LL | let a = 4;
58
| ^
69
| |
710
| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
8-
| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
911
| help: introduce a variable instead: `a_var`
1012
|
1113
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
1214
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
1315
= note: the matched value is of type `u8`
1416

1517
error[E0005]: refutable pattern in local binding
16-
--> $DIR/const-pattern-irrefutable.rs:17:9
18+
--> $DIR/const-pattern-irrefutable.rs:19:9
1719
|
20+
LL | pub const b: u8 = 2;
21+
| --------------- missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
22+
...
1823
LL | let c = 4;
1924
| ^
2025
| |
2126
| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
22-
| missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
2327
| help: introduce a variable instead: `c_var`
2428
|
2529
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
2630
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
2731
= note: the matched value is of type `u8`
2832

2933
error[E0005]: refutable pattern in local binding
30-
--> $DIR/const-pattern-irrefutable.rs:22:9
34+
--> $DIR/const-pattern-irrefutable.rs:23:9
3135
|
36+
LL | pub const d: u8 = 2;
37+
| --------------- missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
38+
...
3239
LL | let d = 4;
3340
| ^
3441
| |
3542
| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
36-
| missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
3743
| help: introduce a variable instead: `d_var`
3844
|
3945
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant

tests/ui/mir/issue-112269.stderr

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
error[E0005]: refutable pattern in local binding
22
--> $DIR/issue-112269.rs:3:9
33
|
4+
LL | const x: i32 = 4;
5+
| ------------ missing patterns are not covered because `x` is interpreted as a constant pattern, not a new variable
46
LL | let x: i32 = 3;
57
| ^
68
| |
79
| patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
8-
| missing patterns are not covered because `x` is interpreted as a constant pattern, not a new variable
910
| help: introduce a variable instead: `x_var`
1011
|
1112
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
@@ -15,11 +16,12 @@ LL | let x: i32 = 3;
1516
error[E0005]: refutable pattern in local binding
1617
--> $DIR/issue-112269.rs:7:9
1718
|
19+
LL | const y: i32 = 3;
20+
| ------------ missing patterns are not covered because `y` is interpreted as a constant pattern, not a new variable
1821
LL | let y = 4;
1922
| ^
2023
| |
2124
| patterns `i32::MIN..=2_i32` and `4_i32..=i32::MAX` not covered
22-
| missing patterns are not covered because `y` is interpreted as a constant pattern, not a new variable
2325
| help: introduce a variable instead: `y_var`
2426
|
2527
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant

tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ fn main() {
22
let A = 3;
33
//~^ ERROR refutable pattern in local binding
44
//~| patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
5-
//~| missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
65
//~| HELP introduce a variable instead
76
//~| SUGGESTION A_var
87

98
const A: i32 = 2;
9+
//~^ missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
1010
}

tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ LL | let A = 3;
55
| ^
66
| |
77
| patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
8-
| missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
98
| help: introduce a variable instead: `A_var`
9+
...
10+
LL | const A: i32 = 2;
11+
| ------------ missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
1012
|
1113
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
1214
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html

0 commit comments

Comments
 (0)