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