Skip to content

Commit 785643a

Browse files
committed
Auto merge of #45668 - nikomatsakis:nll-free-region, r=arielb1
extend NLL with preliminary support for free regions on functions This PR extends #45538 with support for free regions. This is pretty preliminary and will no doubt want to change in various ways, particularly as we add support for closures, but it's enough to get the basic idea in place: - We now create specific regions to represent each named lifetime declared on the function. - Region values can contain references to these regions (represented for now as a `BTreeSet<RegionIndex>`). - If we wind up trying to infer that `'a: 'b` must hold, but no such relationship was declared, we report an error. It also does a number of drive-by refactorings. r? @arielb1 cc @spastorino
2 parents bd0e45a + 7b4282e commit 785643a

File tree

19 files changed

+660
-222
lines changed

19 files changed

+660
-222
lines changed

src/librustc/infer/error_reporting/mod.rs

+21
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
262262
errors: &Vec<RegionResolutionError<'tcx>>) {
263263
debug!("report_region_errors(): {} errors to start", errors.len());
264264

265+
if self.tcx.sess.opts.debugging_opts.nll {
266+
for error in errors {
267+
match *error {
268+
RegionResolutionError::ConcreteFailure(ref origin, ..) |
269+
RegionResolutionError::GenericBoundFailure(ref origin, ..) => {
270+
self.tcx.sess.span_warn(
271+
origin.span(),
272+
"not reporting region error due to -Znll");
273+
}
274+
275+
RegionResolutionError::SubSupConflict(ref rvo, ..) => {
276+
self.tcx.sess.span_warn(
277+
rvo.span(),
278+
"not reporting region error due to -Znll");
279+
}
280+
}
281+
}
282+
283+
return;
284+
}
285+
265286
// try to pre-process the errors, which will group some of them
266287
// together into a `ProcessedErrors` group:
267288
let errors = self.process_errors(errors);

src/librustc/middle/free_region.rs

+13
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,19 @@ impl<'tcx> FreeRegionMap<'tcx> {
182182
debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result);
183183
result
184184
}
185+
186+
/// Returns all regions that are known to outlive `r_a`. For
187+
/// example, in a function:
188+
///
189+
/// ```
190+
/// fn foo<'a, 'b: 'a, 'c: 'b>() { .. }
191+
/// ```
192+
///
193+
/// if `r_a` represents `'a`, this function would return `{'b, 'c}`.
194+
pub fn regions_that_outlive<'a, 'gcx>(&self, r_a: Region<'tcx>) -> Vec<&Region<'tcx>> {
195+
assert!(is_free(r_a));
196+
self.relation.greater_than(&r_a)
197+
}
185198
}
186199

