@@ -133,9 +133,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
133133 return ;
134134 } ;
135135 let sugg = self . add_generic_param_suggestion ( generics, self_ty. span , & impl_trait_name) ;
136- if sugg. is_empty ( ) {
137- return ;
138- } ;
139136 diag. multipart_suggestion (
140137 format ! (
141138 "alternatively use a blanket implementation to implement `{of_trait_name}` for \
@@ -170,6 +167,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
170167 let parent_id = tcx. hir ( ) . get_parent_item ( self_ty. hir_id ) . def_id ;
171168 // FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0<Ty = Trait1>`
172169 // 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
173174 let ( sig, generics, owner) = match tcx. hir_node_by_def_id ( parent_id) {
174175 hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Fn ( sig, generics, _) , .. } ) => {
175176 ( sig, generics, None )
@@ -180,13 +181,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
180181 owner_id,
181182 ..
182183 } ) => ( 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 ( ) ) ) ) ,
183190 _ => return false ,
184191 } ;
185192 let Ok ( trait_name) = tcx. sess . source_map ( ) . span_to_snippet ( self_ty. span ) else {
186193 return false ;
187194 } ;
188195 let impl_sugg = vec ! [ ( self_ty. span. shrink_to_lo( ) , "impl " . to_string( ) ) ] ;
189196 let mut is_downgradable = true ;
197+
198+ // Check if trait object is safe for suggesting dynamic dispatch.
190199 let is_object_safe = match self_ty. kind {
191200 hir:: TyKind :: TraitObject ( objects, ..) => {
192201 objects. iter ( ) . all ( |( o, _) | match o. trait_ref . path . res {
@@ -202,8 +211,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
202211 }
203212 _ => false ,
204213 } ;
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.
205221 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
207223 {
208224 let pre = if !is_object_safe {
209225 format ! ( "`{trait_name}` is not object safe, " )
@@ -214,14 +230,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
214230 "{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \
215231 single underlying type",
216232 ) ;
233+
217234 diag. multipart_suggestion_verbose ( msg, impl_sugg, Applicability :: MachineApplicable ) ;
235+
236+ // Suggest `Box<dyn Trait>` for return type
218237 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 {
221244 vec ! [
222245 ( ty. span. shrink_to_lo( ) , "Box<dyn " . to_string( ) ) ,
223246 ( 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,
225253 Applicability :: MachineApplicable ,
226254 ) ;
227255 } else if is_downgradable {
@@ -230,39 +258,43 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
230258 }
231259 return true ;
232260 }
261+
262+ // Suggestions for function parameters.
233263 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 {
235265 continue ;
236266 }
237267 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+ ) ;
251279 if !is_object_safe {
252280 diag. note ( format ! ( "`{trait_name}` it is not object safe, so it can't be `dyn`" ) ) ;
253281 if is_downgradable {
254282 // We'll emit the object safety error already, with a structured suggestion.
255283 diag. downgrade_to_delayed_bug ( ) ;
256284 }
257285 } 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+
258290 let sugg = if let hir:: TyKind :: TraitObject ( [ _, _, ..] , _, _) = self_ty. kind {
259291 // There are more than one trait bound, we need surrounding parentheses.
260292 vec ! [
261- ( self_ty. span. shrink_to_lo( ) , "&(dyn " . to_string( ) ) ,
293+ ( self_ty. span. shrink_to_lo( ) , paren_dyn_str . to_string( ) ) ,
262294 ( self_ty. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
263295 ]
264296 } else {
265- vec ! [ ( self_ty. span. shrink_to_lo( ) , "&dyn " . to_string( ) ) ]
297+ vec ! [ ( self_ty. span. shrink_to_lo( ) , dyn_str . to_string( ) ) ]
266298 } ;
267299 diag. multipart_suggestion_verbose (
268300 format ! (
0 commit comments