1+ // ignore-tidy-filelength
12//! Error Reporting Code for the inference engine
23//!
34//! Because of the way inference, and in particular region inference,
@@ -64,8 +65,12 @@ use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, Mul
6465use rustc_hir as hir;
6566use rustc_hir:: def:: DefKind ;
6667use 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 ;
6771use rustc_hir:: lang_items:: LangItem ;
68- use rustc_hir:: Node ;
72+ use rustc_hir:: HirId ;
73+ use rustc_hir:: { Expr , Node } ;
6974use rustc_middle:: dep_graph:: DepContext ;
7075use rustc_middle:: ty:: print:: with_no_trimmed_paths;
7176use rustc_middle:: ty:: relate:: { self , RelateResult , TypeRelation } ;
@@ -620,12 +625,55 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
620625 }
621626 }
622627
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+
623670 fn note_error_origin (
624671 & self ,
625672 err : & mut Diagnostic ,
626673 cause : & ObligationCause < ' tcx > ,
627674 exp_found : Option < ty:: error:: ExpectedFound < Ty < ' tcx > > > ,
628675 terr : TypeError < ' tcx > ,
676+ detect_enum_noparm : bool ,
629677 ) {
630678 match * cause. code ( ) {
631679 ObligationCauseCode :: Pattern { origin_expr : true , span : Some ( span) , root_ty } => {
@@ -639,8 +687,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
639687 {
640688 err. span_label ( span, format ! ( "this is an iterator with items of type `{}`" , substs. type_at( 0 ) ) ) ;
641689 } 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+ }
644698 }
645699 if let Some ( ty:: error:: ExpectedFound { found, .. } ) = exp_found
646700 && ty. is_box ( ) && ty. boxed_ty ( ) == found
@@ -1489,6 +1543,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
14891543 terr : TypeError < ' tcx > ,
14901544 swap_secondary_and_primary : bool ,
14911545 prefer_label : bool ,
1546+ detect_enum_noparm : bool ,
14921547 ) {
14931548 let span = cause. span ( ) ;
14941549
@@ -1939,7 +1994,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
19391994
19401995 // It reads better to have the error origin as the final
19411996 // thing.
1942- self . note_error_origin ( diag, cause, exp_found, terr) ;
1997+ self . note_error_origin ( diag, cause, exp_found, terr, detect_enum_noparm ) ;
19431998
19441999 debug ! ( ?diag) ;
19452000 }
@@ -2259,6 +2314,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
22592314
22602315 let span = trace. cause . span ( ) ;
22612316 let failure_code = trace. cause . as_failure_code ( terr) ;
2317+ let mut detect_enum_noparm = false ;
22622318 let mut diag = match failure_code {
22632319 FailureCode :: Error0038 ( did) => {
22642320 let violations = self . tcx . object_safety_violations ( did) ;
@@ -2332,6 +2388,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23322388 }
23332389 }
23342390 }
2391+ ( ty:: FnDef ( _, _) , ty:: Adt ( adt_id, _) ) if adt_id. is_enum ( ) => {
2392+ detect_enum_noparm = true ;
2393+ }
23352394 _ => { }
23362395 }
23372396 }
@@ -2352,7 +2411,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23522411 struct_span_err ! ( self . tcx. sess, span, E0644 , "{}" , failure_str)
23532412 }
23542413 } ;
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+ ) ;
23562424 diag
23572425 }
23582426
0 commit comments