diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 32577ac46f3..df67c3abbe8 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -536,14 +536,29 @@ impl<'gcx> HashStable> 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> for mir::ClosureOutlivesSubject<'gcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + 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); + } + } + } +} diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index a83c3f29d25..d7afce7de46 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -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, + pub outlives_requirements: Vec>, } -/// 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 */ diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 7ba063adff4..319f63dd7c8 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -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, + [] fn mir_borrowck: MirBorrowCheck(DefId) -> Option>, /// Gets a complete map from all types to their inherent impls. /// Not meant to be used directly outside of coherence. diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 576d5985798..e0b03aec69a 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -65,7 +65,7 @@ pub fn provide(providers: &mut Providers) { fn mir_borrowck<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, -) -> Option { +) -> Option> { 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 { +) -> Option> { let tcx = infcx.tcx; let attributes = tcx.get_attrs(def_id); let param_env = tcx.param_env(def_id); diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 9e7c94cd7ff..23fa2689053 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -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, + Option>, ) { // 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, ))?; } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 4759185d226..4a1eca38bc7 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -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 { + ) -> Option> { 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>, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + mut propagated_outlives_requirements: Option<&mut Vec>>, ) { // 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, + propagated_outlives_requirements: &mut Vec>, ) { 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"); + } + } } } }