@@ -9,6 +9,7 @@ use rustc_data_structures::unord::{UnordBag, UnordMap, UnordSet};
99use rustc_hir as hir;
1010use rustc_hir:: HirId ;
1111use rustc_hir:: def:: { DefKind , Res } ;
12+ use rustc_hir:: def_id:: DefId ;
1213use rustc_hir:: intravisit:: Visitor ;
1314use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable } ;
1415use rustc_session:: lint;
@@ -592,10 +593,45 @@ struct VidVisitor<'a, 'tcx> {
592593 reachable_vids : FxHashSet < ty:: TyVid > ,
593594 fcx : & ' a FnCtxt < ' a , ' tcx > ,
594595}
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+ }
595630impl < ' tcx > Visitor < ' tcx > for VidVisitor < ' _ , ' tcx > {
596631 type Result = ControlFlow < errors:: SuggestAnnotation > ;
597632
598633 fn visit_ty ( & mut self , hir_ty : & ' tcx hir:: Ty < ' tcx > ) -> Self :: Result {
634+ // Try to replace `_` with `()`.
599635 if let hir:: TyKind :: Infer = hir_ty. kind
600636 && let ty = self . fcx . typeck_results . borrow ( ) . node_type ( hir_ty. hir_id )
601637 && let Some ( vid) = self . fcx . root_vid ( ty)
@@ -606,7 +642,32 @@ impl<'tcx> Visitor<'tcx> for VidVisitor<'_, 'tcx> {
606642 hir:: intravisit:: walk_ty ( self , hir_ty)
607643 }
608644
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+
609669 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.
610671 if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = expr. kind
611672 && let Res :: Def ( DefKind :: AssocFn , def_id) = path. res
612673 && self . fcx . tcx . trait_of_item ( def_id) . is_some ( )
@@ -618,6 +679,13 @@ impl<'tcx> Visitor<'tcx> for VidVisitor<'_, 'tcx> {
618679 let span = path. span . shrink_to_lo ( ) . to ( trait_segment. ident . span ) ;
619680 return ControlFlow :: Break ( errors:: SuggestAnnotation :: Path ( span) ) ;
620681 }
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+ }
621689 hir:: intravisit:: walk_expr ( self , expr)
622690 }
623691
0 commit comments