Skip to content

Commit

Permalink
Auto merge of rust-lang#110399 - cjgillot:infer-variance, r=aliemjay
Browse files Browse the repository at this point in the history
Account for opaque variance in outlives

Fixes rust-lang#108591
Fixes rust-lang#108592
cc `@aliemjay`
  • Loading branch information
bors committed Apr 20, 2023
2 parents dc73052 + 8fc1d68 commit 7fde083
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 13 deletions.
40 changes: 38 additions & 2 deletions compiler/rustc_infer/src/infer/outlives/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
}
}
Expand Down Expand Up @@ -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<GenericArg<'tcx>>,
) {
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]>,
Expand Down
29 changes: 20 additions & 9 deletions compiler/rustc_infer/src/infer/outlives/obligations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down
9 changes: 7 additions & 2 deletions compiler/rustc_infer/src/infer/outlives/verify.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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)
};

Expand Down
30 changes: 30 additions & 0 deletions tests/ui/impl-trait/issue-108591.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// check-pass

#![feature(type_alias_impl_trait)]

struct MyTy<'a>(Vec<u8>, &'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() {}
21 changes: 21 additions & 0 deletions tests/ui/impl-trait/issue-108592.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// check-pass
#![feature(type_alias_impl_trait)]

fn opaque<'a: 'a>() -> impl Sized {}
fn assert_static<T: '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() {}

0 comments on commit 7fde083

Please sign in to comment.