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 {
@@ -59,7 +64,7 @@ impl BodyValidationDiagnostic {
59
64
struct ExprValidator {
60
65
owner : DefWithBodyId ,
61
66
infer : Arc < InferenceResult > ,
62
- pub ( super ) diagnostics : Vec < BodyValidationDiagnostic > ,
67
+ diagnostics : Vec < BodyValidationDiagnostic > ,
63
68
}
64
69
65
70
impl ExprValidator {
@@ -89,6 +94,9 @@ impl ExprValidator {
89
94
Expr :: Call { .. } | Expr :: MethodCall { .. } => {
90
95
self . validate_call ( db, id, expr, & mut filter_map_next_checker) ;
91
96
}
97
+ Expr :: Block { .. } => {
98
+ self . validate_block ( db, expr) ;
99
+ }
92
100
_ => { }
93
101
}
94
102
}
@@ -214,7 +222,7 @@ impl ExprValidator {
214
222
if !witnesses. is_empty ( ) {
215
223
self . diagnostics . push ( BodyValidationDiagnostic :: MissingMatchArms {
216
224
match_expr,
217
- uncovered_patterns : missing_match_arms ( & cx, scrut_ty, witnesses, arms ) ,
225
+ uncovered_patterns : missing_match_arms ( & cx, scrut_ty, witnesses, & m_arms ) ,
218
226
} ) ;
219
227
}
220
228
}
@@ -235,6 +243,36 @@ impl ExprValidator {
235
243
}
236
244
pattern
237
245
}
246
+
247
+ fn validate_block ( & mut self , db : & dyn HirDatabase , expr : & Expr ) {
248
+ let Expr :: Block { statements, .. } = expr else { return } ;
249
+ let body = db. body ( self . owner ) ;
250
+ let pattern_arena = Arena :: new ( ) ;
251
+ let cx = MatchCheckCtx :: new ( self . owner . module ( db. upcast ( ) ) , self . owner , db, & pattern_arena) ;
252
+ for stmt in & * * statements {
253
+ let Statement :: Let { pat, initializer, else_branch : None , .. } = stmt else { continue } ;
254
+ let Some ( initializer) = initializer else { continue } ;
255
+ let init_ty = & self . infer [ * initializer] ;
256
+
257
+ let mut have_errors = false ;
258
+ let match_arm = match_check:: MatchArm {
259
+ pat : self . lower_pattern ( & cx, * pat, db, & body, & mut have_errors) ,
260
+ has_guard : false ,
261
+ } ;
262
+ if have_errors {
263
+ continue ;
264
+ }
265
+
266
+ let report = compute_match_usefulness ( & cx, & [ match_arm] , init_ty) ;
267
+ let witnesses = report. non_exhaustiveness_witnesses ;
268
+ if !witnesses. is_empty ( ) {
269
+ self . diagnostics . push ( BodyValidationDiagnostic :: NonExhaustiveLet {
270
+ pat : * pat,
271
+ uncovered_patterns : missing_match_arms ( & cx, init_ty, witnesses, & [ match_arm] ) ,
272
+ } ) ;
273
+ }
274
+ }
275
+ }
238
276
}
239
277
240
278
struct FilterMapNextChecker {
@@ -375,7 +413,7 @@ fn missing_match_arms<'p>(
375
413
cx : & MatchCheckCtx < ' _ , ' p > ,
376
414
scrut_ty : & Ty ,
377
415
witnesses : Vec < DeconstructedPat < ' p > > ,
378
- arms : & [ MatchArm ] ,
416
+ arms : & [ match_check :: MatchArm < ' _ > ] ,
379
417
) -> String {
380
418
struct DisplayWitness < ' a , ' p > ( & ' a DeconstructedPat < ' p > , & ' a MatchCheckCtx < ' a , ' p > ) ;
381
419
impl fmt:: Display for DisplayWitness < ' _ , ' _ > {
0 commit comments