@@ -642,14 +642,7 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
642
642
. into_iter ( )
643
643
. flat_map ( |witness| {
644
644
new_patterns. iter ( ) . map ( move |pat| {
645
- Witness (
646
- witness
647
- . 0
648
- . iter ( )
649
- . chain ( once ( pat) )
650
- . map ( DeconstructedPat :: clone_and_forget_reachability)
651
- . collect ( ) ,
652
- )
645
+ Witness ( witness. 0 . iter ( ) . chain ( once ( pat) ) . cloned ( ) . collect ( ) )
653
646
} )
654
647
} )
655
648
. collect ( )
@@ -843,7 +836,6 @@ fn is_useful<'p, 'tcx>(
843
836
}
844
837
// We split the head constructor of `v`.
845
838
let split_ctors = v_ctor. split ( pcx, matrix. heads ( ) . map ( DeconstructedPat :: ctor) ) ;
846
- let is_non_exhaustive_and_wild = is_non_exhaustive && v_ctor. is_wildcard ( ) ;
847
839
// For each constructor, we compute whether there's a value that starts with it that would
848
840
// witness the usefulness of `v`.
849
841
let start_matrix = & matrix;
@@ -864,56 +856,6 @@ fn is_useful<'p, 'tcx>(
864
856
)
865
857
} ) ;
866
858
let usefulness = usefulness. apply_constructor ( pcx, start_matrix, & ctor) ;
867
-
868
- // When all the conditions are met we have a match with a `non_exhaustive` enum
869
- // that has the potential to trigger the `non_exhaustive_omitted_patterns` lint.
870
- // To understand the workings checkout `Constructor::split` and `SplitWildcard::new/into_ctors`
871
- if is_non_exhaustive_and_wild
872
- // Only emit a lint on refutable patterns.
873
- && cx. refutable
874
- // We check that the match has a wildcard pattern and that wildcard is useful,
875
- // meaning there are variants that are covered by the wildcard. Without the check
876
- // for `witness_preference` the lint would trigger on `if let NonExhaustiveEnum::A = foo {}`
877
- && usefulness. is_useful ( ) && matches ! ( witness_preference, RealArm )
878
- && matches ! (
879
- & ctor,
880
- Constructor :: Missing { nonexhaustive_enum_missing_real_variants: true }
881
- )
882
- {
883
- let patterns = {
884
- let mut split_wildcard = SplitWildcard :: new ( pcx) ;
885
- split_wildcard. split ( pcx, matrix. heads ( ) . map ( DeconstructedPat :: ctor) ) ;
886
- // Construct for each missing constructor a "wild" version of this
887
- // constructor, that matches everything that can be built with
888
- // it. For example, if `ctor` is a `Constructor::Variant` for
889
- // `Option::Some`, we get the pattern `Some(_)`.
890
- split_wildcard
891
- . iter_missing ( pcx)
892
- // Filter out the `NonExhaustive` because we want to list only real
893
- // variants. Also remove any unstable feature gated variants.
894
- // Because of how we computed `nonexhaustive_enum_missing_real_variants`,
895
- // this will not return an empty `Vec`.
896
- . filter ( |c| !( c. is_non_exhaustive ( ) || c. is_unstable_variant ( pcx) ) )
897
- . cloned ( )
898
- . map ( |missing_ctor| DeconstructedPat :: wild_from_ctor ( pcx, missing_ctor) )
899
- . collect :: < Vec < _ > > ( )
900
- } ;
901
-
902
- // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
903
- // is not exhaustive enough.
904
- //
905
- // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
906
- cx. tcx . emit_spanned_lint (
907
- NON_EXHAUSTIVE_OMITTED_PATTERNS ,
908
- lint_root,
909
- pcx. span ,
910
- NonExhaustiveOmittedPattern {
911
- scrut_ty : pcx. ty ,
912
- uncovered : Uncovered :: new ( pcx. span , pcx. cx , patterns) ,
913
- } ,
914
- ) ;
915
- }
916
-
917
859
ret. extend ( usefulness) ;
918
860
}
919
861
}
@@ -925,6 +867,96 @@ fn is_useful<'p, 'tcx>(
925
867
ret
926
868
}
927
869
870
+ /// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned
871
+ /// in a given column. This traverses patterns column-by-column, where a column is the intuitive
872
+ /// notion of "subpatterns that inspect the same subvalue".
873
+ /// Despite similarities with `is_useful`, this traversal is different. Notably this is linear in the
874
+ /// depth of patterns, whereas `is_useful` is worst-case exponential (exhaustiveness is NP-complete).
875
+ fn collect_nonexhaustive_missing_variants < ' p , ' tcx > (
876
+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
877
+ column : & [ & DeconstructedPat < ' p , ' tcx > ] ,
878
+ ) -> Vec < DeconstructedPat < ' p , ' tcx > > {
879
+ let mut witnesses = Vec :: new ( ) ;
880
+ // If the column is all wildcards, we don't want to collect anything and we can't recurse
881
+ // further.
882
+ let is_all_wildcards = column. iter ( ) . all ( |p| p. ctor ( ) . is_wildcard ( ) ) ;
883
+ if column. is_empty ( ) || is_all_wildcards {
884
+ return witnesses;
885
+ }
886
+
887
+ let ty = column[ 0 ] . ty ( ) ;
888
+ let span = column[ 0 ] . span ( ) ;
889
+ let is_non_exhaustive = cx. is_foreign_non_exhaustive_enum ( ty) ;
890
+ let pcx = & PatCtxt { cx, ty, span, is_top_level : false , is_non_exhaustive } ;
891
+
892
+ let mut split_wildcard = SplitWildcard :: new ( pcx) ;
893
+ split_wildcard. split ( pcx, column. iter ( ) . map ( |p| p. ctor ( ) ) ) ;
894
+
895
+ if is_non_exhaustive {
896
+ witnesses. extend (
897
+ split_wildcard
898
+ . iter_missing ( pcx)
899
+ // Filter out the `NonExhaustive` ctor because we want to list only real variants.
900
+ // Also remove any unstable feature gated variants.
901
+ . filter ( |c| !( c. is_non_exhaustive ( ) || c. is_unstable_variant ( pcx) ) )
902
+ . cloned ( )
903
+ . map ( |missing_ctor| DeconstructedPat :: wild_from_ctor ( pcx, missing_ctor) ) ,
904
+ )
905
+ }
906
+
907
+ // Recurse into the fields.
908
+ for ctor in split_wildcard. iter_present ( pcx) {
909
+ let arity = ctor. arity ( pcx) ;
910
+ if arity == 0 {
911
+ continue ;
912
+ }
913
+
914
+ // We specialize the column by `ctor`. This gives us `arity`-many columns of patterns. These
915
+ // columns may not have the same length in the presence of or-patterns (this is why we can't
916
+ // reuse what `Matrix` does).
917
+ let mut specialized_columns: Vec < Vec < _ > > = ( 0 ..arity) . map ( |_| Vec :: new ( ) ) . collect ( ) ;
918
+ let relevant_patterns = column. iter ( ) . filter ( |pat| ctor. is_covered_by ( pcx, pat. ctor ( ) ) ) ;
919
+ for pat in relevant_patterns {
920
+ let specialized = pat. specialize ( pcx, & ctor) ;
921
+ for ( subpat, sub_column) in specialized. iter ( ) . zip ( & mut specialized_columns) {
922
+ if subpat. is_or_pat ( ) {
923
+ sub_column. extend ( subpat. iter_fields ( ) )
924
+ } else {
925
+ sub_column. push ( subpat)
926
+ }
927
+ }
928
+ }
929
+ assert ! (
930
+ !specialized_columns[ 0 ] . is_empty( ) ,
931
+ "ctor {ctor:?} was listed as present but isn't"
932
+ ) ;
933
+
934
+ for ( i, col_i) in specialized_columns. iter ( ) . enumerate ( ) {
935
+ // Compute witnesses for each column.
936
+ let wits_for_col_i = collect_nonexhaustive_missing_variants ( cx, col_i. as_slice ( ) ) ;
937
+ if wits_for_col_i. is_empty ( ) {
938
+ continue ;
939
+ }
940
+ // For each witness, we build a new pattern in the shape of `ctor(_, _, wit, _, _)`,
941
+ // adding enough wildcards to match `arity`.
942
+ let fields = Fields :: wildcards ( pcx, & ctor) ;
943
+ for wit in wits_for_col_i {
944
+ let fields_with_wit = Fields :: from_iter (
945
+ cx,
946
+ fields
947
+ . iter_patterns ( )
948
+ . enumerate ( )
949
+ . map ( |( j, wild) | if i == j { & wit } else { wild } )
950
+ . cloned ( ) ,
951
+ ) ;
952
+ let pat = DeconstructedPat :: new ( ctor. clone ( ) , fields_with_wit, ty, DUMMY_SP ) ;
953
+ witnesses. push ( pat) ;
954
+ }
955
+ }
956
+ }
957
+ witnesses
958
+ }
959
+
928
960
/// The arm of a match expression.
929
961
#[ derive( Clone , Copy , Debug ) ]
930
962
pub ( crate ) struct MatchArm < ' p , ' tcx > {
@@ -965,6 +997,7 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
965
997
arms : & [ MatchArm < ' p , ' tcx > ] ,
966
998
lint_root : HirId ,
967
999
scrut_ty : Ty < ' tcx > ,
1000
+ scrut_span : Span ,
968
1001
) -> UsefulnessReport < ' p , ' tcx > {
969
1002
let mut matrix = Matrix :: empty ( ) ;
970
1003
let arm_usefulness: Vec < _ > = arms
@@ -989,9 +1022,39 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
989
1022
let wild_pattern = cx. pattern_arena . alloc ( DeconstructedPat :: wildcard ( scrut_ty, DUMMY_SP ) ) ;
990
1023
let v = PatStack :: from_pattern ( wild_pattern) ;
991
1024
let usefulness = is_useful ( cx, & matrix, & v, FakeExtraWildcard , lint_root, false , true ) ;
992
- let non_exhaustiveness_witnesses = match usefulness {
1025
+ let non_exhaustiveness_witnesses: Vec < _ > = match usefulness {
993
1026
WithWitnesses ( pats) => pats. into_iter ( ) . map ( |w| w. single_pattern ( ) ) . collect ( ) ,
994
1027
NoWitnesses { .. } => bug ! ( ) ,
995
1028
} ;
1029
+
1030
+ // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hittin
1031
+ // `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
1032
+ if cx. refutable
1033
+ && non_exhaustiveness_witnesses. is_empty ( )
1034
+ && !matches ! (
1035
+ cx. tcx. lint_level_at_node( NON_EXHAUSTIVE_OMITTED_PATTERNS , lint_root) . 0 ,
1036
+ rustc_session:: lint:: Level :: Allow
1037
+ )
1038
+ {
1039
+ let pat_column = arms. iter ( ) . flat_map ( |arm| arm. pat . flatten_or_pat ( ) ) . collect :: < Vec < _ > > ( ) ;
1040
+ let witnesses = collect_nonexhaustive_missing_variants ( cx, & pat_column) ;
1041
+
1042
+ if !witnesses. is_empty ( ) {
1043
+ // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
1044
+ // is not exhaustive enough.
1045
+ //
1046
+ // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
1047
+ cx. tcx . emit_spanned_lint (
1048
+ NON_EXHAUSTIVE_OMITTED_PATTERNS ,
1049
+ lint_root,
1050
+ scrut_span,
1051
+ NonExhaustiveOmittedPattern {
1052
+ scrut_ty,
1053
+ uncovered : Uncovered :: new ( scrut_span, cx, witnesses) ,
1054
+ } ,
1055
+ ) ;
1056
+ }
1057
+ }
1058
+
996
1059
UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }
997
1060
}
0 commit comments