use the FulfillmentContext and InferCtxt more correctly

This commit is contained in:
Ariel Ben-Yehuda 2016-02-13 00:23:16 +02:00
parent a61963ab08
commit 881249aa46
9 changed files with 117 additions and 77 deletions

View File

@ -12,6 +12,7 @@ use util::nodemap::NodeMap;
use mir::repr::Mir;
use mir::transform::MirPass;
use middle::ty;
use middle::infer;
pub struct MirMap<'tcx> {
pub map: NodeMap<Mir<'tcx>>,
@ -19,9 +20,14 @@ pub struct MirMap<'tcx> {
impl<'tcx> MirMap<'tcx> {
pub fn run_passes(&mut self, passes: &mut [Box<MirPass>], tcx: &ty::ctxt<'tcx>) {
for (_, ref mut mir) in &mut self.map {
if passes.is_empty() { return; }
for (&id, mir) in &mut self.map {
let param_env = ty::ParameterEnvironment::for_item(tcx, id);
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env));
for pass in &mut *passes {
pass.run_on_mir(mir, tcx)
pass.run_on_mir(mir, &infcx)
}
}
}

View File

@ -9,8 +9,8 @@
// except according to those terms.
use mir::repr::Mir;
use middle::ty::ctxt;
use middle::infer::InferCtxt;
pub trait MirPass {
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, tcx: &ctxt<'tcx>);
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, infcx: &InferCtxt<'a, 'tcx>);
}

View File

@ -149,11 +149,11 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
Ok(mut mir) => {
clear_dead_blocks::ClearDeadBlocks::new().run_on_mir(&mut mir, self.tcx);
type_check::TypeckMir::new(&infcx).run_on_mir(&mut mir, self.tcx);
no_landing_pads::NoLandingPads.run_on_mir(&mut mir, self.tcx);
clear_dead_blocks::ClearDeadBlocks::new().run_on_mir(&mut mir, &infcx);
type_check::TypeckMir::new().run_on_mir(&mut mir, &infcx);
no_landing_pads::NoLandingPads.run_on_mir(&mut mir, &infcx);
if self.tcx.sess.opts.mir_opt_level > 0 {
simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir, self.tcx);
simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir, &infcx);
}
let meta_item_list = self.attr
.iter()

View File

@ -15,7 +15,7 @@
//! This pass does not renumber or remove the blocks, to have the
//! MIR better match the source.
use rustc::middle::ty;
use rustc::middle::infer;
use rustc::mir::repr::*;
use rustc::mir::transform::MirPass;
@ -56,7 +56,8 @@ impl ClearDeadBlocks {
}
impl MirPass for ClearDeadBlocks {
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, _tcx: &ty::ctxt<'tcx>) {
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &infer::InferCtxt<'a, 'tcx>)
{
self.clear_dead_blocks(mir);
}
}

View File

