diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 6b7e1416118..eacb11fc1ac 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -167,6 +167,17 @@ pub enum PatternKind<'tcx> { }, } +impl<'tcx> PatternKind<'tcx> { + /// If this is a `PatternKind::AscribeUserType` then return the subpattern kind, otherwise + /// return this pattern kind. + fn with_user_type_ascription_subpattern(self) -> Self { + match self { + PatternKind::AscribeUserType { subpattern: Pattern { box kind, .. }, .. } => kind, + kind => kind, + } + } +} + #[derive(Clone, Copy, Debug, PartialEq)] pub struct PatternRange<'tcx> { pub lo: ty::Const<'tcx>, @@ -403,9 +414,15 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> { PatKind::Lit(ref value) => self.lower_lit(value), PatKind::Range(ref lo_expr, ref hi_expr, end) => { - match (self.lower_lit(lo_expr), self.lower_lit(hi_expr)) { - (PatternKind::Constant { value: lo }, - PatternKind::Constant { value: hi }) => { + match ( + // Look for `PatternKind::Constant` patterns inside of any + // `PatternKind::AscribeUserType` patterns. Type ascriptions can be safely + // ignored for the purposes of lowering a range correctly - these are checked + // elsewhere for well-formedness. + self.lower_lit(lo_expr).with_user_type_ascription_subpattern(), + self.lower_lit(hi_expr).with_user_type_ascription_subpattern(), + ) { + (PatternKind::Constant { value: lo }, PatternKind::Constant { value: hi }) => { use std::cmp::Ordering; let cmp = compare_const_vals( self.tcx, @@ -454,7 +471,15 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> { } } } - _ => PatternKind::Wild + ref pats => { + self.tcx.sess.delay_span_bug( + pat.span, + &format!("found bad range pattern `{:?}` outside of error recovery", + pats), + ); + + PatternKind::Wild + } } } diff --git a/src/test/ui/nll/issue-57960.rs b/src/test/ui/nll/issue-57960.rs new file mode 100644 index 00000000000..0b52e46c459 --- /dev/null +++ b/src/test/ui/nll/issue-57960.rs @@ -0,0 +1,39 @@ +// run-pass + +#![allow(dead_code)] + +trait Range { + const FIRST: u8; + const LAST: u8; +} + +struct OneDigit; +impl Range for OneDigit { + const FIRST: u8 = 0; + const LAST: u8 = 9; +} + +struct TwoDigits; +impl Range for TwoDigits { + const FIRST: u8 = 10; + const LAST: u8 = 99; +} + +struct ThreeDigits; +impl Range for ThreeDigits { + const FIRST: u8 = 100; + const LAST: u8 = 255; +} + +fn digits(x: u8) -> u32 { + match x { + OneDigit::FIRST...OneDigit::LAST => 1, + TwoDigits::FIRST...TwoDigits::LAST => 2, + ThreeDigits::FIRST...ThreeDigits::LAST => 3, + _ => unreachable!(), + } +} + +fn main() { + assert_eq!(digits(100), 3); +}