+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Code to extract the free regions declared on a function and the
-//! relationships between them. For example:
-//!
-//! ```
-//! fn foo<'a, 'b, 'c: 'b>() { }
-//! ```
-//!
-//! here we would be returning a map assigning each of `{'a, 'b, 'c}`
-//! to an index, as well as the `FreeRegionMap` which can compute
-//! relationships between them.
-//!
-//! The code in this file doesn't *do anything* with those results; it
-//! just returns them for other code to use.
-
-use rustc::hir::def_id::DefId;
-use rustc::infer::InferCtxt;
-use rustc::infer::outlives::free_region_map::FreeRegionMap;
-use rustc::ty::{self, RegionVid};
-use rustc::ty::subst::Substs;
-use rustc::util::nodemap::FxHashMap;
-use rustc_data_structures::indexed_vec::Idx;
-
-#[derive(Debug)]
-pub struct FreeRegions<'tcx> {
- /// Given a free region defined on this function (either early- or
- /// late-bound), this maps it to its internal region index. When
- /// the region context is created, the first N variables will be
- /// created based on these indices.
- pub indices: FxHashMap<ty::Region<'tcx>, RegionVid>,
-
- /// The map from the typeck tables telling us how to relate free regions.
- pub free_region_map: &'tcx FreeRegionMap<'tcx>,
-}
-
-pub fn free_regions<'a, 'gcx, 'tcx>(
- infcx: &InferCtxt<'a, 'gcx, 'tcx>,
- item_def_id: DefId,
-) -> FreeRegions<'tcx> {
- debug!("free_regions(item_def_id={:?})", item_def_id);
-
- let mut indices = FxHashMap();
-
- // `'static` is always free.
- insert_free_region(&mut indices, infcx.tcx.types.re_static);
-
- // Extract the early regions.
- let item_substs = Substs::identity_for_item(infcx.tcx, item_def_id);
- for item_subst in item_substs {
- if let Some(region) = item_subst.as_region() {
- insert_free_region(&mut indices, region);
- }
- }
-
- // Extract the late-bound regions. Use the liberated fn sigs,
- // where the late-bound regions will have been converted into free
- // regions, and add them to the map.
- let item_id = infcx.tcx.hir.as_local_node_id(item_def_id).unwrap();
- let fn_hir_id = infcx.tcx.hir.node_to_hir_id(item_id);
- let tables = infcx.tcx.typeck_tables_of(item_def_id);
- let fn_sig = tables.liberated_fn_sigs()[fn_hir_id].clone();
- infcx
- .tcx
- .for_each_free_region(&fn_sig.inputs_and_output, |region| {
- if let ty::ReFree(_) = *region {
- insert_free_region(&mut indices, region);
- }
- });
-
- debug!("free_regions: indices={:#?}", indices);
-
- FreeRegions { indices, free_region_map: &tables.free_region_map }
-}
-
-fn insert_free_region<'tcx>(
- free_regions: &mut FxHashMap<ty::Region<'tcx>, RegionVid>,
- region: ty::Region<'tcx>,
-) {
- let next = RegionVid::new(free_regions.len());
- free_regions.entry(region).or_insert(next);
-}
mod constraint_generation;
mod subtype_constraint_generation;
-mod free_regions;
-use self::free_regions::FreeRegions;
+mod universal_regions;
+use self::universal_regions::UniversalRegions;
pub(crate) mod region_infer;
use self::region_infer::RegionInferenceContext;
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
def_id: DefId,
mir: &mut Mir<'tcx>,
-) -> FreeRegions<'tcx> {
+) -> UniversalRegions<'tcx> {
// Compute named region information.
- let free_regions = free_regions::free_regions(infcx, def_id);
+ let universal_regions = universal_regions::universal_regions(infcx, def_id);
// Replace all regions with fresh inference variables.
- renumber::renumber_mir(infcx, &free_regions, mir);
+ renumber::renumber_mir(infcx, &universal_regions, mir);
- free_regions
+ universal_regions
}
/// Computes the (non-lexical) regions from the input MIR.
pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
def_id: DefId,
- free_regions: FreeRegions<'tcx>,
+ universal_regions: UniversalRegions<'tcx>,
mir: &Mir<'tcx>,
param_env: ty::ParamEnv<'gcx>,
flow_inits: &mut FlowInProgress<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
// Create the region inference context, taking ownership of the region inference
// data that was contained in `infcx`.
let var_origins = infcx.take_region_var_origins();
- let mut regioncx = RegionInferenceContext::new(var_origins, &free_regions, mir);
- subtype_constraint_generation::generate(&mut regioncx, &free_regions, mir, constraint_sets);
+ let mut regioncx = RegionInferenceContext::new(var_origins, &universal_regions, mir);
+ subtype_constraint_generation::generate(
+ &mut regioncx,
+ &universal_regions,
+ mir,
+ constraint_sets,
+ );
// Compute what is live where.
let liveness = &LivenessResults {
writeln!(out, " | Live variables at {:?}: {}", location, s)?;
}
- PassWhere::AfterLocation(_) |
- PassWhere::AfterCFG => {}
+ PassWhere::AfterLocation(_) | PassWhere::AfterCFG => {}
}
Ok(())
});
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::free_regions::FreeRegions;
+use super::universal_regions::UniversalRegions;
use rustc::infer::InferCtxt;
use rustc::infer::RegionVariableOrigin;
use rustc::infer::NLLRegionVariableOrigin;
/// The liveness constraints added to each region. For most
/// regions, these start out empty and steadily grow, though for
- /// each free region R they start out containing the entire CFG
- /// and `end(R)`.
+ /// each universally quantified region R they start out containing
+ /// the entire CFG and `end(R)`.
///
/// In this `BitMatrix` representation, the rows are the region
/// variables and the columns are the free regions and MIR locations.
/// the free regions.)
point_indices: BTreeMap<Location, usize>,
- num_free_regions: usize,
+ /// Number of universally quantified regions. This is used to
+ /// determine the meaning of the bits in `inferred_values` and
+ /// friends.
+ num_universal_regions: usize,
free_region_map: &'tcx FreeRegionMap<'tcx>,
}
/// Creates a new region inference context with a total of
/// `num_region_variables` valid inference variables; the first N
/// of those will be constant regions representing the free
- /// regions defined in `free_regions`.
- pub fn new(var_origins: VarOrigins, free_regions: &FreeRegions<'tcx>, mir: &Mir<'tcx>) -> Self {
+ /// regions defined in `universal_regions`.
+ pub fn new(
+ var_origins: VarOrigins,
+ universal_regions: &UniversalRegions<'tcx>,
+ mir: &Mir<'tcx>,
+ ) -> Self {
let num_region_variables = var_origins.len();
- let num_free_regions = free_regions.indices.len();
+ let num_universal_regions = universal_regions.indices.len();
let mut num_points = 0;
let mut point_indices = BTreeMap::new();
block,
statement_index,
};
- point_indices.insert(location, num_free_regions + num_points);
+ point_indices.insert(location, num_universal_regions + num_points);
num_points += 1;
}
}
definitions,
liveness_constraints: BitMatrix::new(
num_region_variables,
- num_free_regions + num_points,
+ num_universal_regions + num_points,
),
inferred_values: None,
constraints: Vec::new(),
point_indices,
- num_free_regions,
- free_region_map: free_regions.free_region_map,
+ num_universal_regions,
+ free_region_map: universal_regions.free_region_map,
};
- result.init_free_regions(free_regions);
+ result.init_universal_regions(universal_regions);
result
}
- /// Initializes the region variables for each free region
- /// (lifetime parameter). The first N variables always correspond
- /// to the free regions appearing in the function signature (both
- /// named and anonymous) and where clauses. This function iterates
- /// over those regions and initializes them with minimum values.
+ /// Initializes the region variables for each universally
+ /// quantified region (lifetime parameter). The first N variables
+ /// always correspond to the regions appearing in the function
+ /// signature (both named and anonymous) and where clauses. This
+ /// function iterates over those regions and initializes them with
+ /// minimum values.
///
/// For example:
///
/// and (b) any free regions that it outlives, which in this case
/// is just itself. R1 (`'b`) in contrast also outlives `'a` and
/// hence contains R0 and R1.
- fn init_free_regions(&mut self, free_regions: &FreeRegions<'tcx>) {
- let FreeRegions {
+ fn init_universal_regions(&mut self, universal_regions: &UniversalRegions<'tcx>) {
+ let UniversalRegions {
indices,
free_region_map: _,
- } = free_regions;
+ } = universal_regions;
- // For each free region X:
+ // For each universally quantified region X:
for (free_region, &variable) in indices {
// These should be free-region variables.
assert!(match self.definitions[variable].origin {
&self,
matrix: &BitMatrix,
r: RegionVid,
- s: RegionVid
+ s: RegionVid,
) -> bool {
matrix.contains(r.index(), s.index())
}
}
}
- for fr in (0 .. self.num_free_regions).map(RegionVid::new) {
+ for fr in (0..self.num_universal_regions).map(RegionVid::new) {
if self.region_contains_region_in_matrix(inferred_values, r, fr) {
result.push_str(&format!("{}{:?}", sep, fr));
sep = ", ";
// Find the minimal regions that can solve the constraints. This is infallible.
self.propagate_constraints(mir);
- // Now, see whether any of the constraints were too strong. In particular,
- // we want to check for a case where a free region exceeded its bounds.
- // Consider:
+ // Now, see whether any of the constraints were too strong. In
+ // particular, we want to check for a case where a universally
+ // quantified region exceeded its bounds. Consider:
//
// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
//
// have no evidence that `'b` outlives `'a`, so we want to report
// an error.
- // The free regions are always found in a prefix of the full list.
+ // The universal regions are always found in a prefix of the
+ // full list.
let free_region_definitions = self.definitions
.iter_enumerated()
.take_while(|(_, fr_definition)| fr_definition.name.is_some());
// Find every region `o` such that `fr: o`
// (because `fr` includes `end(o)`).
- for outlived_fr in fr_value.take_while(|&i| i < self.num_free_regions) {
+ for outlived_fr in fr_value.take_while(|&i| i < self.num_universal_regions) {
// `fr` includes `end(fr)`, that's not especially
// interesting.
if fr.index() == outlived_fr {
// If we reach the END point in the graph, then copy
// over any skolemized end points in the `from_region`
// and make sure they are included in the `to_region`.
- let free_region_indices = inferred_values
+ let universal_region_indices = inferred_values
.iter(from_region.index())
- .take_while(|&i| i < self.num_free_regions)
+ .take_while(|&i| i < self.num_universal_regions)
.collect::<Vec<_>>();
- for fr in &free_region_indices {
+ for fr in &universal_region_indices {
changed |= inferred_values.add(to_region.index(), *fr);
}
} else {
fn new(origin: RegionVariableOrigin) -> Self {
// Create a new region definition. Note that, for free
// regions, these fields get updated later in
- // `init_free_regions`.
+ // `init_universal_regions`.
Self { origin, name: None }
}
}
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
use super::ToRegionVid;
-use super::free_regions::FreeRegions;
+use super::universal_regions::UniversalRegions;
/// Replaces all free regions appearing in the MIR with fresh
/// inference variables, returning the number of variables created.
pub fn renumber_mir<'a, 'gcx, 'tcx>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
- free_regions: &FreeRegions<'tcx>,
+ universal_regions: &UniversalRegions<'tcx>,
mir: &mut Mir<'tcx>,
) {
// Create inference variables for each of the free regions
// declared on the function signature.
- let free_region_inference_vars = (0..free_regions.indices.len())
+ let free_region_inference_vars = (0..universal_regions.indices.len())
.map(RegionVid::new)
.map(|vid_expected| {
let r = infcx.next_nll_region_var(NLLRegionVariableOrigin::FreeRegion);
.collect();
debug!("renumber_mir()");
- debug!("renumber_mir: free_regions={:#?}", free_regions);
+ debug!("renumber_mir: universal_regions={:#?}", universal_regions);
debug!("renumber_mir: mir.arg_count={:?}", mir.arg_count);
let mut visitor = NLLVisitor {
infcx,
- free_regions,
+ universal_regions,
free_region_inference_vars,
arg_count: mir.arg_count,
};
struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
- free_regions: &'a FreeRegions<'tcx>,
+ universal_regions: &'a UniversalRegions<'tcx>,
free_region_inference_vars: IndexVec<RegionVid, ty::Region<'tcx>>,
arg_count: usize,
}
/// Renumbers the regions appearing in `value`, but those regions
/// are expected to be free regions from the function signature.
- fn renumber_free_regions<T>(&mut self, value: &T) -> T
+ fn renumber_universal_regions<T>(&mut self, value: &T) -> T
where
T: TypeFoldable<'tcx>,
{
- debug!("renumber_free_regions(value={:?})", value);
+ debug!("renumber_universal_regions(value={:?})", value);
self.infcx
.tcx
.fold_regions(value, &mut false, |region, _depth| {
- let index = self.free_regions.indices[®ion];
+ let index = self.universal_regions.indices[®ion];
self.free_region_inference_vars[index]
})
}
let old_ty = *ty;
*ty = if is_arg {
- self.renumber_free_regions(&old_ty)
+ self.renumber_universal_regions(&old_ty)
} else {
self.renumber_regions(ty_context, &old_ty)
};
use transform::type_check::MirTypeckRegionConstraints;
use transform::type_check::OutlivesSet;
-use super::free_regions::FreeRegions;
+use super::universal_regions::UniversalRegions;
use super::region_infer::RegionInferenceContext;
/// When the MIR type-checker executes, it validates all the types in
/// them into the NLL `RegionInferenceContext`.
pub(super) fn generate<'tcx>(
regioncx: &mut RegionInferenceContext<'tcx>,
- free_regions: &FreeRegions<'tcx>,
+ universal_regions: &UniversalRegions<'tcx>,
mir: &Mir<'tcx>,
constraints: &MirTypeckRegionConstraints<'tcx>,
) {
SubtypeConstraintGenerator {
regioncx,
- free_regions,
+ universal_regions,
mir,
}.generate(constraints);
}
struct SubtypeConstraintGenerator<'cx, 'tcx: 'cx> {
regioncx: &'cx mut RegionInferenceContext<'tcx>,
- free_regions: &'cx FreeRegions<'tcx>,
+ universal_regions: &'cx UniversalRegions<'tcx>,
mir: &'cx Mir<'tcx>,
}
// Every region that we see in the constraints came from the
// MIR or from the parameter environment. If the former, it
// will be a region variable. If the latter, it will be in
- // the set of free regions *somewhere*.
+ // the set of universal regions *somewhere*.
if let ty::ReVar(vid) = r {
*vid
} else {
- self.free_regions.indices[&r]
+ self.universal_regions.indices[&r]
}
}
}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Code to extract the universally quantified regions declared on a
+//! function and the relationships between them. For example:
+//!
+//! ```
+//! fn foo<'a, 'b, 'c: 'b>() { }
+//! ```
+//!
+//! here we would be returning a map assigning each of `{'a, 'b, 'c}`
+//! to an index, as well as the `FreeRegionMap` which can compute
+//! relationships between them.
+//!
+//! The code in this file doesn't *do anything* with those results; it
+//! just returns them for other code to use.
+
+use rustc::hir::def_id::DefId;
+use rustc::infer::InferCtxt;
+use rustc::infer::outlives::free_region_map::FreeRegionMap;
+use rustc::ty::{self, RegionVid};
+use rustc::ty::subst::Substs;
+use rustc::util::nodemap::FxHashMap;
+use rustc_data_structures::indexed_vec::Idx;
+
+#[derive(Debug)]
+pub struct UniversalRegions<'tcx> {
+ /// Given a universally quantified region defined on this function
+ /// (either early- or late-bound), this maps it to its internal
+ /// region index. When the region context is created, the first N
+ /// variables will be created based on these indices.
+ pub indices: FxHashMap<ty::Region<'tcx>, RegionVid>,
+
+ /// The map from the typeck tables telling us how to relate universal regions.
+ pub free_region_map: &'tcx FreeRegionMap<'tcx>,
+}
+
+pub fn universal_regions<'a, 'gcx, 'tcx>(
+ infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+ item_def_id: DefId,
+) -> UniversalRegions<'tcx> {
+ debug!("universal_regions(item_def_id={:?})", item_def_id);
+
+ let mut indices = FxHashMap();
+
+ // `'static` is always free.
+ insert_free_region(&mut indices, infcx.tcx.types.re_static);
+
+ // Extract the early regions.
+ let item_substs = Substs::identity_for_item(infcx.tcx, item_def_id);
+ for item_subst in item_substs {
+ if let Some(region) = item_subst.as_region() {
+ insert_free_region(&mut indices, region);
+ }
+ }
+
+ // Extract the late-bound regions. Use the liberated fn sigs,
+ // where the late-bound regions will have been converted into free
+ // regions, and add them to the map.
+ let item_id = infcx.tcx.hir.as_local_node_id(item_def_id).unwrap();
+ let fn_hir_id = infcx.tcx.hir.node_to_hir_id(item_id);
+ let tables = infcx.tcx.typeck_tables_of(item_def_id);
+ let fn_sig = tables.liberated_fn_sigs()[fn_hir_id].clone();
+ infcx
+ .tcx
+ .for_each_free_region(&fn_sig.inputs_and_output, |region| {
+ if let ty::ReFree(_) = *region {
+ insert_free_region(&mut indices, region);
+ }
+ });
+
+ debug!("universal_regions: indices={:#?}", indices);
+
+ UniversalRegions { indices, free_region_map: &tables.free_region_map }
+}
+
+fn insert_free_region<'tcx>(
+ universal_regions: &mut FxHashMap<ty::Region<'tcx>, RegionVid>,
+ region: ty::Region<'tcx>,
+) {
+ let next = RegionVid::new(universal_regions.len());
+ universal_regions.entry(region).or_insert(next);
+}