From: Nadrieril Date: Sat, 17 Oct 2020 22:12:28 +0000 (+0100) Subject: Handle ranges of float consistently X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=aa4172076ea9b886fefadafda6e479ab6c574bff;p=rust.git Handle ranges of float consistently This deconfuses the comparison of floats, that currently mixed ranges and non-ranges. --- diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs index 7124cad513e..6a37dd896b6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs @@ -834,13 +834,6 @@ enum Constructor<'tcx> { } impl<'tcx> Constructor<'tcx> { - fn is_slice(&self) -> bool { - match self { - Slice(_) => true, - _ => false, - } - } - fn variant_index_for_adt<'a>( &self, cx: &MatchCheckCtxt<'a, 'tcx>, @@ -2111,7 +2104,10 @@ fn pat_constructor<'tcx>( if let Some(int_range) = IntRange::from_const(tcx, param_env, value, pat.span) { Some(IntRange(int_range)) } else { - Some(ConstantValue(value)) + match value.ty.kind() { + ty::Float(_) => Some(FloatRange(value, value, RangeEnd::Included)), + _ => Some(ConstantValue(value)), + } } } PatKind::Range(PatRange { lo, hi, end }) => { @@ -2443,35 +2439,6 @@ fn lint_overlapping_patterns<'tcx>( } } -fn constructor_covered_by_range<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ctor: &Constructor<'tcx>, - pat: &Pat<'tcx>, -) -> Option<()> { - if let Single = ctor { - return Some(()); - } - - let (pat_from, pat_to, pat_end, ty) = match *pat.kind { - PatKind::Constant { value } => (value, value, RangeEnd::Included, value.ty), - PatKind::Range(PatRange { lo, hi, end }) => (lo, hi, end, lo.ty), - _ => bug!("`constructor_covered_by_range` called with {:?}", pat), - }; - let (ctor_from, ctor_to, ctor_end) = match *ctor { - ConstantValue(value) => (value, value, RangeEnd::Included), - FloatRange(from, to, ctor_end) => (from, to, ctor_end), - _ => bug!("`constructor_covered_by_range` called with {:?}", ctor), - }; - trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, pat_from, pat_to, ty); - - let to = compare_const_vals(tcx, ctor_to, pat_to, param_env, ty)?; - let from = compare_const_vals(tcx, ctor_from, pat_from, param_env, ty)?; - let intersects = (from == Ordering::Greater || from == Ordering::Equal) - && (to == Ordering::Less || (pat_end == ctor_end && to == Ordering::Equal)); - if intersects { Some(()) } else { None } -} - /// This is the main specialization step. It expands the pattern /// into `arity` patterns based on the constructor. For most patterns, the step is trivial, /// for instance tuple patterns are flattened and box patterns expand into their inner pattern. @@ -2516,27 +2483,51 @@ fn specialize_one_pattern<'p, 'tcx>( PatKind::Deref { ref subpattern } => Some(Fields::from_single_pattern(subpattern)), - PatKind::Constant { value } if constructor.is_slice() => { - span_bug!(pat.span, "unexpected const-val {:?} with ctor {:?}", value, constructor) - } - PatKind::Constant { .. } | PatKind::Range { .. } => { - // If the constructor is a: - // - Single value: add a row if the pattern contains the constructor. - // - Range: add a row if the constructor intersects the pattern. - if let IntRange(ctor) = constructor { - let pat = IntRange::from_pat(cx.tcx, cx.param_env, pat)?; - ctor.intersection(cx.tcx, &pat)?; - // Constructor splitting should ensure that all intersections we encounter - // are actually inclusions. - assert!(ctor.is_subrange(&pat)); - } else { - // Fallback for non-ranges and ranges that involve - // floating-point numbers, which are not conveniently handled - // by `IntRange`. For these cases, the constructor may not be a - // range so intersection actually devolves into being covered - // by the pattern. - constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat)?; + match constructor { + Single => {} + IntRange(ctor) => { + let pat = IntRange::from_pat(cx.tcx, cx.param_env, pat)?; + ctor.intersection(cx.tcx, &pat)?; + // Constructor splitting should ensure that all intersections we encounter + // are actually inclusions. + assert!(ctor.is_subrange(&pat)); + } + FloatRange(ctor_from, ctor_to, ctor_end) => { + let (pat_from, pat_to, pat_end, ty) = match *pat.kind { + PatKind::Constant { value } => (value, value, RangeEnd::Included, value.ty), + PatKind::Range(PatRange { lo, hi, end }) => (lo, hi, end, lo.ty), + _ => unreachable!(), // This is ensured by the branch we're in + }; + let to = compare_const_vals(cx.tcx, ctor_to, pat_to, cx.param_env, ty)?; + let from = compare_const_vals(cx.tcx, ctor_from, pat_from, cx.param_env, ty)?; + let intersects = (from == Ordering::Greater || from == Ordering::Equal) + && (to == Ordering::Less + || (pat_end == *ctor_end && to == Ordering::Equal)); + if !intersects { + return None; + } + } + ConstantValue(ctor_value) => { + let pat_value = match *pat.kind { + PatKind::Constant { value } => value, + _ => span_bug!( + pat.span, + "unexpected range pattern {:?} for constant value ctor", + pat + ), + }; + + // FIXME: there's probably a more direct way of comparing for equality + if compare_const_vals(cx.tcx, ctor_value, pat_value, cx.param_env, pat.ty)? + != Ordering::Equal + { + return None; + } + } + _ => { + span_bug!(pat.span, "unexpected pattern {:?} with ctor {:?}", pat, constructor) + } } Some(Fields::empty()) }