]>
Commit | Line | Data |
---|---|---|
3b2f2976 XL |
1 | // Copyright 2017 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | use rustc::ty::TypeFoldable; | |
12 | use rustc::ty::subst::{Kind, Substs}; | |
13 | use rustc::ty::{Ty, TyCtxt, ClosureSubsts, RegionVid, RegionKind}; | |
14 | use rustc::mir::{Mir, Location, Rvalue, BasicBlock, Statement, StatementKind}; | |
15 | use rustc::mir::visit::{MutVisitor, Lookup}; | |
16 | use rustc::mir::transform::{MirPass, MirSource}; | |
17 | use rustc::infer::{self, InferCtxt}; | |
18 | use syntax_pos::DUMMY_SP; | |
19 | use std::collections::HashMap; | |
20 | ||
21 | #[allow(dead_code)] | |
22 | struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { | |
23 | lookup_map: HashMap<RegionVid, Lookup>, | |
24 | infcx: InferCtxt<'a, 'gcx, 'tcx>, | |
25 | } | |
26 | ||
27 | impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> { | |
28 | pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self { | |
29 | NLLVisitor { | |
30 | infcx, | |
31 | lookup_map: HashMap::new(), | |
32 | } | |
33 | } | |
34 | ||
35 | pub fn into_results(self) -> HashMap<RegionVid, Lookup> { | |
36 | self.lookup_map | |
37 | } | |
38 | ||
39 | fn renumber_regions<T>(&self, value: &T) -> T where T: TypeFoldable<'tcx> { | |
40 | self.infcx.tcx.fold_regions(value, &mut false, |_region, _depth| { | |
41 | self.infcx.next_region_var(infer::MiscVariable(DUMMY_SP)) | |
42 | }) | |
43 | } | |
44 | ||
45 | fn store_region(&mut self, region: &RegionKind, lookup: Lookup) { | |
46 | if let RegionKind::ReVar(rid) = *region { | |
47 | self.lookup_map.entry(rid).or_insert(lookup); | |
48 | } | |
49 | } | |
50 | ||
51 | fn store_ty_regions(&mut self, ty: &Ty<'tcx>, lookup: Lookup) { | |
52 | for region in ty.regions() { | |
53 | self.store_region(region, lookup); | |
54 | } | |
55 | } | |
56 | ||
57 | fn store_kind_regions(&mut self, kind: &'tcx Kind, lookup: Lookup) { | |
58 | if let Some(ty) = kind.as_type() { | |
59 | self.store_ty_regions(&ty, lookup); | |
60 | } else if let Some(region) = kind.as_region() { | |
61 | self.store_region(region, lookup); | |
62 | } | |
63 | } | |
64 | } | |
65 | ||
66 | impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { | |
67 | fn visit_ty(&mut self, ty: &mut Ty<'tcx>, lookup: Lookup) { | |
68 | let old_ty = *ty; | |
69 | *ty = self.renumber_regions(&old_ty); | |
70 | self.store_ty_regions(ty, lookup); | |
71 | } | |
72 | ||
73 | fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) { | |
74 | *substs = self.renumber_regions(&{*substs}); | |
75 | let lookup = Lookup::Loc(location); | |
76 | for kind in *substs { | |
77 | self.store_kind_regions(kind, lookup); | |
78 | } | |
79 | } | |
80 | ||
81 | fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { | |
82 | match *rvalue { | |
83 | Rvalue::Ref(ref mut r, _, _) => { | |
84 | let old_r = *r; | |
85 | *r = self.renumber_regions(&old_r); | |
86 | let lookup = Lookup::Loc(location); | |
87 | self.store_region(r, lookup); | |
88 | } | |
89 | Rvalue::Use(..) | | |
90 | Rvalue::Repeat(..) | | |
91 | Rvalue::Len(..) | | |
92 | Rvalue::Cast(..) | | |
93 | Rvalue::BinaryOp(..) | | |
94 | Rvalue::CheckedBinaryOp(..) | | |
95 | Rvalue::UnaryOp(..) | | |
96 | Rvalue::Discriminant(..) | | |
97 | Rvalue::NullaryOp(..) | | |
98 | Rvalue::Aggregate(..) => { | |
99 | // These variants don't contain regions. | |
100 | } | |
101 | } | |
102 | self.super_rvalue(rvalue, location); | |
103 | } | |
104 | ||
105 | fn visit_closure_substs(&mut self, | |
106 | substs: &mut ClosureSubsts<'tcx>, | |
107 | location: Location) { | |
108 | *substs = self.renumber_regions(substs); | |
109 | let lookup = Lookup::Loc(location); | |
110 | for kind in substs.substs { | |
111 | self.store_kind_regions(kind, lookup); | |
112 | } | |
113 | } | |
114 | ||
115 | fn visit_statement(&mut self, | |
116 | block: BasicBlock, | |
117 | statement: &mut Statement<'tcx>, | |
118 | location: Location) { | |
119 | if let StatementKind::EndRegion(_) = statement.kind { | |
120 | statement.kind = StatementKind::Nop; | |
121 | } | |
122 | self.super_statement(block, statement, location); | |
123 | } | |
124 | } | |
125 | ||
126 | // MIR Pass for non-lexical lifetimes | |
127 | pub struct NLL; | |
128 | ||
129 | impl MirPass for NLL { | |
130 | fn run_pass<'a, 'tcx>(&self, | |
131 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
132 | _: MirSource, | |
133 | mir: &mut Mir<'tcx>) { | |
134 | if !tcx.sess.opts.debugging_opts.nll { | |
135 | return; | |
136 | } | |
137 | ||
138 | tcx.infer_ctxt().enter(|infcx| { | |
139 | // Clone mir so we can mutate it without disturbing the rest of the compiler | |
140 | let mut renumbered_mir = mir.clone(); | |
141 | let mut visitor = NLLVisitor::new(infcx); | |
142 | visitor.visit_mir(&mut renumbered_mir); | |
143 | let _results = visitor.into_results(); | |
144 | }) | |
145 | } | |
146 | } |