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 Mar 1, 2014
1 parent 123eb4e commit 91fe6d6
Show file tree
Hide file tree
Showing 21 changed files with 500 additions and 50 deletions.
15 changes: 15 additions & 0 deletions src/doc/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,21 @@ 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.
For example:

~~~~ {.ignore}
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: 1 addition & 1 deletion src/librustc/driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ pub fn phase_3_run_analysis_passes(sess: Session,
last_private_map: last_private_map
} =
time(time_passes, "resolution", (), |_|
middle::resolve::resolve_crate(sess, lang_items, krate));
middle::resolve::resolve_crate(sess, lang_items, &ast_map, krate));

let named_region_map = time(time_passes, "lifetime resolution", (),
|_| middle::resolve_lifetime::krate(sess, krate));
Expand Down
1 change: 1 addition & 0 deletions src/librustc/front/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ 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(),
}
}

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

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

ast::ItemStruct(..) => {
ast::ItemStruct(struct_definition, _) => {
if attr::contains_name(i.attrs, "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 => {}
}
}

_ => {}
Expand Down
40 changes: 37 additions & 3 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1007,12 +1007,43 @@ fn encode_info_for_item(ecx: &EncodeContext,
generics);
}
ItemStruct(struct_def, _) => {
// Create a list of all structs which compose this struct. That is, the
// reflexive, transitive closure over struct_def's super-struct.
let mut cur_struct = struct_def;
let mut structs: ~[@StructDef] = ~[];
loop {
structs.push(cur_struct);
match cur_struct.super_struct {
Some(t) => match t.node {
ast::TyPath(_, _, path_id) => {
let def_map = tcx.def_map.borrow();
match def_map.get().find(&path_id) {
Some(&DefStruct(def_id)) => {
cur_struct = match tcx.map.find(def_id.node) {
Some(ast_map::NodeItem(i)) => {
match i.node {
ast::ItemStruct(struct_def, _) => struct_def,
_ => ecx.diag.handler().bug("Expected ItemStruct"),
}
},
_ => ecx.diag.handler().bug("Expected NodeItem"),
};
},
_ => ecx.diag.handler().bug("Expected DefStruct"),
}
}
_ => ecx.diag.handler().bug("Expected TyPath"),
},
None => break,
}
}

/* 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, index);
let idx = structs.iter().fold(~[], |a: ~[entry<i64>], &s|
a + encode_info_for_struct(ecx, ebml_w, s.fields, index));

/* Index the class*/
add_to_index(item, ebml_w, index);
Expand All @@ -1032,7 +1063,10 @@ 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);
structs.iter().advance(|&s| {
encode_struct_fields(ebml_w, s);
true
});

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

Expand Down
Loading

0 comments on commit 91fe6d6

Please sign in to comment.