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