diff --git a/src/error.rs b/src/error.rs index 370d59e5a3a..fd692ef8b64 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,7 +2,7 @@ use std::error::Error; use std::fmt; use rustc::mir; use rustc::ty::{FnSig, Ty, layout}; -use memory::{Pointer, Function}; +use memory::Pointer; use rustc_const_math::ConstMathErr; use syntax::codemap::Span; @@ -52,9 +52,6 @@ pub enum EvalError<'tcx> { DeallocatedStaticMemory, Layout(layout::LayoutError<'tcx>), Unreachable, - ExpectedConcreteFunction(Function<'tcx>), - ExpectedDropGlue(Function<'tcx>), - ManuallyCalledDropGlue, Panic, } @@ -128,12 +125,6 @@ impl<'tcx> Error for EvalError<'tcx> { "attempted to get length of a null terminated string, but no null found before end of allocation", EvalError::Unreachable => "entered unreachable code", - EvalError::ExpectedConcreteFunction(_) => - "tried to use glue function as function", - EvalError::ExpectedDropGlue(_) => - "tried to use non-drop-glue function as drop glue", - EvalError::ManuallyCalledDropGlue => - "tried to manually invoke drop glue", EvalError::Panic => "the evaluated program panicked", } diff --git a/src/eval_context.rs b/src/eval_context.rs index 011a25774ac..9b2e5e1ceab 100644 --- a/src/eval_context.rs +++ b/src/eval_context.rs @@ -8,7 +8,7 @@ use rustc::middle::const_val::ConstVal; use rustc::mir; use rustc::traits::Reveal; use rustc::ty::layout::{self, Layout, Size}; -use rustc::ty::subst::{self, Subst, Substs}; +use rustc::ty::subst::{Subst, Substs, Kind}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Binder}; use rustc_data_structures::indexed_vec::Idx; use syntax::codemap::{self, DUMMY_SP}; @@ -52,11 +52,8 @@ pub struct Frame<'tcx> { /// The MIR for the function called on this frame. pub mir: MirRef<'tcx>, - /// The def_id of the current function. - pub def_id: DefId, - - /// type substitutions for the current function invocation. - pub substs: &'tcx Substs<'tcx>, + /// The def_id and substs of the current function + pub instance: ty::Instance<'tcx>, /// The span of the call site. pub span: codemap::Span, @@ -78,12 +75,6 @@ pub struct Frame<'tcx> { /// Before being initialized, all locals are `Value::ByVal(PrimVal::Undef)`. pub locals: Vec, - /// Temporary allocations introduced to save stackframes - /// This is pure interpreter magic and has nothing to do with how rustc does it - /// An example is calling an FnMut closure that has been converted to a FnOnce closure - /// The value's destructor will be called and the memory freed when the stackframe finishes - pub interpreter_temporaries: Vec<(Pointer, Ty<'tcx>)>, - //////////////////////////////////////////////////////////////////////////////// // Current position within the function //////////////////////////////////////////////////////////////////////////////// @@ -208,12 +199,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ty.is_sized(self.tcx, &self.tcx.empty_parameter_environment(), DUMMY_SP) } - pub fn load_mir(&self, def_id: DefId) -> EvalResult<'tcx, MirRef<'tcx>> { - trace!("load mir {:?}", def_id); - if def_id.is_local() || self.tcx.sess.cstore.is_item_mir_available(def_id) { - Ok(self.tcx.item_mir(def_id)) - } else { - Err(EvalError::NoMirFor(self.tcx.item_path_str(def_id))) + pub fn load_mir(&self, instance: ty::InstanceDef<'tcx>) -> EvalResult<'tcx, MirRef<'tcx>> { + trace!("load mir {:?}", instance); + match instance { + ty::InstanceDef::Item(def_id) => self.tcx.maybe_item_mir(def_id).ok_or_else(|| EvalError::NoMirFor(self.tcx.item_path_str(def_id))), + _ => Ok(self.tcx.instance_mir(instance)), } } @@ -272,13 +262,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { pub fn push_stack_frame( &mut self, - def_id: DefId, + instance: ty::Instance<'tcx>, span: codemap::Span, mir: MirRef<'tcx>, - substs: &'tcx Substs<'tcx>, return_lvalue: Lvalue<'tcx>, return_to_block: StackPopCleanup, - temporaries: Vec<(Pointer, Ty<'tcx>)>, ) -> EvalResult<'tcx> { ::log_settings::settings().indentation += 1; @@ -293,10 +281,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { return_to_block, return_lvalue, locals, - interpreter_temporaries: temporaries, span, - def_id, - substs, + instance, stmt: 0, }); @@ -352,13 +338,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } } } - // drop and deallocate all temporary allocations - for (ptr, ty) in frame.interpreter_temporaries { - trace!("dropping temporary allocation"); - let mut drops = Vec::new(); - self.drop(Lvalue::from_ptr(ptr), ty, &mut drops)?; - self.eval_drop_impls(drops, frame.span)?; - } + Ok(()) } @@ -665,8 +645,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } ReifyFnPointer => match self.operand_ty(operand).sty { - ty::TyFnDef(def_id, substs, sig) => { - let fn_ptr = self.memory.create_fn_ptr(def_id, substs, sig); + ty::TyFnDef(def_id, substs, _) => { + let fn_ptr = self.memory.create_fn_ptr(def_id, substs); self.write_value(Value::ByVal(PrimVal::Ptr(fn_ptr)), dest, dest_ty)?; }, ref other => bug!("reify fn pointer on {:?}", other), @@ -682,8 +662,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { ClosureFnPointer => match self.operand_ty(operand).sty { ty::TyClosure(def_id, substs) => { - let fn_ty = self.tcx.closure_type(def_id); - let fn_ptr = self.memory.create_fn_ptr_from_noncapture_closure(def_id, substs, fn_ty); + let instance = resolve_closure(self.tcx, def_id, substs, ty::ClosureKind::FnOnce); + let fn_ptr = self.memory.create_fn_alloc(instance); self.write_value(Value::ByVal(PrimVal::Ptr(fn_ptr)), dest, dest_ty)?; }, ref other => bug!("reify fn pointer on {:?}", other), @@ -845,16 +825,15 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { // function items are zero sized Value::ByRef(self.memory.allocate(0, 0)?) } else { - let (def_id, substs) = self.resolve_associated_const(def_id, substs); - let cid = GlobalId { def_id, substs, promoted: None }; + let instance = self.resolve_associated_const(def_id, substs); + let cid = GlobalId { instance, promoted: None }; self.globals.get(&cid).expect("static/const not cached").value } } Literal::Promoted { index } => { let cid = GlobalId { - def_id: self.frame().def_id, - substs: self.substs(), + instance: self.frame().instance, promoted: Some(index), }; self.globals.get(&cid).expect("promoted not cached").value @@ -891,8 +870,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { }, val => { let ty = self.stack[frame].mir.local_decls[local].ty; - let ty = self.monomorphize(ty, self.stack[frame].substs); - let substs = self.stack[frame].substs; + let ty = self.monomorphize(ty, self.stack[frame].instance.substs); + let substs = self.stack[frame].instance.substs; let ptr = self.alloc_ptr_with_substs(ty, substs)?; self.stack[frame].locals[local.index() - 1] = Value::ByRef(ptr); self.write_value_to_ptr(val, ptr, ty)?; @@ -911,7 +890,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { match global_val.value { Value::ByRef(ptr) => Lvalue::from_ptr(ptr), _ => { - let ptr = self.alloc_ptr_with_substs(global_val.ty, cid.substs)?; + let ptr = self.alloc_ptr_with_substs(global_val.ty, cid.instance.substs)?; self.memory.mark_static(ptr.alloc_id); self.write_value_to_ptr(global_val.value, ptr, global_val.ty)?; // see comment on `initialized` field @@ -1289,7 +1268,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } pub(super) fn substs(&self) -> &'tcx Substs<'tcx> { - self.frame().substs + self.frame().instance.substs } fn unsize_into_ptr( @@ -1320,7 +1299,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { (_, &ty::TyDynamic(ref data, _)) => { let trait_ref = data.principal().unwrap().with_self_ty(self.tcx, src_pointee_ty); let trait_ref = self.tcx.erase_regions(&trait_ref); - let vtable = self.get_vtable(trait_ref)?; + let vtable = self.get_vtable(src_pointee_ty, trait_ref)?; let ptr = src.read_ptr(&self.memory)?; let ptr = PrimVal::Ptr(ptr); let extra = PrimVal::Ptr(vtable); @@ -1519,7 +1498,8 @@ pub fn eval_main<'a, 'tcx: 'a>( limits: ResourceLimits, ) { let mut ecx = EvalContext::new(tcx, limits); - let mir = ecx.load_mir(def_id).expect("main function's MIR not found"); + let instance = ty::Instance::mono(tcx, def_id); + let mir = ecx.load_mir(instance.def).expect("main function's MIR not found"); if !mir.return_ty.is_nil() || mir.arg_count != 0 { let msg = "miri does not support main functions without `fn()` type signatures"; @@ -1528,13 +1508,11 @@ pub fn eval_main<'a, 'tcx: 'a>( } ecx.push_stack_frame( - def_id, + instance, DUMMY_SP, mir, - tcx.intern_substs(&[]), Lvalue::from_ptr(Pointer::zst_ptr()), StackPopCleanup::None, - Vec::new(), ).expect("could not allocate first stack frame"); loop { @@ -1564,23 +1542,12 @@ fn report(tcx: TyCtxt, ecx: &EvalContext, e: EvalError) { block.terminator().source_info.span }; let mut err = tcx.sess.struct_span_err(span, &e.to_string()); - for &Frame { def_id, substs, span, .. } in ecx.stack().iter().rev() { - if tcx.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr { + for &Frame { instance, span, .. } in ecx.stack().iter().rev() { + if tcx.def_key(instance.def_id()).disambiguated_data.data == DefPathData::ClosureExpr { err.span_note(span, "inside call to closure"); continue; } - // FIXME(solson): Find a way to do this without this Display impl hack. - use rustc::util::ppaux; - use std::fmt; - struct Instance<'tcx>(DefId, &'tcx subst::Substs<'tcx>); - impl<'tcx> ::std::panic::UnwindSafe for Instance<'tcx> {} - impl<'tcx> ::std::panic::RefUnwindSafe for Instance<'tcx> {} - impl<'tcx> fmt::Display for Instance<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ppaux::parameterized(f, self.1, self.0, &[]) - } - } - err.span_note(span, &format!("inside call to {}", Instance(def_id, substs))); + err.span_note(span, &format!("inside call to {}", instance)); } err.emit(); } @@ -1657,3 +1624,80 @@ impl<'b, 'tcx: 'b> IntoValTyPair<'tcx> for &'b mir::Operand<'tcx> { Ok((value, value_ty)) } } + + +/// FIXME: expose trans::monomorphize::resolve_closure +pub fn resolve_closure<'a, 'tcx> ( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + substs: ty::ClosureSubsts<'tcx>, + requested_kind: ty::ClosureKind, +) -> ty::Instance<'tcx> { + let actual_kind = tcx.closure_kind(def_id); + match needs_fn_once_adapter_shim(actual_kind, requested_kind) { + Ok(true) => fn_once_adapter_instance(tcx, def_id, substs), + _ => ty::Instance::new(def_id, substs.substs) + } +} + +fn fn_once_adapter_instance<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + closure_did: DefId, + substs: ty::ClosureSubsts<'tcx>, +) -> ty::Instance<'tcx> { + debug!("fn_once_adapter_shim({:?}, {:?})", + closure_did, + substs); + let fn_once = tcx.lang_items.fn_once_trait().unwrap(); + let call_once = tcx.associated_items(fn_once) + .find(|it| it.kind == ty::AssociatedKind::Method) + .unwrap().def_id; + let def = ty::InstanceDef::ClosureOnceShim { call_once }; + + let self_ty = tcx.mk_closure_from_closure_substs( + closure_did, substs); + + let sig = tcx.closure_type(closure_did).subst(tcx, substs.substs); + let sig = tcx.erase_late_bound_regions_and_normalize(&sig); + assert_eq!(sig.inputs().len(), 1); + let substs = tcx.mk_substs([ + Kind::from(self_ty), + Kind::from(sig.inputs()[0]), + ].iter().cloned()); + + debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig); + ty::Instance { def, substs } +} + +fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind, + trait_closure_kind: ty::ClosureKind) + -> Result +{ + match (actual_closure_kind, trait_closure_kind) { + (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | + (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { + // No adapter needed. + Ok(false) + } + (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { + // The closure fn `llfn` is a `fn(&self, ...)`. We want a + // `fn(&mut self, ...)`. In fact, at trans time, these are + // basically the same thing, so we can just return llfn. + Ok(false) + } + (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { + // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut + // self, ...)`. We want a `fn(self, ...)`. We can produce + // this by doing something like: + // + // fn call_once(self, ...) { call_mut(&self, ...) } + // fn call_once(mut self, ...) { call_mut(&mut self, ...) } + // + // These are both the same at trans time. + Ok(true) + } + _ => Err(()), + } +} diff --git a/src/lvalue.rs b/src/lvalue.rs index 35fe958f756..62855c04505 100644 --- a/src/lvalue.rs +++ b/src/lvalue.rs @@ -1,7 +1,5 @@ -use rustc::hir::def_id::DefId; use rustc::mir; use rustc::ty::layout::{Size, Align}; -use rustc::ty::subst::Substs; use rustc::ty::{self, Ty}; use rustc_data_structures::indexed_vec::Idx; @@ -42,15 +40,9 @@ pub enum LvalueExtra { /// Uniquely identifies a specific constant or static. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct GlobalId<'tcx> { - /// For a constant or static, the `DefId` of the item itself. - /// For a promoted global, the `DefId` of the function they belong to. - pub(super) def_id: DefId, - - /// For statics and constants this is `Substs::empty()`, so only promoteds and associated - /// constants actually have something useful here. We could special case statics and constants, - /// but that would only require more branching when working with constants, and not bring any - /// real benefits. - pub(super) substs: &'tcx Substs<'tcx>, + /// For a constant or static, the `Instance` of the item itself. + /// For a promoted global, the `Instance` of the function they belong to. + pub(super) instance: ty::Instance<'tcx>, /// The index for promoted globals within their function's `Mir`. pub(super) promoted: Option, @@ -138,8 +130,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Local(local) => Lvalue::Local { frame: self.stack.len() - 1, local, field: None }, Static(ref static_) => { - let substs = self.tcx.intern_substs(&[]); - Lvalue::Global(GlobalId { def_id: static_.def_id, substs, promoted: None }) + let instance = ty::Instance::mono(self.tcx, static_.def_id); + Lvalue::Global(GlobalId { instance, promoted: None }) } Projection(ref proj) => return self.eval_lvalue_projection(proj), diff --git a/src/memory.rs b/src/memory.rs index d6563c4c703..058f8b478ca 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -3,7 +3,7 @@ use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque, BTreeSet use std::{fmt, iter, ptr, mem, io}; use rustc::hir::def_id::DefId; -use rustc::ty::{self, PolyFnSig, ClosureSubsts}; +use rustc::ty; use rustc::ty::subst::Substs; use rustc::ty::layout::{self, TargetDataLayout}; @@ -102,44 +102,6 @@ impl Pointer { } } -#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] -/// Identifies a specific monomorphized function -pub struct FunctionDefinition<'tcx> { - pub def_id: DefId, - pub substs: &'tcx Substs<'tcx>, - pub sig: PolyFnSig<'tcx>, -} - -/// Either a concrete function, or a glue function -#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] -pub enum Function<'tcx> { - /// A function or method created by compiling code - Concrete(FunctionDefinition<'tcx>), - /// Glue required to call a regular function through a Fn(Mut|Once) trait object - FnDefAsTraitObject(FunctionDefinition<'tcx>), - /// A drop glue function only needs to know the real type, and then miri can extract - /// that type from a vtable's drop pointer. - /// Instead of storing some drop function, we act as if there are no trait objects, by - /// mapping trait objects to their real types before acting on them. - DropGlue(ty::Ty<'tcx>), - /// Glue required to treat the ptr part of a fat pointer - /// as a function pointer - FnPtrAsTraitObject(PolyFnSig<'tcx>), - /// Glue for Closures - Closure(FunctionDefinition<'tcx>), - /// Glue for noncapturing closures casted to function pointers - NonCaptureClosureAsFnPtr(FunctionDefinition<'tcx>), -} - -impl<'tcx> Function<'tcx> { - pub fn expect_drop_glue_real_ty(self) -> EvalResult<'tcx, ty::Ty<'tcx>> { - match self { - Function::DropGlue(real_ty) => Ok(real_ty), - other => Err(EvalError::ExpectedDropGlue(other)), - } - } -} - //////////////////////////////////////////////////////////////////////////////// // Top-level interpreter memory //////////////////////////////////////////////////////////////////////////////// @@ -165,10 +127,10 @@ pub struct Memory<'a, 'tcx> { /// Function "allocations". They exist solely so pointers have something to point to, and /// we can figure out what they point to. - functions: HashMap>, + functions: HashMap>, /// Inverse map of `functions` so we don't allocate a new pointer every time we need one - function_alloc_cache: HashMap, AllocId>, + function_alloc_cache: HashMap, AllocId>, /// Target machine data layout to emulate. pub layout: &'a TargetDataLayout, @@ -214,55 +176,20 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { self.alloc_map.iter() } - pub fn create_closure_ptr(&mut self, def_id: DefId, substs: ClosureSubsts<'tcx>, sig: PolyFnSig<'tcx>) -> Pointer { - self.create_fn_alloc(Function::Closure(FunctionDefinition { - def_id, - substs: substs.substs, - sig, - })) + pub fn create_fn_ptr(&mut self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Pointer { + let instance = ty::Instance::new(def_id, substs); + self.create_fn_alloc(instance) } - pub fn create_fn_ptr_from_noncapture_closure(&mut self, def_id: DefId, substs: ClosureSubsts<'tcx>, sig: PolyFnSig<'tcx>) -> Pointer { - self.create_fn_alloc(Function::NonCaptureClosureAsFnPtr(FunctionDefinition { - def_id, - substs: substs.substs, - sig, - })) - } - - pub fn create_fn_as_trait_glue(&mut self, def_id: DefId, substs: &'tcx Substs, sig: PolyFnSig<'tcx>) -> Pointer { - self.create_fn_alloc(Function::FnDefAsTraitObject(FunctionDefinition { - def_id, - substs, - sig, - })) - } - - pub fn create_fn_ptr_as_trait_glue(&mut self, sig: PolyFnSig<'tcx>) -> Pointer { - self.create_fn_alloc(Function::FnPtrAsTraitObject(sig)) - } - - pub fn create_drop_glue(&mut self, ty: ty::Ty<'tcx>) -> Pointer { - self.create_fn_alloc(Function::DropGlue(ty)) - } - - pub fn create_fn_ptr(&mut self, def_id: DefId, substs: &'tcx Substs, sig: PolyFnSig<'tcx>) -> Pointer { - self.create_fn_alloc(Function::Concrete(FunctionDefinition { - def_id, - substs, - sig, - })) - } - - fn create_fn_alloc(&mut self, def: Function<'tcx>) -> Pointer { - if let Some(&alloc_id) = self.function_alloc_cache.get(&def) { + pub fn create_fn_alloc(&mut self, instance: ty::Instance<'tcx>) -> Pointer { + if let Some(&alloc_id) = self.function_alloc_cache.get(&instance) { return Pointer::new(alloc_id, 0); } let id = self.next_id; debug!("creating fn ptr: {}", id); self.next_id.0 += 1; - self.functions.insert(id, def); - self.function_alloc_cache.insert(def, id); + self.functions.insert(id, instance); + self.function_alloc_cache.insert(instance, id); Pointer::new(id, 0) } @@ -469,7 +396,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { } } - pub fn get_fn(&self, id: AllocId) -> EvalResult<'tcx, Function<'tcx>> { + pub fn get_fn(&self, id: AllocId) -> EvalResult<'tcx, ty::Instance<'tcx>> { debug!("reading fn ptr: {}", id); match self.functions.get(&id) { Some(&fndef) => Ok(fndef), @@ -501,28 +428,8 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { let alloc = match (self.alloc_map.get(&id), self.functions.get(&id)) { (Some(a), None) => a, - (None, Some(&Function::Concrete(fn_def))) => { - trace!("{} {}", msg, dump_fn_def(fn_def)); - continue; - }, - (None, Some(&Function::DropGlue(real_ty))) => { - trace!("{} drop glue for {}", msg, real_ty); - continue; - }, - (None, Some(&Function::FnDefAsTraitObject(fn_def))) => { - trace!("{} fn as Fn glue for {}", msg, dump_fn_def(fn_def)); - continue; - }, - (None, Some(&Function::FnPtrAsTraitObject(fn_def))) => { - trace!("{} fn ptr as Fn glue (signature: {:?})", msg, fn_def); - continue; - }, - (None, Some(&Function::Closure(fn_def))) => { - trace!("{} closure glue for {}", msg, dump_fn_def(fn_def)); - continue; - }, - (None, Some(&Function::NonCaptureClosureAsFnPtr(fn_def))) => { - trace!("{} non-capture closure as fn ptr glue for {}", msg, dump_fn_def(fn_def)); + (None, Some(instance)) => { + trace!("{} {}", msg, instance); continue; }, (None, None) => { @@ -594,11 +501,6 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { } } -fn dump_fn_def<'tcx>(fn_def: FunctionDefinition<'tcx>) -> String { - let name = ty::tls::with(|tcx| tcx.item_path_str(fn_def.def_id)); - format!("function pointer: {}: {}", name, fn_def.sig.skip_binder()) -} - /// Byte accessors impl<'a, 'tcx> Memory<'a, 'tcx> { fn get_bytes_unchecked(&self, ptr: Pointer, size: u64, align: u64) -> EvalResult<'tcx, &[u8]> { diff --git a/src/step.rs b/src/step.rs index 23f0142a7f5..8a0cbc4a8f1 100644 --- a/src/step.rs +++ b/src/step.rs @@ -45,8 +45,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let mut new = Ok(0); ConstantExtractor { span: stmt.source_info.span, - substs: self.substs(), - def_id: self.frame().def_id, + instance: self.frame().instance, ecx: self, mir: Ref::clone(&mir), new_constants: &mut new, @@ -63,8 +62,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let mut new = Ok(0); ConstantExtractor { span: terminator.source_info.span, - substs: self.substs(), - def_id: self.frame().def_id, + instance: self.frame().instance, ecx: self, mir: Ref::clone(&mir), new_constants: &mut new, @@ -145,8 +143,7 @@ struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b> { span: Span, ecx: &'a mut EvalContext<'b, 'tcx>, mir: MirRef<'tcx>, - def_id: DefId, - substs: &'tcx subst::Substs<'tcx>, + instance: ty::Instance<'tcx>, new_constants: &'a mut EvalResult<'tcx, u64>, } @@ -158,26 +155,24 @@ impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> { span: Span, shared: bool, ) { - let (def_id, substs) = self.ecx.resolve_associated_const(def_id, substs); - let cid = GlobalId { def_id, substs, promoted: None }; + let instance = self.ecx.resolve_associated_const(def_id, substs); + let cid = GlobalId { instance, promoted: None }; if self.ecx.globals.contains_key(&cid) { return; } self.try(|this| { - let mir = this.ecx.load_mir(def_id)?; + let mir = this.ecx.load_mir(instance.def)?; this.ecx.globals.insert(cid, Global::uninitialized(mir.return_ty)); let mutable = !shared || mir.return_ty.type_contents(this.ecx.tcx).interior_unsafe(); let cleanup = StackPopCleanup::MarkStatic(mutable); let name = ty::tls::with(|tcx| tcx.item_path_str(def_id)); trace!("pushing stack frame for global: {}", name); this.ecx.push_stack_frame( - def_id, + instance, span, mir, - substs, Lvalue::Global(cid), cleanup, - Vec::new(), ) }); } @@ -210,8 +205,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> { }, mir::Literal::Promoted { index } => { let cid = GlobalId { - def_id: self.def_id, - substs: self.substs, + instance: self.instance, promoted: Some(index), }; if self.ecx.globals.contains_key(&cid) { @@ -220,16 +214,14 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> { let mir = Ref::clone(&self.mir); let mir = Ref::map(mir, |mir| &mir.promoted[index]); self.try(|this| { - let ty = this.ecx.monomorphize(mir.return_ty, this.substs); + let ty = this.ecx.monomorphize(mir.return_ty, this.instance.substs); this.ecx.globals.insert(cid, Global::uninitialized(ty)); trace!("pushing stack frame for {:?}", index); - this.ecx.push_stack_frame(this.def_id, + this.ecx.push_stack_frame(this.instance, constant.span, mir, - this.substs, Lvalue::Global(cid), - StackPopCleanup::MarkStatic(false), - Vec::new()) + StackPopCleanup::MarkStatic(false)) }); } } diff --git a/src/terminator/drop.rs b/src/terminator/drop.rs deleted file mode 100644 index efa41567932..00000000000 --- a/src/terminator/drop.rs +++ /dev/null @@ -1,224 +0,0 @@ -use rustc::hir::def_id::DefId; -use rustc::traits; -use rustc::ty::layout::Layout; -use rustc::ty::subst::{Substs, Kind}; -use rustc::ty::{self, Ty}; -use rustc::mir; -use syntax::codemap::Span; - -use error::{EvalError, EvalResult}; -use eval_context::{EvalContext, monomorphize_field_ty, StackPopCleanup}; -use lvalue::{Lvalue, LvalueExtra}; -use memory::Pointer; -use value::PrimVal; -use value::Value; - -impl<'a, 'tcx> EvalContext<'a, 'tcx> { - /// Creates stack frames for all drop impls. See `drop` for the actual content. - pub fn eval_drop_impls(&mut self, drops: Vec<(DefId, Value, &'tcx Substs<'tcx>)>, span: Span) -> EvalResult<'tcx> { - // add them to the stack in reverse order, because the impl that needs to run the last - // is the one that needs to be at the bottom of the stack - for (drop_def_id, self_arg, substs) in drops.into_iter().rev() { - let mir = self.load_mir(drop_def_id)?; - trace!("substs for drop glue: {:?}", substs); - self.push_stack_frame( - drop_def_id, - span, - mir, - substs, - Lvalue::from_ptr(Pointer::zst_ptr()), - StackPopCleanup::None, - Vec::new(), - )?; - let mut arg_locals = self.frame().mir.args_iter(); - let first = arg_locals.next().expect("drop impl has self arg"); - assert!(arg_locals.next().is_none(), "drop impl should have only one arg"); - let dest = self.eval_lvalue(&mir::Lvalue::Local(first))?; - let ty = self.frame().mir.local_decls[first].ty; - self.write_value(self_arg, dest, ty)?; - } - Ok(()) - } - - /// push DefIds of drop impls and their argument on the given vector - pub fn drop( - &mut self, - lval: Lvalue<'tcx>, - ty: Ty<'tcx>, - drop: &mut Vec<(DefId, Value, &'tcx Substs<'tcx>)>, - ) -> EvalResult<'tcx> { - if !self.type_needs_drop(ty) { - debug!("no need to drop {:?}", ty); - return Ok(()); - } - trace!("need to drop {:?} at {:?}", ty, lval); - - match ty.sty { - // special case `Box` to deallocate the inner allocation - ty::TyAdt(ref def, _) if def.is_box() => { - let contents_ty = ty.boxed_ty(); - let val = self.read_lvalue(lval); - // we are going through the read_value path, because that already does all the - // checks for the trait object types. We'd only be repeating ourselves here. - let val = self.follow_by_ref_value(val, ty)?; - trace!("box dealloc on {:?}", val); - match val { - Value::ByRef(_) => bug!("follow_by_ref_value can't result in ByRef"), - Value::ByVal(ptr) => { - assert!(self.type_is_sized(contents_ty)); - let contents_ptr = ptr.to_ptr()?; - self.drop(Lvalue::from_ptr(contents_ptr), contents_ty, drop)?; - }, - Value::ByValPair(prim_ptr, extra) => { - let ptr = prim_ptr.to_ptr()?; - let extra = match self.tcx.struct_tail(contents_ty).sty { - ty::TyDynamic(..) => LvalueExtra::Vtable(extra.to_ptr()?), - ty::TyStr | ty::TySlice(_) => LvalueExtra::Length(extra.to_u64()?), - _ => bug!("invalid fat pointer type: {}", ty), - }; - self.drop(Lvalue::Ptr { ptr, extra }, contents_ty, drop)?; - }, - } - // We cannot use Box's destructor, because it is a no-op and only exists to reduce - // the number of hacks required in the compiler around the Box type. - let box_free_fn = self.tcx.lang_items.box_free_fn().expect("no box_free lang item"); - let substs = self.tcx.intern_substs(&[Kind::from(contents_ty)]); - // this is somewhat hacky, but hey, there's no representation difference between - // pointers, `Box`es and references, so - // #[lang = "box_free"] unsafe fn box_free(ptr: *mut T) - // is the same as - // fn drop(&mut self) if Self is Box - drop.push((box_free_fn, val, substs)); - } - - ty::TyAdt(adt_def, substs) => { - // FIXME: some structs are represented as ByValPair - let mut lval = self.force_allocation(lval)?; - let (adt_ptr, extra) = lval.to_ptr_and_extra(); - - // run drop impl before the fields' drop impls - if let Some(destructor) = adt_def.destructor(self.tcx) { - let trait_ref = ty::Binder(ty::TraitRef { - def_id: self.tcx.lang_items.drop_trait().unwrap(), - substs: self.tcx.mk_substs_trait(ty, &[]), - }); - let vtable = match self.fulfill_obligation(trait_ref) { - traits::VtableImpl(data) => data, - _ => bug!("dtor for {:?} is not an impl???", ty) - }; - let val = match extra { - LvalueExtra::None => Value::ByVal(PrimVal::Ptr(adt_ptr)), - LvalueExtra::DowncastVariant(_) => bug!("downcast variant in drop"), - LvalueExtra::Length(n) => Value::ByValPair(PrimVal::Ptr(adt_ptr), PrimVal::from_u128(n as u128)), - LvalueExtra::Vtable(vtable) => Value::ByValPair(PrimVal::Ptr(adt_ptr), PrimVal::Ptr(vtable)), - }; - drop.push((destructor.did, val, vtable.substs)); - } - - let layout = self.type_layout(ty)?; - let fields = match *layout { - Layout::Univariant { .. } => &adt_def.struct_variant().fields, - Layout::General { .. } => { - let discr_val = self.read_discriminant_value(adt_ptr, ty)? as u128; - let ptr = self.force_allocation(lval)?.to_ptr(); - match adt_def.discriminants(self.tcx).position(|v| discr_val == v.to_u128_unchecked()) { - Some(i) => { - lval = Lvalue::Ptr { - ptr, - extra: LvalueExtra::DowncastVariant(i), - }; - &adt_def.variants[i].fields - }, - None => return Err(EvalError::InvalidDiscriminant), - } - }, - Layout::StructWrappedNullablePointer { .. } | - Layout::RawNullablePointer { .. } => { - let discr = self.read_discriminant_value(adt_ptr, ty)?; - assert_eq!(discr as usize as u128, discr); - &adt_def.variants[discr as usize].fields - }, - Layout::CEnum { .. } => return Ok(()), - _ => bug!("{:?} is not an adt layout", layout), - }; - let tcx = self.tcx; - self.drop_fields( - fields.iter().map(|field| monomorphize_field_ty(tcx, field, substs)), - lval, - ty, - drop, - )?; - } - - ty::TyTuple(fields, _) => - self.drop_fields(fields.into_iter().cloned(), lval, ty, drop)?, - - ty::TyDynamic(..) => { - let (ptr, vtable) = match lval { - Lvalue::Ptr { ptr, extra: LvalueExtra::Vtable(vtable) } => (ptr, vtable), - _ => bug!("expected an lvalue with a vtable"), - }; - if let Some(real_ty) = self.read_drop_type_from_vtable(vtable)? { - self.drop(Lvalue::from_ptr(ptr), real_ty, drop)?; - } - } - - ty::TySlice(elem_ty) => { - let (ptr, len) = match lval { - Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len) } => (ptr, len), - _ => bug!("expected an lvalue with a length"), - }; - let size = self.type_size(elem_ty)?.expect("slice element must be sized"); - // FIXME: this creates a lot of stack frames if the element type has - // a drop impl - for i in 0..len { - self.drop(Lvalue::from_ptr(ptr.offset(i * size)), elem_ty, drop)?; - } - } - - ty::TyArray(elem_ty, len) => { - let lval = self.force_allocation(lval)?; - let (ptr, extra) = match lval { - Lvalue::Ptr { ptr, extra } => (ptr, extra), - _ => bug!("expected an lvalue with optional extra data"), - }; - let size = self.type_size(elem_ty)?.expect("array element cannot be unsized"); - // FIXME: this creates a lot of stack frames if the element type has - // a drop impl - for i in 0..(len as u64) { - self.drop(Lvalue::Ptr { ptr: ptr.offset(i * size), extra }, elem_ty, drop)?; - } - } - - ty::TyClosure(def_id, substs) => { - let fields = substs.upvar_tys(def_id, self.tcx); - self.drop_fields(fields, lval, ty, drop)?; - } - - _ => bug!(), - } - - Ok(()) - } - - fn drop_fields( - &mut self, - fields: I, - lval: Lvalue<'tcx>, - ty: Ty<'tcx>, - drop: &mut Vec<(DefId, Value, &'tcx Substs<'tcx>)>, - ) -> EvalResult<'tcx> - where I: Iterator>, - { - trace!("drop_fields: {:?} of type {}", lval, ty); - for (i, field_ty) in fields.enumerate() { - let field_lval = self.lvalue_field(lval, i, ty, field_ty)?; - self.drop(field_lval, field_ty, drop)?; - } - Ok(()) - } - - fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { - self.tcx.type_needs_drop_given_env(ty, &self.tcx.empty_parameter_environment()) - } -} diff --git a/src/terminator/intrinsic.rs b/src/terminator/intrinsic.rs index a2e1202ab5d..a84b87f49a7 100644 --- a/src/terminator/intrinsic.rs +++ b/src/terminator/intrinsic.rs @@ -1,4 +1,3 @@ -use rustc::hir::def_id::DefId; use rustc::mir; use rustc::ty::layout::{Layout, Size, Align}; use rustc::ty::subst::Substs; @@ -13,8 +12,7 @@ use value::{PrimVal, PrimValKind, Value}; impl<'a, 'tcx> EvalContext<'a, 'tcx> { pub(super) fn call_intrinsic( &mut self, - def_id: DefId, - substs: &'tcx Substs<'tcx>, + instance: ty::Instance<'tcx>, args: &[mir::Operand<'tcx>], dest: Lvalue<'tcx>, dest_ty: Ty<'tcx>, @@ -31,7 +29,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let f32 = self.tcx.types.f32; let f64 = self.tcx.types.f64; - let intrinsic_name = &self.tcx.item_name(def_id).as_str()[..]; + let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "add_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Add, &args[0], &args[1], dest, dest_ty)?, @@ -60,7 +58,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "atomic_load_relaxed" | "atomic_load_acq" | "volatile_load" => { - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let ptr = arg_vals[0].read_ptr(&self.memory)?; self.write_value(Value::ByRef(ptr), dest, ty)?; } @@ -69,7 +67,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "atomic_store_relaxed" | "atomic_store_rel" | "volatile_store" => { - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let dest = arg_vals[0].read_ptr(&self.memory)?; self.write_value_to_ptr(arg_vals[1], dest, ty)?; } @@ -79,7 +77,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } _ if intrinsic_name.starts_with("atomic_xchg") => { - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let ptr = arg_vals[0].read_ptr(&self.memory)?; let change = self.value_to_primval(arg_vals[1], ty)?; let old = self.read_value(ptr, ty)?; @@ -93,7 +91,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } _ if intrinsic_name.starts_with("atomic_cxchg") => { - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let ptr = arg_vals[0].read_ptr(&self.memory)?; let expect_old = self.value_to_primval(arg_vals[1], ty)?; let change = self.value_to_primval(arg_vals[2], ty)?; @@ -115,7 +113,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "atomic_and" | "atomic_and_acq" | "atomic_and_rel" | "atomic_and_acqrel" | "atomic_and_relaxed" | "atomic_xadd" | "atomic_xadd_acq" | "atomic_xadd_rel" | "atomic_xadd_acqrel" | "atomic_xadd_relaxed" | "atomic_xsub" | "atomic_xsub_acq" | "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let ptr = arg_vals[0].read_ptr(&self.memory)?; let change = self.value_to_primval(arg_vals[1], ty)?; let old = self.read_value(ptr, ty)?; @@ -144,7 +142,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "copy" | "copy_nonoverlapping" => { // FIXME: check whether overlapping occurs - let elem_ty = substs.type_at(0); + let elem_ty = instance.substs.type_at(0); let elem_size = self.type_size(elem_ty)?.expect("cannot copy unsized value"); let elem_align = self.type_align(elem_ty)?; let src = arg_vals[0].read_ptr(&self.memory)?; @@ -157,7 +155,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "cttz" | "ctlz" | "bswap" => { - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let num = self.value_to_primval(arg_vals[0], ty)?; let kind = self.ty_to_primval_kind(ty)?; let num = numeric_intrinsic(intrinsic_name, num, kind)?; @@ -165,41 +163,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } "discriminant_value" => { - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let adt_ptr = arg_vals[0].read_ptr(&self.memory)?; let discr_val = self.read_discriminant_value(adt_ptr, ty)?; self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?; } - "drop_in_place" => { - let ty = substs.type_at(0); - trace!("drop in place on {}", ty); - let ptr_ty = self.tcx.mk_mut_ptr(ty); - let lvalue = match self.follow_by_ref_value(arg_vals[0], ptr_ty)? { - Value::ByRef(_) => bug!("follow_by_ref_value returned ByRef"), - Value::ByVal(value) => Lvalue::from_ptr(value.to_ptr()?), - Value::ByValPair(ptr, extra) => Lvalue::Ptr { - ptr: ptr.to_ptr()?, - extra: match self.tcx.struct_tail(ty).sty { - ty::TyDynamic(..) => LvalueExtra::Vtable(extra.to_ptr()?), - ty::TyStr | ty::TySlice(_) => LvalueExtra::Length(extra.to_u64()?), - _ => bug!("invalid fat pointer type: {}", ptr_ty), - }, - }, - }; - let mut drops = Vec::new(); - self.drop(lvalue, ty, &mut drops)?; - let span = { - let frame = self.frame(); - frame.mir[frame.block].terminator().source_info.span - }; - // need to change the block before pushing the drop impl stack frames - // we could do this for all intrinsics before evaluating the intrinsics, but if - // the evaluation fails, we should not have moved forward - self.goto_block(target); - return self.eval_drop_impls(drops, span); - } - "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | @@ -247,7 +216,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let kind = self.ty_to_primval_kind(ty)?; let a = self.value_to_primval(arg_vals[0], ty)?; let b = self.value_to_primval(arg_vals[1], ty)?; @@ -279,7 +248,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Value::ByVal(PrimVal::Undef) => match this.ty_to_primval_kind(dest_ty) { Ok(_) => Value::ByVal(PrimVal::Bytes(0)), Err(_) => { - let ptr = this.alloc_ptr_with_substs(dest_ty, substs)?; + let ptr = this.alloc_ptr_with_substs(dest_ty, instance.substs)?; this.memory.write_repeat(ptr, 0, size)?; Value::ByRef(ptr) } @@ -299,14 +268,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } "min_align_of" => { - let elem_ty = substs.type_at(0); + let elem_ty = instance.substs.type_at(0); let elem_align = self.type_align(elem_ty)?; let align_val = PrimVal::from_u128(elem_align as u128); self.write_primval(dest, align_val, dest_ty)?; } "pref_align_of" => { - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let layout = self.type_layout(ty)?; let align = layout.align(&self.tcx.data_layout).pref(); let align_val = PrimVal::from_u128(align as u128); @@ -314,20 +283,20 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } "move_val_init" => { - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let ptr = arg_vals[0].read_ptr(&self.memory)?; self.write_value_to_ptr(arg_vals[1], ptr, ty)?; } "needs_drop" => { - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let env = self.tcx.empty_parameter_environment(); let needs_drop = self.tcx.type_needs_drop_given_env(ty, &env); self.write_primval(dest, PrimVal::from_bool(needs_drop), dest_ty)?; } "offset" => { - let pointee_ty = substs.type_at(0); + let pointee_ty = instance.substs.type_at(0); // FIXME: assuming here that type size is < i64::max_value() let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64; let offset = self.value_to_primval(arg_vals[1], isize)?.to_i128()? as i64; @@ -388,7 +357,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } "size_of" => { - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); // FIXME: change the `box_free` lang item to take `T: ?Sized` and have it use the // `size_of_val` intrinsic, then change this back to // .expect("size_of intrinsic called on unsized value") @@ -398,32 +367,32 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } "size_of_val" => { - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let (size, _) = self.size_and_align_of_dst(ty, arg_vals[0])?; self.write_primval(dest, PrimVal::from_u128(size as u128), dest_ty)?; } "min_align_of_val" | "align_of_val" => { - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let (_, align) = self.size_and_align_of_dst(ty, arg_vals[0])?; self.write_primval(dest, PrimVal::from_u128(align as u128), dest_ty)?; } "type_name" => { - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let ty_name = ty.to_string(); let s = self.str_to_value(&ty_name)?; self.write_value(s, dest, dest_ty)?; } "type_id" => { - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let n = self.tcx.type_id_hash(ty); self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?; } "transmute" => { - let dest_ty = substs.type_at(1); + let dest_ty = instance.substs.type_at(1); self.write_value(arg_vals[0], dest, dest_ty)?; } @@ -449,7 +418,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "write_bytes" => { let u8 = self.tcx.types.u8; - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let ty_align = self.type_align(ty)?; let val_byte = self.value_to_primval(arg_vals[1], u8)?.to_u128()? as u8; let size = self.type_size(ty)?.expect("write_bytes() type must be sized"); diff --git a/src/terminator/mod.rs b/src/terminator/mod.rs index 659f8e31520..8e0623dcba1 100644 --- a/src/terminator/mod.rs +++ b/src/terminator/mod.rs @@ -1,9 +1,6 @@ use rustc::hir::def_id::DefId; use rustc::mir; -use rustc::ty::layout::Layout; -use rustc::ty::subst::Substs; use rustc::ty::{self, Ty}; -use rustc_const_math::ConstInt; use syntax::codemap::Span; use syntax::attr; use syntax::abi::Abi; @@ -11,12 +8,11 @@ use syntax::abi::Abi; use error::{EvalError, EvalResult}; use eval_context::{EvalContext, IntegerExt, StackPopCleanup, is_inhabited}; use lvalue::Lvalue; -use memory::{Pointer, FunctionDefinition, Function}; +use memory::Pointer; use value::PrimVal; use value::Value; mod intrinsic; -mod drop; impl<'a, 'tcx> EvalContext<'a, 'tcx> { pub(super) fn goto_block(&mut self, target: mir::BasicBlock) { @@ -64,46 +60,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let func_ty = self.operand_ty(func); let fn_def = match func_ty.sty { - ty::TyFnPtr(bare_sig) => { - let bare_sig = self.erase_lifetimes(&bare_sig); + ty::TyFnPtr(_) => { let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr()?; - let fn_def = self.memory.get_fn(fn_ptr.alloc_id)?; - match fn_def { - Function::Concrete(fn_def) => { - // transmuting function pointers in miri is fine as long as the number of - // arguments and the abi don't change. - let sig = self.erase_lifetimes(&fn_def.sig); - if sig.abi != bare_sig.abi || - sig.variadic != bare_sig.variadic || - sig.inputs_and_output != bare_sig.inputs_and_output { - return Err(EvalError::FunctionPointerTyMismatch(sig, bare_sig)); - } - }, - Function::NonCaptureClosureAsFnPtr(fn_def) => { - let sig = self.erase_lifetimes(&fn_def.sig); - assert_eq!(sig.abi, Abi::RustCall); - if sig.variadic != bare_sig.variadic || - sig.inputs().len() != 1 { - return Err(EvalError::FunctionPointerTyMismatch(sig, bare_sig)); - } - if let ty::TyTuple(fields, _) = sig.inputs()[0].sty { - if **fields != *bare_sig.inputs() { - return Err(EvalError::FunctionPointerTyMismatch(sig, bare_sig)); - } - } else { - return Err(EvalError::FunctionPointerTyMismatch(sig, bare_sig)); - } - }, - other => return Err(EvalError::ExpectedConcreteFunction(other)), - } self.memory.get_fn(fn_ptr.alloc_id)? }, - ty::TyFnDef(def_id, substs, fn_ty) => Function::Concrete(FunctionDefinition { - def_id, - substs, - sig: fn_ty, - }), - + ty::TyFnDef(def_id, substs, _) => ty::Instance::new(def_id, substs), _ => { let msg = format!("can't handle callee of type {:?}", func_ty); return Err(EvalError::Unimplemented(msg)); @@ -112,19 +73,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.eval_fn_call(fn_def, destination, args, terminator.source_info.span)?; } - Drop { ref location, target, .. } => { - let lval = self.eval_lvalue(location)?; - - let ty = self.lvalue_ty(location); - - // we can't generate the drop stack frames on the fly, - // because that would change our call stack - // and very much confuse the further processing of the drop glue - let mut drops = Vec::new(); - self.drop(lval, ty, &mut drops)?; - self.goto_block(target); - self.eval_drop_impls(drops, terminator.source_info.span)?; - } + Drop { .. } => unreachable!(), Assert { ref cond, expected, ref msg, target, .. } => { let cond_val = self.eval_operand_to_primval(cond)?.to_bool()?; @@ -158,15 +107,18 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { fn eval_fn_call( &mut self, - fn_def: Function<'tcx>, + instance: ty::Instance<'tcx>, destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>, arg_operands: &[mir::Operand<'tcx>], span: Span, ) -> EvalResult<'tcx> { - use syntax::abi::Abi; - match fn_def { - // Intrinsics can only be addressed directly - Function::Concrete(FunctionDefinition { def_id, substs, sig }) if sig.abi() == Abi::RustIntrinsic => { + let sig = match instance.def.def_ty(self.tcx).sty { + ty::TyFnPtr(bare_sig) => bare_sig, + ty::TyFnDef(_, _, fn_ty) => fn_ty, + ref other => bug!("expected function or pointer, got {:?}", other), + }; + match sig.abi() { + Abi::RustIntrinsic => { let sig = self.erase_lifetimes(&sig); let ty = sig.output(); let layout = self.type_layout(ty)?; @@ -174,139 +126,51 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Some(dest) if is_inhabited(self.tcx, ty) => dest, _ => return Err(EvalError::Unreachable), }; - self.call_intrinsic(def_id, substs, arg_operands, ret, ty, layout, target)?; + self.call_intrinsic(instance, arg_operands, ret, ty, layout, target)?; self.dump_local(ret); Ok(()) }, - // C functions can only be addressed directly - Function::Concrete(FunctionDefinition { def_id, sig, ..}) if sig.abi() == Abi::C => { + Abi::C => { let sig = self.erase_lifetimes(&sig); let ty = sig.output(); let (ret, target) = destination.unwrap(); - self.call_c_abi(def_id, arg_operands, ret, ty)?; + match instance.def { + ty::InstanceDef::Item(_) => {}, + _ => bug!("C abi function must be InstanceDef::Item"), + } + self.call_c_abi(instance.def_id(), arg_operands, ret, ty)?; self.dump_local(ret); self.goto_block(target); Ok(()) }, - Function::DropGlue(_) => Err(EvalError::ManuallyCalledDropGlue), - Function::Concrete(FunctionDefinition { def_id, sig, substs }) if sig.abi() == Abi::Rust || sig.abi() == Abi::RustCall => { + Abi::Rust | Abi::RustCall => { let mut args = Vec::new(); for arg in arg_operands { let arg_val = self.eval_operand(arg)?; let arg_ty = self.operand_ty(arg); args.push((arg_val, arg_ty)); } - - // Only trait methods can have a Self parameter. - let (resolved_def_id, resolved_substs, temporaries) = - if let Some(trait_id) = self.tcx.trait_of_item(def_id) { - self.trait_method(trait_id, def_id, substs, &mut args)? - } else { - (def_id, substs, Vec::new()) - }; - - // FIXME(eddyb) Detect ADT constructors more efficiently. - if let Some(adt_def) = sig.output().skip_binder().ty_adt_def() { - let dids = adt_def.variants.iter().map(|v| v.did); - let discrs = adt_def.discriminants(self.tcx).map(ConstInt::to_u128_unchecked); - if let Some((_, disr_val)) = dids.zip(discrs).find(|&(did, _)| resolved_def_id == did) { - let (lvalue, target) = destination.expect("tuple struct constructors can't diverge"); - let dest_ty = self.tcx.item_type(adt_def.did); - let dest_layout = self.type_layout(dest_ty)?; - trace!("layout({:?}) = {:#?}", dest_ty, dest_layout); - match *dest_layout { - Layout::Univariant { .. } => { - assert_eq!(disr_val, 0); - self.assign_fields(lvalue, dest_ty, args)?; - }, - Layout::General { discr, ref variants, .. } => { - let discr_size = discr.size().bytes(); - self.assign_discr_and_fields( - lvalue, - dest_ty, - variants[disr_val as usize].offsets[0].bytes(), - args, - disr_val, - disr_val as usize, - discr_size, - )?; - }, - Layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { - if nndiscr as u128 == disr_val { - self.assign_fields(lvalue, dest_ty, args)?; - } else { - for (_, ty) in args { - assert_eq!(self.type_size(ty)?, Some(0)); - } - let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?; - - // FIXME(solson) - let dest = self.force_allocation(lvalue)?.to_ptr(); - - let dest = dest.offset(offset.bytes()); - let dest_size = self.type_size(ty)? - .expect("bad StructWrappedNullablePointer discrfield"); - self.memory.write_int(dest, 0, dest_size)?; - } - }, - Layout::RawNullablePointer { .. } => { - assert_eq!(args.len(), 1); - let (val, ty) = args.pop().unwrap(); - self.write_value(val, lvalue, ty)?; - }, - _ => bug!("bad layout for tuple struct constructor: {:?}", dest_layout), - } - self.goto_block(target); - return Ok(()); - } - } self.eval_fn_call_inner( - resolved_def_id, - resolved_substs, + instance, destination, args, - temporaries, span, ) }, - Function::NonCaptureClosureAsFnPtr(FunctionDefinition { def_id, substs, sig }) if sig.abi() == Abi::RustCall => { - let sig = self.erase_lifetimes(&sig); - let mut args = Vec::new(); - for arg in arg_operands { - let arg_val = self.eval_operand(arg)?; - let arg_ty = self.operand_ty(arg); - args.push((arg_val, arg_ty)); - } - args.insert(0, ( - Value::ByVal(PrimVal::Undef), - sig.inputs()[0], - )); - self.eval_fn_call_inner( - def_id, - substs, - destination, - args, - Vec::new(), - span, - ) - } - Function::Concrete(fn_def) => Err(EvalError::Unimplemented(format!("can't handle function with {:?} ABI", fn_def.sig.abi()))), - other => Err(EvalError::Unimplemented(format!("can't call function kind {:#?}", other))), + other => Err(EvalError::Unimplemented(format!("can't handle function with {:?} ABI", other))), } } fn eval_fn_call_inner( &mut self, - resolved_def_id: DefId, - resolved_substs: &'tcx Substs, + instance: ty::Instance<'tcx>, destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>, args: Vec<(Value, Ty<'tcx>)>, - temporaries: Vec<(Pointer, Ty<'tcx>)>, span: Span, ) -> EvalResult<'tcx> { - trace!("eval_fn_call_inner: {:#?}, {:#?}, {:#?}", args, temporaries, destination); + trace!("eval_fn_call_inner: {:#?}, {:#?}", args, destination); - let mir = match self.load_mir(resolved_def_id) { + let mir = match self.load_mir(instance.def) { Ok(mir) => mir, Err(EvalError::NoMirFor(path)) => { match &path[..] { @@ -344,13 +208,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { }; self.push_stack_frame( - resolved_def_id, + instance, span, mir, - resolved_substs, return_lvalue, return_to_block, - temporaries, )?; let arg_locals = self.frame().mir.args_iter(); @@ -530,33 +392,4 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { // current frame. Ok(()) } - - pub(crate) fn unpack_fn_args(&self, args: &mut Vec<(Value, Ty<'tcx>)>) -> EvalResult<'tcx> { - if let Some((last, last_ty)) = args.pop() { - let last_layout = self.type_layout(last_ty)?; - match (&last_ty.sty, last_layout) { - (&ty::TyTuple(fields, _), - &Layout::Univariant { ref variant, .. }) => { - let offsets = variant.offsets.iter().map(|s| s.bytes()); - match last { - Value::ByRef(last_ptr) => { - for (offset, ty) in offsets.zip(fields) { - let arg = Value::ByRef(last_ptr.offset(offset)); - args.push((arg, ty)); - } - }, - // propagate undefs - undef @ Value::ByVal(PrimVal::Undef) => { - for field_ty in fields { - args.push((undef, field_ty)); - } - }, - _ => bug!("rust-call ABI tuple argument was {:?}, but {:?} were expected", last, fields), - } - } - ty => bug!("expected tuple as last argument in function with 'rust-call' ABI, got {:?}", ty), - } - } - Ok(()) - } } diff --git a/src/traits.rs b/src/traits.rs index 72de17801d5..74cb6966c06 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -8,171 +8,11 @@ use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use syntax::codemap::DUMMY_SP; -use syntax::{ast, abi}; +use syntax::ast; -use error::{EvalError, EvalResult}; -use memory::Function; -use value::PrimVal; -use value::Value; +use error::EvalResult; impl<'a, 'tcx> EvalContext<'a, 'tcx> { - /// Trait method, which has to be resolved to an impl method. - pub(crate) fn trait_method( - &mut self, - trait_id: DefId, - def_id: DefId, - substs: &'tcx Substs<'tcx>, - args: &mut Vec<(Value, Ty<'tcx>)>, - ) -> EvalResult<'tcx, (DefId, &'tcx Substs<'tcx>, Vec<(Pointer, Ty<'tcx>)>)> { - let trait_ref = ty::TraitRef::from_method(self.tcx, trait_id, substs); - let trait_ref = self.tcx.normalize_associated_type(&ty::Binder(trait_ref)); - - 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 (did, substs) = find_method(self.tcx, substs, impl_did, vtable_impl.substs, mname); - - Ok((did, substs, Vec::new())) - } - - traits::VtableClosure(vtable_closure) => { - let trait_closure_kind = self.tcx - .lang_items - .fn_trait_kind(trait_id) - .expect("The substitutions should have no type parameters remaining after passing through fulfill_obligation"); - let closure_kind = self.tcx.closure_kind(vtable_closure.closure_def_id); - trace!("closures {:?}, {:?}", closure_kind, trait_closure_kind); - self.unpack_fn_args(args)?; - let mut temporaries = Vec::new(); - match (closure_kind, trait_closure_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | - (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {} // No adapter needed. - - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { - // The closure fn is a `fn(&self, ...)` or `fn(&mut self, ...)`. - // We want a `fn(self, ...)`. - // We can produce this by doing something like: - // - // fn call_once(self, ...) { call_mut(&self, ...) } - // fn call_once(mut self, ...) { call_mut(&mut self, ...) } - // - // These are both the same at trans time. - - // Interpreter magic: insert an intermediate pointer, so we can skip the - // intermediate function call. - let ptr = match args[0].0 { - Value::ByRef(ptr) => ptr, - Value::ByVal(primval) => { - let ptr = self.alloc_ptr(args[0].1)?; - let size = self.type_size(args[0].1)?.expect("closures are sized"); - self.memory.write_primval(ptr, primval, size)?; - ptr - }, - Value::ByValPair(a, b) => { - let ptr = self.alloc_ptr(args[0].1)?; - self.write_pair_to_ptr(a, b, ptr, args[0].1)?; - ptr - }, - }; - temporaries.push((ptr, args[0].1)); - args[0].0 = Value::ByVal(PrimVal::Ptr(ptr)); - args[0].1 = self.tcx.mk_mut_ptr(args[0].1); - } - - _ => bug!("cannot convert {:?} to {:?}", closure_kind, trait_closure_kind), - } - Ok((vtable_closure.closure_def_id, vtable_closure.substs.substs, temporaries)) - } - - traits::VtableFnPointer(vtable_fn_ptr) => { - if let ty::TyFnDef(did, substs, _) = vtable_fn_ptr.fn_ty.sty { - args.remove(0); - self.unpack_fn_args(args)?; - Ok((did, substs, Vec::new())) - } else { - bug!("VtableFnPointer did not contain a concrete function: {:?}", vtable_fn_ptr) - } - } - - traits::VtableObject(ref data) => { - let idx = self.tcx.get_vtable_index_of_object_method(data, def_id) as u64; - if args.is_empty() { - return Err(EvalError::VtableForArgumentlessMethod); - } - let (self_ptr, vtable) = args[0].0.expect_ptr_vtable_pair(&self.memory)?; - let idx = idx + 3; - let offset = idx * self.memory.pointer_size(); - let fn_ptr = self.memory.read_ptr(vtable.offset(offset))?; - trace!("args: {:#?}", args); - match self.memory.get_fn(fn_ptr.alloc_id)? { - Function::FnDefAsTraitObject(fn_def) => { - trace!("sig: {:#?}", fn_def.sig); - assert!(fn_def.sig.abi() != abi::Abi::RustCall); - assert_eq!(args.len(), 2); - // a function item turned into a closure trait object - // the first arg is just there to give use the vtable - args.remove(0); - self.unpack_fn_args(args)?; - Ok((fn_def.def_id, fn_def.substs, Vec::new())) - }, - Function::DropGlue(_) => Err(EvalError::ManuallyCalledDropGlue), - Function::Concrete(fn_def) => { - let sig = self.erase_lifetimes(&fn_def.sig); - trace!("sig: {:#?}", sig); - args[0] = ( - Value::ByVal(PrimVal::Ptr(self_ptr)), - sig.inputs()[0], - ); - Ok((fn_def.def_id, fn_def.substs, Vec::new())) - }, - Function::NonCaptureClosureAsFnPtr(fn_def) => { - let sig = self.erase_lifetimes(&fn_def.sig); - args.insert(0, ( - Value::ByVal(PrimVal::Undef), - sig.inputs()[0], - )); - Ok((fn_def.def_id, fn_def.substs, Vec::new())) - } - Function::Closure(fn_def) => { - self.unpack_fn_args(args)?; - Ok((fn_def.def_id, fn_def.substs, Vec::new())) - } - Function::FnPtrAsTraitObject(sig) => { - let sig = self.erase_lifetimes(&sig); - trace!("sig: {:#?}", sig); - // the first argument was the fat ptr - args.remove(0); - self.unpack_fn_args(args)?; - let fn_ptr = self.memory.read_ptr(self_ptr)?; - let fn_def = match self.memory.get_fn(fn_ptr.alloc_id)? { - Function::Concrete(fn_def) => { - let fn_def_sig = self.erase_lifetimes(&fn_def.sig); - assert_eq!(sig, fn_def_sig); - fn_def - }, - Function::NonCaptureClosureAsFnPtr(fn_def) => { - let fn_def_sig = self.erase_lifetimes(&fn_def.sig); - args.insert(0, ( - Value::ByVal(PrimVal::Undef), - fn_def_sig.inputs()[0], - )); - fn_def - }, - other => bug!("FnPtrAsTraitObject for {:?}", other), - }; - Ok((fn_def.def_id, fn_def.substs, Vec::new())) - } - } - }, - vtable => bug!("resolved vtable bad vtable {:?} in trans", vtable), - } - } 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 @@ -202,7 +42,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { /// The `trait_ref` encodes the erased self type. Hence if we are /// making an object `Foo` from a value of type `Foo`, then /// `trait_ref` would map `T:Trait`. - pub fn get_vtable(&mut self, trait_ref: ty::PolyTraitRef<'tcx>) -> EvalResult<'tcx, Pointer> { + pub fn get_vtable(&mut self, ty: Ty<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> EvalResult<'tcx, Pointer> { let tcx = self.tcx; debug!("get_vtable(trait_ref={:?})", trait_ref); @@ -219,13 +59,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.get_vtable_methods(id, substs) .into_iter() .map(|opt_mth| opt_mth.map(|mth| { - let fn_ty = self.tcx.item_type(mth.method.def_id); - let fn_ty = match fn_ty.sty { - ty::TyFnDef(_, _, fn_ty) => fn_ty, - _ => bug!("bad function type: {}", fn_ty), - }; - let fn_ty = self.tcx.erase_regions(&fn_ty); - self.memory.create_fn_ptr(mth.method.def_id, mth.substs, fn_ty) + self.memory.create_fn_ptr(mth.method.def_id, mth.substs) })) .collect::>() .into_iter() @@ -238,18 +72,22 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { .. } ) => { - let closure_type = self.tcx.closure_type(closure_def_id); - vec![Some(self.memory.create_closure_ptr(closure_def_id, substs, closure_type))].into_iter() + let instance = ::eval_context::resolve_closure(self.tcx, closure_def_id, substs, ty::ClosureKind::FnOnce); + vec![Some(self.memory.create_fn_alloc(instance))].into_iter() } // turn a function definition into a Fn trait object traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, .. }) => { match fn_ty.sty { - ty::TyFnDef(did, substs, bare_fn_ty) => { - vec![Some(self.memory.create_fn_as_trait_glue(did, substs, bare_fn_ty))].into_iter() + ty::TyFnDef(did, substs, _) => { + let instance = ty::Instance { + def: ty::InstanceDef::FnPtrShim(did, fn_ty), + substs, + }; + vec![Some(self.memory.create_fn_alloc(instance))].into_iter() }, - ty::TyFnPtr(bare_fn_ty) => { - vec![Some(self.memory.create_fn_ptr_as_trait_glue(bare_fn_ty))].into_iter() + ty::TyFnPtr(_) => { + unimplemented!(); }, _ => bug!("bad VtableFnPointer fn_ty: {:#?}", fn_ty.sty), } @@ -279,19 +117,17 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { // in case there is no drop function to be called, this still needs to be initialized self.memory.write_usize(vtable, 0)?; + let drop_in_place = self.tcx.lang_items.drop_in_place_fn().expect("drop_in_place lang item not available"); if let ty::TyAdt(adt_def, substs) = trait_ref.self_ty().sty { - if let Some(destructor) = adt_def.destructor(self.tcx) { - let fn_ty = match self.tcx.item_type(destructor.did).sty { - ty::TyFnDef(_, _, fn_ty) => self.tcx.erase_regions(&fn_ty), - _ => bug!("drop method is not a TyFnDef"), + if adt_def.has_dtor(self.tcx) { + let env = self.tcx.empty_parameter_environment(); + let def = if self.tcx.type_needs_drop_given_env(ty, &env) { + ty::InstanceDef::DropGlue(drop_in_place, Some(ty)) + } else { + ty::InstanceDef::DropGlue(drop_in_place, None) }; - let fn_ty = self.erase_lifetimes(&fn_ty); - // The real type is taken from the self argument in `fn drop(&mut self)` - let real_ty = match fn_ty.inputs()[0].sty { - ty::TyRef(_, mt) => self.monomorphize(mt.ty, substs), - _ => bug!("first argument of Drop::drop must be &mut T"), - }; - let fn_ptr = self.memory.create_drop_glue(real_ty); + let instance = ty::Instance { substs, def }; + let fn_ptr = self.memory.create_fn_alloc(instance); self.memory.write_ptr(vtable, fn_ptr)?; } } @@ -310,20 +146,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Ok(vtable) } - pub fn read_drop_type_from_vtable(&self, vtable: Pointer) -> EvalResult<'tcx, Option>> { - let drop_fn = self.memory.read_ptr(vtable)?; - - // just a sanity check - assert_eq!(drop_fn.offset, 0); - - // some values don't need to call a drop impl, so the value is null - if drop_fn == Pointer::from_int(0) { - Ok(None) - } else { - self.memory.get_fn(drop_fn.alloc_id)?.expect_drop_glue_real_ty().map(Some) - } - } - pub fn read_size_and_align_from_vtable(&self, vtable: Pointer) -> EvalResult<'tcx, (u64, u64)> { let pointer_size = self.memory.pointer_size(); let size = self.memory.read_usize(vtable.offset(pointer_size))?; @@ -423,7 +245,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { &self, def_id: DefId, substs: &'tcx Substs<'tcx>, - ) -> (DefId, &'tcx Substs<'tcx>) { + ) -> ty::Instance<'tcx> { 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); @@ -432,11 +254,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { 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 { - return (assoc_const.def_id, vtable_impl.substs); + return ty::Instance::new(assoc_const.def_id, vtable_impl.substs); } } } - (def_id, substs) + ty::Instance::new(def_id, substs) } } @@ -483,35 +305,3 @@ pub(super) fn get_impl_method<'a, 'tcx>( } } } - -/// Locates the applicable definition of a method, given its name. -pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - substs: &'tcx Substs<'tcx>, - impl_def_id: DefId, - impl_substs: &'tcx Substs<'tcx>, - name: ast::Name) - -> (DefId, &'tcx Substs<'tcx>) -{ - assert!(!substs.needs_infer()); - - let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); - let trait_def = tcx.lookup_trait_def(trait_def_id); - - match trait_def.ancestors(impl_def_id).defs(tcx, name, ty::AssociatedKind::Method).next() { - Some(node_item) => { - let substs = tcx.infer_ctxt((), Reveal::All).enter(|infcx| { - let substs = substs.rebase_onto(tcx, trait_def_id, impl_substs); - let substs = traits::translate_substs(&infcx, impl_def_id, substs, node_item.node); - tcx.lift(&substs).unwrap_or_else(|| { - bug!("find_method: translate_substs \ - returned {:?} which contains inference types/regions", - substs); - }) - }); - (node_item.item.def_id, substs) - } - None => { - bug!("method {:?} not found in {:?}", name, impl_def_id) - } - } -}