Make regionck care about placeholders in outlives components
This commit is contained in:
parent
290fc68f2d
commit
8f267e2b87
16 changed files with 177 additions and 13 deletions
|
@ -2351,6 +2351,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
|
||||
let labeled_user_string = match bound_kind {
|
||||
GenericKind::Param(ref p) => format!("the parameter type `{p}`"),
|
||||
GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"),
|
||||
GenericKind::Alias(ref p) => match p.kind(self.tcx) {
|
||||
ty::AliasKind::Projection | ty::AliasKind::Inherent => {
|
||||
format!("the associated type `{p}`")
|
||||
|
|
|
@ -11,6 +11,7 @@ use smallvec::{smallvec, SmallVec};
|
|||
pub enum Component<'tcx> {
|
||||
Region(ty::Region<'tcx>),
|
||||
Param(ty::ParamTy),
|
||||
Placeholder(ty::PlaceholderType),
|
||||
UnresolvedInferenceVariable(ty::InferTy),
|
||||
|
||||
// Projections like `T::Foo` are tricky because a constraint like
|
||||
|
@ -120,6 +121,10 @@ fn compute_components<'tcx>(
|
|||
out.push(Component::Param(p));
|
||||
}
|
||||
|
||||
ty::Placeholder(p) => {
|
||||
out.push(Component::Placeholder(p));
|
||||
}
|
||||
|
||||
// For projections, we prefer to generate an obligation like
|
||||
// `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
|
||||
// regionck more ways to prove that it holds. However,
|
||||
|
@ -176,7 +181,6 @@ fn compute_components<'tcx>(
|
|||
ty::Tuple(..) | // ...
|
||||
ty::FnPtr(_) | // OutlivesFunction (*)
|
||||
ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*)
|
||||
ty::Placeholder(..) |
|
||||
ty::Bound(..) |
|
||||
ty::Error(_) => {
|
||||
// (*) Function pointers and trait objects are both binders.
|
||||
|
|
|
@ -243,6 +243,9 @@ where
|
|||
Component::Param(param_ty) => {
|
||||
self.param_ty_must_outlive(origin, region, *param_ty);
|
||||
}
|
||||
Component::Placeholder(placeholder_ty) => {
|
||||
self.placeholder_ty_must_outlive(origin, region, *placeholder_ty);
|
||||
}
|
||||
Component::Alias(alias_ty) => self.alias_ty_must_outlive(origin, region, *alias_ty),
|
||||
Component::EscapingAlias(subcomponents) => {
|
||||
self.components_must_outlive(origin, &subcomponents, region, category);
|
||||
|
@ -267,10 +270,28 @@ where
|
|||
region: ty::Region<'tcx>,
|
||||
param_ty: ty::ParamTy,
|
||||
) {
|
||||
let verify_bound = self.verify_bound.param_bound(param_ty);
|
||||
let verify_bound = self.verify_bound.param_or_placeholder_bound(param_ty.to_ty(self.tcx));
|
||||
self.delegate.push_verify(origin, GenericKind::Param(param_ty), region, verify_bound);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn placeholder_ty_must_outlive(
|
||||
&mut self,
|
||||
origin: infer::SubregionOrigin<'tcx>,
|
||||
region: ty::Region<'tcx>,
|
||||
placeholder_ty: ty::PlaceholderType,
|
||||
) {
|
||||
let verify_bound = self
|
||||
.verify_bound
|
||||
.param_or_placeholder_bound(Ty::new_placeholder(self.tcx, placeholder_ty));
|
||||
self.delegate.push_verify(
|
||||
origin,
|
||||
GenericKind::Placeholder(placeholder_ty),
|
||||
region,
|
||||
verify_bound,
|
||||
);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn alias_ty_must_outlive(
|
||||
&mut self,
|
||||
|
|
|
@ -37,11 +37,11 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
|
||||
pub fn param_or_placeholder_bound(&self, ty: Ty<'tcx>) -> 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.
|
||||
let declared_bounds_from_env = self.declared_generic_bounds_from_env(param_ty);
|
||||
let declared_bounds_from_env = self.declared_generic_bounds_from_env(ty);
|
||||
debug!(?declared_bounds_from_env);
|
||||
let mut param_bounds = vec![];
|
||||
for declared_bound in declared_bounds_from_env {
|
||||
|
@ -51,7 +51,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||
param_bounds.push(VerifyBound::OutlivedBy(region));
|
||||
} else {
|
||||
// This is `for<'a> T: 'a`. This means that `T` outlives everything! All done here.
|
||||
debug!("found that {param_ty:?} outlives any lifetime, returning empty vector");
|
||||
debug!("found that {ty:?} outlives any lifetime, returning empty vector");
|
||||
return VerifyBound::AllBounds(vec![]);
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +168,10 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||
) -> VerifyBound<'tcx> {
|
||||
match *component {
|
||||
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
|
||||
Component::Param(param_ty) => self.param_bound(param_ty),
|
||||
Component::Param(param_ty) => self.param_or_placeholder_bound(param_ty.to_ty(self.tcx)),
|
||||
Component::Placeholder(placeholder_ty) => {
|
||||
self.param_or_placeholder_bound(Ty::new_placeholder(self.tcx, placeholder_ty))
|
||||
}
|
||||
Component::Alias(alias_ty) => self.alias_bound(alias_ty, visited),
|
||||
Component::EscapingAlias(ref components) => {
|
||||
self.bound_from_components(components, visited)
|
||||
|
@ -195,9 +198,9 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||
/// bounds, but all the bounds it returns can be relied upon.
|
||||
fn declared_generic_bounds_from_env(
|
||||
&self,
|
||||
param_ty: ty::ParamTy,
|
||||
generic_ty: Ty<'tcx>,
|
||||
) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
|
||||
let generic_ty = param_ty.to_ty(self.tcx);
|
||||
assert!(matches!(generic_ty.kind(), ty::Param(_) | ty::Placeholder(_)));
|
||||
self.declared_generic_bounds_from_env_for_erased_ty(generic_ty)
|
||||
}
|
||||
|
||||
|
|
|
@ -147,6 +147,7 @@ pub struct Verify<'tcx> {
|
|||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
|
||||
pub enum GenericKind<'tcx> {
|
||||
Param(ty::ParamTy),
|
||||
Placeholder(ty::PlaceholderType),
|
||||
Alias(ty::AliasTy<'tcx>),
|
||||
}
|
||||
|
||||
|
@ -707,6 +708,7 @@ impl<'tcx> fmt::Debug for GenericKind<'tcx> {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
GenericKind::Param(ref p) => write!(f, "{p:?}"),
|
||||
GenericKind::Placeholder(ref p) => write!(f, "{p:?}"),
|
||||
GenericKind::Alias(ref p) => write!(f, "{p:?}"),
|
||||
}
|
||||
}
|
||||
|
@ -716,6 +718,7 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
GenericKind::Param(ref p) => write!(f, "{p}"),
|
||||
GenericKind::Placeholder(ref p) => write!(f, "{p:?}"),
|
||||
GenericKind::Alias(ref p) => write!(f, "{p}"),
|
||||
}
|
||||
}
|
||||
|
@ -725,6 +728,7 @@ impl<'tcx> GenericKind<'tcx> {
|
|||
pub fn to_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
match *self {
|
||||
GenericKind::Param(ref p) => p.to_ty(tcx),
|
||||
GenericKind::Placeholder(ref p) => Ty::new_placeholder(tcx, *p),
|
||||
GenericKind::Alias(ref p) => p.to_ty(tcx),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -365,6 +365,11 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
|
|||
Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, r_min)))
|
||||
}
|
||||
|
||||
Component::Placeholder(p) => {
|
||||
let ty = Ty::new_placeholder(tcx, p);
|
||||
Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, r_min)))
|
||||
}
|
||||
|
||||
Component::UnresolvedInferenceVariable(_) => None,
|
||||
|
||||
Component::Alias(alias_ty) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue