@@ -182,7 +182,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
182
182
item_segment : & hir:: PathSegment )
183
183
-> & ' tcx Substs < ' tcx >
184
184
{
185
- let ( substs, assoc_bindings) = item_segment. with_generic_args ( |generic_args| {
185
+ let ( substs, assoc_bindings, _ ) = item_segment. with_generic_args ( |generic_args| {
186
186
self . create_substs_for_ast_path (
187
187
span,
188
188
def_id,
@@ -256,7 +256,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
256
256
} ,
257
257
def. parent . is_none ( ) && def. has_self , // `has_self`
258
258
seg. infer_types || suppress_mismatch, // `infer_types`
259
- )
259
+ ) . 0
260
260
}
261
261
262
262
/// 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 {
269
269
position : GenericArgPosition ,
270
270
has_self : bool ,
271
271
infer_types : bool ,
272
- ) -> bool {
272
+ ) -> ( bool , Option < Vec < Span > > ) {
273
273
// At this stage we are guaranteed that the generic arguments are in the correct order, e.g.
274
274
// that lifetimes will proceed types. So it suffices to check the number of each generic
275
275
// 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 {
303
303
let mut err = tcx. sess . struct_span_err ( span, msg) ;
304
304
err. span_note ( span_late, note) ;
305
305
err. emit ( ) ;
306
- return true ;
306
+ return ( true , None ) ;
307
307
} else {
308
308
let mut multispan = MultiSpan :: from_span ( span) ;
309
309
multispan. push_span_label ( span_late, note. to_string ( ) ) ;
310
310
tcx. lint_node ( lint:: builtin:: LATE_BOUND_LIFETIME_ARGUMENTS ,
311
311
args. args [ 0 ] . id ( ) , multispan, msg) ;
312
- return false ;
312
+ return ( false , None ) ;
313
313
}
314
314
}
315
315
}
@@ -323,7 +323,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
323
323
// For kinds without defaults (i.e. lifetimes), `required == permitted`.
324
324
// For other kinds (i.e. types), `permitted` may be greater than `required`.
325
325
if required <= provided && provided <= permitted {
326
- return false ;
326
+ return ( false , None ) ;
327
327
}
328
328
329
329
// Unfortunately lifetime and type parameter mismatches are typically styled
@@ -338,33 +338,28 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
338
338
( required, "" )
339
339
} ;
340
340
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) )
356
351
} else {
357
- format ! (
352
+ ( vec ! [ span ] , format ! (
358
353
"expected {}{} {} argument{}" ,
359
354
quantifier,
360
355
bound,
361
356
kind,
362
357
if bound != 1 { "s" } else { "" } ,
363
- )
358
+ ) )
364
359
} ;
365
360
366
- tcx. sess . struct_span_err_with_code (
367
- span ,
361
+ let mut err = tcx. sess . struct_span_err_with_code (
362
+ spans . clone ( ) ,
368
363
& format ! (
369
364
"wrong number of {} arguments: expected {}{}, found {}" ,
370
365
kind,
@@ -373,9 +368,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
373
368
provided,
374
369
) ,
375
370
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 ( ) ;
377
376
378
- provided > required // `suppress_error`
377
+ ( provided > required, // `suppress_error`
378
+ potential_assoc_types)
379
379
} ;
380
380
381
381
if !infer_lifetimes || arg_counts. lifetimes > param_counts. lifetimes {
@@ -397,7 +397,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
397
397
arg_counts. lifetimes ,
398
398
)
399
399
} else {
400
- false
400
+ ( false , None )
401
401
}
402
402
}
403
403
@@ -555,7 +555,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
555
555
generic_args : & hir:: GenericArgs ,
556
556
infer_types : bool ,
557
557
self_ty : Option < Ty < ' tcx > > )
558
- -> ( & ' tcx Substs < ' tcx > , Vec < ConvertedBinding < ' tcx > > )
558
+ -> ( & ' tcx Substs < ' tcx > , Vec < ConvertedBinding < ' tcx > > , Option < Vec < Span > > )
559
559
{
560
560
// If the type is parameterized by this region, then replace this
561
561
// region with the current anon region binding (in other words,
@@ -571,7 +571,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
571
571
assert_eq ! ( generic_params. has_self, self_ty. is_some( ) ) ;
572
572
573
573
let has_self = generic_params. has_self ;
574
- Self :: check_generic_arg_count (
574
+ let ( _ , potential_assoc_types ) = Self :: check_generic_arg_count (
575
575
self . tcx ( ) ,
576
576
span,
577
577
& generic_params,
@@ -676,7 +676,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
676
676
debug ! ( "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}" ,
677
677
generic_params, self_ty, substs) ;
678
678
679
- ( substs, assoc_bindings)
679
+ ( substs, assoc_bindings, potential_assoc_types )
680
680
}
681
681
682
682
/// 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 {
718
718
self_ty : Ty < ' tcx > ,
719
719
poly_projections : & mut Vec < ( ty:: PolyProjectionPredicate < ' tcx > , Span ) > ,
720
720
speculative : bool )
721
- -> ty:: PolyTraitRef < ' tcx >
721
+ -> ( ty:: PolyTraitRef < ' tcx > , Option < Vec < Span > > )
722
722
{
723
723
let trait_def_id = self . trait_def_id ( trait_ref) ;
724
724
725
725
debug ! ( "instantiate_poly_trait_ref({:?}, def_id={:?})" , trait_ref, trait_def_id) ;
726
726
727
727
self . prohibit_generics ( trait_ref. path . segments . split_last ( ) . unwrap ( ) . 1 ) ;
728
728
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
+ ) ;
734
735
let poly_trait_ref = ty:: Binder :: bind ( ty:: TraitRef :: new ( trait_def_id, substs) ) ;
735
736
736
737
let mut dup_bindings = FxHashMap :: default ( ) ;
@@ -745,14 +746,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
745
746
746
747
debug ! ( "instantiate_poly_trait_ref({:?}, projections={:?}) -> {:?}" ,
747
748
trait_ref, poly_projections, poly_trait_ref) ;
748
- poly_trait_ref
749
+ ( poly_trait_ref, potential_assoc_types )
749
750
}
750
751
751
752
pub fn instantiate_poly_trait_ref ( & self ,
752
753
poly_trait_ref : & hir:: PolyTraitRef ,
753
754
self_ty : Ty < ' tcx > ,
754
755
poly_projections : & mut Vec < ( ty:: PolyProjectionPredicate < ' tcx > , Span ) > )
755
- -> ty:: PolyTraitRef < ' tcx >
756
+ -> ( ty:: PolyTraitRef < ' tcx > , Option < Vec < Span > > )
756
757
{
757
758
self . instantiate_poly_trait_ref_inner ( & poly_trait_ref. trait_ref , self_ty,
758
759
poly_projections, false )
@@ -765,7 +766,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
765
766
trait_segment : & hir:: PathSegment )
766
767
-> ty:: TraitRef < ' tcx >
767
768
{
768
- let ( substs, assoc_bindings) =
769
+ let ( substs, assoc_bindings, _ ) =
769
770
self . create_substs_for_ast_trait_ref ( span,
770
771
trait_def_id,
771
772
self_ty,
@@ -774,13 +775,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
774
775
ty:: TraitRef :: new ( trait_def_id, substs)
775
776
}
776
777
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 > > ) {
784
785
debug ! ( "create_substs_for_ast_trait_ref(trait_segment={:?})" ,
785
786
trait_segment) ;
786
787
@@ -970,9 +971,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
970
971
971
972
let mut projection_bounds = Vec :: new ( ) ;
972
973
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
+ ) ;
976
979
debug ! ( "principal: {:?}" , principal) ;
977
980
978
981
for trait_bound in trait_bounds[ 1 ..] . iter ( ) {
@@ -1027,16 +1030,74 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
1027
1030
associated_types. remove ( & projection_bound. projection_def_id ( ) ) ;
1028
1031
}
1029
1032
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 ( ) ;
1040
1101
}
1041
1102
1042
1103
// Erase the `dummy_self` (`TRAIT_OBJECT_DUMMY_SELF`) used above.
0 commit comments