]> git.lizzy.rs Git - rust.git/commitdiff
Account for multiple impl/dyn Trait in return type when suggesting `'_`
authorEsteban Küber <esteban@kuber.com.ar>
Tue, 9 Jun 2020 20:57:33 +0000 (13:57 -0700)
committerEsteban Küber <esteban@kuber.com.ar>
Fri, 19 Jun 2020 20:40:51 +0000 (13:40 -0700)
12 files changed:
src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs
src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs
src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
src/librustc_middle/ty/context.rs
src/librustc_middle/ty/diagnostics.rs
src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr [new file with mode: 0644]
src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs [new file with mode: 0644]
src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr [new file with mode: 0644]

index de71363cbde5ccfad45d91fa688d294f74666695..6677c0e59f63a9e5cd6a0554ed0f212078e6fcde 100644 (file)
@@ -26,7 +26,7 @@ pub(super) fn find_anon_type(
         &self,
         region: Region<'tcx>,
         br: &ty::BoundRegion,
-    ) -> Option<(&hir::Ty<'_>, &hir::FnDecl<'_>)> {
+    ) -> Option<(&hir::Ty<'tcx>, &hir::FnDecl<'tcx>)> {
         if let Some(anon_reg) = self.tcx().is_suitable_region(region) {
             let def_id = anon_reg.def_id;
             if let Some(def_id) = def_id.as_local() {
index a56401ebb90f089ecaecfe29bb2d18ff5f7c8b23..7c8ba834dcdcba9b631119f8e486860a22b82303 100644 (file)
@@ -2,7 +2,8 @@
 //! where one region is named and the other is anonymous.
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
-use rustc_hir::{FnRetTy, TyKind};
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::FnRetTy;
 use rustc_middle::ty;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@@ -80,12 +81,16 @@ pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<
             }
 
             if let FnRetTy::Return(ty) = &fndecl.output {
-                let mut v = ty::TraitObjectVisitor(vec![]);
-                rustc_hir::intravisit::walk_ty(&mut v, ty);
+                let mut v = ty::TraitObjectVisitor(vec![], self.tcx().hir());
+                v.visit_ty(ty);
 
                 debug!("try_report_named_anon_conflict: ret ty {:?}", ty);
                 if sub == &ty::ReStatic
-                    && (matches!(ty.kind, TyKind::OpaqueDef(_, _)) || v.0.len() == 1)
+                    && v.0
+                        .into_iter()
+                        .filter(|t| t.span.desugaring_kind().is_none())
+                        .next()
+                        .is_some()
                 {
                     debug!("try_report_named_anon_conflict: impl Trait + 'static");
                     // This is an `impl Trait` or `dyn Trait` return that evaluates de need of
index 82feebc80292a27476089da8f8cfbc7b271fdec5..20b275ea34af0694286f306fffc59b15b2c93a79 100644 (file)
@@ -26,8 +26,11 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
                 );
                 let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
                 debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
-                let fn_return = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
-                debug!("try_report_static_impl_trait: fn_return={:?}", fn_return);
+                let fn_returns = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id);
+                if fn_returns.is_empty() {
+                    return None;
+                }
+                debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
                 if **sub_r == RegionKind::ReStatic {
                     let sp = var_origin.span();
                     let return_sp = sub_origin.span();
@@ -98,25 +101,26 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
                         );
                     }
 
-                    // only apply this suggestion onto functions with
-                    // explicit non-desugar'able return.
-                    if fn_return.span.desugaring_kind().is_none() {
-                        // FIXME: account for the need of parens in `&(dyn Trait + '_)`
-
-                        let consider = "consider changing the";
-                        let declare = "to declare that the";
-                        let arg = match param_info.param.pat.simple_ident() {
-                            Some(simple_ident) => format!("argument `{}`", simple_ident),
-                            None => "the argument".to_string(),
-                        };
-                        let explicit =
-                            format!("you can add an explicit `{}` lifetime bound", lifetime_name);
-                        let explicit_static =
-                            format!("explicit `'static` bound to the lifetime of {}", arg);
-                        let captures = format!("captures data from {}", arg);
-                        let add_static_bound =
-                            "alternatively, add an explicit `'static` bound to this reference";
-                        let plus_lt = format!(" + {}", lifetime_name);
+                    // FIXME: account for the need of parens in `&(dyn Trait + '_)`
+                    let consider = "consider changing the";
+                    let declare = "to declare that the";
+                    let arg = match param_info.param.pat.simple_ident() {
+                        Some(simple_ident) => format!("argument `{}`", simple_ident),
+                        None => "the argument".to_string(),
+                    };
+                    let explicit =
+                        format!("you can add an explicit `{}` lifetime bound", lifetime_name);
+                    let explicit_static =
+                        format!("explicit `'static` bound to the lifetime of {}", arg);
+                    let captures = format!("captures data from {}", arg);
+                    let add_static_bound =
+                        "alternatively, add an explicit `'static` bound to this reference";
+                    let plus_lt = format!(" + {}", lifetime_name);
+                    for fn_return in fn_returns {
+                        if fn_return.span.desugaring_kind().is_some() {
+                            // Skip `async` desugaring `impl Future`.
+                            continue;
+                        }
                         match fn_return.kind {
                             TyKind::OpaqueDef(item_id, _) => {
                                 let item = self.tcx().hir().item(item_id.id);
@@ -143,7 +147,7 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
                                     err.span_suggestion_verbose(
                                         span,
                                         &format!("{} `impl Trait`'s {}", consider, explicit_static),
-                                        lifetime_name,
+                                        lifetime_name.clone(),
                                         Applicability::MaybeIncorrect,
                                     );
                                     err.span_suggestion_verbose(
@@ -152,6 +156,19 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
                                         param_info.param_ty.to_string(),
                                         Applicability::MaybeIncorrect,
                                     );
+                                } else if let Some(_) = opaque
+                                    .bounds
+                                    .iter()
+                                    .filter_map(|arg| match arg {
+                                        GenericBound::Outlives(Lifetime { name, span, .. })
+                                            if name.ident().to_string() == lifetime_name =>
+                                        {
+                                            Some(*span)
+                                        }
+                                        _ => None,
+                                    })
+                                    .next()
+                                {
                                 } else {
                                     err.span_suggestion_verbose(
                                         fn_return.span.shrink_to_hi(),
@@ -161,10 +178,10 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
                                             captures = captures,
                                             explicit = explicit,
                                         ),
-                                        plus_lt,
+                                        plus_lt.clone(),
                                         Applicability::MaybeIncorrect,
                                     );
-                                };
+                                }
                             }
                             TyKind::TraitObject(_, lt) => match lt.name {
                                 LifetimeName::ImplicitObjectLifetimeDefault => {
@@ -176,15 +193,19 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
                                             captures = captures,
                                             explicit = explicit,
                                         ),
-                                        plus_lt,
+                                        plus_lt.clone(),
                                         Applicability::MaybeIncorrect,
                                     );
                                 }
