Auto merge of #31474 - arielb1:mir-typeck, r=nikomatsakis
This should stop broken MIR from annoying us when we try to implement things
This commit is contained in:
commit
6c751e0456
43 changed files with 1509 additions and 190 deletions
|
|
@ -721,10 +721,11 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
|
|||
if let Some(adjustment) = adj {
|
||||
match adjustment {
|
||||
adjustment::AdjustReifyFnPointer |
|
||||
adjustment::AdjustUnsafeFnPointer => {
|
||||
adjustment::AdjustUnsafeFnPointer |
|
||||
adjustment::AdjustMutToConstPointer => {
|
||||
// Creating a closure/fn-pointer or unsizing consumes
|
||||
// the input and stores it into the resulting rvalue.
|
||||
debug!("walk_adjustment(AdjustReifyFnPointer|AdjustUnsafeFnPointer)");
|
||||
debug!("walk_adjustment: trivial adjustment");
|
||||
let cmt_unadjusted =
|
||||
return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
||||
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
|
||||
|
|
|
|||
|
|
@ -430,6 +430,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {
|
|||
|
||||
adjustment::AdjustReifyFnPointer |
|
||||
adjustment::AdjustUnsafeFnPointer |
|
||||
adjustment::AdjustMutToConstPointer |
|
||||
adjustment::AdjustDerefRef(_) => {
|
||||
debug!("cat_expr({:?}): {:?}",
|
||||
adjustment,
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@ use rustc_front::hir;
|
|||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum AutoAdjustment<'tcx> {
|
||||
AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type
|
||||
AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer
|
||||
AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type
|
||||
AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer
|
||||
AdjustMutToConstPointer, // go from a mut raw pointer to a const raw pointer
|
||||
AdjustDerefRef(AutoDerefRef<'tcx>),
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +107,8 @@ impl<'tcx> AutoAdjustment<'tcx> {
|
|||
pub fn is_identity(&self) -> bool {
|
||||
match *self {
|
||||
AdjustReifyFnPointer |
|
||||
AdjustUnsafeFnPointer => false,
|
||||
AdjustUnsafeFnPointer |
|
||||
AdjustMutToConstPointer => false,
|
||||
AdjustDerefRef(ref r) => r.is_identity(),
|
||||
}
|
||||
}
|
||||
|
|
@ -151,7 +153,7 @@ impl<'tcx> ty::TyS<'tcx> {
|
|||
return match adjustment {
|
||||
Some(adjustment) => {
|
||||
match *adjustment {
|
||||
AdjustReifyFnPointer => {
|
||||
AdjustReifyFnPointer => {
|
||||
match self.sty {
|
||||
ty::TyBareFn(Some(_), b) => {
|
||||
cx.mk_fn(None, b)
|
||||
|
|
@ -164,17 +166,32 @@ impl<'tcx> ty::TyS<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
AdjustUnsafeFnPointer => {
|
||||
AdjustUnsafeFnPointer => {
|
||||
match self.sty {
|
||||
ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b),
|
||||
ref b => {
|
||||
cx.sess.bug(
|
||||
&format!("AdjustReifyFnPointer adjustment on non-fn-item: \
|
||||
&format!("AdjustUnsafeFnPointer adjustment on non-fn-ptr: \
|
||||
{:?}",
|
||||
b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AdjustMutToConstPointer => {
|
||||
match self.sty {
|
||||
ty::TyRawPtr(mt) => cx.mk_ptr(ty::TypeAndMut {
|
||||
ty: mt.ty,
|
||||
mutbl: hir::MutImmutable
|
||||
}),
|
||||
ref b => {
|
||||
cx.sess.bug(
|
||||
&format!("AdjustMutToConstPointer on non-raw-ptr: \
|
||||
{:?}",
|
||||
b));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AdjustDerefRef(ref adj) => {
|
||||
let mut adjusted_ty = self;
|
||||
|
|
|
|||
|
|
@ -131,6 +131,12 @@ pub struct Tables<'tcx> {
|
|||
/// equivalents. This table is not used in trans (since regions
|
||||
/// are erased there) and hence is not serialized to metadata.
|
||||
pub liberated_fn_sigs: NodeMap<ty::FnSig<'tcx>>,
|
||||
|
||||
/// For each FRU expression, record the normalized types of the fields
|
||||
/// of the struct - this is needed because it is non-trivial to
|
||||
/// normalize while preserving regions. This table is used only in
|
||||
/// MIR construction and hence is not serialized to metadata.
|
||||
pub fru_field_types: NodeMap<Vec<Ty<'tcx>>>
|
||||
}
|
||||
|
||||
impl<'tcx> Tables<'tcx> {
|
||||
|
|
@ -144,6 +150,7 @@ impl<'tcx> Tables<'tcx> {
|
|||
closure_tys: DefIdMap(),
|
||||
closure_kinds: DefIdMap(),
|
||||
liberated_fn_sigs: NodeMap(),
|
||||
fru_field_types: NodeMap()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use dep_graph::DepNode;
|
||||
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 +21,17 @@ 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 did = tcx.map.local_def_id(id);
|
||||
let _task = tcx.dep_graph.in_task(DepNode::MirMapConstruction(did));
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@ pub struct Mir<'tcx> {
|
|||
/// values in that it is possible to borrow them and mutate them
|
||||
/// through the resulting reference.
|
||||
pub temp_decls: Vec<TempDecl<'tcx>>,
|
||||
|
||||
/// A span representing this MIR, for error reporting
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
/// where execution begins
|
||||
|
|
@ -145,7 +148,7 @@ pub enum BorrowKind {
|
|||
|
||||
/// A "variable" is a binding declared by the user as part of the fn
|
||||
/// decl, a let, etc.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct VarDecl<'tcx> {
|
||||
pub mutability: Mutability,
|
||||
pub name: Name,
|
||||
|
|
@ -154,7 +157,7 @@ pub struct VarDecl<'tcx> {
|
|||
|
||||
/// A "temp" is a temporary that we place on the stack. They are
|
||||
/// anonymous, always mutable, and have only a type.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct TempDecl<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
|
@ -170,7 +173,7 @@ pub struct TempDecl<'tcx> {
|
|||
///
|
||||
/// there is only one argument, of type `(i32, u32)`, but two bindings
|
||||
/// (`x` and `y`).
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct ArgDecl<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
|
@ -499,7 +502,7 @@ pub struct Projection<'tcx, B, V> {
|
|||
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
pub enum ProjectionElem<'tcx, V> {
|
||||
Deref,
|
||||
Field(Field),
|
||||
Field(Field, Ty<'tcx>),
|
||||
Index(V),
|
||||
|
||||
/// These indices are generated by slice patterns. Easiest to explain
|
||||
|
|
@ -550,8 +553,8 @@ impl Field {
|
|||
}
|
||||
|
||||
impl<'tcx> Lvalue<'tcx> {
|
||||
pub fn field(self, f: Field) -> Lvalue<'tcx> {
|
||||
self.elem(ProjectionElem::Field(f))
|
||||
pub fn field(self, f: Field, ty: Ty<'tcx>) -> Lvalue<'tcx> {
|
||||
self.elem(ProjectionElem::Field(f, ty))
|
||||
}
|
||||
|
||||
pub fn deref(self) -> Lvalue<'tcx> {
|
||||
|
|
@ -591,8 +594,8 @@ impl<'tcx> Debug for Lvalue<'tcx> {
|
|||
write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].name),
|
||||
ProjectionElem::Deref =>
|
||||
write!(fmt, "(*{:?})", data.base),
|
||||
ProjectionElem::Field(field) =>
|
||||
write!(fmt, "{:?}.{:?}", data.base, field.index()),
|
||||
ProjectionElem::Field(field, ty) =>
|
||||
write!(fmt, "({:?}.{:?}: {:?})", data.base, field.index(), ty),
|
||||
ProjectionElem::Index(ref index) =>
|
||||
write!(fmt, "{:?}[{:?}]", data.base, index),
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end: false } =>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@
|
|||
*/
|
||||
|
||||
use mir::repr::*;
|
||||
use middle::subst::Substs;
|
||||
use middle::const_eval::ConstVal;
|
||||
use middle::subst::{Subst, Substs};
|
||||
use middle::ty::{self, AdtDef, Ty};
|
||||
use rustc_front::hir;
|
||||
|
||||
|
|
@ -72,23 +73,7 @@ impl<'tcx> LvalueTy<'tcx> {
|
|||
tcx.sess.bug(&format!("cannot downcast non-enum type: `{:?}`", self))
|
||||
}
|
||||
},
|
||||
ProjectionElem::Field(field) => {
|
||||
let field_ty = match self {
|
||||
LvalueTy::Ty { ty } => match ty.sty {
|
||||
ty::TyStruct(adt_def, substs) =>
|
||||
adt_def.struct_variant().fields[field.index()].ty(tcx, substs),
|
||||
ty::TyTuple(ref tys) =>
|
||||
tys[field.index()],
|
||||
ty::TyClosure(_, ref closure_substs) =>
|
||||
closure_substs.upvar_tys[field.index()],
|
||||
_ =>
|
||||
tcx.sess.bug(&format!("cannot get field of type: `{:?}`", ty)),
|
||||
},
|
||||
LvalueTy::Downcast { adt_def, substs, variant_index } =>
|
||||
adt_def.variants[variant_index].fields[field.index()].ty(tcx, substs),
|
||||
};
|
||||
LvalueTy::Ty { ty: field_ty }
|
||||
}
|
||||
ProjectionElem::Field(_, fty) => LvalueTy::Ty { ty: fty }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -150,6 +135,73 @@ impl<'tcx> Mir<'tcx> {
|
|||
self.lvalue_ty(tcx, &proj.base).projection_ty(tcx, &proj.elem)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rvalue_ty(&self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
rvalue: &Rvalue<'tcx>)
|
||||
-> Option<Ty<'tcx>>
|
||||
{
|
||||
match *rvalue {
|
||||
Rvalue::Use(ref operand) => Some(self.operand_ty(tcx, operand)),
|
||||
Rvalue::Repeat(ref operand, ref count) => {
|
||||
if let ConstVal::Uint(u) = count.value {
|
||||
let op_ty = self.operand_ty(tcx, operand);
|
||||
Some(tcx.mk_array(op_ty, u as usize))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Rvalue::Ref(reg, bk, ref lv) => {
|
||||
let lv_ty = self.lvalue_ty(tcx, lv).to_ty(tcx);
|
||||
Some(tcx.mk_ref(
|
||||
tcx.mk_region(reg),
|
||||
ty::TypeAndMut {
|
||||
ty: lv_ty,
|
||||
mutbl: bk.to_mutbl_lossy()
|
||||
}
|
||||
))
|
||||
}
|
||||
Rvalue::Len(..) => Some(tcx.types.usize),
|
||||
Rvalue::Cast(_, _, ty) => Some(ty),
|
||||
Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
|
||||
let lhs_ty = self.operand_ty(tcx, lhs);
|
||||
let rhs_ty = self.operand_ty(tcx, rhs);
|
||||
Some(self.binop_ty(tcx, op, lhs_ty, rhs_ty))
|
||||
}
|
||||
Rvalue::UnaryOp(_, ref operand) => {
|
||||
Some(self.operand_ty(tcx, operand))
|
||||
}
|
||||
Rvalue::Box(t) => {
|
||||
Some(tcx.mk_box(t))
|
||||
}
|
||||
Rvalue::Aggregate(ref ak, ref ops) => {
|
||||
match *ak {
|
||||
AggregateKind::Vec => {
|
||||
if let Some(operand) = ops.get(0) {
|
||||
let ty = self.operand_ty(tcx, operand);
|
||||
Some(tcx.mk_array(ty, ops.len()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
AggregateKind::Tuple => {
|
||||
Some(tcx.mk_tup(
|
||||
ops.iter().map(|op| self.operand_ty(tcx, op)).collect()
|
||||
))
|
||||
}
|
||||
AggregateKind::Adt(def, _, substs) => {
|
||||
Some(def.type_scheme(tcx).ty.subst(tcx, substs))
|
||||
}
|
||||
AggregateKind::Closure(did, substs) => {
|
||||
Some(tcx.mk_closure_from_closure_substs(
|
||||
did, Box::new(substs.clone())))
|
||||
}
|
||||
}
|
||||
}
|
||||
Rvalue::Slice { .. } => None,
|
||||
Rvalue::InlineAsm(..) => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BorrowKind {
|
||||
|
|
|
|||
|
|
@ -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>);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ pub struct Options {
|
|||
pub no_trans: bool,
|
||||
pub error_format: ErrorOutputType,
|
||||
pub treat_err_as_bug: bool,
|
||||
pub mir_opt_level: usize,
|
||||
|
||||
/// if true, build up the dep-graph
|
||||
pub build_dep_graph: bool,
|
||||
|
|
@ -254,6 +255,7 @@ pub fn basic_options() -> Options {
|
|||
parse_only: false,
|
||||
no_trans: false,
|
||||
treat_err_as_bug: false,
|
||||
mir_opt_level: 1,
|
||||
build_dep_graph: false,
|
||||
dump_dep_graph: false,
|
||||
no_analysis: false,
|
||||
|
|
@ -655,6 +657,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
|||
"show spans for compiler debugging (expr|pat|ty)"),
|
||||
print_trans_items: Option<String> = (None, parse_opt_string,
|
||||
"print the result of the translation item collection pass"),
|
||||
mir_opt_level: Option<usize> = (None, parse_opt_uint,
|
||||
"set the MIR optimization level (0-3)"),
|
||||
}
|
||||
|
||||
pub fn default_lib_output() -> CrateType {
|
||||
|
|
@ -988,6 +992,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
|||
let parse_only = debugging_opts.parse_only;
|
||||
let no_trans = debugging_opts.no_trans;
|
||||
let treat_err_as_bug = debugging_opts.treat_err_as_bug;
|
||||
let mir_opt_level = debugging_opts.mir_opt_level.unwrap_or(1);
|
||||
let incremental_compilation = debugging_opts.incr_comp;
|
||||
let dump_dep_graph = debugging_opts.dump_dep_graph;
|
||||
let no_analysis = debugging_opts.no_analysis;
|
||||
|
|
@ -1166,6 +1171,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
|||
parse_only: parse_only,
|
||||
no_trans: no_trans,
|
||||
treat_err_as_bug: treat_err_as_bug,
|
||||
mir_opt_level: mir_opt_level,
|
||||
build_dep_graph: incremental_compilation || dump_dep_graph,
|
||||
dump_dep_graph: dump_dep_graph,
|
||||
no_analysis: no_analysis,
|
||||
|
|
|
|||
|
|
@ -396,6 +396,9 @@ impl<'tcx> fmt::Debug for ty::adjustment::AutoAdjustment<'tcx> {
|
|||
ty::adjustment::AdjustUnsafeFnPointer => {
|
||||
write!(f, "AdjustUnsafeFnPointer")
|
||||
}
|
||||
ty::adjustment::AdjustMutToConstPointer => {
|
||||
write!(f, "AdjustMutToConstPointer")
|
||||
}
|
||||
ty::adjustment::AdjustDerefRef(ref data) => {
|
||||
write!(f, "{:?}", data)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue