aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_ty/src/diagnostics/pattern.rs666
1 files changed, 597 insertions, 69 deletions
diff --git a/crates/hir_ty/src/diagnostics/pattern.rs b/crates/hir_ty/src/diagnostics/pattern.rs
index 4f88dfe60..f8d2e9baa 100644
--- a/crates/hir_ty/src/diagnostics/pattern.rs
+++ b/crates/hir_ty/src/diagnostics/pattern.rs
@@ -3,7 +3,7 @@
3//! This module provides lowering from [hir_def::expr::Pat] to [self::Pat] and match 3//! This module provides lowering from [hir_def::expr::Pat] to [self::Pat] and match
4//! checking algorithm. 4//! checking algorithm.
5//! 5//!
6//! It is a loose port of `rustc_mir_build::thir::pattern` module. 6//! It is modeled on the rustc module `rustc_mir_build::thir::pattern`.
7 7
8mod deconstruct_pat; 8mod deconstruct_pat;
9mod pat_util; 9mod pat_util;
@@ -341,136 +341,636 @@ mod tests {
341 use crate::diagnostics::tests::check_diagnostics; 341 use crate::diagnostics::tests::check_diagnostics;
342 342
343 #[test] 343 #[test]
344 fn unit() { 344 fn empty_tuple() {
345 check_diagnostics( 345 check_diagnostics(
346 r#" 346 r#"
347fn main() { 347fn main() {
348 match () { () => {} } 348 match () { }
349 match () { _ => {} }
350 match () { }
351 //^^ Missing match arm 349 //^^ Missing match arm
350 match (()) { }
351 //^^^^ Missing match arm
352
353 match () { _ => (), }
354 match () { () => (), }
355 match (()) { (()) => (), }
352} 356}
353"#, 357"#,
354 ); 358 );
355 } 359 }
356 360
357 #[test] 361 #[test]
358 fn tuple_of_units() { 362 fn tuple_of_two_empty_tuple() {
359 check_diagnostics( 363 check_diagnostics(
360 r#" 364 r#"
361fn main() { 365fn main() {
362 match ((), ()) { ((), ()) => {} } 366 match ((), ()) { }
363 match ((), ()) { ((), _) => {} }
364 match ((), ()) { (_, _) => {} }
365 match ((), ()) { _ => {} }
366 match ((), ()) { }
367 //^^^^^^^^ Missing match arm 367 //^^^^^^^^ Missing match arm
368
369 match ((), ()) { ((), ()) => (), }
368} 370}
369"#, 371"#,
370 ); 372 );
371 } 373 }
372 374
373 #[test] 375 #[test]
374 fn tuple_with_ellipsis() { 376 fn boolean() {
375 check_diagnostics( 377 check_diagnostics(
376 r#" 378 r#"
377struct A; struct B; 379fn test_main() {
378fn main(v: (A, (), B)) { 380 match false { }
379 match v { (A, ..) => {} } 381 //^^^^^ Missing match arm
380 match v { (.., B) => {} } 382 match false { true => (), }
381 match v { (A, .., B) => {} } 383 //^^^^^ Missing match arm
382 match v { (..) => {} } 384 match (false, true) {}
383 match v { } 385 //^^^^^^^^^^^^^ Missing match arm
384 //^ Missing match arm 386 match (false, true) { (true, true) => (), }
387 //^^^^^^^^^^^^^ Missing match arm
388 match (false, true) {
389 //^^^^^^^^^^^^^ Missing match arm
390 (false, true) => (),
391 (false, false) => (),
392 (true, false) => (),
393 }
394 match (false, true) { (true, _x) => (), }
395 //^^^^^^^^^^^^^ Missing match arm
396
397 match false { true => (), false => (), }
398 match (false, true) {
399 (false, _) => (),
400 (true, false) => (),
401 (_, true) => (),
402 }
403 match (false, true) {
404 (true, true) => (),
405 (true, false) => (),
406 (false, true) => (),
407 (false, false) => (),
408 }
409 match (false, true) {
410 (true, _x) => (),
411 (false, true) => (),
412 (false, false) => (),
413 }
414 match (false, true, false) {
415 (false, ..) => (),
416 (true, ..) => (),
417 }
418 match (false, true, false) {
419 (.., false) => (),
420 (.., true) => (),
421 }
422 match (false, true, false) { (..) => (), }
385} 423}
386"#, 424"#,
387 ); 425 );
388 } 426 }
389 427
390 #[test] 428 #[test]
391 fn strukt() { 429 fn tuple_of_tuple_and_bools() {
392 check_diagnostics( 430 check_diagnostics(
393 r#" 431 r#"
394struct A; struct B; 432fn main() {
395struct S { a: A, b: B} 433 match (false, ((), false)) {}
396fn main(v: S) { 434 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
397 match v { S { a, b } => {} } 435 match (false, ((), false)) { (true, ((), true)) => (), }
398 match v { S { a: _, b: _ } => {} } 436 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
399 match v { S { .. } => {} } 437 match (false, ((), false)) { (true, _) => (), }
400 match v { _ => {} } 438 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
401 match v { } 439
402 //^ Missing match arm 440 match (false, ((), false)) {
441 (true, ((), true)) => (),
442 (true, ((), false)) => (),
443 (false, ((), true)) => (),
444 (false, ((), false)) => (),
445 }
446 match (false, ((), false)) {
447 (true, ((), true)) => (),
448 (true, ((), false)) => (),
449 (false, _) => (),
450 }
403} 451}
404"#, 452"#,
405 ); 453 );
406 } 454 }
407 455
408 #[test] 456 #[test]
409 fn c_enum() { 457 fn enums() {
410 check_diagnostics( 458 check_diagnostics(
411 r#" 459 r#"
412enum E { A, B } 460enum Either { A, B, }
413fn main(v: E) { 461
414 match v { E::A | E::B => {} } 462fn main() {
415 match v { _ => {} } 463 match Either::A { }
416 match v { E::A => {} } 464 //^^^^^^^^^ Missing match arm
465 match Either::B { Either::A => (), }
466 //^^^^^^^^^ Missing match arm
467
468 match &Either::B {
469 //^^^^^^^^^^ Missing match arm
470 Either::A => (),
471 }
472
473 match Either::B {
474 Either::A => (), Either::B => (),
475 }
476 match &Either::B {
477 Either::A => (), Either::B => (),
478 }
479}
480"#,
481 );
482 }
483
484 #[test]
485 fn enum_containing_bool() {
486 check_diagnostics(
487 r#"
488enum Either { A(bool), B }
489
490fn main() {
491 match Either::B { }
492 //^^^^^^^^^ Missing match arm
493 match Either::B {
494 //^^^^^^^^^ Missing match arm
495 Either::A(true) => (), Either::B => ()
496 }
497
498 match Either::B {
499 Either::A(true) => (),
500 Either::A(false) => (),
501 Either::B => (),
502 }
503 match Either::B {
504 Either::B => (),
505 _ => (),
506 }
507 match Either::B {
508 Either::A(_) => (),
509 Either::B => (),
510 }
511
512}
513 "#,
514 );
515 }
516
517 #[test]
518 fn enum_different_sizes() {
519 check_diagnostics(
520 r#"
521enum Either { A(bool), B(bool, bool) }
522
523fn main() {
524 match Either::A(false) {
525 //^^^^^^^^^^^^^^^^ Missing match arm
526 Either::A(_) => (),
527 Either::B(false, _) => (),
528 }
529
530 match Either::A(false) {
531 Either::A(_) => (),
532 Either::B(true, _) => (),
533 Either::B(false, _) => (),
534 }
535 match Either::A(false) {
536 Either::A(true) | Either::A(false) => (),
537 Either::B(true, _) => (),
538 Either::B(false, _) => (),
539 }
540}
541"#,
542 );
543 }
544
545 #[test]
546 fn tuple_of_enum_no_diagnostic() {
547 check_diagnostics(
548 r#"
549enum Either { A(bool), B(bool, bool) }
550enum Either2 { C, D }
551
552fn main() {
553 match (Either::A(false), Either2::C) {
554 (Either::A(true), _) | (Either::A(false), _) => (),
555 (Either::B(true, _), Either2::C) => (),
556 (Either::B(false, _), Either2::C) => (),
557 (Either::B(_, _), Either2::D) => (),
558 }
559}
560"#,
561 );
562 }
563
564 #[test]
565 fn or_pattern_no_diagnostic() {
566 check_diagnostics(
567 r#"
568enum Either {A, B}
569
570fn main() {
571 match (Either::A, Either::B) {
572 (Either::A | Either::B, _) => (),
573 }
574}"#,
575 )
576 }
577
578 #[test]
579 fn mismatched_types() {
580 // Match statements with arms that don't match the
581 // expression pattern do not fire this diagnostic.
582 check_diagnostics(
583 r#"
584enum Either { A, B }
585enum Either2 { C, D }
586
587fn main() {
588 match Either::A {
589 Either2::C => (),
590 Either2::D => (),
591 }
592 match (true, false) {
593 (true, false, true) => (),
594 (true) => (),
595 }
596 match (0) { () => () }
597 match Unresolved::Bar { Unresolved::Baz => () }
598}
599 "#,
600 );
601 }
602
603 #[test]
604 fn malformed_match_arm_tuple_enum_missing_pattern() {
605 // We are testing to be sure we don't panic here when the match
606 // arm `Either::B` is missing its pattern.
607 check_diagnostics(
608 r#"
609enum Either { A, B(u32) }
610
611fn main() {
612 match Either::A {
613 Either::A => (),
614 Either::B() => (),
615 }
616}
617"#,
618 );
619 }
620
621 #[test]
622 fn expr_diverges() {
623 check_diagnostics(
624 r#"
625enum Either { A, B }
626
627fn main() {
628 match loop {} {
629 Either::A => (),
630 Either::B => (),
631 }
632 match loop {} {
633 Either::A => (),
634 }
635 match loop { break Foo::A } {
636 //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
637 Either::A => (),
638 }
639 match loop { break Foo::A } {
640 Either::A => (),
641 Either::B => (),
642 }
643}
644"#,
645 );
646 }
647
648 #[test]
649 fn expr_partially_diverges() {
650 check_diagnostics(
651 r#"
652enum Either<T> { A(T), B }
653
654fn foo() -> Either<!> { Either::B }
655fn main() -> u32 {
656 match foo() {
657 Either::A(val) => val,
658 Either::B => 0,
659 }
660}
661"#,
662 );
663 }
664
665 #[test]
666 fn enum_record() {
667 check_diagnostics(
668 r#"
669enum Either { A { foo: bool }, B }
670
671fn main() {
672 let a = Either::A { foo: true };
673 match a { }
417 //^ Missing match arm 674 //^ Missing match arm
418 match v { } 675 match a { Either::A { foo: true } => () }
419 //^ Missing match arm 676 //^ Missing match arm
677 match a {
678 Either::A { } => (),
679 //^^^^^^^^^ Missing structure fields:
680 // | - foo
681 Either::B => (),
682 }
683 match a {
684 //^ Missing match arm
685 Either::A { } => (),
686 } //^^^^^^^^^ Missing structure fields:
687 // | - foo
688
689 match a {
690 Either::A { foo: true } => (),
691 Either::A { foo: false } => (),
692 Either::B => (),
693 }
694 match a {
695 Either::A { foo: _ } => (),
696 Either::B => (),
697 }
420} 698}
421"#, 699"#,
422 ); 700 );
423 } 701 }
424 702
425 #[test] 703 #[test]
426 fn enum_() { 704 fn enum_record_fields_out_of_order() {
427 check_diagnostics( 705 check_diagnostics(
428 r#" 706 r#"
429struct A; struct B; 707enum Either {
430enum E { Tuple(A, B), Struct{ a: A, b: B } } 708 A { foo: bool, bar: () },
431fn main(v: E) { 709 B,
432 match v { 710}
433 E::Tuple(a, b) => {} 711
434 E::Struct{ a, b } => {} 712fn main() {
435 } 713 let a = Either::A { foo: true, bar: () };
436 match v { 714 match a {
437 E::Tuple(_, _) => {}
438 E::Struct{..} => {}
439 }
440 match v {
441 E::Tuple(..) => {}
442 _ => {}
443 }
444 match v { E::Tuple(..) => {} }
445 //^ Missing match arm 715 //^ Missing match arm
446 match v { } 716 Either::A { bar: (), foo: false } => (),
717 Either::A { foo: true, bar: () } => (),
718 }
719
720 match a {
721 Either::A { bar: (), foo: false } => (),
722 Either::A { foo: true, bar: () } => (),
723 Either::B => (),
724 }
725}
726"#,
727 );
728 }
729
730 #[test]
731 fn enum_record_ellipsis() {
732 check_diagnostics(
733 r#"
734enum Either {
735 A { foo: bool, bar: bool },
736 B,
737}
738
739fn main() {
740 let a = Either::B;
741 match a {
742 //^ Missing match arm
743 Either::A { foo: true, .. } => (),
744 Either::B => (),
745 }
746 match a {
447 //^ Missing match arm 747 //^ Missing match arm
748 Either::A { .. } => (),
749 }
750
751 match a {
752 Either::A { foo: true, .. } => (),
753 Either::A { foo: false, .. } => (),
754 Either::B => (),
755 }
756
757 match a {
758 Either::A { .. } => (),
759 Either::B => (),
760 }
448} 761}
449"#, 762"#,
450 ); 763 );
451 } 764 }
452 765
453 #[test] 766 #[test]
454 fn boolean() { 767 fn enum_tuple_partial_ellipsis() {
455 check_diagnostics( 768 check_diagnostics(
456 r#" 769 r#"
770enum Either {
771 A(bool, bool, bool, bool),
772 B,
773}
774
457fn main() { 775fn main() {
458 match true { 776 match Either::B {
459 true => {} 777 //^^^^^^^^^ Missing match arm
460 false => {} 778 Either::A(true, .., true) => (),
779 Either::A(true, .., false) => (),
780 Either::A(false, .., false) => (),
781 Either::B => (),
461 } 782 }
462 match true { 783 match Either::B {
463 true | false => {} 784 //^^^^^^^^^ Missing match arm
785 Either::A(true, .., true) => (),
786 Either::A(true, .., false) => (),
787 Either::A(.., true) => (),
788 Either::B => (),
464 } 789 }
465 match true { 790
466 true => {} 791 match Either::B {
467 _ => {} 792 Either::A(true, .., true) => (),
793 Either::A(true, .., false) => (),
794 Either::A(false, .., true) => (),
795 Either::A(false, .., false) => (),
796 Either::B => (),
797 }
798 match Either::B {
799 Either::A(true, .., true) => (),
800 Either::A(true, .., false) => (),
801 Either::A(.., true) => (),
802 Either::A(.., false) => (),
803 Either::B => (),
804 }
805}
806"#,
807 );
808 }
809
810 #[test]
811 fn never() {
812 check_diagnostics(
813 r#"
814enum Never {}
815
816fn enum_(never: Never) {
817 match never {}
818}
819fn enum_ref(never: &Never) {
820 match never {}
821 //^^^^^ Missing match arm
822}
823fn bang(never: !) {
824 match never {}
825}
826"#,
827 );
828 }
829
830 #[test]
831 fn unknown_type() {
832 check_diagnostics(
833 r#"
834enum Option<T> { Some(T), None }
835
836fn main() {
837 // `Never` is deliberately not defined so that it's an uninferred type.
838 match Option::<Never>::None {
839 None => (),
840 Some(never) => match never {},
841 }
842}
843"#,
844 );
845 }
846
847 #[test]
848 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
849 check_diagnostics(
850 r#"
851fn main() {
852 match (false, true, false) {
853 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
854 (false, ..) => (),
855 }
856}"#,
857 );
858 }
859
860 #[test]
861 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
862 check_diagnostics(
863 r#"
864fn main() {
865 match (false, true, false) {
866 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
867 (.., false) => (),
868 }
869}"#,
870 );
871 }
872
873 #[test]
874 fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() {
875 check_diagnostics(
876 r#"
877fn main() {
878 match (false, true, false) {
879 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
880 (true, .., false) => (),
881 }
882}"#,
883 );
884 }
885
886 #[test]
887 fn record_struct() {
888 check_diagnostics(
889 r#"struct Foo { a: bool }
890fn main(f: Foo) {
891 match f {}
892 //^ Missing match arm
893 match f { Foo { a: true } => () }
894 //^ Missing match arm
895 match &f { Foo { a: true } => () }
896 //^^ Missing match arm
897 match f { Foo { a: _ } => () }
898 match f {
899 Foo { a: true } => (),
900 Foo { a: false } => (),
901 }
902 match &f {
903 Foo { a: true } => (),
904 Foo { a: false } => (),
905 }
906}
907"#,
908 );
468 } 909 }
469 match true {}
470 //^^^^ Missing match arm
471 match true { true => {} }
472 //^^^^ Missing match arm
473 910
911 #[test]
912 fn tuple_struct() {
913 check_diagnostics(
914 r#"struct Foo(bool);
915fn main(f: Foo) {
916 match f {}
917 //^ Missing match arm
918 match f { Foo(true) => () }
919 //^ Missing match arm
920 match f {
921 Foo(true) => (),
922 Foo(false) => (),
923 }
924}
925"#,
926 );
927 }
928
929 #[test]
930 fn unit_struct() {
931 check_diagnostics(
932 r#"struct Foo;
933fn main(f: Foo) {
934 match f {}
935 //^ Missing match arm
936 match f { Foo => () }
937}
938"#,
939 );
940 }
941
942 #[test]
943 fn record_struct_ellipsis() {
944 check_diagnostics(
945 r#"struct Foo { foo: bool, bar: bool }
946fn main(f: Foo) {
947 match f { Foo { foo: true, .. } => () }
948 //^ Missing match arm
949 match f {
950 //^ Missing match arm
951 Foo { foo: true, .. } => (),
952 Foo { bar: false, .. } => ()
953 }
954 match f { Foo { .. } => () }
955 match f {
956 Foo { foo: true, .. } => (),
957 Foo { foo: false, .. } => ()
958 }
959}
960"#,
961 );
962 }
963
964 #[test]
965 fn internal_or() {
966 check_diagnostics(
967 r#"
968fn main() {
969 enum Either { A(bool), B }
970 match Either::B {
971 //^^^^^^^^^ Missing match arm
972 Either::A(true | false) => (),
973 }
474} 974}
475"#, 975"#,
476 ); 976 );
@@ -483,7 +983,7 @@ fn main() {
483struct S { a: char} 983struct S { a: char}
484fn main(v: S) { 984fn main(v: S) {
485 match v { S{ a } => {} } 985 match v { S{ a } => {} }
486 match v { S{ a: _x } => {} } 986 match v { S{ a: _x } => {} }
487 match v { S{ a: 'a' } => {} } 987 match v { S{ a: 'a' } => {} }
488 match v { S{..} => {} } 988 match v { S{..} => {} }
489 match v { _ => {} } 989 match v { _ => {} }
@@ -509,4 +1009,32 @@ fn main() {
509"#, 1009"#,
510 ); 1010 );
511 } 1011 }
1012
1013 mod false_negatives {
1014 //! The implementation of match checking here is a work in progress. As we roll this out, we
1015 //! prefer false negatives to false positives (ideally there would be no false positives). This
1016 //! test module should document known false negatives. Eventually we will have a complete
1017 //! implementation of match checking and this module will be empty.
1018 //!
1019 //! The reasons for documenting known false negatives:
1020 //!
1021 //! 1. It acts as a backlog of work that can be done to improve the behavior of the system.
1022 //! 2. It ensures the code doesn't panic when handling these cases.
1023 use super::*;
1024
1025 #[test]
1026 fn integers() {
1027 // We don't currently check integer exhaustiveness.
1028 check_diagnostics(
1029 r#"
1030fn main() {
1031 match 5 {
1032 10 => (),
1033 11..20 => (),
1034 }
1035}
1036"#,
1037 );
1038 }
1039 }
512} 1040}