diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index ff23087fe8d8a..cb63d2f18b634 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -143,7 +143,7 @@ fn compute_components<'tcx>( // through and constrain Pi. let mut subcomponents = smallvec![]; let mut subvisited = SsoHashSet::new(); - compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited); + compute_alias_components_recursive(tcx, ty, &mut subcomponents, &mut subvisited); out.push(Component::EscapingAlias(subcomponents.into_iter().collect())); } } @@ -193,7 +193,43 @@ fn compute_components<'tcx>( /// /// This should not be used to get the components of `parent` itself. /// Use [push_outlives_components] instead. -pub(super) fn compute_components_recursive<'tcx>( +pub(super) fn compute_alias_components_recursive<'tcx>( + tcx: TyCtxt<'tcx>, + alias_ty: Ty<'tcx>, + out: &mut SmallVec<[Component<'tcx>; 4]>, + visited: &mut SsoHashSet>, +) { + let ty::Alias(kind, alias_ty) = alias_ty.kind() else { bug!() }; + let opt_variances = if *kind == ty::Opaque { tcx.variances_of(alias_ty.def_id) } else { &[] }; + for (index, child) in alias_ty.substs.iter().enumerate() { + if opt_variances.get(index) == Some(&ty::Bivariant) { + continue; + } + if !visited.insert(child) { + continue; + } + match child.unpack() { + GenericArgKind::Type(ty) => { + compute_components(tcx, ty, out, visited); + } + GenericArgKind::Lifetime(lt) => { + // Ignore late-bound regions. + if !lt.is_late_bound() { + out.push(Component::Region(lt)); + } + } + GenericArgKind::Const(_) => { + compute_components_recursive(tcx, child, out, visited); + } + } + } +} + +/// Collect [Component]s for *all* the substs of `parent`. +/// +/// This should not be used to get the components of `parent` itself. +/// Use [push_outlives_components] instead. +fn compute_components_recursive<'tcx>( tcx: TyCtxt<'tcx>, parent: GenericArg<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>, diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index ccf11c61b573b..2f5e2e417a6fd 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -344,12 +344,14 @@ where // the problem is to add `T: 'r`, which isn't true. So, if there are no // inference variables, we use a verify constraint instead of adding // edges, which winds up enforcing the same condition. + let is_opaque = alias_ty.kind(self.tcx) == ty::Opaque; if approx_env_bounds.is_empty() && trait_bounds.is_empty() - && (alias_ty.needs_infer() || alias_ty.kind(self.tcx) == ty::Opaque) + && (alias_ty.needs_infer() || is_opaque) { debug!("no declared bounds"); - self.substs_must_outlive(alias_ty.substs, origin, region); + let opt_variances = is_opaque.then(|| self.tcx.variances_of(alias_ty.def_id)); + self.substs_must_outlive(alias_ty.substs, origin, region, opt_variances); return; } @@ -395,22 +397,31 @@ where self.delegate.push_verify(origin, GenericKind::Alias(alias_ty), region, verify_bound); } + #[instrument(level = "debug", skip(self))] fn substs_must_outlive( &mut self, substs: SubstsRef<'tcx>, origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, + opt_variances: Option<&[ty::Variance]>, ) { let constraint = origin.to_constraint_category(); - for k in substs { + for (index, k) in substs.iter().enumerate() { match k.unpack() { GenericArgKind::Lifetime(lt) => { - self.delegate.push_sub_region_constraint( - origin.clone(), - region, - lt, - constraint, - ); + let variance = if let Some(variances) = opt_variances { + variances[index] + } else { + ty::Invariant + }; + if variance == ty::Invariant { + self.delegate.push_sub_region_constraint( + origin.clone(), + region, + lt, + constraint, + ); + } } GenericArgKind::Type(ty) => { self.type_must_outlive(origin.clone(), ty, region, constraint); diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index bae246418b05a..e1cb53bc71d33 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,4 +1,4 @@ -use crate::infer::outlives::components::{compute_components_recursive, Component}; +use crate::infer::outlives::components::{compute_alias_components_recursive, Component}; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::region_constraints::VerifyIfEq; use crate::infer::VerifyBound; @@ -130,7 +130,12 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // see the extensive comment in projection_must_outlive let recursive_bound = { let mut components = smallvec![]; - compute_components_recursive(self.tcx, alias_ty_as_ty.into(), &mut components, visited); + compute_alias_components_recursive( + self.tcx, + alias_ty_as_ty.into(), + &mut components, + visited, + ); self.bound_from_components(&components, visited) }; diff --git a/tests/ui/impl-trait/issue-108591.rs b/tests/ui/impl-trait/issue-108591.rs new file mode 100644 index 0000000000000..6b9d14941f237 --- /dev/null +++ b/tests/ui/impl-trait/issue-108591.rs @@ -0,0 +1,30 @@ +// check-pass + +#![feature(type_alias_impl_trait)] + +struct MyTy<'a>(Vec, &'a ()); + +impl MyTy<'_> { + fn one(&mut self) -> &mut impl Sized { + &mut self.0 + } + fn two(&mut self) -> &mut (impl Sized + 'static) { + self.one() + } +} + +type Opaque<'a> = impl Sized; +fn define<'a>() -> Opaque<'a> {} + +fn test<'a>() { + None::<&'static Opaque<'a>>; +} + +fn one<'a, 'b: 'b>() -> &'a impl Sized { + &() +} +fn two<'a, 'b>() { + one::<'a, 'b>(); +} + +fn main() {} diff --git a/tests/ui/impl-trait/issue-108592.rs b/tests/ui/impl-trait/issue-108592.rs new file mode 100644 index 0000000000000..58a0ed9bf1a18 --- /dev/null +++ b/tests/ui/impl-trait/issue-108592.rs @@ -0,0 +1,21 @@ +// check-pass +#![feature(type_alias_impl_trait)] + +fn opaque<'a: 'a>() -> impl Sized {} +fn assert_static(_: T) {} + +fn test_closure() { + let closure = |_| { + assert_static(opaque()); + }; + closure(&opaque()); +} + +type Opaque<'a> = impl Sized; +fn define<'a>() -> Opaque<'a> {} + +fn test_tait(_: &Opaque<'_>) { + None::<&'static Opaque<'_>>; +} + +fn main() {}