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,
@@ -64,8 +65,12 @@ use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, Mul
64
65
use rustc_hir as hir;
65
66
use rustc_hir:: def:: DefKind ;
66
67
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
68
+ use rustc_hir:: intravisit:: walk_block;
69
+ use rustc_hir:: intravisit:: walk_expr;
70
+ use rustc_hir:: intravisit:: Visitor ;
67
71
use rustc_hir:: lang_items:: LangItem ;
68
- use rustc_hir:: Node ;
72
+ use rustc_hir:: HirId ;
73
+ use rustc_hir:: { Expr , Node } ;
69
74
use rustc_middle:: dep_graph:: DepContext ;
70
75
use rustc_middle:: ty:: print:: with_no_trimmed_paths;
71
76
use rustc_middle:: ty:: relate:: { self , RelateResult , TypeRelation } ;
@@ -620,12 +625,55 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
620
625
}
621
626
}
622
627
628
+ fn note_enum_suggestion (
629
+ & self ,
630
+ err : & mut Diagnostic ,
631
+ span : Span ,
632
+ body_id : HirId ,
633
+ arg_size : usize ,
634
+ ) {
635
+ let body_node = self . tcx . hir ( ) . get ( body_id) ;
636
+ let hir:: Node :: Expr ( & hir:: Expr { kind : hir:: ExprKind :: Block ( body_expr, ..) , ..} ) = body_node else { return ( ) } ;
637
+ struct FindExprVisitor < ' tcx > {
638
+ target_span : Span ,
639
+ size : usize ,
640
+ terr : & ' tcx mut Diagnostic ,
641
+ }
642
+ impl < ' tcx > Visitor < ' tcx > for FindExprVisitor < ' tcx > {
643
+ fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
644
+ if expr. span == self . target_span {
645
+ let mut suggest_vec = vec ! [ ] ;
646
+ let mut i = 0 ;
647
+ suggest_vec. push ( ( expr. span . shrink_to_hi ( ) , "(" . to_string ( ) ) ) ;
648
+ while i < self . size {
649
+ suggest_vec. push ( ( expr. span . shrink_to_hi ( ) , "_" . to_string ( ) ) ) ;
650
+ if i != self . size - 1 {
651
+ suggest_vec. push ( ( expr. span . shrink_to_hi ( ) , "," . to_string ( ) ) ) ;
652
+ }
653
+ i = i + 1 ;
654
+ }
655
+ suggest_vec. push ( ( expr. span . shrink_to_hi ( ) , ")" . to_string ( ) ) ) ;
656
+
657
+ self . terr . multipart_suggestion (
658
+ "use parentheses to instantiate this tuple variant" ,
659
+ suggest_vec,
660
+ Applicability :: MachineApplicable ,
661
+ ) ;
662
+ }
663
+ walk_expr ( self , expr) ;
664
+ }
665
+ }
666
+ let mut visitor = FindExprVisitor { target_span : span, size : arg_size, terr : err } ;
667
+ walk_block ( & mut visitor, body_expr) ;
668
+ }
669
+
623
670
fn note_error_origin (
624
671
& self ,
625
672
err : & mut Diagnostic ,
626
673
cause : & ObligationCause < ' tcx > ,
627
674
exp_found : Option < ty:: error:: ExpectedFound < Ty < ' tcx > > > ,
628
675
terr : TypeError < ' tcx > ,
676
+ detect_enum_noparm : bool ,
629
677
) {
630
678
match * cause. code ( ) {
631
679
ObligationCauseCode :: Pattern { origin_expr : true , span : Some ( span) , root_ty } => {
@@ -639,8 +687,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
639
687
{
640
688
err. span_label ( span, format ! ( "this is an iterator with items of type `{}`" , substs. type_at( 0 ) ) ) ;
641
689
} else {
642
- err. span_label ( span, format ! ( "this expression has type `{}`" , ty) ) ;
643
- }
690
+ err. span_label ( span, format ! ( "this expression has type `{}`" , ty) ) ;
691
+ if detect_enum_noparm &&
692
+ let ty:: FnDef ( def_id, substs) = ty. kind ( ) {
693
+ let sig = self . tcx . bound_fn_sig ( * def_id) . subst ( self . tcx , substs) ;
694
+ let sig = self . tcx . erase_late_bound_regions ( sig) ;
695
+ self . note_enum_suggestion ( err, span, cause. body_id , sig. inputs ( ) . len ( ) ) ;
696
+ }
697
+ }
644
698
}
645
699
if let Some ( ty:: error:: ExpectedFound { found, .. } ) = exp_found
646
700
&& ty. is_box ( ) && ty. boxed_ty ( ) == found
@@ -1489,6 +1543,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
1489
1543
terr : TypeError < ' tcx > ,
1490
1544
swap_secondary_and_primary : bool ,
1491
1545
prefer_label : bool ,
1546
+ detect_enum_noparm : bool ,
1492
1547
) {
1493
1548
let span = cause. span ( ) ;
1494
1549
@@ -1939,7 +1994,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
1939
1994
1940
1995
// It reads better to have the error origin as the final
1941
1996
// thing.
1942
- self . note_error_origin ( diag, cause, exp_found, terr) ;
1997
+ self . note_error_origin ( diag, cause, exp_found, terr, detect_enum_noparm ) ;
1943
1998
1944
1999
debug ! ( ?diag) ;
1945
2000
}
@@ -2259,6 +2314,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
2259
2314
2260
2315
let span = trace. cause . span ( ) ;
2261
2316
let failure_code = trace. cause . as_failure_code ( terr) ;
2317
+ let mut detect_enum_noparm = false ;
2262
2318
let mut diag = match failure_code {
2263
2319
FailureCode :: Error0038 ( did) => {
2264
2320
let violations = self . tcx . object_safety_violations ( did) ;
@@ -2332,6 +2388,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
2332
2388
}
2333
2389
}
2334
2390
}
2391
+ ( ty:: FnDef ( _, _) , ty:: Adt ( adt_id, _) ) if adt_id. is_enum ( ) => {
2392
+ detect_enum_noparm = true ;
2393
+ }
2335
2394
_ => { }
2336
2395
}
2337
2396
}
@@ -2352,7 +2411,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
2352
2411
struct_span_err ! ( self . tcx. sess, span, E0644 , "{}" , failure_str)
2353
2412
}
2354
2413
} ;
2355
- self . note_type_err ( & mut diag, & trace. cause , None , Some ( trace. values ) , terr, false , false ) ;
2414
+ self . note_type_err (
2415
+ & mut diag,
2416
+ & trace. cause ,
2417
+ None ,
2418
+ Some ( trace. values ) ,
2419
+ terr,
2420
+ false ,
2421
+ false ,
2422
+ detect_enum_noparm,
2423
+ ) ;
2356
2424
diag
2357
2425
}
2358
2426
0 commit comments