Also collect bounds from the ParamEnv for opaque types

This commit is contained in:
Oli Scherer 2022-05-19 12:18:16 +00:00
parent 37928f5986
commit 90b6744af7
4 changed files with 34 additions and 59 deletions

View file

@ -318,7 +318,7 @@ where
);
let generic = GenericKind::Param(param_ty);
let verify_bound = self.verify_bound.generic_bound(generic);
let verify_bound = self.verify_bound.param_bound(param_ty);
self.delegate.push_verify(origin, generic, region, verify_bound);
}
@ -476,7 +476,12 @@ where
// projection outlive; in some cases, this may add insufficient
// edges into the inference graph, leading to inference failures
// even though a satisfactory solution exists.
let verify_bound = self.verify_bound.generic_bound(generic);
let verify_bound = self.verify_bound.projection_opaque_bounds(
generic,
def_id,
substs,
&mut Default::default(),
);
debug!("projection_must_outlive: pushing {:?}", verify_bound);
self.delegate.push_verify(origin, generic, region, verify_bound);
}

View file

@ -38,21 +38,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
Self { tcx, region_bound_pairs, implicit_region_bound, param_env }
}
/// Returns a "verify bound" that encodes what we know about
/// `generic` and the regions it outlives.
pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> {
let mut visited = SsoHashSet::new();
match generic {
GenericKind::Param(param_ty) => self.param_bound(param_ty),
GenericKind::Projection(projection_ty) => {
self.projection_bound(projection_ty, &mut visited)
}
GenericKind::Opaque(def_id, substs) => self.opaque_bound(def_id, substs),
}
}
#[instrument(level = "debug", skip(self))]
fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
pub fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
// Start with anything like `T: 'a` we can scrape from the
// environment. If the environment contains something like
// `for<'a> T: 'a`, then we know that `T` outlives everything.
@ -116,20 +103,21 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
}
#[instrument(level = "debug", skip(self, visited))]
fn projection_bound(
pub fn projection_opaque_bounds(
&self,
projection_ty: ty::ProjectionTy<'tcx>,
generic: GenericKind<'tcx>,
def_id: DefId,
substs: SubstsRef<'tcx>,
visited: &mut SsoHashSet<GenericArg<'tcx>>,
) -> VerifyBound<'tcx> {
let projection_ty_as_ty =
self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
let generic_ty = generic.to_ty(self.tcx);
// Search the env for where clauses like `P: 'a`.
let env_bounds = self
.approx_declared_bounds_from_env(GenericKind::Projection(projection_ty))
let projection_opaque_bounds = self
.approx_declared_bounds_from_env(generic)
.into_iter()
.map(|binder| {
if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == projection_ty_as_ty {
if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == generic_ty {
// Micro-optimize if this is an exact match (this
// occurs often when there are no region variables
// involved).
@ -139,35 +127,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
VerifyBound::IfEq(verify_if_eq_b)
}
});
// Extend with bounds that we can find from the trait.
let trait_bounds = self
.bounds(projection_ty.item_def_id, projection_ty.substs)
.map(|r| VerifyBound::OutlivedBy(r));
let trait_bounds = self.bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r));
// see the extensive comment in projection_must_outlive
let recursive_bound = {
let mut components = smallvec![];
let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
compute_components_recursive(self.tcx, ty.into(), &mut components, visited);
compute_components_recursive(self.tcx, generic_ty.into(), &mut components, visited);
self.bound_from_components(&components, visited)
};
VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
}
fn opaque_bound(&self, def_id: DefId, substs: SubstsRef<'tcx>) -> VerifyBound<'tcx> {
let bounds: Vec<_> =
self.bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r)).collect();
trace!("{:#?}", bounds);
if bounds.is_empty() {
// No bounds means the value must not have any lifetimes.
// FIXME: should we implicitly add 'static to `tcx.item_bounds` for opaque types, just
// like we add `Sized`?
VerifyBound::OutlivedBy(self.tcx.lifetimes.re_static)
} else {
VerifyBound::AnyBound(bounds)
}
VerifyBound::AnyBound(projection_opaque_bounds.chain(trait_bounds).collect())
.or(recursive_bound)
}
fn bound_from_components(
@ -199,8 +170,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
match *component {
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
Component::Param(param_ty) => self.param_bound(param_ty),
Component::Opaque(did, substs) => self.opaque_bound(did, substs),
Component::Projection(projection_ty) => self.projection_bound(projection_ty, visited),
Component::Opaque(did, substs) => self.projection_opaque_bounds(
GenericKind::Opaque(did, substs),
did,
substs,
visited,
),
Component::Projection(projection_ty) => self.projection_opaque_bounds(
GenericKind::Projection(projection_ty),
projection_ty.item_def_id,
projection_ty.substs,
visited,
),
Component::EscapingProjection(ref components) => {
self.bound_from_components(components, visited)
}

View file

@ -1,9 +1,10 @@
// check-pass
#![feature(type_alias_impl_trait)]
type Ty<'a, A> = impl Sized + 'a;
fn defining<'a, A>() -> Ty<'a, A> {}
fn assert_static<T: 'static>() {}
fn test<'a, A>() where Ty<'a, A>: 'static, { assert_static::<Ty<'a, A>>() }
//~^ ERROR: may not live long enough
fn main() {}

View file

@ -1,12 +0,0 @@
error[E0310]: the opaque type `Ty<'_, A>::{opaque#0}` may not live long enough
--> $DIR/implied_bounds2.rs:6:46
|
LL | fn test<'a, A>() where Ty<'a, A>: 'static, { assert_static::<Ty<'a, A>>() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `Ty<'_, A>::{opaque#0}: 'static`...
= note: ...so that the type `Ty<'_, A>` will meet its required lifetime bounds
error: aborting due to previous error
For more information about this error, try `rustc --explain E0310`.