From a8f039a085c7d7622899b7a4d1bebfe2d7621165 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 11 Feb 2013 16:28:39 -0800 Subject: [PATCH] librustc: Make monomorphic newtype structs work cross-crate --- src/librustc/metadata/common.rs | 2 + src/librustc/metadata/csearch.rs | 5 +- src/librustc/metadata/decoder.rs | 24 ++++++--- src/librustc/metadata/encoder.rs | 69 +++++++++++++++++-------- src/librustc/middle/resolve.rs | 17 ++++-- src/librustc/middle/trans/base.rs | 9 +++- src/librustc/middle/trans/reachable.rs | 3 ++ src/librustc/middle/ty.rs | 2 +- src/librustc/middle/typeck/coherence.rs | 2 +- src/test/auxiliary/newtype_struct_xc.rs | 4 ++ src/test/run-pass/newtype-struct-xc.rs | 9 ++++ 11 files changed, 109 insertions(+), 37 deletions(-) create mode 100644 src/test/auxiliary/newtype_struct_xc.rs create mode 100644 src/test/run-pass/newtype-struct-xc.rs diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 37c19e80600..62bfdf4c3aa 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -153,5 +153,7 @@ pub const tag_lang_items_item: uint = 0x73; pub const tag_lang_items_item_id: uint = 0x74; pub const tag_lang_items_item_node_id: uint = 0x75; +pub const tag_item_unnamed_field: uint = 0x76; + pub type link_meta = {name: @str, vers: @str, extras_hash: @str}; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 2cb5cfbddd7..fa82e6c92c0 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -166,8 +166,9 @@ pub fn get_item_attrs(cstore: @mut cstore::CStore, decoder::get_item_attrs(cdata, def_id.node, f) } -pub fn get_struct_fields(tcx: ty::ctxt, def: ast::def_id) -> ~[ty::field_ty] { - let cstore = tcx.cstore; +pub fn get_struct_fields(cstore: @mut cstore::CStore, + def: ast::def_id) + -> ~[ty::field_ty] { let cdata = cstore::get_crate_data(cstore, def.crate); decoder::get_struct_fields(cstore.intr, cdata, def.node) } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 67498ad5aaf..14dda962282 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -42,7 +42,7 @@ use std::serialize::Decodable; use syntax::ast_map; use syntax::attr; use syntax::diagnostic::span_handler; -use syntax::parse::token::ident_interner; +use syntax::parse::token::{ident_interner, special_idents}; use syntax::print::pprust; use syntax::{ast, ast_util}; use syntax::codemap; @@ -231,7 +231,9 @@ pub fn item_type(item_id: ast::def_id, item: ebml::Doc, let t = doc_type(item, tcx, cdata); if family_names_type(item_family(item)) { ty::mk_with_id(tcx, t, item_id) - } else { t } + } else { + t + } } fn item_impl_traits(item: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ~[ty::t] { @@ -661,11 +663,12 @@ fn item_impl_methods(intr: @ident_interner, cdata: cmd, item: ebml::Doc, rslt } -pub fn get_impls_for_mod(intr: @ident_interner, cdata: cmd, - m_id: ast::node_id, name: Option, - get_cdata: fn(ast::crate_num) -> cmd) +pub fn get_impls_for_mod(intr: @ident_interner, + cdata: cmd, + m_id: ast::node_id, + name: Option, + get_cdata: &fn(ast::crate_num) -> cmd) -> @~[@_impl] { - let data = cdata.data; let mod_item = lookup_item(m_id, data); let mut result = ~[]; @@ -887,6 +890,15 @@ pub fn get_struct_fields(intr: @ident_interner, cdata: cmd, id: ast::node_id) }); } } + for reader::tagged_docs(item, tag_item_unnamed_field) |an_item| { + let did = item_def_id(an_item, cdata); + result.push(ty::field_ty { + ident: special_idents::unnamed_field, + id: did, + vis: ast::inherited, + mutability: ast::struct_immutable, + }); + } result } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index fcc1a4e806d..e6dcf17f34c 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -46,6 +46,7 @@ use syntax::ast_map; use syntax::ast_util::*; use syntax::attr; use syntax::diagnostic::span_handler; +use syntax::parse::token::special_idents; use syntax::print::pprust; use syntax::{ast_util, visit}; use syntax; @@ -328,7 +329,7 @@ fn encode_info_for_mod(ecx: @encode_ctxt, ebml_w: writer::Encoder, // Encode info about all the module children. for md.items.each |item| { match item.node { - item_impl(*) | item_struct(*) => { + item_impl(*) => { let (ident, did) = (item.ident, item.id); debug!("(encoding info for module) ... encoding impl %s \ (%?/%?)", @@ -432,25 +433,28 @@ fn encode_info_for_struct(ecx: @encode_ctxt, ebml_w: writer::Encoder, /* We encode both private and public fields -- need to include private fields to get the offsets right */ for fields.each |field| { - match field.node.kind { - named_field(nm, mt, vis) => { - let id = field.node.id; - index.push({val: id, pos: ebml_w.writer.tell()}); - global_index.push({val: id, - pos: ebml_w.writer.tell()}); - ebml_w.start_tag(tag_items_data_item); - debug!("encode_info_for_struct: doing %s %d", - tcx.sess.str_of(nm), id); - encode_visibility(ebml_w, vis); - encode_name(ecx, ebml_w, nm); - encode_path(ecx, ebml_w, path, ast_map::path_name(nm)); - encode_type(ecx, ebml_w, node_id_to_type(tcx, id)); - encode_mutability(ebml_w, mt); - encode_def_id(ebml_w, local_def(id)); - ebml_w.end_tag(); - } - unnamed_field => {} - } + let (nm, mt, vis) = match field.node.kind { + named_field(nm, mt, vis) => (nm, mt, vis), + unnamed_field => ( + special_idents::unnamed_field, + struct_immutable, + inherited + ) + }; + + let id = field.node.id; + index.push({val: id, pos: ebml_w.writer.tell()}); + global_index.push({val: id, pos: ebml_w.writer.tell()}); + ebml_w.start_tag(tag_items_data_item); + debug!("encode_info_for_struct: doing %s %d", + tcx.sess.str_of(nm), id); + encode_visibility(ebml_w, vis); + encode_name(ecx, ebml_w, nm); + encode_path(ecx, ebml_w, path, ast_map::path_name(nm)); + encode_type(ecx, ebml_w, node_id_to_type(tcx, id)); + encode_mutability(ebml_w, mt); + encode_def_id(ebml_w, local_def(id)); + ebml_w.end_tag(); } /*bad*/copy *index } @@ -673,7 +677,24 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: writer::Encoder, encode_def_id(ebml_w, local_def(item.id)); encode_family(ebml_w, 'S'); encode_type_param_bounds(ebml_w, ecx, tps); - encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); + + // If this is a tuple- or enum-like struct, encode the type of the + // constructor. Otherwise, encode the type of the struct. + if struct_def.fields.len() > 0 && + struct_def.fields[0].node.kind == ast::unnamed_field { + // Tuple- or enum-like struct. + let ctor_id = match struct_def.ctor_id { + Some(ctor_id) => ctor_id, + None => ecx.tcx.sess.bug(~"struct def didn't have ctor id"), + }; + encode_type(ecx, ebml_w, node_id_to_type(tcx, ctor_id)); + + // Also encode the symbol. + encode_symbol(ecx, ebml_w, ctor_id); + } else { + encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); + } + encode_name(ecx, ebml_w, item.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); encode_region_param(ecx, ebml_w, item); @@ -697,7 +718,11 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: writer::Encoder, encode_def_id(ebml_w, local_def(f.node.id)); ebml_w.end_tag(); } - unnamed_field => {} + unnamed_field => { + ebml_w.start_tag(tag_item_unnamed_field); + encode_def_id(ebml_w, local_def(f.node.id)); + ebml_w.end_tag(); + } } } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index ba550dbbde8..14e27f328d1 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -13,7 +13,8 @@ use core::prelude::*; use driver::session; use driver::session::Session; use metadata::csearch::{each_path, get_method_names_if_trait}; -use metadata::csearch::{get_static_methods_if_impl, get_type_name_if_impl}; +use metadata::csearch::{get_static_methods_if_impl, get_struct_fields}; +use metadata::csearch::{get_type_name_if_impl}; use metadata::cstore::find_use_stmt_cnum; use metadata::decoder::{def_like, dl_def, dl_field, dl_impl}; use middle::lang_items::LanguageItems; @@ -1659,6 +1660,14 @@ pub impl Resolver { crate) building type %s", final_ident); child_name_bindings.define_type(Public, def, dummy_sp()); + + // Define the struct constructor if this is a tuple-like struct. + let fields = get_struct_fields(self.session.cstore, def_id); + if fields.len() != 0 && + fields[0].ident == special_idents::unnamed_field { + child_name_bindings.define_value(Public, def, dummy_sp()); + } + self.structs.insert(def_id, ()); } def_self(*) | def_arg(*) | def_local(*) | @@ -1745,10 +1754,12 @@ pub impl Resolver { OverwriteDuplicates, dummy_sp()); - self.handle_external_def(def, modules, + self.handle_external_def(def, + modules, child_name_bindings, self.session.str_of(final_ident), - final_ident, new_parent); + final_ident, + new_parent); } dl_impl(def) => { // We only process static methods of impls here. diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index ced47bb5681..c61ff7d5e02 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1905,8 +1905,13 @@ pub fn trans_tuple_struct(ccx: @crate_ctxt, } }; - let fcx = new_fn_ctxt_w_id(ccx, ~[], llfndecl, ctor_id, None, - param_substs, None); + let fcx = new_fn_ctxt_w_id(ccx, + ~[], + llfndecl, + ctor_id, + None, + param_substs, + None); // XXX: Bad copy. let raw_llargs = create_llargs_for_fn_args(fcx, no_self, copy fn_args); diff --git a/src/librustc/middle/trans/reachable.rs b/src/librustc/middle/trans/reachable.rs index f77aa33407d..bf417e9a5f4 100644 --- a/src/librustc/middle/trans/reachable.rs +++ b/src/librustc/middle/trans/reachable.rs @@ -122,6 +122,9 @@ fn traverse_public_item(cx: ctx, item: @item) { } } item_struct(struct_def, tps) => { + for struct_def.ctor_id.each |&ctor_id| { + cx.rmap.insert(ctor_id, ()); + } do option::iter(&struct_def.dtor) |dtor| { cx.rmap.insert(dtor.node.id, ()); if tps.len() > 0u || attr::find_inline_attr(dtor.node.attrs) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 4350c62af6f..136a2f05565 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4011,7 +4011,7 @@ pub fn lookup_struct_fields(cx: ctxt, did: ast::def_id) -> ~[field_ty] { } } else { - return csearch::get_struct_fields(cx, did); + return csearch::get_struct_fields(cx.sess.cstore, did); } } diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 5e51c216093..fdf936f7aec 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -828,7 +828,7 @@ pub impl CoherenceChecker { let implementations = get_impls_for_mod(crate_store, module_def_id, None); - for (*implementations).each |implementation| { + for implementations.each |implementation| { debug!("coherence: adding impl from external crate: %s", ty::item_path_str(self.crate_context.tcx, implementation.did)); diff --git a/src/test/auxiliary/newtype_struct_xc.rs b/src/test/auxiliary/newtype_struct_xc.rs new file mode 100644 index 00000000000..90036e0f96c --- /dev/null +++ b/src/test/auxiliary/newtype_struct_xc.rs @@ -0,0 +1,4 @@ +#[crate_type="lib"]; + +pub struct Au(int); + diff --git a/src/test/run-pass/newtype-struct-xc.rs b/src/test/run-pass/newtype-struct-xc.rs new file mode 100644 index 00000000000..8b15d73dc93 --- /dev/null +++ b/src/test/run-pass/newtype-struct-xc.rs @@ -0,0 +1,9 @@ +// xfail-fast +// aux-build:newtype_struct_xc.rs + +extern mod newtype_struct_xc; + +fn main() { + let _ = newtype_struct_xc::Au(2); +} +