diff options
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/_match.rs | 1112 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 63 |
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 | //! ``` | ||
190 | use std::sync::Arc; | 219 | use std::sync::Arc; |
191 | 220 | ||
192 | use smallvec::{smallvec, SmallVec}; | 221 | use 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::{ | |||
73 | pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; | 73 | pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; |
74 | 74 | ||
75 | pub use chalk_ir::{BoundVar, DebruijnIndex}; | 75 | pub use chalk_ir::{BoundVar, DebruijnIndex}; |
76 | use 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)] |
1059 | pub(crate) struct ReturnTypeImplTrait { | 1108 | pub(crate) struct ReturnTypeImplTrait { |
1060 | pub(crate) bounds: Binders<Vec<GenericPredicate>>, | 1109 | pub bounds: Binders<Vec<GenericPredicate>>, |
1061 | } | 1110 | } |