diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index fd3a9f8cd2d9a..2b3bb098a8022 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -741,6 +741,7 @@ macro_rules! make_mir_visitor { make_mir_visitor!(Visitor,); make_mir_visitor!(MutVisitor,mut); +#[derive(Copy, Clone, Debug)] pub enum Lookup { Loc(Location), Src(SourceInfo), diff --git a/src/librustc_mir/transform/nll.rs b/src/librustc_mir/transform/nll.rs index 3273b4ff347e5..fb4764c496268 100644 --- a/src/librustc_mir/transform/nll.rs +++ b/src/librustc_mir/transform/nll.rs @@ -8,26 +8,119 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::ty::TyCtxt; -use rustc::mir::Mir; -use rustc::mir::visit::MutVisitor; +use rustc::ty::TypeFoldable; +use rustc::ty::subst::{Kind, Substs}; +use rustc::ty::{Ty, TyCtxt, ClosureSubsts, RegionVid, RegionKind}; +use rustc::mir::{Mir, Location, Rvalue, BasicBlock, Statement, StatementKind}; +use rustc::mir::visit::{MutVisitor, Lookup}; use rustc::mir::transform::{MirPass, MirSource}; +use rustc::infer::{self, InferCtxt}; +use syntax_pos::DUMMY_SP; +use std::collections::HashMap; #[allow(dead_code)] -struct NLLVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { + lookup_map: HashMap, + infcx: InferCtxt<'a, 'gcx, 'tcx>, } -impl<'a, 'tcx> NLLVisitor<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { +impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> { + pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self { NLLVisitor { - tcx: tcx + infcx: infcx, + lookup_map: HashMap::new(), + } + } + + pub fn into_results(self) -> HashMap { + self.lookup_map + } + + fn renumber_regions(&self, value: &T) -> T where T: TypeFoldable<'tcx> { + self.infcx.tcx.fold_regions(value, &mut false, |_region, _depth| { + self.infcx.next_region_var(infer::MiscVariable(DUMMY_SP)) + }) + } + + fn store_region(&mut self, region: &RegionKind, lookup: Lookup) { + if let RegionKind::ReVar(rid) = *region { + self.lookup_map.entry(rid).or_insert(lookup); + } + } + + fn store_ty_regions(&mut self, ty: &Ty<'tcx>, lookup: Lookup) { + for region in ty.regions() { + self.store_region(region, lookup); + } + } + + fn store_kind_regions(&mut self, kind: &'tcx Kind, lookup: Lookup) { + if let Some(ty) = kind.as_type() { + self.store_ty_regions(&ty, lookup); + } else if let Some(region) = kind.as_region() { + self.store_region(region, lookup); } } } -impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { - // FIXME: Nashenas88: implement me! +impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { + fn visit_ty(&mut self, ty: &mut Ty<'tcx>, lookup: Lookup) { + let old_ty = *ty; + *ty = self.renumber_regions(&old_ty); + self.store_ty_regions(ty, lookup); + } + + fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) { + *substs = self.renumber_regions(&{*substs}); + let lookup = Lookup::Loc(location); + for kind in *substs { + self.store_kind_regions(kind, lookup); + } + } + + fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { + match *rvalue { + Rvalue::Ref(ref mut r, _, _) => { + let old_r = *r; + *r = self.renumber_regions(&old_r); + let lookup = Lookup::Loc(location); + self.store_region(r, lookup); + } + Rvalue::Use(..) | + Rvalue::Repeat(..) | + Rvalue::Len(..) | + Rvalue::Cast(..) | + Rvalue::BinaryOp(..) | + Rvalue::CheckedBinaryOp(..) | + Rvalue::UnaryOp(..) | + Rvalue::Discriminant(..) | + Rvalue::NullaryOp(..) | + Rvalue::Aggregate(..) => { + // These variants don't contain regions. + } + } + self.super_rvalue(rvalue, location); + } + + fn visit_closure_substs(&mut self, + substs: &mut ClosureSubsts<'tcx>, + location: Location) { + *substs = self.renumber_regions(substs); + let lookup = Lookup::Loc(location); + for kind in substs.substs { + self.store_kind_regions(kind, lookup); + } + } + + fn visit_statement(&mut self, + block: BasicBlock, + statement: &mut Statement<'tcx>, + location: Location) { + if let StatementKind::EndRegion(_) = statement.kind { + statement.kind = StatementKind::Nop; + } + self.super_statement(block, statement, location); + } } // MIR Pass for non-lexical lifetimes @@ -38,10 +131,16 @@ impl MirPass for NLL { tcx: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) { - if tcx.sess.opts.debugging_opts.nll { - // Clone mir so we can mutate it without disturbing the rest - // of the compiler - NLLVisitor::new(tcx).visit_mir(&mut mir.clone()); + if !tcx.sess.opts.debugging_opts.nll { + return; } + + tcx.infer_ctxt().enter(|infcx| { + // Clone mir so we can mutate it without disturbing the rest of the compiler + let mut renumbered_mir = mir.clone(); + let mut visitor = NLLVisitor::new(infcx); + visitor.visit_mir(&mut renumbered_mir); + let _results = visitor.into_results(); + }) } } \ No newline at end of file