@@ -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,19 +338,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
338
338
( required, "" )
339
339
} ;
340
340
341
+ let mut potential_assoc_types: Option < Vec < Span > > = None ;
341
342
let ( spans, label) = if required == permitted && provided > permitted {
342
343
// In the case when the user has provided too many arguments,
343
344
// 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]
346
346
. iter ( )
347
347
. 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) )
354
351
} else {
355
352
( vec ! [ span] , format ! (
356
353
"expected {}{} {} argument{}" ,
@@ -377,7 +374,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
377
374
}
378
375
err. emit ( ) ;
379
376
380
- provided > required // `suppress_error`
377
+ ( provided > required, // `suppress_error`
378
+ potential_assoc_types)
381
379
} ;
382
380
383
381
if !infer_lifetimes || arg_counts. lifetimes > param_counts. lifetimes {
@@ -399,7 +397,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
399
397
arg_counts. lifetimes ,
400
398
)
401
399
} else {
402
- false
400
+ ( false , None )
403
401
}
404
402
}
405
403
@@ -557,7 +555,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
557
555
generic_args : & hir:: GenericArgs ,
558
556
infer_types : bool ,
559
557
self_ty : Option < Ty < ' tcx > > )
560
- -> ( & ' tcx Substs < ' tcx > , Vec < ConvertedBinding < ' tcx > > )
558
+ -> ( & ' tcx Substs < ' tcx > , Vec < ConvertedBinding < ' tcx > > , Option < Vec < Span > > )
561
559
{
562
560
// If the type is parameterized by this region, then replace this
563
561
// region with the current anon region binding (in other words,
@@ -573,7 +571,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
573
571
assert_eq ! ( generic_params. has_self, self_ty. is_some( ) ) ;
574
572
575
573
let has_self = generic_params. has_self ;
576
- Self :: check_generic_arg_count (
574
+ let ( _ , potential_assoc_types ) = Self :: check_generic_arg_count (
577
575
self . tcx ( ) ,
578
576
span,
579
577
& generic_params,
@@ -678,7 +676,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
678
676
debug ! ( "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}" ,
679
677
generic_params, self_ty, substs) ;
680
678
681
- ( substs, assoc_bindings)
679
+ ( substs, assoc_bindings, potential_assoc_types )
682
680
}
683
681
684
682
/// 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 {
720
718
self_ty : Ty < ' tcx > ,
721
719
poly_projections : & mut Vec < ( ty:: PolyProjectionPredicate < ' tcx > , Span ) > ,
722
720
speculative : bool )
723
- -> ty:: PolyTraitRef < ' tcx >
721
+ -> ( ty:: PolyTraitRef < ' tcx > , Option < Vec < Span > > )
724
722
{
725
723
let trait_def_id = self . trait_def_id ( trait_ref) ;
726
724
727
725
debug ! ( "instantiate_poly_trait_ref({:?}, def_id={:?})" , trait_ref, trait_def_id) ;
728
726
729
727
self . prohibit_generics ( trait_ref. path . segments . split_last ( ) . unwrap ( ) . 1 ) ;
730
728
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
+ ) ;
736
735
let poly_trait_ref = ty:: Binder :: bind ( ty:: TraitRef :: new ( trait_def_id, substs) ) ;
737
736
738
737
let mut dup_bindings = FxHashMap :: default ( ) ;
@@ -747,14 +746,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
747
746
748
747
debug ! ( "instantiate_poly_trait_ref({:?}, projections={:?}) -> {:?}" ,
749
748
trait_ref, poly_projections, poly_trait_ref) ;
750
- poly_trait_ref
749
+ ( poly_trait_ref, potential_assoc_types )
751
750
}
752
751
753
752
pub fn instantiate_poly_trait_ref ( & self ,
754
753
poly_trait_ref : & hir:: PolyTraitRef ,
755
754
self_ty : Ty < ' tcx > ,
756
755
poly_projections : & mut Vec < ( ty:: PolyProjectionPredicate < ' tcx > , Span ) > )
757
- -> ty:: PolyTraitRef < ' tcx >
756
+ -> ( ty:: PolyTraitRef < ' tcx > , Option < Vec < Span > > )
758
757
{
759
758
self . instantiate_poly_trait_ref_inner ( & poly_trait_ref. trait_ref , self_ty,
760
759
poly_projections, false )
@@ -767,7 +766,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
767
766
trait_segment : & hir:: PathSegment )
768
767
-> ty:: TraitRef < ' tcx >
769
768
{
770
- let ( substs, assoc_bindings) =
769
+ let ( substs, assoc_bindings, _ ) =
771
770
self . create_substs_for_ast_trait_ref ( span,
772
771
trait_def_id,
773
772
self_ty,
@@ -776,13 +775,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
776
775
ty:: TraitRef :: new ( trait_def_id, substs)
777
776
}
778
777
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 > > ) {
786
785
debug ! ( "create_substs_for_ast_trait_ref(trait_segment={:?})" ,
787
786
trait_segment) ;
788
787
@@ -972,9 +971,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
972
971
973
972
let mut projection_bounds = Vec :: new ( ) ;
974
973
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
+ ) ;
978
979
debug ! ( "principal: {:?}" , principal) ;
979
980
980
981
for trait_bound in trait_bounds[ 1 ..] . iter ( ) {
@@ -1047,16 +1048,47 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
1047
1048
if associated_types. len( ) == 1 { "" } else { "s" } ,
1048
1049
names,
1049
1050
) ;
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) ;
1052
1067
err. span_label (
1053
1068
span,
1054
1069
format ! ( "missing associated type `{}` value" , assoc_item. ident) ,
1055
1070
) ;
1056
1071
err. span_label (
1057
- tcx. def_span ( item_def_id) ,
1072
+ tcx. def_span ( * item_def_id) ,
1058
1073
format ! ( "`{}` defined here" , assoc_item. ident) ,
1059
1074
) ;
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
+ ) ;
1060
1092
}
1061
1093
err. emit ( ) ;
1062
1094
}
0 commit comments