make TypeOutlives parameterized over a delegate

It was only using the `infcx` to "accumulate" constraints anyhow.
This commit is contained in:
Niko Matsakis 2018-06-07 04:57:18 -04:00
parent b858ed5919
commit 65ceec71ec

View File

@ -159,8 +159,13 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
} }
} }
let outlives = let outlives = &mut TypeOutlives::new(
TypeOutlives::new(self, region_bound_pairs, implicit_region_bound, param_env); self,
self.tcx,
region_bound_pairs,
implicit_region_bound,
param_env,
);
for RegionObligation { for RegionObligation {
sup_type, sup_type,
@ -193,32 +198,68 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
ty: Ty<'tcx>, ty: Ty<'tcx>,
region: ty::Region<'tcx>, region: ty::Region<'tcx>,
) { ) {
let outlives = let outlives = &mut TypeOutlives::new(
TypeOutlives::new(self, region_bound_pairs, implicit_region_bound, param_env); self,
self.tcx,
region_bound_pairs,
implicit_region_bound,
param_env,
);
let ty = self.resolve_type_vars_if_possible(&ty); let ty = self.resolve_type_vars_if_possible(&ty);
outlives.type_must_outlive(origin, ty, region); outlives.type_must_outlive(origin, ty, region);
} }
} }
#[must_use] // you ought to invoke `into_accrued_obligations` when you are done =) /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
struct TypeOutlives<'cx, 'gcx: 'tcx, 'tcx: 'cx> { /// obligation into a series of `'a: 'b` constraints and "verifys", as
/// described on the module comment. The final constraints are emitted
/// via a "delegate" of type `D` -- this is usually the `infcx`, which
/// accrues them into the `region_obligations` code, but for NLL we
/// use something else.
pub struct TypeOutlives<'cx, 'gcx: 'tcx, 'tcx: 'cx, D>
where
D: TypeOutlivesDelegate<'tcx>,
{
// See the comments on `process_registered_region_obligations` for the meaning // See the comments on `process_registered_region_obligations` for the meaning
// of these fields. // of these fields.
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, delegate: D,
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)], region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)],
implicit_region_bound: Option<ty::Region<'tcx>>, implicit_region_bound: Option<ty::Region<'tcx>>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
} }
impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> { pub trait TypeOutlivesDelegate<'tcx> {
fn push_sub_region_constraint(
&mut self,
origin: SubregionOrigin<'tcx>,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
);
fn push_verify(
&mut self,
origin: SubregionOrigin<'tcx>,
kind: GenericKind<'tcx>,
a: ty::Region<'tcx>,
bound: VerifyBound<'tcx>,
);
}
impl<'cx, 'gcx, 'tcx, D> TypeOutlives<'cx, 'gcx, 'tcx, D>
where
D: TypeOutlivesDelegate<'tcx>,
{
fn new( fn new(
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, delegate: D,
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)], region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)],
implicit_region_bound: Option<ty::Region<'tcx>>, implicit_region_bound: Option<ty::Region<'tcx>>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
) -> Self { ) -> Self {
Self { Self {
infcx, delegate,
tcx,
region_bound_pairs, region_bound_pairs,
implicit_region_bound, implicit_region_bound,
param_env, param_env,
@ -234,7 +275,7 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> {
/// - `ty`, the type `T` /// - `ty`, the type `T`
/// - `region`, the region `'a` /// - `region`, the region `'a`
fn type_must_outlive( fn type_must_outlive(
&self, &mut self,
origin: infer::SubregionOrigin<'tcx>, origin: infer::SubregionOrigin<'tcx>,
ty: Ty<'tcx>, ty: Ty<'tcx>,
region: ty::Region<'tcx>, region: ty::Region<'tcx>,
@ -246,16 +287,12 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> {
assert!(!ty.has_escaping_regions()); assert!(!ty.has_escaping_regions());
let components = self.tcx().outlives_components(ty); let components = self.tcx.outlives_components(ty);
self.components_must_outlive(origin, components, region); self.components_must_outlive(origin, components, region);
} }
fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
self.infcx.tcx
}
fn components_must_outlive( fn components_must_outlive(
&self, &mut self,
origin: infer::SubregionOrigin<'tcx>, origin: infer::SubregionOrigin<'tcx>,
components: Vec<Component<'tcx>>, components: Vec<Component<'tcx>>,
region: ty::Region<'tcx>, region: ty::Region<'tcx>,
@ -264,7 +301,7 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> {
let origin = origin.clone(); let origin = origin.clone();
match component { match component {
Component::Region(region1) => { Component::Region(region1) => {
self.infcx.sub_regions(origin, region, region1); self.delegate.push_sub_region_constraint(origin, region, region1);
} }
Component::Param(param_ty) => { Component::Param(param_ty) => {
self.param_ty_must_outlive(origin, region, param_ty); self.param_ty_must_outlive(origin, region, param_ty);
@ -279,7 +316,7 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> {
// ignore this, we presume it will yield an error // ignore this, we presume it will yield an error
// later, since if a type variable is not resolved by // later, since if a type variable is not resolved by
// this point it never will be // this point it never will be
self.infcx.tcx.sess.delay_span_bug( self.tcx.sess.delay_span_bug(
origin.span(), origin.span(),
&format!("unresolved inference variable in outlives: {:?}", v), &format!("unresolved inference variable in outlives: {:?}", v),
); );
@ -289,7 +326,7 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> {
} }
fn param_ty_must_outlive( fn param_ty_must_outlive(
&self, &mut self,
origin: infer::SubregionOrigin<'tcx>, origin: infer::SubregionOrigin<'tcx>,
region: ty::Region<'tcx>, region: ty::Region<'tcx>,
param_ty: ty::ParamTy, param_ty: ty::ParamTy,
@ -301,12 +338,12 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> {
let verify_bound = self.param_bound(param_ty); let verify_bound = self.param_bound(param_ty);
let generic = GenericKind::Param(param_ty); let generic = GenericKind::Param(param_ty);
self.infcx self.delegate
.verify_generic_bound(origin, generic, region, verify_bound); .push_verify(origin, generic, region, verify_bound);
} }
fn projection_must_outlive( fn projection_must_outlive(
&self, &mut self,
origin: infer::SubregionOrigin<'tcx>, origin: infer::SubregionOrigin<'tcx>,
region: ty::Region<'tcx>, region: ty::Region<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>, projection_ty: ty::ProjectionTy<'tcx>,
@ -367,7 +404,7 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> {
} }
for r in projection_ty.substs.regions() { for r in projection_ty.substs.regions() {
self.infcx.sub_regions(origin.clone(), region, r); self.delegate.push_sub_region_constraint(origin.clone(), region, r);
} }
return; return;
@ -393,7 +430,8 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> {
.any(|r| env_bounds.contains(&r)) .any(|r| env_bounds.contains(&r))
{ {
debug!("projection_must_outlive: unique declared bound appears in trait ref"); debug!("projection_must_outlive: unique declared bound appears in trait ref");
self.infcx.sub_regions(origin.clone(), region, unique_bound); self.delegate
.push_sub_region_constraint(origin.clone(), region, unique_bound);
return; return;
} }
} }
@ -405,8 +443,8 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> {
// even though a satisfactory solution exists. // even though a satisfactory solution exists.
let verify_bound = self.projection_bound(env_bounds, projection_ty); let verify_bound = self.projection_bound(env_bounds, projection_ty);
let generic = GenericKind::Projection(projection_ty); let generic = GenericKind::Projection(projection_ty);
self.infcx self.delegate
.verify_generic_bound(origin, generic.clone(), region, verify_bound); .push_verify(origin, generic.clone(), region, verify_bound);
} }
fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
@ -459,7 +497,6 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> {
// see the extensive comment in projection_must_outlive // see the extensive comment in projection_must_outlive
let ty = self let ty = self
.infcx
.tcx .tcx
.mk_projection(projection_ty.item_def_id, projection_ty.substs); .mk_projection(projection_ty.item_def_id, projection_ty.substs);
let recursive_bound = self.recursive_type_bound(ty); let recursive_bound = self.recursive_type_bound(ty);
@ -492,7 +529,7 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> {
&self, &self,
generic: GenericKind<'tcx>, generic: GenericKind<'tcx>,
) -> Vec<ty::Region<'tcx>> { ) -> Vec<ty::Region<'tcx>> {
let tcx = self.tcx(); let tcx = self.tcx;
// To start, collect bounds from user environment. Note that // To start, collect bounds from user environment. Note that
// parameter environments are already elaborated, so we don't // parameter environments are already elaborated, so we don't
@ -544,7 +581,7 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> {
debug!("projection_bounds(projection_ty={:?})", projection_ty); debug!("projection_bounds(projection_ty={:?})", projection_ty);
let mut bounds = self.region_bounds_declared_on_associated_item(projection_ty.item_def_id); let mut bounds = self.region_bounds_declared_on_associated_item(projection_ty.item_def_id);
for r in &mut bounds { for r in &mut bounds {
*r = r.subst(self.tcx(), projection_ty.substs); *r = r.subst(self.tcx, projection_ty.substs);
} }
bounds bounds
} }
@ -583,7 +620,7 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> {
&self, &self,
assoc_item_def_id: DefId, assoc_item_def_id: DefId,
) -> Vec<ty::Region<'tcx>> { ) -> Vec<ty::Region<'tcx>> {
let tcx = self.tcx(); let tcx = self.tcx;
let assoc_item = tcx.associated_item(assoc_item_def_id); let assoc_item = tcx.associated_item(assoc_item_def_id);
let trait_def_id = assoc_item.container.assert_trait(); let trait_def_id = assoc_item.container.assert_trait();
let trait_predicates = tcx.predicates_of(trait_def_id); let trait_predicates = tcx.predicates_of(trait_def_id);
@ -619,3 +656,25 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> {
.collect() .collect()
} }
} }
impl<'cx, 'gcx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'gcx, 'tcx> {
fn push_sub_region_constraint(
&mut self,
origin: SubregionOrigin<'tcx>,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
) {
self.sub_regions(origin, a, b)
}
fn push_verify(
&mut self,
origin: SubregionOrigin<'tcx>,
kind: GenericKind<'tcx>,
a: ty::Region<'tcx>,
bound: VerifyBound<'tcx>,
) {
self.verify_generic_bound(origin, kind, a, bound)
}
}