add some instrumentation

This commit is contained in:
Niko Matsakis 2018-06-01 09:59:25 -04:00
parent a561ea7083
commit 956e2f8348
3 changed files with 182 additions and 127 deletions

View file

@ -21,17 +21,18 @@ use borrow_check::nll::renumber;
use borrow_check::nll::universal_regions::UniversalRegions;
use rustc::hir::def_id::DefId;
use rustc::infer::InferOk;
use rustc::ty::Ty;
use rustc::ty::subst::Subst;
use rustc::mir::*;
use rustc::mir::visit::TyContext;
use rustc::mir::*;
use rustc::traits::PredicateObligations;
use rustc::ty::subst::Subst;
use rustc::ty::Ty;
use rustc_data_structures::indexed_vec::Idx;
use super::{Locations, TypeChecker};
impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
#[inline(never)]
pub(super) fn equate_inputs_and_outputs(
&mut self,
mir: &Mir<'tcx>,
@ -56,8 +57,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
assert!(
mir.yield_ty.is_some() && universal_regions.yield_ty.is_some() ||
mir.yield_ty.is_none() && universal_regions.yield_ty.is_none()
mir.yield_ty.is_some() && universal_regions.yield_ty.is_some()
|| mir.yield_ty.is_none() && universal_regions.yield_ty.is_none()
);
if let Some(mir_yield_ty) = mir.yield_ty {
let ur_yield_ty = universal_regions.yield_ty.unwrap();
@ -76,57 +77,66 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
output_ty
);
let mir_output_ty = mir.local_decls[RETURN_PLACE].ty;
let anon_type_map = self.fully_perform_op(Locations::All, |cx| {
let mut obligations = ObligationAccumulator::default();
let anon_type_map =
self.fully_perform_op(
Locations::All,
|| format!("input_output"),
|cx| {
let mut obligations = ObligationAccumulator::default();
let (output_ty, anon_type_map) = obligations.add(infcx.instantiate_anon_types(
mir_def_id,
cx.body_id,
cx.param_env,
&output_ty,
));
debug!(
"equate_inputs_and_outputs: instantiated output_ty={:?}",
output_ty
);
debug!(
"equate_inputs_and_outputs: anon_type_map={:#?}",
anon_type_map
);
let (output_ty, anon_type_map) = obligations.add(infcx.instantiate_anon_types(
mir_def_id,
cx.body_id,
cx.param_env,
&output_ty,
));
debug!(
"equate_inputs_and_outputs: instantiated output_ty={:?}",
output_ty
);
debug!(
"equate_inputs_and_outputs: anon_type_map={:#?}",
anon_type_map
);
debug!(
"equate_inputs_and_outputs: mir_output_ty={:?}",
mir_output_ty
);
obligations.add(infcx
.at(&cx.misc(cx.last_span), cx.param_env)
.eq(output_ty, mir_output_ty)?);
debug!(
"equate_inputs_and_outputs: mir_output_ty={:?}",
mir_output_ty
);
obligations.add(
infcx
.at(&cx.misc(cx.last_span), cx.param_env)
.eq(output_ty, mir_output_ty)?,
);
for (&anon_def_id, anon_decl) in &anon_type_map {
let anon_defn_ty = tcx.type_of(anon_def_id);
let anon_defn_ty = anon_defn_ty.subst(tcx, anon_decl.substs);
let anon_defn_ty = renumber::renumber_regions(
cx.infcx,
TyContext::Location(Location::START),
&anon_defn_ty,
);
debug!(
"equate_inputs_and_outputs: concrete_ty={:?}",
anon_decl.concrete_ty
);
debug!("equate_inputs_and_outputs: anon_defn_ty={:?}", anon_defn_ty);
obligations.add(infcx
.at(&cx.misc(cx.last_span), cx.param_env)
.eq(anon_decl.concrete_ty, anon_defn_ty)?);
}
for (&anon_def_id, anon_decl) in &anon_type_map {
let anon_defn_ty = tcx.type_of(anon_def_id);
let anon_defn_ty = anon_defn_ty.subst(tcx, anon_decl.substs);
let anon_defn_ty = renumber::renumber_regions(
cx.infcx,
TyContext::Location(Location::START),
&anon_defn_ty,
);
debug!(
"equate_inputs_and_outputs: concrete_ty={:?}",
anon_decl.concrete_ty
);
debug!("equate_inputs_and_outputs: anon_defn_ty={:?}", anon_defn_ty);
obligations.add(
infcx
.at(&cx.misc(cx.last_span), cx.param_env)
.eq(anon_decl.concrete_ty, anon_defn_ty)?,
);
}
debug!("equate_inputs_and_outputs: equated");
debug!("equate_inputs_and_outputs: equated");
Ok(InferOk {
value: Some(anon_type_map),
obligations: obligations.into_vec(),
})
}).unwrap_or_else(|terr| {
Ok(InferOk {
value: Some(anon_type_map),
obligations: obligations.into_vec(),
})
},
).unwrap_or_else(|terr| {
span_mirbug!(
self,
Location::START,
@ -143,13 +153,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
// prove that `T: Iterator` where `T` is the type we
// instantiated it with).
if let Some(anon_type_map) = anon_type_map {
self.fully_perform_op(Locations::All, |_cx| {
infcx.constrain_anon_types(&anon_type_map, universal_regions);
Ok(InferOk {
value: (),
obligations: vec![],
})
}).unwrap();
self.fully_perform_op(
Locations::All,
|| format!("anon_type_map"),
|_cx| {
infcx.constrain_anon_types(&anon_type_map, universal_regions);
Ok(InferOk {
value: (),
obligations: vec![],
})
},
).unwrap();
}
}

View file

@ -8,15 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use dataflow::{FlowAtLocation, FlowsAtLocation};
use borrow_check::nll::region_infer::Cause;
use dataflow::MaybeInitializedPlaces;
use dataflow::move_paths::{HasMoveData, MoveData};
use rustc::mir::{BasicBlock, Location, Mir};
use rustc::mir::Local;
use rustc::ty::{Ty, TyCtxt, TypeFoldable};
use rustc::infer::InferOk;
use borrow_check::nll::type_check::AtLocation;
use dataflow::move_paths::{HasMoveData, MoveData};
use dataflow::MaybeInitializedPlaces;
use dataflow::{FlowAtLocation, FlowsAtLocation};
use rustc::infer::InferOk;
use rustc::mir::Local;
use rustc::mir::{BasicBlock, Location, Mir};
use rustc::ty::{Ty, TyCtxt, TypeFoldable};
use util::liveness::LivenessResults;
use super::TypeChecker;
@ -170,6 +170,7 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
/// 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.
#[inline(never)]
fn add_drop_live_constraint(
&mut self,
dropped_local: Local,
@ -191,33 +192,39 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
//
// For this reason, we avoid calling TypeChecker.normalize, instead doing all normalization
// ourselves in one large 'fully_perform_op' callback.
let kind_constraints = self.cx
.fully_perform_op(location.at_self(), |cx| {
let span = cx.last_span;
let kind_constraints = self
.cx
.fully_perform_op(
location.at_self(),
|| format!("add_drop_live_constraint(dropped_ty={:?})", dropped_ty),
|cx| {
let span = cx.last_span;
let mut final_obligations = Vec::new();
let mut kind_constraints = Vec::new();
let mut final_obligations = Vec::new();
let mut kind_constraints = Vec::new();
let InferOk {
value: kinds,
obligations,
} = cx.infcx
.at(&cx.misc(span), cx.param_env)
.dropck_outlives(dropped_ty);
for kind in kinds {
// All things in the `outlives` array may be touched by
// the destructor and must be live at this point.
let cause = Cause::DropVar(dropped_local, location);
kind_constraints.push((kind, location, cause));
}
let InferOk {
value: kinds,
obligations,
} = cx
.infcx
.at(&cx.misc(span), cx.param_env)
.dropck_outlives(dropped_ty);
for kind in kinds {
// All things in the `outlives` array may be touched by
// the destructor and must be live at this point.
let cause = Cause::DropVar(dropped_local, location);
kind_constraints.push((kind, location, cause));
}
final_obligations.extend(obligations);
final_obligations.extend(obligations);
Ok(InferOk {
value: kind_constraints,
obligations: final_obligations,
})
})
Ok(InferOk {
value: kind_constraints,
obligations: final_obligations,
})
},
)
.unwrap();
for (kind, location, cause) in kind_constraints {

View file

@ -710,14 +710,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
traits::ObligationCause::misc(span, self.body_id)
}
#[inline(never)]
fn fully_perform_op<OP, R>(
&mut self,
locations: Locations,
describe_op: impl Fn() -> String,
op: OP,
) -> Result<R, TypeError<'tcx>>
where
OP: FnOnce(&mut Self) -> InferResult<'tcx, R>,
{
if cfg!(debug_assertions) {
info!("fully_perform_op(describe_op={}) at {:?}", describe_op(), locations);
}
let mut fulfill_cx = TraitEngine::new(self.infcx.tcx);
let InferOk { value, obligations } = self.infcx.commit_if_ok(|_| op(self))?;
fulfill_cx.register_predicate_obligations(self.infcx, obligations);
@ -746,25 +752,35 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
Ok(value)
}
#[inline(never)]
fn sub_types(
&mut self,
sub: Ty<'tcx>,
sup: Ty<'tcx>,
locations: Locations,
) -> UnitResult<'tcx> {
self.fully_perform_op(locations, |this| {
this.infcx
.at(&this.misc(this.last_span), this.param_env)
.sup(sup, sub)
})
self.fully_perform_op(
locations,
|| format!("sub_types({:?} <: {:?})", sub, sup),
|this| {
this.infcx
.at(&this.misc(this.last_span), this.param_env)
.sup(sup, sub)
},
)
}
#[inline(never)]
fn eq_types(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, locations: Locations) -> UnitResult<'tcx> {
self.fully_perform_op(locations, |this| {
this.infcx
.at(&this.misc(this.last_span), this.param_env)
.eq(b, a)
})
self.fully_perform_op(
locations,
|| format!("eq_types({:?} = {:?})", a, b),
|this| {
this.infcx
.at(&this.misc(this.last_span), this.param_env)
.eq(b, a)
},
)
}
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
@ -1520,29 +1536,42 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
);
}
#[inline(never)]
fn prove_predicates<T>(&mut self, predicates: T, location: Location)
where
T: IntoIterator<Item = ty::Predicate<'tcx>>,
T::IntoIter: Clone,
T: IntoIterator<Item = ty::Predicate<'tcx>> + Clone,
{
let predicates = predicates.into_iter();
// This intermediate vector is mildly unfortunate, in that we
// sometimes create it even when logging is disabled, but only
// if debug-info is enabled, and I doubt it is actually
// expensive. -nmatsakis
let predicates_vec: Vec<_> = if cfg!(debug_assertions) {
predicates.clone().into_iter().collect()
} else {
Vec::new()
};
debug!(
"prove_predicates(predicates={:?}, location={:?})",
predicates.clone().collect::<Vec<_>>(),
predicates_vec,
location,
);
self.fully_perform_op(location.at_self(), |this| {
let cause = this.misc(this.last_span);
let obligations = predicates
.into_iter()
.map(|p| traits::Obligation::new(cause.clone(), this.param_env, p))
.collect();
Ok(InferOk {
value: (),
obligations,
})
}).unwrap()
self.fully_perform_op(
location.at_self(),
|| format!("prove_predicates({:?})", predicates_vec),
|this| {
let cause = this.misc(this.last_span);
let obligations = predicates
.into_iter()
.map(|p| traits::Obligation::new(cause.clone(), this.param_env, p))
.collect();
Ok(InferOk {
value: (),
obligations,
})
},
).unwrap()
}
fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
@ -1571,25 +1600,30 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
}
#[inline(never)]
fn normalize<T>(&mut self, value: &T, location: impl ToLocations) -> T
where
T: fmt::Debug + TypeFoldable<'tcx>,
{
debug!("normalize(value={:?}, location={:?})", value, location);
self.fully_perform_op(location.to_locations(), |this| {
let Normalized { value, obligations } = this.infcx
.at(&this.misc(this.last_span), this.param_env)
.normalize(value)
.unwrap_or_else(|NoSolution| {
span_bug!(
this.last_span,
"normalization of `{:?}` failed at {:?}",
value,
location,
);
});
Ok(InferOk { value, obligations })
}).unwrap()
self.fully_perform_op(
location.to_locations(),
|| format!("normalize(value={:?})", value),
|this| {
let Normalized { value, obligations } = this.infcx
.at(&this.misc(this.last_span), this.param_env)
.normalize(value)
.unwrap_or_else(|NoSolution| {
span_bug!(
this.last_span,
"normalization of `{:?}` failed at {:?}",
value,
location,
);
});
Ok(InferOk { value, obligations })
},
).unwrap()
}
}