@@ -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,33 +338,28 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
338338 ( required, "" )
339339 } ;
340340
341- let mut span = span;
342- let label = if required == permitted && provided > permitted {
343- let diff = provided - permitted;
344- if diff == 1 {
345- // In the case when the user has provided too many arguments,
346- // we want to point to the first unexpected argument.
347- let first_superfluous_arg: & GenericArg = & args. args [ offset + permitted] ;
348- span = first_superfluous_arg. span ( ) ;
349- }
350- format ! (
351- "{}unexpected {} argument{}" ,
352- if diff != 1 { format!( "{} " , diff) } else { String :: new( ) } ,
353- kind,
354- if diff != 1 { "s" } else { "" } ,
355- )
341+ let mut potential_assoc_types: Option < Vec < Span > > = None ;
342+ let ( spans, label) = if required == permitted && provided > permitted {
343+ // In the case when the user has provided too many arguments,
344+ // we want to point to the unexpected arguments.
345+ let spans: Vec < Span > = args. args [ offset+permitted .. offset+provided]
346+ . iter ( )
347+ . map ( |arg| arg. span ( ) )
348+ . collect ( ) ;
349+ potential_assoc_types = Some ( spans. clone ( ) ) ;
350+ ( spans, format ! ( "unexpected {} argument" , kind) )
356351 } else {
357- format ! (
352+ ( vec ! [ span ] , format ! (
358353 "expected {}{} {} argument{}" ,
359354 quantifier,
360355 bound,
361356 kind,
362357 if bound != 1 { "s" } else { "" } ,
363- )
358+ ) )
364359 } ;
365360
366- tcx. sess . struct_span_err_with_code (
367- span ,
361+ let mut err = tcx. sess . struct_span_err_with_code (
362+ spans . clone ( ) ,
368363 & format ! (
369364 "wrong number of {} arguments: expected {}{}, found {}" ,
370365 kind,
@@ -373,9 +368,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
373368 provided,
374369 ) ,
375370 DiagnosticId :: Error ( "E0107" . into ( ) )
376- ) . span_label ( span, label) . emit ( ) ;
371+ ) ;
372+ for span in spans {
373+ err. span_label ( span, label. as_str ( ) ) ;
374+ }
375+ err. emit ( ) ;
377376
378- provided > required // `suppress_error`
377+ ( provided > required, // `suppress_error`
378+ potential_assoc_types)
379379 } ;
380380
381381 if !infer_lifetimes || arg_counts. lifetimes > param_counts. lifetimes {
@@ -397,7 +397,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
397397 arg_counts. lifetimes ,
398398 )
399399 } else {
400- false
400+ ( false , None )
401401 }
402402 }
403403
@@ -555,7 +555,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
555555 generic_args : & hir:: GenericArgs ,
556556 infer_types : bool ,
557557 self_ty : Option < Ty < ' tcx > > )
558- -> ( & ' tcx Substs < ' tcx > , Vec < ConvertedBinding < ' tcx > > )
558+ -> ( & ' tcx Substs < ' tcx > , Vec < ConvertedBinding < ' tcx > > , Option < Vec < Span > > )
559559 {
560560 // If the type is parameterized by this region, then replace this
561561 // region with the current anon region binding (in other words,
@@ -571,7 +571,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
571571 assert_eq ! ( generic_params. has_self, self_ty. is_some( ) ) ;
572572
573573 let has_self = generic_params. has_self ;
574- Self :: check_generic_arg_count (
574+ let ( _ , potential_assoc_types ) = Self :: check_generic_arg_count (
575575 self . tcx ( ) ,
576576 span,
577577 & generic_params,
@@ -676,7 +676,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
676676 debug ! ( "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}" ,
677677 generic_params, self_ty, substs) ;
678678
679- ( substs, assoc_bindings)
679+ ( substs, assoc_bindings, potential_assoc_types )
680680 }
681681
682682 /// Instantiates the path for the given trait reference, assuming that it's
@@ -718,19 +718,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
718718 self_ty : Ty < ' tcx > ,
719719 poly_projections : & mut Vec < ( ty:: PolyProjectionPredicate < ' tcx > , Span ) > ,
720720 speculative : bool )
721- -> ty:: PolyTraitRef < ' tcx >
721+ -> ( ty:: PolyTraitRef < ' tcx > , Option < Vec < Span > > )
722722 {
723723 let trait_def_id = self . trait_def_id ( trait_ref) ;
724724
725725 debug ! ( "instantiate_poly_trait_ref({:?}, def_id={:?})" , trait_ref, trait_def_id) ;
726726
727727 self . prohibit_generics ( trait_ref. path . segments . split_last ( ) . unwrap ( ) . 1 ) ;
728728
729- let ( substs, assoc_bindings) =
730- self . create_substs_for_ast_trait_ref ( trait_ref. path . span ,
731- trait_def_id,
732- self_ty,
733- 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+ ) ;
734735 let poly_trait_ref = ty:: Binder :: bind ( ty:: TraitRef :: new ( trait_def_id, substs) ) ;
735736
736737 let mut dup_bindings = FxHashMap :: default ( ) ;
@@ -745,14 +746,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
745746
746747 debug ! ( "instantiate_poly_trait_ref({:?}, projections={:?}) -> {:?}" ,
747748 trait_ref, poly_projections, poly_trait_ref) ;
748- poly_trait_ref
749+ ( poly_trait_ref, potential_assoc_types )
749750 }
750751
751752 pub fn instantiate_poly_trait_ref ( & self ,
752753 poly_trait_ref : & hir:: PolyTraitRef ,
753754 self_ty : Ty < ' tcx > ,
754755 poly_projections : & mut Vec < ( ty:: PolyProjectionPredicate < ' tcx > , Span ) > )
755- -> ty:: PolyTraitRef < ' tcx >
756+ -> ( ty:: PolyTraitRef < ' tcx > , Option < Vec < Span > > )
756757 {
757758 self . instantiate_poly_trait_ref_inner ( & poly_trait_ref. trait_ref , self_ty,
758759 poly_projections, false )
@@ -765,7 +766,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
765766 trait_segment : & hir:: PathSegment )
766767 -> ty:: TraitRef < ' tcx >
767768 {
768- let ( substs, assoc_bindings) =
769+ let ( substs, assoc_bindings, _ ) =
769770 self . create_substs_for_ast_trait_ref ( span,
770771 trait_def_id,
771772 self_ty,
@@ -774,13 +775,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
774775 ty:: TraitRef :: new ( trait_def_id, substs)
775776 }
776777
777- fn create_substs_for_ast_trait_ref ( & self ,
778- span : Span ,
779- trait_def_id : DefId ,
780- self_ty : Ty < ' tcx > ,
781- trait_segment : & hir :: PathSegment )
782- -> ( & ' tcx Substs < ' tcx > , Vec < ConvertedBinding < ' tcx > > )
783- {
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 > > ) {
784785 debug ! ( "create_substs_for_ast_trait_ref(trait_segment={:?})" ,
785786 trait_segment) ;
786787
@@ -970,9 +971,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
970971
971972 let mut projection_bounds = Vec :: new ( ) ;
972973 let dummy_self = tcx. mk_ty ( TRAIT_OBJECT_DUMMY_SELF ) ;
973- let principal = self . instantiate_poly_trait_ref ( & trait_bounds[ 0 ] ,
974- dummy_self,
975- & 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+ ) ;
976979 debug ! ( "principal: {:?}" , principal) ;
977980
978981 for trait_bound in trait_bounds[ 1 ..] . iter ( ) {
@@ -1027,16 +1030,74 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
10271030 associated_types. remove ( & projection_bound. projection_def_id ( ) ) ;
10281031 }
10291032
1030- for item_def_id in associated_types {
1031- let assoc_item = tcx. associated_item ( item_def_id) ;
1032- let trait_def_id = assoc_item. container . id ( ) ;
1033- struct_span_err ! ( tcx. sess, span, E0191 , "the value of the associated type `{}` \
1034- (from the trait `{}`) must be specified",
1035- assoc_item. ident,
1036- tcx. item_path_str( trait_def_id) )
1037- . span_label ( span, format ! ( "missing associated type `{}` value" ,
1038- assoc_item. ident) )
1039- . emit ( ) ;
1033+ if !associated_types. is_empty ( ) {
1034+ let names = associated_types. iter ( ) . map ( |item_def_id| {
1035+ let assoc_item = tcx. associated_item ( * item_def_id) ;
1036+ let trait_def_id = assoc_item. container . id ( ) ;
1037+ format ! (
1038+ "`{}` (from the trait `{}`)" ,
1039+ assoc_item. ident,
1040+ tcx. item_path_str( trait_def_id) ,
1041+ )
1042+ } ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
1043+ let mut err = struct_span_err ! (
1044+ tcx. sess,
1045+ span,
1046+ E0191 ,
1047+ "the value of the associated type{} {} must be specified" ,
1048+ if associated_types. len( ) == 1 { "" } else { "s" } ,
1049+ names,
1050+ ) ;
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) ;
1067+ err. span_label (
1068+ span,
1069+ format ! ( "associated type `{}` must be specified" , assoc_item. ident) ,
1070+ ) ;
1071+ if item_def_id. is_local ( ) {
1072+ err. span_label (
1073+ tcx. def_span ( * item_def_id) ,
1074+ format ! ( "`{}` defined here" , assoc_item. ident) ,
1075+ ) ;
1076+ }
1077+ if suggest {
1078+ if let Ok ( snippet) = tcx. sess . source_map ( ) . span_to_snippet (
1079+ potential_assoc_types_spans[ i] ,
1080+ ) {
1081+ suggestions. push ( (
1082+ potential_assoc_types_spans[ i] ,
1083+ format ! ( "{} = {}" , assoc_item. ident, snippet) ,
1084+ ) ) ;
1085+ }
1086+ }
1087+ }
1088+ if !suggestions. is_empty ( ) {
1089+ let msg = if suggestions. len ( ) == 1 {
1090+ "if you meant to specify the associated type, write"
1091+ } else {
1092+ "if you meant to specify the associated types, write"
1093+ } ;
1094+ err. multipart_suggestion_with_applicability (
1095+ msg,
1096+ suggestions,
1097+ Applicability :: MaybeIncorrect ,
1098+ ) ;
1099+ }
1100+ err. emit ( ) ;
10401101 }
10411102
10421103 // Erase the `dummy_self` (`TRAIT_OBJECT_DUMMY_SELF`) used above.
0 commit comments