Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MIR] Implement translation of references to various items #29907

Merged
merged 4 commits into from
Dec 18, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/librustc/mir/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -698,10 +698,20 @@ pub struct Constant<'tcx> {
pub literal: Literal<'tcx>,
}

#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum ItemKind {
Constant,
Function,
Struct,
Variant,
Method,
}

#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum Literal<'tcx> {
Item {
def_id: DefId,
kind: ItemKind,
substs: &'tcx Substs<'tcx>,
},
Value {
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir/build/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
-> Operand<'tcx> {
let literal = Literal::Item {
def_id: item_ref.def_id,
kind: item_ref.kind,
substs: item_ref.substs,
};
self.literal_operand(span, item_ref.ty, literal)
Expand Down
36 changes: 30 additions & 6 deletions src/librustc_mir/hair/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ fn method_callee<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
kind: ExprKind::Literal {
literal: Literal::Item {
def_id: callee.def_id,
kind: ItemKind::Method,
substs: callee.substs,
},
},
Expand Down Expand Up @@ -514,16 +515,39 @@ fn convert_arm<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, arm: &'tcx hir::Arm) -> Arm<

fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> ExprKind<'tcx> {
let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs);
match cx.tcx.def_map.borrow()[&expr.id].full_def() {
// Otherwise there may be def_map borrow conflicts
let def = cx.tcx.def_map.borrow()[&expr.id].full_def();
match def {
def::DefVariant(_, def_id, false) |
def::DefStruct(def_id) |
def::DefFn(def_id, _) |
def::DefConst(def_id) |
def::DefMethod(def_id) |
def::DefAssociatedConst(def_id) =>
def::DefMethod(def_id) => {
let kind = match def {
def::DefVariant(..) => ItemKind::Variant,
def::DefStruct(..) => ItemKind::Struct,
def::DefFn(..) => ItemKind::Function,
def::DefMethod(..) => ItemKind::Method,
_ => panic!()
};
ExprKind::Literal {
literal: Literal::Item { def_id: def_id, substs: substs }
},
literal: Literal::Item { def_id: def_id, kind: kind, substs: substs }
}
},
def::DefConst(def_id) |
def::DefAssociatedConst(def_id) => {
if let Some(v) = cx.try_const_eval_literal(expr) {
ExprKind::Literal { literal: v }
} else {
ExprKind::Literal {
literal: Literal::Item {
def_id: def_id,
kind: ItemKind::Constant,
substs: substs
}
}
}
}


def::DefStatic(node_id, _) =>
ExprKind::StaticRef {
Expand Down
8 changes: 8 additions & 0 deletions src/librustc_mir/hair/cx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ impl<'a,'tcx:'a> Cx<'a, 'tcx> {
Literal::Value { value: const_eval::eval_const_expr(self.tcx, e) }
}

pub fn try_const_eval_literal(&mut self, e: &hir::Expr) -> Option<Literal<'tcx>> {
let hint = const_eval::EvalHint::ExprTypeChecked;
const_eval::eval_const_expr_partial(self.tcx, e, hint, None)
.ok()
.map(|v| Literal::Value { value: v })
}

pub fn partial_eq(&mut self, ty: Ty<'tcx>) -> ItemRef<'tcx> {
let eq_def_id = self.tcx.lang_items.eq_trait().unwrap();
self.cmp_method_ref(eq_def_id, "eq", ty)
Expand Down Expand Up @@ -132,6 +139,7 @@ impl<'a,'tcx:'a> Cx<'a, 'tcx> {
let method_ty = method_ty.ty.subst(self.tcx, &substs);
return ItemRef {
ty: method_ty,
kind: ItemKind::Method,
def_id: method.def_id,
substs: self.tcx.mk_substs(substs),
};
Expand Down
6 changes: 5 additions & 1 deletion src/librustc_mir/hair/cx/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,11 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
Literal::Value { value: value }
} else {
let substs = self.cx.tcx.mk_substs(Substs::empty());
Literal::Item { def_id: def_id, substs: substs }
Literal::Item {
def_id: def_id,
kind: ItemKind::Constant,
substs: substs
}
};
PatternKind::Constant { value: literal }
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_mir/hair/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
//! unit-tested and separated from the Rust source and compiler data
//! structures.

use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp};
use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp, ItemKind};
use rustc::middle::def_id::DefId;
use rustc::middle::region::CodeExtent;
use rustc::middle::subst::Substs;
Expand All @@ -29,6 +29,7 @@ pub mod cx;
#[derive(Clone, Debug)]
pub struct ItemRef<'tcx> {
pub ty: Ty<'tcx>,
pub kind: ItemKind,
pub def_id: DefId,
pub substs: &'tcx Substs<'tcx>,
}
Expand Down
15 changes: 7 additions & 8 deletions src/librustc_trans/trans/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,13 @@ pub fn const_lit(cx: &CrateContext, e: &hir::Expr, lit: &ast::Lit)
}
}

