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,13 +625,55 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
620625 _ => ( ) , // FIXME(#22750) handle traits and stuff
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+ }
623669
624670 fn note_error_origin (
625671 & self ,
626672 err : & mut Diagnostic ,
627673 cause : & ObligationCause < ' tcx > ,
628674 exp_found : Option < ty:: error:: ExpectedFound < Ty < ' tcx > > > ,
629675 terr : TypeError < ' tcx > ,
676+ detect_enum_noparm : bool ,
630677 ) {
631678 match * cause. code ( ) {
632679 ObligationCauseCode :: Pattern { origin_expr : true , span : Some ( span) , root_ty } => {
@@ -640,8 +687,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
640687 {
641688 err. span_label ( span, format ! ( "this is an iterator with items of type `{}`" , substs. type_at( 0 ) ) ) ;
642689 } 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+ }
645698 }
646699 if let Some ( ty:: error:: ExpectedFound { found, .. } ) = exp_found
647700 && ty. is_box ( ) && ty. boxed_ty ( ) == found
@@ -1490,6 +1543,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
14901543 terr : TypeError < ' tcx > ,
14911544 swap_secondary_and_primary : bool ,
14921545 prefer_label : bool ,
1546+ detect_enum_noparm : bool ,
14931547 ) {
14941548 let span = cause. span ( ) ;
14951549
@@ -1940,7 +1994,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
19401994
19411995 // It reads better to have the error origin as the final
19421996 // thing.
1943- self . note_error_origin ( diag, cause, exp_found, terr) ;
1997+ self . note_error_origin ( diag, cause, exp_found, terr, detect_enum_noparm ) ;
19441998
19451999 debug ! ( ?diag) ;
19462000 }
@@ -2260,6 +2314,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
22602314
22612315 let span = trace. cause . span ( ) ;
22622316 let failure_code = trace. cause . as_failure_code ( terr) ;
2317+ let mut detect_enum_noparm = false ;
22632318 let mut diag = match failure_code {
22642319 FailureCode :: Error0038 ( did) => {
22652320 let violations = self . tcx . object_safety_violations ( did) ;
@@ -2314,6 +2369,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23142369 }
23152370 }
23162371 }
2372+ ( ty:: FnDef ( _, _) , ty:: Adt ( adt_id, _) ) if adt_id. is_enum ( ) => {
2373+ detect_enum_noparm = true ;
2374+ }
23172375 _ => { }
23182376 }
23192377 }
@@ -2334,7 +2392,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23342392 struct_span_err ! ( self . tcx. sess, span, E0644 , "{}" , failure_str)
23352393 }
23362394 } ;
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+ ) ;
23382405 diag
23392406 }
23402407
0 commit comments