Skip to content

Commit 5804637

Browse files
committed
permit ClosureOutlivesRequirement to constrain regions or types
1 parent c7cfa23 commit 5804637

File tree

6 files changed

+96
-38
lines changed

6 files changed

+96
-38
lines changed

src/librustc/ich/impls_mir.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -536,14 +536,29 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Literal<'gcx> {
536536

537537
impl_stable_hash_for!(struct mir::Location { block, statement_index });
538538

539-
impl_stable_hash_for!(struct mir::ClosureRegionRequirements {
539+
impl_stable_hash_for!(struct mir::ClosureRegionRequirements<'tcx> {
540540
num_external_vids,
541541
outlives_requirements
542542
});
543543

544-
impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement {
545-
free_region,
544+
impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement<'tcx> {
545+
subject,
546546
outlived_free_region,
547547
blame_span
548548
});
549549

550+
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::ClosureOutlivesSubject<'gcx> {
551+
fn hash_stable<W: StableHasherResult>(&self,
552+
hcx: &mut StableHashingContext<'gcx>,
553+
hasher: &mut StableHasher<W>) {
554+
mem::discriminant(self).hash_stable(hcx, hasher);
555+
match *self {
556+
mir::ClosureOutlivesSubject::Ty(ref ty) => {
557+
ty.hash_stable(hcx, hasher);
558+
}
559+
mir::ClosureOutlivesSubject::Region(ref region) => {
560+
region.hash_stable(hcx, hasher);
561+
}
562+
}
563+
}
564+
}

