diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 2c606ebf322a8..373c8e039f8de 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -70,13 +70,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - PatternKind::Range { lo, hi, end } => { + PatternKind::Range { lo, hi, ty, end } => { + assert!(ty == match_pair.pattern.ty); Test { span: match_pair.pattern.span, kind: TestKind::Range { lo, hi, - ty: match_pair.pattern.ty.clone(), + ty, end, }, } diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index e05e0bb0470f4..aa1c6902dce33 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -416,7 +416,7 @@ pub enum Constructor<'tcx> { /// Literal values. ConstantValue(&'tcx ty::Const<'tcx>), /// Ranges of literal values (`2...5` and `2..5`). - ConstantRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd), + ConstantRange(u128, u128, Ty<'tcx>, RangeEnd), /// Array patterns of length n. Slice(u64), } @@ -588,7 +588,12 @@ impl<'tcx> Witness<'tcx> { _ => { match *ctor { ConstantValue(value) => PatternKind::Constant { value }, - ConstantRange(lo, hi, end) => PatternKind::Range { lo, hi, end }, + ConstantRange(lo, hi, ty, end) => PatternKind::Range { + lo: ty::Const::from_bits(cx.tcx, lo, ty::ParamEnv::empty().and(ty)), + hi: ty::Const::from_bits(cx.tcx, hi, ty::ParamEnv::empty().and(ty)), + ty, + end, + }, _ => PatternKind::Wild, } } @@ -648,14 +653,18 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, .collect() } ty::Char if exhaustive_integer_patterns => { - let endpoint = |c: char| { - let ty = ty::ParamEnv::empty().and(cx.tcx.types.char); - ty::Const::from_bits(cx.tcx, c as u128, ty) - }; vec![ // The valid Unicode Scalar Value ranges. - ConstantRange(endpoint('\u{0000}'), endpoint('\u{D7FF}'), RangeEnd::Included), - ConstantRange(endpoint('\u{E000}'), endpoint('\u{10FFFF}'), RangeEnd::Included), + ConstantRange('\u{0000}' as u128, + '\u{D7FF}' as u128, + cx.tcx.types.char, + RangeEnd::Included + ), + ConstantRange('\u{E000}' as u128, + '\u{10FFFF}' as u128, + cx.tcx.types.char, + RangeEnd::Included + ), ] } ty::Int(ity) if exhaustive_integer_patterns => { @@ -663,19 +672,13 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, let bits = Integer::from_attr(cx.tcx, SignedInt(ity)).size().bits() as u128; let min = 1u128 << (bits - 1); let max = (1u128 << (bits - 1)) - 1; - let ty = ty::ParamEnv::empty().and(pcx.ty); - vec![ConstantRange(ty::Const::from_bits(cx.tcx, min as u128, ty), - ty::Const::from_bits(cx.tcx, max as u128, ty), - RangeEnd::Included)] + vec![ConstantRange(min, max, pcx.ty, RangeEnd::Included)] } ty::Uint(uty) if exhaustive_integer_patterns => { // FIXME(49937): refactor these bit manipulations into interpret. let bits = Integer::from_attr(cx.tcx, UnsignedInt(uty)).size().bits() as u128; let max = !0u128 >> (128 - bits); - let ty = ty::ParamEnv::empty().and(pcx.ty); - vec![ConstantRange(ty::Const::from_bits(cx.tcx, 0, ty), - ty::Const::from_bits(cx.tcx, max, ty), - RangeEnd::Included)] + vec![ConstantRange(0, max, pcx.ty, RangeEnd::Included)] } _ => { if cx.is_uninhabited(pcx.ty) { @@ -811,26 +814,18 @@ impl<'tcx> IntRange<'tcx> { ctor: &Constructor<'tcx>) -> Option> { match ctor { - ConstantRange(lo, hi, end) => { - assert_eq!(lo.ty, hi.ty); - let ty = lo.ty; - let env_ty = ty::ParamEnv::empty().and(ty); - if let Some(lo) = lo.assert_bits(tcx, env_ty) { - if let Some(hi) = hi.assert_bits(tcx, env_ty) { - // Perform a shift if the underlying types are signed, - // which makes the interval arithmetic simpler. - let bias = IntRange::signed_bias(tcx, ty); - let (lo, hi) = (lo ^ bias, hi ^ bias); - // Make sure the interval is well-formed. - return if lo > hi || lo == hi && *end == RangeEnd::Excluded { - None - } else { - let offset = (*end == RangeEnd::Excluded) as u128; - Some(IntRange { range: lo..=(hi - offset), ty }) - }; - } + ConstantRange(lo, hi, ty, end) => { + // Perform a shift if the underlying types are signed, + // which makes the interval arithmetic simpler. + let bias = IntRange::signed_bias(tcx, ty); + let (lo, hi) = (lo ^ bias, hi ^ bias); + // Make sure the interval is well-formed. + if lo > hi || lo == hi && *end == RangeEnd::Excluded { + None + } else { + let offset = (*end == RangeEnd::Excluded) as u128; + Some(IntRange { range: lo..=(hi - offset), ty }) } - None } ConstantValue(val) => { let ty = val.ty; @@ -853,7 +848,12 @@ impl<'tcx> IntRange<'tcx> { -> Option> { Self::from_ctor(tcx, &match pat.kind { box PatternKind::Constant { value } => ConstantValue(value), - box PatternKind::Range { lo, hi, end } => ConstantRange(lo, hi, end), + box PatternKind::Range { lo, hi, ty, end } => ConstantRange( + lo.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(), + hi.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(), + ty, + end, + ), _ => return None, }) } @@ -876,14 +876,12 @@ impl<'tcx> IntRange<'tcx> { r: RangeInclusive, ) -> Constructor<'tcx> { let bias = IntRange::signed_bias(tcx, ty); - let ty = ty::ParamEnv::empty().and(ty); let (lo, hi) = r.into_inner(); if lo == hi { + let ty = ty::ParamEnv::empty().and(ty); ConstantValue(ty::Const::from_bits(tcx, lo ^ bias, ty)) } else { - ConstantRange(ty::Const::from_bits(tcx, lo ^ bias, ty), - ty::Const::from_bits(tcx, hi ^ bias, ty), - RangeEnd::Included) + ConstantRange(lo ^ bias, hi ^ bias, ty, RangeEnd::Included) } } @@ -1228,8 +1226,8 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>( /// Slice patterns, however, can match slices of different lengths. For instance, /// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on. /// -/// Returns `None` in case of a catch-all, which can't be specialized. -fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt, +/// Returns None in case of a catch-all, which can't be specialized. +fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>, pat: &Pattern<'tcx>, pcx: PatternContext) -> Option>> @@ -1243,7 +1241,13 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt, Some(vec![Variant(adt_def.variants[variant_index].did)]) } PatternKind::Constant { value } => Some(vec![ConstantValue(value)]), - PatternKind::Range { lo, hi, end } => Some(vec![ConstantRange(lo, hi, end)]), + PatternKind::Range { lo, hi, ty, end } => + Some(vec![ConstantRange( + lo.to_bits(cx.tcx, ty::ParamEnv::empty().and(ty)).unwrap(), + hi.to_bits(cx.tcx, ty::ParamEnv::empty().and(ty)).unwrap(), + ty, + end, + )]), PatternKind::Array { .. } => match pcx.ty.sty { ty::Array(_, length) => Some(vec![ Slice(length.unwrap_usize(cx.tcx)) @@ -1383,10 +1387,13 @@ fn slice_pat_covered_by_constructor<'tcx>( // constructor is a range or constant with an integer type. fn should_treat_range_exhaustively(tcx: TyCtxt<'_, 'tcx, 'tcx>, ctor: &Constructor<'tcx>) -> bool { if tcx.features().exhaustive_integer_patterns { - if let ConstantValue(value) | ConstantRange(value, _, _) = ctor { - if let ty::Char | ty::Int(_) | ty::Uint(_) = value.ty.sty { - return true; - } + let ty = match ctor { + ConstantValue(value) => value.ty, + ConstantRange(_, _, ty, _) => ty, + _ => return false, + }; + if let ty::Char | ty::Int(_) | ty::Uint(_) = ty.sty { + return true; } } false @@ -1537,7 +1544,7 @@ fn constructor_covered_by_range<'a, 'tcx>( ) -> Result { let (from, to, end, ty) = match pat.kind { box PatternKind::Constant { value } => (value, value, RangeEnd::Included, value.ty), - box PatternKind::Range { lo, hi, end } => (lo, hi, end, lo.ty), + box PatternKind::Range { lo, hi, ty, end } => (lo, hi, end, ty), _ => bug!("`constructor_covered_by_range` called with {:?}", pat), }; trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty); @@ -1559,17 +1566,33 @@ fn constructor_covered_by_range<'a, 'tcx>( (end == RangeEnd::Included && to == Ordering::Equal); Ok(some_or_ok!(cmp_from(value)) && end) }, - ConstantRange(from, to, RangeEnd::Included) => { - let to = some_or_ok!(cmp_to(to)); + ConstantRange(from, to, ty, RangeEnd::Included) => { + let to = some_or_ok!(cmp_to(ty::Const::from_bits( + tcx, + to, + ty::ParamEnv::empty().and(ty), + ))); let end = (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); - Ok(some_or_ok!(cmp_from(from)) && end) + Ok(some_or_ok!(cmp_from(ty::Const::from_bits( + tcx, + from, + ty::ParamEnv::empty().and(ty), + ))) && end) }, - ConstantRange(from, to, RangeEnd::Excluded) => { - let to = some_or_ok!(cmp_to(to)); + ConstantRange(from, to, ty, RangeEnd::Excluded) => { + let to = some_or_ok!(cmp_to(ty::Const::from_bits( + tcx, + to, + ty::ParamEnv::empty().and(ty) + ))); let end = (to == Ordering::Less) || (end == RangeEnd::Excluded && to == Ordering::Equal); - Ok(some_or_ok!(cmp_from(from)) && end) + Ok(some_or_ok!(cmp_from(ty::Const::from_bits( + tcx, + from, + ty::ParamEnv::empty().and(ty))) + ) && end) } Single => Ok(true), _ => bug!(), diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index cd44869211a7d..ee50322fbb355 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -106,6 +106,7 @@ pub enum PatternKind<'tcx> { Range { lo: &'tcx ty::Const<'tcx>, hi: &'tcx ty::Const<'tcx>, + ty: Ty<'tcx>, end: RangeEnd, }, @@ -237,7 +238,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { PatternKind::Constant { value } => { fmt_const_val(f, value) } - PatternKind::Range { lo, hi, end } => { + PatternKind::Range { lo, hi, ty: _, end } => { fmt_const_val(f, lo)?; match end { RangeEnd::Included => write!(f, "..=")?, @@ -366,7 +367,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ); match (end, cmp) { (RangeEnd::Excluded, Some(Ordering::Less)) => - PatternKind::Range { lo, hi, end }, + PatternKind::Range { lo, hi, ty, end }, (RangeEnd::Excluded, _) => { span_err!( self.tcx.sess, @@ -380,7 +381,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { PatternKind::Constant { value: lo } } (RangeEnd::Included, Some(Ordering::Less)) => { - PatternKind::Range { lo, hi, end } + PatternKind::Range { lo, hi, ty, end } } (RangeEnd::Included, _) => { let mut err = struct_span_err!( @@ -1031,10 +1032,12 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { PatternKind::Range { lo, hi, + ty, end, } => PatternKind::Range { lo: lo.fold_with(folder), hi: hi.fold_with(folder), + ty: ty.fold_with(folder), end, }, PatternKind::Slice {