-                                _ => {
+                                name if name.ident().to_string() != lifetime_name => {
+                                    // With this check we avoid suggesting redundant bounds. This
+                                    // would happen if there are nested impl/dyn traits and only
+                                    // one of them has the bound we'd suggest already there, like
+                                    // in `impl Foo<X = dyn Bar> + '_`.
                                     err.span_suggestion_verbose(
                                         lt.span,
                                         &format!("{} trait object's {}", consider, explicit_static),
-                                        lifetime_name,
+                                        lifetime_name.clone(),
                                         Applicability::MaybeIncorrect,
                                     );
                                     err.span_suggestion_verbose(
@@ -194,6 +215,7 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
                                         Applicability::MaybeIncorrect,
                                     );
                                 }
+                                _ => {}
                             },
                             _ => {}
                         }
index 62d6de2d71e6ddb10f6789b5a0923034bce2c795..73374bb1e844316318d6b7b6ca61b48d105e8762 100644 (file)
@@ -37,6 +37,7 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::{DefPathHash, Definitions};
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::{self, PanicLocationLangItem};
 use rustc_hir::{HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate};
 use rustc_index::vec::{Idx, IndexVec};
@@ -1405,10 +1406,7 @@ pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo>
         })
     }
 
-    pub fn return_type_impl_or_dyn_trait(
-        &self,
-        scope_def_id: DefId,
-    ) -> Option<&'tcx hir::Ty<'tcx>> {
+    pub fn return_type_impl_or_dyn_trait(&self, scope_def_id: DefId) -> Vec<&'tcx hir::Ty<'tcx>> {
         let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local());
         let hir_output = match self.hir().get(hir_id) {
             Node::Item(hir::Item {
@@ -1444,30 +1442,12 @@ pub fn return_type_impl_or_dyn_trait(
                     ),
                 ..
             }) => ty,
-            _ => return None,
+            _ => return vec![],
         };
 
-        let ret_ty = self.type_of(scope_def_id);
-        match ret_ty.kind {
-            ty::FnDef(_, _) => {
-                let sig = ret_ty.fn_sig(*self);
-                let output = self.erase_late_bound_regions(&sig.output());
-                if output.is_impl_trait() {
-                    let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap();
-                    if let hir::FnRetTy::Return(ty) = fn_decl.output {
-                        return Some(ty);
-                    }
-                } else {
-                    let mut v = TraitObjectVisitor(vec![]);
-                    rustc_hir::intravisit::walk_ty(&mut v, hir_output);
-                    if v.0.len() == 1 {
-                        return Some(v.0[0]);
-                    }
-                }
-                None
-            }
-            _ => None,
-        }
+        let mut v = TraitObjectVisitor(vec![], self.hir());
+        v.visit_ty(hir_output);
+        v.0
     }
 
     pub fn return_type_impl_trait(&self, scope_def_id: DefId) -> Option<(Ty<'tcx>, Span)> {
index a2812e117ed39571f9e7e154bfdf27c4f1237143..b22727bdd7587b71848ce692971577f2cf1cdc3c 100644 (file)
@@ -236,7 +236,9 @@ pub fn suggest_constraining_type_param(
     }
 }
 
-pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>);
+/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
+pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);
+
 impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
     type Map = rustc_hir::intravisit::ErasedMap<'v>;
 
@@ -245,15 +247,24 @@ fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
     }
 
     fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
-        if let hir::TyKind::TraitObject(
-            _,
-            hir::Lifetime {
-                name: hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
-                ..
-            },
-        ) = ty.kind
-        {
-            self.0.push(ty);
+        match ty.kind {
+            hir::TyKind::TraitObject(
+                _,
+                hir::Lifetime {
+                    name:
+                        hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
+                    ..
+                },
+            ) => {
+                self.0.push(ty);
+            }
+            hir::TyKind::OpaqueDef(item_id, _) => {
+                self.0.push(ty);
+                let item = self.1.expect_item(item_id.id);
+                hir::intravisit::walk_item(self, item);
+            }
+            _ => {}
         }
+        hir::intravisit::walk_ty(self, ty);
     }
 }
index ca9ca8a9debe2a62dfee8a8b31a77f81506bb096..3b339c5c3d7fc69a75c6a1f00338b8b8a748f2f2 100644 (file)
@@ -53,7 +53,15 @@ LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
    |               help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
 
 error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:33:69
+  --> $DIR/must_outlive_least_region_or_bound.rs:30:24
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+   |               -        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
+   |               |
+   |               let's call the lifetime of this reference `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/must_outlive_least_region_or_bound.rs:37:69
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |               -- lifetime `'a` defined here                         ^ returning this value requires that `'a` must outlive `'static`
@@ -62,7 +70,7 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    = help: consider replacing `'a` with `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:38:61
+  --> $DIR/must_outlive_least_region_or_bound.rs:42:61
    |
 LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
    |                          --  -- lifetime `'b` defined here  ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
