@@ -77,49 +77,86 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
77
77
( ty:: Param ( p) , ty:: Alias ( ty:: Projection , proj) ) | ( ty:: Alias ( ty:: Projection , proj) , ty:: Param ( p) )
78
78
if tcx. def_kind ( proj. def_id ) != DefKind :: ImplTraitPlaceholder =>
79
79
{
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) ;
82
85
if !sp. contains ( p_span) {
83
86
diag. span_label ( p_span, "this type parameter" ) ;
84
87
}
85
88
let hir = tcx. hir ( ) ;
86
89
let mut note = true ;
87
- if let Some ( generics) = generics
88
- . type_param ( p, tcx)
89
- . def_id
90
+ let parent = p_def_id
90
91
. 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
95
98
{
96
99
// Synthesize the associated type restriction `Add<Output = Expected>`.
97
100
// FIXME: extract this logic for use in other diagnostics.
98
101
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 ) ;
101
102
let item_name = tcx. item_name ( proj. def_id ) ;
102
103
let item_args = self . format_generic_args ( assoc_substs) ;
103
104
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
+ ) ;
112
145
} 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
+ }
123
160
}
124
161
if note {
125
162
diag. note ( "you might be missing a type parameter or trait bound" ) ;
0 commit comments