Allow inheritance between structs.
No subtyping, no interaction with traits. Partially addresses #9912.
This commit is contained in:
parent
3757f01c9b
commit
ff04aa8e38
30 changed files with 800 additions and 205 deletions
|
@ -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*,
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
|
|
|
@ -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;
|
||||
/*
|
||||
|
@ -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,
|
||||
pub enum astencode_tag { // Reserves 0x40 -- 0x5f
|
||||
tag_ast = 0x40,
|
||||
|
||||
tag_tree = 0x33,
|
||||
tag_tree = 0x41,
|
||||
|
||||
tag_id_range = 0x34,
|
||||
tag_id_range = 0x42,
|
||||
|
||||
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
|
||||
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;
|
||||
|
@ -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:
|
||||
//
|
||||
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
});
|
||||
|
|
|
@ -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) => {
|
||||
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);
|
||||
encode_struct_field_family(ebml_w, vis);
|
||||
encode_def_id(ebml_w, local_def(f.node.id));
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -676,12 +676,9 @@ 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,
|
||||
|
@ -689,9 +686,9 @@ fn encode_info_for_struct(ecx: &EncodeContext,
|
|||
});
|
||||
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();
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
||||
|
|
|
@ -488,7 +488,7 @@ impl<'a> PrivacyVisitor<'a> {
|
|||
// members, so that's why we test the parent, and not the did itself.
|
||||
let mut cur = self.curitem;
|
||||
loop {
|
||||
debug!("privacy - questioning {}", self.nodestr(cur));
|
||||
debug!("privacy - questioning {}, {:?}", self.nodestr(cur), cur);
|
||||
match cur {
|
||||
// If the relevant parent is in our history, then we're allowed
|
||||
// to look inside any of our ancestor's immediate private items,
|
||||
|
@ -554,11 +554,14 @@ impl<'a> PrivacyVisitor<'a> {
|
|||
}
|
||||
|
||||
// Checks that a field is in scope.
|
||||
fn check_field(&mut self, span: Span, id: ast::DefId,
|
||||
fn check_field(&mut self,
|
||||
span: Span,
|
||||
id: ast::DefId,
|
||||
name: FieldName) {
|
||||
let fields = ty::lookup_struct_fields(self.tcx, id);
|
||||
let field = match name {
|
||||
NamedField(ident) => {
|
||||
debug!("privacy - check named field {} in struct {}", ident.name, id);
|
||||
fields.iter().find(|f| f.name == ident.name).unwrap()
|
||||
}
|
||||
UnnamedField(idx) => fields.get(idx)
|
||||
|
|
|
@ -3708,6 +3708,7 @@ impl<'a> Resolver<'a> {
|
|||
ItemStruct(ref struct_def, ref generics) => {
|
||||
self.resolve_struct(item.id,
|
||||
generics,
|
||||
struct_def.super_struct,
|
||||
struct_def.fields.as_slice());
|
||||
}
|
||||
|
||||
|
@ -3924,28 +3925,8 @@ impl<'a> Resolver<'a> {
|
|||
fn resolve_struct(&mut self,
|
||||
id: NodeId,
|
||||
generics: &Generics,
|
||||
super_struct: Option<P<Ty>>,
|
||||
fields: &[StructField]) {
|
||||
let mut ident_map: HashMap<ast::Ident, &StructField> = HashMap::new();
|
||||
for field in fields.iter() {
|
||||
match field.node.kind {
|
||||
NamedField(ident, _) => {
|
||||
match ident_map.find(&ident) {
|
||||
Some(&prev_field) => {
|
||||
let ident_str = token::get_ident(ident);
|
||||
self.resolve_error(field.span,
|
||||
format!("field `{}` is already declared", ident_str));
|
||||
self.session.span_note(prev_field.span,
|
||||
"previously declared here");
|
||||
},
|
||||
None => {
|
||||
ident_map.insert(ident, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
// If applicable, create a rib for the type parameters.
|
||||
self.with_type_parameter_rib(HasTypeParameters(generics,
|
||||
id,
|
||||
|
@ -3955,6 +3936,39 @@ impl<'a> Resolver<'a> {
|
|||
// Resolve the type parameters.
|
||||
this.resolve_type_parameters(&generics.ty_params);
|
||||
|
||||
// Resolve the super struct.
|
||||
match super_struct {
|
||||
Some(t) => match t.node {
|
||||
TyPath(ref path, None, path_id) => {
|
||||
match this.resolve_path(id, path, TypeNS, true) {
|
||||
Some((DefTy(def_id), lp)) if this.structs.contains(&def_id) => {
|
||||
let def = DefStruct(def_id);
|
||||
debug!("(resolving struct) resolved `{}` to type {:?}",
|
||||
token::get_ident(path.segments
|
||||
.last().unwrap()
|
||||
.identifier),
|
||||
def);
|
||||
debug!("(resolving struct) writing resolution for `{}` (id {})",
|
||||
this.path_idents_to_str(path),
|
||||
path_id);
|
||||
this.record_def(path_id, (def, lp));
|
||||
}
|
||||
Some((DefStruct(_), _)) => {
|
||||
this.session.span_err(t.span,
|
||||
"super-struct is defined \
|
||||
in a different crate")
|
||||
},
|
||||
Some(_) => this.session.span_err(t.span,
|
||||
"super-struct is not a struct type"),
|
||||
None => this.session.span_err(t.span,
|
||||
"super-struct could not be resolved"),
|
||||
}
|
||||
},
|
||||
_ => this.session.span_bug(t.span, "path not mapped to a TyPath")
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
|
||||
// Resolve fields.
|
||||
for field in fields.iter() {
|
||||
this.resolve_type(field.node.ty);
|
||||
|
|
|
@ -52,7 +52,6 @@ use syntax::parse::token::InternedString;
|
|||
use syntax::{ast, ast_map};
|
||||
use syntax::owned_slice::OwnedSlice;
|
||||
use syntax::abi;
|
||||
use syntax;
|
||||
use collections::enum_set::{EnumSet, CLike};
|
||||
|
||||
pub type Disr = u64;
|
||||
|
@ -150,10 +149,12 @@ pub enum TraitStore {
|
|||
RegionTraitStore(Region, ast::Mutability),
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct field_ty {
|
||||
pub name: Name,
|
||||
pub id: DefId,
|
||||
pub vis: ast::Visibility,
|
||||
pub origin: ast::DefId, // The DefId of the struct in which the field is declared.
|
||||
}
|
||||
|
||||
// Contains information needed to resolve types and (in the future) look up
|
||||
|
@ -303,6 +304,8 @@ pub struct ctxt {
|
|||
// A mapping of fake provided method def_ids to the default implementation
|
||||
pub provided_method_sources: RefCell<DefIdMap<ast::DefId>>,
|
||||
pub supertraits: RefCell<DefIdMap<@Vec<@TraitRef> >>,
|
||||
pub superstructs: RefCell<DefIdMap<Option<ast::DefId>>>,
|
||||
pub struct_fields: RefCell<DefIdMap<@Vec<field_ty>>>,
|
||||
|
||||
// Maps from def-id of a type or region parameter to its
|
||||
// (inferred) variance.
|
||||
|
@ -1115,6 +1118,8 @@ pub fn mk_ctxt(s: Session,
|
|||
lang_items: lang_items,
|
||||
provided_method_sources: RefCell::new(DefIdMap::new()),
|
||||
supertraits: RefCell::new(DefIdMap::new()),
|
||||
superstructs: RefCell::new(DefIdMap::new()),
|
||||
struct_fields: RefCell::new(DefIdMap::new()),
|
||||
destructor_for_type: RefCell::new(DefIdMap::new()),
|
||||
destructors: RefCell::new(DefIdSet::new()),
|
||||
trait_impls: RefCell::new(DefIdMap::new()),
|
||||
|
@ -3987,61 +3992,71 @@ pub fn lookup_field_type(tcx: &ctxt,
|
|||
subst(tcx, substs, t)
|
||||
}
|
||||
|
||||
// Look up the list of field names and IDs for a given struct
|
||||
// Fails if the id is not bound to a struct.
|
||||
pub fn lookup_struct_fields(cx: &ctxt, did: ast::DefId) -> Vec<field_ty> {
|
||||
if did.krate == ast::LOCAL_CRATE {
|
||||
match cx.map.find(did.node) {
|
||||
Some(ast_map::NodeItem(i)) => {
|
||||
match i.node {
|
||||
ast::ItemStruct(struct_def, _) => {
|
||||
struct_field_tys(struct_def.fields.as_slice())
|
||||
}
|
||||
_ => cx.sess.bug("struct ID bound to non-struct")
|
||||
}
|
||||
}
|
||||
Some(ast_map::NodeVariant(ref variant)) => {
|
||||
match (*variant).node.kind {
|
||||
ast::StructVariantKind(struct_def) => {
|
||||
struct_field_tys(struct_def.fields.as_slice())
|
||||
}
|
||||
_ => {
|
||||
cx.sess.bug("struct ID bound to enum variant that \
|
||||
isn't struct-like")
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Lookup all ancestor structs of a struct indicated by did. That is the reflexive,
|
||||
// transitive closure of doing a single lookup in cx.superstructs.
|
||||
fn lookup_super_structs(cx: &ctxt,
|
||||
did: ast::DefId) -> Vec<DefId> {
|
||||
let mut this_result: Vec<DefId> = vec!(did);
|
||||
match cx.superstructs.borrow().find(&did) {
|
||||
Some(&Some(def_id)) => {
|
||||
let ss: Vec<DefId> = lookup_super_structs(cx, def_id);
|
||||
this_result.extend(ss.move_iter());
|
||||
this_result
|
||||
},
|
||||
Some(&None) => this_result,
|
||||
None => {
|
||||
cx.sess.bug(
|
||||
format!("struct ID not bound to an item: {}",
|
||||
format!("ID not mapped to super-struct: {}",
|
||||
cx.map.node_to_str(did.node)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Look up the list of field names and IDs for a given struct.
|
||||
// Fails if the id is not bound to a struct.
|
||||
pub fn lookup_struct_fields(cx: &ctxt, did: ast::DefId) -> Vec<field_ty> {
|
||||
if did.krate == ast::LOCAL_CRATE {
|
||||
// We store the fields which are syntactically in each struct in cx. So
|
||||
// we have to walk the inheritance chain of the struct to get all the
|
||||
// structs (explicit and inherited) for a struct. If this is expensive
|
||||
// we could cache the whole list of fields here.
|
||||
let structs = lookup_super_structs(cx, did);
|
||||
let struct_fields = cx.struct_fields.borrow();
|
||||
let results: Vec<&@Vec<field_ty>> = structs.iter().map(|s| {
|
||||
match struct_fields.find(s) {
|
||||
Some(fields) => fields,
|
||||
_ => {
|
||||
cx.sess.bug(
|
||||
format!("ID not mapped to struct fields: {}",
|
||||
cx.map.node_to_str(did.node)));
|
||||
}
|
||||
}
|
||||
}).collect();
|
||||
|
||||
let len = results.iter().map(|x| x.len()).fold(0, |a, b| a + b);
|
||||
let mut result: Vec<field_ty> = Vec::with_capacity(len);
|
||||
for rs in results.iter() {
|
||||
for r in rs.iter() {
|
||||
result.push(*r);
|
||||
}
|
||||
}
|
||||
assert!(result.len() == len);
|
||||
result
|
||||
} else {
|
||||
csearch::get_struct_fields(&cx.sess.cstore, did)
|
||||
}
|
||||
}
|
||||
|
||||
fn struct_field_tys(fields: &[StructField]) -> Vec<field_ty> {
|
||||
fields.iter().map(|field| {
|
||||
match field.node.kind {
|
||||
NamedField(ident, visibility) => {
|
||||
field_ty {
|
||||
name: ident.name,
|
||||
id: ast_util::local_def(field.node.id),
|
||||
vis: visibility,
|
||||
pub fn lookup_struct_field(cx: &ctxt,
|
||||
parent: ast::DefId,
|
||||
field_id: ast::DefId)
|
||||
-> field_ty {
|
||||
let r = lookup_struct_fields(cx, parent);
|
||||
match r.iter().find(|f| f.id.node == field_id.node) {
|
||||
Some(t) => *t,
|
||||
None => cx.sess.bug("struct ID not found in parent's fields")
|
||||
}
|
||||
}
|
||||
UnnamedField(visibility) => {
|
||||
field_ty {
|
||||
name: syntax::parse::token::special_idents::unnamed_field.name,
|
||||
id: ast_util::local_def(field.node.id),
|
||||
vis: visibility,
|
||||
}
|
||||
}
|
||||
}
|
||||
}).collect()
|
||||
}
|
||||
|
||||
// Returns a list of fields corresponding to the struct's items. trans uses
|
||||
// this. Takes a list of substs with which to instantiate field types.
|
||||
|
|
|
@ -122,6 +122,7 @@ use std::vec::Vec;
|
|||
use syntax::abi;
|
||||
use syntax::ast::{Provided, Required};
|
||||
use syntax::ast;
|
||||
use syntax::ast_map;
|
||||
use syntax::ast_util::local_def;
|
||||
use syntax::ast_util;
|
||||
use syntax::attr;
|
||||
|
@ -509,6 +510,57 @@ fn check_fn<'a>(ccx: &'a CrateCtxt<'a>,
|
|||
fcx
|
||||
}
|
||||
|
||||
fn span_for_field(tcx: &ty::ctxt, field: &ty::field_ty, struct_id: ast::DefId) -> Span {
|
||||
assert!(field.id.krate == ast::LOCAL_CRATE);
|
||||
let item = match tcx.map.find(struct_id.node) {
|
||||
Some(ast_map::NodeItem(item)) => item,
|
||||
None => fail!("node not in ast map: {}", struct_id.node),
|
||||
_ => fail!("expected item, found {}", tcx.map.node_to_str(struct_id.node))
|
||||
};
|
||||
|
||||
match item.node {
|
||||
ast::ItemStruct(struct_def, _) => {
|
||||
match struct_def.fields.iter().find(|f| match f.node.kind {
|
||||
ast::NamedField(ident, _) => ident.name == field.name,
|
||||
_ => false,
|
||||
}) {
|
||||
Some(f) => f.span,
|
||||
None => tcx.sess.bug(format!("Could not find field {}",
|
||||
token::get_name(field.name))),
|
||||
}
|
||||
},
|
||||
_ => tcx.sess.bug("Field found outside of a struct?"),
|
||||
}
|
||||
}
|
||||
|
||||
// Check struct fields are uniquely named wrt parents.
|
||||
fn check_for_field_shadowing(tcx: &ty::ctxt,
|
||||
id: ast::DefId) {
|
||||
let struct_fields = tcx.struct_fields.borrow();
|
||||
let fields = struct_fields.get(&id);
|
||||
|
||||
let superstructs = tcx.superstructs.borrow();
|
||||
let super_struct = superstructs.get(&id);
|
||||
match *super_struct {
|
||||
Some(parent_id) => {
|
||||
let super_fields = ty::lookup_struct_fields(tcx, parent_id);
|
||||
for f in fields.iter() {
|
||||
match super_fields.iter().find(|sf| f.name == sf.name) {
|
||||
Some(prev_field) => {
|
||||
tcx.sess.span_err(span_for_field(tcx, f, id),
|
||||
format!("field `{}` hides field declared in super-struct",
|
||||
token::get_name(f.name)));
|
||||
tcx.sess.span_note(span_for_field(tcx, prev_field, parent_id),
|
||||
"previously declared here");
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
|
||||
let tcx = ccx.tcx;
|
||||
|
||||
|
@ -518,6 +570,9 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
|
|||
// Check that the struct is instantiable
|
||||
check_instantiable(tcx, span, id);
|
||||
|
||||
// Check there are no overlapping fields in super-structs
|
||||
check_for_field_shadowing(tcx, local_def(id));
|
||||
|
||||
if ty::lookup_simd(tcx, local_def(id)) {
|
||||
check_simd(tcx, span, id);
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ use util::ppaux;
|
|||
use util::ppaux::Repr;
|
||||
|
||||
use std::rc::Rc;
|
||||
use collections::HashSet;
|
||||
use collections::{HashMap, HashSet};
|
||||
|
||||
use syntax::abi;
|
||||
use syntax::ast::{RegionTyParamBound, TraitTyParamBound};
|
||||
|
@ -440,7 +440,8 @@ pub fn ensure_supertraits(ccx: &CrateCtxt,
|
|||
|
||||
pub fn convert_field(ccx: &CrateCtxt,
|
||||
struct_generics: &ty::Generics,
|
||||
v: &ast::StructField) {
|
||||
v: &ast::StructField,
|
||||
origin: ast::DefId) -> ty::field_ty {
|
||||
let tt = ccx.to_ty(&ExplicitRscope, v.node.ty);
|
||||
write_ty_to_tcx(ccx.tcx, v.node.id, tt);
|
||||
/* add the field to the tcache */
|
||||
|
@ -449,6 +450,25 @@ pub fn convert_field(ccx: &CrateCtxt,
|
|||
generics: struct_generics.clone(),
|
||||
ty: tt
|
||||
});
|
||||
|
||||
match v.node.kind {
|
||||
ast::NamedField(ident, visibility) => {
|
||||
ty::field_ty {
|
||||
name: ident.name,
|
||||
id: local_def(v.node.id),
|
||||
vis: visibility,
|
||||
origin: origin,
|
||||
}
|
||||
}
|
||||
ast::UnnamedField(visibility) => {
|
||||
ty::field_ty {
|
||||
name: special_idents::unnamed_field.name,
|
||||
id: local_def(v.node.id),
|
||||
vis: visibility,
|
||||
origin: origin,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_methods(ccx: &CrateCtxt,
|
||||
|
@ -637,12 +657,21 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
|
|||
ast::ItemStruct(struct_def, ref generics) => {
|
||||
ensure_no_ty_param_bounds(ccx, it.span, generics, "structure");
|
||||
|
||||
// Write the class type
|
||||
// Write the class type.
|
||||
let tpt = ty_of_item(ccx, it);
|
||||
write_ty_to_tcx(tcx, it.id, tpt.ty);
|
||||
|
||||
tcx.tcache.borrow_mut().insert(local_def(it.id), tpt.clone());
|
||||
|
||||
// Write the super-struct type, if it exists.
|
||||
match struct_def.super_struct {
|
||||
Some(ty) => {
|
||||
let supserty = ccx.to_ty(&ExplicitRscope, ty);
|
||||
write_ty_to_tcx(tcx, it.id, supserty);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
convert_struct(ccx, struct_def, tpt, it.id);
|
||||
},
|
||||
ast::ItemTy(_, ref generics) => {
|
||||
|
@ -671,10 +700,67 @@ pub fn convert_struct(ccx: &CrateCtxt,
|
|||
id: ast::NodeId) {
|
||||
let tcx = ccx.tcx;
|
||||
|
||||
// Write the type of each of the members
|
||||
for f in struct_def.fields.iter() {
|
||||
convert_field(ccx, &tpt.generics, f);
|
||||
// Write the type of each of the members and check for duplicate fields.
|
||||
let mut seen_fields: HashMap<ast::Name, Span> = HashMap::new();
|
||||
let field_tys = struct_def.fields.iter().map(|f| {
|
||||
let result = convert_field(ccx, &tpt.generics, f, local_def(id));
|
||||
|
||||
if result.name != special_idents::unnamed_field.name {
|
||||
let dup = match seen_fields.find(&result.name) {
|
||||
Some(prev_span) => {
|
||||
tcx.sess.span_err(f.span,
|
||||
format!("field `{}` is already declared", token::get_name(result.name)));
|
||||
tcx.sess.span_note(*prev_span,
|
||||
"previously declared here");
|
||||
true
|
||||
},
|
||||
None => false,
|
||||
};
|
||||
// FIXME(#6393) this whole dup thing is just to satisfy
|
||||
// the borrow checker :-(
|
||||
if !dup {
|
||||
seen_fields.insert(result.name, f.span);
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}).collect();
|
||||
|
||||
tcx.struct_fields.borrow_mut().insert(local_def(id), @field_tys);
|
||||
|
||||
let super_struct = match struct_def.super_struct {
|
||||
Some(t) => match t.node {
|
||||
ast::TyPath(_, _, path_id) => {
|
||||
let def_map = tcx.def_map.borrow();
|
||||
match def_map.find(&path_id) {
|
||||
Some(&ast::DefStruct(def_id)) => {
|
||||
// FIXME(#12511) Check for cycles in the inheritance hierarchy.
|
||||
// Check super-struct is virtual.
|
||||
match tcx.map.find(def_id.node) {
|
||||
Some(ast_map::NodeItem(i)) => match i.node {
|
||||
ast::ItemStruct(struct_def, _) => {
|
||||
if !struct_def.is_virtual {
|
||||
tcx.sess.span_err(t.span,
|
||||
"struct inheritance is only \
|
||||
allowed from virtual structs");
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
Some(def_id)
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
tcx.superstructs.borrow_mut().insert(local_def(id), super_struct);
|
||||
|
||||
let substs = mk_item_substs(ccx, &tpt.generics, None);
|
||||
let selfty = ty::mk_struct(tcx, local_def(id), substs);
|
||||
|
||||
|
|
|
@ -1080,7 +1080,9 @@ pub struct StructDef {
|
|||
pub fields: Vec<StructField>, /* fields, not including ctor */
|
||||
/* ID of the constructor. This is only used for tuple- or enum-like
|
||||
* structs. */
|
||||
pub ctor_id: Option<NodeId>
|
||||
pub ctor_id: Option<NodeId>,
|
||||
pub super_struct: Option<P<Ty>>, // Super struct, if specified.
|
||||
pub is_virtual: bool, // True iff the struct may be inherited from.
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -235,7 +235,12 @@ pub trait Folder {
|
|||
kind = StructVariantKind(@ast::StructDef {
|
||||
fields: struct_def.fields.iter()
|
||||
.map(|f| self.fold_struct_field(f)).collect(),
|
||||
ctor_id: struct_def.ctor_id.map(|c| self.new_id(c))
|
||||
ctor_id: struct_def.ctor_id.map(|c| self.new_id(c)),
|
||||
super_struct: match struct_def.super_struct {
|
||||
Some(t) => Some(self.fold_ty(t)),
|
||||
None => None
|
||||
},
|
||||
is_virtual: struct_def.is_virtual,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -480,6 +485,11 @@ fn fold_struct_def<T: Folder>(struct_def: @StructDef, fld: &mut T) -> @StructDef
|
|||
@ast::StructDef {
|
||||
fields: struct_def.fields.iter().map(|f| fold_struct_field(f, fld)).collect(),
|
||||
ctor_id: struct_def.ctor_id.map(|cid| fld.new_id(cid)),
|
||||
super_struct: match struct_def.super_struct {
|
||||
Some(t) => Some(fld.fold_ty(t)),
|
||||
None => None
|
||||
},
|
||||
is_virtual: struct_def.is_virtual,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3884,10 +3884,25 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
// parse struct Foo { ... }
|
||||
fn parse_item_struct(&mut self) -> ItemInfo {
|
||||
fn parse_item_struct(&mut self, is_virtual: bool) -> ItemInfo {
|
||||
let class_name = self.parse_ident();
|
||||
let generics = self.parse_generics();
|
||||
|
||||
let super_struct = if self.eat(&token::COLON) {
|
||||
let ty = self.parse_ty(false);
|
||||
match ty.node {
|
||||
TyPath(_, None, _) => {
|
||||
Some(ty)
|
||||
}
|
||||
_ => {
|
||||
self.span_err(ty.span, "not a struct");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut fields: Vec<StructField>;
|
||||
let is_tuple_like;
|
||||
|
||||
|
@ -3938,7 +3953,9 @@ impl<'a> Parser<'a> {
|
|||
(class_name,
|
||||
ItemStruct(@ast::StructDef {
|
||||
fields: fields,
|
||||
ctor_id: if is_tuple_like { Some(new_id) } else { None }
|
||||
ctor_id: if is_tuple_like { Some(new_id) } else { None },
|
||||
super_struct: super_struct,
|
||||
is_virtual: is_virtual,
|
||||
}, generics),
|
||||
None)
|
||||
}
|
||||
|
@ -4329,7 +4346,9 @@ impl<'a> Parser<'a> {
|
|||
|
||||
return @ast::StructDef {
|
||||
fields: fields,
|
||||
ctor_id: None
|
||||
ctor_id: None,
|
||||
super_struct: None,
|
||||
is_virtual: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -4514,6 +4533,12 @@ impl<'a> Parser<'a> {
|
|||
format!("expected `\\{` or `fn` but found `{}`", token_str));
|
||||
}
|
||||
|
||||
let is_virtual = self.eat_keyword(keywords::Virtual);
|
||||
if is_virtual && !self.is_keyword(keywords::Struct) {
|
||||
self.span_err(self.span,
|
||||
"`virtual` keyword may only be used with `struct`");
|
||||
}
|
||||
|
||||
// the rest are all guaranteed to be items:
|
||||
if self.is_keyword(keywords::Static) {
|
||||
// STATIC ITEM
|
||||
|
@ -4614,7 +4639,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
if self.eat_keyword(keywords::Struct) {
|
||||
// STRUCT ITEM
|
||||
let (ident, item_, extra_attrs) = self.parse_item_struct();
|
||||
let (ident, item_, extra_attrs) = self.parse_item_struct(is_virtual);
|
||||
let item = self.mk_item(lo,
|
||||
self.last_span.hi,
|
||||
ident,
|
||||
|
|
|
@ -474,22 +474,23 @@ declare_special_idents_and_keywords! {
|
|||
(35, Type, "type");
|
||||
(36, Unsafe, "unsafe");
|
||||
(37, Use, "use");
|
||||
(38, While, "while");
|
||||
(39, Continue, "continue");
|
||||
(40, Proc, "proc");
|
||||
(41, Box, "box");
|
||||
(38, Virtual, "virtual");
|
||||
(39, While, "while");
|
||||
(40, Continue, "continue");
|
||||
(41, Proc, "proc");
|
||||
(42, Box, "box");
|
||||
|
||||
'reserved:
|
||||
(42, Alignof, "alignof");
|
||||
(43, Be, "be");
|
||||
(44, Offsetof, "offsetof");
|
||||
(45, Priv, "priv");
|
||||
(46, Pure, "pure");
|
||||
(47, Sizeof, "sizeof");
|
||||
(48, Typeof, "typeof");
|
||||
(49, Unsized, "unsized");
|
||||
(50, Yield, "yield");
|
||||
(51, Do, "do");
|
||||
(43, Alignof, "alignof");
|
||||
(44, Be, "be");
|
||||
(45, Offsetof, "offsetof");
|
||||
(46, Priv, "priv");
|
||||
(47, Pure, "pure");
|
||||
(48, Sizeof, "sizeof");
|
||||
(49, Typeof, "typeof");
|
||||
(50, Unsized, "unsized");
|
||||
(51, Yield, "yield");
|
||||
(52, Do, "do");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -640,6 +640,9 @@ impl<'a> State<'a> {
|
|||
));
|
||||
}
|
||||
ast::ItemStruct(struct_def, ref generics) => {
|
||||
if struct_def.is_virtual {
|
||||
try!(self.word_space("virtual"));
|
||||
}
|
||||
try!(self.head(visibility_qualified(item.vis, "struct")));
|
||||
try!(self.print_struct(struct_def, generics, item.ident, item.span));
|
||||
}
|
||||
|
@ -754,6 +757,13 @@ impl<'a> State<'a> {
|
|||
span: codemap::Span) -> IoResult<()> {
|
||||
try!(self.print_ident(ident));
|
||||
try!(self.print_generics(generics));
|
||||
match struct_def.super_struct {
|
||||
Some(t) => {
|
||||
try!(self.word_space(":"));
|
||||
try!(self.print_type(t));
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
if ast_util::struct_def_is_tuple_like(struct_def) {
|
||||
if !struct_def.fields.is_empty() {
|
||||
try!(self.popen());
|
||||
|
|
|
@ -571,6 +571,10 @@ pub fn walk_struct_def<E: Clone, V: Visitor<E>>(visitor: &mut V,
|
|||
_: &Generics,
|
||||
_: NodeId,
|
||||
env: E) {
|
||||
match struct_definition.super_struct {
|
||||
Some(t) => visitor.visit_ty(t, env.clone()),
|
||||
None => {},
|
||||
}
|
||||
for field in struct_definition.fields.iter() {
|
||||
visitor.visit_struct_field(field, env.clone())
|
||||
}
|
||||
|
|
27
src/test/auxiliary/inherit_struct_lib.rs
Normal file
27
src/test/auxiliary/inherit_struct_lib.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test struct inheritance on structs from another crate.
|
||||
#![feature(struct_inherit)]
|
||||
|
||||
pub virtual struct S1 {
|
||||
pub f1: int,
|
||||
}
|
||||
|
||||
pub struct S2 : S1 {
|
||||
pub f2: int,
|
||||
}
|
||||
|
||||
pub fn test_s2(s2: S2) {
|
||||
assert!(s2.f1 == 115);
|
||||
assert!(s2.f2 == 113);
|
||||
}
|
||||
|
||||
pub static glob_s: S2 = S2 { f1: 32, f2: -45 };
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
|
@ -8,7 +8,10 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
struct q : r {
|
||||
//~^ ERROR expected `{`, `(`, or `;` after struct name
|
||||
foo: int
|
||||
// Test struct inheritance.
|
||||
#![feature(struct_inherit)]
|
||||
|
||||
struct S6 : ~S2; //~ ERROR not a struct
|
||||
|
||||
pub fn main() {
|
||||
}
|
25
src/test/compile-fail/inherit-struct2.rs
Normal file
25
src/test/compile-fail/inherit-struct2.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test struct inheritance.
|
||||
#![feature(struct_inherit)]
|
||||
|
||||
struct S2 : S0 { //~ ERROR super-struct could not be resolved
|
||||
f2: int,
|
||||
}
|
||||
|
||||
trait T {}
|
||||
|
||||
struct S3 : T { //~ ERROR super-struct is not a struct type
|
||||
f3: int,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
}
|
25
src/test/compile-fail/inherit-struct3.rs
Normal file
25
src/test/compile-fail/inherit-struct3.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test struct inheritance.
|
||||
#![feature(struct_inherit)]
|
||||
|
||||
virtual struct S1 {
|
||||
f1: int,
|
||||
}
|
||||
|
||||
struct S6 : S1 {
|
||||
f2: int,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let s = S6{f2: 3}; //~ ERROR missing field: `f1`
|
||||
let s = S6{f1: 3}; //~ ERROR missing field: `f2`
|
||||
}
|
24
src/test/compile-fail/inherit-struct4.rs
Normal file
24
src/test/compile-fail/inherit-struct4.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test struct inheritance.
|
||||
#![feature(struct_inherit)]
|
||||
|
||||
// With lifetime parameters.
|
||||
struct S5<'a> : S4 { //~ ERROR wrong number of lifetime parameters: expected 1 but found 0
|
||||
f4: int,
|
||||
}
|
||||
|
||||
virtual struct S4<'a> {
|
||||
f3: &'a int,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
}
|
20
src/test/compile-fail/inherit-struct5.rs
Normal file
20
src/test/compile-fail/inherit-struct5.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test struct inheritance on structs from another crate.
|
||||
#![feature(struct_inherit)]
|
||||
|
||||
// aux-build:inherit_struct_lib.rs
|
||||
extern crate inherit_struct_lib;
|
||||
|
||||
struct S3 : inherit_struct_lib::S1; //~ ERROR super-struct is defined in a different crate
|
||||
|
||||
pub fn main() {
|
||||
}
|
42
src/test/compile-fail/inherit-struct6.rs
Normal file
42
src/test/compile-fail/inherit-struct6.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test privacy and struct inheritance.
|
||||
#![feature(struct_inherit)]
|
||||
|
||||
mod Foo {
|
||||
pub virtual struct S1 {
|
||||
pub f1: int,
|
||||
f2: int,
|
||||
}
|
||||
}
|
||||
|
||||
struct S2 : Foo::S1 {
|
||||
pub f3: int,
|
||||
}
|
||||
|
||||
impl S2 {
|
||||
fn new() -> S2 {
|
||||
S2{f1: 3, f2: 4, f3: 5} //~ ERROR field `f2` of struct `S2` is private
|
||||
}
|
||||
|
||||
fn bar(&self) {
|
||||
self.f3;
|
||||
self.f1;
|
||||
self.f2; //~ ERROR field `f2` of struct `S2` is private
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let s = S2{f1: 3, f2: 4, f3: 5}; //~ ERROR field `f2` of struct `S2` is private
|
||||
s.f3;
|
||||
s.f1;
|
||||
s.f2; //~ ERROR field `f2` of struct `S2` is private
|
||||
}
|
19
src/test/compile-fail/inherit-struct7.rs
Normal file
19
src/test/compile-fail/inherit-struct7.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test struct inheritance.
|
||||
#![feature(struct_inherit)]
|
||||
|
||||
virtual trait Foo {} //~ ERROR `virtual` keyword may only be used with `struct`
|
||||
virtual enum Bar {} //~ ERROR `virtual` keyword may only be used with `struct`
|
||||
virtual fn baz() {} //~ ERROR `virtual` keyword may only be used with `struct`
|
||||
|
||||
pub fn main() {
|
||||
}
|
31
src/test/compile-fail/inherit-struct8.rs
Normal file
31
src/test/compile-fail/inherit-struct8.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test struct inheritance.
|
||||
#![feature(struct_inherit)]
|
||||
|
||||
virtual struct S1 {
|
||||
f1: int,
|
||||
}
|
||||
|
||||
virtual struct S6 : S1 {
|
||||
f2: int,
|
||||
}
|
||||
|
||||
struct S7 : S1 {
|
||||
f1: int, //~ ERROR field `f1` hides field declared in super-struct
|
||||
}
|
||||
|
||||
struct S8 : S6 {
|
||||
f1: int, //~ ERROR field `f1` hides field declared in super-struct
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
}
|
18
src/test/compile-fail/inherit-struct9.rs
Normal file
18
src/test/compile-fail/inherit-struct9.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test struct inheritance.
|
||||
#![feature(struct_inherit)]
|
||||
|
||||
struct s9;
|
||||
struct s10 : s9; //~ ERROR struct inheritance is only allowed from virtual structs
|
||||
|
||||
pub fn main() {
|
||||
}
|
|
@ -72,15 +72,20 @@
|
|||
// debugger:print 'simple-struct::PADDING_AT_END'
|
||||
// check:$18 = {x = -27, y = 28}
|
||||
|
||||
#![allow(unused_variable)]
|
||||
#![allow(dead_code)]
|
||||
// debugger:print inheriting
|
||||
// check:$19 = {a = 10019, b = -10020, x = -10016, y = -10017.5, z = 10018}
|
||||
|
||||
|
||||
#![feature(struct_inherit)];
|
||||
#![allow(unused_variable)];
|
||||
#![allow(dead_code)];
|
||||
|
||||
struct NoPadding16 {
|
||||
x: u16,
|
||||
y: i16
|
||||
}
|
||||
|
||||
struct NoPadding32 {
|
||||
virtual struct NoPadding32 {
|
||||
x: i32,
|
||||
y: f32,
|
||||
z: u32
|
||||
|
@ -143,6 +148,11 @@ static mut PADDING_AT_END: PaddingAtEnd = PaddingAtEnd {
|
|||
y: 14
|
||||
};
|
||||
|
||||
struct Inheriting : NoPadding32 {
|
||||
a: u16,
|
||||
b: i16
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let no_padding16 = NoPadding16 { x: 10000, y: -10001 };
|
||||
let no_padding32 = NoPadding32 { x: -10002, y: -10003.5, z: 10004 };
|
||||
|
@ -152,6 +162,8 @@ fn main() {
|
|||
let internal_padding = InternalPadding { x: 10012, y: -10013 };
|
||||
let padding_at_end = PaddingAtEnd { x: -10014, y: 10015 };
|
||||
|
||||
let inheriting = Inheriting { a: 10019, b: -10020, x: -10016, y: -10017.5, z: 10018 };
|
||||
|
||||
unsafe {
|
||||
NO_PADDING_16.x = 100;
|
||||
NO_PADDING_16.y = -101;
|
||||
|
|
61
src/test/run-pass/inherit-struct1.rs
Normal file
61
src/test/run-pass/inherit-struct1.rs
Normal file
|
@ -0,0 +1,61 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test struct inheritance.
|
||||
#![feature(struct_inherit)]
|
||||
|
||||
virtual struct S1 {
|
||||
f1: int,
|
||||
}
|
||||
|
||||
virtual struct S2 : S1 {
|
||||
f2: int,
|
||||
}
|
||||
|
||||
struct S3 : S2 {
|
||||
f3: int,
|
||||
}
|
||||
|
||||
// With lifetime parameters.
|
||||
struct S5<'a> : S4<'a> {
|
||||
f4: int,
|
||||
}
|
||||
|
||||
virtual struct S4<'a> {
|
||||
f3: &'a int,
|
||||
}
|
||||
|
||||
// With type parameters.
|
||||
struct S7<T> : S6<T> {
|
||||
f4: int,
|
||||
}
|
||||
|
||||
virtual struct S6<T> {
|
||||
f3: T,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let s = S2{f1: 115, f2: 113};
|
||||
assert!(s.f1 == 115);
|
||||
assert!(s.f2 == 113);
|
||||
|
||||
let s = S3{f1: 15, f2: 13, f3: 17};
|
||||
assert!(s.f1 == 15);
|
||||
assert!(s.f2 == 13);
|
||||
assert!(s.f3 == 17);
|
||||
|
||||
let s = S5{f3: &5, f4: 3};
|
||||
assert!(*s.f3 == 5);
|
||||
assert!(s.f4 == 3);
|
||||
|
||||
let s = S7{f3: 5u, f4: 3};
|
||||
assert!(s.f3 == 5u);
|
||||
assert!(s.f4 == 3);
|
||||
}
|
25
src/test/run-pass/inherit-struct2.rs
Normal file
25
src/test/run-pass/inherit-struct2.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test struct inheritance on structs from another crate.
|
||||
|
||||
// aux-build:inherit_struct_lib.rs
|
||||
extern crate inherit_struct_lib;
|
||||
|
||||
pub fn main() {
|
||||
let s = inherit_struct_lib::S2{f1: 115, f2: 113};
|
||||
assert!(s.f1 == 115);
|
||||
assert!(s.f2 == 113);
|
||||
|
||||
assert!(inherit_struct_lib::glob_s.f1 == 32);
|
||||
assert!(inherit_struct_lib::glob_s.f2 == -45);
|
||||
|
||||
inherit_struct_lib::test_s2(s);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue