51
51
/// or `None`). This operation returns zero or more altered pattern-stacks, as follows.
52
52
/// We look at the pattern `p_1` on top of the stack, and we have four cases:
53
53
/// 1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We push
54
- /// onto the stack the arguments of this constructor, and return the result:
54
+ /// onto the stack the arguments of this constructor, and return the result:
55
55
/// r_1, .., r_a, p_2, .., p_n
56
- /// 2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and return nothing.
56
+ /// 2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and return
57
+ /// nothing.
57
58
/// 3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c`
58
- /// has arguments (its arity), and return the resulting stack:
59
+ /// has arguments (its arity), and return the resulting stack:
59
60
/// _, .., _, p_2, .., p_n
60
61
/// 4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting stack:
61
62
/// S(c, (r_1, p_2, .., p_n))
84
85
/// Inductive step. (`n > 0`)
85
86
/// We look at `p_1`, the head of the pattern-stack `p`.
86
87
///
87
- /// We first generate the list of constructors that are covered by a pattern `pat`. We name this operation
88
- /// `pat_constructors`.
89
- /// - If `pat == c(r_1, .., r_a)`, i.e. we have a constructor pattern. Then we just return `c`:
88
+ /// We first generate the list of constructors that are covered by a pattern `pat`. We name
89
+ /// this operation `pat_constructors`.
90
+ /// - If `pat == c(r_1, .., r_a)`, i.e. we have a constructor pattern. Then we just
91
+ /// return `c`:
90
92
/// `pat_constructors(pat) = [c]`
91
93
///
92
- /// - If `pat == _`, then we return the list of all possible constructors for the relevant type:
94
+ /// - If `pat == _`, then we return the list of all possible constructors for the
95
+ /// relevant type:
93
96
/// `pat_constructors(pat) = all_constructors(pat.ty)`
94
97
///
95
- /// - If `pat == r_1 | r_2`, then we return the constructors for either branch of the OR-pattern:
98
+ /// - If `pat == r_1 | r_2`, then we return the constructors for either branch of the
99
+ /// OR-pattern:
96
100
/// `pat_constructors(pat) = pat_constructors(r_1) + pat_constructors(r_2)`
97
101
///
98
102
/// Then for each constructor `c` in `pat_constructors(p_1)`, we want to check whether a value
101
105
/// For that, we only care about those rows of `M` whose first component covers the
102
106
/// constructor `c`; and for those rows that do, we want to unpack the arguments to `c` to check
103
107
/// further that `p` matches additional values.
104
- /// This is where specialization comes in: this check amounts to computing `U(S(c, M), S(c, p))`.
105
- /// More details can be found in the paper.
108
+ /// This is where specialization comes in: this check amounts to computing `U(S(c, M), S(c,
109
+ /// p))`. More details can be found in the paper.
106
110
///
107
111
/// Thus we get: `U(M, p) := ∃(c ϵ pat_constructors(p_1)) U(S(c, M), S(c, p))`
108
112
///
109
- /// Note that for c ϵ pat_constructors(p_1), `S(c, P)` always returns exactly one element, so the
110
- /// formula above makes sense.
113
+ /// Note that for c ϵ pat_constructors(p_1), `S(c, P)` always returns exactly one element, so
114
+ /// the formula above makes sense.
111
115
///
112
116
/// This algorithm however has a lot of practical issues. Most importantly, it may not terminate
113
117
/// in the presence of recursive types, since we always unpack all constructors as much
@@ -601,7 +605,7 @@ impl<'tcx> Constructor<'tcx> {
601
605
match self {
602
606
Wildcard => true ,
603
607
MissingConstructors ( _) => bug ! (
604
- "Not sure if MissingConstructors should count as a wildcard. Shouldn't happen anyways."
608
+ "Not sure if MissingConstructors should be a wildcard. Shouldn't happen anyways."
605
609
) ,
606
610
_ => false ,
607
611
}
@@ -640,38 +644,44 @@ impl<'tcx> Constructor<'tcx> {
640
644
// Any base constructor can be used unchanged.
641
645
Single | Variant ( _) | ConstantValue ( _) | FixedLenSlice ( _) => smallvec ! [ self ] ,
642
646
ConstantRange ( ..) if should_treat_range_exhaustively ( cx. tcx , & self ) => {
643
- // For exhaustive integer matching, some constructors are grouped within other constructors
644
- // (namely integer typed values are grouped within ranges). However, when specialising these
645
- // constructors, we want to be specialising for the underlying constructors (the integers), not
646
- // the groups (the ranges). Thus we need to split the groups up. Splitting them up naïvely would
647
- // mean creating a separate constructor for every single value in the range, which is clearly
648
- // impractical. However, observe that for some ranges of integers, the specialisation will be
649
- // identical across all values in that range (i.e., there are equivalence classes of ranges of
650
- // constructors based on their `is_useful_specialized` outcome). These classes are grouped by
651
- // the patterns that apply to them (in the matrix `P`). We can split the range whenever the
652
- // patterns that apply to that range (specifically: the patterns that *intersect* with that range)
653
- // change.
654
- // Our solution, therefore, is to split the range constructor into subranges at every single point
655
- // the group of intersecting patterns changes (using the method described below).
656
- // And voilà! We're testing precisely those ranges that we need to, without any exhaustive matching
657
- // on actual integers. The nice thing about this is that the number of subranges is linear in the
658
- // number of rows in the matrix (i.e., the number of cases in the `match` statement), so we don't
659
- // need to be worried about matching over gargantuan ranges.
647
+ // For exhaustive integer matching, some constructors are grouped within other
648
+ // constructors (namely integer typed values are grouped within ranges). However,
649
+ // when specialising these constructors, we want to be specialising for the
650
+ // underlying constructors (the integers), not the groups (the ranges). Thus we
651
+ // need to split the groups up. Splitting them up naïvely would mean creating a
652
+ // separate constructor for every single value in the range, which is clearly
653
+ // impractical. However, observe that for some ranges of integers, the
654
+ // specialisation will be identical across all values in that range (i.e., there
655
+ // are equivalence classes of ranges of constructors based on their
656
+ // `is_useful_specialized` outcome). These classes are grouped by the patterns that
657
+ // apply to them (in the matrix `P`). We can split the range whenever the patterns
658
+ // that apply to that range (specifically: the patterns that *intersect* with that
659
+ // range) change.
660
+ // Our solution, therefore, is to split the range constructor into subranges at
661
+ // every single point the group of intersecting patterns changes (using the method
662
+ // described below). And voilà! We're testing precisely those ranges that we need
663
+ // to, without any exhaustive matching on actual integers. The nice thing about
664
+ // this is that the number of subranges is linear in the number of rows in the
665
+ // matrix (i.e., the number of cases in the `match` statement), so we don't need to
666
+ // be worried about matching over gargantuan ranges.
660
667
//
661
- // Essentially, given the first column of a matrix representing ranges, looking like the following:
668
+ // Essentially, given the first column of a matrix representing ranges, looking
669
+ // like the following:
662
670
//
663
671
// |------| |----------| |-------| ||
664
672
// |-------| |-------| |----| ||
665
673
// |---------|
666
674
//
667
- // We split the ranges up into equivalence classes so the ranges are no longer overlapping:
675
+ // We split the ranges up into equivalence classes so the ranges are no longer
676
+ // overlapping:
668
677
//
669
678
// |--|--|||-||||--||---|||-------| |-|||| ||
670
679
//
671
- // The logic for determining how to split the ranges is fairly straightforward: we calculate
672
- // boundaries for each interval range, sort them, then create constructors for each new interval
673
- // between every pair of boundary points. (This essentially sums up to performing the intuitive
674
- // merging operation depicted above.)
680
+ // The logic for determining how to split the ranges is fairly straightforward: we
681
+ // calculate boundaries for each interval range, sort them, then create
682
+ // constructors for each new interval between every pair of boundary points. (This
683
+ // essentially sums up to performing the intuitive merging operation depicted
684
+ // above.)
675
685
676
686
// We only care about finding all the subranges within the range of the constructor
677
687
// range. Anything else is irrelevant, because it is guaranteed to result in
@@ -709,9 +719,9 @@ impl<'tcx> Constructor<'tcx> {
709
719
let mut borders: Vec < _ > = row_borders. chain ( ctor_borders) . collect ( ) ;
710
720
borders. sort_unstable ( ) ;
711
721
712
- // We're going to iterate through every adjacent pair of borders, making sure that each
713
- // represents an interval of nonnegative length, and convert each such interval
714
- // into a constructor.
722
+ // We're going to iterate through every adjacent pair of borders, making sure that
723
+ // each represents an interval of nonnegative length, and convert each such
724
+ // interval into a constructor.
715
725
borders
716
726
. windows ( 2 )
717
727
. filter_map ( |window| match ( window[ 0 ] , window[ 1 ] ) {
@@ -785,8 +795,8 @@ impl<'tcx> Constructor<'tcx> {
785
795
// to them and we can ignore the other ones. Otherwise, we have to try all
786
796
// existing constructors one-by-one.
787
797
if is_non_exhaustive {
788
- // We pretend the type has an additional `_` constructor, that counts as a missing
789
- // constructor. So we return that constructor.
798
+ // We pretend the type has an additional `_` constructor, that counts as a
799
+ // missing constructor. So we return that constructor.
790
800
smallvec ! [ Wildcard ]
791
801
} else if !missing_ctors. is_empty ( ) {
792
802
if head_ctors. is_empty ( ) {
@@ -795,17 +805,17 @@ impl<'tcx> Constructor<'tcx> {
795
805
smallvec ! [ Wildcard ]
796
806
} else {
797
807
// Otherwise, we have a set of missing constructors that is neither empty
798
- // not equal to all_constructors. Since all missing constructors will behave
799
- // the same (i.e. will be matched only by wildcards), we return a metaconstructor
800
- // that contains all of them at once.
808
+ // not equal to all_constructors. Since all missing constructors will
809
+ // behave the same (i.e. will be matched only by wildcards), we return a
810
+ // metaconstructor that contains all of them at once.
801
811
smallvec ! [ MissingConstructors ( missing_ctors) ]
802
812
}
803
813
} else {
804
- // Here we know there are no missing constructors, so we have to try all existing
805
- // constructors one-by-one.
814
+ // Here we know there are no missing constructors, so we have to try all
815
+ // existing constructors one-by-one.
806
816
let ( all_ctors, _) = missing_ctors. into_inner ( ) ;
807
- // Recursively split newly generated list of constructors. This list must not contain
808
- // any wildcards so we don't recurse infinitely.
817
+ // Recursively split newly generated list of constructors. This list must not
818
+ // contain any wildcards so we don't recurse infinitely.
809
819
all_ctors
810
820
. into_iter ( )
811
821
. flat_map ( |ctor| ctor. split_meta_constructor ( cx, pcx, head_ctors) )
@@ -816,8 +826,9 @@ impl<'tcx> Constructor<'tcx> {
816
826
}
817
827
}
818
828
819
- /// Returns a collection of constructors that spans the constructors covered by `self`, subtracted
820
- /// by the constructors covered by `head_ctors`: i.e., `self \ head_ctors` (in set notation).
829
+ /// Returns a collection of constructors that spans the constructors covered by `self`,
830
+ /// subtracted by the constructors covered by `head_ctors`: i.e., `self \ head_ctors` (in set
831
+ /// notation).
821
832
fn subtract_meta_constructor (
822
833
self ,
823
834
_pcx : PatCtxt < ' tcx > ,
@@ -1091,11 +1102,11 @@ impl<'tcx> Constructor<'tcx> {
1091
1102
let wild = Pat { ty, span : DUMMY_SP , kind : Box :: new ( PatKind :: Wild ) } ;
1092
1103
PatKind :: Slice { prefix, slice : Some ( wild) , suffix : vec ! [ ] }
1093
1104
} else {
1094
- // We don't want to output a variable-length slice pattern if the slice_patterns
1095
- // feature is not enabled.
1096
- // The constructor covers infinitely many slice lengths, but for diagnostic purposes
1097
- // it is correct to return only some examples of non-covered patterns. So we just
1098
- // return the smallest length pattern here.
1105
+ // We don't want to output a variable-length slice pattern if the
1106
+ // slice_patterns feature is not enabled.
1107
+ // The constructor covers infinitely many slice lengths, but for diagnostic
1108
+ // purposes it is correct to return only some examples of non-covered
1109
+ // patterns. So we just return the smallest length pattern here.
1099
1110
PatKind :: Slice { prefix, slice : None , suffix : vec ! [ ] }
1100
1111
}
1101
1112
}
0 commit comments