@@ -12,6 +12,7 @@ use hir_expand::name;
1212use itertools:: Itertools ;
1313use rustc_hash:: FxHashSet ;
1414use rustc_pattern_analysis:: usefulness:: { compute_match_usefulness, ValidityConstraint } ;
15+ use tracing:: debug;
1516use triomphe:: Arc ;
1617use typed_arena:: Arena ;
1718
@@ -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 RemoveTrailingReturn {
4853 return_expr : ExprId ,
4954 } ,
@@ -68,7 +73,7 @@ struct ExprValidator {
6873 owner : DefWithBodyId ,
6974 body : Arc < Body > ,
7075 infer : Arc < InferenceResult > ,
71- pub ( super ) diagnostics : Vec < BodyValidationDiagnostic > ,
76+ diagnostics : Vec < BodyValidationDiagnostic > ,
7277}
7378
7479impl ExprValidator {
@@ -105,6 +110,9 @@ impl ExprValidator {
105110 Expr :: If { .. } => {
106111 self . check_for_unnecessary_else ( id, expr, & body) ;
107112 }
113+ Expr :: Block { .. } => {
114+ self . validate_block ( db, expr) ;
115+ }
108116 _ => { }
109117 }
110118 }
@@ -231,11 +239,55 @@ impl ExprValidator {
231239 if !witnesses. is_empty ( ) {
232240 self . diagnostics . push ( BodyValidationDiagnostic :: MissingMatchArms {
233241 match_expr,
234- uncovered_patterns : missing_match_arms ( & cx, scrut_ty, witnesses, arms ) ,
242+ uncovered_patterns : missing_match_arms ( & cx, scrut_ty, witnesses, m_arms . is_empty ( ) ) ,
235243 } ) ;
236244 }
237245 }
238246
247+ fn validate_block ( & mut self , db : & dyn HirDatabase , expr : & Expr ) {
248+ let Expr :: Block { statements, .. } = expr else { return } ;
249+ let pattern_arena = Arena :: new ( ) ;
250+ let cx = MatchCheckCtx :: new ( self . owner . module ( db. upcast ( ) ) , self . owner , db) ;
251+ for stmt in & * * statements {
252+ let & Statement :: Let { pat, initializer, else_branch : None , .. } = stmt else {
253+ continue ;
254+ } ;
255+ let Some ( initializer) = initializer else { continue } ;
256+ let ty = & self . infer [ initializer] ;
257+
258+ let mut have_errors = false ;
259+ let deconstructed_pat = self . lower_pattern ( & cx, pat, db, & mut have_errors) ;
260+ let match_arm = rustc_pattern_analysis:: MatchArm {
261+ pat : pattern_arena. alloc ( deconstructed_pat) ,
262+ has_guard : false ,
263+ arm_data : ( ) ,
264+ } ;
265+ if have_errors {
266+ continue ;
267+ }
268+
269+ let report = match compute_match_usefulness (
270+ & cx,
271+ & [ match_arm] ,
272+ ty. clone ( ) ,
273+ ValidityConstraint :: ValidOnly ,
274+ ) {
275+ Ok ( v) => v,
276+ Err ( e) => {
277+ debug ! ( ?e, "match usefulness error" ) ;
278+ continue ;
279+ }
280+ } ;
281+ let witnesses = report. non_exhaustiveness_witnesses ;
282+ if !witnesses. is_empty ( ) {
283+ self . diagnostics . push ( BodyValidationDiagnostic :: NonExhaustiveLet {
284+ pat,
285+ uncovered_patterns : missing_match_arms ( & cx, ty, witnesses, false ) ,
286+ } ) ;
287+ }
288+ }
289+ }
290+
239291 fn lower_pattern < ' p > (
240292 & self ,
241293 cx : & MatchCheckCtx < ' p > ,
@@ -444,7 +496,7 @@ fn missing_match_arms<'p>(
444496 cx : & MatchCheckCtx < ' p > ,
445497 scrut_ty : & Ty ,
446498 witnesses : Vec < WitnessPat < ' p > > ,
447- arms : & [ MatchArm ] ,
499+ arms_is_empty : bool ,
448500) -> String {
449501 struct DisplayWitness < ' a , ' p > ( & ' a WitnessPat < ' p > , & ' a MatchCheckCtx < ' p > ) ;
450502 impl fmt:: Display for DisplayWitness < ' _ , ' _ > {
@@ -459,7 +511,7 @@ fn missing_match_arms<'p>(
459511 Some ( ( AdtId :: EnumId ( e) , _) ) => !cx. db . enum_data ( e) . variants . is_empty ( ) ,
460512 _ => false ,
461513 } ;
462- if arms . is_empty ( ) && !non_empty_enum {
514+ if arms_is_empty && !non_empty_enum {
463515 format ! ( "type `{}` is non-empty" , scrut_ty. display( cx. db) )
464516 } else {
465517 let pat_display = |witness| DisplayWitness ( witness, cx) ;
0 commit comments