extract the code to create OutlivesBounds
into its own module
Now it can be reused by the NLL code.
This commit is contained in:
parent
1f33145ae9
commit
c45307fae1
@ -8,9 +8,9 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use infer::{InferCtxt, GenericKind};
|
||||
use infer::{GenericKind, InferCtxt};
|
||||
use infer::outlives::free_region_map::FreeRegionMap;
|
||||
use infer::outlives::implied_bounds::ImpliedBound;
|
||||
use infer::outlives::implied_bounds::{self, OutlivesBound};
|
||||
use ty::{self, Ty};
|
||||
|
||||
use syntax::ast;
|
||||
@ -50,7 +50,7 @@ pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
|
||||
region_bound_pairs: vec![],
|
||||
};
|
||||
|
||||
env.init_free_regions_from_predicates();
|
||||
env.add_outlives_bounds(None, implied_bounds::explicit_outlives_bounds(param_env));
|
||||
|
||||
env
|
||||
}
|
||||
@ -144,65 +144,54 @@ pub fn add_implied_bounds(
|
||||
for &ty in fn_sig_tys {
|
||||
let ty = infcx.resolve_type_vars_if_possible(&ty);
|
||||
debug!("add_implied_bounds: ty = {}", ty);
|
||||
let implied_bounds = infcx.implied_bounds(self.param_env, body_id, ty, span);
|
||||
|
||||
// But also record other relationships, such as `T:'x`,
|
||||
// that don't go into the free-region-map but which we use
|
||||
// here.
|
||||
for implication in implied_bounds {
|
||||
debug!("add_implied_bounds: implication={:?}", implication);
|
||||
match implication {
|
||||
ImpliedBound::RegionSubRegion(
|
||||
r_a @ &ty::ReEarlyBound(_),
|
||||
&ty::ReVar(vid_b),
|
||||
) |
|
||||
ImpliedBound::RegionSubRegion(r_a @ &ty::ReFree(_), &ty::ReVar(vid_b)) => {
|
||||
infcx.add_given(r_a, vid_b);
|
||||
}
|
||||
ImpliedBound::RegionSubParam(r_a, param_b) => {
|
||||
self.region_bound_pairs
|
||||
.push((r_a, GenericKind::Param(param_b)));
|
||||
}
|
||||
ImpliedBound::RegionSubProjection(r_a, projection_b) => {
|
||||
self.region_bound_pairs
|
||||
.push((r_a, GenericKind::Projection(projection_b)));
|
||||
}
|
||||
ImpliedBound::RegionSubRegion(r_a, r_b) => {
|
||||
// In principle, we could record (and take
|
||||
// advantage of) every relationship here, but
|
||||
// we are also free not to -- it simply means
|
||||
// strictly less that we can successfully type
|
||||
// check. Right now we only look for things
|
||||
// relationships between free regions. (It may
|
||||
// also be that we should revise our inference
|
||||
// system to be more general and to make use
|
||||
// of *every* relationship that arises here,
|
||||
// but presently we do not.)
|
||||
self.free_region_map.relate_regions(r_a, r_b);
|
||||
}
|
||||
}
|
||||
}
|
||||
let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span);
|
||||
self.add_outlives_bounds(Some(infcx), implied_bounds)
|
||||
}
|
||||
}
|
||||
|
||||
fn init_free_regions_from_predicates(&mut self) {
|
||||
debug!("init_free_regions_from_predicates()");
|
||||
for predicate in self.param_env.caller_bounds {
|
||||
debug!("init_free_regions_from_predicates: predicate={:?}", predicate);
|
||||
match *predicate {
|
||||
ty::Predicate::Projection(..) |
|
||||
ty::Predicate::Trait(..) |
|
||||
ty::Predicate::Equate(..) |
|
||||
ty::Predicate::Subtype(..) |
|
||||
ty::Predicate::WellFormed(..) |
|
||||
ty::Predicate::ObjectSafe(..) |
|
||||
ty::Predicate::ClosureKind(..) |
|
||||
ty::Predicate::TypeOutlives(..) |
|
||||
ty::Predicate::ConstEvaluatable(..) => {
|
||||
// No region bounds here
|
||||
/// Processes outlives bounds that are known to hold, whether from implied or other sources.
|
||||
///
|
||||
/// The `infcx` parameter is optional; if the implied bounds may
|
||||
/// contain inference variables, it should be supplied, in which
|
||||
/// case we will register "givens" on the inference context. (See
|
||||
/// `RegionConstraintData`.)
|
||||
fn add_outlives_bounds<I>(
|
||||
&mut self,
|
||||
infcx: Option<&InferCtxt<'a, 'gcx, 'tcx>>,
|
||||
outlives_bounds: I,
|
||||
) where
|
||||
I: IntoIterator<Item = OutlivesBound<'tcx>>,
|
||||
{
|
||||
// But also record other relationships, such as `T:'x`,
|
||||
// that don't go into the free-region-map but which we use
|
||||
// here.
|
||||
for outlives_bound in outlives_bounds {
|
||||
debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
|
||||
match outlives_bound {
|
||||
OutlivesBound::RegionSubRegion(r_a @ &ty::ReEarlyBound(_), &ty::ReVar(vid_b)) |
|
||||
OutlivesBound::RegionSubRegion(r_a @ &ty::ReFree(_), &ty::ReVar(vid_b)) => {
|
||||
infcx.expect("no infcx provided but region vars found").add_given(r_a, vid_b);
|
||||
}
|
||||
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
|
||||
self.free_region_map.relate_regions(r_b, r_a);
|
||||
OutlivesBound::RegionSubParam(r_a, param_b) => {
|
||||
self.region_bound_pairs
|
||||
.push((r_a, GenericKind::Param(param_b)));
|
||||
}
|
||||
OutlivesBound::RegionSubProjection(r_a, projection_b) => {
|
||||
self.region_bound_pairs
|
||||
.push((r_a, GenericKind::Projection(projection_b)));
|
||||
}
|
||||
OutlivesBound::RegionSubRegion(r_a, r_b) => {
|
||||
// In principle, we could record (and take
|
||||
// advantage of) every relationship here, but
|
||||
// we are also free not to -- it simply means
|
||||
// strictly less that we can successfully type
|
||||
// check. Right now we only look for things
|
||||
// relationships between free regions. (It may
|
||||
// also be that we should revise our inference
|
||||
// system to be more general and to make use
|
||||
// of *every* relationship that arises here,
|
||||
// but presently we do not.)
|
||||
self.free_region_map.relate_regions(r_a, r_b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,28 +16,32 @@
|
||||
use ty::outlives::Component;
|
||||
use ty::wf;
|
||||
|
||||
/// Implied bounds are region relationships that we deduce
|
||||
/// automatically. The idea is that (e.g.) a caller must check that a
|
||||
/// function's argument types are well-formed immediately before
|
||||
/// calling that fn, and hence the *callee* can assume that its
|
||||
/// argument types are well-formed. This may imply certain relationships
|
||||
/// between generic parameters. For example:
|
||||
///
|
||||
/// fn foo<'a,T>(x: &'a T)
|
||||
///
|
||||
/// can only be called with a `'a` and `T` such that `&'a T` is WF.
|
||||
/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
|
||||
/// Outlives bounds are relationships between generic parameters,
|
||||
/// whether they both be regions (`'a: 'b`) or whether types are
|
||||
/// involved (`T: 'a`). These relationships can be extracted from the
|
||||
/// full set of predicates we understand or also from types (in which
|
||||
/// case they are called implied bounds). They are fed to the
|
||||
/// `OutlivesEnv` which in turn is supplied to the region checker and
|
||||
/// other parts of the inference system.
|
||||
#[derive(Debug)]
|
||||
pub enum ImpliedBound<'tcx> {
|
||||
pub enum OutlivesBound<'tcx> {
|
||||
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
|
||||
RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
|
||||
RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
||||
/// Compute the implied bounds that a callee/impl can assume based on
|
||||
/// the fact that caller/projector has ensured that `ty` is WF. See
|
||||
/// the `ImpliedBound` type for more details.
|
||||
/// Implied bounds are region relationships that we deduce
|
||||
/// automatically. The idea is that (e.g.) a caller must check that a
|
||||
/// function's argument types are well-formed immediately before
|
||||
/// calling that fn, and hence the *callee* can assume that its
|
||||
/// argument types are well-formed. This may imply certain relationships
|
||||
/// between generic parameters. For example:
|
||||
///
|
||||
/// fn foo<'a,T>(x: &'a T)
|
||||
///
|
||||
/// can only be called with a `'a` and `T` such that `&'a T` is WF.
|
||||
/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
@ -48,13 +52,13 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
||||
/// - `ty`, the type that we are supposed to assume is WF.
|
||||
/// - `span`, a span to use when normalizing, hopefully not important,
|
||||
/// might be useful if a `bug!` occurs.
|
||||
pub fn implied_bounds(
|
||||
pub fn implied_outlives_bounds(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body_id: ast::NodeId,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> Vec<ImpliedBound<'tcx>> {
|
||||
) -> Vec<OutlivesBound<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
// Sometimes when we ask what it takes for T: WF, we get back that
|
||||
@ -76,8 +80,7 @@ pub fn implied_bounds(
|
||||
// than the ultimate set. (Note: normally there won't be
|
||||
// unresolved inference variables here anyway, but there might be
|
||||
// during typeck under some circumstances.)
|
||||
let obligations =
|
||||
wf::obligations(self, param_env, body_id, ty, span).unwrap_or(vec![]);
|
||||
let obligations = wf::obligations(self, param_env, body_id, ty, span).unwrap_or(vec![]);
|
||||
|
||||
// NB: All of these predicates *ought* to be easily proven
|
||||
// true. In fact, their correctness is (mostly) implied by
|
||||
@ -105,7 +108,8 @@ pub fn implied_bounds(
|
||||
obligations
|
||||
.iter()
|
||||
.filter(|o| o.predicate.has_infer_types())
|
||||
.cloned());
|
||||
.cloned(),
|
||||
);
|
||||
|
||||
// From the full set of obligations, just filter down to the
|
||||
// region relationships.
|
||||
@ -125,25 +129,21 @@ pub fn implied_bounds(
|
||||
vec![]
|
||||
}
|
||||
|
||||
ty::Predicate::RegionOutlives(ref data) => {
|
||||
match data.no_late_bound_regions() {
|
||||
None => vec![],
|
||||
Some(ty::OutlivesPredicate(r_a, r_b)) => {
|
||||
vec![ImpliedBound::RegionSubRegion(r_b, r_a)]
|
||||
}
|
||||
ty::Predicate::RegionOutlives(ref data) => match data.no_late_bound_regions() {
|
||||
None => vec![],
|
||||
Some(ty::OutlivesPredicate(r_a, r_b)) => {
|
||||
vec![OutlivesBound::RegionSubRegion(r_b, r_a)]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ty::Predicate::TypeOutlives(ref data) => {
|
||||
match data.no_late_bound_regions() {
|
||||
None => vec![],
|
||||
Some(ty::OutlivesPredicate(ty_a, r_b)) => {
|
||||
let ty_a = self.resolve_type_vars_if_possible(&ty_a);
|
||||
let components = tcx.outlives_components(ty_a);
|
||||
Self::implied_bounds_from_components(r_b, components)
|
||||
}
|
||||
ty::Predicate::TypeOutlives(ref data) => match data.no_late_bound_regions() {
|
||||
None => vec![],
|
||||
Some(ty::OutlivesPredicate(ty_a, r_b)) => {
|
||||
let ty_a = self.resolve_type_vars_if_possible(&ty_a);
|
||||
let components = tcx.outlives_components(ty_a);
|
||||
Self::implied_bounds_from_components(r_b, components)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}));
|
||||
}
|
||||
@ -165,17 +165,17 @@ pub fn implied_bounds(
|
||||
fn implied_bounds_from_components(
|
||||
sub_region: ty::Region<'tcx>,
|
||||
sup_components: Vec<Component<'tcx>>,
|
||||
) -> Vec<ImpliedBound<'tcx>> {
|
||||
) -> Vec<OutlivesBound<'tcx>> {
|
||||
sup_components
|
||||
.into_iter()
|
||||
.flat_map(|component| {
|
||||
match component {
|
||||
Component::Region(r) =>
|
||||
vec![ImpliedBound::RegionSubRegion(sub_region, r)],
|
||||
vec![OutlivesBound::RegionSubRegion(sub_region, r)],
|
||||
Component::Param(p) =>
|
||||
vec![ImpliedBound::RegionSubParam(sub_region, p)],
|
||||
vec![OutlivesBound::RegionSubParam(sub_region, p)],
|
||||
Component::Projection(p) =>
|
||||
vec![ImpliedBound::RegionSubProjection(sub_region, p)],
|
||||
vec![OutlivesBound::RegionSubProjection(sub_region, p)],
|
||||
Component::EscapingProjection(_) =>
|
||||
// If the projection has escaping regions, don't
|
||||
// try to infer any implied bounds even for its
|
||||
@ -193,3 +193,26 @@ fn implied_bounds_from_components(
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn explicit_outlives_bounds<'tcx>(
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
|
||||
debug!("explicit_outlives_bounds()");
|
||||
param_env
|
||||
.caller_bounds
|
||||
.into_iter()
|
||||
.filter_map(move |predicate| match predicate {
|
||||
ty::Predicate::Projection(..) |
|
||||
ty::Predicate::Trait(..) |
|
||||
ty::Predicate::Equate(..) |
|
||||
ty::Predicate::Subtype(..) |
|
||||
ty::Predicate::WellFormed(..) |
|
||||
ty::Predicate::ObjectSafe(..) |
|
||||
ty::Predicate::ClosureKind(..) |
|
||||
ty::Predicate::TypeOutlives(..) |
|
||||
ty::Predicate::ConstEvaluatable(..) => None,
|
||||
ty::Predicate::RegionOutlives(ref data) => data.no_late_bound_regions().map(
|
||||
|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user