55use std:: fmt;
66
77use either:: Either ;
8+ use hir_def:: hir:: Statement ;
89use hir_def:: lang_item:: LangItem ;
910use hir_def:: { resolver:: HasResolver , AdtId , AssocItemId , DefWithBodyId , HasModule } ;
1011use hir_def:: { ItemContainerId , Lookup } ;
@@ -44,6 +45,10 @@ pub enum BodyValidationDiagnostic {
4445 match_expr : ExprId ,
4546 uncovered_patterns : String ,
4647 } ,
48+ NonExhaustiveLet {
49+ pat : PatId ,
50+ uncovered_patterns : String ,
51+ } ,
4752}
4853
4954impl BodyValidationDiagnostic {
@@ -59,7 +64,7 @@ impl BodyValidationDiagnostic {
5964struct ExprValidator {
6065 owner : DefWithBodyId ,
6166 infer : Arc < InferenceResult > ,
62- pub ( super ) diagnostics : Vec < BodyValidationDiagnostic > ,
67+ diagnostics : Vec < BodyValidationDiagnostic > ,
6368}
6469
6570impl ExprValidator {
@@ -89,6 +94,9 @@ impl ExprValidator {
8994 Expr :: Call { .. } | Expr :: MethodCall { .. } => {
9095 self . validate_call ( db, id, expr, & mut filter_map_next_checker) ;
9196 }
97+ Expr :: Block { .. } => {
98+ self . validate_block ( db, expr) ;
99+ }
92100 _ => { }
93101 }
94102 }
@@ -214,7 +222,7 @@ impl ExprValidator {
214222 if !witnesses. is_empty ( ) {
215223 self . diagnostics . push ( BodyValidationDiagnostic :: MissingMatchArms {
216224 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 ) ,
218226 } ) ;
219227 }
220228 }
@@ -235,6 +243,36 @@ impl ExprValidator {
235243 }
236244 pattern
237245 }
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+ }
238276}
239277
240278struct FilterMapNextChecker {
@@ -375,7 +413,7 @@ fn missing_match_arms<'p>(
375413 cx : & MatchCheckCtx < ' _ , ' p > ,
376414 scrut_ty : & Ty ,
377415 witnesses : Vec < DeconstructedPat < ' p > > ,
378- arms : & [ MatchArm ] ,
416+ arms : & [ match_check :: MatchArm < ' _ > ] ,
379417) -> String {
380418 struct DisplayWitness < ' a , ' p > ( & ' a DeconstructedPat < ' p > , & ' a MatchCheckCtx < ' a , ' p > ) ;
381419 impl fmt:: Display for DisplayWitness < ' _ , ' _ > {
0 commit comments