From d2fc06e7f6068f3e30a21099f4cf4a2e423e9159 Mon Sep 17 00:00:00 2001 From: Paul Faria Date: Mon, 17 Jul 2017 22:26:21 -0400 Subject: [PATCH 1/4] Renumber regions as the first step of the non-lexical lifetimes inference --- src/librustc_mir/transform/nll.rs | 94 +++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 12 deletions(-) diff --git a/src/librustc_mir/transform/nll.rs b/src/librustc_mir/transform/nll.rs index 3273b4ff347e5..65294e9ef24b7 100644 --- a/src/librustc_mir/transform/nll.rs +++ b/src/librustc_mir/transform/nll.rs @@ -8,26 +8,90 @@ // 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::ty::TypeFoldable; +use rustc::ty::subst::Substs; +use rustc::ty::{Ty, TyCtxt, ClosureSubsts}; +use rustc::mir::{Mir, Location, Rvalue, BasicBlock, Statement, StatementKind}; use rustc::mir::visit::MutVisitor; use rustc::mir::transform::{MirPass, MirSource}; +use rustc::infer::{self, InferCtxt}; +use syntax_pos::Span; #[allow(dead_code)] -struct NLLVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, +struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { + infcx: InferCtxt<'a, 'gcx, 'tcx>, + source: Mir<'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>, source: Mir<'tcx>) -> Self { NLLVisitor { - tcx: tcx + infcx: infcx, + source: source, } } + + fn renumber_regions(&self, value: &T, span: Span) -> T where T: TypeFoldable<'tcx> { + self.infcx.tcx.fold_regions(value, &mut false, |_region, _depth| { + self.infcx.next_region_var(infer::MiscVariable(span)) + }) + } } -impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { - // FIXME: Nashenas88: implement me! +fn span_from_location<'tcx>(source: Mir<'tcx>, location: Location) -> Span { + source[location.block].statements[location.statement_index].source_info.span +} + +impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { + fn visit_ty(&mut self, ty: &mut Ty<'tcx>) { + let old_ty = *ty; + // FIXME: Nashenas88 - span should be narrowed down + *ty = self.renumber_regions(&old_ty, self.source.span); + } + + fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>) { + // FIXME: Nashenas88 - span should be narrowed down + *substs = self.renumber_regions(&{*substs}, self.source.span); + } + + fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { + match *rvalue { + Rvalue::Ref(ref mut r, _, _) => { + let span = span_from_location(location); + let old_r = *r; + *r = self.renumber_regions(&old_r, span); + } + 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>) { + // FIXME: Nashenas88 - span should be narrowed down + *substs = self.renumber_regions(substs, self.source.span); + } + + 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 +102,16 @@ impl MirPass for NLL { tcx: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) { - if tcx.sess.opts.debugging_opts.nll { + if !tcx.sess.opts.debugging_opts.nll { + return; + } + + tcx.infer_ctxt().enter(|infcx| { + let mut visitor = NLLVisitor::new(infcx, mir.clone()); // Clone mir so we can mutate it without disturbing the rest // of the compiler - NLLVisitor::new(tcx).visit_mir(&mut mir.clone()); - } + let mut mir = mir.clone(); + visitor.visit_mir(&mut mir); + }) } } \ No newline at end of file From 5b2f6c7302cd81040d77e35aabac376bc33e4512 Mon Sep 17 00:00:00 2001 From: Paul Faria Date: Sun, 30 Jul 2017 15:08:07 -0400 Subject: [PATCH 2/4] Consume MirVisitor changes and use more accurate spans for region renumbering --- src/librustc_mir/transform/nll.rs | 41 +++++++++++++++++-------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/librustc_mir/transform/nll.rs b/src/librustc_mir/transform/nll.rs index 65294e9ef24b7..0793bdabf0ba9 100644 --- a/src/librustc_mir/transform/nll.rs +++ b/src/librustc_mir/transform/nll.rs @@ -12,7 +12,7 @@ use rustc::ty::TypeFoldable; use rustc::ty::subst::Substs; use rustc::ty::{Ty, TyCtxt, ClosureSubsts}; use rustc::mir::{Mir, Location, Rvalue, BasicBlock, Statement, StatementKind}; -use rustc::mir::visit::MutVisitor; +use rustc::mir::visit::{MutVisitor, Lookup}; use rustc::mir::transform::{MirPass, MirSource}; use rustc::infer::{self, InferCtxt}; use syntax_pos::Span; @@ -20,11 +20,11 @@ use syntax_pos::Span; #[allow(dead_code)] struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { infcx: InferCtxt<'a, 'gcx, 'tcx>, - source: Mir<'tcx> + source: &'a Mir<'tcx> } impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> { - pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>, source: Mir<'tcx>) -> Self { + pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>, source: &'a Mir<'tcx>) -> Self { NLLVisitor { infcx: infcx, source: source, @@ -38,28 +38,29 @@ impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> { } } -fn span_from_location<'tcx>(source: Mir<'tcx>, location: Location) -> Span { +fn span_from_location<'tcx>(source: &Mir<'tcx>, location: Location) -> Span { source[location.block].statements[location.statement_index].source_info.span } impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { - fn visit_ty(&mut self, ty: &mut Ty<'tcx>) { + fn visit_ty(&mut self, ty: &mut Ty<'tcx>, lookup: Lookup) { let old_ty = *ty; - // FIXME: Nashenas88 - span should be narrowed down - *ty = self.renumber_regions(&old_ty, self.source.span); + let span = match lookup { + Lookup::Loc(location) => span_from_location(self.source, location), + Lookup::Src(source_info) => source_info.span, + }; + *ty = self.renumber_regions(&old_ty, span); } - fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>) { - // FIXME: Nashenas88 - span should be narrowed down - *substs = self.renumber_regions(&{*substs}, self.source.span); + fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) { + *substs = self.renumber_regions(&{*substs}, span_from_location(self.source, location)); } fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { match *rvalue { Rvalue::Ref(ref mut r, _, _) => { - let span = span_from_location(location); let old_r = *r; - *r = self.renumber_regions(&old_r, span); + *r = self.renumber_regions(&old_r, span_from_location(self.source, location)); } Rvalue::Use(..) | Rvalue::Repeat(..) | @@ -78,9 +79,9 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { } fn visit_closure_substs(&mut self, - substs: &mut ClosureSubsts<'tcx>) { - // FIXME: Nashenas88 - span should be narrowed down - *substs = self.renumber_regions(substs, self.source.span); + substs: &mut ClosureSubsts<'tcx>, + location: Location) { + *substs = self.renumber_regions(substs, span_from_location(self.source, location)); } fn visit_statement(&mut self, @@ -107,11 +108,15 @@ impl MirPass for NLL { } tcx.infer_ctxt().enter(|infcx| { - let mut visitor = NLLVisitor::new(infcx, mir.clone()); // Clone mir so we can mutate it without disturbing the rest // of the compiler - let mut mir = mir.clone(); - visitor.visit_mir(&mut mir); + let mut renumbered_mir = mir.clone(); + + // Note that we're using the passed-in mir for the visitor. This is + // so we can lookup locations during traversal without worrying about + // maintaing both a mutable and immutable reference to the same object + let mut visitor = NLLVisitor::new(infcx, &mir); + visitor.visit_mir(&mut renumbered_mir); }) } } \ No newline at end of file From 7193c68271f62bc311e57ea5126e795babf02f1e Mon Sep 17 00:00:00 2001 From: Paul Faria Date: Thu, 3 Aug 2017 00:16:36 -0400 Subject: [PATCH 3/4] Store map of region variable ids to lookups in nll visitor and remove reference to mir --- src/librustc/mir/visit.rs | 1 + src/librustc_mir/transform/nll.rs | 71 ++++++++++++++++++++----------- 2 files changed, 46 insertions(+), 26 deletions(-) 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 0793bdabf0ba9..9699495eb0ef6 100644 --- a/src/librustc_mir/transform/nll.rs +++ b/src/librustc_mir/transform/nll.rs @@ -9,58 +9,78 @@ // except according to those terms. use rustc::ty::TypeFoldable; -use rustc::ty::subst::Substs; -use rustc::ty::{Ty, TyCtxt, ClosureSubsts}; +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::Span; +use syntax_pos::DUMMY_SP; +use std::collections::HashMap; #[allow(dead_code)] struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { + pub lookup_map: HashMap, infcx: InferCtxt<'a, 'gcx, 'tcx>, - source: &'a Mir<'tcx> } impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> { - pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>, source: &'a Mir<'tcx>) -> Self { + pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self { NLLVisitor { infcx: infcx, - source: source, + lookup_map: HashMap::new(), } } - fn renumber_regions(&self, value: &T, span: Span) -> T where T: TypeFoldable<'tcx> { + 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(span)) + self.infcx.next_region_var(infer::MiscVariable(DUMMY_SP)) }) } -} -fn span_from_location<'tcx>(source: &Mir<'tcx>, location: Location) -> Span { - source[location.block].statements[location.statement_index].source_info.span + 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, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { fn visit_ty(&mut self, ty: &mut Ty<'tcx>, lookup: Lookup) { let old_ty = *ty; - let span = match lookup { - Lookup::Loc(location) => span_from_location(self.source, location), - Lookup::Src(source_info) => source_info.span, - }; - *ty = self.renumber_regions(&old_ty, span); + *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}, span_from_location(self.source, 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, span_from_location(self.source, location)); + *r = self.renumber_regions(&old_r); + let lookup = Lookup::Loc(location); + self.store_region(r, lookup); } Rvalue::Use(..) | Rvalue::Repeat(..) | @@ -81,7 +101,11 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { fn visit_closure_substs(&mut self, substs: &mut ClosureSubsts<'tcx>, location: Location) { - *substs = self.renumber_regions(substs, span_from_location(self.source, 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, @@ -108,14 +132,9 @@ impl MirPass for NLL { } tcx.infer_ctxt().enter(|infcx| { - // Clone mir so we can mutate it without disturbing the rest - // of the compiler + // Clone mir so we can mutate it without disturbing the rest of the compiler let mut renumbered_mir = mir.clone(); - - // Note that we're using the passed-in mir for the visitor. This is - // so we can lookup locations during traversal without worrying about - // maintaing both a mutable and immutable reference to the same object - let mut visitor = NLLVisitor::new(infcx, &mir); + let mut visitor = NLLVisitor::new(infcx); visitor.visit_mir(&mut renumbered_mir); }) } From 0d29cd4c80a9cc042d34ea31d70ff42830df0001 Mon Sep 17 00:00:00 2001 From: Paul Faria Date: Fri, 4 Aug 2017 09:06:55 -0400 Subject: [PATCH 4/4] Keep map hidden and instead move it out after visitor is finished --- src/librustc_mir/transform/nll.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/nll.rs b/src/librustc_mir/transform/nll.rs index 9699495eb0ef6..fb4764c496268 100644 --- a/src/librustc_mir/transform/nll.rs +++ b/src/librustc_mir/transform/nll.rs @@ -20,7 +20,7 @@ use std::collections::HashMap; #[allow(dead_code)] struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { - pub lookup_map: HashMap, + lookup_map: HashMap, infcx: InferCtxt<'a, 'gcx, 'tcx>, } @@ -32,6 +32,10 @@ impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> { } } + 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)) @@ -136,6 +140,7 @@ impl MirPass for NLL { 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