Skip to content

Commit

Permalink
Allow inheritance between structs.
Browse files Browse the repository at this point in the history
No subtyping, no interaction with traits. Partially addresses rust-lang#9912.
  • Loading branch information
nrc committed Apr 20, 2014
1 parent 3757f01 commit ff04aa8
Show file tree
Hide file tree
Showing 30 changed files with 803 additions and 208 deletions.
16 changes: 16 additions & 0 deletions src/doc/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,22 @@ struct Cookie;
let c = [Cookie, Cookie, Cookie, Cookie];
~~~~

By using the `struct_inherit` feature gate, structures may use single inheritance. A Structure may only
inherit from a single other structure, called the _super-struct_. The inheriting structure (sub-struct)
acts as if all fields in the super-struct were present in the sub-struct. Fields declared in a sub-struct
must not have the same name as any field in any (transitive) super-struct. All fields (both declared
and inherited) must be specified in any initializers. Inheritance between structures does not give
subtyping or coercion. The super-struct and sub-struct must be defined in the same crate. The super-struct
must be declared using the `virtual` keyword.
For example:

~~~~ {.ignore}
virtual struct Sup { x: int }
struct Sub : Sup { y: int }
let s = Sub {x: 10, y: 11};
let sx = s.x;
~~~~

### Enumerations

An _enumeration_ is a simultaneous definition of a nominal [enumerated type](#enumerated-types) as well as a set of *constructors*,
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/front/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ fn fold_struct(cx: &Context, def: &ast::StructDef) -> @ast::StructDef {
@ast::StructDef {
fields: fields.collect(),
ctor_id: def.ctor_id,
super_struct: def.super_struct.clone(),
is_virtual: def.is_virtual,
}
}

Expand Down
14 changes: 13 additions & 1 deletion src/librustc/front/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
("default_type_params", Active),
("quote", Active),
("linkage", Active),
("struct_inherit", Active),

// These are used to test this portion of the compiler, they don't actually
// mean anything
Expand Down Expand Up @@ -190,11 +191,22 @@ impl<'a> Visitor<()> for Context<'a> {
}
}

