170 lines
6.8 KiB
Rust
170 lines
6.8 KiB
Rust
// 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, TypeFoldable};
|
|
use rustc::middle::subst::Substs;
|
|
use rustc::middle::const_eval;
|
|
use rustc::middle::def_id::DefId;
|
|
use rustc::middle::traits;
|
|
use rustc::mir::repr::ItemKind;
|
|
use trans::common::{Block, fulfill_obligation};
|
|
use trans::base;
|
|
use trans::closure;
|
|
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> {
|
|
debug!("trans_item_ref(ty={:?}, kind={:?}, substs={:?}, did={})",
|
|
ty, kind, substs, bcx.tcx().item_path_str(did));
|
|
|
|
match kind {
|
|
ItemKind::Function => 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_trait_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, Some(substs))
|
|
.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> {
|
|
debug!("trans_fn_ref(ty={:?}, substs={:?}, did={})",
|
|
ty, substs, bcx.tcx().item_path_str(did));
|
|
|
|
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 trait methods.
|
|
///
|
|
/// This is an adaptation of meth::trans_static_method_callee
|
|
pub fn trans_trait_method(&mut self,
|
|
bcx: Block<'bcx, 'tcx>,
|
|
ty: Ty<'tcx>,
|
|
method_id: DefId,
|
|
trait_id: DefId,
|
|
substs: &'tcx Substs<'tcx>)
|
|
-> OperandRef<'tcx> {
|
|
debug!("trans_static_method(ty={:?}, method={}, trait={}, substs={:?})",
|
|
ty,
|
|
bcx.tcx().item_path_str(method_id),
|
|
bcx.tcx().item_path_str(trait_id),
|
|
substs);
|
|
|
|
let ccx = bcx.ccx();
|
|
let tcx = bcx.tcx();
|
|
let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
|
|
let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
|
|
match vtbl {
|
|
traits::VtableImpl(traits::VtableImplData {
|
|
impl_def_id, substs: impl_substs, ..
|
|
}) => {
|
|
assert!(!impl_substs.types.needs_infer());
|
|
|
|
let mname = tcx.item_name(method_id);
|
|
|
|
let callee_substs = impl_substs.with_method_from(substs);
|
|
let mth = tcx.get_impl_method(impl_def_id, callee_substs, mname);
|
|
let mth_substs = tcx.mk_substs(mth.substs);
|
|
self.trans_fn_ref(bcx, ty, mth_substs, mth.method.def_id)
|
|
},
|
|
traits::VtableClosure(data) => {
|
|
let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
|
|
let llfn = closure::trans_closure_method(bcx.ccx(),
|
|
data.closure_def_id,
|
|
data.substs,
|
|
trait_closure_kind);
|
|
OperandRef {
|
|
ty: ty,
|
|
val: OperandValue::Immediate(llfn)
|
|
}
|
|
},
|
|
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
|
|
}
|
|
}
|