move some methods from FnEvalContext to GlobalEvalContext
This commit is contained in:
parent
4c833a54d2
commit
4d44a970a3
1 changed files with 160 additions and 96 deletions
|
@ -173,16 +173,150 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> {
|
|||
|
||||
fn call(&mut self, mir: &mir::Mir<'tcx>, def_id: DefId) -> EvalResult<Option<Pointer>> {
|
||||
let substs = self.tcx.mk_substs(subst::Substs::empty());
|
||||
let return_ptr = self.alloc_ret_ptr(mir.return_ty, substs);
|
||||
|
||||
let mut nested_fecx = FnEvalContext::new(self);
|
||||
|
||||
nested_fecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, None);
|
||||
let return_ptr = nested_fecx.alloc_ret_ptr(mir.return_ty);
|
||||
|
||||
nested_fecx.frame_mut().return_ptr = return_ptr;
|
||||
|
||||
nested_fecx.run()?;
|
||||
Ok(return_ptr)
|
||||
}
|
||||
|
||||
fn alloc_ret_ptr(&mut self, ty: ty::FnOutput<'tcx>, substs: &'tcx Substs<'tcx>) -> Option<Pointer> {
|
||||
match ty {
|
||||
ty::FnConverging(ty) => {
|
||||
let size = self.type_size(ty, substs);
|
||||
Some(self.memory.allocate(size))
|
||||
}
|
||||
ty::FnDiverging => None,
|
||||
}
|
||||
}
|
||||
// TODO(solson): Try making const_to_primval instead.
|
||||
fn const_to_ptr(&mut self, const_val: &const_val::ConstVal) -> EvalResult<Pointer> {
|
||||
use rustc::middle::const_val::ConstVal::*;
|
||||
match *const_val {
|
||||
Float(_f) => unimplemented!(),
|
||||
Integral(int) => {
|
||||
// TODO(solson): Check int constant type.
|
||||
let ptr = self.memory.allocate(8);
|
||||
self.memory.write_uint(ptr, int.to_u64_unchecked(), 8)?;
|
||||
Ok(ptr)
|
||||
}
|
||||
Str(ref s) => {
|
||||
let psize = self.memory.pointer_size;
|
||||
let static_ptr = self.memory.allocate(s.len());
|
||||
let ptr = self.memory.allocate(psize * 2);
|
||||
self.memory.write_bytes(static_ptr, s.as_bytes())?;
|
||||
self.memory.write_ptr(ptr, static_ptr)?;
|
||||
self.memory.write_usize(ptr.offset(psize as isize), s.len() as u64)?;
|
||||
Ok(ptr)
|
||||
}
|
||||
ByteStr(ref bs) => {
|
||||
let psize = self.memory.pointer_size;
|
||||
let static_ptr = self.memory.allocate(bs.len());
|
||||
let ptr = self.memory.allocate(psize);
|
||||
self.memory.write_bytes(static_ptr, bs)?;
|
||||
self.memory.write_ptr(ptr, static_ptr)?;
|
||||
Ok(ptr)
|
||||
}
|
||||
Bool(b) => {
|
||||
let ptr = self.memory.allocate(1);
|
||||
self.memory.write_bool(ptr, b)?;
|
||||
Ok(ptr)
|
||||
}
|
||||
Char(_c) => unimplemented!(),
|
||||
Struct(_node_id) => unimplemented!(),
|
||||
Tuple(_node_id) => unimplemented!(),
|
||||
Function(_def_id) => unimplemented!(),
|
||||
Array(_, _) => unimplemented!(),
|
||||
Repeat(_, _) => unimplemented!(),
|
||||
Dummy => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
|
||||
self.tcx.type_needs_drop_given_env(ty, &self.tcx.empty_parameter_environment())
|
||||
}
|
||||
|
||||
fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
|
||||
ty.is_sized(self.tcx, &self.tcx.empty_parameter_environment(), DUMMY_SP)
|
||||
}
|
||||
|
||||
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.
|
||||
self.tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
|
||||
let mut selcx = traits::SelectionContext::new(&infcx);
|
||||
|
||||
let obligation = traits::Obligation::new(
|
||||
traits::ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID),
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
/// Trait method, which has to be resolved to an impl method.
|
||||
pub fn trait_method(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
substs: &'tcx Substs<'tcx>
|
||||
) -> (DefId, &'tcx Substs<'tcx>) {
|
||||
let method_item = self.tcx.impl_or_trait_item(def_id);
|
||||
let trait_id = method_item.container().id();
|
||||
let trait_ref = ty::Binder(substs.to_trait_ref(self.tcx, trait_id));
|
||||
match self.fulfill_obligation(trait_ref) {
|
||||
traits::VtableImpl(vtable_impl) => {
|
||||
let impl_did = vtable_impl.impl_def_id;
|
||||
let mname = self.tcx.item_name(def_id);
|
||||
// Create a concatenated set of substitutions which includes those from the impl
|
||||
// and those from the method:
|
||||
let impl_substs = vtable_impl.substs.with_method_from(substs);
|
||||
let substs = self.tcx.mk_substs(impl_substs);
|
||||
let mth = get_impl_method(self.tcx, impl_did, substs, mname);
|
||||
|
||||
(mth.method.def_id, mth.substs)
|
||||
}
|
||||
|
||||
traits::VtableClosure(vtable_closure) =>
|
||||
(vtable_closure.closure_def_id, vtable_closure.substs.func_substs),
|
||||
|
||||
traits::VtableFnPointer(_fn_ty) => {
|
||||
let _trait_closure_kind = self.tcx.lang_items.fn_trait_kind(trait_id).unwrap();
|
||||
unimplemented!()
|
||||
// let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty);
|
||||
|
||||
// let method_ty = def_ty(tcx, def_id, substs);
|
||||
// let fn_ptr_ty = match method_ty.sty {
|
||||
// ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
|
||||
// _ => unreachable!("expected fn item type, found {}",
|
||||
// method_ty)
|
||||
// };
|
||||
// Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
|
||||
}
|
||||
|
||||
traits::VtableObject(ref _data) => {
|
||||
unimplemented!()
|
||||
// Callee {
|
||||
// data: Virtual(traits::get_vtable_index_of_object_method(
|
||||
// tcx, data, def_id)),
|
||||
// ty: def_ty(tcx, def_id, substs)
|
||||
// }
|
||||
}
|
||||
vtable => unreachable!("resolved vtable bad vtable {:?} in trans", vtable),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
||||
|
@ -193,18 +327,16 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn alloc_ret_ptr(&mut self, ty: ty::FnOutput<'tcx>) -> Option<Pointer> {
|
||||
match ty {
|
||||
ty::FnConverging(ty) => {
|
||||
let size = self.type_size(ty);
|
||||
Some(self.memory.allocate(size))
|
||||
}
|
||||
ty::FnDiverging => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_report<T>(&self, span: codemap::Span, r: EvalResult<T>) -> EvalResult<T> {
|
||||
if let Err(ref e) = r {
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn report(&self, e: &EvalError) {
|
||||
let stmt = self.frame().stmt;
|
||||
let block = self.basic_block();
|
||||
let span = if stmt < block.statements.len() {
|
||||
block.statements[stmt].span
|
||||
} else {
|
||||
block.terminator().span
|
||||
};
|
||||
let mut err = self.tcx.sess.struct_span_err(span, &e.to_string());
|
||||
for &Frame{ def_id, substs, span, .. } in self.stack.iter().rev() {
|
||||
// FIXME(solson): Find a way to do this without this Display impl hack.
|
||||
|
@ -221,6 +353,11 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fn maybe_report<T>(&self, r: EvalResult<T>) -> EvalResult<T> {
|
||||
if let Err(ref e) = r {
|
||||
self.report(e);
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -1317,79 +1454,6 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
self.tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
|
||||
let mut selcx = traits::SelectionContext::new(&infcx);
|
||||
|
||||
let obligation = traits::Obligation::new(
|
||||
traits::ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID),
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
/// Trait method, which has to be resolved to an impl method.
|
||||
pub fn trait_method(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
substs: &'tcx Substs<'tcx>
|
||||
) -> (DefId, &'tcx Substs<'tcx>) {
|
||||
let method_item = self.tcx.impl_or_trait_item(def_id);
|
||||
let trait_id = method_item.container().id();
|
||||
let trait_ref = ty::Binder(substs.to_trait_ref(self.tcx, trait_id));
|
||||
match self.fulfill_obligation(trait_ref) {
|
||||
traits::VtableImpl(vtable_impl) => {
|
||||
let impl_did = vtable_impl.impl_def_id;
|
||||
let mname = self.tcx.item_name(def_id);
|
||||
// Create a concatenated set of substitutions which includes those from the impl
|
||||
// and those from the method:
|
||||
let impl_substs = vtable_impl.substs.with_method_from(substs);
|
||||
let substs = self.tcx.mk_substs(impl_substs);
|
||||
let mth = get_impl_method(self.tcx, impl_did, substs, mname);
|
||||
|
||||
(mth.method.def_id, mth.substs)
|
||||
}
|
||||
|
||||
traits::VtableClosure(vtable_closure) =>
|
||||
(vtable_closure.closure_def_id, vtable_closure.substs.func_substs),
|
||||
|
||||
traits::VtableFnPointer(_fn_ty) => {
|
||||
let _trait_closure_kind = self.tcx.lang_items.fn_trait_kind(trait_id).unwrap();
|
||||
unimplemented!()
|
||||
// let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty);
|
||||
|
||||
// let method_ty = def_ty(tcx, def_id, substs);
|
||||
// let fn_ptr_ty = match method_ty.sty {
|
||||
// ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
|
||||
// _ => unreachable!("expected fn item type, found {}",
|
||||
// method_ty)
|
||||
// };
|
||||
// Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
|
||||
}
|
||||
|
||||
traits::VtableObject(ref _data) => {
|
||||
unimplemented!()
|
||||
// Callee {
|
||||
// data: Virtual(traits::get_vtable_index_of_object_method(
|
||||
// tcx, data, def_id)),
|
||||
// ty: def_ty(tcx, def_id, substs)
|
||||
// }
|
||||
}
|
||||
vtable => unreachable!("resolved vtable bad vtable {:?} in trans", vtable),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pointee_type(ptr_ty: ty::Ty) -> Option<ty::Ty> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue