Also collect bounds from the ParamEnv for opaque types
This commit is contained in:
parent
37928f5986
commit
90b6744af7
4 changed files with 34 additions and 59 deletions
|
@ -318,7 +318,7 @@ where
|
||||||
);
|
);
|
||||||
|
|
||||||
let generic = GenericKind::Param(param_ty);
|
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);
|
self.delegate.push_verify(origin, generic, region, verify_bound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,7 +476,12 @@ where
|
||||||
// projection outlive; in some cases, this may add insufficient
|
// projection outlive; in some cases, this may add insufficient
|
||||||
// edges into the inference graph, leading to inference failures
|
// edges into the inference graph, leading to inference failures
|
||||||
// even though a satisfactory solution exists.
|
// 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);
|
debug!("projection_must_outlive: pushing {:?}", verify_bound);
|
||||||
self.delegate.push_verify(origin, generic, region, verify_bound);
|
self.delegate.push_verify(origin, generic, region, verify_bound);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,21 +38,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||||
Self { tcx, region_bound_pairs, implicit_region_bound, param_env }
|
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))]
|
#[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
|
// Start with anything like `T: 'a` we can scrape from the
|
||||||
// environment. If the environment contains something like
|
// environment. If the environment contains something like
|
||||||
// `for<'a> T: 'a`, then we know that `T` outlives everything.
|
// `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))]
|
#[instrument(level = "debug", skip(self, visited))]
|
||||||
fn projection_bound(
|
pub fn projection_opaque_bounds(
|
||||||
&self,
|
&self,
|
||||||
projection_ty: ty::ProjectionTy<'tcx>,
|
generic: GenericKind<'tcx>,
|
||||||
|
def_id: DefId,
|
||||||
|
substs: SubstsRef<'tcx>,
|
||||||
visited: &mut SsoHashSet<GenericArg<'tcx>>,
|
visited: &mut SsoHashSet<GenericArg<'tcx>>,
|
||||||
) -> VerifyBound<'tcx> {
|
) -> VerifyBound<'tcx> {
|
||||||
let projection_ty_as_ty =
|
let generic_ty = generic.to_ty(self.tcx);
|
||||||
self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
|
|
||||||
|
|
||||||
// Search the env for where clauses like `P: 'a`.
|
// Search the env for where clauses like `P: 'a`.
|
||||||
let env_bounds = self
|
let projection_opaque_bounds = self
|
||||||
.approx_declared_bounds_from_env(GenericKind::Projection(projection_ty))
|
.approx_declared_bounds_from_env(generic)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|binder| {
|
.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
|
// Micro-optimize if this is an exact match (this
|
||||||
// occurs often when there are no region variables
|
// occurs often when there are no region variables
|
||||||
// involved).
|
// involved).
|
||||||
|
@ -139,35 +127,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||||
VerifyBound::IfEq(verify_if_eq_b)
|
VerifyBound::IfEq(verify_if_eq_b)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Extend with bounds that we can find from the trait.
|
// Extend with bounds that we can find from the trait.
|
||||||
let trait_bounds = self
|
let trait_bounds = self.bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r));
|
||||||
.bounds(projection_ty.item_def_id, projection_ty.substs)
|
|
||||||
.map(|r| VerifyBound::OutlivedBy(r));
|
|
||||||
|
|
||||||
// see the extensive comment in projection_must_outlive
|
// see the extensive comment in projection_must_outlive
|
||||||
let recursive_bound = {
|
let recursive_bound = {
|
||||||
let mut components = smallvec![];
|
let mut components = smallvec![];
|
||||||
let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
|
compute_components_recursive(self.tcx, generic_ty.into(), &mut components, visited);
|
||||||
compute_components_recursive(self.tcx, ty.into(), &mut components, visited);
|
|
||||||
self.bound_from_components(&components, visited)
|
self.bound_from_components(&components, visited)
|
||||||
};
|
};
|
||||||
|
|
||||||
VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
|
VerifyBound::AnyBound(projection_opaque_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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bound_from_components(
|
fn bound_from_components(
|
||||||
|
@ -199,8 +170,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||||
match *component {
|
match *component {
|
||||||
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
|
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
|
||||||
Component::Param(param_ty) => self.param_bound(param_ty),
|
Component::Param(param_ty) => self.param_bound(param_ty),
|
||||||
Component::Opaque(did, substs) => self.opaque_bound(did, substs),
|
Component::Opaque(did, substs) => self.projection_opaque_bounds(
|
||||||
Component::Projection(projection_ty) => self.projection_bound(projection_ty, visited),
|
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) => {
|
Component::EscapingProjection(ref components) => {
|
||||||
self.bound_from_components(components, visited)
|
self.bound_from_components(components, visited)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
type Ty<'a, A> = impl Sized + 'a;
|
type Ty<'a, A> = impl Sized + 'a;
|
||||||
fn defining<'a, A>() -> Ty<'a, A> {}
|
fn defining<'a, A>() -> Ty<'a, A> {}
|
||||||
fn assert_static<T: 'static>() {}
|
fn assert_static<T: 'static>() {}
|
||||||
fn test<'a, A>() where Ty<'a, A>: 'static, { assert_static::<Ty<'a, A>>() }
|
fn test<'a, A>() where Ty<'a, A>: 'static, { assert_static::<Ty<'a, A>>() }
|
||||||
//~^ ERROR: may not live long enough
|
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -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`.
|
|
Loading…
Add table
Add a link
Reference in a new issue