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.
33///
44/// This file includes the logic for exhaustiveness and usefulness checking for
55/// pattern-matching. Specifically, given a list of patterns for a type, we can
1313/// summarise the algorithm here to hopefully save time and be a little clearer
1414/// (without being so rigorous).
1515///
16+ /// # Premise
17+ ///
1618/// The core of the algorithm revolves about a "usefulness" check. In particular, we
1719/// are trying to compute a predicate `U(P, p)` where `P` is a list of patterns (we refer to this as
1820/// a matrix). `U(P, p)` represents whether, given an existing list of patterns
2729/// pattern to those that have come before it doesn't increase the number of values
2830/// we're matching).
2931///
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.
3076/// 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
3278/// calls those pattern-vectors, and we will call them pattern-stacks. The same holds for the
3379/// new pattern `p`.
3480///
@@ -936,6 +982,9 @@ impl<'tcx> Constructor<'tcx> {
936982 }
937983}
938984
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.
939988#[ derive( Debug , Copy , Clone ) ]
940989enum FilteredField < ' p , ' tcx > {
941990 Kept ( & ' p Pat < ' tcx > ) ,
@@ -972,10 +1021,17 @@ impl<'p, 'tcx> FilteredField<'p, 'tcx> {
9721021#[ derive( Debug , Clone ) ]
9731022enum Fields < ' p , ' tcx > {
9741023 /// 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.
9751027 Slice ( & ' p [ Pat < ' tcx > ] ) ,
9761028 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+ } ,
9791035}
9801036
9811037impl < ' p , ' tcx > Fields < ' p , ' tcx > {
@@ -1098,7 +1154,8 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
10981154 pats. into_iter ( )
10991155 }
11001156
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.
11021159 fn replace_with_fieldpats (
11031160 & self ,
11041161 new_pats : impl IntoIterator < Item = & ' p FieldPat < ' tcx > > ,
@@ -1108,7 +1165,11 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
11081165 )
11091166 }
11101167
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.
11121173 fn replace_fields_indexed (
11131174 & self ,
11141175 new_pats : impl IntoIterator < Item = ( usize , & ' p Pat < ' tcx > ) > ,
0 commit comments