Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non-lexical lifetimes region renumberer #43559

Merged
merged 4 commits into from
Aug 11, 2017
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
122 changes: 108 additions & 14 deletions src/librustc_mir/transform/nll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,115 @@
// 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> {
pub lookup_map: HashMap<RegionVid, Lookup>,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to add a method on NLLVisitor that takes ownership of self and returns the HashMap? This is rather than making the field public.

fn to_lookup(self) -> HashMap<RegionVid, Lookup> { self.lookup_map }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would usually do something like that, yeah, but I'd call it into_lookup() or into_results().

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(),
}
}

fn renumber_regions<T>(&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 {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure if this should also be used from the erase_regions pass. Should the be changed, left as is or just removed?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EndRegion is not going to be relevant with NLL, so I think this is OK

statement.kind = StatementKind::Nop;
}
self.super_statement(block, statement, location);
}
}

// MIR Pass for non-lexical lifetimes
Expand All @@ -38,10 +127,15 @@ 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);
})
}
}