pub fn trans_constval<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
pub fn trans_constval<'blk, 'tcx>(bcx: common::Block<'blk, 'tcx>,
cv: &ConstVal,
ty: Ty<'tcx>,
param_substs: &'tcx Substs<'tcx>)
-> ValueRef
{
let ccx = bcx.ccx();
let llty = type_of::type_of(ccx, ty);
match *cv {
ConstVal::Float(v) => C_floating_f64(v, llty),
Expand All @@ -123,19 +124,17 @@ pub fn trans_constval<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
ConstVal::ByteStr(ref v) => addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
ConstVal::Struct(id) | ConstVal::Tuple(id) => {
let expr = ccx.tcx().map.expect_expr(id);
let expr = bcx.tcx().map.expect_expr(id);
match const_expr(ccx, expr, param_substs, None, TrueConst::Yes) {
Ok((val, _)) => val,
Err(e) => panic!("const eval failure: {}", e.description()),
}
},
ConstVal::Function(_) => {
unimplemented!()
ConstVal::Array(id, _) | ConstVal::Repeat(id, _) => {
let expr = bcx.tcx().map.expect_expr(id);
expr::trans(bcx, expr).datum.val
},
ConstVal::Array(..) => {
unimplemented!()
},
ConstVal::Repeat(..) => {
ConstVal::Function(_) => {
unimplemented!()
},
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/meth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
///
/// In fact, all virtual calls can be thought of as normal trait calls
/// that go through this shim function.
fn trans_object_shim<'a, 'tcx>(
pub fn trans_object_shim<'a, 'tcx>(
ccx: &'a CrateContext<'a, 'tcx>,
upcast_trait_ref: ty::PolyTraitRef<'tcx>,
method_id: DefId,
Expand Down
20 changes: 9 additions & 11 deletions src/librustc_trans/trans/mir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use rustc::mir::repr as mir;
use trans::consts;
use trans::common::{self, Block};

use super::operand::OperandRef;

use super::operand::{OperandRef, OperandValue};
use super::MirContext;

impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
Expand All @@ -24,14 +25,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
ty: Ty<'tcx>)
-> OperandRef<'tcx>
{
use super::operand::OperandValue::{Ref, Immediate};

let ccx = bcx.ccx();
let val = consts::trans_constval(ccx, cv, ty, bcx.fcx.param_substs);
let val = consts::trans_constval(bcx, cv, ty, bcx.fcx.param_substs);
let val = if common::type_is_immediate(ccx, ty) {
Immediate(val)
OperandValue::Immediate(val)
} else {
Ref(val)
OperandValue::Ref(val)
};

assert!(!ty.has_erasable_regions());
Expand All @@ -47,13 +46,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
constant: &mir::Constant<'tcx>)
-> OperandRef<'tcx>
{
let constant_ty = bcx.monomorphize(&constant.ty);
let ty = bcx.monomorphize(&constant.ty);
match constant.literal {
mir::Literal::Item { .. } => {
unimplemented!()
}
mir::Literal::Item { def_id, kind, substs } =>
self.trans_item_ref(bcx, ty, kind, substs, def_id),
mir::Literal::Value { ref value } => {
self.trans_constval(bcx, value, constant_ty)
self.trans_constval(bcx, value, ty)
}
}
}
Expand Down
160 changes: 160 additions & 0 deletions src/librustc_trans/trans/mir/did.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// Copyright 2015 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.

//! Code for translating references to other items (DefIds).

use syntax::codemap::DUMMY_SP;
use rustc::front::map;
use rustc::middle::ty::{self, Ty, HasTypeFlags};
use rustc::middle::subst::Substs;
use rustc::middle::const_eval;
use rustc::middle::def_id::DefId;
use rustc::middle::subst;
use rustc::middle::traits;
use rustc::mir::repr::ItemKind;
use trans::common::{Block, fulfill_obligation};
use trans::base;
use trans::expr;
use trans::monomorphize;
use trans::meth;
use trans::inline;

use super::MirContext;
use super::operand::{OperandRef, OperandValue};

impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
/// Translate reference to item.
pub fn trans_item_ref(&mut self,
bcx: Block<'bcx, 'tcx>,
ty: Ty<'tcx>,
kind: ItemKind,
substs: &'tcx Substs<'tcx>,
did: DefId)
-> OperandRef<'tcx> {
match kind {
ItemKind::Function |
ItemKind::Struct |
ItemKind::Variant => self.trans_fn_ref(bcx, ty, substs, did),
ItemKind::Method => match bcx.tcx().impl_or_trait_item(did).container() {
ty::ImplContainer(_) => self.trans_fn_ref(bcx, ty, substs, did),
ty::TraitContainer(tdid) => self.trans_static_method(bcx, ty, did, tdid, substs)
},
ItemKind::Constant => {
let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
let expr = const_eval::lookup_const_by_id(bcx.tcx(), did, None)
.expect("def was const, but lookup_const_by_id failed");
// FIXME: this is falling back to translating from HIR. This is not easy to fix,
// because we would have somehow adapt const_eval to work on MIR rather than HIR.
let d = expr::trans(bcx, expr);
OperandRef::from_rvalue_datum(d.datum.to_rvalue_datum(d.bcx, "").datum)
}
}
}

/// Translates references to a function-like items.
///
/// That includes regular functions, non-static methods, struct and enum variant constructors,
/// closures and possibly more.
///
/// This is an adaptation of callee::trans_fn_ref_with_substs.
pub fn trans_fn_ref(&mut self,
bcx: Block<'bcx, 'tcx>,
ty: Ty<'tcx>,
substs: &'tcx Substs<'tcx>,
did: DefId)
-> OperandRef<'tcx> {
let did = inline::maybe_instantiate_inline(bcx.ccx(), did);

if !substs.types.is_empty() || is_named_tuple_constructor(bcx.tcx(), did) {
let (val, fn_ty, _) = monomorphize::monomorphic_fn(bcx.ccx(), did, substs, None);
// FIXME: cast fnptr to proper type if necessary
OperandRef {
ty: fn_ty,
val: OperandValue::Immediate(val)
}
} else {
let val = if let Some(node_id) = bcx.tcx().map.as_local_node_id(did) {
base::get_item_val(bcx.ccx(), node_id)
} else {
base::trans_external_path(bcx.ccx(), did, ty)
};
// FIXME: cast fnptr to proper type if necessary
OperandRef {
ty: ty,
val: OperandValue::Immediate(val)
}
}
}

/// Translates references to static methods.
///
/// This is an adaptation of meth::trans_static_method_callee
pub fn trans_static_method(&mut self,
bcx: Block<'bcx, 'tcx>,
ty: Ty<'tcx>,
method_id: DefId,
trait_id: DefId,
substs: &'tcx Substs<'tcx>)
-> OperandRef<'tcx> {
let ccx = bcx.ccx();
let tcx = bcx.tcx();
let mname = tcx.item_name(method_id);
let subst::SeparateVecsPerParamSpace {
types: rcvr_type,
selfs: rcvr_self,
fns: rcvr_method
} = substs.clone().types.split();
let trait_substs = Substs::erased(
subst::VecPerParamSpace::new(rcvr_type, rcvr_self, Vec::new())
);
let trait_substs = tcx.mk_substs(trait_substs);
let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, trait_substs));
let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
match vtbl {
traits::VtableImpl(traits::VtableImplData { impl_def_id, substs: imp_substs, .. }) => {
assert!(!imp_substs.types.needs_infer());
let subst::SeparateVecsPerParamSpace {
types: impl_type,
selfs: impl_self,
fns: _
} = imp_substs.types.split();
let callee_substs = Substs::erased(
subst::VecPerParamSpace::new(impl_type, impl_self, rcvr_method)
);
let mth = tcx.get_impl_method(impl_def_id, callee_substs, mname);
let mthsubsts = tcx.mk_substs(mth.substs);
self.trans_fn_ref(bcx, ty, mthsubsts, mth.method.def_id)
},
traits::VtableObject(ref data) => {
let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id);
OperandRef::from_rvalue_datum(
meth::trans_object_shim(ccx, data.upcast_trait_ref.clone(), method_id, idx)
)
}
_ => {
tcx.sess.bug(&format!("static call to invalid vtable: {:?}", vtbl));
}
}
}
}

fn is_named_tuple_constructor(tcx: &ty::ctxt, def_id: DefId) -> bool {
let node_id = match tcx.map.as_local_node_id(def_id) {
Some(n) => n,
None => { return false; }
};
match tcx.map.find(node_id).expect("local item should be in ast map") {
map::NodeVariant(v) => {
v.node.data.is_tuple()
}
map::NodeStructCtor(_) => true,
_ => false
}
}
1 change: 1 addition & 0 deletions src/librustc_trans/trans/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,4 @@ mod lvalue;
mod rvalue;
mod operand;
mod statement;
mod did;
Loading