@@ -77,49 +77,86 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
7777 ( ty:: Param ( p) , ty:: Alias ( ty:: Projection , proj) ) | ( ty:: Alias ( ty:: Projection , proj) , ty:: Param ( p) )
7878 if tcx. def_kind ( proj. def_id ) != DefKind :: ImplTraitPlaceholder =>
7979 {
80- let generics = tcx. generics_of ( body_owner_def_id) ;
81- let p_span = tcx. def_span ( generics. type_param ( p, tcx) . def_id ) ;
80+ let p_def_id = tcx
81+ . generics_of ( body_owner_def_id)
82+ . type_param ( p, tcx)
83+ . def_id ;
84+ let p_span = tcx. def_span ( p_def_id) ;
8285 if !sp. contains ( p_span) {
8386 diag. span_label ( p_span, "this type parameter" ) ;
8487 }
8588 let hir = tcx. hir ( ) ;
8689 let mut note = true ;
87- if let Some ( generics) = generics
88- . type_param ( p, tcx)
89- . def_id
90+ let parent = p_def_id
9091 . as_local ( )
91- . map ( |id| hir. local_def_id_to_hir_id ( id) )
92- . and_then ( |id| tcx. hir ( ) . find_parent ( id) )
93- . as_ref ( )
94- . and_then ( |node| node. generics ( ) )
92+ . and_then ( |id| {
93+ let local_id = hir. local_def_id_to_hir_id ( id) ;
94+ let generics = tcx. hir ( ) . find_parent ( local_id) ?. generics ( ) ?;
95+ Some ( ( id, generics) )
96+ } ) ;
97+ if let Some ( ( local_id, generics) ) = parent
9598 {
9699 // Synthesize the associated type restriction `Add<Output = Expected>`.
97100 // FIXME: extract this logic for use in other diagnostics.
98101 let ( trait_ref, assoc_substs) = proj. trait_ref_and_own_substs ( tcx) ;
99- let path =
100- tcx. def_path_str_with_substs ( trait_ref. def_id , trait_ref. substs ) ;
101102 let item_name = tcx. item_name ( proj. def_id ) ;
102103 let item_args = self . format_generic_args ( assoc_substs) ;
103104
104- let path = if path. ends_with ( '>' ) {
105- format ! (
106- "{}, {}{} = {}>" ,
107- & path[ ..path. len( ) - 1 ] ,
108- item_name,
109- item_args,
110- p
111- )
105+ // Here, we try to see if there's an existing
106+ // trait implementation that matches the one that
107+ // we're suggesting to restrict. If so, find the
108+ // "end", whether it be at the end of the trait
109+ // or the end of the generic arguments.
110+ let mut matching_span = None ;
111+ let mut matched_end_of_args = false ;
112+ for bound in generics. bounds_for_param ( local_id) {
113+ let potential_spans = bound
114+ . bounds
115+ . iter ( )
116+ . find_map ( |bound| {
117+ let bound_trait_path = bound. trait_ref ( ) ?. path ;
118+ let def_id = bound_trait_path. res . opt_def_id ( ) ?;
119+ let generic_args = bound_trait_path. segments . iter ( ) . last ( ) . map ( |path| path. args ( ) ) ;
120+ ( def_id == trait_ref. def_id ) . then_some ( ( bound_trait_path. span , generic_args) )
121+ } ) ;
122+
123+ if let Some ( ( end_of_trait, end_of_args) ) = potential_spans {
124+ let args_span = end_of_args. and_then ( |args| args. span ( ) ) ;
125+ matched_end_of_args = args_span. is_some ( ) ;
126+ matching_span = args_span
127+ . or_else ( || Some ( end_of_trait) )
128+ . map ( |span| span. shrink_to_hi ( ) ) ;
129+ break ;
130+ }
131+ }
132+
133+ if matched_end_of_args {
134+ // Append suggestion to the end of our args
135+ let path = format ! ( ", {}{} = {}" , item_name, item_args, p) ;
136+ note = !suggest_constraining_type_param (
137+ tcx,
138+ generics,
139+ diag,
140+ & format ! ( "{}" , proj. self_ty( ) ) ,
141+ & path,
142+ None ,
143+ matching_span,
144+ ) ;
112145 } else {
113- format ! ( "{}<{}{} = {}>" , path, item_name, item_args, p)
114- } ;
115- note = !suggest_constraining_type_param (
116- tcx,
117- generics,
118- diag,
119- & format ! ( "{}" , proj. self_ty( ) ) ,
120- & path,
121- None ,
122- ) ;
146+ // Suggest adding a bound to an existing trait
147+ // or if the trait doesn't exist, add the trait
148+ // and the suggested bounds.
149+ let path = format ! ( "<{}{} = {}>" , item_name, item_args, p) ;
150+ note = !suggest_constraining_type_param (
151+ tcx,
152+ generics,
153+ diag,
154+ & format ! ( "{}" , proj. self_ty( ) ) ,
155+ & path,
156+ None ,
157+ matching_span,
158+ ) ;
159+ }
123160 }
124161 if note {
125162 diag. note ( "you might be missing a type parameter or trait bound" ) ;
0 commit comments