2017-10-24 14:20:47 -04:00
|
|
|
// 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.
|
|
|
|
|
2017-10-25 15:10:48 -04:00
|
|
|
use rustc::hir;
|
2017-12-01 14:31:47 +02:00
|
|
|
use rustc::mir::{Location, Place, Mir, Rvalue};
|
2017-10-24 18:28:39 -04:00
|
|
|
use rustc::mir::visit::Visitor;
|
2017-12-01 14:31:47 +02:00
|
|
|
use rustc::mir::Place::Projection;
|
|
|
|
use rustc::mir::{PlaceProjection, ProjectionElem};
|
2017-10-24 14:20:47 -04:00
|
|
|
use rustc::infer::InferCtxt;
|
2017-10-24 17:14:39 -04:00
|
|
|
use rustc::traits::{self, ObligationCause};
|
|
|
|
use rustc::ty::{self, Ty};
|
|
|
|
use rustc::ty::fold::TypeFoldable;
|
|
|
|
use rustc::util::common::ErrorReported;
|
|
|
|
use rustc_data_structures::fx::FxHashSet;
|
|
|
|
use syntax::codemap::DUMMY_SP;
|
2017-10-24 14:20:47 -04:00
|
|
|
|
2017-10-24 16:20:47 -04:00
|
|
|
use super::LivenessResults;
|
2017-11-06 04:15:38 -05:00
|
|
|
use super::ToRegionVid;
|
2017-10-24 14:20:47 -04:00
|
|
|
use super::region_infer::RegionInferenceContext;
|
|
|
|
|
2017-10-24 16:20:47 -04:00
|
|
|
pub(super) fn generate_constraints<'a, 'gcx, 'tcx>(
|
|
|
|
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
2017-10-30 04:51:10 -04:00
|
|
|
regioncx: &mut RegionInferenceContext<'tcx>,
|
2017-10-24 16:20:47 -04:00
|
|
|
mir: &Mir<'tcx>,
|
2017-11-10 19:20:35 +02:00
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
2017-10-24 16:20:47 -04:00
|
|
|
liveness: &LivenessResults,
|
|
|
|
) {
|
|
|
|
ConstraintGeneration {
|
|
|
|
infcx,
|
|
|
|
regioncx,
|
|
|
|
mir,
|
|
|
|
liveness,
|
2017-11-10 19:20:35 +02:00
|
|
|
param_env,
|
2017-10-24 16:20:47 -04:00
|
|
|
}.add_constraints();
|
2017-10-24 14:20:47 -04:00
|
|
|
}
|
|
|
|
|
2017-10-24 18:28:39 -04:00
|
|
|
struct ConstraintGeneration<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
|
|
|
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
|
2017-10-30 04:51:10 -04:00
|
|
|
regioncx: &'cx mut RegionInferenceContext<'tcx>,
|
2017-10-24 18:28:39 -04:00
|
|
|
mir: &'cx Mir<'tcx>,
|
|
|
|
liveness: &'cx LivenessResults,
|
2017-11-10 19:20:35 +02:00
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
2017-10-24 14:20:47 -04:00
|
|
|
}
|
|
|
|
|
2017-10-24 18:28:39 -04:00
|
|
|
impl<'cx, 'gcx, 'tcx> ConstraintGeneration<'cx, 'gcx, 'tcx> {
|
2017-10-24 14:20:47 -04:00
|
|
|
fn add_constraints(&mut self) {
|
|
|
|
self.add_liveness_constraints();
|
2017-10-24 18:28:39 -04:00
|
|
|
self.add_borrow_constraints();
|
2017-10-24 14:20:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Liveness constraints:
|
|
|
|
///
|
|
|
|
/// > If a variable V is live at point P, then all regions R in the type of V
|
|
|
|
/// > must include the point P.
|
|
|
|
fn add_liveness_constraints(&mut self) {
|
|
|
|
debug!("add_liveness_constraints()");
|
|
|
|
for bb in self.mir.basic_blocks().indices() {
|
|
|
|
debug!("add_liveness_constraints: bb={:?}", bb);
|
|
|
|
|
2017-10-24 16:20:47 -04:00
|
|
|
self.liveness
|
|
|
|
.regular
|
|
|
|
.simulate_block(self.mir, bb, |location, live_locals| {
|
2017-10-24 17:14:39 -04:00
|
|
|
for live_local in live_locals.iter() {
|
|
|
|
let live_local_ty = self.mir.local_decls[live_local].ty;
|
|
|
|
self.add_regular_live_constraint(live_local_ty, location);
|
|
|
|
}
|
|
|
|
});
|
2017-10-24 14:20:47 -04:00
|
|
|
|
2017-10-24 17:14:39 -04:00
|
|
|
self.liveness
|
|
|
|
.drop
|
|
|
|
.simulate_block(self.mir, bb, |location, live_locals| {
|
2017-10-24 16:20:47 -04:00
|
|
|
for live_local in live_locals.iter() {
|
|
|
|
let live_local_ty = self.mir.local_decls[live_local].ty;
|
2017-10-24 17:14:39 -04:00
|
|
|
self.add_drop_live_constraint(live_local_ty, location);
|
2017-10-24 16:20:47 -04:00
|
|
|
}
|
|
|
|
});
|
2017-10-24 14:20:47 -04:00
|
|
|
}
|
|
|
|
}
|
2017-10-24 17:14:39 -04:00
|
|
|
|
|
|
|
/// Some variable with type `live_ty` is "regular live" at
|
|
|
|
/// `location` -- i.e., it may be used later. This means that all
|
|
|
|
/// regions appearing in the type `live_ty` must be live at
|
|
|
|
/// `location`.
|
|
|
|
fn add_regular_live_constraint<T>(&mut self, live_ty: T, location: Location)
|
|
|
|
where
|
|
|
|
T: TypeFoldable<'tcx>,
|
|
|
|
{
|
|
|
|
debug!(
|
|
|
|
"add_regular_live_constraint(live_ty={:?}, location={:?})",
|
|
|
|
live_ty,
|
|
|
|
location
|
|
|
|
);
|
|
|
|
|
|
|
|
self.infcx
|
|
|
|
.tcx
|
|
|
|
.for_each_free_region(&live_ty, |live_region| {
|
2017-11-06 04:15:38 -05:00
|
|
|
let vid = live_region.to_region_vid();
|
2017-10-24 17:14:39 -04:00
|
|
|
self.regioncx.add_live_point(vid, location);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Some variable with type `live_ty` is "drop live" at `location`
|
|
|
|
/// -- i.e., it may be dropped later. This means that *some* of
|
|
|
|
/// the regions in its type must be live at `location`. The
|
|
|
|
/// precise set will depend on the dropck constraints, and in
|
|
|
|
/// particular this takes `#[may_dangle]` into account.
|
|
|
|
fn add_drop_live_constraint(&mut self, dropped_ty: Ty<'tcx>, location: Location) {
|
|
|
|
debug!(
|
|
|
|
"add_drop_live_constraint(dropped_ty={:?}, location={:?})",
|
|
|
|
dropped_ty,
|
|
|
|
location
|
|
|
|
);
|
|
|
|
|
|
|
|
let tcx = self.infcx.tcx;
|
|
|
|
let mut types = vec![(dropped_ty, 0)];
|
|
|
|
let mut known = FxHashSet();
|
|
|
|
while let Some((ty, depth)) = types.pop() {
|
|
|
|
let span = DUMMY_SP; // FIXME
|
|
|
|
let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) {
|
|
|
|
Ok(result) => result,
|
|
|
|
Err(ErrorReported) => {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let ty::DtorckConstraint {
|
|
|
|
outlives,
|
|
|
|
dtorck_types,
|
|
|
|
} = result;
|
|
|
|
|
|
|
|
// All things in the `outlives` array may be touched by
|
|
|
|
// the destructor and must be live at this point.
|
|
|
|
for outlive in outlives {
|
|
|
|
if let Some(ty) = outlive.as_type() {
|
|
|
|
self.add_regular_live_constraint(ty, location);
|
|
|
|
} else if let Some(r) = outlive.as_region() {
|
|
|
|
self.add_regular_live_constraint(r, location);
|
|
|
|
} else {
|
|
|
|
bug!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// However, there may also be some types that
|
|
|
|
// `dtorck_constraint_for_ty` could not resolve (e.g.,
|
|
|
|
// associated types and parameters). We need to normalize
|
|
|
|
// associated types here and possibly recursively process.
|
|
|
|
for ty in dtorck_types {
|
|
|
|
let cause = ObligationCause::dummy();
|
2017-11-23 23:03:47 +02:00
|
|
|
// We know that our original `dropped_ty` is well-formed,
|
|
|
|
// so region obligations resulting from this normalization
|
|
|
|
// should always hold.
|
|
|
|
//
|
|
|
|
// Therefore we ignore them instead of trying to match
|
|
|
|
// them up with a location.
|
|
|
|
let fulfillcx = traits::FulfillmentContext::new_ignoring_regions();
|
|
|
|
match traits::fully_normalize_with_fulfillcx(
|
|
|
|
self.infcx, fulfillcx, cause, self.param_env, &ty
|
|
|
|
) {
|
2017-10-24 17:14:39 -04:00
|
|
|
Ok(ty) => match ty.sty {
|
|
|
|
ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
|
|
|
|
self.add_regular_live_constraint(ty, location);
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => if known.insert(ty) {
|
|
|
|
types.push((ty, depth + 1));
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
Err(errors) => {
|
|
|
|
self.infcx.report_fulfillment_errors(&errors, None);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-10-24 18:28:39 -04:00
|
|
|
|
|
|
|
fn add_borrow_constraints(&mut self) {
|
|
|
|
self.visit_mir(self.mir);
|
|
|
|
}
|
|
|
|
|
2017-10-25 15:10:48 -04:00
|
|
|
fn add_reborrow_constraint(
|
|
|
|
&mut self,
|
|
|
|
location: Location,
|
|
|
|
borrow_region: ty::Region<'tcx>,
|
2017-12-01 14:31:47 +02:00
|
|
|
borrowed_lv: &Place<'tcx>,
|
2017-10-25 15:10:48 -04:00
|
|
|
) {
|
|
|
|
if let Projection(ref proj) = *borrowed_lv {
|
2017-12-01 14:31:47 +02:00
|
|
|
let PlaceProjection { ref base, ref elem } = **proj;
|
2017-10-25 15:10:48 -04:00
|
|
|
|
|
|
|
if let ProjectionElem::Deref = *elem {
|
|
|
|
let tcx = self.infcx.tcx;
|
|
|
|
let base_ty = base.ty(self.mir, tcx).to_ty(tcx);
|
|
|
|
let base_sty = &base_ty.sty;
|
|
|
|
|
|
|
|
if let ty::TyRef(base_region, ty::TypeAndMut{ ty: _, mutbl }) = *base_sty {
|
|
|
|
match mutbl {
|
|
|
|
hir::Mutability::MutImmutable => { },
|
|
|
|
|
|
|
|
hir::Mutability::MutMutable => {
|
|
|
|
self.add_reborrow_constraint(location, borrow_region, base);
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2017-10-31 13:21:58 -04:00
|
|
|
let span = self.mir.source_info(location).span;
|
|
|
|
self.regioncx.add_outlives(span,
|
2017-11-06 04:15:38 -05:00
|
|
|
base_region.to_region_vid(),
|
|
|
|
borrow_region.to_region_vid(),
|
2017-10-25 15:10:48 -04:00
|
|
|
location.successor_within_block());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-10-24 18:28:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cx, 'gcx, 'tcx> {
|
2017-11-06 07:26:34 -05:00
|
|
|
fn visit_rvalue(&mut self,
|
|
|
|
rvalue: &Rvalue<'tcx>,
|
|
|
|
location: Location) {
|
|
|
|
debug!("visit_rvalue(rvalue={:?}, location={:?})", rvalue, location);
|
2017-10-25 18:04:57 -04:00
|
|
|
|
2017-11-06 07:26:34 -05:00
|
|
|
// Look for an rvalue like:
|
2017-10-24 18:28:39 -04:00
|
|
|
//
|
2017-11-06 07:26:34 -05:00
|
|
|
// & L
|
2017-10-24 18:28:39 -04:00
|
|
|
//
|
2017-11-06 07:26:34 -05:00
|
|
|
// 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);
|
2017-10-24 18:28:39 -04:00
|
|
|
}
|
|
|
|
|
2017-11-06 07:26:34 -05:00
|
|
|
self.super_rvalue(rvalue, location);
|
2017-10-24 18:28:39 -04:00
|
|
|
}
|
2017-10-24 14:20:47 -04:00
|
|
|
}
|