diff options
author | Aleksey Kladov <[email protected]> | 2021-06-13 19:44:31 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-06-13 19:44:31 +0100 |
commit | b292e1b9da39813e2739cb450c263e7502c97c8d (patch) | |
tree | 92a09f547c7d7ca41f90ebdc68f0f81ac1805560 /crates/ide/src/diagnostics | |
parent | 3478897f86cc1b3e3f83e9d4e7cedff41721fb04 (diff) |
internal: refactor missing match arms diagnostics
Diffstat (limited to 'crates/ide/src/diagnostics')
-rw-r--r-- | crates/ide/src/diagnostics/missing_match_arms.rs | 924 |
1 files changed, 924 insertions, 0 deletions
diff --git a/crates/ide/src/diagnostics/missing_match_arms.rs b/crates/ide/src/diagnostics/missing_match_arms.rs new file mode 100644 index 000000000..6b977fa59 --- /dev/null +++ b/crates/ide/src/diagnostics/missing_match_arms.rs | |||
@@ -0,0 +1,924 @@ | |||
1 | use hir::InFile; | ||
2 | |||
3 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | ||
4 | |||
5 | // Diagnostic: missing-match-arm | ||
6 | // | ||
7 | // This diagnostic is triggered if `match` block is missing one or more match arms. | ||
8 | pub(super) fn missing_match_arms( | ||
9 | ctx: &DiagnosticsContext<'_>, | ||
10 | d: &hir::MissingMatchArms, | ||
11 | ) -> Diagnostic { | ||
12 | Diagnostic::new( | ||
13 | "missing-match-arm", | ||
14 | "missing match arm", | ||
15 | ctx.sema.diagnostics_display_range(InFile::new(d.file, d.match_expr.clone().into())).range, | ||
16 | ) | ||
17 | } | ||
18 | |||
19 | #[cfg(test)] | ||
20 | pub(super) mod tests { | ||
21 | use crate::diagnostics::tests::check_diagnostics; | ||
22 | |||
23 | #[test] | ||
24 | fn empty_tuple() { | ||
25 | check_diagnostics( | ||
26 | r#" | ||
27 | fn main() { | ||
28 | match () { } | ||
29 | //^^ missing match arm | ||
30 | match (()) { } | ||
31 | //^^^^ missing match arm | ||
32 | |||
33 | match () { _ => (), } | ||
34 | match () { () => (), } | ||
35 | match (()) { (()) => (), } | ||
36 | } | ||
37 | "#, | ||
38 | ); | ||
39 | } | ||
40 | |||
41 | #[test] | ||
42 | fn tuple_of_two_empty_tuple() { | ||
43 | check_diagnostics( | ||
44 | r#" | ||
45 | fn main() { | ||
46 | match ((), ()) { } | ||
47 | //^^^^^^^^ missing match arm | ||
48 | |||
49 | match ((), ()) { ((), ()) => (), } | ||
50 | } | ||
51 | "#, | ||
52 | ); | ||
53 | } | ||
54 | |||
55 | #[test] | ||
56 | fn boolean() { | ||
57 | check_diagnostics( | ||
58 | r#" | ||
59 | fn test_main() { | ||
60 | match false { } | ||
61 | //^^^^^ missing match arm | ||
62 | match false { true => (), } | ||
63 | //^^^^^ missing match arm | ||
64 | match (false, true) {} | ||
65 | //^^^^^^^^^^^^^ missing match arm | ||
66 | match (false, true) { (true, true) => (), } | ||
67 | //^^^^^^^^^^^^^ missing match arm | ||
68 | match (false, true) { | ||
69 | //^^^^^^^^^^^^^ missing match arm | ||
70 | (false, true) => (), | ||
71 | (false, false) => (), | ||
72 | (true, false) => (), | ||
73 | } | ||
74 | match (false, true) { (true, _x) => (), } | ||
75 | //^^^^^^^^^^^^^ missing match arm | ||
76 | |||
77 | match false { true => (), false => (), } | ||
78 | match (false, true) { | ||
79 | (false, _) => (), | ||
80 | (true, false) => (), | ||
81 | (_, true) => (), | ||
82 | } | ||
83 | match (false, true) { | ||
84 | (true, true) => (), | ||
85 | (true, false) => (), | ||
86 | (false, true) => (), | ||
87 | (false, false) => (), | ||
88 | } | ||
89 | match (false, true) { | ||
90 | (true, _x) => (), | ||
91 | (false, true) => (), | ||
92 | (false, false) => (), | ||
93 | } | ||
94 | match (false, true, false) { | ||
95 | (false, ..) => (), | ||
96 | (true, ..) => (), | ||
97 | } | ||
98 | match (false, true, false) { | ||
99 | (.., false) => (), | ||
100 | (.., true) => (), | ||
101 | } | ||
102 | match (false, true, false) { (..) => (), } | ||
103 | } | ||
104 | "#, | ||
105 | ); | ||
106 | } | ||
107 | |||
108 | #[test] | ||
109 | fn tuple_of_tuple_and_bools() { | ||
110 | check_diagnostics( | ||
111 | r#" | ||
112 | fn main() { | ||
113 | match (false, ((), false)) {} | ||
114 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | ||
115 | match (false, ((), false)) { (true, ((), true)) => (), } | ||
116 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | ||
117 | match (false, ((), false)) { (true, _) => (), } | ||
118 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | ||
119 | |||
120 | match (false, ((), false)) { | ||
121 | (true, ((), true)) => (), | ||
122 | (true, ((), false)) => (), | ||
123 | (false, ((), true)) => (), | ||
124 | (false, ((), false)) => (), | ||
125 | } | ||
126 | match (false, ((), false)) { | ||
127 | (true, ((), true)) => (), | ||
128 | (true, ((), false)) => (), | ||
129 | (false, _) => (), | ||
130 | } | ||
131 | } | ||
132 | "#, | ||
133 | ); | ||
134 | } | ||
135 | |||
136 | #[test] | ||
137 | fn enums() { | ||
138 | check_diagnostics( | ||
139 | r#" | ||
140 | enum Either { A, B, } | ||
141 | |||
142 | fn main() { | ||
143 | match Either::A { } | ||
144 | //^^^^^^^^^ missing match arm | ||
145 | match Either::B { Either::A => (), } | ||
146 | //^^^^^^^^^ missing match arm | ||
147 | |||
148 | match &Either::B { | ||
149 | //^^^^^^^^^^ missing match arm | ||
150 | Either::A => (), | ||
151 | } | ||
152 | |||
153 | match Either::B { | ||
154 | Either::A => (), Either::B => (), | ||
155 | } | ||
156 | match &Either::B { | ||
157 | Either::A => (), Either::B => (), | ||
158 | } | ||
159 | } | ||
160 | "#, | ||
161 | ); | ||
162 | } | ||
163 | |||
164 | #[test] | ||
165 | fn enum_containing_bool() { | ||
166 | check_diagnostics( | ||
167 | r#" | ||
168 | enum Either { A(bool), B } | ||
169 | |||
170 | fn main() { | ||
171 | match Either::B { } | ||
172 | //^^^^^^^^^ missing match arm | ||
173 | match Either::B { | ||
174 | //^^^^^^^^^ missing match arm | ||
175 | Either::A(true) => (), Either::B => () | ||
176 | } | ||
177 | |||
178 | match Either::B { | ||
179 | Either::A(true) => (), | ||
180 | Either::A(false) => (), | ||
181 | Either::B => (), | ||
182 | } | ||
183 | match Either::B { | ||
184 | Either::B => (), | ||
185 | _ => (), | ||
186 | } | ||
187 | match Either::B { | ||
188 | Either::A(_) => (), | ||
189 | Either::B => (), | ||
190 | } | ||
191 | |||
192 | } | ||
193 | "#, | ||
194 | ); | ||
195 | } | ||
196 | |||
197 | #[test] | ||
198 | fn enum_different_sizes() { | ||
199 | check_diagnostics( | ||
200 | r#" | ||
201 | enum Either { A(bool), B(bool, bool) } | ||
202 | |||
203 | fn main() { | ||
204 | match Either::A(false) { | ||
205 | //^^^^^^^^^^^^^^^^ missing match arm | ||
206 | Either::A(_) => (), | ||
207 | Either::B(false, _) => (), | ||
208 | } | ||
209 | |||
210 | match Either::A(false) { | ||
211 | Either::A(_) => (), | ||
212 | Either::B(true, _) => (), | ||
213 | Either::B(false, _) => (), | ||
214 | } | ||
215 | match Either::A(false) { | ||
216 | Either::A(true) | Either::A(false) => (), | ||
217 | Either::B(true, _) => (), | ||
218 | Either::B(false, _) => (), | ||
219 | } | ||
220 | } | ||
221 | "#, | ||
222 | ); | ||
223 | } | ||
224 | |||
225 | #[test] | ||
226 | fn tuple_of_enum_no_diagnostic() { | ||
227 | check_diagnostics( | ||
228 | r#" | ||
229 | enum Either { A(bool), B(bool, bool) } | ||
230 | enum Either2 { C, D } | ||
231 | |||
232 | fn main() { | ||
233 | match (Either::A(false), Either2::C) { | ||
234 | (Either::A(true), _) | (Either::A(false), _) => (), | ||
235 | (Either::B(true, _), Either2::C) => (), | ||
236 | (Either::B(false, _), Either2::C) => (), | ||
237 | (Either::B(_, _), Either2::D) => (), | ||
238 | } | ||
239 | } | ||
240 | "#, | ||
241 | ); | ||
242 | } | ||
243 | |||
244 | #[test] | ||
245 | fn or_pattern_no_diagnostic() { | ||
246 | check_diagnostics( | ||
247 | r#" | ||
248 | enum Either {A, B} | ||
249 | |||
250 | fn main() { | ||
251 | match (Either::A, Either::B) { | ||
252 | (Either::A | Either::B, _) => (), | ||
253 | } | ||
254 | }"#, | ||
255 | ) | ||
256 | } | ||
257 | |||
258 | #[test] | ||
259 | fn mismatched_types() { | ||
260 | // Match statements with arms that don't match the | ||
261 | // expression pattern do not fire this diagnostic. | ||
262 | check_diagnostics( | ||
263 | r#" | ||
264 | enum Either { A, B } | ||
265 | enum Either2 { C, D } | ||
266 | |||
267 | fn main() { | ||
268 | match Either::A { | ||
269 | Either2::C => (), | ||
270 | // ^^^^^^^^^^ Internal: match check bailed out | ||
271 | Either2::D => (), | ||
272 | } | ||
273 | match (true, false) { | ||
274 | (true, false, true) => (), | ||
275 | // ^^^^^^^^^^^^^^^^^^^ Internal: match check bailed out | ||
276 | (true) => (), | ||
277 | } | ||
278 | match (true, false) { (true,) => {} } | ||
279 | // ^^^^^^^ Internal: match check bailed out | ||
280 | match (0) { () => () } | ||
281 | // ^^ Internal: match check bailed out | ||
282 | match Unresolved::Bar { Unresolved::Baz => () } | ||
283 | } | ||
284 | "#, | ||
285 | ); | ||
286 | } | ||
287 | |||
288 | #[test] | ||
289 | fn mismatched_types_in_or_patterns() { | ||
290 | check_diagnostics( | ||
291 | r#" | ||
292 | fn main() { | ||
293 | match false { true | () => {} } | ||
294 | // ^^^^^^^^^ Internal: match check bailed out | ||
295 | match (false,) { (true | (),) => {} } | ||
296 | // ^^^^^^^^^^^^ Internal: match check bailed out | ||
297 | } | ||
298 | "#, | ||
299 | ); | ||
300 | } | ||
301 | |||
302 | #[test] | ||
303 | fn malformed_match_arm_tuple_enum_missing_pattern() { | ||
304 | // We are testing to be sure we don't panic here when the match | ||
305 | // arm `Either::B` is missing its pattern. | ||
306 | check_diagnostics( | ||
307 | r#" | ||
308 | enum Either { A, B(u32) } | ||
309 | |||
310 | fn main() { | ||
311 | match Either::A { | ||
312 | Either::A => (), | ||
313 | Either::B() => (), | ||
314 | } | ||
315 | } | ||
316 | "#, | ||
317 | ); | ||
318 | } | ||
319 | |||
320 | #[test] | ||
321 | fn malformed_match_arm_extra_fields() { | ||
322 | check_diagnostics( | ||
323 | r#" | ||
324 | enum A { B(isize, isize), C } | ||
325 | fn main() { | ||
326 | match A::B(1, 2) { | ||
327 | A::B(_, _, _) => (), | ||
328 | // ^^^^^^^^^^^^^ Internal: match check bailed out | ||
329 | } | ||
330 | match A::B(1, 2) { | ||
331 | A::C(_) => (), | ||
332 | // ^^^^^^^ Internal: match check bailed out | ||
333 | } | ||
334 | } | ||
335 | "#, | ||
336 | ); | ||
337 | } | ||
338 | |||
339 | #[test] | ||
340 | fn expr_diverges() { | ||
341 | check_diagnostics( | ||
342 | r#" | ||
343 | enum Either { A, B } | ||
344 | |||
345 | fn main() { | ||
346 | match loop {} { | ||
347 | Either::A => (), | ||
348 | // ^^^^^^^^^ Internal: match check bailed out | ||
349 | Either::B => (), | ||
350 | } | ||
351 | match loop {} { | ||
352 | Either::A => (), | ||
353 | // ^^^^^^^^^ Internal: match check bailed out | ||
354 | } | ||
355 | match loop { break Foo::A } { | ||
356 | //^^^^^^^^^^^^^^^^^^^^^ missing match arm | ||
357 | Either::A => (), | ||
358 | } | ||
359 | match loop { break Foo::A } { | ||
360 | Either::A => (), | ||
361 | Either::B => (), | ||
362 | } | ||
363 | } | ||
364 | "#, | ||
365 | ); | ||
366 | } | ||
367 | |||
368 | #[test] | ||
369 | fn expr_partially_diverges() { | ||
370 | check_diagnostics( | ||
371 | r#" | ||
372 | enum Either<T> { A(T), B } | ||
373 | |||
374 | fn foo() -> Either<!> { Either::B } | ||
375 | fn main() -> u32 { | ||
376 | match foo() { | ||
377 | Either::A(val) => val, | ||
378 | Either::B => 0, | ||
379 | } | ||
380 | } | ||
381 | "#, | ||
382 | ); | ||
383 | } | ||
384 | |||
385 | #[test] | ||
386 | fn enum_record() { | ||
387 | check_diagnostics( | ||
388 | r#" | ||
389 | enum Either { A { foo: bool }, B } | ||
390 | |||
391 | fn main() { | ||
392 | let a = Either::A { foo: true }; | ||
393 | match a { } | ||
394 | //^ missing match arm | ||
395 | match a { Either::A { foo: true } => () } | ||
396 | //^ missing match arm | ||
397 | match a { | ||
398 | Either::A { } => (), | ||
399 | //^^^^^^^^^ Missing structure fields: | ||
400 | // | - foo | ||
401 | Either::B => (), | ||
402 | } | ||
403 | match a { | ||
404 | //^ missing match arm | ||
405 | Either::A { } => (), | ||
406 | } //^^^^^^^^^ Missing structure fields: | ||
407 | // | - foo | ||
408 | |||
409 | match a { | ||
410 | Either::A { foo: true } => (), | ||
411 | Either::A { foo: false } => (), | ||
412 | Either::B => (), | ||
413 | } | ||
414 | match a { | ||
415 | Either::A { foo: _ } => (), | ||
416 | Either::B => (), | ||
417 | } | ||
418 | } | ||
419 | "#, | ||
420 | ); | ||
421 | } | ||
422 | |||
423 | #[test] | ||
424 | fn enum_record_fields_out_of_order() { | ||
425 | check_diagnostics( | ||
426 | r#" | ||
427 | enum Either { | ||
428 | A { foo: bool, bar: () }, | ||
429 | B, | ||
430 | } | ||
431 | |||
432 | fn main() { | ||
433 | let a = Either::A { foo: true, bar: () }; | ||
434 | match a { | ||
435 | //^ missing match arm | ||
436 | Either::A { bar: (), foo: false } => (), | ||
437 | Either::A { foo: true, bar: () } => (), | ||
438 | } | ||
439 | |||
440 | match a { | ||
441 | Either::A { bar: (), foo: false } => (), | ||
442 | Either::A { foo: true, bar: () } => (), | ||
443 | Either::B => (), | ||
444 | } | ||
445 | } | ||
446 | "#, | ||
447 | ); | ||
448 | } | ||
449 | |||
450 | #[test] | ||
451 | fn enum_record_ellipsis() { | ||
452 | check_diagnostics( | ||
453 | r#" | ||
454 | enum Either { | ||
455 | A { foo: bool, bar: bool }, | ||
456 | B, | ||
457 | } | ||
458 | |||
459 | fn main() { | ||
460 | let a = Either::B; | ||
461 | match a { | ||
462 | //^ missing match arm | ||
463 | Either::A { foo: true, .. } => (), | ||
464 | Either::B => (), | ||
465 | } | ||
466 | match a { | ||
467 | //^ missing match arm | ||
468 | Either::A { .. } => (), | ||
469 | } | ||
470 | |||
471 | match a { | ||
472 | Either::A { foo: true, .. } => (), | ||
473 | Either::A { foo: false, .. } => (), | ||
474 | Either::B => (), | ||
475 | } | ||
476 | |||
477 | match a { | ||
478 | Either::A { .. } => (), | ||
479 | Either::B => (), | ||
480 | } | ||
481 | } | ||
482 | "#, | ||
483 | ); | ||
484 | } | ||
485 | |||
486 | #[test] | ||
487 | fn enum_tuple_partial_ellipsis() { | ||
488 | check_diagnostics( | ||
489 | r#" | ||
490 | enum Either { | ||
491 | A(bool, bool, bool, bool), | ||
492 | B, | ||
493 | } | ||
494 | |||
495 | fn main() { | ||
496 | match Either::B { | ||
497 | //^^^^^^^^^ missing match arm | ||
498 | Either::A(true, .., true) => (), | ||
499 | Either::A(true, .., false) => (), | ||
500 | Either::A(false, .., false) => (), | ||
501 | Either::B => (), | ||
502 | } | ||
503 | match Either::B { | ||
504 | //^^^^^^^^^ missing match arm | ||
505 | Either::A(true, .., true) => (), | ||
506 | Either::A(true, .., false) => (), | ||
507 | Either::A(.., true) => (), | ||
508 | Either::B => (), | ||
509 | } | ||
510 | |||
511 | match Either::B { | ||
512 | Either::A(true, .., true) => (), | ||
513 | Either::A(true, .., false) => (), | ||
514 | Either::A(false, .., true) => (), | ||
515 | Either::A(false, .., false) => (), | ||
516 | Either::B => (), | ||
517 | } | ||
518 | match Either::B { | ||
519 | Either::A(true, .., true) => (), | ||
520 | Either::A(true, .., false) => (), | ||
521 | Either::A(.., true) => (), | ||
522 | Either::A(.., false) => (), | ||
523 | Either::B => (), | ||
524 | } | ||
525 | } | ||
526 | "#, | ||
527 | ); | ||
528 | } | ||
529 | |||
530 | #[test] | ||
531 | fn never() { | ||
532 | check_diagnostics( | ||
533 | r#" | ||
534 | enum Never {} | ||
535 | |||
536 | fn enum_(never: Never) { | ||
537 | match never {} | ||
538 | } | ||
539 | fn enum_ref(never: &Never) { | ||
540 | match never {} | ||
541 | //^^^^^ missing match arm | ||
542 | } | ||
543 | fn bang(never: !) { | ||
544 | match never {} | ||
545 | } | ||
546 | "#, | ||
547 | ); | ||
548 | } | ||
549 | |||
550 | #[test] | ||
551 | fn unknown_type() { | ||
552 | check_diagnostics( | ||
553 | r#" | ||
554 | enum Option<T> { Some(T), None } | ||
555 | |||
556 | fn main() { | ||
557 | // `Never` is deliberately not defined so that it's an uninferred type. | ||
558 | match Option::<Never>::None { | ||
559 | None => (), | ||
560 | Some(never) => match never {}, | ||
561 | // ^^^^^^^^^^^ Internal: match check bailed out | ||
562 | } | ||
563 | match Option::<Never>::None { | ||
564 | //^^^^^^^^^^^^^^^^^^^^^ missing match arm | ||
565 | Option::Some(_never) => {}, | ||
566 | } | ||
567 | } | ||
568 | "#, | ||
569 | ); | ||
570 | } | ||
571 | |||
572 | #[test] | ||
573 | fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { | ||
574 | check_diagnostics( | ||
575 | r#" | ||
576 | fn main() { | ||
577 | match (false, true, false) { | ||
578 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | ||
579 | (false, ..) => (), | ||
580 | } | ||
581 | }"#, | ||
582 | ); | ||
583 | } | ||
584 | |||
585 | #[test] | ||
586 | fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { | ||
587 | check_diagnostics( | ||
588 | r#" | ||
589 | fn main() { | ||
590 | match (false, true, false) { | ||
591 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | ||
592 | (.., false) => (), | ||
593 | } | ||
594 | }"#, | ||
595 | ); | ||
596 | } | ||
597 | |||
598 | #[test] | ||
599 | fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() { | ||
600 | check_diagnostics( | ||
601 | r#" | ||
602 | fn main() { | ||
603 | match (false, true, false) { | ||
604 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | ||
605 | (true, .., false) => (), | ||
606 | } | ||
607 | }"#, | ||
608 | ); | ||
609 | } | ||
610 | |||
611 | #[test] | ||
612 | fn record_struct() { | ||
613 | check_diagnostics( | ||
614 | r#"struct Foo { a: bool } | ||
615 | fn main(f: Foo) { | ||
616 | match f {} | ||
617 | //^ missing match arm | ||
618 | match f { Foo { a: true } => () } | ||
619 | //^ missing match arm | ||
620 | match &f { Foo { a: true } => () } | ||
621 | //^^ missing match arm | ||
622 | match f { Foo { a: _ } => () } | ||
623 | match f { | ||
624 | Foo { a: true } => (), | ||
625 | Foo { a: false } => (), | ||
626 | } | ||
627 | match &f { | ||
628 | Foo { a: true } => (), | ||
629 | Foo { a: false } => (), | ||
630 | } | ||
631 | } | ||
632 | "#, | ||
633 | ); | ||
634 | } | ||
635 | |||
636 | #[test] | ||
637 | fn tuple_struct() { | ||
638 | check_diagnostics( | ||
639 | r#"struct Foo(bool); | ||
640 | fn main(f: Foo) { | ||
641 | match f {} | ||
642 | //^ missing match arm | ||
643 | match f { Foo(true) => () } | ||
644 | //^ missing match arm | ||
645 | match f { | ||
646 | Foo(true) => (), | ||
647 | Foo(false) => (), | ||
648 | } | ||
649 | } | ||
650 | "#, | ||
651 | ); | ||
652 | } | ||
653 | |||
654 | #[test] | ||
655 | fn unit_struct() { | ||
656 | check_diagnostics( | ||
657 | r#"struct Foo; | ||
658 | fn main(f: Foo) { | ||
659 | match f {} | ||
660 | //^ missing match arm | ||
661 | match f { Foo => () } | ||
662 | } | ||
663 | "#, | ||
664 | ); | ||
665 | } | ||
666 | |||
667 | #[test] | ||
668 | fn record_struct_ellipsis() { | ||
669 | check_diagnostics( | ||
670 | r#"struct Foo { foo: bool, bar: bool } | ||
671 | fn main(f: Foo) { | ||
672 | match f { Foo { foo: true, .. } => () } | ||
673 | //^ missing match arm | ||
674 | match f { | ||
675 | //^ missing match arm | ||
676 | Foo { foo: true, .. } => (), | ||
677 | Foo { bar: false, .. } => () | ||
678 | } | ||
679 | match f { Foo { .. } => () } | ||
680 | match f { | ||
681 | Foo { foo: true, .. } => (), | ||
682 | Foo { foo: false, .. } => () | ||
683 | } | ||
684 | } | ||
685 | "#, | ||
686 | ); | ||
687 | } | ||
688 | |||
689 | #[test] | ||
690 | fn internal_or() { | ||
691 | check_diagnostics( | ||
692 | r#" | ||
693 | fn main() { | ||
694 | enum Either { A(bool), B } | ||
695 | match Either::B { | ||
696 | //^^^^^^^^^ missing match arm | ||
697 | Either::A(true | false) => (), | ||
698 | } | ||
699 | } | ||
700 | "#, | ||
701 | ); | ||
702 | } | ||
703 | |||
704 | #[test] | ||
705 | fn no_panic_at_unimplemented_subpattern_type() { | ||
706 | check_diagnostics( | ||
707 | r#" | ||
708 | struct S { a: char} | ||
709 | fn main(v: S) { | ||
710 | match v { S{ a } => {} } | ||
711 | match v { S{ a: _x } => {} } | ||
712 | match v { S{ a: 'a' } => {} } | ||
713 | //^^^^^^^^^^^ Internal: match check bailed out | ||
714 | match v { S{..} => {} } | ||
715 | match v { _ => {} } | ||
716 | match v { } | ||
717 | //^ missing match arm | ||
718 | } | ||
719 | "#, | ||
720 | ); | ||
721 | } | ||
722 | |||
723 | #[test] | ||
724 | fn binding() { | ||
725 | check_diagnostics( | ||
726 | r#" | ||
727 | fn main() { | ||
728 | match true { | ||
729 | _x @ true => {} | ||
730 | false => {} | ||
731 | } | ||
732 | match true { _x @ true => {} } | ||
733 | //^^^^ missing match arm | ||
734 | } | ||
735 | "#, | ||
736 | ); | ||
737 | } | ||
738 | |||
739 | #[test] | ||
740 | fn binding_ref_has_correct_type() { | ||
741 | // Asserts `PatKind::Binding(ref _x): bool`, not &bool. | ||
742 | // If that's not true match checking will panic with "incompatible constructors" | ||
743 | // FIXME: make facilities to test this directly like `tests::check_infer(..)` | ||
744 | check_diagnostics( | ||
745 | r#" | ||
746 | enum Foo { A } | ||
747 | fn main() { | ||
748 | // FIXME: this should not bail out but current behavior is such as the old algorithm. | ||
749 | // ExprValidator::validate_match(..) checks types of top level patterns incorrecly. | ||
750 | match Foo::A { | ||
751 | ref _x => {} | ||
752 | // ^^^^^^ Internal: match check bailed out | ||
753 | Foo::A => {} | ||
754 | } | ||
755 | match (true,) { | ||
756 | (ref _x,) => {} | ||
757 | (true,) => {} | ||
758 | } | ||
759 | } | ||
760 | "#, | ||
761 | ); | ||
762 | } | ||
763 | |||
764 | #[test] | ||
765 | fn enum_non_exhaustive() { | ||
766 | check_diagnostics( | ||
767 | r#" | ||
768 | //- /lib.rs crate:lib | ||
769 | #[non_exhaustive] | ||
770 | pub enum E { A, B } | ||
771 | fn _local() { | ||
772 | match E::A { _ => {} } | ||
773 | match E::A { | ||
774 | E::A => {} | ||
775 | E::B => {} | ||
776 | } | ||
777 | match E::A { | ||
778 | E::A | E::B => {} | ||
779 | } | ||
780 | } | ||
781 | |||
782 | //- /main.rs crate:main deps:lib | ||
783 | use lib::E; | ||
784 | fn main() { | ||
785 | match E::A { _ => {} } | ||
786 | match E::A { | ||
787 | //^^^^ missing match arm | ||
788 | E::A => {} | ||
789 | E::B => {} | ||
790 | } | ||
791 | match E::A { | ||
792 | //^^^^ missing match arm | ||
793 | E::A | E::B => {} | ||
794 | } | ||
795 | } | ||
796 | "#, | ||
797 | ); | ||
798 | } | ||
799 | |||
800 | #[test] | ||
801 | fn match_guard() { | ||
802 | check_diagnostics( | ||
803 | r#" | ||
804 | fn main() { | ||
805 | match true { | ||
806 | true if false => {} | ||
807 | true => {} | ||
808 | false => {} | ||
809 | } | ||
810 | match true { | ||
811 | //^^^^ missing match arm | ||
812 | true if false => {} | ||
813 | false => {} | ||
814 | } | ||
815 | } | ||
816 | "#, | ||
817 | ); | ||
818 | } | ||
819 | |||
820 | #[test] | ||
821 | fn pattern_type_is_of_substitution() { | ||
822 | cov_mark::check!(match_check_wildcard_expanded_to_substitutions); | ||
823 | check_diagnostics( | ||
824 | r#" | ||
825 | struct Foo<T>(T); | ||
826 | struct Bar; | ||
827 | fn main() { | ||
828 | match Foo(Bar) { | ||
829 | _ | Foo(Bar) => {} | ||
830 | } | ||
831 | } | ||
832 | "#, | ||
833 | ); | ||
834 | } | ||
835 | |||
836 | #[test] | ||
837 | fn record_struct_no_such_field() { | ||
838 | check_diagnostics( | ||
839 | r#" | ||
840 | struct Foo { } | ||
841 | fn main(f: Foo) { | ||
842 | match f { Foo { bar } => () } | ||
843 | // ^^^^^^^^^^^ Internal: match check bailed out | ||
844 | } | ||
845 | "#, | ||
846 | ); | ||
847 | } | ||
848 | |||
849 | #[test] | ||
850 | fn match_ergonomics_issue_9095() { | ||
851 | check_diagnostics( | ||
852 | r#" | ||
853 | enum Foo<T> { A(T) } | ||
854 | fn main() { | ||
855 | match &Foo::A(true) { | ||
856 | _ => {} | ||
857 | Foo::A(_) => {} | ||
858 | } | ||
859 | } | ||
860 | "#, | ||
861 | ); | ||
862 | } | ||
863 | |||
864 | mod false_negatives { | ||
865 | //! The implementation of match checking here is a work in progress. As we roll this out, we | ||
866 | //! prefer false negatives to false positives (ideally there would be no false positives). This | ||
867 | //! test module should document known false negatives. Eventually we will have a complete | ||
868 | //! implementation of match checking and this module will be empty. | ||
869 | //! | ||
870 | //! The reasons for documenting known false negatives: | ||
871 | //! | ||
872 | //! 1. It acts as a backlog of work that can be done to improve the behavior of the system. | ||
873 | //! 2. It ensures the code doesn't panic when handling these cases. | ||
874 | use super::*; | ||
875 | |||
876 | #[test] | ||
877 | fn integers() { | ||
878 | // We don't currently check integer exhaustiveness. | ||
879 | check_diagnostics( | ||
880 | r#" | ||
881 | fn main() { | ||
882 | match 5 { | ||
883 | 10 => (), | ||
884 | // ^^ Internal: match check bailed out | ||
885 | 11..20 => (), | ||
886 | } | ||
887 | } | ||
888 | "#, | ||
889 | ); | ||
890 | } | ||
891 | |||
892 | #[test] | ||
893 | fn reference_patterns_at_top_level() { | ||
894 | check_diagnostics( | ||
895 | r#" | ||
896 | fn main() { | ||
897 | match &false { | ||
898 | &true => {} | ||
899 | // ^^^^^ Internal: match check bailed out | ||
900 | } | ||
901 | } | ||
902 | "#, | ||
903 | ); | ||
904 | } | ||
905 | |||
906 | #[test] | ||
907 | fn reference_patterns_in_fields() { | ||
908 | check_diagnostics( | ||
909 | r#" | ||
910 | fn main() { | ||
911 | match (&false,) { | ||
912 | (true,) => {} | ||
913 | // ^^^^^^^ Internal: match check bailed out | ||
914 | } | ||
915 | match (&false,) { | ||
916 | (&true,) => {} | ||
917 | // ^^^^^^^^ Internal: match check bailed out | ||
918 | } | ||
919 | } | ||
920 | "#, | ||
921 | ); | ||
922 | } | ||
923 | } | ||
924 | } | ||