diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 9fcebeb0acd..328f569bb74 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -845,7 +845,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { return; } - let Some((alias_tys, alias_span)) = self + let Some((alias_tys, alias_span, lt_addition_span)) = self .infcx .tcx .return_type_impl_or_dyn_traits_with_type_alias(suitable_region.def_id) else { return; }; @@ -858,10 +858,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { () } if let TyKind::TraitObject(_, lt, _) = alias_ty.kind { - spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string())); + if lt.ident.name == kw::Empty { + spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string())); + } else { + spans_suggs.push((lt.ident.span, "'a".to_string())); + } } } - spans_suggs.push((alias_span.shrink_to_hi(), "<'a>".to_string())); + + if let Some(lt_addition_span) = lt_addition_span { + spans_suggs.push((lt_addition_span, "'a, ".to_string())); + } else { + spans_suggs.push((alias_span.shrink_to_hi(), "<'a>".to_string())); + } + diag.multipart_suggestion_verbose( &format!( "to declare that the trait object {captures}, you can add a lifetime parameter `'a` in the type alias" diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4a4f6770fc4..cf388f3e855 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1116,11 +1116,13 @@ impl<'tcx> TyCtxt<'tcx> { v.0 } - /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type and associated alias span when type alias is used + /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in + /// its return type, and the associated alias span when type alias is used, + /// along with a span for lifetime suggestion (if there are existing generics). pub fn return_type_impl_or_dyn_traits_with_type_alias( self, scope_def_id: LocalDefId, - ) -> Option<(Vec<&'tcx hir::Ty<'tcx>>, Span)> { + ) -> Option<(Vec<&'tcx hir::Ty<'tcx>>, Span, Option)> { let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); let mut v = TraitObjectVisitor(vec![], self.hir()); // when the return type is a type alias @@ -1134,7 +1136,7 @@ impl<'tcx> TyCtxt<'tcx> { { v.visit_ty(alias_ty); if !v.0.is_empty() { - return Some((v.0, alias_generics.span)); + return Some((v.0, alias_generics.span, alias_generics.span_for_lifetime_suggestion())); } } return None; diff --git a/tests/ui/borrowck/suggest-lt-on-ty-alias-w-generics.rs b/tests/ui/borrowck/suggest-lt-on-ty-alias-w-generics.rs new file mode 100644 index 00000000000..c9e043577ed --- /dev/null +++ b/tests/ui/borrowck/suggest-lt-on-ty-alias-w-generics.rs @@ -0,0 +1,11 @@ +type Lazy = Box T + 'static>; + +fn test(x: &i32) -> Lazy { + Box::new(|| { + //~^ ERROR lifetime may not live long enough + //~| ERROR closure may outlive the current function + *x + }) +} + +fn main() {} diff --git a/tests/ui/borrowck/suggest-lt-on-ty-alias-w-generics.stderr b/tests/ui/borrowck/suggest-lt-on-ty-alias-w-generics.stderr new file mode 100644 index 00000000000..28b4b4aa290 --- /dev/null +++ b/tests/ui/borrowck/suggest-lt-on-ty-alias-w-generics.stderr @@ -0,0 +1,43 @@ +error: lifetime may not live long enough + --> $DIR/suggest-lt-on-ty-alias-w-generics.rs:4:5 + | +LL | fn test(x: &i32) -> Lazy { + | - let's call the lifetime of this reference `'1` +LL | / Box::new(|| { +LL | | +LL | | +LL | | *x +LL | | }) + | |______^ returning this value requires that `'1` must outlive `'static` + | +help: to declare that the trait object captures data from argument `x`, you can add a lifetime parameter `'a` in the type alias + | +LL | type Lazy<'a, T> = Box T + 'a>; + | +++ ~~ + +error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function + --> $DIR/suggest-lt-on-ty-alias-w-generics.rs:4:14 + | +LL | Box::new(|| { + | ^^ may outlive borrowed value `x` +... +LL | *x + | -- `x` is borrowed here + | +note: closure is returned here + --> $DIR/suggest-lt-on-ty-alias-w-generics.rs:4:5 + | +LL | / Box::new(|| { +LL | | +LL | | +LL | | *x +LL | | }) + | |______^ +help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword + | +LL | Box::new(move || { + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0373`.