@@ -9,6 +9,7 @@ use rustc_data_structures::unord::{UnordBag, UnordMap, UnordSet};
9
9
use rustc_hir as hir;
10
10
use rustc_hir:: HirId ;
11
11
use rustc_hir:: def:: { DefKind , Res } ;
12
+ use rustc_hir:: def_id:: DefId ;
12
13
use rustc_hir:: intravisit:: Visitor ;
13
14
use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable } ;
14
15
use rustc_session:: lint;
@@ -592,10 +593,45 @@ struct VidVisitor<'a, 'tcx> {
592
593
reachable_vids : FxHashSet < ty:: TyVid > ,
593
594
fcx : & ' a FnCtxt < ' a , ' tcx > ,
594
595
}
596
+ impl < ' tcx > VidVisitor < ' _ , ' tcx > {
597
+ fn suggest_for_segment (
598
+ & self ,
599
+ arg_segment : & ' tcx hir:: PathSegment < ' tcx > ,
600
+ def_id : DefId ,
601
+ id : HirId ,
602
+ ) -> ControlFlow < errors:: SuggestAnnotation > {
603
+ if arg_segment. args . is_none ( )
604
+ && let Some ( all_args) = self . fcx . typeck_results . borrow ( ) . node_args_opt ( id)
605
+ && let generics = self . fcx . tcx . generics_of ( def_id)
606
+ && let args = & all_args[ generics. parent_count ..]
607
+ // We can't turbofish consts :(
608
+ && args. iter ( ) . all ( |arg| matches ! ( arg. unpack( ) , ty:: GenericArgKind :: Type ( _) | ty:: GenericArgKind :: Lifetime ( _) ) )
609
+ {
610
+ let n_tys = args
611
+ . iter ( )
612
+ . filter ( |arg| matches ! ( arg. unpack( ) , ty:: GenericArgKind :: Type ( _) ) )
613
+ . count ( ) ;
614
+ for ( idx, arg) in args. iter ( ) . enumerate ( ) {
615
+ if let Some ( ty) = arg. as_type ( )
616
+ && let Some ( vid) = self . fcx . root_vid ( ty)
617
+ && self . reachable_vids . contains ( & vid)
618
+ {
619
+ return ControlFlow :: Break ( errors:: SuggestAnnotation :: Turbo (
620
+ arg_segment. ident . span . shrink_to_hi ( ) ,
621
+ n_tys,
622
+ idx,
623
+ ) ) ;
624
+ }
625
+ }
626
+ }
627
+ ControlFlow :: Continue ( ( ) )
628
+ }
629
+ }
595
630
impl < ' tcx > Visitor < ' tcx > for VidVisitor < ' _ , ' tcx > {
596
631
type Result = ControlFlow < errors:: SuggestAnnotation > ;
597
632
598
633
fn visit_ty ( & mut self , hir_ty : & ' tcx hir:: Ty < ' tcx > ) -> Self :: Result {
634
+ // Try to replace `_` with `()`.
599
635
if let hir:: TyKind :: Infer = hir_ty. kind
600
636
&& let ty = self . fcx . typeck_results . borrow ( ) . node_type ( hir_ty. hir_id )
601
637
&& let Some ( vid) = self . fcx . root_vid ( ty)
@@ -606,7 +642,32 @@ impl<'tcx> Visitor<'tcx> for VidVisitor<'_, 'tcx> {
606
642
hir:: intravisit:: walk_ty ( self , hir_ty)
607
643
}
608
644
645
+ fn visit_qpath (
646
+ & mut self ,
647
+ qpath : & ' tcx rustc_hir:: QPath < ' tcx > ,
648
+ id : HirId ,
649
+ _span : Span ,
650
+ ) -> Self :: Result {
651
+ let arg_segment = match qpath {
652
+ hir:: QPath :: Resolved ( _, path) => {
653
+ path. segments . last ( ) . expect ( "paths should have a segment" )
654
+ }
655
+ hir:: QPath :: TypeRelative ( _, segment) => segment,
656
+ hir:: QPath :: LangItem ( ..) => {
657
+ return hir:: intravisit:: walk_qpath ( self , qpath, id) ;
658
+ }
659
+ } ;
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...
663
+ if let Some ( def_id) = self . fcx . typeck_results . borrow ( ) . qpath_res ( qpath, id) . opt_def_id ( ) {
664
+ self . suggest_for_segment ( arg_segment, def_id, id) ?;
665
+ }
666
+ hir:: intravisit:: walk_qpath ( self , qpath, id)
667
+ }
668
+
609
669
fn visit_expr ( & mut self , expr : & ' tcx hir:: Expr < ' tcx > ) -> Self :: Result {
670
+ // Try to suggest adding an explicit qself `()` to a trait method path.
610
671
if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = expr. kind
611
672
&& let Res :: Def ( DefKind :: AssocFn , def_id) = path. res
612
673
&& self . fcx . tcx . trait_of_item ( def_id) . is_some ( )
@@ -618,6 +679,13 @@ impl<'tcx> Visitor<'tcx> for VidVisitor<'_, 'tcx> {
618
679
let span = path. span . shrink_to_lo ( ) . to ( trait_segment. ident . span ) ;
619
680
return ControlFlow :: Break ( errors:: SuggestAnnotation :: Path ( span) ) ;
620
681
}
682
+ // Or else turbofishing the method
683
+ if let hir:: ExprKind :: MethodCall ( segment, ..) = expr. kind
684
+ && let Some ( def_id) =
685
+ self . fcx . typeck_results . borrow ( ) . type_dependent_def_id ( expr. hir_id )
686
+ {
687
+ self . suggest_for_segment ( segment, def_id, expr. hir_id ) ?;
688
+ }
621
689
hir:: intravisit:: walk_expr ( self , expr)
622
690
}
623
691
0 commit comments