@@ -64,8 +64,12 @@ use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, Mul
64
64
use rustc_hir as hir;
65
65
use rustc_hir:: def:: DefKind ;
66
66
use 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 ;
67
70
use rustc_hir:: lang_items:: LangItem ;
68
- use rustc_hir:: Node ;
71
+ use rustc_hir:: HirId ;
72
+ use rustc_hir:: { Expr , Node } ;
69
73
use rustc_middle:: dep_graph:: DepContext ;
70
74
use rustc_middle:: ty:: print:: with_no_trimmed_paths;
71
75
use rustc_middle:: ty:: relate:: { self , RelateResult , TypeRelation } ;
@@ -564,12 +568,56 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
564
568
}
565
569
}
566
570
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
+
567
614
fn note_error_origin (
568
615
& self ,
569
616
err : & mut Diagnostic ,
570
617
cause : & ObligationCause < ' tcx > ,
571
618
exp_found : Option < ty:: error:: ExpectedFound < Ty < ' tcx > > > ,
572
619
terr : TypeError < ' tcx > ,
620
+ detect_enum_noparm : bool ,
573
621
) {
574
622
match * cause. code ( ) {
575
623
ObligationCauseCode :: Pattern { origin_expr : true , span : Some ( span) , root_ty } => {
@@ -584,6 +632,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
584
632
err. span_label ( span, format ! ( "this is an iterator with items of type `{}`" , substs. type_at( 0 ) ) ) ;
585
633
} else {
586
634
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
+ }
587
641
}
588
642
}
589
643
if let Some ( ty:: error:: ExpectedFound { found, .. } ) = exp_found
@@ -1432,6 +1486,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1432
1486
terr : TypeError < ' tcx > ,
1433
1487
swap_secondary_and_primary : bool ,
1434
1488
prefer_label : bool ,
1489
+ detect_enum_noparm : bool ,
1435
1490
) {
1436
1491
let span = cause. span ( ) ;
1437
1492
@@ -1882,7 +1937,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1882
1937
1883
1938
// It reads better to have the error origin as the final
1884
1939
// thing.
1885
- self . note_error_origin ( diag, cause, exp_found, terr) ;
1940
+ self . note_error_origin ( diag, cause, exp_found, terr, detect_enum_noparm ) ;
1886
1941
1887
1942
debug ! ( ?diag) ;
1888
1943
}
@@ -2225,6 +2280,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
2225
2280
2226
2281
let span = trace. cause . span ( ) ;
2227
2282
let failure_code = trace. cause . as_failure_code ( terr) ;
2283
+ let mut detect_enum_noparm = false ;
2228
2284
let mut diag = match failure_code {
2229
2285
FailureCode :: Error0038 ( did) => {
2230
2286
let violations = self . tcx . object_safety_violations ( did) ;
@@ -2279,6 +2335,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
2279
2335
}
2280
2336
}
2281
2337
}
2338
+ ( ty:: FnDef ( _, _) , ty:: Adt ( adt_id, _) ) if adt_id. is_enum ( ) => {
2339
+ detect_enum_noparm = true ;
2340
+ }
2282
2341
_ => { }
2283
2342
}
2284
2343
}
@@ -2299,7 +2358,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
2299
2358
struct_span_err ! ( self . tcx. sess, span, E0644 , "{}" , failure_str)
2300
2359
}
2301
2360
} ;
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
+ ) ;
2303
2371
diag
2304
2372
}
2305
2373
0 commit comments