From baa010561e5c109341e9a1ebe8a613fcae095884 Mon Sep 17 00:00:00 2001 From: Douglas Campos Date: Mon, 18 Sep 2017 22:49:40 -0400 Subject: [PATCH 01/12] copy resolve() over to librustc --- src/librustc/ty/instance.rs | 191 ++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 871a23863ac21..b14715615f225 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -10,6 +10,10 @@ use hir::def_id::DefId; use ty::{self, Ty, TypeFoldable, Substs, TyCtxt}; +use ty::subst::{Kind, Subst}; +use traits; +use syntax::abi::Abi; +use syntax::codemap::DUMMY_SP; use util::ppaux; use std::fmt; @@ -111,4 +115,191 @@ impl<'a, 'b, 'tcx> Instance<'tcx> { pub fn def_id(&self) -> DefId { self.def.def_id() } + + /// The point where linking happens. Resolve a (def_id, substs) + /// pair to an instance. + pub fn resolve(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option> { + let def_id = self.def_id(); + debug!("resolve(def_id={:?}, substs={:?})", def_id, self.substs); + let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { + debug!(" => associated item, attempting to find impl"); + let item = tcx.associated_item(def_id); + resolve_associated_item(tcx, &item, trait_def_id, self.substs) + } else { + let ty = tcx.type_of(def_id); + let item_type = tcx.trans_apply_param_substs(self.substs, &ty); + + let def = match item_type.sty { + ty::TyFnDef(..) if { + let f = item_type.fn_sig(tcx); + f.abi() == Abi::RustIntrinsic || + f.abi() == Abi::PlatformIntrinsic + } => + { + debug!(" => intrinsic"); + ty::InstanceDef::Intrinsic(def_id) + } + _ => { + if Some(def_id) == tcx.lang_items().drop_in_place_fn() { + let ty = self.substs.type_at(0); + if ty.needs_drop(tcx, ty::ParamEnv::empty(traits::Reveal::All)) { + debug!(" => nontrivial drop glue"); + ty::InstanceDef::DropGlue(def_id, Some(ty)) + } else { + debug!(" => trivial drop glue"); + ty::InstanceDef::DropGlue(def_id, None) + } + } else { + debug!(" => free item"); + ty::InstanceDef::Item(def_id) + } + } + }; + Some(Instance { + def: def, + substs: self.substs + }) + }; + debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, self.substs, result); + result + } + + +} + +fn resolve_closure<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + substs: ty::ClosureSubsts<'tcx>, + requested_kind: ty::ClosureKind) +-> 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), + _ => Instance::new(def_id, substs.substs) + } +} + +fn resolve_associated_item<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + trait_item: &ty::AssociatedItem, + trait_id: DefId, + rcvr_substs: &'tcx Substs<'tcx> + ) -> Option> { + let def_id = trait_item.def_id; + debug!("resolve_associated_item(trait_item={:?}, \ + trait_id={:?}, \ + rcvr_substs={:?})", + def_id, trait_id, rcvr_substs); + + let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); + let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, ty::Binder(trait_ref)); + + // Now that we know which impl is being used, we can dispatch to + // the actual function: + match vtbl { + traits::VtableImpl(impl_data) => { + let (def_id, substs) = traits::find_associated_item( + tcx, trait_item, rcvr_substs, &impl_data); + let substs = tcx.erase_regions(&substs); + Some(ty::Instance::new(def_id, substs)) + } + traits::VtableGenerator(closure_data) => { + Some(Instance { + def: ty::InstanceDef::Item(closure_data.closure_def_id), + substs: closure_data.substs.substs + }) + } + traits::VtableClosure(closure_data) => { + let trait_closure_kind = tcx.lang_items().fn_trait_kind(trait_id).unwrap(); + Some(resolve_closure(tcx, closure_data.closure_def_id, closure_data.substs, + trait_closure_kind)) + } + traits::VtableFnPointer(ref data) => { + Some(Instance { + def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty), + substs: rcvr_substs + }) + } + traits::VtableObject(ref data) => { + let index = tcx.get_vtable_index_of_object_method(data, def_id); + Some(Instance { + def: ty::InstanceDef::Virtual(def_id, index), + substs: rcvr_substs + }) + } + traits::VtableBuiltin(..) if Some(trait_id) == tcx.lang_items().clone_trait() => { + Some(Instance { + def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()), + substs: rcvr_substs + }) + } + _ => { + None + } + } +} + +fn needs_fn_once_adapter_shim<'a, 'tcx>(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(()), + } +} + +fn fn_once_adapter_instance<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + closure_did: DefId, + substs: ty::ClosureSubsts<'tcx>, + ) -> 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.fn_sig(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); + Instance { def, substs } } From 3bd09dee45c045307f6a1cd41498e362c5992fd9 Mon Sep 17 00:00:00 2001 From: Douglas Campos Date: Mon, 18 Sep 2017 23:53:33 -0400 Subject: [PATCH 02/12] re-enable mir inlining across trait methods this fixes #44389 --- src/librustc_mir/transform/inline.rs | 31 +++++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 48a21dfdbd467..41eaf864ca47e 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -18,7 +18,7 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::mir::*; use rustc::mir::transform::{MirPass, MirSource}; use rustc::mir::visit::*; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt, Instance}; use rustc::ty::subst::{Subst,Substs}; use std::collections::VecDeque; @@ -88,13 +88,28 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { if let TerminatorKind::Call { func: Operand::Constant(ref f), .. } = terminator.kind { if let ty::TyFnDef(callee_def_id, substs) = f.ty.sty { - if self.tcx.trait_of_item(callee_def_id).is_none() { - callsites.push_back(CallSite { - callee: callee_def_id, - substs, - bb, - location: terminator.source_info - }); + match self.tcx.trait_of_item(callee_def_id) { + Some(_) => { + match Instance::new(callee_def_id, substs).resolve(self.tcx) { + Some(instance) => { + callsites.push_back(CallSite { + callee: instance.def_id(), + substs: instance.substs, + bb, + location: terminator.source_info + }); + }, + None => {} + } + } + None => { + callsites.push_back(CallSite { + callee: callee_def_id, + substs, + bb, + location: terminator.source_info + }); + } } } } From 5eb302fba812b2c4105192c88d92cbdb8db7cd6f Mon Sep 17 00:00:00 2001 From: Douglas Campos Date: Tue, 19 Sep 2017 09:14:43 -0400 Subject: [PATCH 03/12] always use resolve --- src/librustc_mir/transform/inline.rs | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 41eaf864ca47e..f8bdca519ce27 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -87,32 +87,17 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let terminator = bb_data.terminator(); if let TerminatorKind::Call { func: Operand::Constant(ref f), .. } = terminator.kind { - if let ty::TyFnDef(callee_def_id, substs) = f.ty.sty { - match self.tcx.trait_of_item(callee_def_id) { - Some(_) => { - match Instance::new(callee_def_id, substs).resolve(self.tcx) { - Some(instance) => { - callsites.push_back(CallSite { - callee: instance.def_id(), - substs: instance.substs, - bb, - location: terminator.source_info - }); - }, - None => {} - } - } - None => { + if let ty::TyFnDef(callee_def_id, substs) = f.ty.sty { + if let Some(instance) = Instance::new(callee_def_id, substs).resolve(self.tcx) { callsites.push_back(CallSite { - callee: callee_def_id, - substs, + callee: instance.def_id(), + substs: instance.substs, bb, location: terminator.source_info }); } } } - } } } From 24fc50fffacef28d580a67b3c881f62d4752a860 Mon Sep 17 00:00:00 2001 From: Douglas Campos Date: Tue, 19 Sep 2017 17:31:00 -0400 Subject: [PATCH 04/12] make it not to be a method --- src/librustc/ty/instance.rs | 15 +++++++-------- src/librustc_mir/transform/inline.rs | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index b14715615f225..fee4b292359a6 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -118,16 +118,15 @@ impl<'a, 'b, 'tcx> Instance<'tcx> { /// The point where linking happens. Resolve a (def_id, substs) /// pair to an instance. - pub fn resolve(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option> { - let def_id = self.def_id(); - debug!("resolve(def_id={:?}, substs={:?})", def_id, self.substs); + pub fn resolve(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Option> { + debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { debug!(" => associated item, attempting to find impl"); let item = tcx.associated_item(def_id); - resolve_associated_item(tcx, &item, trait_def_id, self.substs) + resolve_associated_item(tcx, &item, trait_def_id, substs) } else { let ty = tcx.type_of(def_id); - let item_type = tcx.trans_apply_param_substs(self.substs, &ty); + let item_type = tcx.trans_apply_param_substs(substs, &ty); let def = match item_type.sty { ty::TyFnDef(..) if { @@ -141,7 +140,7 @@ impl<'a, 'b, 'tcx> Instance<'tcx> { } _ => { if Some(def_id) == tcx.lang_items().drop_in_place_fn() { - let ty = self.substs.type_at(0); + let ty = substs.type_at(0); if ty.needs_drop(tcx, ty::ParamEnv::empty(traits::Reveal::All)) { debug!(" => nontrivial drop glue"); ty::InstanceDef::DropGlue(def_id, Some(ty)) @@ -157,10 +156,10 @@ impl<'a, 'b, 'tcx> Instance<'tcx> { }; Some(Instance { def: def, - substs: self.substs + substs: substs }) }; - debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, self.substs, result); + debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, substs, result); result } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index f8bdca519ce27..426dce4da1a94 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -88,7 +88,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { if let TerminatorKind::Call { func: Operand::Constant(ref f), .. } = terminator.kind { if let ty::TyFnDef(callee_def_id, substs) = f.ty.sty { - if let Some(instance) = Instance::new(callee_def_id, substs).resolve(self.tcx) { + if let Some(instance) = Instance::resolve(self.tcx, callee_def_id, substs) { callsites.push_back(CallSite { callee: instance.def_id(), substs: instance.substs, From 8a5800e1d45a5d4960f3e889cff01923be05e1ce Mon Sep 17 00:00:00 2001 From: Douglas Campos Date: Wed, 27 Sep 2017 22:22:55 -0400 Subject: [PATCH 05/12] take ParamEnv into account when resolving --- src/librustc/ty/instance.rs | 7 ++++--- src/librustc_mir/transform/inline.rs | 7 +++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index fee4b292359a6..89f55c57048d2 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -118,12 +118,12 @@ impl<'a, 'b, 'tcx> Instance<'tcx> { /// The point where linking happens. Resolve a (def_id, substs) /// pair to an instance. - pub fn resolve(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Option> { + pub fn resolve(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Option> { debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { debug!(" => associated item, attempting to find impl"); let item = tcx.associated_item(def_id); - resolve_associated_item(tcx, &item, trait_def_id, substs) + resolve_associated_item(tcx, &item, param_env, trait_def_id, substs) } else { let ty = tcx.type_of(def_id); let item_type = tcx.trans_apply_param_substs(substs, &ty); @@ -184,6 +184,7 @@ fn resolve_closure<'a, 'tcx>( fn resolve_associated_item<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &ty::AssociatedItem, + param_env: ty::ParamEnv<'tcx>, trait_id: DefId, rcvr_substs: &'tcx Substs<'tcx> ) -> Option> { @@ -194,7 +195,7 @@ fn resolve_associated_item<'a, 'tcx>( def_id, trait_id, rcvr_substs); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, ty::Binder(trait_ref)); + let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, param_env, ty::Binder(trait_ref)); // Now that we know which impl is being used, we can dispatch to // the actual function: diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 426dce4da1a94..1eb8f21f80a91 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -78,7 +78,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let mut callsites = VecDeque::new(); // Only do inlining into fn bodies. - if let MirSource::Fn(_) = self.source { + if let MirSource::Fn(caller_id) = self.source { for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated() { // Don't inline calls that are in cleanup blocks. if bb_data.is_cleanup { continue; } @@ -88,7 +88,10 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { if let TerminatorKind::Call { func: Operand::Constant(ref f), .. } = terminator.kind { if let ty::TyFnDef(callee_def_id, substs) = f.ty.sty { - if let Some(instance) = Instance::resolve(self.tcx, callee_def_id, substs) { + let caller_def_id = self.tcx.hir.local_def_id(caller_id); + let param_env = self.tcx.param_env(caller_def_id); + + if let Some(instance) = Instance::resolve(self.tcx, param_env, callee_def_id, substs) { callsites.push_back(CallSite { callee: instance.def_id(), substs: instance.substs, From 081b29c1f69171c092b4c73ef4d1a04bab4f85dd Mon Sep 17 00:00:00 2001 From: Douglas Campos Date: Wed, 27 Sep 2017 23:23:16 -0400 Subject: [PATCH 06/12] stop using monomorphize::resolve() --- src/librustc/ty/instance.rs | 7 +- src/librustc_mir/transform/inline.rs | 5 +- src/librustc_trans/callee.rs | 10 ++- src/librustc_trans/collector.rs | 28 +++++-- src/librustc_trans/mir/block.rs | 6 +- src/librustc_trans/mir/constant.rs | 7 +- src/librustc_trans/monomorphize.rs | 114 +-------------------------- 7 files changed, 49 insertions(+), 128 deletions(-) diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 89f55c57048d2..dbdca1266af9d 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -118,7 +118,10 @@ impl<'a, 'b, 'tcx> Instance<'tcx> { /// The point where linking happens. Resolve a (def_id, substs) /// pair to an instance. - pub fn resolve(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Option> { + pub fn resolve(tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>) -> Option> { debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { debug!(" => associated item, attempting to find impl"); @@ -154,7 +157,7 @@ impl<'a, 'b, 'tcx> Instance<'tcx> { } } }; - Some(Instance { + Some(Instance { def: def, substs: substs }) diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 1eb8f21f80a91..9d32861aedade 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -91,7 +91,10 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let caller_def_id = self.tcx.hir.local_def_id(caller_id); let param_env = self.tcx.param_env(caller_def_id); - if let Some(instance) = Instance::resolve(self.tcx, param_env, callee_def_id, substs) { + if let Some(instance) = Instance::resolve(self.tcx, + param_env, + callee_def_id, + substs) { callsites.push_back(CallSite { callee: instance.def_id(), substs: instance.substs, diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 52e6dce24ed92..5231a516f62f2 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -19,9 +19,10 @@ use common::{self, CrateContext}; use consts; use declare; use llvm::{self, ValueRef}; -use monomorphize::{self, Instance}; +use monomorphize::Instance; use rustc::hir::def_id::DefId; -use rustc::ty::TypeFoldable; +use rustc::ty::{self, TypeFoldable}; +use rustc::traits; use rustc::ty::subst::Substs; use type_of; @@ -179,5 +180,8 @@ pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, substs: &'tcx Substs<'tcx>) -> ValueRef { - get_fn(ccx, monomorphize::resolve(ccx.tcx(), def_id, substs)) + get_fn(ccx, ty::Instance::resolve(ccx.tcx(), + ty::ParamEnv::empty(traits::Reveal::All), + def_id, + substs).unwrap()) } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 6fa69de74b0a1..285a1fb7c7365 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -566,7 +566,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { if let ConstVal::Unevaluated(def_id, substs) = constant.val { let substs = self.tcx.trans_apply_param_substs(self.param_substs, &substs); - let instance = monomorphize::resolve(self.tcx, def_id, substs); + let instance = ty::Instance::resolve(self.tcx, + ty::ParamEnv::empty(traits::Reveal::All), + def_id, + substs).unwrap(); collect_neighbours(self.tcx, instance, true, self.output); } @@ -587,7 +590,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let constness = match (self.const_context, &callee_ty.sty) { (true, &ty::TyFnDef(def_id, substs)) if self.tcx.is_const_fn(def_id) => { - let instance = monomorphize::resolve(self.tcx, def_id, substs); + let instance = + ty::Instance::resolve(self.tcx, + ty::ParamEnv::empty(traits::Reveal::All), + def_id, + substs).unwrap(); Some(instance) } _ => None @@ -657,7 +664,10 @@ fn visit_fn_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, output: &mut Vec>) { if let ty::TyFnDef(def_id, substs) = ty.sty { - let instance = monomorphize::resolve(tcx, def_id, substs); + let instance = ty::Instance::resolve(tcx, + ty::ParamEnv::empty(traits::Reveal::All), + def_id, + substs).unwrap(); visit_instance_use(tcx, instance, is_direct_call, output); } } @@ -845,7 +855,11 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Walk all methods of the trait, including those of its supertraits let methods = traits::get_vtable_methods(tcx, poly_trait_ref); let methods = methods.filter_map(|method| method) - .map(|(def_id, substs)| monomorphize::resolve(tcx, def_id, substs)) + .map(|(def_id, substs)| ty::Instance::resolve( + tcx, + ty::ParamEnv::empty(traits::Reveal::All), + def_id, + substs).unwrap()) .filter(|&instance| should_trans_locally(tcx, &instance)) .map(|instance| create_fn_trans_item(instance)); output.extend(methods); @@ -1000,8 +1014,10 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, continue; } - let instance = - monomorphize::resolve(tcx, method.def_id, callee_substs); + let instance = ty::Instance::resolve(tcx, + ty::ParamEnv::empty(traits::Reveal::All), + method.def_id, + callee_substs).unwrap(); let trans_item = create_fn_trans_item(instance); if trans_item.is_instantiable(tcx) && should_trans_locally(tcx, &instance) { diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 9246822b33920..6e27c0dafafd9 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -13,6 +13,7 @@ use rustc::middle::lang_items; use rustc::middle::const_val::{ConstEvalErr, ConstInt, ErrKind}; use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::layout::{self, LayoutTyper}; +use rustc::traits; use rustc::mir; use abi::{Abi, FnType, ArgType}; use adt; @@ -429,7 +430,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let (instance, mut llfn) = match callee.ty.sty { ty::TyFnDef(def_id, substs) => { - (Some(monomorphize::resolve(bcx.ccx.tcx(), def_id, substs)), + (Some(ty::Instance::resolve(bcx.ccx.tcx(), + ty::ParamEnv::empty(traits::Reveal::All), + def_id, + substs).unwrap()), None) } ty::TyFnPtr(_) => { diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 9232d73f832e7..1ccf6d256204f 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -14,6 +14,7 @@ use rustc_const_math::ConstInt::*; use rustc_const_math::{ConstInt, ConstMathErr}; use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; +use rustc::traits; use rustc::mir; use rustc::mir::tcx::LvalueTy; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -30,7 +31,6 @@ use common::{C_array, C_bool, C_bytes, C_int, C_uint, C_big_integral, C_u32, C_u use common::{C_null, C_struct, C_str_slice, C_undef, C_usize, C_vector, is_undef}; use common::const_to_opt_u128; use consts; -use monomorphize; use type_of; use type_::Type; use value::Value; @@ -261,7 +261,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { substs: &'tcx Substs<'tcx>, args: IndexVec, ConstEvalErr<'tcx>>>) -> Result, ConstEvalErr<'tcx>> { - let instance = monomorphize::resolve(ccx.tcx(), def_id, substs); + let instance = ty::Instance::resolve(ccx.tcx(), + ty::ParamEnv::empty(traits::Reveal::All), + def_id, + substs).unwrap(); let mir = ccx.tcx().instance_mir(instance.def); MirConstContext::new(ccx, &mir, instance.substs, args).trans() } diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 62ccd55b483ca..cd2a881451cd3 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::Abi; -use common::*; - use rustc::hir::def_id::DefId; use rustc::middle::lang_items::DropInPlaceFnLangItem; use rustc::traits; @@ -99,115 +96,6 @@ pub fn resolve_closure<'a, 'tcx> ( } } -fn resolve_associated_item<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - trait_item: &ty::AssociatedItem, - trait_id: DefId, - rcvr_substs: &'tcx Substs<'tcx> -) -> Instance<'tcx> { - let def_id = trait_item.def_id; - debug!("resolve_associated_item(trait_item={:?}, \ - trait_id={:?}, \ - rcvr_substs={:?})", - def_id, trait_id, rcvr_substs); - - let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = tcx.trans_fulfill_obligation( - DUMMY_SP, ty::ParamEnv::empty(traits::Reveal::All), ty::Binder(trait_ref)); - - // Now that we know which impl is being used, we can dispatch to - // the actual function: - match vtbl { - traits::VtableImpl(impl_data) => { - let (def_id, substs) = traits::find_associated_item( - tcx, trait_item, rcvr_substs, &impl_data); - let substs = tcx.erase_regions(&substs); - ty::Instance::new(def_id, substs) - } - traits::VtableGenerator(closure_data) => { - Instance { - def: ty::InstanceDef::Item(closure_data.closure_def_id), - substs: closure_data.substs.substs - } - } - traits::VtableClosure(closure_data) => { - let trait_closure_kind = tcx.lang_items().fn_trait_kind(trait_id).unwrap(); - resolve_closure(tcx, closure_data.closure_def_id, closure_data.substs, - trait_closure_kind) - } - traits::VtableFnPointer(ref data) => { - Instance { - def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty), - substs: rcvr_substs - } - } - traits::VtableObject(ref data) => { - let index = tcx.get_vtable_index_of_object_method(data, def_id); - Instance { - def: ty::InstanceDef::Virtual(def_id, index), - substs: rcvr_substs - } - } - traits::VtableBuiltin(..) if Some(trait_id) == tcx.lang_items().clone_trait() => { - Instance { - def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()), - substs: rcvr_substs - } - } - _ => { - bug!("static call to invalid vtable: {:?}", vtbl) - } - } -} - -/// The point where linking happens. Resolve a (def_id, substs) -/// pair to an instance. -pub fn resolve<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx> -) -> Instance<'tcx> { - debug!("resolve(def_id={:?}, substs={:?})", - def_id, substs); - let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { - debug!(" => associated item, attempting to find impl"); - let item = tcx.associated_item(def_id); - resolve_associated_item(tcx, &item, trait_def_id, substs) - } else { - let item_type = def_ty(tcx, def_id, substs); - let def = match item_type.sty { - ty::TyFnDef(..) if { - let f = item_type.fn_sig(tcx); - f.abi() == Abi::RustIntrinsic || - f.abi() == Abi::PlatformIntrinsic - } => - { - debug!(" => intrinsic"); - ty::InstanceDef::Intrinsic(def_id) - } - _ => { - if Some(def_id) == tcx.lang_items().drop_in_place_fn() { - let ty = substs.type_at(0); - if type_needs_drop(tcx, ty) { - debug!(" => nontrivial drop glue"); - ty::InstanceDef::DropGlue(def_id, Some(ty)) - } else { - debug!(" => trivial drop glue"); - ty::InstanceDef::DropGlue(def_id, None) - } - } else { - debug!(" => free item"); - ty::InstanceDef::Item(def_id) - } - } - }; - Instance { def, substs } - }; - debug!("resolve(def_id={:?}, substs={:?}) = {}", - def_id, substs, result); - result -} - pub fn resolve_drop_in_place<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) @@ -215,7 +103,7 @@ pub fn resolve_drop_in_place<'a, 'tcx>( { let def_id = tcx.require_lang_item(DropInPlaceFnLangItem); let substs = tcx.intern_substs(&[Kind::from(ty)]); - resolve(tcx, def_id, substs) + Instance::resolve(tcx, ty::ParamEnv::empty(traits::Reveal::All), def_id, substs).unwrap() } pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, From 29220663c14e7e52db8dc5eb796ace22f5b3591b Mon Sep 17 00:00:00 2001 From: Douglas Campos Date: Thu, 28 Sep 2017 08:36:34 -0400 Subject: [PATCH 07/12] style fixes as requested by @eddyb --- src/librustc/ty/instance.rs | 2 -- src/librustc_trans/callee.rs | 6 +++--- src/librustc_trans/mir/block.rs | 6 +++--- src/librustc_trans/mir/constant.rs | 6 +++--- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index dbdca1266af9d..6f1be020c7bd3 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -165,8 +165,6 @@ impl<'a, 'b, 'tcx> Instance<'tcx> { debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, substs, result); result } - - } fn resolve_closure<'a, 'tcx>( diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 5231a516f62f2..c5a754719a191 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -181,7 +181,7 @@ pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, -> ValueRef { get_fn(ccx, ty::Instance::resolve(ccx.tcx(), - ty::ParamEnv::empty(traits::Reveal::All), - def_id, - substs).unwrap()) + ty::ParamEnv::empty(traits::Reveal::All), + def_id, + substs).unwrap()) } diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 6e27c0dafafd9..591aa974666cc 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -431,9 +431,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let (instance, mut llfn) = match callee.ty.sty { ty::TyFnDef(def_id, substs) => { (Some(ty::Instance::resolve(bcx.ccx.tcx(), - ty::ParamEnv::empty(traits::Reveal::All), - def_id, - substs).unwrap()), + ty::ParamEnv::empty(traits::Reveal::All), + def_id, + substs).unwrap()), None) } ty::TyFnPtr(_) => { diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 1ccf6d256204f..1b8e68f691ae6 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -262,9 +262,9 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { args: IndexVec, ConstEvalErr<'tcx>>>) -> Result, ConstEvalErr<'tcx>> { let instance = ty::Instance::resolve(ccx.tcx(), - ty::ParamEnv::empty(traits::Reveal::All), - def_id, - substs).unwrap(); + ty::ParamEnv::empty(traits::Reveal::All), + def_id, + substs).unwrap(); let mir = ccx.tcx().instance_mir(instance.def); MirConstContext::new(ccx, &mir, instance.substs, args).trans() } From 08e1f0b9d74ac5cdf115b9548d10da1ca01f966d Mon Sep 17 00:00:00 2001 From: Douglas Campos Date: Fri, 29 Sep 2017 21:51:20 -0400 Subject: [PATCH 08/12] fix formatting --- src/librustc_trans/callee.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index c5a754719a191..b89ec3d14b528 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -180,8 +180,13 @@ pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, substs: &'tcx Substs<'tcx>) -> ValueRef { - get_fn(ccx, ty::Instance::resolve(ccx.tcx(), - ty::ParamEnv::empty(traits::Reveal::All), - def_id, - substs).unwrap()) + get_fn( + ccx, + ty::Instance::resolve( + ccx.tcx(), + ty::ParamEnv::empty(traits::Reveal::All), + def_id, + substs,) + .unwrap() + ) } From 59e778e5e1932eaa97cd46bca8f58a8233c579d1 Mon Sep 17 00:00:00 2001 From: Douglas Campos Date: Fri, 29 Sep 2017 21:57:12 -0400 Subject: [PATCH 09/12] improve documentation for resolve() --- src/librustc/ty/instance.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 6f1be020c7bd3..9560d6359a532 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -116,8 +116,24 @@ impl<'a, 'b, 'tcx> Instance<'tcx> { self.def.def_id() } - /// The point where linking happens. Resolve a (def_id, substs) - /// pair to an instance. + /// Resolve a (def_id, substs) pair to an (optional) instance -- most commonly, + /// this is used to find the precise code that will run for a trait method invocation, + /// if known. + /// + /// Returns `None` if we cannot resolve `Instance` to a specific instance. + /// For example, in a context like this, + /// + /// ``` + /// fn foo(t: T) { ... } + /// ``` + /// + /// trying to resolve `Debug::fmt` applied to `T` will yield `None`, because we do not + /// know what code ought to run. (Note that this setting is also affected by the + /// `RevealMode` in the parameter environment.) + /// + /// Presuming that coherence and type-check have succeeded, if this method is invoked + /// in a monomorphic context (i.e., like during trans), then it is guaranteed to return + /// `Some`. pub fn resolve(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, def_id: DefId, From a29c770c68591f4defe355c6db0a8478b9ef053f Mon Sep 17 00:00:00 2001 From: Douglas Campos Date: Fri, 29 Sep 2017 22:21:35 -0400 Subject: [PATCH 10/12] make match exaustive --- src/librustc/ty/instance.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 9560d6359a532..35ab1cec4cf9e 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -247,15 +247,17 @@ fn resolve_associated_item<'a, 'tcx>( substs: rcvr_substs }) } - traits::VtableBuiltin(..) if Some(trait_id) == tcx.lang_items().clone_trait() => { - Some(Instance { - def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()), - substs: rcvr_substs - }) - } - _ => { - None + traits::VtableBuiltin(..) => { + if let Some(_) = tcx.lang_items().clone_trait() { + Some(Instance { + def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()), + substs: rcvr_substs + }) + } else { + None + } } + traits::VtableDefaultImpl(..) | traits::VtableParam(..) => None } } @@ -287,8 +289,9 @@ fn needs_fn_once_adapter_shim<'a, 'tcx>(actual_closure_kind: ty::ClosureKind, // // These are both the same at trans time. Ok(true) - } - _ => Err(()), + } + (ty::ClosureKind::FnMut, _) | + (ty::ClosureKind::FnOnce, _) => Err(()) } } From b24a6726135ade8b49a4a4980007139b6791ec37 Mon Sep 17 00:00:00 2001 From: Douglas Campos Date: Sat, 30 Sep 2017 11:08:08 -0400 Subject: [PATCH 11/12] weird formatting --- src/librustc_trans/callee.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index b89ec3d14b528..713613cedc90f 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -186,7 +186,7 @@ pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.tcx(), ty::ParamEnv::empty(traits::Reveal::All), def_id, - substs,) - .unwrap() + substs, + ).unwrap() ) } From 11e141eba3d21fc8d7f9c406c85b44fe114e5a01 Mon Sep 17 00:00:00 2001 From: Douglas Campos Date: Sun, 1 Oct 2017 11:14:47 -0400 Subject: [PATCH 12/12] stray comma --- src/librustc_trans/callee.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 713613cedc90f..f5a90fc2e4a19 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -186,7 +186,7 @@ pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.tcx(), ty::ParamEnv::empty(traits::Reveal::All), def_id, - substs, + substs ).unwrap() ) }