Rollup merge of #132708 - estebank:const-as-binding, r=Nadrieril

Point at `const` definition when used instead of a binding in a `let` statement

Modify `PatKind::InlineConstant` to be `ExpandedConstant` standing in not only for inline `const` blocks but also for `const` items. This allows us to track named `const`s used in patterns when the pattern is a single binding. When we detect that there is a refutable pattern involving a `const` that could have been a binding instead, we point at the `const` item, and suggest renaming. We do this for both `let` bindings and `match` expressions missing a catch-all arm if there's at least one single binding pattern referenced.

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
   |
   = 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`
help: introduce a variable instead
   |
LL |         let PAT_var = v1;
   |             ~~~~~~~
```

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`
```

CC #132582.
This commit is contained in:
Matthias Krüger 2024-11-20 20:10:12 +01:00 committed by GitHub
commit 7fc2b33722
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 365 additions and 94 deletions

View File

@ -645,7 +645,7 @@ impl<'tcx> Pat<'tcx> {
| Binding { subpattern: Some(subpattern), .. } | Binding { subpattern: Some(subpattern), .. }
| Deref { subpattern } | Deref { subpattern }
| DerefPattern { subpattern, .. } | DerefPattern { subpattern, .. }
| InlineConstant { subpattern, .. } => subpattern.walk_(it), | ExpandedConstant { subpattern, .. } => subpattern.walk_(it),
Leaf { subpatterns } | Variant { subpatterns, .. } => { Leaf { subpatterns } | Variant { subpatterns, .. } => {
subpatterns.iter().for_each(|field| field.pattern.walk_(it)) subpatterns.iter().for_each(|field| field.pattern.walk_(it))
} }
@ -788,12 +788,17 @@ pub enum PatKind<'tcx> {
value: mir::Const<'tcx>, value: mir::Const<'tcx>,
}, },
/// Inline constant found while lowering a pattern. /// Pattern obtained by converting a constant (inline or named) to its pattern
InlineConstant { /// representation using `const_to_pat`.
/// [LocalDefId] of the constant, we need this so that we have a ExpandedConstant {
/// [DefId] of the constant, we need this so that we have a
/// reference that can be used by unsafety checking to visit nested /// reference that can be used by unsafety checking to visit nested
/// unevaluated constants. /// unevaluated constants and for diagnostics. If the `DefId` doesn't
def: LocalDefId, /// correspond to a local crate, it points at the `const` item.
def_id: DefId,
/// If `false`, then `def_id` points at a `const` item, otherwise it
/// corresponds to a local inline const.
is_inline: bool,
/// If the inline constant is used in a range pattern, this subpattern /// If the inline constant is used in a range pattern, this subpattern
/// represents the range (if both ends are inline constants, there will /// represents the range (if both ends are inline constants, there will
/// be multiple InlineConstant wrappers). /// be multiple InlineConstant wrappers).

View File

@ -247,7 +247,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
} }
} }
Constant { value: _ } => {} Constant { value: _ } => {}
InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern), ExpandedConstant { def_id: _, is_inline: _, subpattern } => visitor.visit_pat(subpattern),
Range(_) => {} Range(_) => {}
Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
for subpattern in prefix.iter() { for subpattern in prefix.iter() {

View File

@ -144,12 +144,20 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
let mut targets = Vec::new(); let mut targets = Vec::new();
for arm in rest { for arm in rest {
let arm = &self.thir[*arm]; let arm = &self.thir[*arm];
let PatKind::Constant { value } = arm.pattern.kind else { let value = match arm.pattern.kind {
return Err(ParseError { PatKind::Constant { value } => value,
span: arm.pattern.span, PatKind::ExpandedConstant { ref subpattern, def_id: _, is_inline: false }
item_description: format!("{:?}", arm.pattern.kind), if let PatKind::Constant { value } = subpattern.kind =>
expected: "constant pattern".to_string(), {
}); value
}
_ => {
return Err(ParseError {
span: arm.pattern.span,
item_description: format!("{:?}", arm.pattern.kind),
expected: "constant pattern".to_string(),
});
}
}; };
values.push(value.eval_bits(self.tcx, self.typing_env)); values.push(value.eval_bits(self.tcx, self.typing_env));
targets.push(self.parse_block(arm.body)?); targets.push(self.parse_block(arm.body)?);

View File

@ -162,7 +162,11 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
TestCase::Irrefutable { ascription: None, binding } TestCase::Irrefutable { ascription: None, binding }
} }
PatKind::InlineConstant { subpattern: ref pattern, def, .. } => { PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => {
subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx));
default_irrefutable()
}
PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => {
// Apply a type ascription for the inline constant to the value at `match_pair.place` // Apply a type ascription for the inline constant to the value at `match_pair.place`
let ascription = place.map(|source| { let ascription = place.map(|source| {
let span = pattern.span; let span = pattern.span;
@ -173,7 +177,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
}) })
.args; .args;
let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf( let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
def.to_def_id(), def_id,
ty::UserArgs { args, user_self_ty: None }, ty::UserArgs { args, user_self_ty: None },
)); ));
let annotation = ty::CanonicalUserTypeAnnotation { let annotation = ty::CanonicalUserTypeAnnotation {

View File

@ -917,7 +917,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.visit_primary_bindings(subpattern, subpattern_user_ty, f) self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
} }
PatKind::InlineConstant { ref subpattern, .. } => { PatKind::ExpandedConstant { ref subpattern, .. } => {
self.visit_primary_bindings(subpattern, pattern_user_ty, f) self.visit_primary_bindings(subpattern, pattern_user_ty, f)
} }

