aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r--crates/ra_hir_ty/src/_match.rs1112
-rw-r--r--crates/ra_hir_ty/src/lib.rs63
2 files changed, 648 insertions, 527 deletions
diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/_match.rs
index 3e6e1e333..5495ce284 100644
--- a/crates/ra_hir_ty/src/_match.rs
+++ b/crates/ra_hir_ty/src/_match.rs
@@ -8,11 +8,11 @@
8//! This file includes the logic for exhaustiveness and usefulness checking for 8//! This file includes the logic for exhaustiveness and usefulness checking for
9//! pattern-matching. Specifically, given a list of patterns for a type, we can 9//! pattern-matching. Specifically, given a list of patterns for a type, we can
10//! tell whether: 10//! tell whether:
11//! (a) the patterns cover every possible constructor for the type [exhaustiveness] 11//! - (a) the patterns cover every possible constructor for the type (exhaustiveness).
12//! (b) each pattern is necessary [usefulness] 12//! - (b) each pattern is necessary (usefulness).
13//! 13//!
14//! The algorithm implemented here is a modified version of the one described in: 14//! The algorithm implemented here is a modified version of the one described in
15//! http://moscova.inria.fr/~maranget/papers/warn/index.html 15//! <http://moscova.inria.fr/~maranget/papers/warn/index.html>.
16//! However, to save future implementors from reading the original paper, we 16//! However, to save future implementors from reading the original paper, we
17//! summarise the algorithm here to hopefully save time and be a little clearer 17//! summarise the algorithm here to hopefully save time and be a little clearer
18//! (without being so rigorous). 18//! (without being so rigorous).
@@ -37,20 +37,26 @@
37//! new pattern `p`. 37//! new pattern `p`.
38//! 38//!
39//! For example, say we have the following: 39//! For example, say we have the following:
40//!
41//! ```ignore
42//! // x: (Option<bool>, Result<()>)
43//! match x {
44//! (Some(true), _) => {}
45//! (None, Err(())) => {}
46//! (None, Err(_)) => {}
47//! }
40//! ``` 48//! ```
41//! // x: (Option<bool>, Result<()>) 49//!
42//! match x {
43//! (Some(true), _) => {}
44//! (None, Err(())) => {}
45//! (None, Err(_)) => {}
46//! }
47//! ```
48//! Here, the matrix `P` starts as: 50//! Here, the matrix `P` starts as:
51//!
52//! ```text
49//! [ 53//! [
50//! [(Some(true), _)], 54//! [(Some(true), _)],
51//! [(None, Err(()))], 55//! [(None, Err(()))],
52//! [(None, Err(_))], 56//! [(None, Err(_))],
53//! ] 57//! ]
58//! ```
59//!
54//! We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering 60//! We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering
55//! `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because 61//! `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because
56//! all the values it covers are already covered by row 2. 62//! all the values it covers are already covered by row 2.
@@ -60,53 +66,61 @@
60//! To match the paper, the top of the stack is at the beginning / on the left. 66//! To match the paper, the top of the stack is at the beginning / on the left.
61//! 67//!
62//! There are two important operations on pattern-stacks necessary to understand the algorithm: 68//! There are two important operations on pattern-stacks necessary to understand the algorithm:
63//! 1. We can pop a given constructor off the top of a stack. This operation is called
64//! `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or
65//! `None`) and `p` a pattern-stack.
66//! If the pattern on top of the stack can cover `c`, this removes the constructor and
67//! pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns.
68//! Otherwise the pattern-stack is discarded.
69//! This essentially filters those pattern-stacks whose top covers the constructor `c` and
70//! discards the others.
71//! 69//!
72//! For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we 70//! 1. We can pop a given constructor off the top of a stack. This operation is called
73//! pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the 71//! `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or
74//! `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get 72//! `None`) and `p` a pattern-stack.
75//! nothing back. 73//! If the pattern on top of the stack can cover `c`, this removes the constructor and
74//! pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns.
75//! Otherwise the pattern-stack is discarded.
76//! This essentially filters those pattern-stacks whose top covers the constructor `c` and
77//! discards the others.
78//!
79//! For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we
80//! pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the
81//! `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get
82//! nothing back.
83//!
84//! This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1`
85//! on top of the stack, and we have four cases:
86//!
87//! * 1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We push onto
88//! the stack the arguments of this constructor, and return the result:
89//!
90//! r_1, .., r_a, p_2, .., p_n
76//! 91//!
77//! This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1` 92//! * 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and return
78//! on top of the stack, and we have four cases: 93//! nothing.
79//! 1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We 94//! * 1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has
80//! push onto the stack the arguments of this constructor, and return the result: 95//! arguments (its arity), and return the resulting stack:
81//! r_1, .., r_a, p_2, .., p_n
82//! 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and
83//! return nothing.
84//! 1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has
85//! arguments (its arity), and return the resulting stack:
86//! _, .., _, p_2, .., p_n
87//! 1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
88//! stack:
89//! S(c, (r_1, p_2, .., p_n))
90//! S(c, (r_2, p_2, .., p_n))
91//! 96//!
92//! 2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is 97//! _, .., _, p_2, .., p_n
93//! a pattern-stack.
94//! This is used when we know there are missing constructor cases, but there might be
95//! existing wildcard patterns, so to check the usefulness of the matrix, we have to check
96//! all its *other* components.
97//! 98//!
98//! It is computed as follows. We look at the pattern `p_1` on top of the stack, 99//! * 1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting stack:
99//! and we have three cases:
100//! 1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing.
101//! 1.2. `p_1 = _`. We return the rest of the stack:
102//! p_2, .., p_n
103//! 1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
104//! stack.
105//! D((r_1, p_2, .., p_n))
106//! D((r_2, p_2, .., p_n))
107//! 100//!
108//! Note that the OR-patterns are not always used directly in Rust, but are used to derive the 101//! S(c, (r_1, p_2, .., p_n))
109//! exhaustive integer matching rules, so they're written here for posterity. 102//! S(c, (r_2, p_2, .., p_n))
103//!
104//! 2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is
105//! a pattern-stack.
106//! This is used when we know there are missing constructor cases, but there might be
107//! existing wildcard patterns, so to check the usefulness of the matrix, we have to check
108//! all its *other* components.
109//!
110//! It is computed as follows. We look at the pattern `p_1` on top of the stack,
111//! and we have three cases:
112//! * 1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing.
113//! * 1.2. `p_1 = _`. We return the rest of the stack:
114//!
115//! p_2, .., p_n
116//!
117//! * 1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting stack:
118//!
119//! D((r_1, p_2, .., p_n))
120//! D((r_2, p_2, .., p_n))
121//!
122//! Note that the OR-patterns are not always used directly in Rust, but are used to derive the
123//! exhaustive integer matching rules, so they're written here for posterity.
110//! 124//!
111//! Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by 125//! Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by
112//! working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with 126//! working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with
@@ -120,73 +134,88 @@
120//! operates principally on the first component of the matrix and new pattern-stack `p`. 134//! operates principally on the first component of the matrix and new pattern-stack `p`.
121//! This algorithm is realised in the `is_useful` function. 135//! This algorithm is realised in the `is_useful` function.
122//! 136//!
123//! Base case. (`n = 0`, i.e., an empty tuple pattern) 137//! Base case (`n = 0`, i.e., an empty tuple pattern):
124//! - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`), 138//! - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`), then
125//! then `U(P, p)` is false. 139//! `U(P, p)` is false.
126//! - Otherwise, `P` must be empty, so `U(P, p)` is true. 140//! - Otherwise, `P` must be empty, so `U(P, p)` is true.
141//!
142//! Inductive step (`n > 0`, i.e., whether there's at least one column [which may then be expanded
143//! into further columns later]). We're going to match on the top of the new pattern-stack, `p_1`:
144//!
145//! - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern.
146//! Then, the usefulness of `p_1` can be reduced to whether it is useful when
147//! we ignore all the patterns in the first column of `P` that involve other constructors.
148//! This is where `S(c, P)` comes in:
149//!
150//! ```text
151//! U(P, p) := U(S(c, P), S(c, p))
152//! ```
127//! 153//!
128//! Inductive step. (`n > 0`, i.e., whether there's at least one column 154//! This special case is handled in `is_useful_specialized`.
129//! [which may then be expanded into further columns later])
130//! We're going to match on the top of the new pattern-stack, `p_1`.
131//! - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern.
132//! Then, the usefulness of `p_1` can be reduced to whether it is useful when
133//! we ignore all the patterns in the first column of `P` that involve other constructors.
134//! This is where `S(c, P)` comes in:
135//! `U(P, p) := U(S(c, P), S(c, p))`
136//! This special case is handled in `is_useful_specialized`.
137//! 155//!
138//! For example, if `P` is: 156//! For example, if `P` is:
139//! [
140//! [Some(true), _],
141//! [None, 0],
142//! ]
143//! and `p` is [Some(false), 0], then we don't care about row 2 since we know `p` only
144//! matches values that row 2 doesn't. For row 1 however, we need to dig into the
145//! arguments of `Some` to know whether some new value is covered. So we compute
146//! `U([[true, _]], [false, 0])`.
147//! 157//!
148//! - If `p_1 == _`, then we look at the list of constructors that appear in the first 158//! ```text
149//! component of the rows of `P`: 159//! [
150//! + If there are some constructors that aren't present, then we might think that the 160//! [Some(true), _],
151//! wildcard `_` is useful, since it covers those constructors that weren't covered 161//! [None, 0],
152//! before. 162//! ]
153//! That's almost correct, but only works if there were no wildcards in those first 163//! ```
154//! components. So we need to check that `p` is useful with respect to the rows that
155//! start with a wildcard, if there are any. This is where `D` comes in:
156//! `U(P, p) := U(D(P), D(p))`
157//! 164//!
158//! For example, if `P` is: 165//! and `p` is `[Some(false), 0]`, then we don't care about row 2 since we know `p` only
159//! [ 166//! matches values that row 2 doesn't. For row 1 however, we need to dig into the
160//! [_, true, _], 167//! arguments of `Some` to know whether some new value is covered. So we compute
161//! [None, false, 1], 168//! `U([[true, _]], [false, 0])`.
162//! ]
163//! and `p` is [_, false, _], the `Some` constructor doesn't appear in `P`. So if we
164//! only had row 2, we'd know that `p` is useful. However row 1 starts with a
165//! wildcard, so we need to check whether `U([[true, _]], [false, 1])`.
166//! 169//!
167//! + Otherwise, all possible constructors (for the relevant type) are present. In this 170//! - If `p_1 == _`, then we look at the list of constructors that appear in the first component of
168//! case we must check whether the wildcard pattern covers any unmatched value. For 171//! the rows of `P`:
169//! that, we can think of the `_` pattern as a big OR-pattern that covers all 172//! - If there are some constructors that aren't present, then we might think that the
170//! possible constructors. For `Option`, that would mean `_ = None | Some(_)` for 173//! wildcard `_` is useful, since it covers those constructors that weren't covered
171//! example. The wildcard pattern is useful in this case if it is useful when 174//! before.
172//! specialized to one of the possible constructors. So we compute: 175//! That's almost correct, but only works if there were no wildcards in those first
173//! `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))` 176//! components. So we need to check that `p` is useful with respect to the rows that
177//! start with a wildcard, if there are any. This is where `D` comes in:
178//! `U(P, p) := U(D(P), D(p))`
174//! 179//!
175//! For example, if `P` is: 180//! For example, if `P` is:
176//! [ 181//! ```text
177//! [Some(true), _], 182//! [
178//! [None, false], 183//! [_, true, _],
179//! ] 184//! [None, false, 1],
180//! and `p` is [_, false], both `None` and `Some` constructors appear in the first 185//! ]
181//! components of `P`. We will therefore try popping both constructors in turn: we 186//! ```
182//! compute U([[true, _]], [_, false]) for the `Some` constructor, and U([[false]], 187//! and `p` is `[_, false, _]`, the `Some` constructor doesn't appear in `P`. So if we
183//! [false]) for the `None` constructor. The first case returns true, so we know that 188//! only had row 2, we'd know that `p` is useful. However row 1 starts with a
184//! `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched 189//! wildcard, so we need to check whether `U([[true, _]], [false, 1])`.
185//! before.
186//! 190//!
187//! - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately: 191//! - Otherwise, all possible constructors (for the relevant type) are present. In this
188//! `U(P, p) := U(P, (r_1, p_2, .., p_n)) 192//! case we must check whether the wildcard pattern covers any unmatched value. For
189//! || U(P, (r_2, p_2, .., p_n))` 193//! that, we can think of the `_` pattern as a big OR-pattern that covers all
194//! possible constructors. For `Option`, that would mean `_ = None | Some(_)` for
195//! example. The wildcard pattern is useful in this case if it is useful when
196//! specialized to one of the possible constructors. So we compute:
197//! `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))`
198//!
199//! For example, if `P` is:
200//! ```text
201//! [
202//! [Some(true), _],
203//! [None, false],
204//! ]
205//! ```
206//! and `p` is `[_, false]`, both `None` and `Some` constructors appear in the first
207//! components of `P`. We will therefore try popping both constructors in turn: we
208//! compute `U([[true, _]], [_, false])` for the `Some` constructor, and `U([[false]],
209//! [false])` for the `None` constructor. The first case returns true, so we know that
210//! `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched
211//! before.
212//!
213//! - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately:
214//!
215//! ```text
216//! U(P, p) := U(P, (r_1, p_2, .., p_n))
217//! || U(P, (r_2, p_2, .., p_n))
218//! ```
190use std::sync::Arc; 219use std::sync::Arc;
191 220
192use smallvec::{smallvec, SmallVec}; 221use smallvec::{smallvec, SmallVec};
@@ -283,20 +312,16 @@ impl PatStack {
283 Self(v) 312 Self(v)
284 } 313 }
285 314
286 fn is_empty(&self) -> bool {
287 self.0.is_empty()
288 }
289
290 fn head(&self) -> PatIdOrWild {
291 self.0[0]
292 }
293
294 fn get_head(&self) -> Option<PatIdOrWild> { 315 fn get_head(&self) -> Option<PatIdOrWild> {
295 self.0.first().copied() 316 self.0.first().copied()
296 } 317 }
297 318
319 fn tail(&self) -> &[PatIdOrWild] {
320 self.0.get(1..).unwrap_or(&[])
321 }
322
298 fn to_tail(&self) -> PatStack { 323 fn to_tail(&self) -> PatStack {
299 Self::from_slice(&self.0[1..]) 324 Self::from_slice(self.tail())
300 } 325 }
301 326
302 fn replace_head_with<I, T>(&self, pats: I) -> PatStack 327 fn replace_head_with<I, T>(&self, pats: I) -> PatStack
@@ -318,7 +343,7 @@ impl PatStack {
318 /// 343 ///
319 /// See the module docs and the associated documentation in rustc for details. 344 /// See the module docs and the associated documentation in rustc for details.
320 fn specialize_wildcard(&self, cx: &MatchCheckCtx) -> Option<PatStack> { 345 fn specialize_wildcard(&self, cx: &MatchCheckCtx) -> Option<PatStack> {
321 if matches!(self.head().as_pat(cx), Pat::Wild) { 346 if matches!(self.get_head()?.as_pat(cx), Pat::Wild) {
322 Some(self.to_tail()) 347 Some(self.to_tail())
323 } else { 348 } else {
324 None 349 None
@@ -333,7 +358,13 @@ impl PatStack {
333 cx: &MatchCheckCtx, 358 cx: &MatchCheckCtx,
334 constructor: &Constructor, 359 constructor: &Constructor,
335 ) -> MatchCheckResult<Option<PatStack>> { 360 ) -> MatchCheckResult<Option<PatStack>> {
336 let result = match (self.head().as_pat(cx), constructor) { 361 let head = match self.get_head() {
362 Some(head) => head,
363 None => return Ok(None),
364 };
365
366 let head_pat = head.as_pat(cx);
367 let result = match (head_pat, constructor) {
337 (Pat::Tuple { args: ref pat_ids, ellipsis }, Constructor::Tuple { arity: _ }) => { 368 (Pat::Tuple { args: ref pat_ids, ellipsis }, Constructor::Tuple { arity: _ }) => {
338 if ellipsis.is_some() { 369 if ellipsis.is_some() {
339 // If there are ellipsis here, we should add the correct number of 370 // If there are ellipsis here, we should add the correct number of
@@ -360,7 +391,7 @@ impl PatStack {
360 (Pat::Wild, constructor) => Some(self.expand_wildcard(cx, constructor)?), 391 (Pat::Wild, constructor) => Some(self.expand_wildcard(cx, constructor)?),
361 (Pat::Path(_), Constructor::Enum(constructor)) => { 392 (Pat::Path(_), Constructor::Enum(constructor)) => {
362 // unit enum variants become `Pat::Path` 393 // unit enum variants become `Pat::Path`
363 let pat_id = self.head().as_id().expect("we know this isn't a wild"); 394 let pat_id = head.as_id().expect("we know this isn't a wild");
364 if !enum_variant_matches(cx, pat_id, *constructor) { 395 if !enum_variant_matches(cx, pat_id, *constructor) {
365 None 396 None
366 } else { 397 } else {
@@ -371,7 +402,7 @@ impl PatStack {
371 Pat::TupleStruct { args: ref pat_ids, ellipsis, .. }, 402 Pat::TupleStruct { args: ref pat_ids, ellipsis, .. },
372 Constructor::Enum(enum_constructor), 403 Constructor::Enum(enum_constructor),
373 ) => { 404 ) => {
374 let pat_id = self.head().as_id().expect("we know this isn't a wild"); 405 let pat_id = head.as_id().expect("we know this isn't a wild");
375 if !enum_variant_matches(cx, pat_id, *enum_constructor) { 406 if !enum_variant_matches(cx, pat_id, *enum_constructor) {
376 None 407 None
377 } else { 408 } else {
@@ -411,7 +442,7 @@ impl PatStack {
411 } 442 }
412 } 443 }
413 (Pat::Record { args: ref arg_patterns, .. }, Constructor::Enum(e)) => { 444 (Pat::Record { args: ref arg_patterns, .. }, Constructor::Enum(e)) => {
414 let pat_id = self.head().as_id().expect("we know this isn't a wild"); 445 let pat_id = head.as_id().expect("we know this isn't a wild");
415 if !enum_variant_matches(cx, pat_id, *e) { 446 if !enum_variant_matches(cx, pat_id, *e) {
416 None 447 None
417 } else { 448 } else {
@@ -457,7 +488,7 @@ impl PatStack {
457 ) -> MatchCheckResult<PatStack> { 488 ) -> MatchCheckResult<PatStack> {
458 assert_eq!( 489 assert_eq!(
459 Pat::Wild, 490 Pat::Wild,
460 self.head().as_pat(cx), 491 self.get_head().expect("expand_wildcard called on empty PatStack").as_pat(cx),
461 "expand_wildcard must only be called on PatStack with wild at head", 492 "expand_wildcard must only be called on PatStack with wild at head",
462 ); 493 );
463 494
@@ -475,7 +506,6 @@ impl PatStack {
475 } 506 }
476} 507}
477 508
478#[derive(Debug)]
479/// A collection of PatStack. 509/// A collection of PatStack.
480/// 510///
481/// This type is modeled from the struct of the same name in `rustc`. 511/// This type is modeled from the struct of the same name in `rustc`.
@@ -502,7 +532,7 @@ impl Matrix {
502 } 532 }
503 533
504 fn heads(&self) -> Vec<PatIdOrWild> { 534 fn heads(&self) -> Vec<PatIdOrWild> {
505 self.0.iter().map(|p| p.head()).collect() 535 self.0.iter().flat_map(|p| p.get_head()).collect()
506 } 536 }
507 537
508 /// Computes `D(self)` for each contained PatStack. 538 /// Computes `D(self)` for each contained PatStack.
@@ -589,13 +619,16 @@ pub(crate) fn is_useful(
589 _ => (), 619 _ => (),
590 } 620 }
591 621
592 if v.is_empty() { 622 let head = match v.get_head() {
593 let result = if matrix.is_empty() { Usefulness::Useful } else { Usefulness::NotUseful }; 623 Some(head) => head,
624 None => {
625 let result = if matrix.is_empty() { Usefulness::Useful } else { Usefulness::NotUseful };
594 626
595 return Ok(result); 627 return Ok(result);
596 } 628 }
629 };
597 630
598 if let Pat::Or(pat_ids) = v.head().as_pat(cx) { 631 if let Pat::Or(pat_ids) = head.as_pat(cx) {
599 let mut found_unimplemented = false; 632 let mut found_unimplemented = false;
600 let any_useful = pat_ids.iter().any(|&pat_id| { 633 let any_useful = pat_ids.iter().any(|&pat_id| {
601 let v = PatStack::from_pattern(pat_id); 634 let v = PatStack::from_pattern(pat_id);
@@ -619,7 +652,7 @@ pub(crate) fn is_useful(
619 }; 652 };
620 } 653 }
621 654
622 if let Some(constructor) = pat_constructor(cx, v.head())? { 655 if let Some(constructor) = pat_constructor(cx, head)? {
623 let matrix = matrix.specialize_constructor(&cx, &constructor)?; 656 let matrix = matrix.specialize_constructor(&cx, &constructor)?;
624 let v = v 657 let v = v
625 .specialize_constructor(&cx, &constructor)? 658 .specialize_constructor(&cx, &constructor)?
@@ -808,194 +841,193 @@ mod tests {
808 841
809 pub(super) use crate::{diagnostics::MissingMatchArms, test_db::TestDB}; 842 pub(super) use crate::{diagnostics::MissingMatchArms, test_db::TestDB};
810 843
811 pub(super) fn check_diagnostic_message(content: &str) -> String { 844 pub(super) fn check_diagnostic_message(ra_fixture: &str) -> String {
812 TestDB::with_single_file(content).0.diagnostic::<MissingMatchArms>().0 845 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().0
813 } 846 }
814 847
815 pub(super) fn check_diagnostic(content: &str) { 848 pub(super) fn check_diagnostic(ra_fixture: &str) {
816 let diagnostic_count = 849 let diagnostic_count =
817 TestDB::with_single_file(content).0.diagnostic::<MissingMatchArms>().1; 850 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().1;
818 851
819 assert_eq!(1, diagnostic_count, "no diagnostic reported"); 852 assert_eq!(1, diagnostic_count, "no diagnostic reported");
820 } 853 }
821 854
822 pub(super) fn check_no_diagnostic(content: &str) { 855 pub(super) fn check_no_diagnostic(ra_fixture: &str) {
823 let diagnostic_count = 856 let (s, diagnostic_count) =
824 TestDB::with_single_file(content).0.diagnostic::<MissingMatchArms>().1; 857 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>();
825 858
826 assert_eq!(0, diagnostic_count, "expected no diagnostic, found one"); 859 assert_eq!(0, diagnostic_count, "expected no diagnostic, found one: {}", s);
827 } 860 }
828 861
829 #[test] 862 #[test]
830 fn empty_tuple_no_arms_diagnostic_message() { 863 fn empty_tuple_no_arms_diagnostic_message() {
831 let content = r"
832 fn test_fn() {
833 match () {
834 }
835 }
836 ";
837
838 assert_snapshot!( 864 assert_snapshot!(
839 check_diagnostic_message(content), 865 check_diagnostic_message(r"
866 fn test_fn() {
867 match () {
868 }
869 }
870 "),
840 @"\"()\": Missing match arm\n" 871 @"\"()\": Missing match arm\n"
841 ); 872 );
842 } 873 }
843 874
844 #[test] 875 #[test]
845 fn empty_tuple_no_arms() { 876 fn empty_tuple_no_arms() {
846 let content = r" 877 check_diagnostic(
878 r"
847 fn test_fn() { 879 fn test_fn() {
848 match () { 880 match () {
849 } 881 }
850 } 882 }
851 "; 883 ",
852 884 );
853 check_diagnostic(content);
854 } 885 }
855 886
856 #[test] 887 #[test]
857 fn empty_tuple_wild() { 888 fn empty_tuple_wild() {
858 let content = r" 889 check_no_diagnostic(
890 r"
859 fn test_fn() { 891 fn test_fn() {
860 match () { 892 match () {
861 _ => {} 893 _ => {}
862 } 894 }
863 } 895 }
864 "; 896 ",
865 897 );
866 check_no_diagnostic(content);
867 } 898 }
868 899
869 #[test] 900 #[test]
870 fn empty_tuple_no_diagnostic() { 901 fn empty_tuple_no_diagnostic() {
871 let content = r" 902 check_no_diagnostic(
903 r"
872 fn test_fn() { 904 fn test_fn() {
873 match () { 905 match () {
874 () => {} 906 () => {}
875 } 907 }
876 } 908 }
877 "; 909 ",
878 910 );
879 check_no_diagnostic(content);
880 } 911 }
881 912
882 #[test] 913 #[test]
883 fn tuple_of_empty_tuple_no_arms() { 914 fn tuple_of_empty_tuple_no_arms() {
884 let content = r" 915 check_diagnostic(
916 r"
885 fn test_fn() { 917 fn test_fn() {
886 match (()) { 918 match (()) {
887 } 919 }
888 } 920 }
889 "; 921 ",
890 922 );
891 check_diagnostic(content);
892 } 923 }
893 924
894 #[test] 925 #[test]
895 fn tuple_of_empty_tuple_no_diagnostic() { 926 fn tuple_of_empty_tuple_no_diagnostic() {
896 let content = r" 927 check_no_diagnostic(
928 r"
897 fn test_fn() { 929 fn test_fn() {
898 match (()) { 930 match (()) {
899 (()) => {} 931 (()) => {}
900 } 932 }
901 } 933 }
902 "; 934 ",
903 935 );
904 check_no_diagnostic(content);
905 } 936 }
906 937
907 #[test] 938 #[test]
908 fn tuple_of_two_empty_tuple_no_arms() { 939 fn tuple_of_two_empty_tuple_no_arms() {
909 let content = r" 940 check_diagnostic(
941 r"
910 fn test_fn() { 942 fn test_fn() {
911 match ((), ()) { 943 match ((), ()) {
912 } 944 }
913 } 945 }
914 "; 946 ",
915 947 );
916 check_diagnostic(content);
917 } 948 }
918 949
919 #[test] 950 #[test]
920 fn tuple_of_two_empty_tuple_no_diagnostic() { 951 fn tuple_of_two_empty_tuple_no_diagnostic() {
921 let content = r" 952 check_no_diagnostic(
953 r"
922 fn test_fn() { 954 fn test_fn() {
923 match ((), ()) { 955 match ((), ()) {
924 ((), ()) => {} 956 ((), ()) => {}
925 } 957 }
926 } 958 }
927 "; 959 ",
928 960 );
929 check_no_diagnostic(content);
930 } 961 }
931 962
932 #[test] 963 #[test]
933 fn bool_no_arms() { 964 fn bool_no_arms() {
934 let content = r" 965 check_diagnostic(
966 r"
935 fn test_fn() { 967 fn test_fn() {
936 match false { 968 match false {
937 } 969 }
938 } 970 }
939 "; 971 ",
940 972 );
941 check_diagnostic(content);
942 } 973 }
943 974
944 #[test] 975 #[test]
945 fn bool_missing_arm() { 976 fn bool_missing_arm() {
946 let content = r" 977 check_diagnostic(
978 r"
947 fn test_fn() { 979 fn test_fn() {
948 match false { 980 match false {
949 true => {} 981 true => {}
950 } 982 }
951 } 983 }
952 "; 984 ",
953 985 );
954 check_diagnostic(content);
955 } 986 }
956 987
957 #[test] 988 #[test]
958 fn bool_no_diagnostic() { 989 fn bool_no_diagnostic() {
959 let content = r" 990 check_no_diagnostic(
991 r"
960 fn test_fn() { 992 fn test_fn() {
961 match false { 993 match false {
962 true => {} 994 true => {}
963 false => {} 995 false => {}
964 } 996 }
965 } 997 }
966 "; 998 ",
967 999 );
968 check_no_diagnostic(content);
969 } 1000 }
970 1001
971 #[test] 1002 #[test]
972 fn tuple_of_bools_no_arms() { 1003 fn tuple_of_bools_no_arms() {
973 let content = r" 1004 check_diagnostic(
1005 r"
974 fn test_fn() { 1006 fn test_fn() {
975 match (false, true) { 1007 match (false, true) {
976 } 1008 }
977 } 1009 }
978 "; 1010 ",
979 1011 );
980 check_diagnostic(content);
981 } 1012 }
982 1013
983 #[test] 1014 #[test]
984 fn tuple_of_bools_missing_arms() { 1015 fn tuple_of_bools_missing_arms() {
985 let content = r" 1016 check_diagnostic(
1017 r"
986 fn test_fn() { 1018 fn test_fn() {
987 match (false, true) { 1019 match (false, true) {
988 (true, true) => {}, 1020 (true, true) => {},
989 } 1021 }
990 } 1022 }
991 "; 1023 ",
992 1024 );
993 check_diagnostic(content);
994 } 1025 }
995 1026
996 #[test] 1027 #[test]
997 fn tuple_of_bools_missing_arm() { 1028 fn tuple_of_bools_missing_arm() {
998 let content = r" 1029 check_diagnostic(
1030 r"
999 fn test_fn() { 1031 fn test_fn() {
1000 match (false, true) { 1032 match (false, true) {
1001 (false, true) => {}, 1033 (false, true) => {},
@@ -1003,14 +1035,14 @@ mod tests {
1003 (true, false) => {}, 1035 (true, false) => {},
1004 } 1036 }
1005 } 1037 }
1006 "; 1038 ",
1007 1039 );
1008 check_diagnostic(content);
1009 } 1040 }
1010 1041
1011 #[test] 1042 #[test]
1012 fn tuple_of_bools_with_wilds() { 1043 fn tuple_of_bools_with_wilds() {
1013 let content = r" 1044 check_no_diagnostic(
1045 r"
1014 fn test_fn() { 1046 fn test_fn() {
1015 match (false, true) { 1047 match (false, true) {
1016 (false, _) => {}, 1048 (false, _) => {},
@@ -1018,14 +1050,14 @@ mod tests {
1018 (_, true) => {}, 1050 (_, true) => {},
1019 } 1051 }
1020 } 1052 }
1021 "; 1053 ",
1022 1054 );
1023 check_no_diagnostic(content);
1024 } 1055 }
1025 1056
1026 #[test] 1057 #[test]
1027 fn tuple_of_bools_no_diagnostic() { 1058 fn tuple_of_bools_no_diagnostic() {
1028 let content = r" 1059 check_no_diagnostic(
1060 r"
1029 fn test_fn() { 1061 fn test_fn() {
1030 match (false, true) { 1062 match (false, true) {
1031 (true, true) => {}, 1063 (true, true) => {},
@@ -1034,27 +1066,27 @@ mod tests {
1034 (false, false) => {}, 1066 (false, false) => {},
1035 } 1067 }
1036 } 1068 }
1037 "; 1069 ",
1038 1070 );
1039 check_no_diagnostic(content);
1040 } 1071 }
1041 1072
1042 #[test] 1073 #[test]
1043 fn tuple_of_bools_binding_missing_arms() { 1074 fn tuple_of_bools_binding_missing_arms() {
1044 let content = r" 1075 check_diagnostic(
1076 r"
1045 fn test_fn() { 1077 fn test_fn() {
1046 match (false, true) { 1078 match (false, true) {
1047 (true, _x) => {}, 1079 (true, _x) => {},
1048 } 1080 }
1049 } 1081 }
1050 "; 1082 ",
1051 1083 );
1052 check_diagnostic(content);
1053 } 1084 }
1054 1085
1055 #[test] 1086 #[test]
1056 fn tuple_of_bools_binding_no_diagnostic() { 1087 fn tuple_of_bools_binding_no_diagnostic() {
1057 let content = r" 1088 check_no_diagnostic(
1089 r"
1058 fn test_fn() { 1090 fn test_fn() {
1059 match (false, true) { 1091 match (false, true) {
1060 (true, _x) => {}, 1092 (true, _x) => {},
@@ -1062,80 +1094,80 @@ mod tests {
1062 (false, false) => {}, 1094 (false, false) => {},
1063 } 1095 }
1064 } 1096 }
1065 "; 1097 ",
1066 1098 );
1067 check_no_diagnostic(content);
1068 } 1099 }
1069 1100
1070 #[test] 1101 #[test]
1071 fn tuple_of_bools_with_ellipsis_at_end_no_diagnostic() { 1102 fn tuple_of_bools_with_ellipsis_at_end_no_diagnostic() {
1072 let content = r" 1103 check_no_diagnostic(
1104 r"
1073 fn test_fn() { 1105 fn test_fn() {
1074 match (false, true, false) { 1106 match (false, true, false) {
1075 (false, ..) => {}, 1107 (false, ..) => {},
1076 (true, ..) => {}, 1108 (true, ..) => {},
1077 } 1109 }
1078 } 1110 }
1079 "; 1111 ",
1080 1112 );
1081 check_no_diagnostic(content);
1082 } 1113 }
1083 1114
1084 #[test] 1115 #[test]
1085 fn tuple_of_bools_with_ellipsis_at_beginning_no_diagnostic() { 1116 fn tuple_of_bools_with_ellipsis_at_beginning_no_diagnostic() {
1086 let content = r" 1117 check_no_diagnostic(
1118 r"
1087 fn test_fn() { 1119 fn test_fn() {
1088 match (false, true, false) { 1120 match (false, true, false) {
1089 (.., false) => {}, 1121 (.., false) => {},
1090 (.., true) => {}, 1122 (.., true) => {},
1091 } 1123 }
1092 } 1124 }
1093 "; 1125 ",
1094 1126 );
1095 check_no_diagnostic(content);
1096 } 1127 }
1097 1128
1098 #[test] 1129 #[test]
1099 fn tuple_of_bools_with_ellipsis_no_diagnostic() { 1130 fn tuple_of_bools_with_ellipsis_no_diagnostic() {
1100 let content = r" 1131 check_no_diagnostic(
1132 r"
1101 fn test_fn() { 1133 fn test_fn() {
1102 match (false, true, false) { 1134 match (false, true, false) {
1103 (..) => {}, 1135 (..) => {},
1104 } 1136 }
1105 } 1137 }
1106 "; 1138 ",
1107 1139 );
1108 check_no_diagnostic(content);
1109 } 1140 }
1110 1141
1111 #[test] 1142 #[test]
1112 fn tuple_of_tuple_and_bools_no_arms() { 1143 fn tuple_of_tuple_and_bools_no_arms() {
1113 let content = r" 1144 check_diagnostic(
1145 r"
1114 fn test_fn() { 1146 fn test_fn() {
1115 match (false, ((), false)) { 1147 match (false, ((), false)) {
1116 } 1148 }
1117 } 1149 }
1118 "; 1150 ",
1119 1151 );
1120 check_diagnostic(content);
1121 } 1152 }
1122 1153
1123 #[test] 1154 #[test]
1124 fn tuple_of_tuple_and_bools_missing_arms() { 1155 fn tuple_of_tuple_and_bools_missing_arms() {
1125 let content = r" 1156 check_diagnostic(
1157 r"
1126 fn test_fn() { 1158 fn test_fn() {
1127 match (false, ((), false)) { 1159 match (false, ((), false)) {
1128 (true, ((), true)) => {}, 1160 (true, ((), true)) => {},
1129 } 1161 }
1130 } 1162 }
1131 "; 1163 ",
1132 1164 );
1133 check_diagnostic(content);
1134 } 1165 }
1135 1166
1136 #[test] 1167 #[test]
1137 fn tuple_of_tuple_and_bools_no_diagnostic() { 1168 fn tuple_of_tuple_and_bools_no_diagnostic() {
1138 let content = r" 1169 check_no_diagnostic(
1170 r"
1139 fn test_fn() { 1171 fn test_fn() {
1140 match (false, ((), false)) { 1172 match (false, ((), false)) {
1141 (true, ((), true)) => {}, 1173 (true, ((), true)) => {},
@@ -1144,27 +1176,27 @@ mod tests {
1144 (false, ((), false)) => {}, 1176 (false, ((), false)) => {},
1145 } 1177 }
1146 } 1178 }
1147 "; 1179 ",
1148 1180 );
1149 check_no_diagnostic(content);
1150 } 1181 }
1151 1182
1152 #[test] 1183 #[test]
1153 fn tuple_of_tuple_and_bools_wildcard_missing_arms() { 1184 fn tuple_of_tuple_and_bools_wildcard_missing_arms() {
1154 let content = r" 1185 check_diagnostic(
1186 r"
1155 fn test_fn() { 1187 fn test_fn() {
1156 match (false, ((), false)) { 1188 match (false, ((), false)) {
1157 (true, _) => {}, 1189 (true, _) => {},
1158 } 1190 }
1159 } 1191 }
1160 "; 1192 ",
1161 1193 );
1162 check_diagnostic(content);
1163 } 1194 }
1164 1195
1165 #[test] 1196 #[test]
1166 fn tuple_of_tuple_and_bools_wildcard_no_diagnostic() { 1197 fn tuple_of_tuple_and_bools_wildcard_no_diagnostic() {
1167 let content = r" 1198 check_no_diagnostic(
1199 r"
1168 fn test_fn() { 1200 fn test_fn() {
1169 match (false, ((), false)) { 1201 match (false, ((), false)) {
1170 (true, ((), true)) => {}, 1202 (true, ((), true)) => {},
@@ -1172,14 +1204,14 @@ mod tests {
1172 (false, _) => {}, 1204 (false, _) => {},
1173 } 1205 }
1174 } 1206 }
1175 "; 1207 ",
1176 1208 );
1177 check_no_diagnostic(content);
1178 } 1209 }
1179 1210
1180 #[test] 1211 #[test]
1181 fn enum_no_arms() { 1212 fn enum_no_arms() {
1182 let content = r" 1213 check_diagnostic(
1214 r"
1183 enum Either { 1215 enum Either {
1184 A, 1216 A,
1185 B, 1217 B,
@@ -1188,14 +1220,14 @@ mod tests {
1188 match Either::A { 1220 match Either::A {
1189 } 1221 }
1190 } 1222 }
1191 "; 1223 ",
1192 1224 );
1193 check_diagnostic(content);
1194 } 1225 }
1195 1226
1196 #[test] 1227 #[test]
1197 fn enum_missing_arms() { 1228 fn enum_missing_arms() {
1198 let content = r" 1229 check_diagnostic(
1230 r"
1199 enum Either { 1231 enum Either {
1200 A, 1232 A,
1201 B, 1233 B,
@@ -1205,14 +1237,14 @@ mod tests {
1205 Either::A => {}, 1237 Either::A => {},
1206 } 1238 }
1207 } 1239 }
1208 "; 1240 ",
1209 1241 );
1210 check_diagnostic(content);
1211 } 1242 }
1212 1243
1213 #[test] 1244 #[test]
1214 fn enum_no_diagnostic() { 1245 fn enum_no_diagnostic() {
1215 let content = r" 1246 check_no_diagnostic(
1247 r"
1216 enum Either { 1248 enum Either {
1217 A, 1249 A,
1218 B, 1250 B,
@@ -1223,14 +1255,14 @@ mod tests {
1223 Either::B => {}, 1255 Either::B => {},
1224 } 1256 }
1225 } 1257 }
1226 "; 1258 ",
1227 1259 );
1228 check_no_diagnostic(content);
1229 } 1260 }
1230 1261
1231 #[test] 1262 #[test]
1232 fn enum_ref_missing_arms() { 1263 fn enum_ref_missing_arms() {
1233 let content = r" 1264 check_diagnostic(
1265 r"
1234 enum Either { 1266 enum Either {
1235 A, 1267 A,
1236 B, 1268 B,
@@ -1240,14 +1272,14 @@ mod tests {
1240 Either::A => {}, 1272 Either::A => {},
1241 } 1273 }
1242 } 1274 }
1243 "; 1275 ",
1244 1276 );
1245 check_diagnostic(content);
1246 } 1277 }
1247 1278
1248 #[test] 1279 #[test]
1249 fn enum_ref_no_diagnostic() { 1280 fn enum_ref_no_diagnostic() {
1250 let content = r" 1281 check_no_diagnostic(
1282 r"
1251 enum Either { 1283 enum Either {
1252 A, 1284 A,
1253 B, 1285 B,
@@ -1258,14 +1290,14 @@ mod tests {
1258 Either::B => {}, 1290 Either::B => {},
1259 } 1291 }
1260 } 1292 }
1261 "; 1293 ",
1262 1294 );
1263 check_no_diagnostic(content);
1264 } 1295 }
1265 1296
1266 #[test] 1297 #[test]
1267 fn enum_containing_bool_no_arms() { 1298 fn enum_containing_bool_no_arms() {
1268 let content = r" 1299 check_diagnostic(
1300 r"
1269 enum Either { 1301 enum Either {
1270 A(bool), 1302 A(bool),
1271 B, 1303 B,
@@ -1274,14 +1306,14 @@ mod tests {
1274 match Either::B { 1306 match Either::B {
1275 } 1307 }
1276 } 1308 }
1277 "; 1309 ",
1278 1310 );
1279 check_diagnostic(content);
1280 } 1311 }
1281 1312
1282 #[test] 1313 #[test]
1283 fn enum_containing_bool_missing_arms() { 1314 fn enum_containing_bool_missing_arms() {
1284 let content = r" 1315 check_diagnostic(
1316 r"
1285 enum Either { 1317 enum Either {
1286 A(bool), 1318 A(bool),
1287 B, 1319 B,
@@ -1292,14 +1324,14 @@ mod tests {
1292 Either::B => (), 1324 Either::B => (),
1293 } 1325 }
1294 } 1326 }
1295 "; 1327 ",
1296 1328 );
1297 check_diagnostic(content);
1298 } 1329 }
1299 1330
1300 #[test] 1331 #[test]
1301 fn enum_containing_bool_no_diagnostic() { 1332 fn enum_containing_bool_no_diagnostic() {
1302 let content = r" 1333 check_no_diagnostic(
1334 r"
1303 enum Either { 1335 enum Either {
1304 A(bool), 1336 A(bool),
1305 B, 1337 B,
@@ -1311,14 +1343,14 @@ mod tests {
1311 Either::B => (), 1343 Either::B => (),
1312 } 1344 }
1313 } 1345 }
1314 "; 1346 ",
1315 1347 );
1316 check_no_diagnostic(content);
1317 } 1348 }
1318 1349
1319 #[test] 1350 #[test]
1320 fn enum_containing_bool_with_wild_no_diagnostic() { 1351 fn enum_containing_bool_with_wild_no_diagnostic() {
1321 let content = r" 1352 check_no_diagnostic(
1353 r"
1322 enum Either { 1354 enum Either {
1323 A(bool), 1355 A(bool),
1324 B, 1356 B,
@@ -1329,14 +1361,14 @@ mod tests {
1329 _ => (), 1361 _ => (),
1330 } 1362 }
1331 } 1363 }
1332 "; 1364 ",
1333 1365 );
1334 check_no_diagnostic(content);
1335 } 1366 }
1336 1367
1337 #[test] 1368 #[test]
1338 fn enum_containing_bool_with_wild_2_no_diagnostic() { 1369 fn enum_containing_bool_with_wild_2_no_diagnostic() {
1339 let content = r" 1370 check_no_diagnostic(
1371 r"
1340 enum Either { 1372 enum Either {
1341 A(bool), 1373 A(bool),
1342 B, 1374 B,
@@ -1347,14 +1379,14 @@ mod tests {
1347 Either::B => (), 1379 Either::B => (),
1348 } 1380 }
1349 } 1381 }
1350 "; 1382 ",
1351 1383 );
1352 check_no_diagnostic(content);
1353 } 1384 }
1354 1385
1355 #[test] 1386 #[test]
1356 fn enum_different_sizes_missing_arms() { 1387 fn enum_different_sizes_missing_arms() {
1357 let content = r" 1388 check_diagnostic(
1389 r"
1358 enum Either { 1390 enum Either {
1359 A(bool), 1391 A(bool),
1360 B(bool, bool), 1392 B(bool, bool),
@@ -1365,14 +1397,14 @@ mod tests {
1365 Either::B(false, _) => (), 1397 Either::B(false, _) => (),
1366 } 1398 }
1367 } 1399 }
1368 "; 1400 ",
1369 1401 );
1370 check_diagnostic(content);
1371 } 1402 }
1372 1403
1373 #[test] 1404 #[test]
1374 fn enum_different_sizes_no_diagnostic() { 1405 fn enum_different_sizes_no_diagnostic() {
1375 let content = r" 1406 check_no_diagnostic(
1407 r"
1376 enum Either { 1408 enum Either {
1377 A(bool), 1409 A(bool),
1378 B(bool, bool), 1410 B(bool, bool),
@@ -1384,14 +1416,14 @@ mod tests {
1384 Either::B(false, _) => (), 1416 Either::B(false, _) => (),
1385 } 1417 }
1386 } 1418 }
1387 "; 1419 ",
1388 1420 );
1389 check_no_diagnostic(content);
1390 } 1421 }
1391 1422
1392 #[test] 1423 #[test]
1393 fn or_no_diagnostic() { 1424 fn or_no_diagnostic() {
1394 let content = r" 1425 check_no_diagnostic(
1426 r"
1395 enum Either { 1427 enum Either {
1396 A(bool), 1428 A(bool),
1397 B(bool, bool), 1429 B(bool, bool),
@@ -1403,14 +1435,14 @@ mod tests {
1403 Either::B(false, _) => (), 1435 Either::B(false, _) => (),
1404 } 1436 }
1405 } 1437 }
1406 "; 1438 ",
1407 1439 );
1408 check_no_diagnostic(content);
1409 } 1440 }
1410 1441
1411 #[test] 1442 #[test]
1412 fn tuple_of_enum_no_diagnostic() { 1443 fn tuple_of_enum_no_diagnostic() {
1413 let content = r" 1444 check_no_diagnostic(
1445 r"
1414 enum Either { 1446 enum Either {
1415 A(bool), 1447 A(bool),
1416 B(bool, bool), 1448 B(bool, bool),
@@ -1427,14 +1459,16 @@ mod tests {
1427 (Either::B(_, _), Either2::D) => (), 1459 (Either::B(_, _), Either2::D) => (),
1428 } 1460 }
1429 } 1461 }
1430 "; 1462 ",
1431 1463 );
1432 check_no_diagnostic(content);
1433 } 1464 }
1434 1465
1435 #[test] 1466 #[test]
1436 fn mismatched_types() { 1467 fn mismatched_types() {
1437 let content = r" 1468 // Match statements with arms that don't match the
1469 // expression pattern do not fire this diagnostic.
1470 check_no_diagnostic(
1471 r"
1438 enum Either { 1472 enum Either {
1439 A, 1473 A,
1440 B, 1474 B,
@@ -1449,47 +1483,47 @@ mod tests {
1449 Either2::D => (), 1483 Either2::D => (),
1450 } 1484 }
1451 } 1485 }
1452 "; 1486 ",
1453 1487 );
1454 // Match statements with arms that don't match the
1455 // expression pattern do not fire this diagnostic.
1456 check_no_diagnostic(content);
1457 } 1488 }
1458 1489
1459 #[test] 1490 #[test]
1460 fn mismatched_types_with_different_arity() { 1491 fn mismatched_types_with_different_arity() {
1461 let content = r" 1492 // Match statements with arms that don't match the
1493 // expression pattern do not fire this diagnostic.
1494 check_no_diagnostic(
1495 r"
1462 fn test_fn() { 1496 fn test_fn() {
1463 match (true, false) { 1497 match (true, false) {
1464 (true, false, true) => (), 1498 (true, false, true) => (),
1465 (true) => (), 1499 (true) => (),
1466 } 1500 }
1467 } 1501 }
1468 "; 1502 ",
1469 1503 );
1470 // Match statements with arms that don't match the
1471 // expression pattern do not fire this diagnostic.
1472 check_no_diagnostic(content);
1473 } 1504 }
1474 1505
1475 #[test] 1506 #[test]
1476 fn malformed_match_arm_tuple_missing_pattern() { 1507 fn malformed_match_arm_tuple_missing_pattern() {
1477 let content = r" 1508 // Match statements with arms that don't match the
1509 // expression pattern do not fire this diagnostic.
1510 check_no_diagnostic(
1511 r"
1478 fn test_fn() { 1512 fn test_fn() {
1479 match (0) { 1513 match (0) {
1480 () => (), 1514 () => (),
1481 } 1515 }
1482 } 1516 }
1483 "; 1517 ",
1484 1518 );
1485 // Match statements with arms that don't match the
1486 // expression pattern do not fire this diagnostic.
1487 check_no_diagnostic(content);
1488 } 1519 }
1489 1520
1490 #[test] 1521 #[test]
1491 fn malformed_match_arm_tuple_enum_missing_pattern() { 1522 fn malformed_match_arm_tuple_enum_missing_pattern() {
1492 let content = r" 1523 // We are testing to be sure we don't panic here when the match
1524 // arm `Either::B` is missing its pattern.
1525 check_no_diagnostic(
1526 r"
1493 enum Either { 1527 enum Either {
1494 A, 1528 A,
1495 B(u32), 1529 B(u32),
@@ -1500,32 +1534,30 @@ mod tests {
1500 Either::B() => (), 1534 Either::B() => (),
1501 } 1535 }
1502 } 1536 }
1503 "; 1537 ",
1504 1538 );
1505 // We are testing to be sure we don't panic here when the match
1506 // arm `Either::B` is missing its pattern.
1507 check_no_diagnostic(content);
1508 } 1539 }
1509 1540
1510 #[test] 1541 #[test]
1511 fn enum_not_in_scope() { 1542 fn enum_not_in_scope() {
1512 let content = r" 1543 // The enum is not in scope so we don't perform exhaustiveness
1544 // checking, but we want to be sure we don't panic here (and
1545 // we don't create a diagnostic).
1546 check_no_diagnostic(
1547 r"
1513 fn test_fn() { 1548 fn test_fn() {
1514 match Foo::Bar { 1549 match Foo::Bar {
1515 Foo::Baz => (), 1550 Foo::Baz => (),
1516 } 1551 }
1517 } 1552 }
1518 "; 1553 ",
1519 1554 );
1520 // The enum is not in scope so we don't perform exhaustiveness
1521 // checking, but we want to be sure we don't panic here (and
1522 // we don't create a diagnostic).
1523 check_no_diagnostic(content);
1524 } 1555 }
1525 1556
1526 #[test] 1557 #[test]
1527 fn expr_diverges() { 1558 fn expr_diverges() {
1528 let content = r" 1559 check_no_diagnostic(
1560 r"
1529 enum Either { 1561 enum Either {
1530 A, 1562 A,
1531 B, 1563 B,
@@ -1536,14 +1568,14 @@ mod tests {
1536 Either::B => (), 1568 Either::B => (),
1537 } 1569 }
1538 } 1570 }
1539 "; 1571 ",
1540 1572 );
1541 check_no_diagnostic(content);
1542 } 1573 }
1543 1574
1544 #[test] 1575 #[test]
1545 fn expr_loop_with_break() { 1576 fn expr_loop_with_break() {
1546 let content = r" 1577 check_no_diagnostic(
1578 r"
1547 enum Either { 1579 enum Either {
1548 A, 1580 A,
1549 B, 1581 B,
@@ -1554,14 +1586,14 @@ mod tests {
1554 Either::B => (), 1586 Either::B => (),
1555 } 1587 }
1556 } 1588 }
1557 "; 1589 ",
1558 1590 );
1559 check_no_diagnostic(content);
1560 } 1591 }
1561 1592
1562 #[test] 1593 #[test]
1563 fn expr_partially_diverges() { 1594 fn expr_partially_diverges() {
1564 let content = r" 1595 check_no_diagnostic(
1596 r"
1565 enum Either<T> { 1597 enum Either<T> {
1566 A(T), 1598 A(T),
1567 B, 1599 B,
@@ -1575,14 +1607,14 @@ mod tests {
1575 Either::B => 0, 1607 Either::B => 0,
1576 } 1608 }
1577 } 1609 }
1578 "; 1610 ",
1579 1611 );
1580 check_no_diagnostic(content);
1581 } 1612 }
1582 1613
1583 #[test] 1614 #[test]
1584 fn enum_record_no_arms() { 1615 fn enum_record_no_arms() {
1585 let content = r" 1616 check_diagnostic(
1617 r"
1586 enum Either { 1618 enum Either {
1587 A { foo: bool }, 1619 A { foo: bool },
1588 B, 1620 B,
@@ -1592,14 +1624,14 @@ mod tests {
1592 match a { 1624 match a {
1593 } 1625 }
1594 } 1626 }
1595 "; 1627 ",
1596 1628 );
1597 check_diagnostic(content);
1598 } 1629 }
1599 1630
1600 #[test] 1631 #[test]
1601 fn enum_record_missing_arms() { 1632 fn enum_record_missing_arms() {
1602 let content = r" 1633 check_diagnostic(
1634 r"
1603 enum Either { 1635 enum Either {
1604 A { foo: bool }, 1636 A { foo: bool },
1605 B, 1637 B,
@@ -1610,14 +1642,14 @@ mod tests {
1610 Either::A { foo: true } => (), 1642 Either::A { foo: true } => (),
1611 } 1643 }
1612 } 1644 }
1613 "; 1645 ",
1614 1646 );
1615 check_diagnostic(content);
1616 } 1647 }
1617 1648
1618 #[test] 1649 #[test]
1619 fn enum_record_no_diagnostic() { 1650 fn enum_record_no_diagnostic() {
1620 let content = r" 1651 check_no_diagnostic(
1652 r"
1621 enum Either { 1653 enum Either {
1622 A { foo: bool }, 1654 A { foo: bool },
1623 B, 1655 B,
@@ -1630,14 +1662,17 @@ mod tests {
1630 Either::B => (), 1662 Either::B => (),
1631 } 1663 }
1632 } 1664 }
1633 "; 1665 ",
1634 1666 );
1635 check_no_diagnostic(content);
1636 } 1667 }
1637 1668
1638 #[test] 1669 #[test]
1639 fn enum_record_missing_field_no_diagnostic() { 1670 fn enum_record_missing_field_no_diagnostic() {
1640 let content = r" 1671 // When `Either::A` is missing a struct member, we don't want
1672 // to fire the missing match arm diagnostic. This should fire
1673 // some other diagnostic.
1674 check_no_diagnostic(
1675 r"
1641 enum Either { 1676 enum Either {
1642 A { foo: bool }, 1677 A { foo: bool },
1643 B, 1678 B,
@@ -1649,17 +1684,16 @@ mod tests {
1649 Either::B => (), 1684 Either::B => (),
1650 } 1685 }
1651 } 1686 }
1652 "; 1687 ",
1653 1688 );
1654 // When `Either::A` is missing a struct member, we don't want
1655 // to fire the missing match arm diagnostic. This should fire
1656 // some other diagnostic.
1657 check_no_diagnostic(content);
1658 } 1689 }
1659 1690
1660 #[test] 1691 #[test]
1661 fn enum_record_missing_field_missing_match_arm() { 1692 fn enum_record_missing_field_missing_match_arm() {
1662 let content = r" 1693 // Even though `Either::A` is missing fields, we still want to fire
1694 // the missing arm diagnostic here, since we know `Either::B` is missing.
1695 check_diagnostic(
1696 r"
1663 enum Either { 1697 enum Either {
1664 A { foo: bool }, 1698 A { foo: bool },
1665 B, 1699 B,
@@ -1670,16 +1704,14 @@ mod tests {
1670 Either::A { } => (), 1704 Either::A { } => (),
1671 } 1705 }
1672 } 1706 }
1673 "; 1707 ",
1674 1708 );
1675 // Even though `Either::A` is missing fields, we still want to fire
1676 // the missing arm diagnostic here, since we know `Either::B` is missing.
1677 check_diagnostic(content);
1678 } 1709 }
1679 1710
1680 #[test] 1711 #[test]
1681 fn enum_record_no_diagnostic_wild() { 1712 fn enum_record_no_diagnostic_wild() {
1682 let content = r" 1713 check_no_diagnostic(
1714 r"
1683 enum Either { 1715 enum Either {
1684 A { foo: bool }, 1716 A { foo: bool },
1685 B, 1717 B,
@@ -1691,14 +1723,14 @@ mod tests {
1691 Either::B => (), 1723 Either::B => (),
1692 } 1724 }
1693 } 1725 }
1694 "; 1726 ",
1695 1727 );
1696 check_no_diagnostic(content);
1697 } 1728 }
1698 1729
1699 #[test] 1730 #[test]
1700 fn enum_record_fields_out_of_order_missing_arm() { 1731 fn enum_record_fields_out_of_order_missing_arm() {
1701 let content = r" 1732 check_diagnostic(
1733 r"
1702 enum Either { 1734 enum Either {
1703 A { foo: bool, bar: () }, 1735 A { foo: bool, bar: () },
1704 B, 1736 B,
@@ -1710,14 +1742,14 @@ mod tests {
1710 Either::A { foo: true, bar: () } => (), 1742 Either::A { foo: true, bar: () } => (),
1711 } 1743 }
1712 } 1744 }
1713 "; 1745 ",
1714 1746 );
1715 check_diagnostic(content);
1716 } 1747 }
1717 1748
1718 #[test] 1749 #[test]
1719 fn enum_record_fields_out_of_order_no_diagnostic() { 1750 fn enum_record_fields_out_of_order_no_diagnostic() {
1720 let content = r" 1751 check_no_diagnostic(
1752 r"
1721 enum Either { 1753 enum Either {
1722 A { foo: bool, bar: () }, 1754 A { foo: bool, bar: () },
1723 B, 1755 B,
@@ -1730,89 +1762,89 @@ mod tests {
1730 Either::B => (), 1762 Either::B => (),
1731 } 1763 }
1732 } 1764 }
1733 "; 1765 ",
1734 1766 );
1735 check_no_diagnostic(content);
1736 } 1767 }
1737 1768
1738 #[test] 1769 #[test]
1739 fn enum_record_ellipsis_missing_arm() { 1770 fn enum_record_ellipsis_missing_arm() {
1740 let content = r" 1771 check_diagnostic(
1741 enum Either { 1772 r"
1742 A { foo: bool, bar: bool }, 1773 enum Either {
1743 B, 1774 A { foo: bool, bar: bool },
1744 } 1775 B,
1745 fn test_fn() { 1776 }
1746 match Either::B { 1777 fn test_fn() {
1747 Either::A { foo: true, .. } => (), 1778 match Either::B {
1748 Either::B => (), 1779 Either::A { foo: true, .. } => (),
1749 } 1780 Either::B => (),
1750 } 1781 }
1751 "; 1782 }
1752 1783 ",
1753 check_diagnostic(content); 1784 );
1754 } 1785 }
1755 1786
1756 #[test] 1787 #[test]
1757 fn enum_record_ellipsis_no_diagnostic() { 1788 fn enum_record_ellipsis_no_diagnostic() {
1758 let content = r" 1789 check_no_diagnostic(
1759 enum Either { 1790 r"
1760 A { foo: bool, bar: bool }, 1791 enum Either {
1761 B, 1792 A { foo: bool, bar: bool },
1762 } 1793 B,
1763 fn test_fn() { 1794 }
1764 let a = Either::A { foo: true }; 1795 fn test_fn() {
1765 match a { 1796 let a = Either::A { foo: true };
1766 Either::A { foo: true, .. } => (), 1797 match a {
1767 Either::A { foo: false, .. } => (), 1798 Either::A { foo: true, .. } => (),
1768 Either::B => (), 1799 Either::A { foo: false, .. } => (),
1769 } 1800 Either::B => (),
1770 } 1801 }
1771 "; 1802 }
1772 1803 ",
1773 check_no_diagnostic(content); 1804 );
1774 } 1805 }
1775 1806
1776 #[test] 1807 #[test]
1777 fn enum_record_ellipsis_all_fields_missing_arm() { 1808 fn enum_record_ellipsis_all_fields_missing_arm() {
1778 let content = r" 1809 check_diagnostic(
1779 enum Either { 1810 r"
1780 A { foo: bool, bar: bool }, 1811 enum Either {
1781 B, 1812 A { foo: bool, bar: bool },
1782 } 1813 B,
1783 fn test_fn() { 1814 }
1784 let a = Either::B; 1815 fn test_fn() {
1785 match a { 1816 let a = Either::B;
1786 Either::A { .. } => (), 1817 match a {
1787 } 1818 Either::A { .. } => (),
1788 } 1819 }
1789 "; 1820 }
1790 1821 ",
1791 check_diagnostic(content); 1822 );
1792 } 1823 }
1793 1824
1794 #[test] 1825 #[test]
1795 fn enum_record_ellipsis_all_fields_no_diagnostic() { 1826 fn enum_record_ellipsis_all_fields_no_diagnostic() {
1796 let content = r" 1827 check_no_diagnostic(
1797 enum Either { 1828 r"
1798 A { foo: bool, bar: bool }, 1829 enum Either {
1799 B, 1830 A { foo: bool, bar: bool },
1800 } 1831 B,
1801 fn test_fn() { 1832 }
1802 let a = Either::B; 1833 fn test_fn() {
1803 match a { 1834 let a = Either::B;
1804 Either::A { .. } => (), 1835 match a {
1805 Either::B => (), 1836 Either::A { .. } => (),
1806 } 1837 Either::B => (),
1807 } 1838 }
1808 "; 1839 }
1809 1840 ",
1810 check_no_diagnostic(content); 1841 );
1811 } 1842 }
1812 1843
1813 #[test] 1844 #[test]
1814 fn enum_tuple_partial_ellipsis_no_diagnostic() { 1845 fn enum_tuple_partial_ellipsis_no_diagnostic() {
1815 let content = r" 1846 check_no_diagnostic(
1847 r"
1816 enum Either { 1848 enum Either {
1817 A(bool, bool, bool, bool), 1849 A(bool, bool, bool, bool),
1818 B, 1850 B,
@@ -1826,14 +1858,14 @@ mod tests {
1826 Either::B => {}, 1858 Either::B => {},
1827 } 1859 }
1828 } 1860 }
1829 "; 1861 ",
1830 1862 );
1831 check_no_diagnostic(content);
1832 } 1863 }
1833 1864
1834 #[test] 1865 #[test]
1835 fn enum_tuple_partial_ellipsis_2_no_diagnostic() { 1866 fn enum_tuple_partial_ellipsis_2_no_diagnostic() {
1836 let content = r" 1867 check_no_diagnostic(
1868 r"
1837 enum Either { 1869 enum Either {
1838 A(bool, bool, bool, bool), 1870 A(bool, bool, bool, bool),
1839 B, 1871 B,
@@ -1847,14 +1879,14 @@ mod tests {
1847 Either::B => {}, 1879 Either::B => {},
1848 } 1880 }
1849 } 1881 }
1850 "; 1882 ",
1851 1883 );
1852 check_no_diagnostic(content);
1853 } 1884 }
1854 1885
1855 #[test] 1886 #[test]
1856 fn enum_tuple_partial_ellipsis_missing_arm() { 1887 fn enum_tuple_partial_ellipsis_missing_arm() {
1857 let content = r" 1888 check_diagnostic(
1889 r"
1858 enum Either { 1890 enum Either {
1859 A(bool, bool, bool, bool), 1891 A(bool, bool, bool, bool),
1860 B, 1892 B,
@@ -1867,14 +1899,14 @@ mod tests {
1867 Either::B => {}, 1899 Either::B => {},
1868 } 1900 }
1869 } 1901 }
1870 "; 1902 ",
1871 1903 );
1872 check_diagnostic(content);
1873 } 1904 }
1874 1905
1875 #[test] 1906 #[test]
1876 fn enum_tuple_partial_ellipsis_2_missing_arm() { 1907 fn enum_tuple_partial_ellipsis_2_missing_arm() {
1877 let content = r" 1908 check_diagnostic(
1909 r"
1878 enum Either { 1910 enum Either {
1879 A(bool, bool, bool, bool), 1911 A(bool, bool, bool, bool),
1880 B, 1912 B,
@@ -1887,14 +1919,14 @@ mod tests {
1887 Either::B => {}, 1919 Either::B => {},
1888 } 1920 }
1889 } 1921 }
1890 "; 1922 ",
1891 1923 );
1892 check_diagnostic(content);
1893 } 1924 }
1894 1925
1895 #[test] 1926 #[test]
1896 fn enum_tuple_ellipsis_no_diagnostic() { 1927 fn enum_tuple_ellipsis_no_diagnostic() {
1897 let content = r" 1928 check_no_diagnostic(
1929 r"
1898 enum Either { 1930 enum Either {
1899 A(bool, bool, bool, bool), 1931 A(bool, bool, bool, bool),
1900 B, 1932 B,
@@ -1905,51 +1937,51 @@ mod tests {
1905 Either::B => {}, 1937 Either::B => {},
1906 } 1938 }
1907 } 1939 }
1908 "; 1940 ",
1909 1941 );
1910 check_no_diagnostic(content);
1911 } 1942 }
1912 1943
1913 #[test] 1944 #[test]
1914 fn enum_never() { 1945 fn enum_never() {
1915 let content = r" 1946 check_no_diagnostic(
1947 r"
1916 enum Never {} 1948 enum Never {}
1917 1949
1918 fn test_fn(never: Never) { 1950 fn test_fn(never: Never) {
1919 match never {} 1951 match never {}
1920 } 1952 }
1921 "; 1953 ",
1922 1954 );
1923 check_no_diagnostic(content);
1924 } 1955 }
1925 1956
1926 #[test] 1957 #[test]
1927 fn type_never() { 1958 fn type_never() {
1928 let content = r" 1959 check_no_diagnostic(
1960 r"
1929 fn test_fn(never: !) { 1961 fn test_fn(never: !) {
1930 match never {} 1962 match never {}
1931 } 1963 }
1932 "; 1964 ",
1933 1965 );
1934 check_no_diagnostic(content);
1935 } 1966 }
1936 1967
1937 #[test] 1968 #[test]
1938 fn enum_never_ref() { 1969 fn enum_never_ref() {
1939 let content = r" 1970 check_no_diagnostic(
1971 r"
1940 enum Never {} 1972 enum Never {}
1941 1973
1942 fn test_fn(never: &Never) { 1974 fn test_fn(never: &Never) {
1943 match never {} 1975 match never {}
1944 } 1976 }
1945 "; 1977 ",
1946 1978 );
1947 check_no_diagnostic(content);
1948 } 1979 }
1949 1980
1950 #[test] 1981 #[test]
1951 fn expr_diverges_missing_arm() { 1982 fn expr_diverges_missing_arm() {
1952 let content = r" 1983 check_no_diagnostic(
1984 r"
1953 enum Either { 1985 enum Either {
1954 A, 1986 A,
1955 B, 1987 B,
@@ -1959,9 +1991,49 @@ mod tests {
1959 Either::A => (), 1991 Either::A => (),
1960 } 1992 }
1961 } 1993 }
1962 "; 1994 ",
1995 );
1996 }
1997
1998 #[test]
1999 fn or_pattern_panic() {
2000 check_no_diagnostic(
2001 r"
2002 pub enum Category {
2003 Infinity,
2004 Zero,
2005 }
2006
2007 fn panic(a: Category, b: Category) {
2008 match (a, b) {
2009 (Category::Zero | Category::Infinity, _) => {}
2010 (_, Category::Zero | Category::Infinity) => {}
2011 }
2012 }
2013 ",
2014 );
2015 }
1963 2016
1964 check_no_diagnostic(content); 2017 #[test]
2018 fn or_pattern_panic_2() {
2019 // FIXME: This is a false positive, but the code used to cause a panic in the match checker,
2020 // so this acts as a regression test for that.
2021 check_diagnostic(
2022 r"
2023 pub enum Category {
2024 Infinity,
2025 Zero,
2026 }
2027
2028 fn panic(a: Category, b: Category) {
2029 match (a, b) {
2030 (Category::Infinity, Category::Infinity) | (Category::Zero, Category::Zero) => {}
2031
2032 (Category::Infinity | Category::Zero, _) => {}
2033 }
2034 }
2035 ",
2036 );
1965 } 2037 }
1966} 2038}
1967 2039
@@ -1981,23 +2053,26 @@ mod false_negatives {
1981 2053
1982 #[test] 2054 #[test]
1983 fn integers() { 2055 fn integers() {
1984 let content = r" 2056 // This is a false negative.
2057 // We don't currently check integer exhaustiveness.
2058 check_no_diagnostic(
2059 r"
1985 fn test_fn() { 2060 fn test_fn() {
1986 match 5 { 2061 match 5 {
1987 10 => (), 2062 10 => (),
1988 11..20 => (), 2063 11..20 => (),
1989 } 2064 }
1990 } 2065 }
1991 "; 2066 ",
1992 2067 );
1993 // This is a false negative.
1994 // We don't currently check integer exhaustiveness.
1995 check_no_diagnostic(content);
1996 } 2068 }
1997 2069
1998 #[test] 2070 #[test]
1999 fn internal_or() { 2071 fn internal_or() {
2000 let content = r" 2072 // This is a false negative.
2073 // We do not currently handle patterns with internal `or`s.
2074 check_no_diagnostic(
2075 r"
2001 fn test_fn() { 2076 fn test_fn() {
2002 enum Either { 2077 enum Either {
2003 A(bool), 2078 A(bool),
@@ -2007,16 +2082,18 @@ mod false_negatives {
2007 Either::A(true | false) => (), 2082 Either::A(true | false) => (),
2008 } 2083 }
2009 } 2084 }
2010 "; 2085 ",
2011 2086 );
2012 // This is a false negative.
2013 // We do not currently handle patterns with internal `or`s.
2014 check_no_diagnostic(content);
2015 } 2087 }
2016 2088
2017 #[test] 2089 #[test]
2018 fn expr_loop_missing_arm() { 2090 fn expr_loop_missing_arm() {
2019 let content = r" 2091 // This is a false negative.
2092 // We currently infer the type of `loop { break Foo::A }` to `!`, which
2093 // causes us to skip the diagnostic since `Either::A` doesn't type check
2094 // with `!`.
2095 check_diagnostic(
2096 r"
2020 enum Either { 2097 enum Either {
2021 A, 2098 A,
2022 B, 2099 B,
@@ -2026,48 +2103,46 @@ mod false_negatives {
2026 Either::A => (), 2103 Either::A => (),
2027 } 2104 }
2028 } 2105 }
2029 "; 2106 ",
2030 2107 );
2031 // This is a false negative.
2032 // We currently infer the type of `loop { break Foo::A }` to `!`, which
2033 // causes us to skip the diagnostic since `Either::A` doesn't type check
2034 // with `!`.
2035 check_diagnostic(content);
2036 } 2108 }
2037 2109
2038 #[test] 2110 #[test]
2039 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { 2111 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
2040 let content = r" 2112 // This is a false negative.
2113 // We don't currently handle tuple patterns with ellipsis.
2114 check_no_diagnostic(
2115 r"
2041 fn test_fn() { 2116 fn test_fn() {
2042 match (false, true, false) { 2117 match (false, true, false) {
2043 (false, ..) => {}, 2118 (false, ..) => {},
2044 } 2119 }
2045 } 2120 }
2046 "; 2121 ",
2047 2122 );
2048 // This is a false negative.
2049 // We don't currently handle tuple patterns with ellipsis.
2050 check_no_diagnostic(content);
2051 } 2123 }
2052 2124
2053 #[test] 2125 #[test]
2054 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { 2126 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
2055 let content = r" 2127 // This is a false negative.
2128 // We don't currently handle tuple patterns with ellipsis.
2129 check_no_diagnostic(
2130 r"
2056 fn test_fn() { 2131 fn test_fn() {
2057 match (false, true, false) { 2132 match (false, true, false) {
2058 (.., false) => {}, 2133 (.., false) => {},
2059 } 2134 }
2060 } 2135 }
2061 "; 2136 ",
2062 2137 );
2063 // This is a false negative.
2064 // We don't currently handle tuple patterns with ellipsis.
2065 check_no_diagnostic(content);
2066 } 2138 }
2067 2139
2068 #[test] 2140 #[test]
2069 fn struct_missing_arm() { 2141 fn struct_missing_arm() {
2070 let content = r" 2142 // This is a false negative.
2143 // We don't currently handle structs.
2144 check_no_diagnostic(
2145 r"
2071 struct Foo { 2146 struct Foo {
2072 a: bool, 2147 a: bool,
2073 } 2148 }
@@ -2076,10 +2151,7 @@ mod false_negatives {
2076 Foo { a: true } => {}, 2151 Foo { a: true } => {},
2077 } 2152 }
2078 } 2153 }
2079 "; 2154 ",
2080 2155 );
2081 // This is a false negative.
2082 // We don't currently handle structs.
2083 check_no_diagnostic(content);
2084 } 2156 }
2085} 2157}
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 2b9372b4b..f22232324 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -73,6 +73,7 @@ pub use lower::{
73pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; 73pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
74 74
75pub use chalk_ir::{BoundVar, DebruijnIndex}; 75pub use chalk_ir::{BoundVar, DebruijnIndex};
76use itertools::Itertools;
76 77
77/// A type constructor or type name: this might be something like the primitive 78/// A type constructor or type name: this might be something like the primitive
78/// type `bool`, a struct like `Vec`, or things like function pointers or 79/// type `bool`, a struct like `Vec`, or things like function pointers or
@@ -815,6 +816,11 @@ impl Ty {
815 } 816 }
816 } 817 }
817 818
819 /// If this is a `dyn Trait`, returns that trait.
820 pub fn dyn_trait(&self) -> Option<TraitId> {
821 self.dyn_trait_ref().map(|it| it.trait_)
822 }
823
818 fn builtin_deref(&self) -> Option<Ty> { 824 fn builtin_deref(&self) -> Option<Ty> {
819 match self { 825 match self {
820 Ty::Apply(a_ty) => match a_ty.ctor { 826 Ty::Apply(a_ty) => match a_ty.ctor {
@@ -867,13 +873,56 @@ impl Ty {
867 } 873 }
868 } 874 }
869 875
870 /// If this is a `dyn Trait`, returns that trait. 876 pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<GenericPredicate>> {
871 pub fn dyn_trait(&self) -> Option<TraitId> {
872 match self { 877 match self {
873 Ty::Dyn(predicates) => predicates.iter().find_map(|pred| match pred { 878 Ty::Opaque(opaque_ty) => {
874 GenericPredicate::Implemented(tr) => Some(tr.trait_), 879 let predicates = match opaque_ty.opaque_ty_id {
875 _ => None, 880 OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
876 }), 881 db.return_type_impl_traits(func).map(|it| {
882 let data = (*it)
883 .as_ref()
884 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
885 data.clone().subst(&opaque_ty.parameters)
886 })
887 }
888 };
889
890 predicates.map(|it| it.value)
891 }
892 Ty::Placeholder(id) => {
893 let generic_params = db.generic_params(id.parent);
894 let param_data = &generic_params.types[id.local_id];
895 match param_data.provenance {
896 hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
897 let predicates = db
898 .generic_predicates_for_param(*id)
899 .into_iter()
900 .map(|pred| pred.value.clone())
901 .collect_vec();
902
903 Some(predicates)
904 }
905 _ => None,
906 }
907 }
908 _ => None,
909 }
910 }
911
912 pub fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> {
913 match self {
914 Ty::Apply(ApplicationTy { ctor: TypeCtor::AssociatedType(type_alias_id), .. }) => {
915 match type_alias_id.lookup(db.upcast()).container {
916 AssocContainerId::TraitId(trait_id) => Some(trait_id),
917 _ => None,
918 }
919 }
920 Ty::Projection(projection_ty) => {
921 match projection_ty.associated_ty.lookup(db.upcast()).container {
922 AssocContainerId::TraitId(trait_id) => Some(trait_id),
923 _ => None,
924 }
925 }
877 _ => None, 926 _ => None,
878 } 927 }
879 } 928 }
@@ -1057,5 +1106,5 @@ pub struct ReturnTypeImplTraits {
1057 1106
1058#[derive(Clone, PartialEq, Eq, Debug, Hash)] 1107#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1059pub(crate) struct ReturnTypeImplTrait { 1108pub(crate) struct ReturnTypeImplTrait {
1060 pub(crate) bounds: Binders<Vec<GenericPredicate>>, 1109 pub bounds: Binders<Vec<GenericPredicate>>,
1061} 1110}