1
- /// Note: most tests relevant to this file can be found (at the time of writing)
2
- /// in src/tests/ui/pattern/usefulness.
1
+ /// Note: most of the tests relevant to this file can be found (at the time of writing) in
2
+ /// src/tests/ui/pattern/usefulness.
3
3
///
4
4
/// This file includes the logic for exhaustiveness and usefulness checking for
5
5
/// pattern-matching. Specifically, given a list of patterns for a type, we can
13
13
/// summarise the algorithm here to hopefully save time and be a little clearer
14
14
/// (without being so rigorous).
15
15
///
16
+ /// # Premise
17
+ ///
16
18
/// The core of the algorithm revolves about a "usefulness" check. In particular, we
17
19
/// are trying to compute a predicate `U(P, p)` where `P` is a list of patterns (we refer to this as
18
20
/// a matrix). `U(P, p)` represents whether, given an existing list of patterns
27
29
/// pattern to those that have come before it doesn't increase the number of values
28
30
/// we're matching).
29
31
///
32
+ /// # Core concept
33
+ ///
34
+ /// The idea that powers everything that is done in this file is the following: a value is made
35
+ /// from a constructor applied to some fields. Examples of constructors are `Some`, `None`, `(,)`
36
+ /// (the 2-tuple constructor), `Foo {..}` (the constructor for a struct `Foo`), and `2` (the
37
+ /// constructor for the number `2`). Fields are just a (possibly empty) list of values.
38
+ ///
39
+ /// Some of the constructors listed above might feel weird: `None` and `2` don't take any
40
+ /// arguments. This is part of what makes constructors so general: we will consider plain values
41
+ /// like numbers and string literals to be constructors that take no arguments, also called "0-ary
42
+ /// constructors"; they are the simplest case of constructors. This allows us to see any value as
43
+ /// made up from a tree of constructors, each having a given number of children. For example:
44
+ /// `(None, Ok(0))` is made from 4 different constructors.
45
+ ///
46
+ /// This idea can be extended to patterns: a pattern captures a set of possible values, and we can
47
+ /// describe this set using constructors. For example, `Err(_)` captures all values of the type
48
+ /// `Result<T, E>` that start with the `Err` constructor (for some choice of `T` and `E`). The
49
+ /// wildcard `_` captures all values of the given type starting with any of the constructors for
50
+ /// that type.
51
+ ///
52
+ /// We use this to compute whether different patterns might capture a same value. Do the patterns
53
+ /// `Ok("foo")` and `Err(_)` capture a common value? The answer is no, because the first pattern
54
+ /// captures only values starting with the `Ok` constructor and the second only values starting
55
+ /// with the `Err` constructor. Do the patterns `Some(42)` and `Some(1..10)` intersect? They might,
56
+ /// since they both capture values starting with `Some`. To be certain, we need to dig under the
57
+ /// `Some` constructor and continue asking the question. This is the main idea behind the
58
+ /// exhaustiveness algorithm: by looking at patterns constructor-by-constructor, we can efficiently
59
+ /// figure out if some new pattern might capture a value that hadn't been captured by previous
60
+ /// patterns.
61
+ ///
62
+ /// Constructors are represented by the `Constructor` enum, and its fields by the `Fields` enum.
63
+ /// Most of the complexity of this file resides in transforming between patterns and
64
+ /// (`Constructor`, `Fields`) pairs, handling all the special cases correctly.
65
+ ///
66
+ /// Caveat: this constructors/fields distinction doesn't quite cover every Rust value. For example
67
+ /// a value of type `Rc<u64>` doesn't fit this idea very well, nor do function pointers and various
68
+ /// other things. However, the idea covers everything that can be pattern-matched, and this is all
69
+ /// we need for exhaustiveness checking.
70
+ ///
71
+ ///
72
+ /// # Algorithm
73
+ ///
74
+ /// Recall that `U(P, p)` represents whether, given an existing list of patterns (aka matrix) `P`,
75
+ /// adding a new pattern `p` will cover previously-uncovered values of the type.
30
76
/// During the course of the algorithm, the rows of the matrix won't just be individual patterns,
31
- /// but rather partially-deconstructed patterns in the form of a list of patterns . The paper
77
+ /// but rather partially-deconstructed patterns in the form of a list of fields . The paper
32
78
/// calls those pattern-vectors, and we will call them pattern-stacks. The same holds for the
33
79
/// new pattern `p`.
34
80
///
@@ -936,6 +982,9 @@ impl<'tcx> Constructor<'tcx> {
936
982
}
937
983
}
938
984
985
+ /// Some fields need to be explicitely hidden away in certain cases; see the comment above the
986
+ /// `Fields` struct. This struct represents such a potentially-hidden field. When a field is hidden
987
+ /// we still keep its type around.
939
988
#[ derive( Debug , Copy , Clone ) ]
940
989
enum FilteredField < ' p , ' tcx > {
941
990
Kept ( & ' p Pat < ' tcx > ) ,
@@ -972,10 +1021,17 @@ impl<'p, 'tcx> FilteredField<'p, 'tcx> {
972
1021
#[ derive( Debug , Clone ) ]
973
1022
enum Fields < ' p , ' tcx > {
974
1023
/// Lists of patterns that don't contain any filtered fields.
1024
+ /// `Slice` and `Vec` behave the same; the difference is only to avoid allocating and
1025
+ /// triple-dereferences when possible. Frankly this is premature optimization, I (Nadrieril)
1026
+ /// have not measured if it really made a difference.
975
1027
Slice ( & ' p [ Pat < ' tcx > ] ) ,
976
1028
Vec ( SmallVec < [ & ' p Pat < ' tcx > ; 2 ] > ) ,
977
- /// Patterns where some of the fields need to be hidden.
978
- Filtered { fields : SmallVec < [ FilteredField < ' p , ' tcx > ; 2 ] > , len : usize } ,
1029
+ /// Patterns where some of the fields need to be hidden. `len` caches the number of non-hidden
1030
+ /// fields.
1031
+ Filtered {
1032
+ fields : SmallVec < [ FilteredField < ' p , ' tcx > ; 2 ] > ,
1033
+ len : usize ,
1034
+ } ,
979
1035
}
980
1036
981
1037
impl < ' p , ' tcx > Fields < ' p , ' tcx > {
@@ -1098,7 +1154,8 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
1098
1154
pats. into_iter ( )
1099
1155
}
1100
1156
1101
- /// Overrides some of the fields with the provided patterns.
1157
+ /// Overrides some of the fields with the provided patterns. Exactly like
1158
+ /// `replace_fields_indexed`, except that it takes `FieldPat`s as input.
1102
1159
fn replace_with_fieldpats (
1103
1160
& self ,
1104
1161
new_pats : impl IntoIterator < Item = & ' p FieldPat < ' tcx > > ,
@@ -1108,7 +1165,11 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
1108
1165
)
1109
1166
}
1110
1167
1111
- /// Overrides some of the fields with the provided patterns.
1168
+ /// Overrides some of the fields with the provided patterns. This is used when a pattern
1169
+ /// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start with a
1170
+ /// `Fields` that is just one wildcard per field of the `Foo` struct, and override the entry
1171
+ /// corresponding to `field1` with the pattern `Some(_)`. This is also used for slice patterns
1172
+ /// for the same reason.
1112
1173
fn replace_fields_indexed (
1113
1174
& self ,
1114
1175
new_pats : impl IntoIterator < Item = ( usize , & ' p Pat < ' tcx > ) > ,
0 commit comments