use ty::wf::ImpliedBound;
use rustc_data_structures::transitive_relation::TransitiveRelation;
-#[derive(Clone)]
+#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct FreeRegionMap {
// Stores the relation `a < b`, where `a` and `b` are regions.
relation: TransitiveRelation<Region>
FreeRegionMap { relation: TransitiveRelation::new() }
}
+ pub fn is_empty(&self) -> bool {
+ self.relation.is_empty()
+ }
+
pub fn relate_free_regions_from_implied_bounds<'tcx>(&mut self,
implied_bounds: &[ImpliedBound<'tcx>])
{
/// If any errors occurred while type-checking this body,
/// this field will be set to `true`.
pub tainted_by_errors: bool,
+
+ /// Stores the free-region relationships that were deduced from
+ /// its where clauses and parameter types. These are then
+ /// read-again by borrowck.
+ pub free_region_map: FreeRegionMap,
}
impl<'tcx> TypeckTables<'tcx> {
lints: lint::LintTable::new(),
used_trait_imports: DefIdSet(),
tainted_by_errors: false,
+ free_region_map: FreeRegionMap::new(),
}
}
pub region_maps: RegionMaps,
- // For each fn declared in the local crate, type check stores the
- // free-region relationships that were deduced from its where
- // clauses and parameter types. These are then read-again by
- // borrowck. (They are not used during trans, and hence are not
- // serialized or needed for cross-crate fns.)
- free_region_maps: RefCell<NodeMap<FreeRegionMap>>,
-
pub hir: hir_map::Map<'tcx>,
pub maps: maps::Maps<'tcx>,
interned
}
- pub fn store_free_region_map(self, id: NodeId, map: FreeRegionMap) {
- if self.free_region_maps.borrow_mut().insert(id, map).is_some() {
- bug!("Tried to overwrite interned FreeRegionMap for NodeId {:?}", id)
- }
- }
-
- pub fn free_region_map(self, id: NodeId) -> FreeRegionMap {
- self.free_region_maps.borrow()[&id].clone()
- }
-
pub fn lift<T: ?Sized + Lift<'tcx>>(self, value: &T) -> Option<T::Lifted> {
value.lift_to_tcx(self)
}
types: common_types,
named_region_map: named_region_map,
region_maps: region_maps,
- free_region_maps: RefCell::new(FxHashMap()),
variance_computed: Cell::new(false),
trait_map: resolutions.trait_map,
fulfilled_predicates: RefCell::new(fulfilled_predicates),
use rustc::middle::dataflow::KillFrom;
use rustc::hir::def_id::DefId;
use rustc::middle::expr_use_visitor as euv;
-use rustc::middle::free_region::FreeRegionMap;
use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
use rustc::middle::region;
use rustc::ty::{self, TyCtxt};
use std::fmt;
-use std::mem;
use std::rc::Rc;
use std::hash::{Hash, Hasher};
use syntax::ast;
match fk {
FnKind::ItemFn(..) |
FnKind::Method(..) => {
- self.with_temp_region_map(id, |this| {
- borrowck_fn(this, fk, fd, b, s, id, fk.attrs())
- });
+ borrowck_fn(self, fk, fd, b, s, id, fk.attrs())
}
FnKind::Closure(..) => {
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let mut bccx = BorrowckCtxt {
tcx: tcx,
- free_region_map: FreeRegionMap::new(),
+ tables: None,
stats: BorrowStats {
loaned_paths_same: 0,
loaned_paths_imm: 0,
attributes: &[ast::Attribute]) {
debug!("borrowck_fn(id={})", id);
+ assert!(this.tables.is_none());
+ let owner_def_id = this.tcx.hir.local_def_id(this.tcx.hir.body_owner(body_id));
+ let tables = this.tcx.item_tables(owner_def_id);
+ this.tables = Some(tables);
+
let body = this.tcx.hir.body(body_id);
if attributes.iter().any(|item| item.check_name("rustc_mir_borrowck")) {
- this.with_temp_region_map(id, |this| {
- mir::borrowck_mir(this, id, attributes)
- });
+ mir::borrowck_mir(this, id, attributes);
}
let cfg = cfg::CFG::new(this.tcx, &body.value);
check_loans::check_loans(this, &loan_dfcx, &flowed_moves, &all_loans[..], body);
+ this.tables = None;
+
intravisit::walk_fn(this, fk, decl, body_id, sp, id);
}
let mut bccx = BorrowckCtxt {
tcx: tcx,
- free_region_map: FreeRegionMap::new(),
+ tables: None,
stats: BorrowStats {
loaned_paths_same: 0,
loaned_paths_imm: 0,
pub struct BorrowckCtxt<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- // Hacky. As we visit various fns, we have to load up the
- // free-region map for each one. This map is computed by during
- // typeck for each fn item and stored -- closures just use the map
- // from the fn item that encloses them. Since we walk the fns in
- // order, we basically just overwrite this field as we enter a fn
- // item and restore it afterwards in a stack-like fashion. Then
- // the borrow checking code can assume that `free_region_map` is
- // always the correct map for the current fn. Feels like it'd be
- // better to just recompute this, rather than store it, but it's a
- // bit of a pain to factor that code out at the moment.
- free_region_map: FreeRegionMap,
+ // tables for the current thing we are checking; set to
+ // Some in `borrowck_fn` and cleared later
+ tables: Option<&'a ty::TypeckTables<'tcx>>,
// Statistics:
stats: BorrowStats
// Misc
impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
- fn with_temp_region_map<F>(&mut self, id: ast::NodeId, f: F)
- where F: for <'b> FnOnce(&'b mut BorrowckCtxt<'a, 'tcx>)
- {
- let new_free_region_map = self.tcx.free_region_map(id);
- let old_free_region_map = mem::replace(&mut self.free_region_map, new_free_region_map);
- f(self);
- self.free_region_map = old_free_region_map;
- }
-
- pub fn is_subregion_of(&self, r_sub: &'tcx ty::Region, r_sup: &'tcx ty::Region)
+ pub fn is_subregion_of(&self,
+ r_sub: &'tcx ty::Region,
+ r_sup: &'tcx ty::Region)
-> bool
{
- self.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup)
+ self.tables.unwrap().free_region_map
+ .is_subregion_of(self.tcx, r_sub, r_sup)
}
pub fn report(&self, err: BckError<'tcx>) {
#![feature(shared)]
#![feature(collections_range)]
#![feature(collections_bound)]
+#![cfg_attr(stage0,feature(field_init_shorthand))]
#![feature(nonzero)]
#![feature(rustc_private)]
#![feature(staged_api)]
// except according to those terms.
use bitvec::BitMatrix;
+use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
use std::cell::RefCell;
use std::fmt::Debug;
use std::mem;
closure: RefCell<Option<BitMatrix>>,
}
-#[derive(Clone, PartialEq, PartialOrd)]
+#[derive(Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
struct Index(usize);
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
struct Edge {
source: Index,
target: Index,
}
}
+ pub fn is_empty(&self) -> bool {
+ self.edges.is_empty()
+ }
+
fn index(&self, a: &T) -> Option<Index> {
self.elements.iter().position(|e| *e == *a).map(Index)
}
}
}
+impl<T> Encodable for TransitiveRelation<T>
+ where T: Encodable + Debug + PartialEq
+{
+ fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
+ s.emit_struct("TransitiveRelation", 2, |s| {
+ s.emit_struct_field("elements", 0, |s| self.elements.encode(s))?;
+ s.emit_struct_field("edges", 1, |s| self.edges.encode(s))?;
+ Ok(())
+ })
+ }
+}
+
+impl<T> Decodable for TransitiveRelation<T>
+ where T: Decodable + Debug + PartialEq
+{
+ fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
+ d.read_struct("TransitiveRelation", 2, |d| {
+ let elements = d.read_struct_field("elements", 0, |d| Decodable::decode(d))?;
+ let edges = d.read_struct_field("edges", 1, |d| Decodable::decode(d))?;
+ Ok(TransitiveRelation { elements, edges, closure: RefCell::new(None) })
+ })
+ }
+}
+
#[test]
fn test_one_step() {
let mut relation = TransitiveRelation::new();
rcx.visit_region_obligations(id);
}
rcx.resolve_regions_and_report_errors();
+
+ assert!(self.tables.borrow().free_region_map.is_empty());
+ self.tables.borrow_mut().free_region_map = rcx.free_region_map;
}
/// Region checking during the WF phase for items. `wf_tys` are the
rcx.resolve_regions_and_report_errors();
- // For the top-level fn, store the free-region-map. We don't store
- // any map for closures; they just share the same map as the
- // function that created them.
- self.tcx.store_free_region_map(fn_id, rcx.free_region_map);
+ // In this mode, we also copy the free-region-map into the
+ // tables of the enclosing fcx. In the other regionck modes
+ // (e.g., `regionck_item`), we don't have an enclosing tables.
+ assert!(self.tables.borrow().free_region_map.is_empty());
+ self.tables.borrow_mut().free_region_map = rcx.free_region_map;
}
}
wbcx.visit_type_nodes();
wbcx.visit_cast_types();
wbcx.visit_lints();
+ wbcx.visit_free_region_map();
let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports,
DefIdSet());
self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints);
}
+ fn visit_free_region_map(&mut self) {
+ self.tables.free_region_map = self.fcx.tables.borrow().free_region_map.clone();
+ }
+
fn visit_anon_types(&mut self) {
let gcx = self.tcx().global_tcx();
for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {