about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs16
-rw-r--r--compiler/rustc_middle/src/ty/context.rs8
-rw-r--r--tests/ui/borrowck/suggest-lt-on-ty-alias-w-generics.rs11
-rw-r--r--tests/ui/borrowck/suggest-lt-on-ty-alias-w-generics.stderr43
4 files changed, 72 insertions, 6 deletions
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<Span>)> {
         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<T> = Box<dyn Fn() -> T + 'static>;
+
+fn test(x: &i32) -> Lazy<i32> {
+    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<i32> {
+   |              - 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<dyn Fn() -> 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`.