From 002bfd796648547839d0f3740308995b4a926f50 Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Thu, 11 Jul 2013 17:07:57 -0700 Subject: [PATCH] Export information about used default methods instead of regenerating it. Closes #7862. --- src/librustc/metadata/decoder.rs | 9 +++++- src/librustc/metadata/encoder.rs | 28 +++++++++++++++---- src/librustc/middle/typeck/coherence.rs | 23 ++++++--------- .../trait_default_method_xc_aux_2.rs | 17 +++++++++++ .../run-pass/trait-default-method-xc-2.rs | 25 +++++++++++++++++ 5 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 src/test/auxiliary/trait_default_method_xc_aux_2.rs create mode 100644 src/test/run-pass/trait-default-method-xc-2.rs diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 6604ef5df34..a77c6c6ab52 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -185,6 +185,12 @@ fn item_def_id(d: ebml::Doc, cdata: cmd) -> ast::def_id { return translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id)); } +fn get_provided_source(d: ebml::Doc, cdata: cmd) -> Option { + do reader::maybe_get_doc(d, tag_item_method_provided_source).map |doc| { + translate_def_id(cdata, reader::with_doc_data(*doc, parse_def_id)) + } +} + fn each_reexport(d: ebml::Doc, f: &fn(ebml::Doc) -> bool) -> bool { for reader::tagged_docs(d, tag_items_data_item_reexport) |reexport_doc| { if !f(reexport_doc) { @@ -844,6 +850,7 @@ pub fn get_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, let fty = doc_method_fty(method_doc, tcx, cdata); let vis = item_visibility(method_doc); let explicit_self = get_explicit_self(method_doc); + let provided_source = get_provided_source(method_doc, cdata); ty::Method::new( name, @@ -857,7 +864,7 @@ pub fn get_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, vis, def_id, container_id, - None + provided_source ) } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 8fda0fff27d..2ef00a2167f 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -650,6 +650,16 @@ fn encode_method_sort(ebml_w: &mut writer::Encoder, sort: char) { ebml_w.end_tag(); } +fn encode_provided_source(ebml_w: &mut writer::Encoder, + source_opt: Option) { + for source_opt.iter().advance |source| { + ebml_w.start_tag(tag_item_method_provided_source); + let s = def_to_str(*source); + ebml_w.writer.write(s.as_bytes()); + ebml_w.end_tag(); + } +} + /* Returns an index of items in this class */ fn encode_info_for_struct(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, @@ -726,6 +736,7 @@ fn encode_method_ty_fields(ecx: &EncodeContext, } _ => encode_family(ebml_w, purity_fn_family(purity)) } + encode_provided_source(ebml_w, method_ty.provided_source); } fn encode_info_for_method(ecx: &EncodeContext, @@ -987,7 +998,6 @@ fn encode_info_for_item(ecx: &EncodeContext, _ => {} } for imp.methods.iter().advance |method| { - if method.provided_source.is_some() { loop; } ebml_w.start_tag(tag_item_impl_method); let s = def_to_str(method.def_id); ebml_w.writer.write(s.as_bytes()); @@ -1005,16 +1015,24 @@ fn encode_info_for_item(ecx: &EncodeContext, let mut impl_path = vec::append(~[], path); impl_path.push(ast_map::path_name(item.ident)); - for ast_methods.iter().advance |ast_method| { - let m = ty::method(ecx.tcx, local_def(ast_method.id)); + // Iterate down the methods, emitting them. We rely on the + // assumption that all of the actually implemented methods + // appear first in the impl structure, in the same order they do + // in the ast. This is a little sketchy. + let num_implemented_methods = ast_methods.len(); + for imp.methods.iter().enumerate().advance |(i, m)| { + let ast_method = if i < num_implemented_methods { + Some(ast_methods[i]) + } else { None }; + index.push(entry {val: m.def_id.node, pos: ebml_w.writer.tell()}); encode_info_for_method(ecx, ebml_w, - m, + *m, impl_path, false, item.id, - Some(*ast_method)); + ast_method) } } item_trait(_, ref super_traits, ref ms) => { diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 51b206428e3..c8225365864 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -664,7 +664,7 @@ impl CoherenceChecker { impls_seen: &mut HashSet, impl_def_id: def_id) { let tcx = self.crate_context.tcx; - let implementation = csearch::get_impl(tcx, impl_def_id); + let implementation = @csearch::get_impl(tcx, impl_def_id); debug!("coherence: adding impl from external crate: %s", ty::item_path_str(tcx, implementation.did)); @@ -697,21 +697,16 @@ impl CoherenceChecker { } // Record all the trait methods. - let mut implementation = @implementation; for associated_traits.iter().advance |trait_ref| { - // XXX(sully): We could probably avoid this copy if there are no - // default methods. - let mut methods = implementation.methods.clone(); - self.instantiate_default_methods(implementation.did, - *trait_ref, - &mut methods); + self.add_trait_impl(trait_ref.def_id, implementation); + } - implementation = @Impl { - methods: methods, - ..*implementation - }; - - self.add_trait_impl(trait_ref.def_id, implementation); + // For any methods that use a default implementation, add them to + // the map. This is a bit unfortunate. + for implementation.methods.iter().advance |method| { + for method.provided_source.iter().advance |source| { + tcx.provided_method_sources.insert(method.def_id, *source); + } } // Add the implementation to the mapping from implementation to base diff --git a/src/test/auxiliary/trait_default_method_xc_aux_2.rs b/src/test/auxiliary/trait_default_method_xc_aux_2.rs new file mode 100644 index 00000000000..2d4f539f82b --- /dev/null +++ b/src/test/auxiliary/trait_default_method_xc_aux_2.rs @@ -0,0 +1,17 @@ +// aux-build:trait_default_method_xc_aux.rs + +extern mod aux(name = "trait_default_method_xc_aux"); +use aux::A; + +pub struct a_struct { x: int } + +impl A for a_struct { + fn f(&self) -> int { 10 } +} + +// This function will need to get inlined, and badness may result. +pub fn welp(x: A) -> A { + let a = a_struct { x: 0 }; + a.g(); + x +} diff --git a/src/test/run-pass/trait-default-method-xc-2.rs b/src/test/run-pass/trait-default-method-xc-2.rs new file mode 100644 index 00000000000..1dad5d23b88 --- /dev/null +++ b/src/test/run-pass/trait-default-method-xc-2.rs @@ -0,0 +1,25 @@ +// xfail-fast +// aux-build:trait_default_method_xc_aux.rs +// aux-build:trait_default_method_xc_aux_2.rs + + +extern mod aux(name = "trait_default_method_xc_aux"); +extern mod aux2(name = "trait_default_method_xc_aux_2"); +use aux::A; +use aux2::{a_struct, welp}; + + +fn main () { + + let a = a_struct { x: 0 }; + let b = a_struct { x: 1 }; + + assert_eq!(0i.g(), 10); + assert_eq!(a.g(), 10); + assert_eq!(a.h(), 11); + assert_eq!(b.g(), 10); + assert_eq!(b.h(), 11); + assert_eq!(A::lurr(&a, &b), 21); + + welp(&0); +}