diff --git a/Cargo.lock b/Cargo.lock index f44644cffa6..6c3a4eefa5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4124,6 +4124,7 @@ dependencies = [ "rustc_data_structures", "rustc_hir", "rustc_span", + "rustc_target", ] [[package]] diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 335953fc41e..332fd0bf46f 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -1,12 +1,11 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::middle::lang_items::DropInPlaceFnLangItem; -use crate::traits; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable}; +use rustc_data_structures::AtomicRef; use rustc_hir::def::Namespace; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_macros::HashStable; -use rustc_target::spec::abi::Abi; use std::fmt; @@ -263,45 +262,7 @@ impl<'tcx> Instance<'tcx> { def_id: DefId, substs: SubstsRef<'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 in param_env {:#?}", param_env); - let item = tcx.associated_item(def_id); - resolve_associated_item(tcx, &item, param_env, trait_def_id, substs) - } else { - let ty = tcx.type_of(def_id); - let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, &ty); - - let def = match item_type.kind { - ty::FnDef(..) - 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 ty.needs_drop(tcx, param_env.with_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: substs }) - }; - debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, substs, result); - result + (*RESOLVE_INSTANCE)(tcx, param_env, def_id, substs) } pub fn resolve_for_fn_ptr( @@ -398,88 +359,6 @@ impl<'tcx> Instance<'tcx> { } } -fn resolve_associated_item<'tcx>( - tcx: TyCtxt<'tcx>, - trait_item: &ty::AssocItem, - param_env: ty::ParamEnv<'tcx>, - trait_id: DefId, - rcvr_substs: SubstsRef<'tcx>, -) -> Option> { - let def_id = trait_item.def_id; - debug!( - "resolve_associated_item(trait_item={:?}, \ - param_env={:?}, \ - trait_id={:?}, \ - rcvr_substs={:?})", - def_id, param_env, trait_id, rcvr_substs - ); - - let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(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, param_env, trait_item, rcvr_substs, &impl_data); - - let resolved_item = tcx.associated_item(def_id); - - // Since this is a trait item, we need to see if the item is either a trait default item - // or a specialization because we can't resolve those unless we can `Reveal::All`. - // NOTE: This should be kept in sync with the similar code in - // `rustc::traits::project::assemble_candidates_from_impls()`. - let eligible = if !resolved_item.defaultness.is_default() { - true - } else if param_env.reveal == traits::Reveal::All { - !trait_ref.needs_subst() - } else { - false - }; - - if !eligible { - return None; - } - - let substs = tcx.erase_regions(&substs); - Some(ty::Instance::new(def_id, substs)) - } - traits::VtableGenerator(generator_data) => Some(Instance { - def: ty::InstanceDef::Item(generator_data.generator_def_id), - substs: generator_data.substs, - }), - traits::VtableClosure(closure_data) => { - let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap(); - Some(Instance::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 = traits::get_vtable_index_of_object_method(tcx, data, def_id); - Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs }) - } - traits::VtableBuiltin(..) => { - if tcx.lang_items().clone_trait().is_some() { - Some(Instance { - def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()), - substs: rcvr_substs, - }) - } else { - None - } - } - traits::VtableAutoImpl(..) | traits::VtableParam(..) | traits::VtableTraitAlias(..) => None, - } -} - fn needs_fn_once_adapter_shim( actual_closure_kind: ty::ClosureKind, trait_closure_kind: ty::ClosureKind, @@ -512,3 +391,21 @@ fn needs_fn_once_adapter_shim( (ty::ClosureKind::FnMut, _) | (ty::ClosureKind::FnOnce, _) => Err(()), } } + +fn resolve_instance_default( + _tcx: TyCtxt<'tcx>, + _param_env: ty::ParamEnv<'tcx>, + _def_id: DefId, + _substs: SubstsRef<'tcx>, +) -> Option> { + unimplemented!() +} + +pub static RESOLVE_INSTANCE: AtomicRef< + for<'tcx> fn( + TyCtxt<'tcx>, + ty::ParamEnv<'tcx>, + DefId, + SubstsRef<'tcx>, + ) -> Option>, +> = AtomicRef::new(&(resolve_instance_default as _)); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index ad51c60ab01..b67cab65207 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -83,6 +83,7 @@ pub use self::context::{ CtxtInterners, GeneratorInteriorTypeCause, GlobalCtxt, Lift, TypeckTables, }; +pub use self::instance::RESOLVE_INSTANCE; pub use self::instance::{Instance, InstanceDef}; pub use self::trait_def::TraitDef; diff --git a/src/librustc_interface/callbacks.rs b/src/librustc_interface/callbacks.rs index 803e8958572..7c8e682e9fb 100644 --- a/src/librustc_interface/callbacks.rs +++ b/src/librustc_interface/callbacks.rs @@ -58,4 +58,5 @@ pub fn setup_callbacks() { rustc_span::SPAN_DEBUG.swap(&(span_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_))); + rustc::ty::RESOLVE_INSTANCE.swap(&(rustc_ty::instance::resolve_instance as _)); } diff --git a/src/librustc_ty/Cargo.toml b/src/librustc_ty/Cargo.toml index fb0d93fe5eb..52606e5fdfe 100644 --- a/src/librustc_ty/Cargo.toml +++ b/src/librustc_ty/Cargo.toml @@ -14,3 +14,4 @@ rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_hir = { path = "../librustc_hir" } rustc_span = { path = "../librustc_span" } +rustc_target = { path = "../librustc_target" } diff --git a/src/librustc_ty/instance.rs b/src/librustc_ty/instance.rs new file mode 100644 index 00000000000..66f189a5d97 --- /dev/null +++ b/src/librustc_ty/instance.rs @@ -0,0 +1,136 @@ +use rustc::traits; +use rustc::ty::subst::SubstsRef; +use rustc::ty::{self, Instance, TyCtxt, TypeFoldable}; +use rustc_hir::def_id::DefId; +use rustc_target::spec::abi::Abi; + +use log::debug; + +pub fn resolve_instance<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + def_id: DefId, + substs: SubstsRef<'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 in param_env {:#?}", param_env); + let item = tcx.associated_item(def_id); + resolve_associated_item(tcx, &item, param_env, trait_def_id, substs) + } else { + let ty = tcx.type_of(def_id); + let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, &ty); + + let def = match item_type.kind { + ty::FnDef(..) + 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 ty.needs_drop(tcx, param_env.with_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: substs }) + }; + debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, substs, result); + result +} + +fn resolve_associated_item<'tcx>( + tcx: TyCtxt<'tcx>, + trait_item: &ty::AssocItem, + param_env: ty::ParamEnv<'tcx>, + trait_id: DefId, + rcvr_substs: SubstsRef<'tcx>, +) -> Option> { + let def_id = trait_item.def_id; + debug!( + "resolve_associated_item(trait_item={:?}, \ + param_env={:?}, \ + trait_id={:?}, \ + rcvr_substs={:?})", + def_id, param_env, trait_id, rcvr_substs + ); + + let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); + let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(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, param_env, trait_item, rcvr_substs, &impl_data); + + let resolved_item = tcx.associated_item(def_id); + + // Since this is a trait item, we need to see if the item is either a trait default item + // or a specialization because we can't resolve those unless we can `Reveal::All`. + // NOTE: This should be kept in sync with the similar code in + // `rustc::traits::project::assemble_candidates_from_impls()`. + let eligible = if !resolved_item.defaultness.is_default() { + true + } else if param_env.reveal == traits::Reveal::All { + !trait_ref.needs_subst() + } else { + false + }; + + if !eligible { + return None; + } + + let substs = tcx.erase_regions(&substs); + Some(ty::Instance::new(def_id, substs)) + } + traits::VtableGenerator(generator_data) => Some(Instance { + def: ty::InstanceDef::Item(generator_data.generator_def_id), + substs: generator_data.substs, + }), + traits::VtableClosure(closure_data) => { + let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap(); + Some(Instance::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 = traits::get_vtable_index_of_object_method(tcx, data, def_id); + Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs }) + } + traits::VtableBuiltin(..) => { + if tcx.lang_items().clone_trait().is_some() { + Some(Instance { + def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()), + substs: rcvr_substs, + }) + } else { + None + } + } + traits::VtableAutoImpl(..) | traits::VtableParam(..) | traits::VtableTraitAlias(..) => None, + } +} diff --git a/src/librustc_ty/lib.rs b/src/librustc_ty/lib.rs index 7eef19b94e4..f9ee4e20d27 100644 --- a/src/librustc_ty/lib.rs +++ b/src/librustc_ty/lib.rs @@ -17,6 +17,7 @@ extern crate log; use rustc::ty::query::Providers; mod common_traits; +pub mod instance; mod needs_drop; mod ty;