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,13 +625,55 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
620
625
_ => ( ) , // FIXME(#22750) handle traits and stuff
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
+ }
623
669
624
670
fn note_error_origin (
625
671
& self ,
626
672
err : & mut Diagnostic ,
627
673
cause : & ObligationCause < ' tcx > ,
628
674
exp_found : Option < ty:: error:: ExpectedFound < Ty < ' tcx > > > ,
629
675
terr : TypeError < ' tcx > ,
676
+ detect_enum_noparm : bool ,
630
677
) {
631
678
match * cause. code ( ) {
632
679
ObligationCauseCode :: Pattern { origin_expr : true , span : Some ( span) , root_ty } => {
@@ -640,8 +687,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
640
687
{
641
688
err. span_label ( span, format ! ( "this is an iterator with items of type `{}`" , substs. type_at( 0 ) ) ) ;
642
689
} else {
643
- err. span_label ( span, format ! ( "this expression has type `{}`" , ty) ) ;
644
- }
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
+ }
645
698
}
646
699
if let Some ( ty:: error:: ExpectedFound { found, .. } ) = exp_found
647
700
&& ty. is_box ( ) && ty. boxed_ty ( ) == found
@@ -1490,6 +1543,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
1490
1543
terr : TypeError < ' tcx > ,
1491
1544
swap_secondary_and_primary : bool ,
1492
1545
prefer_label : bool ,
1546
+ detect_enum_noparm : bool ,
1493
1547
) {
1494
1548
let span = cause. span ( ) ;
1495
1549
@@ -1940,7 +1994,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
1940
1994
1941
1995
// It reads better to have the error origin as the final
1942
1996
// thing.
1943
- self . note_error_origin ( diag, cause, exp_found, terr) ;
1997
+ self . note_error_origin ( diag, cause, exp_found, terr, detect_enum_noparm ) ;
1944
1998
1945
1999
debug ! ( ?diag) ;
1946
2000
}
@@ -2260,6 +2314,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
2260
2314
2261
2315
let span = trace. cause . span ( ) ;
2262
2316
let failure_code = trace. cause . as_failure_code ( terr) ;
2317
+ let mut detect_enum_noparm = false ;
2263
2318
let mut diag = match failure_code {
2264
2319
FailureCode :: Error0038 ( did) => {
2265
2320
let violations = self . tcx . object_safety_violations ( did) ;
@@ -2314,6 +2369,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
2314
2369
}
2315
2370
}
2316
2371
}
2372
+ ( ty:: FnDef ( _, _) , ty:: Adt ( adt_id, _) ) if adt_id. is_enum ( ) => {
2373
+ detect_enum_noparm = true ;
2374
+ }
2317
2375
_ => { }
2318
2376
}
2319
2377
}
@@ -2334,7 +2392,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
2334
2392
struct_span_err ! ( self . tcx. sess, span, E0644 , "{}" , failure_str)
2335
2393
}
2336
2394
} ;
2337
- self . note_type_err ( & mut diag, & trace. cause , None , Some ( trace. values ) , terr, false , false ) ;
2395
+ self . note_type_err (
2396
+ & mut diag,
2397
+ & trace. cause ,
2398
+ None ,
2399
+ Some ( trace. values ) ,
2400
+ terr,
2401
+ false ,
2402
+ false ,
2403
+ detect_enum_noparm,
2404
+ ) ;
2338
2405
diag
2339
2406
}
2340
2407
0 commit comments