Change:
The following compiles on the current nightly (1.67.0-nightly (2022-12-03 )) although it shouldn't: It is correctly rejected by the current beta: 1.66.0-beta.2 (2022-11-20 ). This is most likely (I haven't bisected though!). Cc label C-bug T-compiler I-unsound regression-from-stable-to-nightly A-impl-trait
WG-prioritization assigning priority (). label -I-prioritize +P-high

Discussion:
use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::query::Providers; <del> use rustc_middle::ty::{self, CrateVariancesMap, TyCtxt, TypeSuperVisitable, TypeVisitable}; </del> <ins> use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt}; use rustc_middle::ty::{DefIdTree, TypeSuperVisitable, TypeVisitable}; </ins> use std::ops::ControlFlow; /// Defines the `TermsContext` basically houses an arena where we can

// type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b; // ``` // we may not use `'c` in the hidden type. <del> struct OpaqueTypeLifetimeCollector { </del> <ins> struct OpaqueTypeLifetimeCollector<'tcx> { tcx: TyCtxt<'tcx>, root_def_id: DefId, </ins> variances: Vec<ty::Variance>, } <del> impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector { </del> <ins> impl<'tcx> OpaqueTypeLifetimeCollector<'tcx> { #[instrument(level = "trace", skip(self), ret)] fn visit_opaque(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> ControlFlow<!> { if def_id != self.root_def_id && self.tcx.is_descendant_of(def_id, self.root_def_id) { let child_variances = self.tcx.variances_of(def_id); for (a, v) in substs.iter().zip(child_variances) { if *v != ty::Bivariant { a.visit_with(self)?; } } ControlFlow::CONTINUE } else { substs.visit_with(self) } } } impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> { </ins> #[instrument(level = "trace", skip(self), ret)] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() {

} r.super_visit_with(self) } <ins> #[instrument(level = "trace", skip(self), ret)] fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { match t.kind() { ty::Opaque(def_id, substs) => self.visit_opaque(*def_id, substs), ty::Projection(proj) if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder => { self.visit_opaque(proj.item_def_id, proj.substs) } _ => t.super_visit_with(self), } } </ins> } // By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt

} } <del> let mut collector = OpaqueTypeLifetimeCollector { variances }; </del> <ins> let mut collector = OpaqueTypeLifetimeCollector { tcx, root_def_id: item_def_id.to_def_id(), variances }; </ins> let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id.to_def_id()); for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() { let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs);

<ins> // edition: 2021 fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> { async move { let _s = s; } //~^ ERROR hidden type for `impl Future<Output = impl Sized>` captures lifetime that does not appear in bounds } fn main() {} </ins>

<ins> error[E0700]: hidden type for `impl Future<Output = impl Sized>` captures lifetime that does not appear in bounds --> $DIR/nested-return-type4.rs:4:5 | LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> { |         -- hidden type `[async block@$DIR/nested-return-type4.rs:4:5: 4:31]` captures the lifetime `'s` as defined here LL |     async move { let _s = s; } |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: to declare that `impl Future<Output = impl Sized>` captures `'s`, you can add an explicit `'s` lifetime bound | LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> + 's { |                                                                              ++++ help: to declare that `impl Sized` captures `'s`, you can add an explicit `'s` lifetime bound | LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized + 's> { |                                                                             ++++ error: aborting due to previous error For more information about this error, try `rustc --explain E0700`. </ins>