Skip to content

Commit aa41720

Browse files
committed
Handle ranges of float consistently
This deconfuses the comparison of floats, that currently mixed ranges and non-ranges.
1 parent f504e9a commit aa41720

File tree

1 file changed

+48
-57
lines changed
  • compiler/rustc_mir_build/src/thir/pattern

1 file changed

+48
-57
lines changed

compiler/rustc_mir_build/src/thir/pattern/_match.rs

+48-57
Original file line numberDiff line numberDiff line change
@@ -834,13 +834,6 @@ enum Constructor<'tcx> {
834834
}
835835

836836
impl<'tcx> Constructor<'tcx> {
837-
fn is_slice(&self) -> bool {
838-
match self {
839-
Slice(_) => true,
840-
_ => false,
841-
}
842-
}
843-
844837
fn variant_index_for_adt<'a>(
845838
&self,
846839
cx: &MatchCheckCtxt<'a, 'tcx>,
@@ -2111,7 +2104,10 @@ fn pat_constructor<'tcx>(
21112104
if let Some(int_range) = IntRange::from_const(tcx, param_env, value, pat.span) {
21122105
Some(IntRange(int_range))
21132106
} else {
2114-
Some(ConstantValue(value))
2107+
match value.ty.kind() {
2108+
ty::Float(_) => Some(FloatRange(value, value, RangeEnd::Included)),
2109+
_ => Some(ConstantValue(value)),
2110+
}
21152111
}
21162112
}
21172113
PatKind::Range(PatRange { lo, hi, end }) => {
@@ -2443,35 +2439,6 @@ fn lint_overlapping_patterns<'tcx>(
24432439
}
24442440
}
24452441

2446-
fn constructor_covered_by_range<'tcx>(
2447-
tcx: TyCtxt<'tcx>,
2448-
param_env: ty::ParamEnv<'tcx>,
2449-
ctor: &Constructor<'tcx>,
2450-
pat: &Pat<'tcx>,
2451-
) -> Option<()> {
2452-
if let Single = ctor {
2453-
return Some(());
2454-
}
2455-
2456-
let (pat_from, pat_to, pat_end, ty) = match *pat.kind {
2457-
PatKind::Constant { value } => (value, value, RangeEnd::Included, value.ty),
2458-
PatKind::Range(PatRange { lo, hi, end }) => (lo, hi, end, lo.ty),
2459-
_ => bug!("`constructor_covered_by_range` called with {:?}", pat),
2460-
};
2461-
let (ctor_from, ctor_to, ctor_end) = match *ctor {
2462-
ConstantValue(value) => (value, value, RangeEnd::Included),
2463-
FloatRange(from, to, ctor_end) => (from, to, ctor_end),
2464-
_ => bug!("`constructor_covered_by_range` called with {:?}", ctor),
2465-
};
2466-
trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, pat_from, pat_to, ty);
2467-
2468-
let to = compare_const_vals(tcx, ctor_to, pat_to, param_env, ty)?;
2469-
let from = compare_const_vals(tcx, ctor_from, pat_from, param_env, ty)?;
2470-
let intersects = (from == Ordering::Greater || from == Ordering::Equal)
2471-
&& (to == Ordering::Less || (pat_end == ctor_end && to == Ordering::Equal));
2472-
if intersects { Some(()) } else { None }
2473-
}
2474-
24752442
/// This is the main specialization step. It expands the pattern
24762443
/// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
24772444
/// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
@@ -2516,27 +2483,51 @@ fn specialize_one_pattern<'p, 'tcx>(
25162483

25172484
PatKind::Deref { ref subpattern } => Some(Fields::from_single_pattern(subpattern)),
25182485

2519-
PatKind::Constant { value } if constructor.is_slice() => {
2520-
span_bug!(pat.span, "unexpected const-val {:?} with ctor {:?}", value, constructor)
2521-
}
2522-
25232486
PatKind::Constant { .. } | PatKind::Range { .. } => {
2524-
// If the constructor is a:
2525-
// - Single value: add a row if the pattern contains the constructor.
2526-
// - Range: add a row if the constructor intersects the pattern.
2527-
if let IntRange(ctor) = constructor {
2528-
let pat = IntRange::from_pat(cx.tcx, cx.param_env, pat)?;
2529-
ctor.intersection(cx.tcx, &pat)?;
2530-
// Constructor splitting should ensure that all intersections we encounter
2531-
// are actually inclusions.
2532-
assert!(ctor.is_subrange(&pat));
2533-
} else {
2534-
// Fallback for non-ranges and ranges that involve
2535-
// floating-point numbers, which are not conveniently handled
2536-
// by `IntRange`. For these cases, the constructor may not be a
2537-
// range so intersection actually devolves into being covered
2538-
// by the pattern.
2539-
constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat)?;
2487+
match constructor {
2488+
Single => {}
2489+
IntRange(ctor) => {
2490+
let pat = IntRange::from_pat(cx.tcx, cx.param_env, pat)?;
2491+
ctor.intersection(cx.tcx, &pat)?;
2492+
// Constructor splitting should ensure that all intersections we encounter
2493+
// are actually inclusions.
2494+
assert!(ctor.is_subrange(&pat));
2495+
}
2496+
FloatRange(ctor_from, ctor_to, ctor_end) => {
2497+
let (pat_from, pat_to, pat_end, ty) = match *pat.kind {
2498+
PatKind::Constant { value } => (value, value, RangeEnd::Included, value.ty),
2499+
PatKind::Range(PatRange { lo, hi, end }) => (lo, hi, end, lo.ty),
2500+
_ => unreachable!(), // This is ensured by the branch we're in
2501+
};
2502+
let to = compare_const_vals(cx.tcx, ctor_to, pat_to, cx.param_env, ty)?;
2503+
let from = compare_const_vals(cx.tcx, ctor_from, pat_from, cx.param_env, ty)?;
2504+
let intersects = (from == Ordering::Greater || from == Ordering::Equal)
2505+
&& (to == Ordering::Less
2506+
|| (pat_end == *ctor_end && to == Ordering::Equal));
2507+
if !intersects {
2508+
return None;
2509+
}
2510+
}
2511+
ConstantValue(ctor_value) => {
2512+
let pat_value = match *pat.kind {
2513+
PatKind::Constant { value } => value,
2514+
_ => span_bug!(
2515+
pat.span,
2516+
"unexpected range pattern {:?} for constant value ctor",
2517+
pat
2518+
),
2519+
};
2520+
2521+
// FIXME: there's probably a more direct way of comparing for equality
2522+
if compare_const_vals(cx.tcx, ctor_value, pat_value, cx.param_env, pat.ty)?
2523+
!= Ordering::Equal
2524+
{
2525+
return None;
2526+
}
2527+
}
2528+
_ => {
2529+
span_bug!(pat.span, "unexpected pattern {:?} with ctor {:?}", pat, constructor)
2530+
}
25402531
}
25412532
Some(Fields::empty())
25422533
}

0 commit comments

Comments
 (0)