@@ -182,7 +182,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
182182 item_segment : & hir:: PathSegment )
183183 -> & ' tcx Substs < ' tcx >
184184 {
185- let ( substs, assoc_bindings) = item_segment. with_generic_args ( |generic_args| {
185+ let ( substs, assoc_bindings, _ ) = item_segment. with_generic_args ( |generic_args| {
186186 self . create_substs_for_ast_path (
187187 span,
188188 def_id,
@@ -256,7 +256,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
256256 } ,
257257 def. parent . is_none ( ) && def. has_self , // `has_self`
258258 seg. infer_types || suppress_mismatch, // `infer_types`
259- )
259+ ) . 0
260260 }
261261
262262 /// Check that the correct number of generic arguments have been provided.
@@ -269,7 +269,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
269269 position : GenericArgPosition ,
270270 has_self : bool ,
271271 infer_types : bool ,
272- ) -> bool {
272+ ) -> ( bool , Option < Vec < Span > > ) {
273273 // At this stage we are guaranteed that the generic arguments are in the correct order, e.g.
274274 // that lifetimes will proceed types. So it suffices to check the number of each generic
275275 // arguments in order to validate them with respect to the generic parameters.
@@ -303,13 +303,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
303303 let mut err = tcx. sess . struct_span_err ( span, msg) ;
304304 err. span_note ( span_late, note) ;
305305 err. emit ( ) ;
306- return true ;
306+ return ( true , None ) ;
307307 } else {
308308 let mut multispan = MultiSpan :: from_span ( span) ;
309309 multispan. push_span_label ( span_late, note. to_string ( ) ) ;
310310 tcx. lint_node ( lint:: builtin:: LATE_BOUND_LIFETIME_ARGUMENTS ,
311311 args. args [ 0 ] . id ( ) , multispan, msg) ;
312- return false ;
312+ return ( false , None ) ;
313313 }
314314 }
315315 }
@@ -323,7 +323,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
323323 // For kinds without defaults (i.e. lifetimes), `required == permitted`.
324324 // For other kinds (i.e. types), `permitted` may be greater than `required`.
325325 if required <= provided && provided <= permitted {
326- return false ;
326+ return ( false , None ) ;
327327 }
328328
329329 // Unfortunately lifetime and type parameter mismatches are typically styled
@@ -338,19 +338,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
338338 ( required, "" )
339339 } ;
340340
341+ let mut potential_assoc_types: Option < Vec < Span > > = None ;
341342 let ( spans, label) = if required == permitted && provided > permitted {
342343 // In the case when the user has provided too many arguments,
343344 // we want to point to the unexpected arguments.
344- (
345- args. args [ offset+permitted .. offset+provided]
345+ let spans: Vec < Span > = args. args [ offset+permitted .. offset+provided]
346346 . iter ( )
347347 . map ( |arg| arg. span ( ) )
348- . collect ( ) ,
349- format ! (
350- "unexpected {} argument" ,
351- kind,
352- ) ,
353- )
348+ . collect ( ) ;
349+ potential_assoc_types = Some ( spans. clone ( ) ) ;
350+ ( spans, format ! ( "unexpected {} argument" , kind) )
354351 } else {
355352 ( vec ! [ span] , format ! (
356353 "expected {}{} {} argument{}" ,
@@ -377,7 +374,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
377374 }
378375 err. emit ( ) ;
379376
380- provided > required // `suppress_error`
377+ ( provided > required, // `suppress_error`
378+ potential_assoc_types)
381379 } ;
382380
383381 if !infer_lifetimes || arg_counts. lifetimes > param_counts. lifetimes {
@@ -399,7 +397,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
399397 arg_counts. lifetimes ,
400398 )
401399 } else {
402- false
400+ ( false , None )
403401 }
404402 }
405403
@@ -557,7 +555,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
557555 generic_args : & hir:: GenericArgs ,
558556 infer_types : bool ,
559557 self_ty : Option < Ty < ' tcx > > )
560- -> ( & ' tcx Substs < ' tcx > , Vec < ConvertedBinding < ' tcx > > )
558+ -> ( & ' tcx Substs < ' tcx > , Vec < ConvertedBinding < ' tcx > > , Option < Vec < Span > > )
561559 {
562560 // If the type is parameterized by this region, then replace this
563561 // region with the current anon region binding (in other words,
@@ -573,7 +571,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
573571 assert_eq ! ( generic_params. has_self, self_ty. is_some( ) ) ;
574572
575573 let has_self = generic_params. has_self ;
576- Self :: check_generic_arg_count (
574+ let ( _ , potential_assoc_types ) = Self :: check_generic_arg_count (
577575 self . tcx ( ) ,
578576 span,
579577 & generic_params,
@@ -678,7 +676,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
678676 debug ! ( "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}" ,
679677 generic_params, self_ty, substs) ;
680678
681- ( substs, assoc_bindings)
679+ ( substs, assoc_bindings, potential_assoc_types )
682680 }
683681
684682 /// Instantiates the path for the given trait reference, assuming that it's
@@ -720,19 +718,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
720718 self_ty : Ty < ' tcx > ,
721719 poly_projections : & mut Vec < ( ty:: PolyProjectionPredicate < ' tcx > , Span ) > ,
722720 speculative : bool )
723- -> ty:: PolyTraitRef < ' tcx >
721+ -> ( ty:: PolyTraitRef < ' tcx > , Option < Vec < Span > > )
724722 {
725723 let trait_def_id = self . trait_def_id ( trait_ref) ;
726724
727725 debug ! ( "instantiate_poly_trait_ref({:?}, def_id={:?})" , trait_ref, trait_def_id) ;
728726
729727 self . prohibit_generics ( trait_ref. path . segments . split_last ( ) . unwrap ( ) . 1 ) ;
730728
731- let ( substs, assoc_bindings) =
732- self . create_substs_for_ast_trait_ref ( trait_ref. path . span ,
733- trait_def_id,
734- self_ty,
735- trait_ref. path . segments . last ( ) . unwrap ( ) ) ;
729+ let ( substs, assoc_bindings, potential_assoc_types) = self . create_substs_for_ast_trait_ref (
730+ trait_ref. path . span ,
731+ trait_def_id,
732+ self_ty,
733+ trait_ref. path . segments . last ( ) . unwrap ( ) ,
734+ ) ;
736735 let poly_trait_ref = ty:: Binder :: bind ( ty:: TraitRef :: new ( trait_def_id, substs) ) ;
737736
738737 let mut dup_bindings = FxHashMap :: default ( ) ;
@@ -747,14 +746,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
747746
748747 debug ! ( "instantiate_poly_trait_ref({:?}, projections={:?}) -> {:?}" ,
749748 trait_ref, poly_projections, poly_trait_ref) ;
750- poly_trait_ref
749+ ( poly_trait_ref, potential_assoc_types )
751750 }
752751
753752 pub fn instantiate_poly_trait_ref ( & self ,
754753 poly_trait_ref : & hir:: PolyTraitRef ,
755754 self_ty : Ty < ' tcx > ,
756755 poly_projections : & mut Vec < ( ty:: PolyProjectionPredicate < ' tcx > , Span ) > )
757- -> ty:: PolyTraitRef < ' tcx >
756+ -> ( ty:: PolyTraitRef < ' tcx > , Option < Vec < Span > > )
758757 {
759758 self . instantiate_poly_trait_ref_inner ( & poly_trait_ref. trait_ref , self_ty,
760759 poly_projections, false )
@@ -767,7 +766,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
767766 trait_segment : & hir:: PathSegment )
768767 -> ty:: TraitRef < ' tcx >
769768 {
770- let ( substs, assoc_bindings) =
769+ let ( substs, assoc_bindings, _ ) =
771770 self . create_substs_for_ast_trait_ref ( span,
772771 trait_def_id,
773772 self_ty,
@@ -776,13 +775,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
776775 ty:: TraitRef :: new ( trait_def_id, substs)
777776 }
778777
779- fn create_substs_for_ast_trait_ref ( & self ,
780- span : Span ,
781- trait_def_id : DefId ,
782- self_ty : Ty < ' tcx > ,
783- trait_segment : & hir :: PathSegment )
784- -> ( & ' tcx Substs < ' tcx > , Vec < ConvertedBinding < ' tcx > > )
785- {
778+ fn create_substs_for_ast_trait_ref (
779+ & self ,
780+ span : Span ,
781+ trait_def_id : DefId ,
782+ self_ty : Ty < ' tcx > ,
783+ trait_segment : & hir :: PathSegment ,
784+ ) -> ( & ' tcx Substs < ' tcx > , Vec < ConvertedBinding < ' tcx > > , Option < Vec < Span > > ) {
786785 debug ! ( "create_substs_for_ast_trait_ref(trait_segment={:?})" ,
787786 trait_segment) ;
788787
@@ -972,9 +971,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
972971
973972 let mut projection_bounds = Vec :: new ( ) ;
974973 let dummy_self = tcx. mk_ty ( TRAIT_OBJECT_DUMMY_SELF ) ;
975- let principal = self . instantiate_poly_trait_ref ( & trait_bounds[ 0 ] ,
976- dummy_self,
977- & mut projection_bounds) ;
974+ let ( principal, potential_assoc_types) = self . instantiate_poly_trait_ref (
975+ & trait_bounds[ 0 ] ,
976+ dummy_self,
977+ & mut projection_bounds,
978+ ) ;
978979 debug ! ( "principal: {:?}" , principal) ;
979980
980981 for trait_bound in trait_bounds[ 1 ..] . iter ( ) {
@@ -1047,16 +1048,47 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
10471048 if associated_types. len( ) == 1 { "" } else { "s" } ,
10481049 names,
10491050 ) ;
1050- for item_def_id in associated_types {
1051- let assoc_item = tcx. associated_item ( item_def_id) ;
1051+ let mut suggest = false ;
1052+ let mut potential_assoc_types_spans = vec ! [ ] ;
1053+ if let Some ( potential_assoc_types) = potential_assoc_types {
1054+ if potential_assoc_types. len ( ) == associated_types. len ( ) {
1055+ // Only suggest when the amount of missing associated types is equals to the
1056+ // extra type arguments present, as that gives us a relatively high confidence
1057+ // that the user forgot to give the associtated type's name. The canonical
1058+ // example would be trying to use `Iterator<isize>` instead of
1059+ // `Iterator<Item=isize>`.
1060+ suggest = true ;
1061+ potential_assoc_types_spans = potential_assoc_types;
1062+ }
1063+ }
1064+ let mut suggestions = vec ! [ ] ;
1065+ for ( i, item_def_id) in associated_types. iter ( ) . enumerate ( ) {
1066+ let assoc_item = tcx. associated_item ( * item_def_id) ;
10521067 err. span_label (
10531068 span,
10541069 format ! ( "missing associated type `{}` value" , assoc_item. ident) ,
10551070 ) ;
10561071 err. span_label (
1057- tcx. def_span ( item_def_id) ,
1072+ tcx. def_span ( * item_def_id) ,
10581073 format ! ( "`{}` defined here" , assoc_item. ident) ,
10591074 ) ;
1075+ if suggest {
1076+ if let Ok ( snippet) = tcx. sess . source_map ( ) . span_to_snippet (
1077+ potential_assoc_types_spans[ i] ,
1078+ ) {
1079+ suggestions. push ( (
1080+ potential_assoc_types_spans[ i] ,
1081+ format ! ( "{} = {}" , assoc_item. ident, snippet) ,
1082+ ) ) ;
1083+ }
1084+ }
1085+ }
1086+ if !suggestions. is_empty ( ) {
1087+ err. multipart_suggestion_with_applicability (
1088+ "if you meant to assign the missing associated type, use the name" ,
1089+ suggestions,
1090+ Applicability :: MaybeIncorrect ,
1091+ ) ;
10601092 }
10611093 err. emit ( ) ;
10621094 }
0 commit comments