src/librustc/mir/mod.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,7 +1832,7 @@ pub struct GeneratorLayout<'tcx> {
18321832
/// can be extracted from its type and constrained to have the given
18331833
/// outlives relationship.
18341834
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
1835-
pub struct ClosureRegionRequirements {
1835+
pub struct ClosureRegionRequirements<'gcx> {
18361836
/// The number of external regions defined on the closure. In our
18371837
/// example above, it would be 3 -- one for `'static`, then `'1`
18381838
/// and `'2`. This is just used for a sanity check later on, to
@@ -1842,15 +1842,15 @@ pub struct ClosureRegionRequirements {
18421842

18431843
/// Requirements between the various free regions defined in
18441844
/// indices.
1845-
pub outlives_requirements: Vec<ClosureOutlivesRequirement>,
1845+
pub outlives_requirements: Vec<ClosureOutlivesRequirement<'gcx>>,
18461846
}
18471847

1848-
/// Indicates an outlives constraint between two free-regions declared
1849-
/// on the closure.
1850-
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
1851-
pub struct ClosureOutlivesRequirement {
1852-
// This region ...
1853-
pub free_region: ty::RegionVid,
1848+
/// Indicates an outlives constraint between a type or between two
1849+
/// free-regions declared on the closure.
1850+
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
1851+
pub struct ClosureOutlivesRequirement<'tcx> {
1852+
// This region or type ...
1853+
pub subject: ClosureOutlivesSubject<'tcx>,
18541854

18551855
// .. must outlive this one.
18561856
pub outlived_free_region: ty::RegionVid,
@@ -1859,6 +1859,23 @@ pub struct ClosureOutlivesRequirement {
18591859
pub blame_span: Span,
18601860
}
18611861

1862+
/// The subject of a ClosureOutlivesRequirement -- that is, the thing
1863+
/// that must outlive some region.
1864+
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
1865+
pub enum ClosureOutlivesSubject<'tcx> {
1866+
/// Subject is a type, typically a type parameter, but could also
1867+
/// be a projection. Indicates a requirement like `T: 'a` being
1868+
/// passed to the caller, where the type here is `T`.
1869+
///
1870+
/// The type here is guaranteed not to contain any free regions at
1871+
/// present.
1872+
Ty(Ty<'tcx>),
1873+
1874+
/// Subject is a free region from the closure. Indicates a requirement
1875+
/// like `'a: 'b` being passed to the caller; the region here is `'a`.
1876+
Region(ty::RegionVid),
1877+
}
1878+
18621879
/*
18631880
* TypeFoldable implementations for MIR types
18641881
*/

src/librustc/ty/maps/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ define_maps! { <'tcx>
193193

194194
/// Borrow checks the function body. If this is a closure, returns
195195
/// additional requirements that the closure's creator must verify.
196-
[] fn mir_borrowck: MirBorrowCheck(DefId) -> Option<mir::ClosureRegionRequirements>,
196+
[] fn mir_borrowck: MirBorrowCheck(DefId) -> Option<mir::ClosureRegionRequirements<'tcx>>,
197197

198198
/// Gets a complete map from all types to their inherent impls.
199199
/// Not meant to be used directly outside of coherence.

src/librustc_mir/borrow_check/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ pub fn provide(providers: &mut Providers) {
6565
fn mir_borrowck<'a, 'tcx>(
6666
tcx: TyCtxt<'a, 'tcx, 'tcx>,
6767
def_id: DefId,
68-
) -> Option<ClosureRegionRequirements> {
68+
) -> Option<ClosureRegionRequirements<'tcx>> {
6969
let input_mir = tcx.mir_validated(def_id);
7070
debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id));
7171

@@ -89,7 +89,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
8989
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
9090
input_mir: &Mir<'gcx>,
9191
def_id: DefId,
92-
) -> Option<ClosureRegionRequirements> {
92+
) -> Option<ClosureRegionRequirements<'gcx>> {
9393
let tcx = infcx.tcx;
9494
let attributes = tcx.get_attrs(def_id);
9595
let param_env = tcx.param_env(def_id);

src/librustc_mir/borrow_check/nll/mod.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
// except according to those terms.
1010

1111
use rustc::hir::def_id::DefId;
12-
use rustc::mir::{ClosureRegionRequirements, Mir};
12+
use rustc::mir::{ClosureRegionRequirements, ClosureOutlivesSubject, Mir};
1313
use rustc::infer::InferCtxt;
1414
use rustc::ty::{self, RegionKind, RegionVid};
1515
use rustc::util::nodemap::FxHashMap;
1616
use std::collections::BTreeSet;
17+
use std::fmt::Debug;
1718
use std::io;
1819
use transform::MirSource;
1920
use util::liveness::{LivenessResults, LocalSet};
@@ -73,7 +74,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
7374
move_data: &MoveData<'tcx>,
7475
) -> (
7576
RegionInferenceContext<'tcx>,
76-
Option<ClosureRegionRequirements>,
77+
Option<ClosureRegionRequirements<'gcx>>,
7778
) {
7879
// Run the MIR type-checker.
7980
let mir_node_id = infcx.tcx.hir.as_local_node_id(def_id).unwrap();
@@ -263,9 +264,13 @@ fn for_each_region_constraint(
263264
with_msg: &mut FnMut(&str) -> io::Result<()>,
264265
) -> io::Result<()> {
265266
for req in &closure_region_requirements.outlives_requirements {
267+
let subject: &Debug = match &req.subject {
268+
ClosureOutlivesSubject::Region(subject) => subject,
269+
ClosureOutlivesSubject::Ty(ty) => ty,
270+
};
266271
with_msg(&format!(
267272
"where {:?}: {:?}",
268-
req.free_region,
273+
subject,
269274
req.outlived_free_region,
270275
))?;
271276
}

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ use rustc::infer::NLLRegionVariableOrigin;
1515
use rustc::infer::RegionVariableOrigin;
1616
use rustc::infer::SubregionOrigin;
1717
use rustc::infer::region_constraints::{GenericKind, VarOrigins};
18-
use rustc::mir::{ClosureOutlivesRequirement, ClosureRegionRequirements, Location, Mir};
18+
use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
19+
Location, Mir};
1920
use rustc::ty::{self, RegionVid};
2021
use rustc_data_structures::indexed_vec::IndexVec;
2122
use std::fmt;
@@ -339,12 +340,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
339340
/// Perform region inference and report errors if we see any
340341
/// unsatisfiable constraints. If this is a closure, returns the
341342
/// region requirements to propagate to our creator, if any.
342-
pub(super) fn solve(
343+
pub(super) fn solve<'gcx>(
343344
&mut self,
344-
infcx: &InferCtxt<'_, '_, 'tcx>,
345+
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
345346
mir: &Mir<'tcx>,
346347
mir_def_id: DefId,
347-
) -> Option<ClosureRegionRequirements> {
348+
) -> Option<ClosureRegionRequirements<'gcx>> {
348349
assert!(self.inferred_values.is_none(), "values already inferred");
349350

350351
self.propagate_constraints(mir);
@@ -559,10 +560,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
559560
/// If `propagated_outlives_requirements` is `Some`, then we will
560561
/// push unsatisfied obligations into there. Otherwise, we'll
561562
/// report them as errors.
562-
fn check_universal_regions(
563+
fn check_universal_regions<'gcx>(
563564
&self,
564-
infcx: &InferCtxt<'_, '_, 'tcx>,
565-
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement>>,
565+
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
566+
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
566567
) {
567568
// The universal regions are always found in a prefix of the
568569
// full list.
@@ -583,9 +584,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
583584
propagated_outlives_requirements.extend(outlives_requirements.drain(..));
584585
} else {
585586
for outlives_requirement in outlives_requirements.drain(..) {
587+
let fr = match outlives_requirement.subject {
588+
ClosureOutlivesSubject::Region(fr) => fr,
589+
_ => span_bug!(
590+
outlives_requirement.blame_span,
591+
"check_universal_region() produced requirement w/ non-region subject"
592+
),
593+
};
594+
586595
self.report_error(
587596
infcx,
588-
outlives_requirement.free_region,
597+
fr,
589598
outlives_requirement.outlived_free_region,
590599
outlives_requirement.blame_span,
591600
);
@@ -602,11 +611,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
602611
///
603612
/// Things that are to be propagated are accumulated into the
604613
/// `outlives_requirements` vector.
605-
fn check_universal_region(
614+
fn check_universal_region<'gcx>(
606615
&self,
607-
infcx: &InferCtxt<'_, '_, 'tcx>,
616+
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
608617
longer_fr: RegionVid,
609-
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement>,
618+
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'gcx>>,
610619
) {
611620
let inferred_values = self.inferred_values.as_ref().unwrap();
612621

@@ -645,7 +654,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
645654

646655
// Push the constraint `fr-: shorter_fr+`
647656
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
648-
free_region: fr_minus,
657+
subject: ClosureOutlivesSubject::Region(fr_minus),
649658
outlived_free_region: shorter_fr_plus,
650659
blame_span: blame_span,
651660
});
@@ -773,7 +782,7 @@ pub trait ClosureRegionRequirementsExt {
773782
);
774783
}
775784

776-
impl ClosureRegionRequirementsExt for ClosureRegionRequirements {
785+
impl<'gcx> ClosureRegionRequirementsExt for ClosureRegionRequirements<'gcx> {
777786
/// Given an instance T of the closure type, this method
778787
/// instantiates the "extra" requirements that we computed for the
779788
/// closure into the inference context. This has the effect of
@@ -815,17 +824,29 @@ impl ClosureRegionRequirementsExt for ClosureRegionRequirements {
815824

816825
// Create the predicates.
817826
for outlives_requirement in &self.outlives_requirements {
818-
let region = closure_mapping[outlives_requirement.free_region];
819827
let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
820-
debug!(
821-
"apply_requirements: region={:?} outlived_region={:?} outlives_requirements={:?}",
822-
region,
823-
outlived_region,
824-
outlives_requirement
825-
);
828+
826829
// FIXME, this origin is not entirely suitable.
827830
let origin = SubregionOrigin::CallRcvr(outlives_requirement.blame_span);
828-
infcx.sub_regions(origin, outlived_region, region);
831+
832+
match outlives_requirement.subject {
833+
ClosureOutlivesSubject::Region(region) => {
834+
let region = closure_mapping[region];
835+
debug!(
836+
"apply_requirements: region={:?} \
837+
outlived_region={:?} \
838+
outlives_requirements={:?}",
839+
region,
840+
outlived_region,
841+
outlives_requirement
842+
);
843+
infcx.sub_regions(origin, outlived_region, region);
844+
}
845+
846+
ClosureOutlivesSubject::Ty(_ty) => {
847+
bug!("TODO not yet implemented -- closure outlives subject of a type");
848+
}
849+
}
829850
}
830851
}
831852
}

0 commit comments

Comments
 (0)