mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-24 21:53:56 +00:00
librustc: Implement basic lazy implementation loading.
This is only for implementations defined in the same crate as the trait they implement.
This commit is contained in:
parent
ff7b8d6d88
commit
6c37e3b7f8
@ -185,6 +185,9 @@ pub static tag_item_impl_vtables: uint = 0x82;
|
||||
pub static tag_impls: uint = 0x83;
|
||||
pub static tag_impls_impl: uint = 0x84;
|
||||
|
||||
pub static tag_items_data_item_inherent_impl: uint = 0x85;
|
||||
pub static tag_items_data_item_extension_impl: uint = 0x86;
|
||||
|
||||
pub struct LinkMeta {
|
||||
name: @str,
|
||||
vers: @str,
|
||||
|
@ -272,3 +272,28 @@ pub fn each_impl(cstore: @mut cstore::CStore,
|
||||
decoder::each_impl(cdata, callback)
|
||||
}
|
||||
|
||||
pub fn each_implementation_for_type(cstore: @mut cstore::CStore,
|
||||
def_id: ast::def_id,
|
||||
callback: &fn(ast::def_id)) {
|
||||
let cdata = cstore::get_crate_data(cstore, def_id.crate);
|
||||
decoder::each_implementation_for_type(cdata, def_id.node, callback)
|
||||
}
|
||||
|
||||
pub fn each_implementation_for_trait(cstore: @mut cstore::CStore,
|
||||
def_id: ast::def_id,
|
||||
callback: &fn(ast::def_id)) {
|
||||
let cdata = cstore::get_crate_data(cstore, def_id.crate);
|
||||
decoder::each_implementation_for_trait(cdata, def_id.node, callback)
|
||||
}
|
||||
|
||||
/// If the given def ID describes a method belonging to a trait (either a
|
||||
/// default method or an implementation of a trait method), returns the ID of
|
||||
/// the trait that the method belongs to. Otherwise, returns `None`.
|
||||
pub fn get_trait_of_method(cstore: @mut cstore::CStore,
|
||||
def_id: ast::def_id,
|
||||
tcx: ty::ctxt)
|
||||
-> Option<ast::def_id> {
|
||||
let cdata = cstore::get_crate_data(cstore, def_id.crate);
|
||||
decoder::get_trait_of_method(cdata, def_id.node, tcx)
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ use metadata::decoder;
|
||||
use metadata::tydecode::{parse_ty_data, parse_def_id,
|
||||
parse_type_param_def_data,
|
||||
parse_bare_fn_ty_data, parse_trait_ref_data};
|
||||
use middle::ty::{ImplContainer, TraitContainer};
|
||||
use middle::ty;
|
||||
use middle::typeck;
|
||||
use middle::astencode::vtable_decoder_helpers;
|
||||
@ -958,8 +959,15 @@ pub fn get_method(intr: @ident_interner, cdata: cmd, id: ast::NodeId,
|
||||
{
|
||||
let method_doc = lookup_item(id, cdata.data);
|
||||
let def_id = item_def_id(method_doc, cdata);
|
||||
|
||||
let container_id = item_reqd_and_translated_parent_item(cdata.cnum,
|
||||
method_doc);
|
||||
let container_doc = lookup_item(container_id.node, cdata.data);
|
||||
let container = match item_family(container_doc) {
|
||||
Trait => TraitContainer(container_id),
|
||||
_ => ImplContainer(container_id),
|
||||
};
|
||||
|
||||
let name = item_name(intr, method_doc);
|
||||
let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
|
||||
tag_item_method_tps);
|
||||
@ -980,7 +988,7 @@ pub fn get_method(intr: @ident_interner, cdata: cmd, id: ast::NodeId,
|
||||
explicit_self,
|
||||
vis,
|
||||
def_id,
|
||||
container_id,
|
||||
container,
|
||||
provided_source
|
||||
)
|
||||
}
|
||||
@ -1391,4 +1399,56 @@ pub fn each_impl(cdata: cmd, callback: &fn(ast::def_id)) {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn each_implementation_for_type(cdata: cmd,
|
||||
id: ast::NodeId,
|
||||
callback: &fn(ast::def_id)) {
|
||||
let item_doc = lookup_item(id, cdata.data);
|
||||
/*println(fmt!(">>> reading inherent impls from %s",
|
||||
token::ident_to_str(&item_name(token::get_ident_interner(),
|
||||
item_doc))));*/
|
||||
do reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl)
|
||||
|impl_doc| {
|
||||
let implementation_def_id = item_def_id(impl_doc, cdata);
|
||||
/*println(fmt!(">>>>> read inherent impl: %d:%d",
|
||||
implementation_def_id.crate,
|
||||
implementation_def_id.node));*/
|
||||
callback(implementation_def_id);
|
||||
true
|
||||
};
|
||||
}
|
||||
|
||||
pub fn each_implementation_for_trait(cdata: cmd,
|
||||
id: ast::NodeId,
|
||||
callback: &fn(ast::def_id)) {
|
||||
let item_doc = lookup_item(id, cdata.data);
|
||||
|
||||
let _ = do reader::tagged_docs(item_doc,
|
||||
tag_items_data_item_extension_impl)
|
||||
|impl_doc| {
|
||||
let implementation_def_id = item_def_id(impl_doc, cdata);
|
||||
callback(implementation_def_id);
|
||||
true
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_trait_of_method(cdata: cmd, id: ast::NodeId, tcx: ty::ctxt)
|
||||
-> Option<ast::def_id> {
|
||||
let item_doc = lookup_item(id, cdata.data);
|
||||
let parent_item_id = match item_parent_item(item_doc) {
|
||||
None => return None,
|
||||
Some(item_id) => item_id,
|
||||
};
|
||||
let parent_item_id = translate_def_id(cdata, parent_item_id);
|
||||
let parent_item_doc = lookup_item(parent_item_id.node, cdata.data);
|
||||
match item_family(parent_item_doc) {
|
||||
Trait => Some(item_def_id(parent_item_doc, cdata)),
|
||||
Impl => {
|
||||
do reader::maybe_get_doc(parent_item_doc, tag_item_trait_ref).map
|
||||
|_| {
|
||||
item_trait_ref(parent_item_doc, tcx, cdata).def_id
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -799,6 +799,38 @@ fn should_inline(attrs: &[Attribute]) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Encodes the inherent implementations of a structure, enumeration, or trait.
|
||||
fn encode_inherent_implementations(ecx: &EncodeContext,
|
||||
ebml_w: &mut writer::Encoder,
|
||||
def_id: def_id) {
|
||||
match ecx.tcx.inherent_impls.find(&def_id) {
|
||||
None => {}
|
||||
Some(&implementations) => {
|
||||
for implementation in implementations.iter() {
|
||||
ebml_w.start_tag(tag_items_data_item_inherent_impl);
|
||||
encode_def_id(ebml_w, implementation.did);
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Encodes the implementations of a trait defined in this crate.
|
||||
fn encode_extension_implementations(ecx: &EncodeContext,
|
||||
ebml_w: &mut writer::Encoder,
|
||||
trait_def_id: def_id) {
|
||||
match ecx.tcx.trait_impls.find(&trait_def_id) {
|
||||
None => {}
|
||||
Some(&implementations) => {
|
||||
for implementation in implementations.iter() {
|
||||
ebml_w.start_tag(tag_items_data_item_extension_impl);
|
||||
encode_def_id(ebml_w, implementation.did);
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_info_for_item(ecx: &EncodeContext,
|
||||
ebml_w: &mut writer::Encoder,
|
||||
item: @item,
|
||||
@ -902,6 +934,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
(ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
|
||||
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
|
||||
encode_region_param(ecx, ebml_w, item);
|
||||
|
||||
// Encode inherent implementations for this enumeration.
|
||||
encode_inherent_implementations(ecx, ebml_w, def_id);
|
||||
|
||||
ebml_w.end_tag();
|
||||
|
||||
encode_enum_variant_info(ecx,
|
||||
@ -954,6 +990,9 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
}
|
||||
}
|
||||
|
||||
// Encode inherent implementations for this structure.
|
||||
encode_inherent_implementations(ecx, ebml_w, def_id);
|
||||
|
||||
/* Each class has its own index -- encode it */
|
||||
let bkts = create_index(idx);
|
||||
encode_index(ebml_w, bkts, write_i64);
|
||||
@ -1069,6 +1108,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id);
|
||||
encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_super_trait_ref);
|
||||
}
|
||||
|
||||
// Encode the implementations of this trait.
|
||||
encode_extension_implementations(ecx, ebml_w, def_id);
|
||||
|
||||
ebml_w.end_tag();
|
||||
|
||||
// Now output the method info for each method.
|
||||
@ -1130,6 +1173,9 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
|
||||
// Encode inherent implementations for this trait.
|
||||
encode_inherent_implementations(ecx, ebml_w, def_id);
|
||||
}
|
||||
item_mac(*) => fail!("item macros unimplemented")
|
||||
}
|
||||
@ -1523,10 +1569,19 @@ struct ImplVisitor<'self> {
|
||||
impl<'self> Visitor<()> for ImplVisitor<'self> {
|
||||
fn visit_item(&mut self, item: @item, _: ()) {
|
||||
match item.node {
|
||||
item_impl(*) => {
|
||||
self.ebml_w.start_tag(tag_impls_impl);
|
||||
encode_def_id(self.ebml_w, local_def(item.id));
|
||||
self.ebml_w.end_tag();
|
||||
item_impl(_, Some(ref trait_ref), _, _) => {
|
||||
let def_map = self.ecx.tcx.def_map;
|
||||
let trait_def = def_map.get_copy(&trait_ref.ref_id);
|
||||
let def_id = ast_util::def_id_of_def(trait_def);
|
||||
|
||||
// Load eagerly if this is an implementation of the Drop trait
|
||||
// or if the trait is not defined in this crate.
|
||||
if def_id == self.ecx.tcx.lang_items.drop_trait().unwrap() ||
|
||||
def_id.crate != LOCAL_CRATE {
|
||||
self.ebml_w.start_tag(tag_impls_impl);
|
||||
encode_def_id(self.ebml_w, local_def(item.id));
|
||||
self.ebml_w.end_tag();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -1534,6 +1589,16 @@ impl<'self> Visitor<()> for ImplVisitor<'self> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Encodes implementations that are eagerly loaded.
|
||||
///
|
||||
/// None of this is necessary in theory; we can load all implementations
|
||||
/// lazily. However, in two cases the optimizations to lazily load
|
||||
/// implementations are not yet implemented. These two cases, which require us
|
||||
/// to load implementations eagerly, are:
|
||||
///
|
||||
/// * Destructors (implementations of the Drop trait).
|
||||
///
|
||||
/// * Implementations of traits not defined in this crate.
|
||||
fn encode_impls(ecx: &EncodeContext,
|
||||
crate: &Crate,
|
||||
ebml_w: &mut writer::Encoder) {
|
||||
|
@ -225,7 +225,7 @@ impl PrivacyVisitor {
|
||||
|
||||
if method_id.crate == LOCAL_CRATE {
|
||||
let is_private = self.method_is_private(span, method_id.node);
|
||||
let container_id = ty::method(self.tcx, method_id).container_id;
|
||||
let container_id = ty::method(self.tcx, method_id).container_id();
|
||||
if is_private &&
|
||||
(container_id.crate != LOCAL_CRATE ||
|
||||
!self.privileged_items.iter().any(|x| x == &(container_id.node))) {
|
||||
|
@ -283,6 +283,14 @@ pub fn trans_fn_ref_with_vtables(
|
||||
self_ty: None,
|
||||
tps: /*bad*/ type_params.to_owned() };
|
||||
|
||||
// Load the info for the appropriate trait if necessary.
|
||||
match ty::trait_of_method(tcx, def_id) {
|
||||
None => {}
|
||||
Some(trait_id) => {
|
||||
ty::populate_implementations_for_trait_if_necessary(tcx, trait_id)
|
||||
}
|
||||
}
|
||||
|
||||
// We need to do a bunch of special handling for default methods.
|
||||
// We need to modify the def_id and our substs in order to monomorphize
|
||||
// the function.
|
||||
@ -303,7 +311,7 @@ pub fn trans_fn_ref_with_vtables(
|
||||
// So, what we need to do is find this substitution and
|
||||
// compose it with the one we already have.
|
||||
|
||||
let impl_id = ty::method(tcx, def_id).container_id;
|
||||
let impl_id = ty::method(tcx, def_id).container_id();
|
||||
let method = ty::method(tcx, source_id);
|
||||
let trait_ref = ty::impl_trait_ref(tcx, impl_id)
|
||||
.expect("could not find trait_ref for impl with \
|
||||
|
@ -176,6 +176,10 @@ pub fn trans_method_callee(bcx: @mut Block,
|
||||
}) => {
|
||||
match bcx.fcx.param_substs {
|
||||
Some(substs) => {
|
||||
ty::populate_implementations_for_trait_if_necessary(
|
||||
bcx.tcx(),
|
||||
trait_id);
|
||||
|
||||
let vtbl = find_vtable(bcx.tcx(), substs,
|
||||
p, b);
|
||||
trans_monomorphized_callee(bcx, callee_id, this, mentry,
|
||||
@ -210,6 +214,8 @@ pub fn trans_static_method_callee(bcx: @mut Block,
|
||||
callee_id);
|
||||
let _indenter = indenter();
|
||||
|
||||
ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trait_id);
|
||||
|
||||
// When we translate a static fn defined in a trait like:
|
||||
//
|
||||
// trait<T1...Tn> Trait {
|
||||
@ -575,6 +581,8 @@ fn emit_vtable_methods(bcx: @mut Block,
|
||||
make a vtable for a type impl!")
|
||||
};
|
||||
|
||||
ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trt_id);
|
||||
|
||||
let trait_method_def_ids = ty::trait_method_def_ids(tcx, trt_id);
|
||||
do trait_method_def_ids.map |method_def_id| {
|
||||
let ident = ty::method(tcx, *method_def_id).ident;
|
||||
|
@ -60,6 +60,12 @@ pub struct field {
|
||||
mt: mt
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub enum MethodContainer {
|
||||
TraitContainer(ast::def_id),
|
||||
ImplContainer(ast::def_id),
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct Method {
|
||||
ident: ast::ident,
|
||||
@ -69,7 +75,7 @@ pub struct Method {
|
||||
explicit_self: ast::explicit_self_,
|
||||
vis: ast::visibility,
|
||||
def_id: ast::def_id,
|
||||
container_id: ast::def_id,
|
||||
container: MethodContainer,
|
||||
|
||||
// If this method is provided, we need to know where it came from
|
||||
provided_source: Option<ast::def_id>
|
||||
@ -83,7 +89,7 @@ impl Method {
|
||||
explicit_self: ast::explicit_self_,
|
||||
vis: ast::visibility,
|
||||
def_id: ast::def_id,
|
||||
container_id: ast::def_id,
|
||||
container: MethodContainer,
|
||||
provided_source: Option<ast::def_id>)
|
||||
-> Method {
|
||||
// Check the invariants.
|
||||
@ -101,10 +107,17 @@ impl Method {
|
||||
explicit_self: explicit_self,
|
||||
vis: vis,
|
||||
def_id: def_id,
|
||||
container_id: container_id,
|
||||
container: container,
|
||||
provided_source: provided_source
|
||||
}
|
||||
}
|
||||
|
||||
pub fn container_id(&self) -> ast::def_id {
|
||||
match self.container {
|
||||
TraitContainer(id) => id,
|
||||
ImplContainer(id) => id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Impl {
|
||||
@ -324,7 +337,15 @@ struct ctxt_ {
|
||||
used_mut_nodes: @mut HashSet<ast::NodeId>,
|
||||
|
||||
// vtable resolution information for impl declarations
|
||||
impl_vtables: typeck::impl_vtable_map
|
||||
impl_vtables: typeck::impl_vtable_map,
|
||||
|
||||
// The set of external nominal types whose implementations have been read.
|
||||
// This is used for lazy resolution of methods.
|
||||
populated_external_types: @mut HashSet<ast::def_id>,
|
||||
|
||||
// The set of external traits whose implementations have been read. This
|
||||
// is used for lazy resolution of traits.
|
||||
populated_external_traits: @mut HashSet<ast::def_id>,
|
||||
}
|
||||
|
||||
pub enum tbox_flag {
|
||||
@ -938,6 +959,8 @@ pub fn mk_ctxt(s: session::Session,
|
||||
used_unsafe: @mut HashSet::new(),
|
||||
used_mut_nodes: @mut HashSet::new(),
|
||||
impl_vtables: @mut HashMap::new(),
|
||||
populated_external_types: @mut HashSet::new(),
|
||||
populated_external_traits: @mut HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -3612,8 +3635,7 @@ pub fn def_has_ty_params(def: ast::def) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn provided_source(cx: ctxt, id: ast::def_id)
|
||||
-> Option<ast::def_id> {
|
||||
pub fn provided_source(cx: ctxt, id: ast::def_id) -> Option<ast::def_id> {
|
||||
cx.provided_method_sources.find(&id).map_move(|x| *x)
|
||||
}
|
||||
|
||||
@ -4553,3 +4575,135 @@ pub fn visitor_object_ty(tcx: ctxt,
|
||||
ast::m_imm,
|
||||
EmptyBuiltinBounds())))
|
||||
}
|
||||
|
||||
/// Records a trait-to-implementation mapping.
|
||||
fn record_trait_implementation(tcx: ctxt,
|
||||
trait_def_id: def_id,
|
||||
implementation: @Impl) {
|
||||
let implementation_list;
|
||||
match tcx.trait_impls.find(&trait_def_id) {
|
||||
None => {
|
||||
implementation_list = @mut ~[];
|
||||
tcx.trait_impls.insert(trait_def_id, implementation_list);
|
||||
}
|
||||
Some(&existing_implementation_list) => {
|
||||
implementation_list = existing_implementation_list
|
||||
}
|
||||
}
|
||||
|
||||
implementation_list.push(implementation);
|
||||
}
|
||||
|
||||
/// Populates the type context with all the implementations for the given type
|
||||
/// if necessary.
|
||||
pub fn populate_implementations_for_type_if_necessary(tcx: ctxt,
|
||||
type_id: ast::def_id) {
|
||||
if type_id.crate == LOCAL_CRATE {
|
||||
return
|
||||
}
|
||||
if tcx.populated_external_types.contains(&type_id) {
|
||||
return
|
||||
}
|
||||
|
||||
do csearch::each_implementation_for_type(tcx.sess.cstore, type_id)
|
||||
|implementation_def_id| {
|
||||
let implementation = @csearch::get_impl(tcx, implementation_def_id);
|
||||
|
||||
// Record the trait->implementation mappings, if applicable.
|
||||
let associated_traits = csearch::get_impl_trait(tcx,
|
||||
implementation.did);
|
||||
for trait_ref in associated_traits.iter() {
|
||||
record_trait_implementation(tcx,
|
||||
trait_ref.def_id,
|
||||
implementation);
|
||||
}
|
||||
|
||||
// For any methods that use a default implementation, add them to
|
||||
// the map. This is a bit unfortunate.
|
||||
for method in implementation.methods.iter() {
|
||||
for source in method.provided_source.iter() {
|
||||
tcx.provided_method_sources.insert(method.def_id, *source);
|
||||
}
|
||||
}
|
||||
|
||||
// If this is an inherent implementation, record it.
|
||||
if associated_traits.is_none() {
|
||||
let implementation_list;
|
||||
match tcx.inherent_impls.find(&type_id) {
|
||||
None => {
|
||||
implementation_list = @mut ~[];
|
||||
tcx.inherent_impls.insert(type_id, implementation_list);
|
||||
}
|
||||
Some(&existing_implementation_list) => {
|
||||
implementation_list = existing_implementation_list;
|
||||
}
|
||||
}
|
||||
implementation_list.push(implementation);
|
||||
}
|
||||
|
||||
// Store the implementation info.
|
||||
tcx.impls.insert(implementation_def_id, implementation);
|
||||
}
|
||||
|
||||
tcx.populated_external_types.insert(type_id);
|
||||
}
|
||||
|
||||
/// Populates the type context with all the implementations for the given
|
||||
/// trait if necessary.
|
||||
pub fn populate_implementations_for_trait_if_necessary(
|
||||
tcx: ctxt,
|
||||
trait_id: ast::def_id) {
|
||||
if trait_id.crate == LOCAL_CRATE {
|
||||
return
|
||||
}
|
||||
if tcx.populated_external_traits.contains(&trait_id) {
|
||||
return
|
||||
}
|
||||
|
||||
do csearch::each_implementation_for_trait(tcx.sess.cstore, trait_id)
|
||||
|implementation_def_id| {
|
||||
let implementation = @csearch::get_impl(tcx, implementation_def_id);
|
||||
|
||||
// Record the trait->implementation mapping.
|
||||
record_trait_implementation(tcx, trait_id, implementation);
|
||||
|
||||
// For any methods that use a default implementation, add them to
|
||||
// the map. This is a bit unfortunate.
|
||||
for method in implementation.methods.iter() {
|
||||
for source in method.provided_source.iter() {
|
||||
tcx.provided_method_sources.insert(method.def_id, *source);
|
||||
}
|
||||
}
|
||||
|
||||
// Store the implementation info.
|
||||
tcx.impls.insert(implementation_def_id, implementation);
|
||||
}
|
||||
|
||||
tcx.populated_external_traits.insert(trait_id);
|
||||
}
|
||||
|
||||
/// If the given def ID describes a trait method, returns the ID of the trait
|
||||
/// that the method belongs to. Otherwise, returns `None`.
|
||||
pub fn trait_of_method(tcx: ctxt, def_id: ast::def_id)
|
||||
-> Option<ast::def_id> {
|
||||
match tcx.methods.find(&def_id) {
|
||||
Some(method_descriptor) => {
|
||||
match method_descriptor.container {
|
||||
TraitContainer(id) => return Some(id),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
// If the method was in the local crate, then if we got here we know the
|
||||
// answer is negative.
|
||||
if def_id.crate == LOCAL_CRATE {
|
||||
return None
|
||||
}
|
||||
|
||||
let result = csearch::get_trait_of_method(tcx.cstore, def_id, tcx);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
|
@ -350,6 +350,10 @@ impl<'self> LookupContext<'self> {
|
||||
let opt_applicable_traits = trait_map.find(&self.expr.id);
|
||||
for applicable_traits in opt_applicable_traits.iter() {
|
||||
for trait_did in applicable_traits.iter() {
|
||||
ty::populate_implementations_for_trait_if_necessary(
|
||||
self.tcx(),
|
||||
*trait_did);
|
||||
|
||||
// Look for explicit implementations.
|
||||
let opt_impl_infos = self.tcx().trait_impls.find(trait_did);
|
||||
for impl_infos in opt_impl_infos.iter() {
|
||||
@ -534,6 +538,10 @@ impl<'self> LookupContext<'self> {
|
||||
|
||||
|
||||
fn push_inherent_impl_candidates_for_type(&self, did: def_id) {
|
||||
// Read the inherent implementation candidates for this type from the
|
||||
// metadata if necessary.
|
||||
ty::populate_implementations_for_type_if_necessary(self.tcx(), did);
|
||||
|
||||
let opt_impl_infos = self.tcx().inherent_impls.find(&did);
|
||||
for impl_infos in opt_impl_infos.iter() {
|
||||
for impl_info in impl_infos.iter() {
|
||||
|
@ -136,6 +136,9 @@ fn lookup_vtables_for_param(vcx: &VtableContext,
|
||||
// ...and here trait_ref is each bound that was declared on A,
|
||||
// expressed in terms of the type parameters.
|
||||
|
||||
ty::populate_implementations_for_trait_if_necessary(tcx,
|
||||
trait_ref.def_id);
|
||||
|
||||
// Substitute the values of the type parameters that may
|
||||
// appear in the bound.
|
||||
let trait_ref = substs.map_default(trait_ref, |substs| {
|
||||
@ -321,6 +324,10 @@ fn search_for_vtable(vcx: &VtableContext,
|
||||
let mut found = ~[];
|
||||
let mut impls_seen = HashSet::new();
|
||||
|
||||
// Load the implementations from external metadata if necessary.
|
||||
ty::populate_implementations_for_trait_if_necessary(tcx,
|
||||
trait_ref.def_id);
|
||||
|
||||
// XXX: this is a bad way to do this, since we do
|
||||
// pointless allocations.
|
||||
let impls = tcx.trait_impls.find(&trait_ref.def_id)
|
||||
|
@ -19,7 +19,7 @@ use metadata::csearch::{each_impl, get_impl_trait};
|
||||
use metadata::csearch;
|
||||
use metadata::cstore::iter_crate_data;
|
||||
use middle::ty::get;
|
||||
use middle::ty::{lookup_item_type, subst};
|
||||
use middle::ty::{ImplContainer, lookup_item_type, subst};
|
||||
use middle::ty::{substs, t, ty_bool, ty_bot, ty_box, ty_enum, ty_err};
|
||||
use middle::ty::{ty_estr, ty_evec, ty_float, ty_infer, ty_int, ty_nil};
|
||||
use middle::ty::{ty_opaque_box, ty_param, ty_param_bounds_and_ty, ty_ptr};
|
||||
@ -42,13 +42,12 @@ use syntax::ast;
|
||||
use syntax::ast_map::node_item;
|
||||
use syntax::ast_map;
|
||||
use syntax::ast_util::{def_id_of_def, local_def};
|
||||
use syntax::codemap::{span, dummy_sp};
|
||||
use syntax::codemap::span;
|
||||
use syntax::opt_vec;
|
||||
use syntax::visit;
|
||||
use syntax::parse;
|
||||
use util::ppaux::ty_to_str;
|
||||
|
||||
use std::hashmap::{HashMap, HashSet};
|
||||
use std::hashmap::HashSet;
|
||||
use std::result::Ok;
|
||||
use std::vec;
|
||||
|
||||
@ -149,19 +148,12 @@ pub fn CoherenceChecker(crate_context: @mut CrateCtxt) -> CoherenceChecker {
|
||||
CoherenceChecker {
|
||||
crate_context: crate_context,
|
||||
inference_context: new_infer_ctxt(crate_context.tcx),
|
||||
|
||||
base_type_def_ids: @mut HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CoherenceChecker {
|
||||
crate_context: @mut CrateCtxt,
|
||||
inference_context: @mut InferCtxt,
|
||||
|
||||
// A mapping from implementations to the corresponding base type
|
||||
// definition ID.
|
||||
|
||||
base_type_def_ids: @mut HashMap<def_id,def_id>,
|
||||
}
|
||||
|
||||
struct CoherenceCheckVisitor { cc: CoherenceChecker }
|
||||
@ -320,9 +312,6 @@ impl CoherenceChecker {
|
||||
if associated_traits.len() == 0 {
|
||||
self.add_inherent_impl(base_type_def_id, implementation);
|
||||
}
|
||||
|
||||
self.base_type_def_ids.insert(local_def(item.id),
|
||||
base_type_def_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -686,25 +675,11 @@ impl CoherenceChecker {
|
||||
}
|
||||
// Good. Continue.
|
||||
|
||||
let self_type = lookup_item_type(tcx, implementation.did);
|
||||
let associated_traits = get_impl_trait(tcx,
|
||||
implementation.did);
|
||||
let _ = lookup_item_type(tcx, implementation.did);
|
||||
let associated_traits = get_impl_trait(tcx, implementation.did);
|
||||
|
||||
// Do a sanity check to make sure that inherent methods have base
|
||||
// types.
|
||||
if associated_traits.is_none() {
|
||||
match get_base_type_def_id(self.inference_context,
|
||||
dummy_sp(),
|
||||
self_type.ty) {
|
||||
None => {
|
||||
tcx.sess.bug(fmt!("no base type for external impl with no \
|
||||
trait: %s (type %s)!",
|
||||
tcx.sess.str_of(implementation.ident),
|
||||
ty_to_str(tcx, self_type.ty)));
|
||||
}
|
||||
Some(_) => {} // Nothing to do.
|
||||
}
|
||||
}
|
||||
// Do a sanity check.
|
||||
assert!(associated_traits.is_some());
|
||||
|
||||
// Record all the trait methods.
|
||||
for trait_ref in associated_traits.iter() {
|
||||
@ -719,25 +694,6 @@ impl CoherenceChecker {
|
||||
}
|
||||
}
|
||||
|
||||
// Add the implementation to the mapping from implementation to base
|
||||
// type def ID, if there is a base type for this implementation.
|
||||
match get_base_type_def_id(self.inference_context,
|
||||
dummy_sp(),
|
||||
self_type.ty) {
|
||||
None => {} // Nothing to do.
|
||||
Some(base_type_def_id) => {
|
||||
// inherent methods apply to `impl Type` but not
|
||||
// `impl Trait for Type`:
|
||||
if associated_traits.is_none() {
|
||||
self.add_inherent_impl(base_type_def_id,
|
||||
implementation);
|
||||
}
|
||||
|
||||
self.base_type_def_ids.insert(implementation.did,
|
||||
base_type_def_id);
|
||||
}
|
||||
}
|
||||
|
||||
tcx.impls.insert(implementation.did, implementation);
|
||||
}
|
||||
|
||||
@ -883,7 +839,7 @@ fn subst_receiver_types_in_method_ty(tcx: ty::ctxt,
|
||||
method.explicit_self,
|
||||
method.vis,
|
||||
new_def_id,
|
||||
impl_id,
|
||||
ImplContainer(impl_id),
|
||||
provided_source
|
||||
)
|
||||
}
|
||||
|
@ -32,7 +32,8 @@ are represented as `ty_param()` instances.
|
||||
|
||||
|
||||
use metadata::csearch;
|
||||
use middle::ty::{substs, ty_param_bounds_and_ty};
|
||||
use middle::ty::{ImplContainer, MethodContainer, TraitContainer, substs};
|
||||
use middle::ty::{ty_param_bounds_and_ty};
|
||||
use middle::ty;
|
||||
use middle::subst::Subst;
|
||||
use middle::typeck::astconv::{AstConv, ty_of_arg};
|
||||
@ -388,7 +389,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
|
||||
// assume public, because this is only invoked on trait methods
|
||||
ast::public,
|
||||
local_def(*m_id),
|
||||
local_def(trait_id),
|
||||
TraitContainer(local_def(trait_id)),
|
||||
None
|
||||
)
|
||||
}
|
||||
@ -744,7 +745,7 @@ pub struct ConvertedMethod {
|
||||
}
|
||||
|
||||
pub fn convert_methods(ccx: &CrateCtxt,
|
||||
container_id: ast::NodeId,
|
||||
container: MethodContainer,
|
||||
ms: &[@ast::method],
|
||||
untransformed_rcvr_ty: ty::t,
|
||||
rcvr_ty_generics: &ty::Generics,
|
||||
@ -758,11 +759,14 @@ pub fn convert_methods(ccx: &CrateCtxt,
|
||||
let m_ty_generics =
|
||||
ty_generics(ccx, rcvr_ty_generics.region_param, &m.generics,
|
||||
num_rcvr_ty_params);
|
||||
let mty =
|
||||
@ty_of_method(ccx, container_id, *m, rcvr_ty_generics.region_param,
|
||||
untransformed_rcvr_ty,
|
||||
rcvr_ast_generics, rcvr_visibility,
|
||||
&m.generics);
|
||||
let mty = @ty_of_method(ccx,
|
||||
container,
|
||||
*m,
|
||||
rcvr_ty_generics.region_param,
|
||||
untransformed_rcvr_ty,
|
||||
rcvr_ast_generics,
|
||||
rcvr_visibility,
|
||||
&m.generics);
|
||||
let fty = ty::mk_bare_fn(tcx, mty.fty.clone());
|
||||
tcx.tcache.insert(
|
||||
local_def(m.id),
|
||||
@ -785,7 +789,7 @@ pub fn convert_methods(ccx: &CrateCtxt,
|
||||
}).collect();
|
||||
|
||||
fn ty_of_method(ccx: &CrateCtxt,
|
||||
container_id: ast::NodeId,
|
||||
container: MethodContainer,
|
||||
m: &ast::method,
|
||||
rp: Option<ty::region_variance>,
|
||||
untransformed_rcvr_ty: ty::t,
|
||||
@ -817,7 +821,7 @@ pub fn convert_methods(ccx: &CrateCtxt,
|
||||
m.explicit_self.node,
|
||||
method_vis,
|
||||
local_def(m.id),
|
||||
local_def(container_id),
|
||||
container,
|
||||
None
|
||||
)
|
||||
}
|
||||
@ -877,8 +881,12 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) {
|
||||
it.vis
|
||||
};
|
||||
|
||||
let cms = convert_methods(ccx, it.id, *ms, selfty,
|
||||
&i_ty_generics, generics,
|
||||
let cms = convert_methods(ccx,
|
||||
ImplContainer(local_def(it.id)),
|
||||
*ms,
|
||||
selfty,
|
||||
&i_ty_generics,
|
||||
generics,
|
||||
parent_visibility);
|
||||
for t in opt_trait_ref.iter() {
|
||||
// Prevent the builtin kind traits from being manually implemented.
|
||||
@ -901,9 +909,12 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) {
|
||||
let untransformed_rcvr_ty = ty::mk_self(tcx, local_def(it.id));
|
||||
let (ty_generics, _) = mk_item_substs(ccx, generics, rp,
|
||||
Some(untransformed_rcvr_ty));
|
||||
let _ = convert_methods(ccx, it.id, provided_methods,
|
||||
let _ = convert_methods(ccx,
|
||||
TraitContainer(local_def(it.id)),
|
||||
provided_methods,
|
||||
untransformed_rcvr_ty,
|
||||
&ty_generics, generics,
|
||||
&ty_generics,
|
||||
generics,
|
||||
it.vis);
|
||||
|
||||
// We need to do this *after* converting methods, since
|
||||
|
Loading…
Reference in New Issue
Block a user