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,14 @@ use crate::traits::{
5859 StatementAsExpression ,
5960} ;
6061
62+ use hir:: intravisit:: { walk_expr, walk_stmt} ;
6163use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
6264use rustc_errors:: { pluralize, struct_span_err, Diagnostic , ErrorGuaranteed , IntoDiagnosticArg } ;
6365use rustc_errors:: { Applicability , DiagnosticBuilder , DiagnosticStyledString , MultiSpan } ;
6466use rustc_hir as hir;
6567use rustc_hir:: def:: DefKind ;
6668use rustc_hir:: def_id:: { DefId , LocalDefId } ;
69+ use rustc_hir:: intravisit:: Visitor ;
6770use rustc_hir:: lang_items:: LangItem ;
6871use rustc_hir:: Node ;
6972use rustc_middle:: dep_graph:: DepContext ;
@@ -2333,6 +2336,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23332336 }
23342337 }
23352338 }
2339+ // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
2340+ // we try to suggest to add the missing `let` for `if let Some(..) = expr`
2341+ ( ty:: Bool , ty:: Tuple ( list) ) => if list. len ( ) == 0 {
2342+ self . suggest_let_for_letchains ( & mut err, & trace. cause , span) ;
2343+ }
23362344 _ => { }
23372345 }
23382346 }
@@ -2357,6 +2365,72 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23572365 diag
23582366 }
23592367
2368+ /// Try to find code with pattern `if Some(..) = expr`
2369+ /// use a `visitor` to mark the `if` which its span contains given error span,
2370+ /// and then try to find a assignment in the `cond` part, which span is equal with error span
2371+ fn suggest_let_for_letchains (
2372+ & self ,
2373+ err : & mut Diagnostic ,
2374+ cause : & ObligationCause < ' _ > ,
2375+ span : Span ,
2376+ ) {
2377+ let hir = self . tcx . hir ( ) ;
2378+ let fn_hir_id = hir. get_parent_node ( cause. body_id ) ;
2379+ if let Some ( node) = self . tcx . hir ( ) . find ( fn_hir_id) &&
2380+ let hir:: Node :: Item ( hir:: Item {
2381+ kind : hir:: ItemKind :: Fn ( _sig, _, body_id) , ..
2382+ } ) = node {
2383+ let body = hir. body ( * body_id) ;
2384+
2385+ /// Find the if expression with given span
2386+ struct IfVisitor {
2387+ pub result : bool ,
2388+ pub found_if : bool ,
2389+ pub err_span : Span ,
2390+ }
2391+
2392+ impl < ' v > Visitor < ' v > for IfVisitor {
2393+ fn visit_expr ( & mut self , ex : & ' v hir:: Expr < ' v > ) {
2394+ if self . result { return ; }
2395+ match ex. kind {
2396+ hir:: ExprKind :: If ( cond, _, _) => {
2397+ self . found_if = true ;
2398+ walk_expr ( self , cond) ;
2399+ self . found_if = false ;
2400+ }
2401+ _ => walk_expr ( self , ex) ,
2402+ }
2403+ }
2404+
2405+ fn visit_stmt ( & mut self , ex : & ' v hir:: Stmt < ' v > ) {
2406+ if let hir:: StmtKind :: Local ( hir:: Local {
2407+ span, pat : hir:: Pat { ..} , ty : None , init : Some ( _) , ..
2408+ } ) = & ex. kind
2409+ && self . found_if
2410+ && span. eq ( & self . err_span ) {
2411+ self . result = true ;
2412+ }
2413+ walk_stmt ( self , ex) ;
2414+ }
2415+
2416+ fn visit_body ( & mut self , body : & ' v hir:: Body < ' v > ) {
2417+ hir:: intravisit:: walk_body ( self , body) ;
2418+ }
2419+ }
2420+
2421+ let mut visitor = IfVisitor { err_span : span, found_if : false , result : false } ;
2422+ visitor. visit_body ( & body) ;
2423+ if visitor. result {
2424+ err. span_suggestion_verbose (
2425+ span. shrink_to_lo ( ) ,
2426+ "consider adding `let`" ,
2427+ "let " . to_string ( ) ,
2428+ Applicability :: MachineApplicable ,
2429+ ) ;
2430+ }
2431+ }
2432+ }
2433+
23602434 fn emit_tuple_wrap_err (
23612435 & self ,
23622436 err : & mut Diagnostic ,
0 commit comments