2017-03-23 07:35:19 -05:00
|
|
|
use rustc::traits::{self, Reveal};
|
2016-09-09 05:51:14 -05:00
|
|
|
|
2016-12-10 18:58:13 -06:00
|
|
|
use eval_context::EvalContext;
|
2017-07-04 06:16:29 -05:00
|
|
|
use memory::MemoryPointer;
|
2017-06-19 03:58:59 -05:00
|
|
|
use value::{Value, PrimVal};
|
2017-02-10 05:21:33 -06:00
|
|
|
|
|
|
|
use rustc::hir::def_id::DefId;
|
|
|
|
use rustc::ty::subst::Substs;
|
2017-03-23 07:35:19 -05:00
|
|
|
use rustc::ty::{self, Ty};
|
2017-02-10 05:21:33 -06:00
|
|
|
use syntax::codemap::DUMMY_SP;
|
2017-03-21 07:53:55 -05:00
|
|
|
use syntax::ast;
|
2017-02-10 05:21:33 -06:00
|
|
|
|
2017-06-19 03:58:59 -05:00
|
|
|
use error::{EvalResult, EvalError};
|
2016-09-09 05:51:14 -05:00
|
|
|
|
|
|
|
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
2017-02-10 05:21:33 -06:00
|
|
|
|
|
|
|
pub(crate) fn fulfill_obligation(&self, trait_ref: ty::PolyTraitRef<'tcx>) -> traits::Vtable<'tcx, ()> {
|
|
|
|
// Do the initial selection for the obligation. This yields the shallow result we are
|
|
|
|
// looking for -- that is, what specific impl.
|
2017-06-10 19:39:48 -05:00
|
|
|
self.tcx.infer_ctxt().enter(|infcx| {
|
2017-02-10 05:21:33 -06:00
|
|
|
let mut selcx = traits::SelectionContext::new(&infcx);
|
|
|
|
|
|
|
|
let obligation = traits::Obligation::new(
|
|
|
|
traits::ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID),
|
2017-06-02 20:00:35 -05:00
|
|
|
ty::ParamEnv::empty(Reveal::All),
|
2017-02-10 05:21:33 -06:00
|
|
|
trait_ref.to_poly_trait_predicate(),
|
|
|
|
);
|
|
|
|
let selection = selcx.select(&obligation).unwrap().unwrap();
|
|
|
|
|
|
|
|
// Currently, we use a fulfillment context to completely resolve all nested obligations.
|
|
|
|
// This is because they can inform the inference of the impl's type parameters.
|
|
|
|
let mut fulfill_cx = traits::FulfillmentContext::new();
|
|
|
|
let vtable = selection.map(|predicate| {
|
|
|
|
fulfill_cx.register_predicate_obligation(&infcx, predicate);
|
|
|
|
});
|
|
|
|
infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &vtable)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-09-11 04:06:44 -05:00
|
|
|
/// Creates a dynamic vtable for the given type and vtable origin. This is used only for
|
|
|
|
/// objects.
|
2016-09-09 05:51:14 -05:00
|
|
|
///
|
|
|
|
/// The `trait_ref` encodes the erased self type. Hence if we are
|
|
|
|
/// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
|
|
|
|
/// `trait_ref` would map `T:Trait`.
|
2017-07-04 06:16:29 -05:00
|
|
|
pub fn get_vtable(&mut self, ty: Ty<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> EvalResult<'tcx, MemoryPointer> {
|
2016-09-09 05:51:14 -05:00
|
|
|
debug!("get_vtable(trait_ref={:?})", trait_ref);
|
|
|
|
|
2016-11-17 10:23:40 -06:00
|
|
|
let size = self.type_size(trait_ref.self_ty())?.expect("can't create a vtable for an unsized type");
|
|
|
|
let align = self.type_align(trait_ref.self_ty())?;
|
2016-09-09 05:51:14 -05:00
|
|
|
|
|
|
|
let ptr_size = self.memory.pointer_size();
|
2017-03-23 07:35:19 -05:00
|
|
|
let methods = ::rustc::traits::get_vtable_methods(self.tcx, trait_ref);
|
|
|
|
let vtable = self.memory.allocate(ptr_size * (3 + methods.count() as u64), ptr_size)?;
|
2016-09-09 05:51:14 -05:00
|
|
|
|
2017-03-23 07:35:19 -05:00
|
|
|
let drop = ::eval_context::resolve_drop_in_place(self.tcx, ty);
|
|
|
|
let drop = self.memory.create_fn_alloc(drop);
|
|
|
|
self.memory.write_ptr(vtable, drop)?;
|
2016-09-09 05:51:14 -05:00
|
|
|
|
2017-06-05 20:07:26 -05:00
|
|
|
self.memory.write_usize(vtable.offset(ptr_size, self.memory.layout)?, size)?;
|
|
|
|
self.memory.write_usize(vtable.offset(ptr_size * 2, self.memory.layout)?, align)?;
|
2016-09-09 05:51:14 -05:00
|
|
|
|
2017-03-23 07:35:19 -05:00
|
|
|
for (i, method) in ::rustc::traits::get_vtable_methods(self.tcx, trait_ref).enumerate() {
|
|
|
|
if let Some((def_id, substs)) = method {
|
|
|
|
let instance = ::eval_context::resolve(self.tcx, def_id, substs);
|
|
|
|
let fn_ptr = self.memory.create_fn_alloc(instance);
|
2017-06-05 20:07:26 -05:00
|
|
|
self.memory.write_ptr(vtable.offset(ptr_size * (3 + i as u64), self.memory.layout)?, fn_ptr)?;
|
2016-09-09 05:51:14 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-08 09:27:28 -06:00
|
|
|
self.memory.mark_static_initalized(vtable.alloc_id, false)?;
|
2016-09-10 08:17:08 -05:00
|
|
|
|
2016-09-09 05:51:14 -05:00
|
|
|
Ok(vtable)
|
|
|
|
}
|
|
|
|
|
2017-07-04 06:16:29 -05:00
|
|
|
pub fn read_drop_type_from_vtable(&self, vtable: MemoryPointer) -> EvalResult<'tcx, Option<ty::Instance<'tcx>>> {
|
2017-06-19 03:58:59 -05:00
|
|
|
// we don't care about the pointee type, we just want a pointer
|
|
|
|
match self.read_ptr(vtable, self.tcx.mk_nil_ptr())? {
|
|
|
|
// some values don't need to call a drop impl, so the value is null
|
|
|
|
Value::ByVal(PrimVal::Bytes(0)) => Ok(None),
|
2017-06-21 23:45:51 -05:00
|
|
|
Value::ByVal(PrimVal::Ptr(drop_fn)) => self.memory.get_fn(drop_fn).map(Some),
|
2017-06-19 03:58:59 -05:00
|
|
|
_ => Err(EvalError::ReadBytesAsPointer),
|
2017-03-22 11:48:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-04 06:16:29 -05:00
|
|
|
pub fn read_size_and_align_from_vtable(&self, vtable: MemoryPointer) -> EvalResult<'tcx, (u64, u64)> {
|
2017-02-15 02:35:43 -06:00
|
|
|
let pointer_size = self.memory.pointer_size();
|
2017-06-05 20:07:26 -05:00
|
|
|
let size = self.memory.read_usize(vtable.offset(pointer_size, self.memory.layout)?)?;
|
|
|
|
let align = self.memory.read_usize(vtable.offset(pointer_size * 2, self.memory.layout)?)?;
|
2017-02-15 02:35:43 -06:00
|
|
|
Ok((size, align))
|
|
|
|
}
|
|
|
|
|
2017-02-10 05:12:33 -06:00
|
|
|
pub(crate) fn resolve_associated_const(
|
|
|
|
&self,
|
|
|
|
def_id: DefId,
|
|
|
|
substs: &'tcx Substs<'tcx>,
|
2017-03-21 07:53:55 -05:00
|
|
|
) -> ty::Instance<'tcx> {
|
2017-02-10 05:12:33 -06:00
|
|
|
if let Some(trait_id) = self.tcx.trait_of_item(def_id) {
|
|
|
|
let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, substs));
|
|
|
|
let vtable = self.fulfill_obligation(trait_ref);
|
|
|
|
if let traits::VtableImpl(vtable_impl) = vtable {
|
|
|
|
let name = self.tcx.item_name(def_id);
|
|
|
|
let assoc_const_opt = self.tcx.associated_items(vtable_impl.impl_def_id)
|
|
|
|
.find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
|
|
|
|
if let Some(assoc_const) = assoc_const_opt {
|
2017-03-21 07:53:55 -05:00
|
|
|
return ty::Instance::new(assoc_const.def_id, vtable_impl.substs);
|
2017-02-10 05:12:33 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-03-21 07:53:55 -05:00
|
|
|
ty::Instance::new(def_id, substs)
|
2017-02-10 05:12:33 -06:00
|
|
|
}
|
2016-09-09 05:51:14 -05:00
|
|
|
}
|