@@ -72,14 +80,14 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
    = help: consider adding the following bound: `'b: 'a`
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:43:51
+  --> $DIR/must_outlive_least_region_or_bound.rs:47:51
    |
 LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
    |                                                   ^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `T: 'static`...
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0310, E0621.
 For more information about an error, try `rustc --explain E0310`.
index 837244b022721c266bd9353b960e2e2b961daf7e..9bf86fa66cdeda4c7ccd2cd6a55d18a2fbdc570a 100644 (file)
@@ -27,6 +27,10 @@ fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
 fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
 //~^ ERROR cannot infer an appropriate lifetime
 
+fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+//~^ ERROR cannot infer an appropriate lifetime
+//~| ERROR cannot infer an appropriate lifetime
+
 trait LifetimeTrait<'a> {}
 impl<'a> LifetimeTrait<'a> for &'a i32 {}
 
index e1fa4f02b6fcf770f2585118eae9c58c507983f4..ffadcaae08e05ed165636b369249098c140a5f37 100644 (file)
@@ -87,13 +87,48 @@ LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
    |               help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
 
 error[E0759]: cannot infer an appropriate lifetime
-  --> $DIR/must_outlive_least_region_or_bound.rs:33:69
+  --> $DIR/must_outlive_least_region_or_bound.rs:30:65
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+   |               ---- this data with an anonymous lifetime `'_`... ^ ...is captured here, requiring it to live as long as `'static`
+   |
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug + '_>, impl Debug) { (Box::new(x), x) }
+   |                                       ^^^^
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
+   |                                                    ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/must_outlive_least_region_or_bound.rs:30:69
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+   |               ---- this data with an anonymous lifetime `'_`...     ^ ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/must_outlive_least_region_or_bound.rs:30:41
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+   |                                         ^^^^^^^^^^
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug + '_>, impl Debug) { (Box::new(x), x) }
+   |                                       ^^^^
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
+   |                                                    ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/must_outlive_least_region_or_bound.rs:37:69
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |                      ------- this data with lifetime `'a`...        ^ ...is captured here...
    |
 note: ...and is required to live as long as `'static` here
-  --> $DIR/must_outlive_least_region_or_bound.rs:33:34
+  --> $DIR/must_outlive_least_region_or_bound.rs:37:34
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -107,7 +142,7 @@ LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x
    |                      ^^^^^^^^^^^^
 
 error[E0623]: lifetime mismatch
-  --> $DIR/must_outlive_least_region_or_bound.rs:38:61
+  --> $DIR/must_outlive_least_region_or_bound.rs:42:61
    |
 LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
    |                                                 -------     ^^^^^^^^^^^^^^^^
@@ -116,7 +151,7 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
    |                                                 this parameter and the return type are declared with different lifetimes...
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:43:51
+  --> $DIR/must_outlive_least_region_or_bound.rs:47:51
    |
 LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
    |                                 --                ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
@@ -181,7 +216,7 @@ help: alternatively, add an explicit `'static` bound to this reference
 LL | fn explicit4<'a>(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) }
    |                     ^^^^^^^^^^^^
 
-error: aborting due to 12 previous errors
+error: aborting due to 14 previous errors
 
 Some errors have detailed explanations: E0310, E0621, E0623, E0759.
 For more information about an error, try `rustc --explain E0310`.
index 88bd990b1e81b095e1c01ce8da9f0802b787ff90..f2fbb0ba7d7556738dd6951afe48ea920e2553d7 100644 (file)
@@ -6,6 +6,11 @@ LL |     async fn f(self: Pin<&Self>) -> impl Clone { self }
    |                |     |
    |                |     this data with an anonymous lifetime `'_`...
    |                ...is captured here...
