@@ -359,8 +359,31 @@ fn report_mismatched_rpitit_signature<'tcx>(
359359 // the type before creating the diagnostic, we need to avoid this query. This is the
360360 // standard approach used elsewhere in the compiler for formatting types in suggestions
361361 // (e.g., see `rustc_hir_typeck/src/demand.rs`).
362- let return_ty_suggestion =
363- with_no_trimmed_paths ! ( with_types_for_signature!( format!( "{return_ty}" ) ) ) ;
362+ //
363+ // Reference-to-opaque types need special handling: when the trait return type is
364+ // e.g. `&(impl A + B)`, the default printer emits `&impl A + B`, which parses as the
365+ // ambiguous `(&impl A) + B` and triggers "ambiguous `+` in a type" once the
366+ // suggestion is applied (cf. https://github.com/rust-lang/rust/issues/144401). Wrap
367+ // the inner opaque in parens when its printed form contains `+`-joined bounds.
368+ // Bare `impl A + B` at the top level is already syntactically valid and is left
369+ // alone; this branch only triggers for references.
370+ let return_ty_suggestion = with_no_trimmed_paths ! ( with_types_for_signature!( {
371+ let printed = format!( "{return_ty}" ) ;
372+ if let ty:: Ref ( _, inner, _) = return_ty. kind( ) {
373+ let inner_printed = format!( "{inner}" ) ;
374+ if inner_printed. contains( " + " ) && printed. ends_with( & inner_printed) {
375+ // Splice parens around the opaque part, keeping the original
376+ // `&`/lifetime/mutability prefix verbatim from the existing printer.
377+ let prefix_len = printed. len( ) - inner_printed. len( ) ;
378+ let prefix = & printed[ ..prefix_len] ;
379+ format!( "{prefix}({inner_printed})" )
380+ } else {
381+ printed
382+ }
383+ } else {
384+ printed
385+ }
386+ } ) ) ;
364387
365388 let span = unmatched_bound. unwrap_or ( span) ;
366389 tcx. emit_node_span_lint (
0 commit comments