@@ -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