add -Znll-facts switch that dumps facts for new analysis
This commit is contained in:
parent
74bb9171cc
commit
eaac10ec0d
7 changed files with 440 additions and 53 deletions
|
|
@ -1250,6 +1250,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
|||
"choose which RELRO level to use"),
|
||||
nll_subminimal_causes: bool = (false, parse_bool, [UNTRACKED],
|
||||
"when tracking region error causes, accept subminimal results for faster execution."),
|
||||
nll_facts: bool = (false, parse_bool, [UNTRACKED],
|
||||
"dump facts from NLL analysis into side files"),
|
||||
disable_nll_user_type_assert: bool = (false, parse_bool, [UNTRACKED],
|
||||
"disable user provided type assertion in NLL"),
|
||||
trans_time_graph: bool = (false, parse_bool, [UNTRACKED],
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(dead_code)] // TODO -- will be used in a later commit, remove then
|
||||
|
||||
use rustc::mir::{BasicBlock, Location, Mir};
|
||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||
|
||||
|
|
|
|||
|
|
@ -8,28 +8,37 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use borrow_check::borrow_set::BorrowSet;
|
||||
use borrow_check::location::LocationTable;
|
||||
use borrow_check::nll::facts::AllFacts;
|
||||
use rustc::hir;
|
||||
use rustc::mir::{BasicBlock, BasicBlockData, Location, Place, Mir, Rvalue};
|
||||
use rustc::infer::InferCtxt;
|
||||
use rustc::mir::visit::TyContext;
|
||||
use rustc::mir::visit::Visitor;
|
||||
use rustc::mir::Place::Projection;
|
||||
use rustc::mir::{Local, PlaceProjection, ProjectionElem};
|
||||
use rustc::mir::visit::TyContext;
|
||||
use rustc::infer::InferCtxt;
|
||||
use rustc::ty::{self, CanonicalTy, ClosureSubsts};
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue};
|
||||
use rustc::mir::{Local, PlaceProjection, ProjectionElem, Statement, Terminator};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{self, CanonicalTy, ClosureSubsts};
|
||||
|
||||
use super::region_infer::{Cause, RegionInferenceContext};
|
||||
use super::ToRegionVid;
|
||||
use super::region_infer::{RegionInferenceContext, Cause};
|
||||
|
||||
pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
|
||||
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
regioncx: &mut RegionInferenceContext<'tcx>,
|
||||
all_facts: &mut Option<AllFacts>,
|
||||
location_table: &LocationTable,
|
||||
mir: &Mir<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
) {
|
||||
let mut cg = ConstraintGeneration {
|
||||
borrow_set,
|
||||
infcx,
|
||||
regioncx,
|
||||
location_table,
|
||||
all_facts,
|
||||
mir,
|
||||
};
|
||||
|
||||
|
|
@ -41,8 +50,11 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
|
|||
/// 'cg = the duration of the constraint generation process itself.
|
||||
struct ConstraintGeneration<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> {
|
||||
infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
all_facts: &'cg mut Option<AllFacts>,
|
||||
location_table: &'cg LocationTable,
|
||||
regioncx: &'cg mut RegionInferenceContext<'tcx>,
|
||||
mir: &'cg Mir<'tcx>,
|
||||
borrow_set: &'cg BorrowSet<'tcx>,
|
||||
}
|
||||
|
||||
impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx, 'tcx> {
|
||||
|
|
@ -68,12 +80,14 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
|
|||
/// call. Make them live at the location where they appear.
|
||||
fn visit_ty(&mut self, ty: &ty::Ty<'tcx>, ty_context: TyContext) {
|
||||
match ty_context {
|
||||
TyContext::ReturnTy(source_info) |
|
||||
TyContext::YieldTy(source_info) |
|
||||
TyContext::LocalDecl { source_info, .. } => {
|
||||
span_bug!(source_info.span,
|
||||
"should not be visiting outside of the CFG: {:?}",
|
||||
ty_context);
|
||||
TyContext::ReturnTy(source_info)
|
||||
| TyContext::YieldTy(source_info)
|
||||
| TyContext::LocalDecl { source_info, .. } => {
|
||||
span_bug!(
|
||||
source_info.span,
|
||||
"should not be visiting outside of the CFG: {:?}",
|
||||
ty_context
|
||||
);
|
||||
}
|
||||
TyContext::Location(location) => {
|
||||
self.add_regular_live_constraint(*ty, location, Cause::LiveOther(location));
|
||||
|
|
@ -90,25 +104,117 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
|
|||
self.super_closure_substs(substs);
|
||||
}
|
||||
|
||||
fn visit_statement(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
statement: &Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
if let Some(all_facts) = self.all_facts {
|
||||
all_facts.cfg_edge.push((
|
||||
self.location_table.start_index(location),
|
||||
self.location_table.mid_index(location),
|
||||
));
|
||||
|
||||
all_facts.cfg_edge.push((
|
||||
self.location_table.mid_index(location),
|
||||
self.location_table
|
||||
.start_index(location.successor_within_block()),
|
||||
));
|
||||
}
|
||||
|
||||
self.super_statement(block, statement, location);
|
||||
}
|
||||
|
||||
fn visit_assign(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
place: &Place<'tcx>,
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
// When we see `X = ...`, then kill borrows of
|
||||
// `(*X).foo` and so forth.
|
||||
if let Some(all_facts) = self.all_facts {
|
||||
if let Place::Local(temp) = place {
|
||||
if let Some(borrow_indices) = self.borrow_set.local_map.get(temp) {
|
||||
for &borrow_index in borrow_indices {
|
||||
let location_index = self.location_table.mid_index(location);
|
||||
all_facts.killed.push((borrow_index, location_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.super_assign(block, place, rvalue, location);
|
||||
}
|
||||
|
||||
fn visit_terminator(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
terminator: &Terminator<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
if let Some(all_facts) = self.all_facts {
|
||||
all_facts.cfg_edge.push((
|
||||
self.location_table.start_index(location),
|
||||
self.location_table.mid_index(location),
|
||||
));
|
||||
|
||||
for successor_block in terminator.successors() {
|
||||
all_facts.cfg_edge.push((
|
||||
self.location_table.mid_index(location),
|
||||
self.location_table
|
||||
.start_index(successor_block.start_location()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
self.super_terminator(block, terminator, location);
|
||||
}
|
||||
|
||||
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
debug!("visit_rvalue(rvalue={:?}, location={:?})", rvalue, location);
|
||||
|
||||
// Look for an rvalue like:
|
||||
//
|
||||
// & L
|
||||
//
|
||||
// where L is the path that is borrowed. In that case, we have
|
||||
// to add the reborrow constraints (which don't fall out
|
||||
// naturally from the type-checker).
|
||||
if let Rvalue::Ref(region, _bk, ref borrowed_lv) = *rvalue {
|
||||
self.add_reborrow_constraint(location, region, borrowed_lv);
|
||||
match rvalue {
|
||||
Rvalue::Ref(region, _borrow_kind, borrowed_place) => {
|
||||
// In some cases, e.g. when borrowing from an unsafe
|
||||
// place, we don't bother to create a loan, since
|
||||
// there are no conditions to validate.
|
||||
if let Some(all_facts) = self.all_facts {
|
||||
if let Some(borrow_index) = self.borrow_set.location_map.get(&location) {
|
||||
let region_vid = region.to_region_vid();
|
||||
all_facts.borrow_region.push((
|
||||
region_vid,
|
||||
*borrow_index,
|
||||
self.location_table.mid_index(location),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Look for an rvalue like:
|
||||
//
|
||||
// & L
|
||||
//
|
||||
// where L is the path that is borrowed. In that case, we have
|
||||
// to add the reborrow constraints (which don't fall out
|
||||
// naturally from the type-checker).
|
||||
self.add_reborrow_constraint(location, region, borrowed_place);
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
|
||||
self.super_rvalue(rvalue, location);
|
||||
}
|
||||
|
||||
fn visit_user_assert_ty(&mut self, _c_ty: &CanonicalTy<'tcx>,
|
||||
_local: &Local, _location: Location) { }
|
||||
fn visit_user_assert_ty(
|
||||
&mut self,
|
||||
_c_ty: &CanonicalTy<'tcx>,
|
||||
_local: &Local,
|
||||
_location: Location,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
|
||||
|
|
@ -122,8 +228,7 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
|
|||
{
|
||||
debug!(
|
||||
"add_regular_live_constraint(live_ty={:?}, location={:?})",
|
||||
live_ty,
|
||||
location
|
||||
live_ty, location
|
||||
);
|
||||
|
||||
self.infcx
|
||||
|
|
@ -144,8 +249,10 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
|
|||
) {
|
||||
let mut borrowed_place = borrowed_place;
|
||||
|
||||
debug!("add_reborrow_constraint({:?}, {:?}, {:?})",
|
||||
location, borrow_region, borrowed_place);
|
||||
debug!(
|
||||
"add_reborrow_constraint({:?}, {:?}, {:?})",
|
||||
location, borrow_region, borrowed_place
|
||||
);
|
||||
while let Projection(box PlaceProjection { base, elem }) = borrowed_place {
|
||||
debug!("add_reborrow_constraint - iteration {:?}", borrowed_place);
|
||||
|
||||
|
|
@ -165,12 +272,20 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
|
|||
location.successor_within_block(),
|
||||
);
|
||||
|
||||
if let Some(all_facts) = self.all_facts {
|
||||
all_facts.outlives.push((
|
||||
ref_region.to_region_vid(),
|
||||
borrow_region.to_region_vid(),
|
||||
self.location_table.mid_index(location),
|
||||
));
|
||||
}
|
||||
|
||||
match mutbl {
|
||||
hir::Mutability::MutImmutable => {
|
||||
// Immutable reference. We don't need the base
|
||||
// to be valid for the entire lifetime of
|
||||
// the borrow.
|
||||
break
|
||||
break;
|
||||
}
|
||||
hir::Mutability::MutMutable => {
|
||||
// Mutable reference. We *do* need the base
|
||||
|
|
@ -199,19 +314,19 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
|
|||
}
|
||||
ty::TyRawPtr(..) => {
|
||||
// deref of raw pointer, guaranteed to be valid
|
||||
break
|
||||
break;
|
||||
}
|
||||
ty::TyAdt(def, _) if def.is_box() => {
|
||||
// deref of `Box`, need the base to be valid - propagate
|
||||
}
|
||||
_ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place)
|
||||
_ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place),
|
||||
}
|
||||
}
|
||||
ProjectionElem::Field(..) |
|
||||
ProjectionElem::Downcast(..) |
|
||||
ProjectionElem::Index(..) |
|
||||
ProjectionElem::ConstantIndex { .. } |
|
||||
ProjectionElem::Subslice { .. } => {
|
||||
ProjectionElem::Field(..)
|
||||
| ProjectionElem::Downcast(..)
|
||||
| ProjectionElem::Index(..)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. } => {
|
||||
// other field access
|
||||
}
|
||||
}
|
||||
|
|
|
|||
194
src/librustc_mir/borrow_check/nll/facts.rs
Normal file
194
src/librustc_mir/borrow_check/nll/facts.rs
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use borrow_check::location::{LocationIndex, LocationTable};
|
||||
use dataflow::indexes::BorrowIndex;
|
||||
use rustc::ty::RegionVid;
|
||||
use std::error::Error;
|
||||
use std::fmt::Debug;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
/// The "facts" which are the basis of the NLL borrow analysis.
|
||||
#[derive(Default)]
|
||||
crate struct AllFacts {
|
||||
// `borrow_region(R, B, P)` -- the region R may refer to data from borrow B
|
||||
// starting at the point P (this is usually the point *after* a borrow rvalue)
|
||||
crate borrow_region: Vec<(RegionVid, BorrowIndex, LocationIndex)>,
|
||||
|
||||
// universal_region(R) -- this is a "free region" within fn body
|
||||
crate universal_region: Vec<RegionVid>,
|
||||
|
||||
// `cfg_edge(P,Q)` for each edge P -> Q in the control flow
|
||||
crate cfg_edge: Vec<(LocationIndex, LocationIndex)>,
|
||||
|
||||
// `killed(B,P)` when some prefix of the path borrowed at B is assigned at point P
|
||||
crate killed: Vec<(BorrowIndex, LocationIndex)>,
|
||||
|
||||
// `outlives(R1, R2, P)` when we require `R1@P: R2@P`
|
||||
crate outlives: Vec<(RegionVid, RegionVid, LocationIndex)>,
|
||||
|
||||
// `region_live_at(R, P)` when the region R appears in a live variable at P
|
||||
crate region_live_at: Vec<(RegionVid, LocationIndex)>,
|
||||
}
|
||||
|
||||
impl AllFacts {
|
||||
crate fn write_to_dir(
|
||||
&self,
|
||||
dir: impl AsRef<Path>,
|
||||
location_table: &LocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let dir: &Path = dir.as_ref();
|
||||
fs::create_dir_all(dir)?;
|
||||
let wr = FactWriter { location_table, dir };
|
||||
macro_rules! write_facts_to_path {
|
||||
($wr:ident . write_facts_to_path($this:ident . [
|
||||
$($field:ident,)*
|
||||
])) => {
|
||||
$(
|
||||
$wr.write_facts_to_path(
|
||||
&$this.$field,
|
||||
&format!("{}.facts", stringify!($field))
|
||||
)?;
|
||||
)*
|
||||
}
|
||||
}
|
||||
write_facts_to_path! {
|
||||
wr.write_facts_to_path(self.[
|
||||
borrow_region,
|
||||
universal_region,
|
||||
cfg_edge,
|
||||
killed,
|
||||
outlives,
|
||||
region_live_at,
|
||||
])
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct FactWriter<'w> {
|
||||
location_table: &'w LocationTable,
|
||||
dir: &'w Path,
|
||||
}
|
||||
|
||||
impl<'w> FactWriter<'w> {
|
||||
fn write_facts_to_path<T>(
|
||||
&self,
|
||||
rows: &Vec<T>,
|
||||
file_name: &str,
|
||||
) -> Result<(), Box<dyn Error>>
|
||||
where
|
||||
T: FactRow,
|
||||
{
|
||||
let file = &self.dir.join(file_name);
|
||||
let mut file = File::create(file)?;
|
||||
for row in rows {
|
||||
row.write(&mut file, self.location_table)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
trait FactRow {
|
||||
fn write(
|
||||
&self,
|
||||
out: &mut File,
|
||||
location_table: &LocationTable,
|
||||
) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
|
||||
impl FactRow for RegionVid {
|
||||
fn write(
|
||||
&self,
|
||||
out: &mut File,
|
||||
location_table: &LocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
write_row(out, location_table, &[self])
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> FactRow for (A, B)
|
||||
where
|
||||
A: FactCell,
|
||||
B: FactCell,
|
||||
{
|
||||
fn write(
|
||||
&self,
|
||||
out: &mut File,
|
||||
location_table: &LocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
write_row(out, location_table, &[&self.0, &self.1])
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, C> FactRow for (A, B, C)
|
||||
where
|
||||
A: FactCell,
|
||||
B: FactCell,
|
||||
C: FactCell,
|
||||
{
|
||||
fn write(
|
||||
&self,
|
||||
out: &mut File,
|
||||
location_table: &LocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
write_row(out, location_table, &[&self.0, &self.1, &self.2])
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, C, D> FactRow for (A, B, C, D)
|
||||
where
|
||||
A: FactCell,
|
||||
B: FactCell,
|
||||
C: FactCell,
|
||||
D: FactCell,
|
||||
{
|
||||
fn write(
|
||||
&self,
|
||||
out: &mut File,
|
||||
location_table: &LocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3])
|
||||
}
|
||||
}
|
||||
|
||||
fn write_row(
|
||||
out: &mut dyn Write,
|
||||
location_table: &LocationTable,
|
||||
columns: &[&dyn FactCell],
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
for (index, c) in columns.iter().enumerate() {
|
||||
let tail = if index == columns.len() - 1 {
|
||||
"\n"
|
||||
} else {
|
||||
"\t"
|
||||
};
|
||||
write!(out, "{:?}{}", c.to_string(location_table), tail)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
trait FactCell {
|
||||
fn to_string(&self, location_table: &LocationTable) -> String;
|
||||
}
|
||||
|
||||
impl<A: Debug> FactCell for A {
|
||||
default fn to_string(&self, _location_table: &LocationTable) -> String {
|
||||
format!("{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl FactCell for LocationIndex {
|
||||
fn to_string(&self, location_table: &LocationTable) -> String {
|
||||
format!("{:?}", location_table.to_location(*self))
|
||||
}
|
||||
}
|
||||
|
|
@ -10,32 +10,35 @@
|
|||
|
||||
use borrow_check::borrow_set::BorrowSet;
|
||||
use borrow_check::location::LocationTable;
|
||||
use dataflow::move_paths::MoveData;
|
||||
use dataflow::FlowAtLocation;
|
||||
use dataflow::MaybeInitializedPlaces;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir::{ClosureRegionRequirements, ClosureOutlivesSubject, Mir};
|
||||
use rustc::infer::InferCtxt;
|
||||
use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Mir};
|
||||
use rustc::ty::{self, RegionKind, RegionVid};
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt::Debug;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use transform::MirSource;
|
||||
use util::liveness::{LivenessResults, LocalSet};
|
||||
use dataflow::FlowAtLocation;
|
||||
use dataflow::MaybeInitializedPlaces;
|
||||
use dataflow::move_paths::MoveData;
|
||||
|
||||
use self::mir_util::PassWhere;
|
||||
use util as mir_util;
|
||||
use util::pretty::{self, ALIGN};
|
||||
use self::mir_util::PassWhere;
|
||||
|
||||
mod constraint_generation;
|
||||
pub mod explain_borrow;
|
||||
mod facts;
|
||||
crate mod region_infer;
|
||||
mod renumber;
|
||||
mod subtype_constraint_generation;
|
||||
crate mod type_check;
|
||||
mod universal_regions;
|
||||
|
||||
use self::facts::AllFacts;
|
||||
use self::region_infer::RegionInferenceContext;
|
||||
use self::universal_regions::UniversalRegions;
|
||||
|
||||
|
|
@ -71,11 +74,11 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
|
|||
def_id: DefId,
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
_location_table: &LocationTable,
|
||||
location_table: &LocationTable,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'cx, 'gcx, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
_borrow_set: &BorrowSet<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
) -> (
|
||||
RegionInferenceContext<'tcx>,
|
||||
Option<ClosureRegionRequirements<'gcx>>,
|
||||
|
|
@ -93,15 +96,47 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
|
|||
move_data,
|
||||
);
|
||||
|
||||
let mut all_facts = if infcx.tcx.sess.opts.debugging_opts.nll_facts {
|
||||
Some(AllFacts::default())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(all_facts) = &mut all_facts {
|
||||
all_facts
|
||||
.universal_region
|
||||
.extend(universal_regions.universal_regions());
|
||||
}
|
||||
|
||||
// Create the region inference context, taking ownership of the region inference
|
||||
// data that was contained in `infcx`.
|
||||
let var_origins = infcx.take_region_var_origins();
|
||||
let mut regioncx = RegionInferenceContext::new(var_origins, universal_regions, mir);
|
||||
subtype_constraint_generation::generate(&mut regioncx, mir, constraint_sets);
|
||||
let mut regioncx =
|
||||
RegionInferenceContext::new(var_origins, universal_regions, mir);
|
||||
|
||||
// Generate various constraints.
|
||||
subtype_constraint_generation::generate(
|
||||
&mut regioncx,
|
||||
&mut all_facts,
|
||||
location_table,
|
||||
mir,
|
||||
constraint_sets,
|
||||
);
|
||||
constraint_generation::generate_constraints(
|
||||
infcx,
|
||||
&mut regioncx,
|
||||
&mut all_facts,
|
||||
location_table,
|
||||
&mir,
|
||||
borrow_set,
|
||||
);
|
||||
|
||||
// Generate non-subtyping constraints.
|
||||
constraint_generation::generate_constraints(infcx, &mut regioncx, &mir);
|
||||
// Dump facts if requested.
|
||||
if let Some(all_facts) = all_facts {
|
||||
let def_path = infcx.tcx.hir.def_path(def_id);
|
||||
let dir_path = PathBuf::from("nll-facts").join(def_path.to_filename_friendly_no_crate());
|
||||
all_facts.write_to_dir(dir_path, location_table).unwrap();
|
||||
}
|
||||
|
||||
// Solve the region constraints.
|
||||
let closure_region_requirements = regioncx.solve(infcx, &mir, def_id);
|
||||
|
|
|
|||
|
|
@ -8,14 +8,17 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::mir::{Location, Mir};
|
||||
use borrow_check::location::LocationTable;
|
||||
use borrow_check::nll::facts::AllFacts;
|
||||
use rustc::infer::region_constraints::Constraint;
|
||||
use rustc::infer::region_constraints::RegionConstraintData;
|
||||
use rustc::infer::region_constraints::{Verify, VerifyBound};
|
||||
use rustc::mir::{Location, Mir};
|
||||
use rustc::ty;
|
||||
use std::iter;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
use super::region_infer::{TypeTest, RegionInferenceContext, RegionTest};
|
||||
use super::region_infer::{RegionInferenceContext, RegionTest, TypeTest};
|
||||
use super::type_check::Locations;
|
||||
use super::type_check::MirTypeckRegionConstraints;
|
||||
use super::type_check::OutlivesSet;
|
||||
|
|
@ -27,19 +30,30 @@ use super::type_check::OutlivesSet;
|
|||
/// them into the NLL `RegionInferenceContext`.
|
||||
pub(super) fn generate<'tcx>(
|
||||
regioncx: &mut RegionInferenceContext<'tcx>,
|
||||
all_facts: &mut Option<AllFacts>,
|
||||
location_table: &LocationTable,
|
||||
mir: &Mir<'tcx>,
|
||||
constraints: &MirTypeckRegionConstraints<'tcx>,
|
||||
) {
|
||||
SubtypeConstraintGenerator { regioncx, mir }.generate(constraints);
|
||||
SubtypeConstraintGenerator {
|
||||
regioncx,
|
||||
location_table,
|
||||
mir,
|
||||
}.generate(constraints, all_facts);
|
||||
}
|
||||
|
||||
struct SubtypeConstraintGenerator<'cx, 'tcx: 'cx> {
|
||||
regioncx: &'cx mut RegionInferenceContext<'tcx>,
|
||||
location_table: &'cx LocationTable,
|
||||
mir: &'cx Mir<'tcx>,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
|
||||
fn generate(&mut self, constraints: &MirTypeckRegionConstraints<'tcx>) {
|
||||
fn generate(
|
||||
&mut self,
|
||||
constraints: &MirTypeckRegionConstraints<'tcx>,
|
||||
all_facts: &mut Option<AllFacts>,
|
||||
) {
|
||||
let MirTypeckRegionConstraints {
|
||||
liveness_set,
|
||||
outlives_sets,
|
||||
|
|
@ -57,6 +71,17 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
|
|||
self.regioncx.add_live_point(region_vid, *location, &cause);
|
||||
}
|
||||
|
||||
if let Some(all_facts) = all_facts {
|
||||
all_facts
|
||||
.region_live_at
|
||||
.extend(liveness_set.into_iter().flat_map(|(region, location, _)| {
|
||||
let r = self.to_region_vid(region);
|
||||
let p1 = self.location_table.start_index(*location);
|
||||
let p2 = self.location_table.mid_index(*location);
|
||||
iter::once((r, p1)).chain(iter::once((r, p2)))
|
||||
}));
|
||||
}
|
||||
|
||||
for OutlivesSet { locations, data } in outlives_sets {
|
||||
debug!("generate: constraints at: {:#?}", locations);
|
||||
let RegionConstraintData {
|
||||
|
|
@ -88,6 +113,23 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
|
|||
// "outlives" (`>=`) whereas the region constraints
|
||||
// talk about `<=`.
|
||||
self.regioncx.add_outlives(span, b_vid, a_vid, at_location);
|
||||
|
||||
// In the new analysis, all outlives relations etc
|
||||
// "take effect" at the mid point of the statement
|
||||
// that requires them, so ignore the `at_location`.
|
||||
if let Some(all_facts) = all_facts {
|
||||
if let Some(from_location) = locations.from_location() {
|
||||
all_facts.outlives.push((
|
||||
b_vid,
|
||||
a_vid,
|
||||
self.location_table.mid_index(from_location),
|
||||
));
|
||||
} else {
|
||||
for location in self.location_table.all_points() {
|
||||
all_facts.outlives.push((b_vid, a_vid, location));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for verify in verifys {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
|||
#![feature(inclusive_range_methods)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(never_type)]
|
||||
#![feature(specialization)]
|
||||
#![cfg_attr(stage0, feature(try_trait))]
|
||||
|
||||
extern crate arena;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue