permit ClosureOutlivesRequirement
to constrain regions or types
This commit is contained in:
parent
c7cfa2367b
commit
5804637a81
@ -536,14 +536,29 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Literal<'gcx> {
|
||||
|
||||
impl_stable_hash_for!(struct mir::Location { block, statement_index });
|
||||
|
||||
impl_stable_hash_for!(struct mir::ClosureRegionRequirements {
|
||||
impl_stable_hash_for!(struct mir::ClosureRegionRequirements<'tcx> {
|
||||
num_external_vids,
|
||||
outlives_requirements
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement {
|
||||
free_region,
|
||||
impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement<'tcx> {
|
||||
subject,
|
||||
outlived_free_region,
|
||||
blame_span
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::ClosureOutlivesSubject<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
match *self {
|
||||
mir::ClosureOutlivesSubject::Ty(ref ty) => {
|
||||
ty.hash_stable(hcx, hasher);
|
||||
}
|
||||
mir::ClosureOutlivesSubject::Region(ref region) => {
|
||||
region.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1832,7 +1832,7 @@ pub struct GeneratorLayout<'tcx> {
|
||||
/// can be extracted from its type and constrained to have the given
|
||||
/// outlives relationship.
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct ClosureRegionRequirements {
|
||||
pub struct ClosureRegionRequirements<'gcx> {
|
||||
/// The number of external regions defined on the closure. In our
|
||||
/// example above, it would be 3 -- one for `'static`, then `'1`
|
||||
/// and `'2`. This is just used for a sanity check later on, to
|
||||
@ -1842,15 +1842,15 @@ pub struct ClosureRegionRequirements {
|
||||
|
||||
/// Requirements between the various free regions defined in
|
||||
/// indices.
|
||||
pub outlives_requirements: Vec<ClosureOutlivesRequirement>,
|
||||
pub outlives_requirements: Vec<ClosureOutlivesRequirement<'gcx>>,
|
||||
}
|
||||
|
||||
/// Indicates an outlives constraint between two free-regions declared
|
||||
/// on the closure.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct ClosureOutlivesRequirement {
|
||||
// This region ...
|
||||
pub free_region: ty::RegionVid,
|
||||
/// Indicates an outlives constraint between a type or between two
|
||||
/// free-regions declared on the closure.
|
||||
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct ClosureOutlivesRequirement<'tcx> {
|
||||
// This region or type ...
|
||||
pub subject: ClosureOutlivesSubject<'tcx>,
|
||||
|
||||
// .. must outlive this one.
|
||||
pub outlived_free_region: ty::RegionVid,
|
||||
@ -1859,6 +1859,23 @@ pub struct ClosureOutlivesRequirement {
|
||||
pub blame_span: Span,
|
||||
}
|
||||
|
||||
/// The subject of a ClosureOutlivesRequirement -- that is, the thing
|
||||
/// that must outlive some region.
|
||||
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum ClosureOutlivesSubject<'tcx> {
|
||||
/// Subject is a type, typically a type parameter, but could also
|
||||
/// be a projection. Indicates a requirement like `T: 'a` being
|
||||
/// passed to the caller, where the type here is `T`.
|
||||
///
|
||||
/// The type here is guaranteed not to contain any free regions at
|
||||
/// present.
|
||||
Ty(Ty<'tcx>),
|
||||
|
||||
/// Subject is a free region from the closure. Indicates a requirement
|
||||
/// like `'a: 'b` being passed to the caller; the region here is `'a`.
|
||||
Region(ty::RegionVid),
|
||||
}
|
||||
|
||||
/*
|
||||
* TypeFoldable implementations for MIR types
|
||||
*/
|
||||
|
@ -193,7 +193,7 @@ define_maps! { <'tcx>
|
||||
|
||||
/// Borrow checks the function body. If this is a closure, returns
|
||||
/// additional requirements that the closure's creator must verify.
|
||||
[] fn mir_borrowck: MirBorrowCheck(DefId) -> Option<mir::ClosureRegionRequirements>,
|
||||
[] fn mir_borrowck: MirBorrowCheck(DefId) -> Option<mir::ClosureRegionRequirements<'tcx>>,
|
||||
|
||||
/// Gets a complete map from all types to their inherent impls.
|
||||
/// Not meant to be used directly outside of coherence.
|
||||
|
@ -65,7 +65,7 @@ pub fn provide(providers: &mut Providers) {
|
||||
fn mir_borrowck<'a, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId,
|
||||
) -> Option<ClosureRegionRequirements> {
|
||||
) -> Option<ClosureRegionRequirements<'tcx>> {
|
||||
let input_mir = tcx.mir_validated(def_id);
|
||||
debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id));
|
||||
|
||||
@ -89,7 +89,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
||||
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
input_mir: &Mir<'gcx>,
|
||||
def_id: DefId,
|
||||
) -> Option<ClosureRegionRequirements> {
|
||||
) -> Option<ClosureRegionRequirements<'gcx>> {
|
||||
let tcx = infcx.tcx;
|
||||
let attributes = tcx.get_attrs(def_id);
|
||||
let param_env = tcx.param_env(def_id);
|
||||
|
@ -9,11 +9,12 @@
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir::{ClosureRegionRequirements, Mir};
|
||||
use rustc::mir::{ClosureRegionRequirements, ClosureOutlivesSubject, Mir};
|
||||
use rustc::infer::InferCtxt;
|
||||
use rustc::ty::{self, RegionKind, RegionVid};
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt::Debug;
|
||||
use std::io;
|
||||
use transform::MirSource;
|
||||
use util::liveness::{LivenessResults, LocalSet};
|
||||
@ -73,7 +74,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
|
||||
move_data: &MoveData<'tcx>,
|
||||
) -> (
|
||||
RegionInferenceContext<'tcx>,
|
||||
Option<ClosureRegionRequirements>,
|
||||
Option<ClosureRegionRequirements<'gcx>>,
|
||||
) {
|
||||
// Run the MIR type-checker.
|
||||
let mir_node_id = infcx.tcx.hir.as_local_node_id(def_id).unwrap();
|
||||
@ -263,9 +264,13 @@ fn for_each_region_constraint(
|
||||
with_msg: &mut FnMut(&str) -> io::Result<()>,
|
||||
) -> io::Result<()> {
|
||||
for req in &closure_region_requirements.outlives_requirements {
|
||||
let subject: &Debug = match &req.subject {
|
||||
ClosureOutlivesSubject::Region(subject) => subject,
|
||||
ClosureOutlivesSubject::Ty(ty) => ty,
|
||||
};
|
||||
with_msg(&format!(
|
||||
"where {:?}: {:?}",
|
||||
req.free_region,
|
||||
subject,
|
||||
req.outlived_free_region,
|
||||
))?;
|
||||
}
|
||||
|
@ -15,7 +15,8 @@ use rustc::infer::NLLRegionVariableOrigin;
|
||||
use rustc::infer::RegionVariableOrigin;
|
||||
use rustc::infer::SubregionOrigin;
|
||||
use rustc::infer::region_constraints::{GenericKind, VarOrigins};
|
||||
use rustc::mir::{ClosureOutlivesRequirement, ClosureRegionRequirements, Location, Mir};
|
||||
use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
|
||||
Location, Mir};
|
||||
use rustc::ty::{self, RegionVid};
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use std::fmt;
|
||||
@ -339,12 +340,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// Perform region inference and report errors if we see any
|
||||
/// unsatisfiable constraints. If this is a closure, returns the
|
||||
/// region requirements to propagate to our creator, if any.
|
||||
pub(super) fn solve(
|
||||
pub(super) fn solve<'gcx>(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'_, '_, 'tcx>,
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
mir_def_id: DefId,
|
||||
) -> Option<ClosureRegionRequirements> {
|
||||
) -> Option<ClosureRegionRequirements<'gcx>> {
|
||||
assert!(self.inferred_values.is_none(), "values already inferred");
|
||||
|
||||
self.propagate_constraints(mir);
|
||||
@ -559,10 +560,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// If `propagated_outlives_requirements` is `Some`, then we will
|
||||
/// push unsatisfied obligations into there. Otherwise, we'll
|
||||
/// report them as errors.
|
||||
fn check_universal_regions(
|
||||
fn check_universal_regions<'gcx>(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, '_, 'tcx>,
|
||||
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement>>,
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
|
||||
) {
|
||||
// The universal regions are always found in a prefix of the
|
||||
// full list.
|
||||
@ -583,9 +584,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
propagated_outlives_requirements.extend(outlives_requirements.drain(..));
|
||||
} else {
|
||||
for outlives_requirement in outlives_requirements.drain(..) {
|
||||
let fr = match outlives_requirement.subject {
|
||||
ClosureOutlivesSubject::Region(fr) => fr,
|
||||
_ => span_bug!(
|
||||
outlives_requirement.blame_span,
|
||||
"check_universal_region() produced requirement w/ non-region subject"
|
||||
),
|
||||
};
|
||||
|
||||
self.report_error(
|
||||
infcx,
|
||||
outlives_requirement.free_region,
|
||||
fr,
|
||||
outlives_requirement.outlived_free_region,
|
||||
outlives_requirement.blame_span,
|
||||
);
|
||||
@ -602,11 +611,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
///
|
||||
/// Things that are to be propagated are accumulated into the
|
||||
/// `outlives_requirements` vector.
|
||||
fn check_universal_region(
|
||||
fn check_universal_region<'gcx>(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, '_, 'tcx>,
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
longer_fr: RegionVid,
|
||||
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement>,
|
||||
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'gcx>>,
|
||||
) {
|
||||
let inferred_values = self.inferred_values.as_ref().unwrap();
|
||||
|
||||
@ -645,7 +654,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
||||
// Push the constraint `fr-: shorter_fr+`
|
||||
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
|
||||
free_region: fr_minus,
|
||||
subject: ClosureOutlivesSubject::Region(fr_minus),
|
||||
outlived_free_region: shorter_fr_plus,
|
||||
blame_span: blame_span,
|
||||
});
|
||||
@ -773,7 +782,7 @@ pub trait ClosureRegionRequirementsExt {
|
||||
);
|
||||
}
|
||||
|
||||
impl ClosureRegionRequirementsExt for ClosureRegionRequirements {
|
||||
impl<'gcx> ClosureRegionRequirementsExt for ClosureRegionRequirements<'gcx> {
|
||||
/// Given an instance T of the closure type, this method
|
||||
/// instantiates the "extra" requirements that we computed for the
|
||||
/// closure into the inference context. This has the effect of
|
||||
@ -815,17 +824,29 @@ impl ClosureRegionRequirementsExt for ClosureRegionRequirements {
|
||||
|
||||
// Create the predicates.
|
||||
for outlives_requirement in &self.outlives_requirements {
|
||||
let region = closure_mapping[outlives_requirement.free_region];
|
||||
let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
|
||||
debug!(
|
||||
"apply_requirements: region={:?} outlived_region={:?} outlives_requirements={:?}",
|
||||
region,
|
||||
outlived_region,
|
||||
outlives_requirement
|
||||
);
|
||||
|
||||
// FIXME, this origin is not entirely suitable.
|
||||
let origin = SubregionOrigin::CallRcvr(outlives_requirement.blame_span);
|
||||
infcx.sub_regions(origin, outlived_region, region);
|
||||
|
||||
match outlives_requirement.subject {
|
||||
ClosureOutlivesSubject::Region(region) => {
|
||||
let region = closure_mapping[region];
|
||||
debug!(
|
||||
"apply_requirements: region={:?} \
|
||||
outlived_region={:?} \
|
||||
outlives_requirements={:?}",
|
||||
region,
|
||||
outlived_region,
|
||||
outlives_requirement
|
||||
);
|
||||
infcx.sub_regions(origin, outlived_region, region);
|
||||
}
|
||||
|
||||
ClosureOutlivesSubject::Ty(_ty) => {
|
||||
bug!("TODO not yet implemented -- closure outlives subject of a type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user