View File

@ -332,7 +332,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
PatKind::Wild | PatKind::Wild |
// these just wrap other patterns, which we recurse on below. // these just wrap other patterns, which we recurse on below.
PatKind::Or { .. } | PatKind::Or { .. } |
PatKind::InlineConstant { .. } | PatKind::ExpandedConstant { .. } |
PatKind::AscribeUserType { .. } | PatKind::AscribeUserType { .. } |
PatKind::Error(_) => {} PatKind::Error(_) => {}
} }
@ -386,8 +386,12 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
visit::walk_pat(self, pat); visit::walk_pat(self, pat);
self.inside_adt = old_inside_adt; self.inside_adt = old_inside_adt;
} }
PatKind::InlineConstant { def, .. } => { PatKind::ExpandedConstant { def_id, is_inline, .. } => {
self.visit_inner_body(*def); if let Some(def) = def_id.as_local()
&& *is_inline
{
self.visit_inner_body(def);
}
visit::walk_pat(self, pat); visit::walk_pat(self, pat);
} }
_ => { _ => {

View File

@ -860,8 +860,10 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
pub(crate) uncovered: Uncovered, pub(crate) uncovered: Uncovered,
#[subdiagnostic] #[subdiagnostic]
pub(crate) inform: Option<Inform>, pub(crate) inform: Option<Inform>,
#[label(mir_build_confused)]
pub(crate) interpreted_as_const: Option<Span>,
#[subdiagnostic] #[subdiagnostic]
pub(crate) interpreted_as_const: Option<InterpretedAsConst>, pub(crate) interpreted_as_const_sugg: Option<InterpretedAsConst>,
#[subdiagnostic] #[subdiagnostic]
pub(crate) adt_defined_here: Option<AdtDefinedHere<'tcx>>, pub(crate) adt_defined_here: Option<AdtDefinedHere<'tcx>>,
#[note(mir_build_privately_uninhabited)] #[note(mir_build_privately_uninhabited)]
@ -911,9 +913,9 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> {
#[suggestion( #[suggestion(
mir_build_interpreted_as_const, mir_build_interpreted_as_const,
code = "{variable}_var", code = "{variable}_var",
applicability = "maybe-incorrect" applicability = "maybe-incorrect",
style = "verbose"
)] )]
#[label(mir_build_confused)]
pub(crate) struct InterpretedAsConst { pub(crate) struct InterpretedAsConst {
#[primary_span] #[primary_span]
pub(crate) span: Span, pub(crate) span: Span,

View File

@ -678,8 +678,25 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
let mut let_suggestion = None; let mut let_suggestion = None;
let mut misc_suggestion = None; let mut misc_suggestion = None;
let mut interpreted_as_const = None; let mut interpreted_as_const = None;
let mut interpreted_as_const_sugg = None;
if let PatKind::Constant { .. } if let PatKind::ExpandedConstant { def_id, is_inline: false, .. }
| PatKind::AscribeUserType {
subpattern:
box Pat { kind: PatKind::ExpandedConstant { def_id, is_inline: false, .. }, .. },
..
} = pat.kind
&& let DefKind::Const = self.tcx.def_kind(def_id)
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
// We filter out paths with multiple path::segments.
&& snippet.chars().all(|c| c.is_alphanumeric() || c == '_')
{
let span = self.tcx.def_span(def_id);
let variable = self.tcx.item_name(def_id).to_string();
// When we encounter a constant as the binding name, point at the `const` definition.
interpreted_as_const = Some(span);
interpreted_as_const_sugg = Some(InterpretedAsConst { span: pat.span, variable });
} else if let PatKind::Constant { .. }
| PatKind::AscribeUserType { | PatKind::AscribeUserType {
subpattern: box Pat { kind: PatKind::Constant { .. }, .. }, subpattern: box Pat { kind: PatKind::Constant { .. }, .. },
.. ..
@ -692,9 +709,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
misc_suggestion = Some(MiscPatternSuggestion::AttemptedIntegerLiteral { misc_suggestion = Some(MiscPatternSuggestion::AttemptedIntegerLiteral {
start_span: pat.span.shrink_to_lo(), start_span: pat.span.shrink_to_lo(),
}); });
} else if snippet.chars().all(|c| c.is_alphanumeric() || c == '_') {
interpreted_as_const =
Some(InterpretedAsConst { span: pat.span, variable: snippet });
} }
} }
@ -743,6 +757,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
uncovered: Uncovered::new(pat.span, &cx, witnesses), uncovered: Uncovered::new(pat.span, &cx, witnesses),
inform, inform,
interpreted_as_const, interpreted_as_const,
interpreted_as_const_sugg,
witness_1_is_privately_uninhabited, witness_1_is_privately_uninhabited,
_p: (), _p: (),
pattern_ty, pattern_ty,
@ -1112,13 +1127,13 @@ fn report_non_exhaustive_match<'p, 'tcx>(
if ty.is_ptr_sized_integral() { if ty.is_ptr_sized_integral() {
if ty.inner() == cx.tcx.types.usize { if ty.inner() == cx.tcx.types.usize {
err.note(format!( err.note(format!(
"`{ty}` does not have a fixed maximum value, so half-open ranges are necessary to match \ "`{ty}` does not have a fixed maximum value, so half-open ranges are \
exhaustively", necessary to match exhaustively",
)); ));
} else if ty.inner() == cx.tcx.types.isize { } else if ty.inner() == cx.tcx.types.isize {
err.note(format!( err.note(format!(
"`{ty}` does not have fixed minimum and maximum values, so half-open ranges are necessary to match \ "`{ty}` does not have fixed minimum and maximum values, so half-open \
exhaustively", ranges are necessary to match exhaustively",
)); ));
} }
} else if ty.inner() == cx.tcx.types.str_ { } else if ty.inner() == cx.tcx.types.str_ {
@ -1139,6 +1154,31 @@ fn report_non_exhaustive_match<'p, 'tcx>(
} }
} }
for &arm in arms {
let arm = &thir.arms[arm];
if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = arm.pattern.kind
&& let Ok(snippet) = cx.tcx.sess.source_map().span_to_snippet(arm.pattern.span)
// We filter out paths with multiple path::segments.
&& snippet.chars().all(|c| c.is_alphanumeric() || c == '_')
{
let const_name = cx.tcx.item_name(def_id);
err.span_label(
arm.pattern.span,
format!(
"this pattern doesn't introduce a new catch-all binding, but rather pattern \
matches against the value of constant `{const_name}`",
),
);
err.span_note(cx.tcx.def_span(def_id), format!("constant `{const_name}` defined here"));
err.span_suggestion_verbose(
arm.pattern.span.shrink_to_hi(),
"if you meant to introduce a binding, use a different name",
"_var".to_string(),
Applicability::MaybeIncorrect,
);
}
}
// Whether we suggest the actual missing patterns or `_`. // Whether we suggest the actual missing patterns or `_`.
let suggest_the_witnesses = witnesses.len() < 4; let suggest_the_witnesses = witnesses.len() < 4;
let suggested_arm = if suggest_the_witnesses { let suggested_arm = if suggest_the_witnesses {

View File

@ -149,21 +149,30 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
None => Ok((None, None, None)), None => Ok((None, None, None)),
Some(expr) => { Some(expr) => {
let (kind, ascr, inline_const) = match self.lower_lit(expr) { let (kind, ascr, inline_const) = match self.lower_lit(expr) {
PatKind::InlineConstant { subpattern, def } => { PatKind::ExpandedConstant { subpattern, def_id, is_inline: true } => {
(subpattern.kind, None, Some(def)) (subpattern.kind, None, def_id.as_local())
}
PatKind::ExpandedConstant { subpattern, is_inline: false, .. } => {
(subpattern.kind, None, None)
} }
PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => { PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
(kind, Some(ascription), None) (kind, Some(ascription), None)
} }
kind => (kind, None, None), kind => (kind, None, None),
}; };
let value = if let PatKind::Constant { value } = kind { let value = match kind {
value PatKind::Constant { value } => value,
} else { PatKind::ExpandedConstant { subpattern, .. }
let msg = format!( if let PatKind::Constant { value } = subpattern.kind =>
"found bad range pattern endpoint `{expr:?}` outside of error recovery" {
); value
return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg)); }
_ => {
let msg = format!(
"found bad range pattern endpoint `{expr:?}` outside of error recovery"
);
return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
}
}; };
Ok((Some(PatRangeBoundary::Finite(value)), ascr, inline_const)) Ok((Some(PatRangeBoundary::Finite(value)), ascr, inline_const))
} }
@ -288,7 +297,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}; };
} }
for def in [lo_inline, hi_inline].into_iter().flatten() { for def in [lo_inline, hi_inline].into_iter().flatten() {
kind = PatKind::InlineConstant { def, subpattern: Box::new(Pat { span, ty, kind }) }; kind = PatKind::ExpandedConstant {
def_id: def.to_def_id(),
is_inline: true,
subpattern: Box::new(Pat { span, ty, kind }),
};
} }
Ok(kind) Ok(kind)
} }
@ -562,7 +575,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let args = self.typeck_results.node_args(id); let args = self.typeck_results.node_args(id);
let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args }); let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
let pattern = self.const_to_pat(c, ty, id, span); let subpattern = self.const_to_pat(c, ty, id, span);
let pattern = Box::new(Pat {
span,
ty,
kind: PatKind::ExpandedConstant { subpattern, def_id, is_inline: false },
});
if !is_associated_const { if !is_associated_const {
return pattern; return pattern;
@ -637,7 +655,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args }; let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args };
let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span); let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span);
PatKind::InlineConstant { subpattern, def: def_id } PatKind::ExpandedConstant { subpattern, def_id: def_id.to_def_id(), is_inline: true }
} }
/// Converts literals, paths and negation of literals to patterns. /// Converts literals, paths and negation of literals to patterns.

