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 ;
@@ -2336,6 +2340,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23362340 }
23372341 }
23382342 }
2343+ // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
2344+ // we try to suggest to add the missing `let` for `if let Some(..) = expr`
2345+ ( ty:: Bool , ty:: Tuple ( list) ) => if list. len ( ) == 0 {
2346+ self . suggest_let_for_letchains ( & mut err, & trace. cause , span) ;
2347+ }
23392348 _ => { }
23402349 }
23412350 }
@@ -2360,6 +2369,67 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23602369 diag
23612370 }
23622371
2372+ /// Try to find code with pattern `if Some(..) = expr`
2373+ /// use a `visitor` to mark the `if` which its span contains given error span,
2374+ /// and then try to find a assignment in the `cond` part, which span is equal with error span
2375+ fn suggest_let_for_letchains (
2376+ & self ,
2377+ err : & mut Diagnostic ,
2378+ cause : & ObligationCause < ' _ > ,
2379+ span : Span ,
2380+ ) {
2381+ let hir = self . tcx . hir ( ) ;
2382+ let fn_hir_id = hir. get_parent_node ( cause. body_id ) ;
2383+ if let Some ( node) = self . tcx . hir ( ) . find ( fn_hir_id) &&
2384+ let hir:: Node :: Item ( hir:: Item {
2385+ kind : hir:: ItemKind :: Fn ( _sig, _, body_id) , ..
2386+ } ) = node {
2387+ let body = hir. body ( * body_id) ;
2388+
2389+ /// Find the if expression with given span
2390+ struct IfVisitor {
2391+ pub result : bool ,
2392+ pub found_if : bool ,
2393+ pub err_span : Span ,
2394+ }
2395+
2396+ impl < ' v > Visitor < ' v > for IfVisitor {
2397+ fn visit_expr ( & mut self , ex : & ' v hir:: Expr < ' v > ) {
2398+ if self . result { return ; }
2399+ match ex. kind {
2400+ hir:: ExprKind :: If ( cond, _, _) => {
2401+ self . found_if = true ;
2402+ walk_expr ( self , cond) ;
2403+ self . found_if = false ;
2404+ }
2405+ _ => walk_expr ( self , ex) ,
2406+ }
2407+ }
2408+
2409+ fn visit_stmt ( & mut self , ex : & ' v hir:: Stmt < ' v > ) {
2410+ if let hir:: StmtKind :: Local ( hir:: Local {
2411+ span, pat : hir:: Pat { ..} , ty : None , init : Some ( _) , ..
2412+ } ) = & ex. kind
2413+ && self . found_if
2414+ && span. eq ( & self . err_span ) {
2415+ self . result = true ;
2416+ }
2417+ walk_stmt ( self , ex) ;
2418+ }
2419+
2420+ fn visit_body ( & mut self , body : & ' v hir:: Body < ' v > ) {
2421+ hir:: intravisit:: walk_body ( self , body) ;
2422+ }
2423+ }
2424+
2425+ let mut visitor = IfVisitor { err_span : span, found_if : false , result : false } ;
2426+ visitor. visit_body ( & body) ;
2427+ if visitor. result {
2428+ err. subdiagnostic ( SuggAddLetForLetChains { span : span. shrink_to_lo ( ) } ) ;
2429+ }
2430+ }
2431+ }
2432+
23632433 fn emit_tuple_wrap_err (
23642434 & self ,
23652435 err : & mut Diagnostic ,
0 commit comments