187200
fn is_free(r: Region) -> bool {

src/librustc/mir/visit.rs

+34-17
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ macro_rules! make_mir_visitor {
209209

210210
fn visit_ty(&mut self,
211211
ty: & $($mutability)* Ty<'tcx>,
212-
_: Lookup) {
212+
_: TyContext) {
213213
self.super_ty(ty);
214214
}
215215

@@ -256,8 +256,9 @@ macro_rules! make_mir_visitor {
256256
}
257257

258258
fn visit_local_decl(&mut self,
259+
local: Local,
259260
local_decl: & $($mutability)* LocalDecl<'tcx>) {
260-
self.super_local_decl(local_decl);
261+
self.super_local_decl(local, local_decl);
261262
}
262263

263264
fn visit_local(&mut self,
@@ -291,14 +292,14 @@ macro_rules! make_mir_visitor {
291292
self.visit_visibility_scope_data(scope);
292293
}
293294

294-
let lookup = Lookup::Src(SourceInfo {
295+
let lookup = TyContext::SourceInfo(SourceInfo {
295296
span: mir.span,
296297
scope: ARGUMENT_VISIBILITY_SCOPE,
297298
});
298299
self.visit_ty(&$($mutability)* mir.return_ty, lookup);
299300

300-
for local_decl in &$($mutability)* mir.local_decls {
301-
self.visit_local_decl(local_decl);
301+
for local in mir.local_decls.indices() {
302+
self.visit_local_decl(local, & $($mutability)* mir.local_decls[local]);
302303
}
303304

304305
self.visit_span(&$($mutability)* mir.span);
@@ -359,7 +360,8 @@ macro_rules! make_mir_visitor {
359360
for operand in lvalues {
360361
self.visit_lvalue(& $($mutability)* operand.lval,
361362
LvalueContext::Validate, location);
362-
self.visit_ty(& $($mutability)* operand.ty, Lookup::Loc(location));
363+
self.visit_ty(& $($mutability)* operand.ty,
364+
TyContext::Location(location));
363365
}
364366
}
365367
StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
@@ -421,7 +423,7 @@ macro_rules! make_mir_visitor {
421423
ref values,
422424
ref targets } => {
423425
self.visit_operand(discr, source_location);
424-
self.visit_ty(switch_ty, Lookup::Loc(source_location));
426+
self.visit_ty(switch_ty, TyContext::Location(source_location));
425427
for value in &values[..] {
426428
self.visit_const_int(value, source_location);
427429
}
@@ -545,7 +547,7 @@ macro_rules! make_mir_visitor {
545547
ref $($mutability)* operand,
546548
ref $($mutability)* ty) => {
547549
self.visit_operand(operand, location);
548-
self.visit_ty(ty, Lookup::Loc(location));
550+
self.visit_ty(ty, TyContext::Location(location));
549551
}
550552

551553
Rvalue::BinaryOp(_bin_op,
@@ -567,15 +569,15 @@ macro_rules! make_mir_visitor {
567569
}
568570

569571
Rvalue::NullaryOp(_op, ref $($mutability)* ty) => {
570-
self.visit_ty(ty, Lookup::Loc(location));
572+
self.visit_ty(ty, TyContext::Location(location));
571573
}
572574

573575
Rvalue::Aggregate(ref $($mutability)* kind,
574576
ref $($mutability)* operands) => {
575577
let kind = &$($mutability)* **kind;
576578
match *kind {
577579
AggregateKind::Array(ref $($mutability)* ty) => {
578-
self.visit_ty(ty, Lookup::Loc(location));
580+
self.visit_ty(ty, TyContext::Location(location));
579581
}
580582
AggregateKind::Tuple => {
581583
}
@@ -645,7 +647,7 @@ macro_rules! make_mir_visitor {
645647
ref $($mutability)* ty,
646648
} = *static_;
647649
self.visit_def_id(def_id, location);
648-
self.visit_ty(ty, Lookup::Loc(location));
650+
self.visit_ty(ty, TyContext::Location(location));
649651
}
650652

651653
fn super_projection(&mut self,
@@ -675,7 +677,7 @@ macro_rules! make_mir_visitor {
675677
ProjectionElem::Subslice { from: _, to: _ } => {
676678
}
677679
ProjectionElem::Field(_field, ref $($mutability)* ty) => {
678-
self.visit_ty(ty, Lookup::Loc(location));
680+
self.visit_ty(ty, TyContext::Location(location));
679681
}
680682
ProjectionElem::Index(ref $($mutability)* local) => {
681683
self.visit_local(local, LvalueContext::Consume, location);
@@ -690,6 +692,7 @@ macro_rules! make_mir_visitor {
690692
}
691693

692694
fn super_local_decl(&mut self,
695+
local: Local,
693696
local_decl: & $($mutability)* LocalDecl<'tcx>) {
694697
let LocalDecl {
695698
mutability: _,
@@ -701,7 +704,10 @@ macro_rules! make_mir_visitor {
701704
is_user_variable: _,
702705
} = *local_decl;
703706

704-
self.visit_ty(ty, Lookup::Src(*source_info));
707+
self.visit_ty(ty, TyContext::LocalDecl {
708+
local,
709+
source_info: *source_info,
710+
});
705711
self.visit_source_info(source_info);
706712
self.visit_visibility_scope(lexical_scope);
707713
}
@@ -725,7 +731,7 @@ macro_rules! make_mir_visitor {
725731
} = *constant;
726732

727733
self.visit_span(span);
728-
self.visit_ty(ty, Lookup::Loc(location));
734+
self.visit_ty(ty, TyContext::Location(location));
729735
self.visit_literal(literal, location);
730736
}
731737

@@ -803,10 +809,21 @@ macro_rules! make_mir_visitor {
803809
make_mir_visitor!(Visitor,);
804810
make_mir_visitor!(MutVisitor,mut);
805811

812+
/// Extra information passed to `visit_ty` and friends to give context
813+
/// about where the type etc appears.
806814
#[derive(Copy, Clone, Debug)]
807-
pub enum Lookup {
808-
Loc(Location),
809-
Src(SourceInfo),
815+
pub enum TyContext {
816+
LocalDecl {
817+
/// The index of the local variable we are visiting.
818+
local: Local,
819+
820+
/// The source location where this local variable was declared.
821+
source_info: SourceInfo,
822+
},
823+
824+
Location(Location),
825+
826+
SourceInfo(SourceInfo),
810827
}
811828

812829
#[derive(Copy, Clone, Debug, PartialEq, Eq)]

src/librustc_data_structures/bitvec.rs

+21-15
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ pub struct BitMatrix {
145145
}
146146

147147
impl BitMatrix {
148-
// Create a new `rows x columns` matrix, initially empty.
148+
/// Create a new `rows x columns` matrix, initially empty.
149149
pub fn new(rows: usize, columns: usize) -> BitMatrix {
150150
// For every element, we need one bit for every other
151151
// element. Round up to an even number of u64s.
@@ -163,29 +163,33 @@ impl BitMatrix {
163163
(start, start + u64s_per_row)
164164
}
165165

166-
pub fn add(&mut self, source: usize, target: usize) -> bool {
167-
let (start, _) = self.range(source);
168-
let (word, mask) = word_mask(target);
166+
/// Sets the cell at `(row, column)` to true. Put another way, add
167+
/// `column` to the bitset for `row`.
168+
///
169+
/// Returns true if this changed the matrix, and false otherwies.
170+
pub fn add(&mut self, row: usize, column: usize) -> bool {
171+
let (start, _) = self.range(row);
172+
let (word, mask) = word_mask(column);
169173
let vector = &mut self.vector[..];
170174
let v1 = vector[start + word];
171175
let v2 = v1 | mask;
172176
vector[start + word] = v2;
173177
v1 != v2
174178
}
175179

176-
/// Do the bits from `source` contain `target`?
177-
///
178-
/// Put another way, if the matrix represents (transitive)
179-
/// reachability, can `source` reach `target`?
180-
pub fn contains(&self, source: usize, target: usize) -> bool {
181-
let (start, _) = self.range(source);
182-
let (word, mask) = word_mask(target);
180+
/// Do the bits from `row` contain `column`? Put another way, is
181+
/// the matrix cell at `(row, column)` true? Put yet another way,
182+
/// if the matrix represents (transitive) reachability, can
183+
/// `row` reach `column`?
184+
pub fn contains(&self, row: usize, column: usize) -> bool {
185+
let (start, _) = self.range(row);
186+
let (word, mask) = word_mask(column);
183187
(self.vector[start + word] & mask) != 0
184188
}
185189

186-
/// Returns those indices that are reachable from both `a` and
187-
/// `b`. This is an O(n) operation where `n` is the number of
188-
/// elements (somewhat independent from the actual size of the
190+
/// Returns those indices that are true in rows `a` and `b`. This
191+
/// is an O(n) operation where `n` is the number of elements
192+
/// (somewhat independent from the actual size of the
189193
/// intersection, in particular).
190194
pub fn intersection(&self, a: usize, b: usize) -> Vec<usize> {
191195
let (a_start, a_end) = self.range(a);
@@ -206,7 +210,7 @@ impl BitMatrix {
206210
result
207211
}
208212

209-
/// Add the bits from `read` to the bits from `write`,
213+
/// Add the bits from row `read` to the bits from row `write`,
210214
/// return true if anything changed.
211215
///
212216
/// This is used when computing transitive reachability because if
@@ -227,6 +231,8 @@ impl BitMatrix {
227231
changed
228232
}
229233

234+
/// Iterates through all the columns set to true in a given row of
235+
/// the matrix.
230236
pub fn iter<'a>(&'a self, row: usize) -> BitVectorIter<'a> {
231237
let (start, end) = self.range(row);
232238
BitVectorIter {

src/librustc_data_structures/transitive_relation.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,12 @@ impl<T: Clone + Debug + Eq + Hash + Clone> TransitiveRelation<T> {
134134
}
135135
}
136136

137-
/// Returns a vector of all things less than `a`.
137+
/// Returns a vector of all things greater than `a`.
138138
///
139139
/// Really this probably ought to be `impl Iterator<Item=&T>`, but
140140
/// I'm too lazy to make that work, and -- given the caching
141141
/// strategy -- it'd be a touch tricky anyhow.
142-
pub fn less_than(&self, a: &T) -> Vec<&T> {
142+
pub fn greater_than(&self, a: &T) -> Vec<&T> {
143143
match self.index(a) {
144144
Some(a) => self.with_closure(|closure| {
145145
closure.iter(a.0).map(|i| &self.elements[i]).collect()

src/librustc_mir/build/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc::hir::def_id::DefId;
1717
use rustc::middle::region;
1818
use rustc::mir::*;
1919
use rustc::mir::transform::MirSource;
20-
use rustc::mir::visit::{MutVisitor, Lookup};
20+
use rustc::mir::visit::{MutVisitor, TyContext};
2121
use rustc::ty::{self, Ty, TyCtxt};
2222
use rustc::ty::subst::Substs;
2323
use rustc::util::nodemap::NodeMap;
@@ -165,7 +165,7 @@ struct GlobalizeMir<'a, 'gcx: 'a> {
165165
}
166166

167167
impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
168-
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: Lookup) {
168+
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
169169
if let Some(lifted) = self.tcx.lift(ty) {
170170
*ty = lifted;
171171
} else {

src/librustc_mir/dataflow/impls/borrows.rs

+17-7
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
3838
location_map: FxHashMap<Location, BorrowIndex>,
3939
region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
4040
region_span_map: FxHashMap<RegionKind, Span>,
41-
nonlexical_regioncx: Option<&'a RegionInferenceContext>,
41+
nonlexical_regioncx: Option<&'a RegionInferenceContext<'tcx>>,
4242
}
4343

4444
// temporarily allow some dead fields: `kind` and `region` will be
@@ -69,7 +69,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
6969
impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
7070
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
7171
mir: &'a Mir<'tcx>,
72-
nonlexical_regioncx: Option<&'a RegionInferenceContext>)
72+
nonlexical_regioncx: Option<&'a RegionInferenceContext<'tcx>>)
7373
-> Self {
7474
let mut visitor = GatherBorrows { idx_vec: IndexVec::new(),
7575
location_map: FxHashMap(),
@@ -139,11 +139,21 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
139139
location: Location) {
140140
if let Some(regioncx) = self.nonlexical_regioncx {
141141
for (borrow_index, borrow_data) in self.borrows.iter_enumerated() {
142-
let borrow_region = regioncx.region_value(borrow_data.region.to_region_index());
143-
if !borrow_region.may_contain(location) && location != borrow_data.location {
144-
debug!("kill_loans_out_of_scope_at_location: kill{:?} \
145-
location={:?} borrow_data={:?}", borrow_index, location, borrow_data);
146-
sets.kill(&borrow_index);
142+
let borrow_region = borrow_data.region.to_region_index();
143+
if !regioncx.region_contains_point(borrow_region, location) {
144+
// The region checker really considers the borrow
145+
// to start at the point **after** the location of
146+
// the borrow, but the borrow checker puts the gen
147+
// directly **on** the location of the
148+
// borrow. This results in a gen/kill both being
149+
// generated for same point if we are not
150+
// careful. Probably we should change the point of
151+
// the gen, but for now we hackily account for the
152+
// mismatch here by not generating a kill for the
153+
// location on the borrow itself.
154+
if location != borrow_data.location {
155+
sets.kill(&borrow_index);
156+
}
147157
}
148158
}
149159
}

src/librustc_mir/transform/clean_end_regions.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use rustc_data_structures::fx::FxHashSet;
2424
use rustc::middle::region;
2525
use rustc::mir::transform::{MirPass, MirSource};
2626
use rustc::mir::{BasicBlock, Location, Mir, Rvalue, Statement, StatementKind};
27-
use rustc::mir::visit::{MutVisitor, Visitor, Lookup};
27+
use rustc::mir::visit::{MutVisitor, Visitor, TyContext};
2828
use rustc::ty::{Ty, RegionKind, TyCtxt};
2929

3030
pub struct CleanEndRegions;
@@ -67,7 +67,7 @@ impl<'tcx> Visitor<'tcx> for GatherBorrowedRegions {
6767
self.super_rvalue(rvalue, location);
6868
}
6969

70-
fn visit_ty(&mut self, ty: &Ty<'tcx>, _: Lookup) {
70+
fn visit_ty(&mut self, ty: &Ty<'tcx>, _: TyContext) {
7171
// Gather regions that occur in types
7272
for re in ty.walk().flat_map(|t| t.regions()) {
7373
match *re {

src/librustc_mir/transform/erase_regions.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
use rustc::ty::subst::Substs;
1818
use rustc::ty::{self, Ty, TyCtxt};
1919
use rustc::mir::*;
20-
use rustc::mir::visit::{MutVisitor, Lookup};
20+
use rustc::mir::visit::{MutVisitor, TyContext};
2121
use rustc::mir::transform::{MirPass, MirSource};
2222

2323
struct EraseRegionsVisitor<'a, 'tcx: 'a> {
@@ -35,7 +35,7 @@ impl<'a, 'tcx> EraseRegionsVisitor<'a, 'tcx> {
3535
}
3636

3737
impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
38-
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: Lookup) {
38+
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
3939
if !self.in_validation_statement {
4040
*ty = self.tcx.erase_regions(ty);
4141
}

0 commit comments

Comments
 (0)