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,14 @@ use crate::traits::{
58
59
StatementAsExpression ,
59
60
} ;
60
61
62
+ use hir:: intravisit:: { walk_expr, walk_stmt} ;
61
63
use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
62
64
use rustc_errors:: { pluralize, struct_span_err, Diagnostic , ErrorGuaranteed , IntoDiagnosticArg } ;
63
65
use rustc_errors:: { Applicability , DiagnosticBuilder , DiagnosticStyledString , MultiSpan } ;
64
66
use rustc_hir as hir;
65
67
use rustc_hir:: def:: DefKind ;
66
68
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
69
+ use rustc_hir:: intravisit:: Visitor ;
67
70
use rustc_hir:: lang_items:: LangItem ;
68
71
use rustc_hir:: Node ;
69
72
use rustc_middle:: dep_graph:: DepContext ;
@@ -2333,6 +2336,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
2333
2336
}
2334
2337
}
2335
2338
}
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
+ }
2336
2344
_ => { }
2337
2345
}
2338
2346
}
@@ -2357,6 +2365,72 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
2357
2365
diag
2358
2366
}
2359
2367
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
+
2360
2434
fn emit_tuple_wrap_err (
2361
2435
& self ,
2362
2436
err : & mut Diagnostic ,
0 commit comments