@ -16,18 +16,13 @@ use rustc::middle::ty;
use rustc::mir::repr::*;
use rustc::mir::visit::MutVisitor;
use rustc::mir::mir_map::MirMap;
use rustc::mir::transform::MirPass;
pub fn erase_regions<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &mut MirMap<'tcx>) {
let mut eraser = EraseRegions;
for (_, mir) in &mut mir_map.map {
eraser.run_on_mir(mir, tcx);
EraseRegionsVisitor::new(tcx).visit_mir(mir);
}
}
pub struct EraseRegions;
struct EraseRegionsVisitor<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
}
@ -58,12 +53,6 @@ impl<'a, 'tcx> EraseRegionsVisitor<'a, 'tcx> {
}
}
impl MirPass for EraseRegions {
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, tcx: &ty::ctxt<'tcx>) {
EraseRegionsVisitor::new(tcx).visit_mir(mir);
}
}
impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
fn visit_mir(&mut self, mir: &mut Mir<'tcx>) {
self.erase_regions_return_ty(&mut mir.return_ty);

View File

@ -11,7 +11,7 @@
//! This pass removes the unwind branch of all the terminators when the no-landing-pads option is
//! specified.
use rustc::middle::ty;
use rustc::middle::infer;
use rustc::mir::repr::*;
use rustc::mir::visit::MutVisitor;
use rustc::mir::transform::MirPass;
@ -41,8 +41,9 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
}
impl MirPass for NoLandingPads {
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, tcx: &ty::ctxt<'tcx>) {
if tcx.sess.no_landing_pads() {
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>,
infcx: &infer::InferCtxt<'a, 'tcx>) {
if infcx.tcx.sess.no_landing_pads() {
self.visit_mir(mir);
}
}

View File

@ -9,6 +9,7 @@
// except according to those terms.
use rustc::middle::const_eval::ConstVal;
use rustc::middle::infer;
use rustc::mir::repr::*;
use transform::util;
use rustc::mir::transform::MirPass;
@ -119,7 +120,7 @@ impl SimplifyCfg {
}
impl MirPass for SimplifyCfg {
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &::rustc::middle::ty::ctxt<'tcx>) {
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &infer::InferCtxt<'a, 'tcx>) {
let mut changed = true;
while changed {
changed = self.simplify_branches(mir);

View File

@ -11,7 +11,7 @@
//! This pass type-checks the MIR to ensure it is not broken.
#![allow(unreachable_code)]
use rustc::middle::infer;
use rustc::middle::infer::{self, InferCtxt};
use rustc::middle::traits;
use rustc::middle::ty::{self, Ty};
use rustc::middle::ty::fold::TypeFoldable;
@ -35,7 +35,7 @@ macro_rules! span_mirbug {
macro_rules! span_mirbug_and_err {
($context:expr, $elem:expr, $($message:tt)*) => ({
{
$context.tcx().sess.span_bug(
$context.tcx().sess.span_warn(
$context.last_span,
&format!("broken MIR ({:?}): {:?}", $elem, format!($($message)*))
);
@ -50,14 +50,14 @@ enum FieldAccessError {
/// Verifies that MIR types are sane to not crash further
/// checks.
struct TypeVerifier<'a, 'tcx: 'a> {
infcx: &'a infer::InferCtxt<'a, 'tcx>,
struct TypeVerifier<'a, 'b: 'a, 'tcx: 'b> {
cx: &'a mut TypeChecker<'b, 'tcx>,
mir: &'a Mir<'tcx>,
last_span: Span,
errors_reported: bool
}
impl<'a, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'tcx> {
impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
fn visit_span(&mut self, span: &Span) {
if *span != DUMMY_SP {
self.last_span = *span;
@ -100,10 +100,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'tcx> {
}
}
impl<'a, 'tcx> TypeVerifier<'a, 'tcx> {
fn new(infcx: &'a infer::InferCtxt<'a, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
fn new(cx: &'a mut TypeChecker<'b, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
TypeVerifier {
infcx: infcx,
cx: cx,
mir: mir,
last_span: mir.span,
errors_reported: false
@ -111,7 +111,11 @@ impl<'a, 'tcx> TypeVerifier<'a, 'tcx> {
}
fn tcx(&self) -> &'a ty::ctxt<'tcx> {
self.infcx.tcx
self.cx.infcx.tcx
}
fn infcx(&self) -> &'a InferCtxt<'a, 'tcx> {
self.cx.infcx
}
fn sanitize_type(&mut self, parent: &fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> {
@ -163,6 +167,7 @@ impl<'a, 'tcx> TypeVerifier<'a, 'tcx> {
debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, lvalue);
let tcx = self.tcx();
let base_ty = base.to_ty(tcx);
let span = self.last_span;
match *pi {
ProjectionElem::Deref => {
let deref_ty = base_ty.builtin_deref(true, ty::LvaluePreference::NoPreference);
@ -227,7 +232,7 @@ impl<'a, 'tcx> TypeVerifier<'a, 'tcx> {
let fty = self.sanitize_type(lvalue, fty);
match self.field_ty(lvalue, base, field) {
Ok(ty) => {
if let Err(terr) = infer::can_mk_subty(self.infcx, ty, fty) {
if let Err(terr) = self.cx.mk_eqty(span, ty, fty) {
span_mirbug!(
self, lvalue, "bad field access ({:?}: {:?}): {:?}",
ty, fty, terr);
@ -282,14 +287,15 @@ impl<'a, 'tcx> TypeVerifier<'a, 'tcx> {
};
if let Some(field) = variant.fields.get(field.index()) {
Ok(self.normalize(parent, field.ty(tcx, substs)))
Ok(self.normalize(field.ty(tcx, substs)))
} else {
Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() })
}
}
fn normalize(&mut self, parent: &fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> {
let mut selcx = traits::SelectionContext::new(&self.infcx);
fn normalize(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
let infcx = self.infcx();
let mut selcx = traits::SelectionContext::new(infcx);
let cause = traits::ObligationCause::misc(self.last_span, 0);
let traits::Normalized { value: ty, obligations } =
traits::normalize(&mut selcx, cause, &ty);
@ -298,33 +304,44 @@ impl<'a, 'tcx> TypeVerifier<'a, 'tcx> {
ty,
obligations);
let mut fulfill_cx = self.infcx.fulfillment_cx.borrow_mut();
let mut fulfill_cx = &mut self.cx.fulfillment_cx;
for obligation in obligations {
fulfill_cx.register_predicate_obligation(&self.infcx, obligation);
fulfill_cx.register_predicate_obligation(infcx, obligation);
}
match infer::drain_fulfillment_cx(&self.infcx, &mut fulfill_cx, &ty) {
Ok(ty) => ty,
Err(e) => {
span_mirbug_and_err!(self, parent, "trait fulfillment failed: {:?}", e)
}
}
ty
}
}
pub struct TypeckMir<'a, 'tcx: 'a> {
infcx: &'a infer::InferCtxt<'a, 'tcx>,
pub struct TypeChecker<'a, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'tcx>,
fulfillment_cx: traits::FulfillmentContext<'tcx>,
last_span: Span
}
impl<'a, 'tcx> TypeckMir<'a, 'tcx> {
pub fn new(infcx: &'a infer::InferCtxt<'a, 'tcx>) -> Self {
TypeckMir {
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
TypeChecker {
infcx: infcx,
fulfillment_cx: traits::FulfillmentContext::new(),
last_span: DUMMY_SP
}
}
fn mk_subty(&self, span: Span, sup: Ty<'tcx>, sub: Ty<'tcx>)
-> infer::UnitResult<'tcx>
{
infer::mk_subty(self.infcx, false, infer::TypeOrigin::Misc(span),
sup, sub)
}
fn mk_eqty(&self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>)
-> infer::UnitResult<'tcx>
{
infer::mk_eqty(self.infcx, false, infer::TypeOrigin::Misc(span),
a, b)
}
fn tcx(&self) -> &'a ty::ctxt<'tcx> {
self.infcx.tcx
}
@ -337,7 +354,7 @@ impl<'a, 'tcx> TypeckMir<'a, 'tcx> {
let lv_ty = mir.lvalue_ty(tcx, lv).to_ty(tcx);
let rv_ty = mir.rvalue_ty(tcx, rv);
if let Some(rv_ty) = rv_ty {
if let Err(terr) = infer::can_mk_subty(self.infcx, rv_ty, lv_ty) {
if let Err(terr) = self.mk_subty(self.last_span, rv_ty, lv_ty) {
span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}",
lv_ty, rv_ty, terr);
}
@ -358,7 +375,10 @@ impl<'a, 'tcx> TypeckMir<'a, 'tcx> {
Terminator::Goto { .. } |
Terminator::Resume |
Terminator::Return |
Terminator::Drop { .. } => {}
Terminator::Drop { .. } => {
// no checks needed for these
}
Terminator::If { ref cond, .. } => {
let cond_ty = mir.operand_ty(tcx, cond);
match cond_ty.sty {
@ -370,15 +390,23 @@ impl<'a, 'tcx> TypeckMir<'a, 'tcx> {
}
Terminator::SwitchInt { ref discr, switch_ty, .. } => {
let discr_ty = mir.lvalue_ty(tcx, discr).to_ty(tcx);
if let Err(terr) = infer::can_mk_subty(self.infcx, discr_ty, switch_ty) {
if let Err(terr) = self.mk_subty(self.last_span, discr_ty, switch_ty) {
span_mirbug!(self, term, "bad SwitchInt ({:?} on {:?}): {:?}",
switch_ty, discr_ty, terr);
}
if !switch_ty.is_integral() && !switch_ty.is_char() &&
!switch_ty.is_bool()
{
span_mirbug!(self, term, "bad SwitchInt discr ty {:?}",switch_ty);
}
// FIXME: check the values
}
Terminator::Switch { ref discr, adt_def, .. } => {
Terminator::Switch { ref discr, adt_def, ref targets } => {
let discr_ty = mir.lvalue_ty(tcx, discr).to_ty(tcx);
match discr_ty.sty {
ty::TyEnum(def, _) if def == adt_def => {},
ty::TyEnum(def, _)
if def == adt_def && adt_def.variants.len() == targets.len()
=> {},
_ => {
span_mirbug!(self, term, "bad Switch ({:?} on {:?})",
adt_def, discr_ty);
@ -419,7 +447,7 @@ impl<'a, 'tcx> TypeckMir<'a, 'tcx> {
}
(&Some((ref dest, _)), ty::FnConverging(ty)) => {
let dest_ty = mir.lvalue_ty(tcx, dest).to_ty(tcx);
if let Err(terr) = infer::can_mk_subty(self.infcx, ty, dest_ty) {
if let Err(terr) = self.mk_subty(self.last_span, ty, dest_ty) {
span_mirbug!(self, term,
"call dest mismatch ({:?} <- {:?}): {:?}",
dest_ty, ty, terr);
@ -445,7 +473,7 @@ impl<'a, 'tcx> TypeckMir<'a, 'tcx> {
}
for (n, (fn_arg, op_arg)) in sig.inputs.iter().zip(args).enumerate() {
let op_arg_ty = mir.operand_ty(self.tcx(), op_arg);
if let Err(terr) = infer::can_mk_subty(self.infcx, op_arg_ty, fn_arg) {
if let Err(terr) = self.mk_subty(self.last_span, op_arg_ty, fn_arg) {
span_mirbug!(self, term, "bad arg #{:?} ({:?} <- {:?}): {:?}",
n, fn_arg, op_arg_ty, terr);
}
@ -500,7 +528,7 @@ impl<'a, 'tcx> TypeckMir<'a, 'tcx> {
}
};
if let Err(terr) = infer::can_mk_subty(self.infcx, arg_ty, pointee_ty) {
if let Err(terr) = self.mk_subty(self.last_span, arg_ty, pointee_ty) {
span_mirbug!(self, term, "bad box_free arg ({:?} <- {:?}): {:?}",
pointee_ty, arg_ty, terr);
}
@ -522,28 +550,45 @@ impl<'a, 'tcx> TypeckMir<'a, 'tcx> {
}
}
}
fn verify_obligations(&mut self, mir: &Mir<'tcx>) {
self.last_span = mir.span;
if let Err(e) = self.fulfillment_cx.select_all_or_error(self.infcx) {
span_mirbug!(self, "", "errors selecting obligation: {:?}",
e);
}
}
}
impl<'a, 'tcx> MirPass for TypeckMir<'a, 'tcx> {
fn run_on_mir<'tcx_>(&mut self,
mir: &mut Mir<'tcx_>,
_tcx: &ty::ctxt<'tcx_>) {
// FIXME: pass param_env to run_on_mir
let mir: &mut Mir<'tcx> = unsafe { ::std::mem::transmute(mir) };
pub struct TypeckMir;
if self.tcx().sess.err_count() > 0 {
impl TypeckMir {
pub fn new() -> Self {
TypeckMir
}
}
impl MirPass for TypeckMir {
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, infcx: &InferCtxt<'a, 'tcx>)
{
if infcx.tcx.sess.err_count() > 0 {
// compiling a broken program can obviously result in a
// broken MIR, so try not to report duplicate errors.
return;
}
let mut type_verifier = TypeVerifier::new(self.infcx, mir);
type_verifier.visit_mir(mir);
let mut checker = TypeChecker::new(infcx);
if type_verifier.errors_reported {
return;
{
let mut verifier = TypeVerifier::new(&mut checker, mir);
verifier.visit_mir(mir);
if verifier.errors_reported {
// don't do further checks to avoid ICEs
return;
}
}
self.typeck_mir(mir);
checker.typeck_mir(mir);
checker.verify_obligations(mir);
}
}

View File

@ -21,17 +21,14 @@ extern crate syntax;
use rustc::mir::transform::MirPass;
use rustc::mir::repr::{Mir, Literal};
use rustc::mir::visit::MutVisitor;
use rustc::middle::ty;
use rustc::middle::infer::InferCtxt;
use rustc::middle::const_eval::ConstVal;
use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray};
use rustc_plugin::Registry;
use rustc_front::hir;
use syntax::attr;
struct Pass;
impl MirPass for Pass {
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, tcx: &ty::ctxt<'tcx>) {
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &InferCtxt<'a, 'tcx>) {
Visitor.visit_mir(mir)
}
}