[−][src]Function rustc_mir::hair::pattern::_match::split_grouped_constructors
fn split_grouped_constructors<'p, 'a: 'p, 'tcx: 'a>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
ctors: Vec<Constructor<'tcx>>,
Matrix: &Matrix<'p, 'tcx>,
ty: Ty<'tcx>
) -> Vec<Constructor<'tcx>>
🔬 This is a nightly-only experimental API. (rustc_private
)
this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via Cargo.toml
instead?
For exhaustive integer matching, some constructors are grouped within other constructors
(namely integer typed values are grouped within ranges). However, when specialising these
constructors, we want to be specialising for the underlying constructors (the integers), not
the groups (the ranges). Thus we need to split the groups up. Splitting them up naïvely would
mean creating a separate constructor for every single value in the range, which is clearly
impractical. However, observe that for some ranges of integers, the specialisation will be
identical across all values in that range (i.e. there are equivalence classes of ranges of
constructors based on their is_useful_specialised
outcome). These classes are grouped by
the patterns that apply to them (in the matrix P
). We can split the range whenever the
patterns that apply to that range (specifically: the patterns that intersect with that range)
change.
Our solution, therefore, is to split the range constructor into subranges at every single point
the group of intersecting patterns changes (using the method described below).
And voilà! We're testing precisely those ranges that we need to, without any exhaustive matching
on actual integers. The nice thing about this is that the number of subranges is linear in the
number of rows in the matrix (i.e. the number of cases in the match
statement), so we don't
need to be worried about matching over gargantuan ranges.
Essentially, given the first column of a matrix representing ranges, looking like the following:
------ | ---------- | ------- | |||
---|---|---|---|---|---|
--------- |
We split the ranges up into equivalence classes so the ranges are no longer overlapping:
|--|--|||-||||--||---|||-------| |-|||| ||
The logic for determining how to split the ranges is fairly straightforward: we calculate boundaries for each interval range, sort them, then create constructors for each new interval between every pair of boundary points. (This essentially sums up to performing the intuitive merging operation depicted above.)