1
+ // ignore-tidy-filelength
1
2
//! Error Reporting Code for the inference engine
2
3
//!
3
4
//! Because of the way inference, and in particular region inference,
@@ -58,12 +59,15 @@ use crate::traits::{
58
59
StatementAsExpression ,
59
60
} ;
60
61
62
+ use crate :: errors:: SuggAddLetForLetChains ;
63
+ use hir:: intravisit:: { walk_expr, walk_stmt} ;
61
64
use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
62
65
use rustc_errors:: { pluralize, struct_span_err, Diagnostic , ErrorGuaranteed , IntoDiagnosticArg } ;
63
66
use rustc_errors:: { Applicability , DiagnosticBuilder , DiagnosticStyledString , MultiSpan } ;
64
67
use rustc_hir as hir;
65
68
use rustc_hir:: def:: DefKind ;
66
69
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
70
+ use rustc_hir:: intravisit:: Visitor ;
67
71
use rustc_hir:: lang_items:: LangItem ;
68
72
use rustc_hir:: Node ;
69
73
use rustc_middle:: dep_graph:: DepContext ;
@@ -2336,6 +2340,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
2336
2340
}
2337
2341
}
2338
2342
}
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
+ }
2339
2348
_ => { }
2340
2349
}
2341
2350
}
@@ -2360,6 +2369,67 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
2360
2369
diag
2361
2370
}
2362
2371
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
+
2363
2433
fn emit_tuple_wrap_err (
2364
2434
& self ,
2365
2435
err : & mut Diagnostic ,
0 commit comments