@@ -64,8 +64,12 @@ use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, Mul
6464use rustc_hir as hir;
6565use rustc_hir:: def:: DefKind ;
6666use rustc_hir:: def_id:: { DefId , LocalDefId } ;
67+ use rustc_hir:: intravisit:: walk_block;
68+ use rustc_hir:: intravisit:: walk_expr;
69+ use rustc_hir:: intravisit:: Visitor ;
6770use rustc_hir:: lang_items:: LangItem ;
68- use rustc_hir:: Node ;
71+ use rustc_hir:: HirId ;
72+ use rustc_hir:: { Expr , Node } ;
6973use rustc_middle:: dep_graph:: DepContext ;
7074use rustc_middle:: ty:: print:: with_no_trimmed_paths;
7175use rustc_middle:: ty:: relate:: { self , RelateResult , TypeRelation } ;
@@ -564,12 +568,56 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
564568 }
565569 }
566570
571+ fn note_enum_suggestion (
572+ & self ,
573+ err : & mut Diagnostic ,
574+ span : Span ,
575+ body_id : HirId ,
576+ arg_size : usize ,
577+ ) {
578+ let body_node = self . tcx . hir ( ) . get ( body_id) ;
579+ let hir:: Node :: Expr ( & hir:: Expr { kind : hir:: ExprKind :: Block ( body_expr, ..) , ..} ) = body_node else { return ( ) } ;
580+ struct FindExprVisitor < ' tcx > {
581+ target_id : u32 ,
582+ size : usize ,
583+ terr : & ' tcx mut Diagnostic ,
584+ }
585+ impl < ' tcx > Visitor < ' tcx > for FindExprVisitor < ' tcx > {
586+ fn visit_expr ( & mut self , expr : & ' tcx Expr < ' tcx > ) {
587+ if expr. span . get_base_or_index ( ) == self . target_id {
588+ let mut suggest_vec = vec ! [ ] ;
589+ let mut i = 0 ;
590+ suggest_vec. push ( ( expr. span . shrink_to_hi ( ) , "(" . to_string ( ) ) ) ;
591+ while i < self . size {
592+ suggest_vec. push ( ( expr. span . shrink_to_hi ( ) , "_" . to_string ( ) ) ) ;
593+ if i != self . size - 1 {
594+ suggest_vec. push ( ( expr. span . shrink_to_hi ( ) , "," . to_string ( ) ) ) ;
595+ }
596+ i = i + 1 ;
597+ }
598+ suggest_vec. push ( ( expr. span . shrink_to_hi ( ) , ")" . to_string ( ) ) ) ;
599+
600+ self . terr . multipart_suggestion (
601+ "use parentheses to instantiate this tuple variant" ,
602+ suggest_vec,
603+ Applicability :: MachineApplicable ,
604+ ) ;
605+ }
606+ walk_expr ( self , expr) ;
607+ }
608+ }
609+ let mut visitor =
610+ FindExprVisitor { target_id : span. get_base_or_index ( ) , size : arg_size, terr : err } ;
611+ walk_block ( & mut visitor, body_expr) ;
612+ }
613+
567614 fn note_error_origin (
568615 & self ,
569616 err : & mut Diagnostic ,
570617 cause : & ObligationCause < ' tcx > ,
571618 exp_found : Option < ty:: error:: ExpectedFound < Ty < ' tcx > > > ,
572619 terr : TypeError < ' tcx > ,
620+ detect_enum_noparm : bool ,
573621 ) {
574622 match * cause. code ( ) {
575623 ObligationCauseCode :: Pattern { origin_expr : true , span : Some ( span) , root_ty } => {
@@ -584,6 +632,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
584632 err. span_label ( span, format ! ( "this is an iterator with items of type `{}`" , substs. type_at( 0 ) ) ) ;
585633 } else {
586634 err. span_label ( span, format ! ( "this expression has type `{}`" , ty) ) ;
635+ if detect_enum_noparm &&
636+ let ty:: FnDef ( def_id, substs) = ty. kind ( ) {
637+ let sig = self . tcx . bound_fn_sig ( * def_id) . subst ( self . tcx , substs) ;
638+ let sig = self . tcx . erase_late_bound_regions ( sig) ;
639+ self . note_enum_suggestion ( err, span, cause. body_id , sig. inputs ( ) . len ( ) ) ;
640+ }
587641 }
588642 }
589643 if let Some ( ty:: error:: ExpectedFound { found, .. } ) = exp_found
@@ -1432,6 +1486,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
14321486 terr : TypeError < ' tcx > ,
14331487 swap_secondary_and_primary : bool ,
14341488 prefer_label : bool ,
1489+ detect_enum_noparm : bool ,
14351490 ) {
14361491 let span = cause. span ( ) ;
14371492
@@ -1882,7 +1937,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
18821937
18831938 // It reads better to have the error origin as the final
18841939 // thing.
1885- self . note_error_origin ( diag, cause, exp_found, terr) ;
1940+ self . note_error_origin ( diag, cause, exp_found, terr, detect_enum_noparm ) ;
18861941
18871942 debug ! ( ?diag) ;
18881943 }
@@ -2225,6 +2280,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
22252280
22262281 let span = trace. cause . span ( ) ;
22272282 let failure_code = trace. cause . as_failure_code ( terr) ;
2283+ let mut detect_enum_noparm = false ;
22282284 let mut diag = match failure_code {
22292285 FailureCode :: Error0038 ( did) => {
22302286 let violations = self . tcx . object_safety_violations ( did) ;
@@ -2279,6 +2335,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
22792335 }
22802336 }
22812337 }
2338+ ( ty:: FnDef ( _, _) , ty:: Adt ( adt_id, _) ) if adt_id. is_enum ( ) => {
2339+ detect_enum_noparm = true ;
2340+ }
22822341 _ => { }
22832342 }
22842343 }
@@ -2299,7 +2358,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
22992358 struct_span_err ! ( self . tcx. sess, span, E0644 , "{}" , failure_str)
23002359 }
23012360 } ;
2302- self . note_type_err ( & mut diag, & trace. cause , None , Some ( trace. values ) , terr, false , false ) ;
2361+ self . note_type_err (
2362+ & mut diag,
2363+ & trace. cause ,
2364+ None ,
2365+ Some ( trace. values ) ,
2366+ terr,
2367+ false ,
2368+ false ,
2369+ detect_enum_noparm,
2370+ ) ;
23032371 diag
23042372 }
23052373
0 commit comments