@@ -11,6 +11,7 @@ use hir_def::{ItemContainerId, Lookup};
1111use hir_expand:: name;
1212use itertools:: Itertools ;
1313use rustc_hash:: FxHashSet ;
14+ use rustc_pattern_analysis:: constructor:: Constructor ;
1415use syntax:: { ast, AstNode } ;
1516use tracing:: debug;
1617use triomphe:: Arc ;
@@ -190,45 +191,45 @@ impl ExprValidator {
190191 let pattern_arena = Arena :: new ( ) ;
191192 let mut m_arms = Vec :: with_capacity ( arms. len ( ) ) ;
192193 let mut has_lowering_errors = false ;
194+ // Note: Skipping the entire diagnostic rather than just not including a faulty match arm is
195+ // preferred to avoid the chance of false positives.
193196 for arm in arms {
194- if let Some ( pat_ty) = self . infer . type_of_pat . get ( arm. pat ) {
195- // We only include patterns whose type matches the type
196- // of the scrutinee expression. If we had an InvalidMatchArmPattern
197- // diagnostic or similar we could raise that in an else
198- // block here.
199- //
200- // When comparing the types, we also have to consider that rustc
201- // will automatically de-reference the scrutinee expression type if
202- // necessary.
203- //
204- // FIXME we should use the type checker for this.
205- if ( pat_ty == scrut_ty
206- || scrut_ty
207- . as_reference ( )
208- . map ( |( match_expr_ty, ..) | match_expr_ty == pat_ty)
209- . unwrap_or ( false ) )
210- && types_of_subpatterns_do_match ( arm. pat , & self . body , & self . infer )
211- {
212- // If we had a NotUsefulMatchArm diagnostic, we could
213- // check the usefulness of each pattern as we added it
214- // to the matrix here.
215- let pat = self . lower_pattern ( & cx, arm. pat , db, & mut has_lowering_errors) ;
216- let m_arm = pat_analysis:: MatchArm {
217- pat : pattern_arena. alloc ( pat) ,
218- has_guard : arm. guard . is_some ( ) ,
219- arm_data : ( ) ,
220- } ;
221- m_arms. push ( m_arm) ;
222- if !has_lowering_errors {
223- continue ;
224- }
197+ let Some ( pat_ty) = self . infer . type_of_pat . get ( arm. pat ) else {
198+ return ;
199+ } ;
200+
201+ // We only include patterns whose type matches the type
202+ // of the scrutinee expression. If we had an InvalidMatchArmPattern
203+ // diagnostic or similar we could raise that in an else
204+ // block here.
205+ //
206+ // When comparing the types, we also have to consider that rustc
207+ // will automatically de-reference the scrutinee expression type if
208+ // necessary.
209+ //
210+ // FIXME we should use the type checker for this.
211+ if ( pat_ty == scrut_ty
212+ || scrut_ty
213+ . as_reference ( )
214+ . map ( |( match_expr_ty, ..) | match_expr_ty == pat_ty)
215+ . unwrap_or ( false ) )
216+ && types_of_subpatterns_do_match ( arm. pat , & self . body , & self . infer )
217+ {
218+ // If we had a NotUsefulMatchArm diagnostic, we could
219+ // check the usefulness of each pattern as we added it
220+ // to the matrix here.
221+ let pat = self . lower_pattern ( & cx, arm. pat , db, & mut has_lowering_errors) ;
222+ let m_arm = pat_analysis:: MatchArm {
223+ pat : pattern_arena. alloc ( pat) ,
224+ has_guard : arm. guard . is_some ( ) ,
225+ arm_data : ( ) ,
226+ } ;
227+ m_arms. push ( m_arm) ;
228+ if !has_lowering_errors {
229+ continue ;
225230 }
226231 }
227-
228- // If we can't resolve the type of a pattern, or the pattern type doesn't
229- // fit the match expression, we skip this diagnostic. Skipping the entire
230- // diagnostic rather than just not including this match arm is preferred
231- // to avoid the chance of false positives.
232+ // If the pattern type doesn't fit the match expression, we skip this diagnostic.
232233 cov_mark:: hit!( validate_match_bailed_out) ;
233234 return ;
234235 }
@@ -266,15 +267,17 @@ impl ExprValidator {
266267
267268 let mut have_errors = false ;
268269 let deconstructed_pat = self . lower_pattern ( & cx, pat, db, & mut have_errors) ;
270+
271+ // optimization, wildcard trivially hold
272+ if have_errors || matches ! ( deconstructed_pat. ctor( ) , Constructor :: Wildcard ) {
273+ continue ;
274+ }
275+
269276 let match_arm = rustc_pattern_analysis:: MatchArm {
270277 pat : pattern_arena. alloc ( deconstructed_pat) ,
271278 has_guard : false ,
272279 arm_data : ( ) ,
273280 } ;
274- if have_errors {
275- continue ;
276- }
277-
278281 let report = match cx. compute_match_usefulness ( & [ match_arm] , ty. clone ( ) ) {
279282 Ok ( v) => v,
280283 Err ( e) => {
@@ -531,8 +534,16 @@ fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResul
531534 fn walk ( pat : PatId , body : & Body , infer : & InferenceResult , has_type_mismatches : & mut bool ) {
532535 match infer. type_mismatch_for_pat ( pat) {
533536 Some ( _) => * has_type_mismatches = true ,
537+ None if * has_type_mismatches => ( ) ,
534538 None => {
535- body[ pat] . walk_child_pats ( |subpat| walk ( subpat, body, infer, has_type_mismatches) )
539+ let pat = & body[ pat] ;
540+ if let Pat :: ConstBlock ( expr) | Pat :: Lit ( expr) = * pat {
541+ * has_type_mismatches |= infer. type_mismatch_for_expr ( expr) . is_some ( ) ;
542+ if * has_type_mismatches {
543+ return ;
544+ }
545+ }
546+ pat. walk_child_pats ( |subpat| walk ( subpat, body, infer, has_type_mismatches) )
536547 }
537548 }
538549 }
0 commit comments