@@ -844,8 +844,6 @@ fn is_useful<'p, 'tcx>(
844844 }
845845 // We split the head constructor of `v`.
846846 let split_ctors = v_ctor. split ( pcx, matrix. heads ( ) . map ( DeconstructedPat :: ctor) ) ;
847- let is_non_exhaustive_and_wild =
848- cx. is_foreign_non_exhaustive_enum ( ty) && v_ctor. is_wildcard ( ) ;
849847 // For each constructor, we compute whether there's a value that starts with it that would
850848 // witness the usefulness of `v`.
851849 let start_matrix = & matrix;
@@ -866,50 +864,6 @@ fn is_useful<'p, 'tcx>(
866864 )
867865 } ) ;
868866 let usefulness = usefulness. apply_constructor ( pcx, start_matrix, & ctor) ;
869-
870- // When all the conditions are met we have a match with a `non_exhaustive` enum
871- // that has the potential to trigger the `non_exhaustive_omitted_patterns` lint.
872- // To understand the workings checkout `Constructor::split` and `SplitWildcard::new/into_ctors`
873- if is_non_exhaustive_and_wild
874- // Only emit a lint on refutable patterns.
875- && cx. refutable
876- // We check that the match has a wildcard pattern and that wildcard is useful,
877- // meaning there are variants that are covered by the wildcard. Without the check
878- // for `witness_preference` the lint would trigger on `if let NonExhaustiveEnum::A = foo {}`
879- && usefulness. is_useful ( ) && matches ! ( witness_preference, RealArm )
880- && matches ! (
881- & ctor,
882- Constructor :: Missing { nonexhaustive_enum_missing_visible_variants: true }
883- )
884- {
885- let missing = ConstructorSet :: for_ty ( pcx. cx , pcx. ty )
886- . compute_missing ( pcx, matrix. heads ( ) . map ( DeconstructedPat :: ctor) ) ;
887- // Construct for each missing constructor a "wild" version of this constructor, that
888- // matches everything that can be built with it. For example, if `ctor` is a
889- // `Constructor::Variant` for `Option::Some`, we get the pattern `Some(_)`.
890- let patterns = missing
891- . into_iter ( )
892- // Because of how we computed `nonexhaustive_enum_missing_visible_variants`,
893- // this will not return an empty `Vec`.
894- . filter ( |c| !( matches ! ( c, Constructor :: NonExhaustive | Constructor :: Hidden ) ) )
895- . map ( |missing_ctor| WitnessPat :: wild_from_ctor ( pcx, missing_ctor) )
896- . collect :: < Vec < _ > > ( ) ;
897-
898- // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
899- // is not exhaustive enough.
900- //
901- // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
902- cx. tcx . emit_spanned_lint (
903- NON_EXHAUSTIVE_OMITTED_PATTERNS ,
904- lint_root,
905- pcx. span ,
906- NonExhaustiveOmittedPattern {
907- scrut_ty : pcx. ty ,
908- uncovered : Uncovered :: new ( pcx. span , pcx. cx , patterns) ,
909- } ,
910- ) ;
911- }
912-
913867 ret. extend ( usefulness) ;
914868 }
915869 }
@@ -921,6 +875,74 @@ fn is_useful<'p, 'tcx>(
921875 ret
922876}
923877
878+ /// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned
879+ /// in a given column. This traverses patterns column-by-column, where a column is the intuitive
880+ /// notion of "subpatterns that inspect the same subvalue".
881+ /// Despite similarities with `is_useful`, this traversal is different. Notably this is linear in the
882+ /// depth of patterns, whereas `is_useful` is worst-case exponential (exhaustiveness is NP-complete).
883+ fn collect_nonexhaustive_missing_variants < ' p , ' tcx > (
884+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
885+ column : & [ & DeconstructedPat < ' p , ' tcx > ] ,
886+ ) -> Vec < WitnessPat < ' tcx > > {
887+ let ty = column[ 0 ] . ty ( ) ;
888+ let pcx = & PatCtxt { cx, ty, span : DUMMY_SP , is_top_level : false } ;
889+
890+ let mut witnesses = Vec :: new ( ) ;
891+
892+ let set = ConstructorSet :: for_ty ( pcx. cx , pcx. ty ) . split ( pcx, column. iter ( ) . map ( |p| p. ctor ( ) ) ) ;
893+ if cx. is_foreign_non_exhaustive_enum ( ty) {
894+ witnesses. extend (
895+ set. missing
896+ . into_iter ( )
897+ // This will list missing visible variants.
898+ . filter ( |c| !matches ! ( c, Constructor :: Hidden | Constructor :: NonExhaustive ) )
899+ . map ( |missing_ctor| WitnessPat :: wild_from_ctor ( pcx, missing_ctor) ) ,
900+ )
901+ }
902+
903+ // Recurse into the fields.
904+ for ctor in set. present {
905+ let arity = ctor. arity ( pcx) ;
906+ if arity == 0 {
907+ continue ;
908+ }
909+
910+ // We specialize the column by `ctor`. This gives us `arity`-many columns of patterns. These
911+ // columns may have different lengths in the presence of or-patterns (this is why we can't
912+ // reuse `Matrix`).
913+ let mut specialized_columns: Vec < Vec < _ > > = ( 0 ..arity) . map ( |_| Vec :: new ( ) ) . collect ( ) ;
914+ let relevant_patterns = column. iter ( ) . filter ( |pat| ctor. is_covered_by ( pcx, pat. ctor ( ) ) ) ;
915+ for pat in relevant_patterns {
916+ let specialized = pat. specialize ( pcx, & ctor) ;
917+ for ( subpat, sub_column) in specialized. iter ( ) . zip ( & mut specialized_columns) {
918+ if subpat. is_or_pat ( ) {
919+ sub_column. extend ( subpat. iter_fields ( ) )
920+ } else {
921+ sub_column. push ( subpat)
922+ }
923+ }
924+ }
925+ debug_assert ! (
926+ !specialized_columns[ 0 ] . is_empty( ) ,
927+ "ctor {ctor:?} was listed as present but isn't"
928+ ) ;
929+
930+ let wild_pat = WitnessPat :: wild_from_ctor ( pcx, ctor) ;
931+ for ( i, col_i) in specialized_columns. iter ( ) . enumerate ( ) {
932+ // Compute witnesses for each column.
933+ let wits_for_col_i = collect_nonexhaustive_missing_variants ( cx, col_i. as_slice ( ) ) ;
934+ // For each witness, we build a new pattern in the shape of `ctor(_, _, wit, _, _)`,
935+ // adding enough wildcards to match `arity`.
936+ for wit in wits_for_col_i {
937+ let mut pat = wild_pat. clone ( ) ;
938+ pat. fields [ i] = wit;
939+ witnesses. push ( pat) ;
940+ }
941+ }
942+ }
943+ witnesses
944+ }
945+
924946/// The arm of a match expression.
925947#[ derive( Clone , Copy , Debug ) ]
926948pub ( crate ) struct MatchArm < ' p , ' tcx > {
@@ -961,6 +983,7 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
961983 arms : & [ MatchArm < ' p , ' tcx > ] ,
962984 lint_root : HirId ,
963985 scrut_ty : Ty < ' tcx > ,
986+ scrut_span : Span ,
964987) -> UsefulnessReport < ' p , ' tcx > {
965988 let mut matrix = Matrix :: empty ( ) ;
966989 let arm_usefulness: Vec < _ > = arms
@@ -985,9 +1008,39 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
9851008 let wild_pattern = cx. pattern_arena . alloc ( DeconstructedPat :: wildcard ( scrut_ty, DUMMY_SP ) ) ;
9861009 let v = PatStack :: from_pattern ( wild_pattern) ;
9871010 let usefulness = is_useful ( cx, & matrix, & v, FakeExtraWildcard , lint_root, false , true ) ;
988- let non_exhaustiveness_witnesses = match usefulness {
1011+ let non_exhaustiveness_witnesses: Vec < _ > = match usefulness {
9891012 WithWitnesses ( pats) => pats. into_iter ( ) . map ( |w| w. single_pattern ( ) ) . collect ( ) ,
9901013 NoWitnesses { .. } => bug ! ( ) ,
9911014 } ;
1015+
1016+ // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
1017+ // `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
1018+ if cx. refutable
1019+ && non_exhaustiveness_witnesses. is_empty ( )
1020+ && !matches ! (
1021+ cx. tcx. lint_level_at_node( NON_EXHAUSTIVE_OMITTED_PATTERNS , lint_root) . 0 ,
1022+ rustc_session:: lint:: Level :: Allow
1023+ )
1024+ {
1025+ let pat_column = arms. iter ( ) . flat_map ( |arm| arm. pat . flatten_or_pat ( ) ) . collect :: < Vec < _ > > ( ) ;
1026+ let witnesses = collect_nonexhaustive_missing_variants ( cx, & pat_column) ;
1027+
1028+ if !witnesses. is_empty ( ) {
1029+ // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
1030+ // is not exhaustive enough.
1031+ //
1032+ // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
1033+ cx. tcx . emit_spanned_lint (
1034+ NON_EXHAUSTIVE_OMITTED_PATTERNS ,
1035+ lint_root,
1036+ scrut_span,
1037+ NonExhaustiveOmittedPattern {
1038+ scrut_ty,
1039+ uncovered : Uncovered :: new ( scrut_span, cx, witnesses) ,
1040+ } ,
1041+ ) ;
1042+ }
1043+ }
1044+
9921045 UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }
9931046}
0 commit comments