+   |
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
+   |
+LL |     async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
+   |                                                ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr
new file mode 100644 (file)
index 0000000..2407d13
--- /dev/null
@@ -0,0 +1,53 @@
+error: lifetime may not live long enough
+  --> $DIR/trait-object-nested-in-impl-trait.rs:27:23
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |             -         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
+   |             |
+   |             let's call the lifetime of this reference `'1`
+   |
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lifetime may not live long enough
+  --> $DIR/trait-object-nested-in-impl-trait.rs:39:9
+   |
+LL |       fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+   |               - let's call the lifetime of this reference `'1`
+LL | /         Iter {
+LL | |             current: None,
+LL | |             remaining: self.0.iter(),
+LL | |         }
+   | |_________^ returning this value requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/trait-object-nested-in-impl-trait.rs:50:9
+   |
+LL |       fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+   |               -- lifetime `'a` defined here
+LL | /         Iter {
+LL | |             current: None,
+LL | |             remaining: self.0.iter(),
+LL | |         }
+   | |_________^ returning this value requires that `'a` must outlive `'static`
+   |
+   = help: consider replacing `'a` with `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/trait-object-nested-in-impl-trait.rs:60:30
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |             --               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
+   |             |
+   |             lifetime `'a` defined here
+   |
+   = help: consider replacing `'a` with `'static`
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs
new file mode 100644 (file)
index 0000000..f78edb1
--- /dev/null
@@ -0,0 +1,68 @@
+trait Foo {}
+impl<'a, T: Foo> Foo for &'a T {}
+impl<T: Foo + ?Sized> Foo for Box<T> {}
+
+struct Iter<'a, T> {
+    current: Option<Box<dyn Foo + 'a>>,
+    remaining: T,
+}
+
+impl<'a, T> Iterator for Iter<'a, T>
+where
+    T: Iterator,
+    T::Item: Foo + 'a,
+{
+    type Item = Box<dyn Foo + 'a>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let result = self.current.take();
+        self.current = Box::new(self.remaining.next()).map(|f| Box::new(f) as _);
+        result
+    }
+}
+
+struct Bar(Vec<Box<dyn Foo>>);
+
+impl Bar {
+    fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+        Iter {
+            current: None,
+            remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+        }
+    }
+}
+
+struct Baz(Vec<Box<dyn Foo>>);
+
+impl Baz {
+    fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+        Iter {
+            current: None,
+            remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+        }
+    }
+}
+
+struct Bat(Vec<Box<dyn Foo>>);
+
+impl Bat {
+    fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+        Iter {
+            current: None,
+            remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+        }
+    }
+}
+
+struct Ban(Vec<Box<dyn Foo>>);
+
+impl Ban {
+    fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+        Iter {
+            current: None,
+            remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr
new file mode 100644 (file)
index 0000000..1257e9b
--- /dev/null
@@ -0,0 +1,95 @@
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/trait-object-nested-in-impl-trait.rs:30:31
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |             ----- this data with an anonymous lifetime `'_`...
+...
+LL |             remaining: self.0.iter(),
+   |                        ------ ^^^^
+   |                        |
+   |                        ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/trait-object-nested-in-impl-trait.rs:27:23
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+   |                                                          ^^^^
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> {
+   |                                                        ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/trait-object-nested-in-impl-trait.rs:41:31
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+   |             ----- this data with an anonymous lifetime `'_`...
+...
+LL |             remaining: self.0.iter(),
+   |                        ------ ^^^^
+   |                        |
+   |                        ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/trait-object-nested-in-impl-trait.rs:38:23
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> + '_ {
+   |                                                        ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/trait-object-nested-in-impl-trait.rs:52:31
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+   |                 -------- this data with lifetime `'a`...
+...
+LL |             remaining: self.0.iter(),
+   |                        ------ ^^^^
+   |                        |
+   |                        ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/trait-object-nested-in-impl-trait.rs:49:30
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> + 'a {
+   |                                                               ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/trait-object-nested-in-impl-trait.rs:63:31
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |                 -------- this data with lifetime `'a`...
+...
+LL |             remaining: self.0.iter(),
+   |                        ------ ^^^^
+   |                        |
+   |                        ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/trait-object-nested-in-impl-trait.rs:60:30
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+   |                                                                 ^^^^
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> {
+   |                                                               ^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0759`.