1+ // ignore-tidy-filelength
12//! Error Reporting Code for the inference engine
23//!
34//! Because of the way inference, and in particular region inference,
@@ -58,12 +59,15 @@ use crate::traits::{
5859 StatementAsExpression ,
5960} ;
6061
62+ use crate :: errors:: SuggAddLetForLetChains ;
63+ use hir:: intravisit:: { walk_expr, walk_stmt} ;
6164use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
6265use rustc_errors:: { pluralize, struct_span_err, Diagnostic , ErrorGuaranteed , IntoDiagnosticArg } ;
6366use rustc_errors:: { Applicability , DiagnosticBuilder , DiagnosticStyledString , MultiSpan } ;
6467use rustc_hir as hir;
6568use rustc_hir:: def:: DefKind ;
6669use rustc_hir:: def_id:: { DefId , LocalDefId } ;
70+ use rustc_hir:: intravisit:: Visitor ;
6771use rustc_hir:: lang_items:: LangItem ;
6872use rustc_hir:: Node ;
6973use rustc_middle:: dep_graph:: DepContext ;
@@ -2333,6 +2337,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23332337 }
23342338 }
23352339 }
2340+ // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
2341+ // we try to suggest to add the missing `let` for `if let Some(..) = expr`
2342+ ( ty:: Bool , ty:: Tuple ( list) ) => if list. len ( ) == 0 {
2343+ self . suggest_let_for_letchains ( & mut err, & trace. cause , span) ;
2344+ }
23362345 _ => { }
23372346 }
23382347 }
@@ -2357,6 +2366,67 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23572366 diag
23582367 }
23592368
2369+ /// Try to find code with pattern `if Some(..) = expr`
2370+ /// use a `visitor` to mark the `if` which its span contains given error span,
2371+ /// and then try to find a assignment in the `cond` part, which span is equal with error span
2372+ fn suggest_let_for_letchains (
2373+ & self ,
2374+ err : & mut Diagnostic ,
2375+ cause : & ObligationCause < ' _ > ,
2376+ span : Span ,
2377+ ) {
2378+ let hir = self . tcx . hir ( ) ;
2379+ let fn_hir_id = hir. get_parent_node ( cause. body_id ) ;
2380+ if let Some ( node) = self . tcx . hir ( ) . find ( fn_hir_id) &&
2381+ let hir:: Node :: Item ( hir:: Item {
2382+ kind : hir:: ItemKind :: Fn ( _sig, _, body_id) , ..
2383+ } ) = node {
2384+ let body = hir. body ( * body_id) ;
2385+
2386+ /// Find the if expression with given span
2387+ struct IfVisitor {
2388+ pub result : bool ,
2389+ pub found_if : bool ,
2390+ pub err_span : Span ,
2391+ }
2392+
2393+ impl < ' v > Visitor < ' v > for IfVisitor {
2394+ fn visit_expr ( & mut self , ex : & ' v hir:: Expr < ' v > ) {
2395+ if self . result { return ; }
2396+ match ex. kind {
2397+ hir:: ExprKind :: If ( cond, _, _) => {
2398+ self . found_if = true ;
2399+ walk_expr ( self , cond) ;
2400+ self . found_if = false ;
2401+ }
2402+ _ => walk_expr ( self , ex) ,
2403+ }
2404+ }
2405+
2406+ fn visit_stmt ( & mut self , ex : & ' v hir:: Stmt < ' v > ) {
2407+ if let hir:: StmtKind :: Local ( hir:: Local {
2408+ span, pat : hir:: Pat { ..} , ty : None , init : Some ( _) , ..
2409+ } ) = & ex. kind
2410+ && self . found_if
2411+ && span. eq ( & self . err_span ) {
2412+ self . result = true ;
2413+ }
2414+ walk_stmt ( self , ex) ;
2415+ }
2416+
2417+ fn visit_body ( & mut self , body : & ' v hir:: Body < ' v > ) {
2418+ hir:: intravisit:: walk_body ( self , body) ;
2419+ }
2420+ }
2421+
2422+ let mut visitor = IfVisitor { err_span : span, found_if : false , result : false } ;
2423+ visitor. visit_body ( & body) ;
2424+ if visitor. result {
2425+ err. subdiagnostic ( SuggAddLetForLetChains { span : span. shrink_to_lo ( ) } ) ;
2426+ }
2427+ }
2428+ }
2429+
23602430 fn emit_tuple_wrap_err (
23612431 & self ,
23622432 err : & mut Diagnostic ,
0 commit comments