]> git.lizzy.rs Git - rust.git/commitdiff
Allow inheritance between structs.
authorNick Cameron <ncameron@mozilla.com>
Mon, 24 Feb 2014 07:17:02 +0000 (20:17 +1300)
committerNick Cameron <ncameron@mozilla.com>
Sun, 20 Apr 2014 01:41:18 +0000 (13:41 +1200)
No subtyping, no interaction with traits. Partially addresses #9912.

31 files changed:
src/doc/rust.md
src/librustc/front/config.rs
src/librustc/front/feature_gate.rs
src/librustc/metadata/common.rs
src/librustc/metadata/decoder.rs
src/librustc/metadata/encoder.rs
src/librustc/middle/privacy.rs
src/librustc/middle/resolve.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/collect.rs
src/libsyntax/ast.rs
src/libsyntax/fold.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs
src/test/auxiliary/inherit_struct_lib.rs [new file with mode: 0644]
src/test/compile-fail/inherit-struct1.rs [new file with mode: 0644]
src/test/compile-fail/inherit-struct2.rs [new file with mode: 0644]
src/test/compile-fail/inherit-struct3.rs [new file with mode: 0644]
src/test/compile-fail/inherit-struct4.rs [new file with mode: 0644]
src/test/compile-fail/inherit-struct5.rs [new file with mode: 0644]
src/test/compile-fail/inherit-struct6.rs [new file with mode: 0644]
src/test/compile-fail/inherit-struct7.rs [new file with mode: 0644]
src/test/compile-fail/inherit-struct8.rs [new file with mode: 0644]
src/test/compile-fail/inherit-struct9.rs [new file with mode: 0644]
src/test/compile-fail/removed-syntax-class-traits.rs [deleted file]
src/test/debug-info/simple-struct.rs
src/test/run-pass/inherit-struct1.rs [new file with mode: 0644]
src/test/run-pass/inherit-struct2.rs [new file with mode: 0644]

index 17941a152094fadf8165adb420c358a1eac5112c..7b402cd4b16d43f73870a43f04fa5df34175aeeb 100644 (file)
@@ -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*,
index 703ff51b3b0e206532019cd34e910f195eed35ee..e630d7e15e03936054c25e02215739a01fe14f40 100644 (file)
@@ -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,
     }
 }
 
index 3ab39dd121f082aca119f359f69293b8863e4b42..0f76075656e0203f3e08694bcb58622a29428c9b 100644 (file)
@@ -55,6 +55,7 @@
     ("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 @@ fn visit_item(&mut self, i: &ast::Item, _:()) {
                 }
             }
 
-            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");
+                }
             }
 
             _ => {}
index 264829b18a309453d318327537b153883b2509aa..4a0b3ea0cf6a03c11b2042e42984c60776cbf1d0 100644 (file)
@@ -92,6 +92,7 @@
 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 @@ impl items contain tag_item_impl_method elements, and classes
   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;
@@ -151,9 +152,9 @@ pub fn from_uint(value : uint) -> Option<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 fn from_uint(value : uint) -> Option<astencode_tag> {
 //   - 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 {
index ee7ce817a3f202dbf8f88794483fe80adc640db8..b1cede8e410c494c6bab9bba47938cb6ca85a7e6 100644 (file)
@@ -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
     });
index 085a96ea7be2f3cc31265d193758b66c0cb890c7..f4c3f5640682ffa8b6900557053cd8bac3facf6d 100644 (file)
@@ -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();
     }
 }
 