View File

@ -707,9 +707,10 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
print_indented!(self, "}", depth_lvl + 1); print_indented!(self, "}", depth_lvl + 1);
} }
PatKind::InlineConstant { def, subpattern } => { PatKind::ExpandedConstant { def_id, is_inline, subpattern } => {
print_indented!(self, "InlineConstant {", depth_lvl + 1); print_indented!(self, "ExpandedConstant {", depth_lvl + 1);
print_indented!(self, format!("def: {:?}", def), depth_lvl + 2); print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2);
print_indented!(self, format!("is_inline: {is_inline:?}"), depth_lvl + 2);
print_indented!(self, "subpattern:", depth_lvl + 2); print_indented!(self, "subpattern:", depth_lvl + 2);
self.print_pat(subpattern, depth_lvl + 2); self.print_pat(subpattern, depth_lvl + 2);
print_indented!(self, "}", depth_lvl + 1); print_indented!(self, "}", depth_lvl + 1);

View File

@ -465,7 +465,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
let fields: Vec<_>; let fields: Vec<_>;
match &pat.kind { match &pat.kind {
PatKind::AscribeUserType { subpattern, .. } PatKind::AscribeUserType { subpattern, .. }
| PatKind::InlineConstant { subpattern, .. } => return self.lower_pat(subpattern), | PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern),
PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat), PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
ctor = Wildcard; ctor = Wildcard;

View File

@ -97,16 +97,19 @@ LL | if let Refutable::A = v3 { todo!() };
error[E0005]: refutable pattern in local binding error[E0005]: refutable pattern in local binding
--> $DIR/bad-pattern.rs:19:13 --> $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; LL | let PAT = v1;
| ^^^ | ^^^ pattern `1_u32..=u32::MAX` not covered
| |
| 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: `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: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `u32` = note: the matched value is of type `u32`
help: introduce a variable instead
|
LL | let PAT_var = v1;
| ~~~~~~~
error: aborting due to 7 previous errors error: aborting due to 7 previous errors

View File

@ -1,28 +1,43 @@
mod foo { mod foo {
pub const b: u8 = 2; pub const b: u8 = 2;
pub const d: u8 = 2; //~^ missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable
pub const d: (u8, u8) = (2, 1);
//~^ missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
} }
use foo::b as c; use foo::b as c;
use foo::d; use foo::d;
const a: u8 = 2; const a: u8 = 2;
//~^ missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
#[derive(PartialEq)]
struct S {
foo: u8,
}
const e: S = S {
foo: 0,
};
fn main() { fn main() {
let a = 4; let a = 4;
//~^ ERROR refutable pattern in local binding //~^ ERROR refutable pattern in local binding
//~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
//~| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
//~| HELP introduce a variable instead //~| HELP introduce a variable instead
let c = 4; let c = 4;
//~^ ERROR refutable pattern in local binding //~^ ERROR refutable pattern in local binding
//~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
//~| missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
//~| HELP introduce a variable instead //~| HELP introduce a variable instead
let d = 4; let d = (4, 4);
//~^ ERROR refutable pattern in local binding //~^ ERROR refutable pattern in local binding
//~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered //~| patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered
//~| missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
//~| HELP introduce a variable instead //~| HELP introduce a variable instead
let e = S {
//~^ ERROR refutable pattern in local binding
//~| pattern `S { foo: 1_u8..=u8::MAX }` not covered
//~| HELP introduce a variable instead
foo: 1,
};
fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115). fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115).
} }

View File

@ -1,45 +1,76 @@
error[E0005]: refutable pattern in local binding error[E0005]: refutable pattern in local binding
--> $DIR/const-pattern-irrefutable.rs:12:9 --> $DIR/const-pattern-irrefutable.rs:24:9
| |
LL | const a: u8 = 2;
| ----------- missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
...
LL | let a = 4; LL | let a = 4;
| ^ | ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
| |
| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
| help: introduce a variable instead: `a_var`
| |
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = 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: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `u8` = note: the matched value is of type `u8`
help: introduce a variable instead
|
LL | let a_var = 4;
| ~~~~~
error[E0005]: refutable pattern in local binding error[E0005]: refutable pattern in local binding
--> $DIR/const-pattern-irrefutable.rs:17:9 --> $DIR/const-pattern-irrefutable.rs:28:9
| |
LL | pub const b: u8 = 2;
| --------------- missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable
...
LL | let c = 4; LL | let c = 4;
| ^ | ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
| |
| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
| missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
| help: introduce a variable instead: `c_var`
| |
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = 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: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `u8` = note: the matched value is of type `u8`
help: introduce a variable instead
|
LL | let b_var = 4;
| ~~~~~
error[E0005]: refutable pattern in local binding error[E0005]: refutable pattern in local binding
--> $DIR/const-pattern-irrefutable.rs:22:9 --> $DIR/const-pattern-irrefutable.rs:32:9
| |
LL | let d = 4; LL | pub const d: (u8, u8) = (2, 1);
| ^ | --------------------- missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
| | ...
| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered LL | let d = (4, 4);
| missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable | ^ patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered
| help: introduce a variable instead: `d_var`
| |
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = 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: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `u8` = note: the matched value is of type `(u8, u8)`
help: introduce a variable instead
|
LL | let d_var = (4, 4);
| ~~~~~
error: aborting due to 3 previous errors error[E0005]: refutable pattern in local binding
--> $DIR/const-pattern-irrefutable.rs:36:9
|
LL | const e: S = S {
| ---------- missing patterns are not covered because `e` is interpreted as a constant pattern, not a new variable
...
LL | let e = S {
| ^ pattern `S { foo: 1_u8..=u8::MAX }` not covered
|
= 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: `S` defined here
--> $DIR/const-pattern-irrefutable.rs:15:8
|
LL | struct S {
| ^
= note: the matched value is of type `S`
help: introduce a variable instead
|
LL | let e_var = S {
| ~~~~~
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0005`. For more information about this error, try `rustc --explain E0005`.

View File

@ -3,8 +3,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
| |
LL | match &[][..] { LL | match &[][..] {
| ^^^^^^^ patterns `&[]` and `&[_, _, ..]` not covered | ^^^^^^^ patterns `&[]` and `&[_, _, ..]` not covered
LL |
LL | E_SL => {}
| ---- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `E_SL`
| |
= note: the matched value is of type `&[E]` = note: the matched value is of type `&[E]`
note: constant `E_SL` defined here
--> $DIR/incomplete-slice.rs:6:1
|
LL | const E_SL: &[E] = &[E::A];
| ^^^^^^^^^^^^^^^^
help: if you meant to introduce a binding, use a different name
|
LL | E_SL_var => {}
| ++++
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
| |
LL ~ E_SL => {}, LL ~ E_SL => {},

View File

@ -0,0 +1,10 @@
fn main() {
match 1 { //~ ERROR non-exhaustive patterns
//~^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
//~| the matched value is of type `i32`
x => {} //~ this pattern doesn't introduce a new catch-all binding
//~^ HELP ensure that all possible cases are being handled
//~| HELP if you meant to introduce a binding, use a different name
}
const x: i32 = 4; //~ NOTE constant `x` defined here
}

View File

@ -0,0 +1,27 @@
error[E0004]: non-exhaustive patterns: `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
--> $DIR/intended-binding-pattern-is-const.rs:2:11
|
LL | match 1 {
| ^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
...
LL | x => {}
| - this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `x`
|
= note: the matched value is of type `i32`
note: constant `x` defined here
--> $DIR/intended-binding-pattern-is-const.rs:9:5
|
LL | const x: i32 = 4;
| ^^^^^^^^^^^^
help: if you meant to introduce a binding, use a different name
|
LL | x_var => {}
| ++++
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
|
LL | x => {}, i32::MIN..=3_i32 | 5_i32..=i32::MAX => todo!()
| ++++++++++++++++++++++++++++++++++++++++++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0004`.

View File

@ -1,30 +1,34 @@
error[E0005]: refutable pattern in local binding error[E0005]: refutable pattern in local binding
--> $DIR/issue-112269.rs:3:9 --> $DIR/issue-112269.rs:3:9
| |
LL | const x: i32 = 4;
| ------------ missing patterns are not covered because `x` is interpreted as a constant pattern, not a new variable
LL | let x: i32 = 3; LL | let x: i32 = 3;
| ^ | ^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
| |
| patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
| missing patterns are not covered because `x` is interpreted as a constant pattern, not a new variable
| help: introduce a variable instead: `x_var`
| |
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = 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: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `i32` = note: the matched value is of type `i32`
help: introduce a variable instead
|
LL | let x_var: i32 = 3;
| ~~~~~
error[E0005]: refutable pattern in local binding error[E0005]: refutable pattern in local binding
--> $DIR/issue-112269.rs:7:9 --> $DIR/issue-112269.rs:7:9
| |
LL | const y: i32 = 3;
| ------------ missing patterns are not covered because `y` is interpreted as a constant pattern, not a new variable
LL | let y = 4; LL | let y = 4;
| ^ | ^ patterns `i32::MIN..=2_i32` and `4_i32..=i32::MAX` not covered
| |
| patterns `i32::MIN..=2_i32` and `4_i32..=i32::MAX` not covered
| missing patterns are not covered because `y` is interpreted as a constant pattern, not a new variable
| help: introduce a variable instead: `y_var`
| |
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = 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: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `i32` = note: the matched value is of type `i32`
help: introduce a variable instead
|
LL | let y_var = 4;
| ~~~~~
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View File

@ -3,8 +3,20 @@ error[E0004]: non-exhaustive patterns: `(true, false)` not covered
| |
LL | match (true, false) { LL | match (true, false) {
| ^^^^^^^^^^^^^ pattern `(true, false)` not covered | ^^^^^^^^^^^^^ pattern `(true, false)` not covered
LL |
LL | TRUE_TRUE => (),
| --------- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `TRUE_TRUE`
| |
= note: the matched value is of type `(bool, bool)` = note: the matched value is of type `(bool, bool)`
note: constant `TRUE_TRUE` defined here
--> $DIR/match-arm-statics-2.rs:14:1
|
LL | const TRUE_TRUE: (bool, bool) = (true, true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: if you meant to introduce a binding, use a different name
|
LL | TRUE_TRUE_var => (),
| ++++
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown 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 ~ (false, true) => (), LL ~ (false, true) => (),

View File

@ -199,8 +199,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
| |
LL | match s { LL | match s {
| ^ patterns `&[]` and `&[_, _, ..]` not covered | ^ patterns `&[]` and `&[_, _, ..]` not covered
LL |
LL | CONST => {}
| ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
| |
= note: the matched value is of type `&[bool]` = note: the matched value is of type `&[bool]`
note: constant `CONST` defined here
--> $DIR/slice-patterns-exhaustiveness.rs:88:5
|
LL | const CONST: &[bool] = &[true];
| ^^^^^^^^^^^^^^^^^^^^
help: if you meant to introduce a binding, use a different name
|
LL | CONST_var => {}
| ++++
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
| |
LL ~ CONST => {}, LL ~ CONST => {},
@ -212,8 +224,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
| |
LL | match s { LL | match s {
| ^ patterns `&[]` and `&[_, _, ..]` not covered | ^ patterns `&[]` and `&[_, _, ..]` not covered
LL |
LL | CONST => {}
| ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
| |
= note: the matched value is of type `&[bool]` = note: the matched value is of type `&[bool]`
note: constant `CONST` defined here
--> $DIR/slice-patterns-exhaustiveness.rs:88:5
|
LL | const CONST: &[bool] = &[true];
| ^^^^^^^^^^^^^^^^^^^^
help: if you meant to introduce a binding, use a different name
|
LL | CONST_var => {}
| ++++
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
| |
LL ~ &[false] => {}, LL ~ &[false] => {},
@ -225,8 +249,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
| |
LL | match s { LL | match s {
| ^ patterns `&[]` and `&[_, _, ..]` not covered | ^ patterns `&[]` and `&[_, _, ..]` not covered
...
LL | CONST => {}
| ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
| |
= note: the matched value is of type `&[bool]` = note: the matched value is of type `&[bool]`
note: constant `CONST` defined here
--> $DIR/slice-patterns-exhaustiveness.rs:88:5
|
LL | const CONST: &[bool] = &[true];
| ^^^^^^^^^^^^^^^^^^^^
help: if you meant to introduce a binding, use a different name
|
LL | CONST_var => {}
| ++++
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
| |
LL ~ CONST => {}, LL ~ CONST => {},
@ -238,8 +274,20 @@ error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
| |
LL | match s { LL | match s {
| ^ pattern `&[_, _, ..]` not covered | ^ pattern `&[_, _, ..]` not covered
...
LL | CONST => {}
| ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
| |
= note: the matched value is of type `&[bool]` = note: the matched value is of type `&[bool]`
note: constant `CONST` defined here
--> $DIR/slice-patterns-exhaustiveness.rs:88:5
|
LL | const CONST: &[bool] = &[true];
| ^^^^^^^^^^^^^^^^^^^^
help: if you meant to introduce a binding, use a different name
|
LL | CONST_var => {}
| ++++
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown 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 ~ CONST => {}, LL ~ CONST => {},
@ -251,8 +299,20 @@ error[E0004]: non-exhaustive patterns: `&[false]` not covered
| |
LL | match s { LL | match s {
| ^ pattern `&[false]` not covered | ^ pattern `&[false]` not covered
...
LL | CONST => {}
| ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
| |
= note: the matched value is of type `&[bool]` = note: the matched value is of type `&[bool]`
note: constant `CONST` defined here
--> $DIR/slice-patterns-exhaustiveness.rs:88:5
|
LL | const CONST: &[bool] = &[true];
| ^^^^^^^^^^^^^^^^^^^^
help: if you meant to introduce a binding, use a different name
|
LL | CONST_var => {}
| ++++
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown 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 ~ &[_, _, ..] => {}, LL ~ &[_, _, ..] => {},
@ -264,8 +324,20 @@ error[E0004]: non-exhaustive patterns: `&[false]` not covered
| |
LL | match s1 { LL | match s1 {
| ^^ pattern `&[false]` not covered | ^^ pattern `&[false]` not covered
LL |
LL | CONST1 => {}
| ------ this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST1`
| |
= note: the matched value is of type `&[bool; 1]` = note: the matched value is of type `&[bool; 1]`
note: constant `CONST1` defined here
--> $DIR/slice-patterns-exhaustiveness.rs:124:5
|
LL | const CONST1: &[bool; 1] = &[true];
| ^^^^^^^^^^^^^^^^^^^^^^^^
help: if you meant to introduce a binding, use a different name
|
LL | CONST1_var => {}
| ++++
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown 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 ~ CONST1 => {}, LL ~ CONST1 => {},

View File

@ -2,9 +2,9 @@ fn main() {
let A = 3; let A = 3;
//~^ ERROR refutable pattern in local binding //~^ ERROR refutable pattern in local binding
//~| patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered //~| patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
//~| missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
//~| HELP introduce a variable instead //~| HELP introduce a variable instead
//~| SUGGESTION A_var //~| SUGGESTION A_var
const A: i32 = 2; const A: i32 = 2;
//~^ missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
} }

View File

@ -2,15 +2,18 @@ error[E0005]: refutable pattern in local binding
--> $DIR/const-pat-non-exaustive-let-new-var.rs:2:9 --> $DIR/const-pat-non-exaustive-let-new-var.rs:2:9
| |
LL | let A = 3; LL | let A = 3;
| ^ | ^ patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
| | ...
| patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered LL | const A: i32 = 2;
| missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable | ------------ missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
| help: introduce a variable instead: `A_var`
| |
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = 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: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `i32` = note: the matched value is of type `i32`
help: introduce a variable instead
|
LL | let A_var = 3;
| ~~~~~
error: aborting due to 1 previous error error: aborting due to 1 previous error