ast::ItemStruct(..) => {
ast::ItemStruct(struct_definition, _) => {
if attr::contains_name(i.attrs.as_slice(), "simd") {
self.gate_feature("simd", i.span,
"SIMD types are experimental and possibly buggy");
}
match struct_definition.super_struct {
Some(ref path) => self.gate_feature("struct_inherit", path.span,
"struct inheritance is experimental \
and possibly buggy"),
None => {}
}
if struct_definition.is_virtual {
self.gate_feature("struct_inherit", i.span,
"struct inheritance (`virtual` keyword) is \
experimental and possibly buggy");
}
}

_ => {}
Expand Down
117 changes: 59 additions & 58 deletions src/librustc/metadata/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ pub static tag_path_len: uint = 0x25;
pub static tag_path_elem_mod: uint = 0x26;
pub static tag_path_elem_name: uint = 0x27;
pub static tag_item_field: uint = 0x28;
pub static tag_item_field_origin: uint = 0x29;

pub static tag_item_variances: uint = 0x2a;
/*
Expand All @@ -102,43 +103,43 @@ pub static tag_item_variances: uint = 0x2a;
both, tag_item_trait_method and tag_item_impl_method have to be two
different tags.
*/
pub static tag_item_impl_method: uint = 0x2c;
pub static tag_item_trait_method_explicit_self: uint = 0x2d;
pub static tag_item_impl_method: uint = 0x30;
pub static tag_item_trait_method_explicit_self: uint = 0x31;


// Reexports are found within module tags. Each reexport contains def_ids
// and names.
pub static tag_items_data_item_reexport: uint = 0x2f;
pub static tag_items_data_item_reexport_def_id: uint = 0x30;
pub static tag_items_data_item_reexport_name: uint = 0x31;
pub static tag_items_data_item_reexport: uint = 0x38;
pub static tag_items_data_item_reexport_def_id: uint = 0x39;
pub static tag_items_data_item_reexport_name: uint = 0x3a;

// used to encode crate_ctxt side tables
#[deriving(Eq)]
#[repr(uint)]
pub enum astencode_tag { // Reserves 0x32 -- 0x45
tag_ast = 0x32,

tag_tree = 0x33,

tag_id_range = 0x34,

tag_table = 0x35,
tag_table_id = 0x36,
tag_table_val = 0x37,
tag_table_def = 0x38,
tag_table_node_type = 0x39,
tag_table_node_type_subst = 0x3a,
tag_table_freevars = 0x3b,
tag_table_tcache = 0x3c,
tag_table_param_defs = 0x3d,
tag_table_mutbl = 0x3e,
tag_table_last_use = 0x3f,
tag_table_spill = 0x40,
tag_table_method_map = 0x41,
tag_table_vtable_map = 0x42,
tag_table_adjustments = 0x43,
tag_table_moves_map = 0x44,
tag_table_capture_map = 0x45
pub enum astencode_tag { // Reserves 0x40 -- 0x5f
tag_ast = 0x40,

tag_tree = 0x41,

tag_id_range = 0x42,

tag_table = 0x43,
tag_table_id = 0x44,
tag_table_val = 0x45,
tag_table_def = 0x46,
tag_table_node_type = 0x47,
tag_table_node_type_subst = 0x48,
tag_table_freevars = 0x49,
tag_table_tcache = 0x4a,
tag_table_param_defs = 0x4b,
tag_table_mutbl = 0x4c,
tag_table_last_use = 0x4d,
tag_table_spill = 0x4e,
tag_table_method_map = 0x4f,
tag_table_vtable_map = 0x50,
tag_table_adjustments = 0x51,
tag_table_moves_map = 0x52,
tag_table_capture_map = 0x53
}
static first_astencode_tag: uint = tag_ast as uint;
static last_astencode_tag: uint = tag_table_capture_map as uint;
Expand All @@ -151,9 +152,9 @@ impl astencode_tag {
}
}

pub static tag_item_trait_method_sort: uint = 0x46;
pub static tag_item_trait_method_sort: uint = 0x60;

pub static tag_item_impl_type_basename: uint = 0x47;
pub static tag_item_impl_type_basename: uint = 0x61;

// Language items are a top-level directory (for speed). Hierarchy:
//
Expand All @@ -162,42 +163,42 @@ pub static tag_item_impl_type_basename: uint = 0x47;
// - tag_lang_items_item_id: u32
// - tag_lang_items_item_node_id: u32

pub static tag_lang_items: uint = 0x48;
pub static tag_lang_items_item: uint = 0x49;
pub static tag_lang_items_item_id: uint = 0x4a;
pub static tag_lang_items_item_node_id: uint = 0x4b;
pub static tag_lang_items: uint = 0x70;
pub static tag_lang_items_item: uint = 0x71;
pub static tag_lang_items_item_id: uint = 0x72;
pub static tag_lang_items_item_node_id: uint = 0x73;

pub static tag_item_unnamed_field: uint = 0x4c;
pub static tag_items_data_item_visibility: uint = 0x4e;
pub static tag_item_unnamed_field: uint = 0x74;
pub static tag_items_data_item_visibility: uint = 0x76;

pub static tag_item_method_tps: uint = 0x51;
pub static tag_item_method_fty: uint = 0x52;
pub static tag_item_method_tps: uint = 0x79;
pub static tag_item_method_fty: uint = 0x7a;

pub static tag_mod_child: uint = 0x53;
pub static tag_misc_info: uint = 0x54;
pub static tag_misc_info_crate_items: uint = 0x55;
pub static tag_mod_child: uint = 0x7b;
pub static tag_misc_info: uint = 0x7c;
pub static tag_misc_info_crate_items: uint = 0x7d;

pub static tag_item_method_provided_source: uint = 0x56;
pub static tag_item_impl_vtables: uint = 0x57;
pub static tag_item_method_provided_source: uint = 0x7e;
pub static tag_item_impl_vtables: uint = 0x7f;

pub static tag_impls: uint = 0x58;
pub static tag_impls_impl: uint = 0x59;
pub static tag_impls: uint = 0x80;
pub static tag_impls_impl: uint = 0x81;

pub static tag_items_data_item_inherent_impl: uint = 0x5a;
pub static tag_items_data_item_extension_impl: uint = 0x5b;
pub static tag_items_data_item_inherent_impl: uint = 0x82;
pub static tag_items_data_item_extension_impl: uint = 0x83;

pub static tag_region_param_def: uint = 0x5c;
pub static tag_region_param_def_ident: uint = 0x5d;
pub static tag_region_param_def_def_id: uint = 0x5e;
pub static tag_region_param_def: uint = 0x84;
pub static tag_region_param_def_ident: uint = 0x85;
pub static tag_region_param_def_def_id: uint = 0x86;

pub static tag_native_libraries: uint = 0x5f;
pub static tag_native_libraries_lib: uint = 0x60;
pub static tag_native_libraries_name: uint = 0x61;
pub static tag_native_libraries_kind: uint = 0x62;
pub static tag_native_libraries: uint = 0x87;
pub static tag_native_libraries_lib: uint = 0x88;
pub static tag_native_libraries_name: uint = 0x89;
pub static tag_native_libraries_kind: uint = 0x8a;

pub static tag_macro_registrar_fn: uint = 0x63;
pub static tag_exported_macros: uint = 0x64;
pub static tag_macro_def: uint = 0x65;
pub static tag_macro_registrar_fn: uint = 0x8b;
pub static tag_exported_macros: uint = 0x8c;
pub static tag_macro_def: uint = 0x8d;

#[deriving(Clone, Show)]
pub struct LinkMeta {
Expand Down
10 changes: 8 additions & 2 deletions src/librustc/metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -975,21 +975,27 @@ pub fn get_struct_fields(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::NodeId)
// FIXME #6993: name should be of type Name, not Ident
let name = item_name(&*intr, an_item);
let did = item_def_id(an_item, cdata);
let tagdoc = reader::get_doc(an_item, tag_item_field_origin);
let origin_id = translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id));
result.push(ty::field_ty {
name: name.name,
id: did, vis:
struct_field_family_to_visibility(f),
id: did,
vis: struct_field_family_to_visibility(f),
origin: origin_id,
});
}
true
});
reader::tagged_docs(item, tag_item_unnamed_field, |an_item| {
let did = item_def_id(an_item, cdata);
let tagdoc = reader::get_doc(an_item, tag_item_field_origin);
let f = item_family(an_item);
let origin_id = translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id));
result.push(ty::field_ty {
name: special_idents::unnamed_field.name,
id: did,
vis: struct_field_family_to_visibility(f),
origin: origin_id,
});
true
});
Expand Down
63 changes: 32 additions & 31 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,23 +290,22 @@ fn encode_parent_item(ebml_w: &mut Encoder, id: DefId) {
}