@@ -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 add_to_index(item: &Item, ebml_w: &Encoder,
                                  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 add_to_index(item: &Item, ebml_w: &Encoder,
         /* 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));
 
index b2e1a992f54792b6f472e744d878ffdf3090feba..59d4c2e03d499b75b70952085cb0c77d17eecd25 100644 (file)
@@ -488,7 +488,7 @@ fn private_accessible(&self, id: ast::NodeId) -> bool {
         // 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 @@ fn ensure_public(&self, span: Span, to_check: ast::DefId,
     }
 
     // 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)
index 70483aac7062d0336590875e87a2c5db48ee8177..9112434b12c83666d5ab3081f6d6672ca51bc1e1 100644 (file)
@@ -3708,6 +3708,7 @@ fn resolve_item(&mut self, item: &Item) {
             ItemStruct(ref struct_def, ref generics) => {
                 self.resolve_struct(item.id,
                                     generics,
+                                    struct_def.super_struct,
                                     struct_def.fields.as_slice());
             }
 
@@ -3922,30 +3923,10 @@ fn resolve_trait_reference(&mut self,
     }
 
     fn resolve_struct(&mut self,
-                          id: NodeId,
-                          generics: &Generics,
-                          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);
-                        }
-                    }
-                }
-                _ => ()
-            }
-        }
-
+                      id: NodeId,
+                      generics: &Generics,
+                      super_struct: Option<P<Ty>>,
+                      fields: &[StructField]) {
         // If applicable, create a rib for the type parameters.
         self.with_type_parameter_rib(HasTypeParameters(generics,
                                                        id,
@@ -3955,6 +3936,39 @@ fn resolve_struct(&mut self,
             // 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);
index d6f1866f5dc0386e77c78d1c3303e4ac4984e076..e32ab1fc8e39a10c4199e65884f82b8c4dc4bdde 100644 (file)
@@ -52,7 +52,6 @@
 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,60 +3992,70 @@ pub fn lookup_field_type(tcx: &ctxt,
     subst(tcx, substs, t)
 }
 
-// Look up the list of field names and IDs for a given struct
+// 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!("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 {
-        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")
-                    }
+        // 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)));
                 }
             }
-            _ => {
-                cx.sess.bug(
-                    format!("struct ID not bound to an item: {}",
-                        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,
-                }
-            }
-            UnnamedField(visibility) => {
-                field_ty {
-                    name: syntax::parse::token::special_idents::unnamed_field.name,
-                    id: ast_util::local_def(field.node.id),
-                    vis: visibility,
-                }
-            }
-        }
-    }).collect()
+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")
+    }
 }
 
 // Returns a list of fields corresponding to the struct's items. trans uses
index d971b2c31c229b6834705a5b4264e25d76125fa4..f640b5dc9be0f30318d2b79d1882bb226d4409b4 100644 (file)
 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);
     }
@@ -2385,14 +2440,14 @@ fn check_struct_constructor(fcx: &FnCtxt,
         // Look up and check the fields.
         let class_fields = ty::lookup_struct_fields(tcx, class_id);
         check_struct_or_variant_fields(fcx,
-                                           struct_type,
-                                           span,
-                                           class_id,
-                                           id,
-                                           substitutions,
-                                           class_fields.as_slice(),
-                                           fields,
-                                           base_expr.is_none());
+                                       struct_type,
+                                       span,
+                                       class_id,
+                                       id,
+                                       substitutions,
+                                       class_fields.as_slice(),
+                                       fields,
+                                       base_expr.is_none());
         if ty::type_is_error(fcx.node_ty(id)) {
             struct_type = ty::mk_err();
         }
index 6df8da3edaa69e39f3c107b6056d5659614af820..490a52df2ba7a0ca42425b645791e69801140ed9 100644 (file)
@@ -46,7 +46,7 @@
 use util::ppaux::Repr;
 
 use std::rc::Rc;
-use collections::HashSet;
+use collections::{HashMap, HashSet};
 
 use syntax::abi;
 use syntax::ast::{RegionTyParamBound, TraitTyParamBound};
@@ -440,15 +440,35 @@ 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 */
     ccx.tcx.tcache.borrow_mut().insert(local_def(v.node.id),
-                          ty::ty_param_bounds_and_ty {
-                              generics: struct_generics.clone(),
-                              ty: tt
-                          });
+                                       ty::ty_param_bounds_and_ty {
+                                           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);
 
index 33c0f2c46bb5ecbf48562d17f3f3e79e5c9deb46..2b6f94e6bf5188008b4ab65f54f22157c3cd9145 100644 (file)
@@ -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.
 }
 
 /*
index fc4f427d8d738e7bb72b0e0dd7f64904dcdefa1b..73ad2664be4c078312b400f54e1f46d585bc691d 100644 (file)
@@ -235,7 +235,12 @@ fn fold_variant(&mut self, v: &Variant) -> P<Variant> {
                 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,
     }
 }
 
index 58634be1995662242977d1ba2c9c0d9198998a78..3d09147d8f3026a1efae9ae7851ec6b825f370a5 100644 (file)
@@ -3884,11 +3884,26 @@ fn parse_trait_ref_list(&mut self, ket: &token::Token) -> Vec<TraitRef> {
     }
 
     // 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 mut fields: Vec<StructField> ;
+        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;
 
         if self.eat(&token::LBRACE) {
@@ -3938,7 +3953,9 @@ fn parse_item_struct(&mut self) -> ItemInfo {
         (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 @@ fn parse_struct_def(&mut self) -> @StructDef {
 
         return @ast::StructDef {
             fields: fields,
-            ctor_id: None
+            ctor_id: None,
+            super_struct: None,
+            is_virtual: false,
         };
     }
 
@@ -4514,6 +4533,12 @@ fn parse_item_or_view_item(&mut self,
                             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 @@ fn parse_item_or_view_item(&mut self,
         }
         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,
index 77743cdb9dfcb2d63b85b1988f0022fd0b5363c8..611ce7cc52798081beecffa6305322a9c2e4574c 100644 (file)
@@ -474,22 +474,23 @@ pub mod 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");
     }
 }
 
index 7041a6585a0cd64bd6665386cde7004362b92f02..f4e337e2048f3b34f9b4f5f249019359b9ed274e 100644 (file)
@@ -640,6 +640,9 @@ pub fn print_item(&mut self, item: &ast::Item) -> IoResult<()> {
                 ));
             }
             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 @@ pub fn print_struct(&mut self,
                         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());
index 266de67b81d7e0295d1716613935bc38705cf765..1f75c2e062ff06deae64da3aa7a6de495e1d7c82 100644 (file)
@@ -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())
     }
diff --git a/src/test/auxiliary/inherit_struct_lib.rs b/src/test/auxiliary/inherit_struct_lib.rs
new file mode 100644 (file)
index 0000000..fd049a2
--- /dev/null
@@ -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 };
diff --git a/src/test/compile-fail/inherit-struct1.rs b/src/test/compile-fail/inherit-struct1.rs
new file mode 100644 (file)
index 0000000..00ea4b7
--- /dev/null
@@ -0,0 +1,17 @@
+// 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 S6 : ~S2; //~ ERROR not a struct
+
+pub fn main() {
+}
diff --git a/src/test/compile-fail/inherit-struct2.rs b/src/test/compile-fail/inherit-struct2.rs
new file mode 100644 (file)
index 0000000..99fd2d2
--- /dev/null
@@ -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() {
+}
diff --git a/src/test/compile-fail/inherit-struct3.rs b/src/test/compile-fail/inherit-struct3.rs
new file mode 100644 (file)
index 0000000..8832903
--- /dev/null
@@ -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`
+}
diff --git a/src/test/compile-fail/inherit-struct4.rs b/src/test/compile-fail/inherit-struct4.rs
new file mode 100644 (file)
index 0000000..e01ec29
--- /dev/null
@@ -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() {
+}
diff --git a/src/test/compile-fail/inherit-struct5.rs b/src/test/compile-fail/inherit-struct5.rs
new file mode 100644 (file)
index 0000000..c40d27c
--- /dev/null
@@ -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() {
+}
diff --git a/src/test/compile-fail/inherit-struct6.rs b/src/test/compile-fail/inherit-struct6.rs
new file mode 100644 (file)
index 0000000..e8c86dc
--- /dev/null
@@ -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
+}
diff --git a/src/test/compile-fail/inherit-struct7.rs b/src/test/compile-fail/inherit-struct7.rs
new file mode 100644 (file)
index 0000000..fb0c917
--- /dev/null
@@ -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() {
+}
diff --git a/src/test/compile-fail/inherit-struct8.rs b/src/test/compile-fail/inherit-struct8.rs
new file mode 100644 (file)
index 0000000..d110834
--- /dev/null
@@ -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() {
+}
diff --git a/src/test/compile-fail/inherit-struct9.rs b/src/test/compile-fail/inherit-struct9.rs
new file mode 100644 (file)
index 0000000..70e341d
--- /dev/null
@@ -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() {
+}
diff --git a/src/test/compile-fail/removed-syntax-class-traits.rs b/src/test/compile-fail/removed-syntax-class-traits.rs
deleted file mode 100644 (file)
index 45b6485..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2013 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.
-
-struct q : r {
-    //~^ ERROR expected `{`, `(`, or `;` after struct name
-    foo: int
-}
index 736ab76f7dbdbbcaa15d03118a5027181f180de2..2ac3b48f6827b9600a89866e47599e5b8c3ad319 100644 (file)
 // 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 @@ struct 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;
diff --git a/src/test/run-pass/inherit-struct1.rs b/src/test/run-pass/inherit-struct1.rs
new file mode 100644 (file)
index 0000000..4602f13
--- /dev/null
@@ -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);
+}
diff --git a/src/test/run-pass/inherit-struct2.rs b/src/test/run-pass/inherit-struct2.rs
new file mode 100644 (file)
index 0000000..bbcba0a
--- /dev/null
@@ -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);
+}