5
5
use std:: fmt;
6
6
7
7
use either:: Either ;
8
+ use hir_def:: hir:: Statement ;
8
9
use hir_def:: lang_item:: LangItem ;
9
10
use hir_def:: { resolver:: HasResolver , AdtId , AssocItemId , DefWithBodyId , HasModule } ;
10
11
use hir_def:: { ItemContainerId , Lookup } ;
@@ -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
}
48
53
49
54
impl BodyValidationDiagnostic {
@@ -61,7 +66,7 @@ struct ExprValidator {
61
66
owner : DefWithBodyId ,
62
67
body : Arc < Body > ,
63
68
infer : Arc < InferenceResult > ,
64
- pub ( super ) diagnostics : Vec < BodyValidationDiagnostic > ,
69
+ diagnostics : Vec < BodyValidationDiagnostic > ,
65
70
}
66
71
67
72
impl ExprValidator {
@@ -88,6 +93,9 @@ impl ExprValidator {
88
93
Expr :: Call { .. } | Expr :: MethodCall { .. } => {
89
94
self . validate_call ( db, id, expr, & mut filter_map_next_checker) ;
90
95
}
96
+ Expr :: Block { .. } => {
97
+ self . validate_block ( db, expr) ;
98
+ }
91
99
_ => { }
92
100
}
93
101
}
@@ -211,7 +219,7 @@ impl ExprValidator {
211
219
if !witnesses. is_empty ( ) {
212
220
self . diagnostics . push ( BodyValidationDiagnostic :: MissingMatchArms {
213
221
match_expr,
214
- uncovered_patterns : missing_match_arms ( & cx, scrut_ty, witnesses, arms ) ,
222
+ uncovered_patterns : missing_match_arms ( & cx, scrut_ty, witnesses, & m_arms ) ,
215
223
} ) ;
216
224
}
217
225
}
@@ -231,6 +239,35 @@ impl ExprValidator {
231
239
}
232
240
pattern
233
241
}
242
+
243
+ fn validate_block ( & mut self , db : & dyn HirDatabase , expr : & Expr ) {
244
+ let Expr :: Block { statements, .. } = expr else { return } ;
245
+ let pattern_arena = Arena :: new ( ) ;
246
+ let cx = MatchCheckCtx :: new ( self . owner . module ( db. upcast ( ) ) , self . owner , db, & pattern_arena) ;
247
+ for stmt in & * * statements {
248
+ let Statement :: Let { pat, initializer, else_branch : None , .. } = stmt else { continue } ;
249
+ let Some ( initializer) = initializer else { continue } ;
250
+ let init_ty = & self . infer [ * initializer] ;
251
+
252
+ let mut have_errors = false ;
253
+ let match_arm = match_check:: MatchArm {
254
+ pat : self . lower_pattern ( & cx, * pat, db, & mut have_errors) ,
255
+ has_guard : false ,
256
+ } ;
257
+ if have_errors {
258
+ continue ;
259
+ }
260
+
261
+ let report = compute_match_usefulness ( & cx, & [ match_arm] , init_ty) ;
262
+ let witnesses = report. non_exhaustiveness_witnesses ;
263
+ if !witnesses. is_empty ( ) {
264
+ self . diagnostics . push ( BodyValidationDiagnostic :: NonExhaustiveLet {
265
+ pat : * pat,
266
+ uncovered_patterns : missing_match_arms ( & cx, init_ty, witnesses, & [ match_arm] ) ,
267
+ } ) ;
268
+ }
269
+ }
270
+ }
234
271
}
235
272
236
273
struct FilterMapNextChecker {
@@ -371,7 +408,7 @@ fn missing_match_arms<'p>(
371
408
cx : & MatchCheckCtx < ' _ , ' p > ,
372
409
scrut_ty : & Ty ,
373
410
witnesses : Vec < DeconstructedPat < ' p > > ,
374
- arms : & [ MatchArm ] ,
411
+ arms : & [ match_check :: MatchArm < ' _ > ] ,
375
412
) -> String {
376
413
struct DisplayWitness < ' a , ' p > ( & ' a DeconstructedPat < ' p > , & ' a MatchCheckCtx < ' a , ' p > ) ;
377
414
impl fmt:: Display for DisplayWitness < ' _ , ' _ > {
0 commit comments