diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 6be2fdf9f19..3b1559dfcf5 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -772,12 +772,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } _ => { - let const_def_id = match pat_ty.kind() { + let (type_def_id, item_def_id) = match pat_ty.kind() { Adt(def, _) => match res { - Res::Def(DefKind::Const, _) => Some(def.did), - _ => None, + Res::Def(DefKind::Const, def_id) => (Some(def.did), Some(def_id)), + _ => (None, None), }, - _ => None, + _ => (None, None), }; let ranges = &[ @@ -788,11 +788,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.lang_items().range_inclusive_struct(), self.tcx.lang_items().range_to_inclusive_struct(), ]; - if const_def_id != None && ranges.contains(&const_def_id) { - let msg = "constants only support matching by type, \ - if you meant to match against a range of values, \ - consider using a range pattern like `min ..= max` in the match block"; - e.note(msg); + if type_def_id != None && ranges.contains(&type_def_id) { + let generic_message = match item_def_id { + Some(def_id) => match self.tcx.hir().get_if_local(def_id) { + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Const(_, body_id), + .. + })) => match self.tcx.hir().get(body_id.hir_id) { + hir::Node::Expr(expr) => { + if hir::is_range_literal(expr) { + let span = self.tcx.hir().span(body_id.hir_id); + if let Ok(snip) = + self.tcx.sess.source_map().span_to_snippet(span) + { + e.span_suggestion_verbose( + span, + "you may want to move the range into the match block", + snip, + Applicability::MachineApplicable + ); + false + } else { + true + } + } else { + true + } + } + _ => true, + }, + _ => true, + }, + _ => true, + }; + + if generic_message { + let msg = "constants only support matching by type, \ + if you meant to match against a range of values, \ + consider using a range pattern like `min ..= max` in the match block"; + e.note(msg); + } } else { let msg = "introduce a new binding instead"; let sugg = format!("other_{}", ident.as_str().to_lowercase()); diff --git a/src/test/ui/issues/issue-76191.rs b/src/test/ui/issues/issue-76191.rs index bc327123c6f..d9790d2b56e 100644 --- a/src/test/ui/issues/issue-76191.rs +++ b/src/test/ui/issues/issue-76191.rs @@ -2,13 +2,18 @@ #![allow(non_snake_case)] use std::ops::RangeInclusive; + const RANGE: RangeInclusive = 0..=255; +const RANGE2: RangeInclusive = panic!(); + fn main() { let n: i32 = 1; match n { RANGE => {} //~^ ERROR mismatched types + RANGE2 => {} + //~^ ERROR mismatched types _ => {} } } diff --git a/src/test/ui/issues/issue-76191.stderr b/src/test/ui/issues/issue-76191.stderr index a5544d9e9da..61f4be81f43 100644 --- a/src/test/ui/issues/issue-76191.stderr +++ b/src/test/ui/issues/issue-76191.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-76191.rs:10:9 + --> $DIR/issue-76191.rs:13:9 | LL | const RANGE: RangeInclusive = 0..=255; | ------------------------------------------- constant defined here @@ -14,8 +14,30 @@ LL | RANGE => {} | = note: expected type `i32` found struct `RangeInclusive` +help: you may want to move the range into the match block + | +LL | const RANGE: RangeInclusive = 0..=255; + | ^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-76191.rs:15:9 + | +LL | const RANGE2: RangeInclusive = panic!(); + | --------------------------------------------- constant defined here +... +LL | match n { + | - this expression has type `i32` +... +LL | RANGE2 => {} + | ^^^^^^ + | | + | expected `i32`, found struct `RangeInclusive` + | `RANGE2` is interpreted as a constant, not a new binding + | + = note: expected type `i32` + found struct `RangeInclusive` = note: constants only support matching by type, if you meant to match against a range of values, consider using a range pattern like `min ..= max` in the match block -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`.