@@ -565,6 +565,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
565
565
Some ( self . root_var ( self . shallow_resolve ( ty) . ty_vid ( ) ?) )
566
566
}
567
567
568
+ /// Given a set of diverging vids and coercions, walk the HIR to gather a
569
+ /// set of suggestions which can be applied to preserve fallback to unit.
568
570
fn try_to_suggest_annotations (
569
571
& self ,
570
572
diverging_vids : & [ ty:: TyVid ] ,
@@ -574,26 +576,34 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
574
576
self . tcx . hir ( ) . maybe_body_owned_by ( self . body_id ) . expect ( "body id must have an owner" ) ;
575
577
// For each diverging var, look through the HIR for a place to give it
576
578
// a type annotation. We do this per var because we only really need one
577
- // per var.
579
+ // suggestion to influence a var to be `()` .
578
580
let suggestions = diverging_vids
579
581
. iter ( )
580
582
. copied ( )
581
583
. filter_map ( |vid| {
582
584
let reachable_vids =
583
585
graph:: depth_first_search_as_undirected ( coercions, vid) . collect ( ) ;
584
- VidVisitor { reachable_vids, fcx : self } . visit_expr ( body. value ) . break_value ( )
586
+ AnnotateUnitFallbackVisitor { reachable_vids, fcx : self }
587
+ . visit_expr ( body. value )
588
+ . break_value ( )
585
589
} )
586
590
. collect ( ) ;
587
591
errors:: SuggestAnnotations { suggestions }
588
592
}
589
593
}
590
594
591
- /// Try to collect a useful suggestion to preserve fallback to `()`.
592
- struct VidVisitor < ' a , ' tcx > {
595
+ /// Try to walk the HIR to find a place to insert a useful suggestion
596
+ /// to preserve fallback to `()` in 2024.
597
+ struct AnnotateUnitFallbackVisitor < ' a , ' tcx > {
593
598
reachable_vids : FxHashSet < ty:: TyVid > ,
594
599
fcx : & ' a FnCtxt < ' a , ' tcx > ,
595
600
}
596
- impl < ' tcx > VidVisitor < ' _ , ' tcx > {
601
+ impl < ' tcx > AnnotateUnitFallbackVisitor < ' _ , ' tcx > {
602
+ // For a given path segment, if it's missing a turbofish, try to suggest adding
603
+ // one so we can constrain an argument to `()`. To keep the suggestion simple,
604
+ // we want to simply suggest `_` for all the other args. This (for now) only
605
+ // works when there are only type variables (and region variables, since we can
606
+ // elide them)...
597
607
fn suggest_for_segment (
598
608
& self ,
599
609
arg_segment : & ' tcx hir:: PathSegment < ' tcx > ,
@@ -627,7 +637,7 @@ impl<'tcx> VidVisitor<'_, 'tcx> {
627
637
ControlFlow :: Continue ( ( ) )
628
638
}
629
639
}
630
- impl < ' tcx > Visitor < ' tcx > for VidVisitor < ' _ , ' tcx > {
640
+ impl < ' tcx > Visitor < ' tcx > for AnnotateUnitFallbackVisitor < ' _ , ' tcx > {
631
641
type Result = ControlFlow < errors:: SuggestAnnotation > ;
632
642
633
643
fn visit_ty ( & mut self , hir_ty : & ' tcx hir:: Ty < ' tcx > ) -> Self :: Result {
@@ -657,9 +667,7 @@ impl<'tcx> Visitor<'tcx> for VidVisitor<'_, 'tcx> {
657
667
return hir:: intravisit:: walk_qpath ( self , qpath, id) ;
658
668
}
659
669
} ;
660
- // Alternatively, try to turbofish `::<_, (), _>` (ignoring lifetimes,
661
- // since we don't need to turbofish those; they'll be inferred).
662
- // FIXME: Same logic could work for types...
670
+ // Alternatively, try to turbofish `::<_, (), _>`.
663
671
if let Some ( def_id) = self . fcx . typeck_results . borrow ( ) . qpath_res ( qpath, id) . opt_def_id ( ) {
664
672
self . suggest_for_segment ( arg_segment, def_id, id) ?;
665
673
}
@@ -668,6 +676,7 @@ impl<'tcx> Visitor<'tcx> for VidVisitor<'_, 'tcx> {
668
676
669
677
fn visit_expr ( & mut self , expr : & ' tcx hir:: Expr < ' tcx > ) -> Self :: Result {
670
678
// Try to suggest adding an explicit qself `()` to a trait method path.
679
+ // i.e. changing `Default::default()` to `<() as Default>::default()`.
671
680
if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = expr. kind
672
681
&& let Res :: Def ( DefKind :: AssocFn , def_id) = path. res
673
682
&& self . fcx . tcx . trait_of_item ( def_id) . is_some ( )
@@ -679,7 +688,7 @@ impl<'tcx> Visitor<'tcx> for VidVisitor<'_, 'tcx> {
679
688
let span = path. span . shrink_to_lo ( ) . to ( trait_segment. ident . span ) ;
680
689
return ControlFlow :: Break ( errors:: SuggestAnnotation :: Path ( span) ) ;
681
690
}
682
- // Or else turbofishing the method
691
+ // Or else, try suggesting turbofishing the method args.
683
692
if let hir:: ExprKind :: MethodCall ( segment, ..) = expr. kind
684
693
&& let Some ( def_id) =
685
694
self . fcx . typeck_results . borrow ( ) . type_dependent_def_id ( expr. hir_id )
@@ -690,6 +699,7 @@ impl<'tcx> Visitor<'tcx> for VidVisitor<'_, 'tcx> {
690
699
}
691
700
692
701
fn visit_local ( & mut self , local : & ' tcx hir:: LetStmt < ' tcx > ) -> Self :: Result {
702
+ // For a local, try suggest annotating the type if it's missing.
693
703
if let None = local. ty
694
704
&& let ty = self . fcx . typeck_results . borrow ( ) . node_type ( local. hir_id )
695
705
&& let Some ( vid) = self . fcx . root_vid ( ty)
0 commit comments