@@ -120,9 +120,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
120
120
return ;
121
121
} ;
122
122
let sugg = self . add_generic_param_suggestion ( generics, self_ty. span , & impl_trait_name) ;
123
- if sugg. is_empty ( ) {
124
- return ;
125
- } ;
126
123
diag. multipart_suggestion (
127
124
format ! (
128
125
"alternatively use a blanket implementation to implement `{of_trait_name}` for \
@@ -157,6 +154,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
157
154
let parent_id = tcx. hir ( ) . get_parent_item ( self_ty. hir_id ) . def_id ;
158
155
// FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0<Ty = Trait1>`
159
156
// and suggest `Trait0<Ty = impl Trait1>`.
157
+ // Functions are found in three different contexts.
158
+ // 1. Independent functions
159
+ // 2. Functions inside trait blocks
160
+ // 3. Functions inside impl blocks
160
161
let ( sig, generics, owner) = match tcx. hir_node_by_def_id ( parent_id) {
161
162
hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Fn ( sig, generics, _) , .. } ) => {
162
163
( sig, generics, None )
@@ -167,13 +168,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
167
168
owner_id,
168
169
..
169
170
} ) => ( sig, generics, Some ( tcx. parent ( owner_id. to_def_id ( ) ) ) ) ,
171
+ hir:: Node :: ImplItem ( hir:: ImplItem {
172
+ kind : hir:: ImplItemKind :: Fn ( sig, _) ,
173
+ generics,
174
+ owner_id,
175
+ ..
176
+ } ) => ( sig, generics, Some ( tcx. parent ( owner_id. to_def_id ( ) ) ) ) ,
170
177
_ => return false ,
171
178
} ;
172
179
let Ok ( trait_name) = tcx. sess . source_map ( ) . span_to_snippet ( self_ty. span ) else {
173
180
return false ;
174
181
} ;
175
182
let impl_sugg = vec ! [ ( self_ty. span. shrink_to_lo( ) , "impl " . to_string( ) ) ] ;
176
183
let mut is_downgradable = true ;
184
+
185
+ // Check if trait object is safe for suggesting dynamic dispatch.
177
186
let is_object_safe = match self_ty. kind {
178
187
hir:: TyKind :: TraitObject ( objects, ..) => {
179
188
objects. iter ( ) . all ( |o| match o. trait_ref . path . res {
@@ -189,8 +198,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
189
198
}
190
199
_ => false ,
191
200
} ;
201
+
202
+ let borrowed = matches ! (
203
+ tcx. parent_hir_node( self_ty. hir_id) ,
204
+ hir:: Node :: Ty ( hir:: Ty { kind: hir:: TyKind :: Ref ( ..) , .. } )
205
+ ) ;
206
+
207
+ // Suggestions for function return type.
192
208
if let hir:: FnRetTy :: Return ( ty) = sig. decl . output
193
- && ty. hir_id == self_ty. hir_id
209
+ && ty. peel_refs ( ) . hir_id == self_ty. hir_id
194
210
{
195
211
let pre = if !is_object_safe {
196
212
format ! ( "`{trait_name}` is not object safe, " )
@@ -201,14 +217,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
201
217
"{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \
202
218
single underlying type",
203
219
) ;
220
+
204
221
diag. multipart_suggestion_verbose ( msg, impl_sugg, Applicability :: MachineApplicable ) ;
222
+
223
+ // Suggest `Box<dyn Trait>` for return type
205
224
if is_object_safe {
206
- diag. multipart_suggestion_verbose (
207
- "alternatively, you can return an owned trait object" ,
225
+ // If the return type is `&Trait`, we don't want
226
+ // the ampersand to be displayed in the `Box<dyn Trait>`
227
+ // suggestion.
228
+ let suggestion = if borrowed {
229
+ vec ! [ ( ty. span, format!( "Box<dyn {trait_name}>" ) ) ]
230
+ } else {
208
231
vec ! [
209
232
( ty. span. shrink_to_lo( ) , "Box<dyn " . to_string( ) ) ,
210
233
( ty. span. shrink_to_hi( ) , ">" . to_string( ) ) ,
211
- ] ,
234
+ ]
235
+ } ;
236
+
237
+ diag. multipart_suggestion_verbose (
238
+ "alternatively, you can return an owned trait object" ,
239
+ suggestion,
212
240
Applicability :: MachineApplicable ,
213
241
) ;
214
242
} else if is_downgradable {
@@ -217,39 +245,43 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
217
245
}
218
246
return true ;
219
247
}
248
+
249
+ // Suggestions for function parameters.
220
250
for ty in sig. decl . inputs {
221
- if ty. hir_id != self_ty. hir_id {
251
+ if ty. peel_refs ( ) . hir_id != self_ty. hir_id {
222
252
continue ;
223
253
}
224
254
let sugg = self . add_generic_param_suggestion ( generics, self_ty. span , & trait_name) ;
225
- if !sugg. is_empty ( ) {
226
- diag. multipart_suggestion_verbose (
227
- format ! ( "use a new generic type parameter, constrained by `{trait_name}`" ) ,
228
- sugg,
229
- Applicability :: MachineApplicable ,
230
- ) ;
231
- diag. multipart_suggestion_verbose (
232
- "you can also use an opaque type, but users won't be able to specify the type \
233
- parameter when calling the `fn`, having to rely exclusively on type inference",
234
- impl_sugg,
235
- Applicability :: MachineApplicable ,
236
- ) ;
237
- }
255
+ diag. multipart_suggestion_verbose (
256
+ format ! ( "use a new generic type parameter, constrained by `{trait_name}`" ) ,
257
+ sugg,
258
+ Applicability :: MachineApplicable ,
259
+ ) ;
260
+ diag. multipart_suggestion_verbose (
261
+ "you can also use an opaque type, but users won't be able to specify the type \
262
+ parameter when calling the `fn`, having to rely exclusively on type inference",
263
+ impl_sugg,
264
+ Applicability :: MachineApplicable ,
265
+ ) ;
238
266
if !is_object_safe {
239
267
diag. note ( format ! ( "`{trait_name}` it is not object safe, so it can't be `dyn`" ) ) ;
240
268
if is_downgradable {
241
269
// We'll emit the object safety error already, with a structured suggestion.
242
270
diag. downgrade_to_delayed_bug ( ) ;
243
271
}
244
272
} else {
273
+ // No ampersand in suggestion if it's borrowed already
274
+ let ( dyn_str, paren_dyn_str) =
275
+ if borrowed { ( "dyn " , "(dyn " ) } else { ( "&dyn " , "&(dyn " ) } ;
276
+
245
277
let sugg = if let hir:: TyKind :: TraitObject ( [ _, _, ..] , _, _) = self_ty. kind {
246
278
// There are more than one trait bound, we need surrounding parentheses.
247
279
vec ! [
248
- ( self_ty. span. shrink_to_lo( ) , "&(dyn " . to_string( ) ) ,
280
+ ( self_ty. span. shrink_to_lo( ) , paren_dyn_str . to_string( ) ) ,
249
281
( self_ty. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
250
282
]
251
283
} else {
252
- vec ! [ ( self_ty. span. shrink_to_lo( ) , "&dyn " . to_string( ) ) ]
284
+ vec ! [ ( self_ty. span. shrink_to_lo( ) , dyn_str . to_string( ) ) ]
253
285
} ;
254
286
diag. multipart_suggestion_verbose (
255
287
format ! (
0 commit comments