aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Mcguigan <[email protected]>2020-04-05 19:28:53 +0100
committerJosh Mcguigan <[email protected]>2020-04-07 13:12:08 +0100
commit5b4316377b9897f064b213a52a7efe8622d48487 (patch)
tree6abe2b962393a56a6e500a22fa24ca2e22fa200e
parent43dfd894934cf7c9161e473495a4e24965239475 (diff)
improving documentation
-rw-r--r--crates/ra_hir_ty/src/_match.rs80
1 files changed, 64 insertions, 16 deletions
diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/_match.rs
index 91206adc3..8b9bdb7cd 100644
--- a/crates/ra_hir_ty/src/_match.rs
+++ b/crates/ra_hir_ty/src/_match.rs
@@ -2,7 +2,7 @@
2//! for match arms. 2//! for match arms.
3//! 3//!
4//! It is modeled on the rustc module `librustc_mir_build::hair::pattern::_match`, which 4//! It is modeled on the rustc module `librustc_mir_build::hair::pattern::_match`, which
5//! contains very detailed documentation about the match checking algorithm. 5//! contains very detailed documentation about the algorithms used here.
6use std::sync::Arc; 6use std::sync::Arc;
7 7
8use smallvec::{smallvec, SmallVec}; 8use smallvec::{smallvec, SmallVec};
@@ -15,6 +15,14 @@ use crate::{
15use hir_def::{adt::VariantData, EnumVariantId, VariantId}; 15use hir_def::{adt::VariantData, EnumVariantId, VariantId};
16 16
17#[derive(Debug, Clone, Copy)] 17#[derive(Debug, Clone, Copy)]
18/// Either a pattern from the source code being analyzed, represented as
19/// as `PatId`, or a `Wild` pattern which is created as an intermediate
20/// step in the match checking algorithm and thus is not backed by a
21/// real `PatId`.
22///
23/// Note that it is totally valid for the `PatId` variant to contain
24/// a `PatId` which resolves to a `Wild` pattern, if that wild pattern
25/// exists in the source code being analyzed.
18enum PatIdOrWild { 26enum PatIdOrWild {
19 PatId(PatId), 27 PatId(PatId),
20 Wild, 28 Wild,
@@ -44,11 +52,22 @@ impl From<PatId> for PatIdOrWild {
44 52
45#[derive(Debug, Clone, Copy, PartialEq)] 53#[derive(Debug, Clone, Copy, PartialEq)]
46pub struct MatchCheckNotImplemented; 54pub struct MatchCheckNotImplemented;
55
56/// The return type of `is_useful` is either an indication of usefulness
57/// of the match arm, or an error in the case the match statement
58/// is made up of types for which exhaustiveness checking is currently
59/// not completely implemented.
60///
61/// The `std::result::Result` type is used here rather than a custom enum
62/// to allow the use of `?`.
47pub type MatchCheckResult<T> = Result<T, MatchCheckNotImplemented>; 63pub type MatchCheckResult<T> = Result<T, MatchCheckNotImplemented>;
48 64
49type PatStackInner = SmallVec<[PatIdOrWild; 2]>;
50#[derive(Debug)] 65#[derive(Debug)]
66/// A row in a Matrix.
67///
68/// This type is modeled from the struct of the same name in `rustc`.
51pub(crate) struct PatStack(PatStackInner); 69pub(crate) struct PatStack(PatStackInner);
70type PatStackInner = SmallVec<[PatIdOrWild; 2]>;
52 71
53impl PatStack { 72impl PatStack {
54 pub(crate) fn from_pattern(pat_id: PatId) -> PatStack { 73 pub(crate) fn from_pattern(pat_id: PatId) -> PatStack {
@@ -94,7 +113,9 @@ impl PatStack {
94 PatStack::from_vec(patterns) 113 PatStack::from_vec(patterns)
95 } 114 }
96 115
97 // Computes `D(self)`. 116 /// Computes `D(self)`.
117 ///
118 /// See the module docs and the associated documentation in rustc for details.
98 fn specialize_wildcard(&self, cx: &MatchCheckCtx) -> Option<PatStack> { 119 fn specialize_wildcard(&self, cx: &MatchCheckCtx) -> Option<PatStack> {
99 if matches!(self.head().as_pat(cx), Pat::Wild) { 120 if matches!(self.head().as_pat(cx), Pat::Wild) {
100 Some(self.to_tail()) 121 Some(self.to_tail())
@@ -103,7 +124,9 @@ impl PatStack {
103 } 124 }
104 } 125 }
105 126
106 // Computes `S(constructor, self)`. 127 /// Computes `S(constructor, self)`.
128 ///
129 /// See the module docs and the associated documentation in rustc for details.
107 fn specialize_constructor( 130 fn specialize_constructor(
108 &self, 131 &self,
109 cx: &MatchCheckCtx, 132 cx: &MatchCheckCtx,
@@ -146,6 +169,11 @@ impl PatStack {
146 Ok(result) 169 Ok(result)
147 } 170 }
148 171
172 /// A special case of `specialize_constructor` where the head of the pattern stack
173 /// is a Wild pattern.
174 ///
175 /// Replaces the Wild pattern at the head of the pattern stack with N Wild patterns
176 /// (N >= 0), where N is the arity of the given constructor.
149 fn expand_wildcard( 177 fn expand_wildcard(
150 &self, 178 &self,
151 cx: &MatchCheckCtx, 179 cx: &MatchCheckCtx,
@@ -183,6 +211,9 @@ impl PatStack {
183} 211}
184 212
185#[derive(Debug)] 213#[derive(Debug)]
214/// A collection of PatStack.
215///
216/// This type is modeled from the struct of the same name in `rustc`.
186pub(crate) struct Matrix(Vec<PatStack>); 217pub(crate) struct Matrix(Vec<PatStack>);
187 218
188impl Matrix { 219impl Matrix {
@@ -191,8 +222,8 @@ impl Matrix {
191 } 222 }
192 223
193 pub(crate) fn push(&mut self, cx: &MatchCheckCtx, row: PatStack) { 224 pub(crate) fn push(&mut self, cx: &MatchCheckCtx, row: PatStack) {
194 // if the pattern is an or pattern it should be expanded
195 if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) { 225 if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) {
226 // Or patterns are expanded here
196 for pat_id in pat_ids { 227 for pat_id in pat_ids {
197 self.0.push(PatStack::from_pattern(pat_id)); 228 self.0.push(PatStack::from_pattern(pat_id));
198 } 229 }
@@ -209,12 +240,16 @@ impl Matrix {
209 self.0.iter().map(|p| p.head()).collect() 240 self.0.iter().map(|p| p.head()).collect()
210 } 241 }
211 242
212 // Computes `D(self)`. 243 /// Computes `D(self)` for each contained PatStack.
244 ///
245 /// See the module docs and the associated documentation in rustc for details.
213 fn specialize_wildcard(&self, cx: &MatchCheckCtx) -> Self { 246 fn specialize_wildcard(&self, cx: &MatchCheckCtx) -> Self {
214 Self::collect(cx, self.0.iter().filter_map(|r| r.specialize_wildcard(cx))) 247 Self::collect(cx, self.0.iter().filter_map(|r| r.specialize_wildcard(cx)))
215 } 248 }
216 249
217 // Computes `S(constructor, self)`. 250 /// Computes `S(constructor, self)` for each contained PatStack.
251 ///
252 /// See the module docs and the associated documentation in rustc for details.
218 fn specialize_constructor( 253 fn specialize_constructor(
219 &self, 254 &self,
220 cx: &MatchCheckCtx, 255 cx: &MatchCheckCtx,
@@ -243,6 +278,11 @@ impl Matrix {
243} 278}
244 279
245#[derive(Clone, Debug, PartialEq)] 280#[derive(Clone, Debug, PartialEq)]
281/// An indication of the usefulness of a given match arm, where
282/// usefulness is defined as matching some patterns which were
283/// not matched by an prior match arms.
284///
285/// We may eventually need an `Unknown` variant here.
246pub enum Usefulness { 286pub enum Usefulness {
247 Useful, 287 Useful,
248 NotUseful, 288 NotUseful,
@@ -257,6 +297,11 @@ pub struct MatchCheckCtx<'a> {
257/// Given a set of patterns `matrix`, and pattern to consider `v`, determines 297/// Given a set of patterns `matrix`, and pattern to consider `v`, determines
258/// whether `v` is useful. A pattern is useful if it covers cases which were 298/// whether `v` is useful. A pattern is useful if it covers cases which were
259/// not previously covered. 299/// not previously covered.
300///
301/// When calling this function externally (that is, not the recursive calls) it
302/// expected that you have already type checked the match arms. All patterns in
303/// matrix should be the same type as v, as well as they should all be the same
304/// type as the match expression.
260pub(crate) fn is_useful( 305pub(crate) fn is_useful(
261 cx: &MatchCheckCtx, 306 cx: &MatchCheckCtx,
262 matrix: &Matrix, 307 matrix: &Matrix,
@@ -311,8 +356,9 @@ pub(crate) fn is_useful(
311 // We assume here that the first constructor is the "correct" type. Since we 356 // We assume here that the first constructor is the "correct" type. Since we
312 // only care about the "type" of the constructor (i.e. if it is a bool we 357 // only care about the "type" of the constructor (i.e. if it is a bool we
313 // don't care about the value), this assumption should be valid as long as 358 // don't care about the value), this assumption should be valid as long as
314 // the match statement is well formed. But potentially a better way to handle 359 // the match statement is well formed. We currently uphold this invariant by
315 // this is to use the match expressions type. 360 // filtering match arms before calling `is_useful`, only passing in match arms
361 // whose type matches the type of the match expression.
316 match &used_constructors.first() { 362 match &used_constructors.first() {
317 Some(constructor) if all_constructors_covered(&cx, constructor, &used_constructors) => { 363 Some(constructor) if all_constructors_covered(&cx, constructor, &used_constructors) => {
318 // If all constructors are covered, then we need to consider whether 364 // If all constructors are covered, then we need to consider whether
@@ -380,23 +426,25 @@ pub(crate) fn is_useful(
380} 426}
381 427
382#[derive(Debug)] 428#[derive(Debug)]
429/// Similar to TypeCtor, but includes additional information about the specific
430/// value being instantiated. For example, TypeCtor::Bool doesn't contain the
431/// boolean value.
383enum Constructor { 432enum Constructor {
384 Bool(bool), 433 Bool(bool),
385 Tuple { arity: usize }, 434 Tuple { arity: usize },
386 Enum(EnumVariantId), 435 Enum(EnumVariantId),
387} 436}
388 437
438/// Returns the constructor for the given pattern. Should only return None
439/// in the case of a Wild pattern.
389fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Option<Constructor>> { 440fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Option<Constructor>> {
390 let res = match pat.as_pat(cx) { 441 let res = match pat.as_pat(cx) {
391 Pat::Wild => None, 442 Pat::Wild => None,
392 Pat::Tuple(pats) => Some(Constructor::Tuple { arity: pats.len() }), 443 Pat::Tuple(pats) => Some(Constructor::Tuple { arity: pats.len() }),
393 Pat::Lit(lit_expr) => { 444 Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] {
394 // for now we only support bool literals 445 Expr::Literal(Literal::Bool(val)) => Some(Constructor::Bool(val)),
395 match cx.body.exprs[lit_expr] { 446 _ => return Err(MatchCheckNotImplemented),
396 Expr::Literal(Literal::Bool(val)) => Some(Constructor::Bool(val)), 447 },
397 _ => return Err(MatchCheckNotImplemented),
398 }
399 }
400 Pat::TupleStruct { .. } | Pat::Path(_) => { 448 Pat::TupleStruct { .. } | Pat::Path(_) => {
401 let pat_id = pat.as_id().expect("we already know this pattern is not a wild"); 449 let pat_id = pat.as_id().expect("we already know this pattern is not a wild");
402 let variant_id = 450 let variant_id =