fn encode_struct_fields(ebml_w: &mut Encoder,
def: @StructDef) {
for f in def.fields.iter() {
match f.node.kind {
NamedField(ident, vis) => {
ebml_w.start_tag(tag_item_field);
encode_struct_field_family(ebml_w, vis);
encode_name(ebml_w, ident.name);
encode_def_id(ebml_w, local_def(f.node.id));
ebml_w.end_tag();
}
UnnamedField(vis) => {
ebml_w.start_tag(tag_item_unnamed_field);
encode_struct_field_family(ebml_w, vis);
encode_def_id(ebml_w, local_def(f.node.id));
ebml_w.end_tag();
}
fields: &Vec<ty::field_ty>,
origin: DefId) {
for f in fields.iter() {
if f.name == special_idents::unnamed_field.name {
ebml_w.start_tag(tag_item_unnamed_field);
} else {
ebml_w.start_tag(tag_item_field);
encode_name(ebml_w, f.name);
}
encode_struct_field_family(ebml_w, f.vis);
encode_def_id(ebml_w, f.id);
ebml_w.start_tag(tag_item_field_origin);
let s = def_to_str(origin);
ebml_w.writer.write(s.as_bytes());
ebml_w.end_tag();
ebml_w.end_tag();
}
}

Expand Down Expand Up @@ -344,12 +343,13 @@ fn encode_enum_variant_info(ecx: &EncodeContext,
encode_symbol(ecx, ebml_w, variant.node.id);
}
ast::TupleVariantKind(_) => {},
ast::StructVariantKind(def) => {
ast::StructVariantKind(_) => {
let fields = ty::lookup_struct_fields(ecx.tcx, def_id);
let idx = encode_info_for_struct(ecx,
ebml_w,
def.fields.as_slice(),
&fields,
index);
encode_struct_fields(ebml_w, def);
encode_struct_fields(ebml_w, &fields, def_id);
let bkts = create_index(idx);
encode_index(ebml_w, bkts, write_i64);
}
Expand Down Expand Up @@ -666,7 +666,7 @@ fn encode_provided_source(ebml_w: &mut Encoder,
/* Returns an index of items in this class */
fn encode_info_for_struct(ecx: &EncodeContext,
ebml_w: &mut Encoder,
fields: &[StructField],
fields: &Vec<ty::field_ty>,
global_index: @RefCell<Vec<entry<i64>> >)
-> Vec<entry<i64>> {
/* Each class has its own index, since different classes
Expand All @@ -676,22 +676,19 @@ fn encode_info_for_struct(ecx: &EncodeContext,
/* We encode both private and public fields -- need to include
private fields to get the offsets right */
for field in fields.iter() {
let (nm, vis) = match field.node.kind {
NamedField(nm, vis) => (nm, vis),
UnnamedField(vis) => (special_idents::unnamed_field, vis)
};
let nm = field.name;
let id = field.id.node;

let id = field.node.id;
index.push(entry {val: id as i64, pos: ebml_w.writer.tell().unwrap()});
global_index.borrow_mut().push(entry {
val: id as i64,
pos: ebml_w.writer.tell().unwrap(),
});
ebml_w.start_tag(tag_items_data_item);
debug!("encode_info_for_struct: doing {} {}",
token::get_ident(nm), id);
encode_struct_field_family(ebml_w, vis);
encode_name(ebml_w, nm.name);
token::get_name(nm), id);
encode_struct_field_family(ebml_w, field.vis);
encode_name(ebml_w, nm);
encode_type(ecx, ebml_w, node_id_to_type(tcx, id));
encode_def_id(ebml_w, local_def(id));
ebml_w.end_tag();
Expand Down Expand Up @@ -983,12 +980,16 @@ fn encode_info_for_item(ecx: &EncodeContext,
generics);
}
ItemStruct(struct_def, _) => {
let fields = ty::lookup_struct_fields(tcx, def_id);

/* First, encode the fields
These come first because we need to write them to make
the index, and the index needs to be in the item for the
class itself */
let idx = encode_info_for_struct(ecx, ebml_w,
struct_def.fields.as_slice(), index);
let idx = encode_info_for_struct(ecx,
ebml_w,
&fields,
index);

/* Index the class*/
add_to_index(item, ebml_w, index);
Expand All @@ -1008,7 +1009,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
/* Encode def_ids for each field and method
for methods, write all the stuff get_trait_method
needs to know*/
encode_struct_fields(ebml_w, struct_def);
encode_struct_fields(ebml_w, &fields, def_id);

(ecx.encode_inlined_item)(ecx, ebml_w, IIItemRef(item));

Expand Down
Loading

2 comments on commit ff04aa8

@emberian
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r=nikomatsakis

@alexcrichton
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bors: retry

Please sign in to comment.