@@ -11,6 +11,7 @@ use hir_def::{ItemContainerId, Lookup};
11
11
use hir_expand:: name;
12
12
use itertools:: Itertools ;
13
13
use rustc_hash:: FxHashSet ;
14
+ use rustc_pattern_analysis:: constructor:: Constructor ;
14
15
use syntax:: { ast, AstNode } ;
15
16
use tracing:: debug;
16
17
use triomphe:: Arc ;
@@ -190,45 +191,45 @@ impl ExprValidator {
190
191
let pattern_arena = Arena :: new ( ) ;
191
192
let mut m_arms = Vec :: with_capacity ( arms. len ( ) ) ;
192
193
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.
193
196
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 ;
225
230
}
226
231
}
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.
232
233
cov_mark:: hit!( validate_match_bailed_out) ;
233
234
return ;
234
235
}
@@ -266,15 +267,17 @@ impl ExprValidator {
266
267
267
268
let mut have_errors = false ;
268
269
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
+
269
276
let match_arm = rustc_pattern_analysis:: MatchArm {
270
277
pat : pattern_arena. alloc ( deconstructed_pat) ,
271
278
has_guard : false ,
272
279
arm_data : ( ) ,
273
280
} ;
274
- if have_errors {
275
- continue ;
276
- }
277
-
278
281
let report = match cx. compute_match_usefulness ( & [ match_arm] , ty. clone ( ) ) {
279
282
Ok ( v) => v,
280
283
Err ( e) => {
@@ -531,8 +534,16 @@ fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResul
531
534
fn walk ( pat : PatId , body : & Body , infer : & InferenceResult , has_type_mismatches : & mut bool ) {
532
535
match infer. type_mismatch_for_pat ( pat) {
533
536
Some ( _) => * has_type_mismatches = true ,
537
+ None if * has_type_mismatches => ( ) ,
534
538
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) )
536
547
}
537
548
}
538
549
}
0 commit comments