From 562f4967b4ce7e859b807fc022040bbb22d1f70e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Esteban=20K=C3=BCber?= Date: Tue, 9 Jun 2020 13:57:33 -0700 Subject: [PATCH] Account for multiple impl/dyn Trait in return type when suggesting `'_` --- .../nice_region_error/find_anon_type.rs | 2 +- .../nice_region_error/named_anon_conflict.rs | 13 ++- .../nice_region_error/static_impl_trait.rs | 76 +++++++++------ src/librustc_middle/ty/context.rs | 32 ++----- src/librustc_middle/ty/diagnostics.rs | 31 ++++-- ...t_outlive_least_region_or_bound.nll.stderr | 16 +++- .../must_outlive_least_region_or_bound.rs | 4 + .../must_outlive_least_region_or_bound.stderr | 45 ++++++++- ...types_pin_lifetime_impl_trait-async.stderr | 5 + ...ait-object-nested-in-impl-trait.nll.stderr | 53 +++++++++++ .../trait-object-nested-in-impl-trait.rs | 68 +++++++++++++ .../trait-object-nested-in-impl-trait.stderr | 95 +++++++++++++++++++ 12 files changed, 363 insertions(+), 77 deletions(-) create mode 100644 src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr create mode 100644 src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs create mode 100644 src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs index de71363cbde..6677c0e59f6 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -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() { diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs index a56401ebb90..7c8ba834dcd 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -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 Option { ); 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 { ); } - // 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 { 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 { 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 { 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 { 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 + '_`. 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 { Applicability::MaybeIncorrect, ); } + _ => {} }, _ => {} } diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 62d6de2d71e..73374bb1e84 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -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 }) } - 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)> { diff --git a/src/librustc_middle/ty/diagnostics.rs b/src/librustc_middle/ty/diagnostics.rs index a2812e117ed..b22727bdd75 100644 --- a/src/librustc_middle/ty/diagnostics.rs +++ b/src/librustc_middle/ty/diagnostics.rs @@ -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 { } 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); } } diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr index ca9ca8a9deb..3b339c5c3d7 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr @@ -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, 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(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`. diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs index 837244b0227..9bf86fa66cd 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs @@ -27,6 +27,10 @@ fn elided4(x: &i32) -> Box { Box::new(x) } fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } //~^ ERROR cannot infer an appropriate lifetime +fn elided5(x: &i32) -> (Box, 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 {} diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index e1fa4f02b6f..ffadcaae08e 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -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, 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, 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, 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, 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, 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, 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, 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(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 { 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`. diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index 88bd990b1e8..f2fbb0ba7d7 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -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 index 00000000000..2407d13714a --- /dev/null +++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr @@ -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> { + | - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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> + '_ { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/trait-object-nested-in-impl-trait.rs:39:9 + | +LL | fn iter(&self) -> impl Iterator> + '_ { + | - 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> + '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> { + | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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> + '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 index 00000000000..f78edb1c83a --- /dev/null +++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs @@ -0,0 +1,68 @@ +trait Foo {} +impl<'a, T: Foo> Foo for &'a T {} +impl Foo for Box {} + +struct Iter<'a, T> { + current: Option>, + remaining: T, +} + +impl<'a, T> Iterator for Iter<'a, T> +where + T: Iterator, + T::Item: Foo + 'a, +{ + type Item = Box; + + fn next(&mut self) -> Option { + let result = self.current.take(); + self.current = Box::new(self.remaining.next()).map(|f| Box::new(f) as _); + result + } +} + +struct Bar(Vec>); + +impl Bar { + fn iter(&self) -> impl Iterator> { + Iter { + current: None, + remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime + } + } +} + +struct Baz(Vec>); + +impl Baz { + fn iter(&self) -> impl Iterator> + '_ { + Iter { + current: None, + remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime + } + } +} + +struct Bat(Vec>); + +impl Bat { + fn iter<'a>(&'a self) -> impl Iterator> + 'a { + Iter { + current: None, + remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime + } + } +} + +struct Ban(Vec>); + +impl Ban { + fn iter<'a>(&'a self) -> impl Iterator> { + 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 index 00000000000..1257e9b172c --- /dev/null +++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr @@ -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> { + | ----- 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> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +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> + '_ { + | ^^^^ +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> { + | ^^^^ + +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/trait-object-nested-in-impl-trait.rs:41:31 + | +LL | fn iter(&self) -> impl Iterator> + '_ { + | ----- 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> + '_ { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +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> + '_ { + | ^^^^ + +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> + '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> + '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> + '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> { + | -------- 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> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +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> + '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> { + | ^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0759`. -- 2.44.0