@@ -12,6 +12,7 @@ use hir_expand::name;
12
12
use itertools:: Itertools ;
13
13
use rustc_hash:: FxHashSet ;
14
14
use rustc_pattern_analysis:: usefulness:: { compute_match_usefulness, ValidityConstraint } ;
15
+ use tracing:: debug;
15
16
use triomphe:: Arc ;
16
17
use typed_arena:: Arena ;
17
18
@@ -44,6 +45,10 @@ pub enum BodyValidationDiagnostic {
44
45
match_expr : ExprId ,
45
46
uncovered_patterns : String ,
46
47
} ,
48
+ NonExhaustiveLet {
49
+ pat : PatId ,
50
+ uncovered_patterns : String ,
51
+ } ,
47
52
RemoveTrailingReturn {
48
53
return_expr : ExprId ,
49
54
} ,
@@ -68,7 +73,7 @@ struct ExprValidator {
68
73
owner : DefWithBodyId ,
69
74
body : Arc < Body > ,
70
75
infer : Arc < InferenceResult > ,
71
- pub ( super ) diagnostics : Vec < BodyValidationDiagnostic > ,
76
+ diagnostics : Vec < BodyValidationDiagnostic > ,
72
77
}
73
78
74
79
impl ExprValidator {
@@ -105,6 +110,9 @@ impl ExprValidator {
105
110
Expr :: If { .. } => {
106
111
self . check_for_unnecessary_else ( id, expr, & body) ;
107
112
}
113
+ Expr :: Block { .. } => {
114
+ self . validate_block ( db, expr) ;
115
+ }
108
116
_ => { }
109
117
}
110
118
}
@@ -230,11 +238,52 @@ impl ExprValidator {
230
238
if !witnesses. is_empty ( ) {
231
239
self . diagnostics . push ( BodyValidationDiagnostic :: MissingMatchArms {
232
240
match_expr,
233
- uncovered_patterns : missing_match_arms ( & cx, scrut_ty, witnesses, arms ) ,
241
+ uncovered_patterns : missing_match_arms ( & cx, scrut_ty, witnesses, m_arms . is_empty ( ) ) ,
234
242
} ) ;
235
243
}
236
244
}
237
245
246
+ fn validate_block ( & mut self , db : & dyn HirDatabase , expr : & Expr ) {
247
+ let Expr :: Block { statements, .. } = expr else { return } ;
248
+ let pattern_arena = Arena :: new ( ) ;
249
+ let cx = MatchCheckCtx :: new ( self . owner . module ( db. upcast ( ) ) , self . owner , db, & pattern_arena) ;
250
+ for stmt in & * * statements {
251
+ let Statement :: Let { pat, initializer, else_branch : None , .. } = stmt else { continue } ;
252
+ let Some ( initializer) = initializer else { continue } ;
253
+ let ty = & self . infer [ * initializer] ;
254
+
255
+ let mut have_errors = false ;
256
+ let match_arm = rustc_pattern_analysis:: MatchArm {
257
+ pat : self . lower_pattern ( & cx, * pat, db, & mut have_errors) ,
258
+ has_guard : false ,
259
+ arm_data : ( ) ,
260
+ } ;
261
+ if have_errors {
262
+ continue ;
263
+ }
264
+
265
+ let report = match compute_match_usefulness (
266
+ & cx,
267
+ & [ match_arm] ,
268
+ ty. clone ( ) ,
269
+ ValidityConstraint :: ValidOnly ,
270
+ ) {
271
+ Ok ( v) => v,
272
+ Err ( e) => {
273
+ debug ! ( ?e, "match usefulness error" ) ;
274
+ continue ;
275
+ }
276
+ } ;
277
+ let witnesses = report. non_exhaustiveness_witnesses ;
278
+ if !witnesses. is_empty ( ) {
279
+ self . diagnostics . push ( BodyValidationDiagnostic :: NonExhaustiveLet {
280
+ pat : * pat,
281
+ uncovered_patterns : missing_match_arms ( & cx, ty, witnesses, false ) ,
282
+ } ) ;
283
+ }
284
+ }
285
+ }
286
+
238
287
fn lower_pattern < ' p > (
239
288
& self ,
240
289
cx : & MatchCheckCtx < ' p > ,
@@ -443,7 +492,7 @@ fn missing_match_arms<'p>(
443
492
cx : & MatchCheckCtx < ' p > ,
444
493
scrut_ty : & Ty ,
445
494
witnesses : Vec < WitnessPat < ' p > > ,
446
- arms : & [ MatchArm ] ,
495
+ arms_is_empty : bool ,
447
496
) -> String {
448
497
struct DisplayWitness < ' a , ' p > ( & ' a WitnessPat < ' p > , & ' a MatchCheckCtx < ' p > ) ;
449
498
impl fmt:: Display for DisplayWitness < ' _ , ' _ > {
@@ -458,7 +507,7 @@ fn missing_match_arms<'p>(
458
507
Some ( ( AdtId :: EnumId ( e) , _) ) => !cx. db . enum_data ( e) . variants . is_empty ( ) ,
459
508
_ => false ,
460
509
} ;
461
- if arms . is_empty ( ) && !non_empty_enum {
510
+ if arms_is_empty && !non_empty_enum {
462
511
format ! ( "type `{}` is non-empty" , scrut_ty. display( cx. db) )
463
512
} else {
464
513
let pat_display = |witness| DisplayWitness ( witness, cx) ;
0 commit comments