diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index 852d9d80a9148..b902a46fea314 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -49,7 +49,7 @@ use std::collections::{HashMap, HashSet}; use syntax::ast::{self, CrateNum, Name, NodeId}; use syntax::attr::{self, AttrMetaMethods}; use syntax::codemap::{DUMMY_SP, Span}; -use syntax::parse::token::{InternedString, special_idents}; +use syntax::parse::token::InternedString; use rustc_front::hir; use rustc_front::hir::{ItemImpl, ItemTrait}; @@ -1353,6 +1353,7 @@ pub struct VariantDefData<'tcx, 'container: 'tcx> { pub name: Name, // struct's name if this is a struct pub disr_val: Disr, pub fields: Vec>, + pub kind: VariantKind, } pub struct FieldDefData<'tcx, 'container: 'tcx> { @@ -1607,13 +1608,7 @@ impl<'tcx, 'container> VariantDefData<'tcx, 'container> { } pub fn kind(&self) -> VariantKind { - match self.fields.get(0) { - None => VariantKind::Unit, - Some(&FieldDefData { name, .. }) if name == special_idents::unnamed_field.name => { - VariantKind::Tuple - } - Some(_) => VariantKind::Struct - } + self.kind } pub fn is_tuple_struct(&self) -> bool { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index b8dfb9f74c6a4..def5897e92d9d 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -101,12 +101,15 @@ enum Family { Mod, // m ForeignMod, // n Enum, // t - TupleVariant, // v StructVariant, // V + TupleVariant, // v + UnitVariant, // w Impl, // i - DefaultImpl, // d + DefaultImpl, // d Trait, // I Struct, // S + TupleStruct, // s + UnitStruct, // u PublicField, // g InheritedField, // N Constant, // C @@ -126,12 +129,15 @@ fn item_family(item: rbml::Doc) -> Family { 'm' => Mod, 'n' => ForeignMod, 't' => Enum, - 'v' => TupleVariant, 'V' => StructVariant, + 'v' => TupleVariant, + 'w' => UnitVariant, 'i' => Impl, 'd' => DefaultImpl, 'I' => Trait, 'S' => Struct, + 's' => TupleStruct, + 'u' => UnitStruct, 'g' => PublicField, 'N' => InheritedField, c => panic!("unexpected family char: {}", c) @@ -282,7 +288,7 @@ fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike { } ImmStatic => DlDef(def::DefStatic(did, false)), MutStatic => DlDef(def::DefStatic(did, true)), - Struct => DlDef(def::DefStruct(did)), + Struct | TupleStruct | UnitStruct => DlDef(def::DefStruct(did)), Fn => DlDef(def::DefFn(did, false)), CtorFn => DlDef(def::DefFn(did, true)), Method | StaticMethod => { @@ -302,7 +308,7 @@ fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike { let enum_did = item_require_parent_item(cdata, item); DlDef(def::DefVariant(enum_did, did, true)) } - TupleVariant => { + TupleVariant | UnitVariant => { let enum_did = item_require_parent_item(cdata, item); DlDef(def::DefVariant(enum_did, did, false)) } @@ -365,6 +371,14 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner, item_id: DefIndex, tcx: &ty::ctxt<'tcx>) -> ty::AdtDefMaster<'tcx> { + fn family_to_variant_kind<'tcx>(family: Family, tcx: &ty::ctxt<'tcx>) -> ty::VariantKind { + match family { + Struct | StructVariant => ty::VariantKind::Struct, + TupleStruct | TupleVariant => ty::VariantKind::Tuple, + UnitStruct | UnitVariant => ty::VariantKind::Unit, + _ => tcx.sess.bug(&format!("unexpected family: {:?}", family)), + } + } fn get_enum_variants<'tcx>(intr: &IdentInterner, cdata: Cmd, doc: rbml::Doc, @@ -384,7 +398,8 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner, did: did, name: item_name(intr, item), fields: get_variant_fields(intr, cdata, item, tcx), - disr_val: disr + disr_val: disr, + kind: family_to_variant_kind(item_family(item), tcx), } }).collect() } @@ -417,7 +432,8 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner, did: did, name: item_name(intr, doc), fields: get_variant_fields(intr, cdata, doc, tcx), - disr_val: 0 + disr_val: 0, + kind: family_to_variant_kind(item_family(doc), tcx), } } @@ -428,7 +444,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner, (ty::AdtKind::Enum, get_enum_variants(intr, cdata, doc, tcx)) } - Struct => { + Struct | TupleStruct | UnitStruct => { let ctor_did = reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor). map_or(did, |ctor_doc| translated_def_id(cdata, ctor_doc)); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 22da853dfedb5..ec70a610e0b3a 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -285,8 +285,9 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, vid); encode_family(rbml_w, match variant.kind() { - ty::VariantKind::Unit | ty::VariantKind::Tuple => 'v', - ty::VariantKind::Struct => 'V' + ty::VariantKind::Struct => 'V', + ty::VariantKind::Tuple => 'v', + ty::VariantKind::Unit => 'w', }); encode_name(rbml_w, variant.name); encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(id)); @@ -1043,7 +1044,11 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, /* Now, make an item for the class itself */ rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'S'); + encode_family(rbml_w, match *struct_def { + hir::VariantData::Struct(..) => 'S', + hir::VariantData::Tuple(..) => 's', + hir::VariantData::Unit(..) => 'u', + }); encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); encode_item_variances(rbml_w, ecx, item.id); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index af2824d0930d2..eb204c5641495 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1006,7 +1006,12 @@ fn convert_struct_variant<'tcx>(tcx: &ty::ctxt<'tcx>, did: did, name: name, disr_val: disr_val, - fields: fields + fields: fields, + kind: match *def { + hir::VariantData::Struct(..) => ty::VariantKind::Struct, + hir::VariantData::Tuple(..) => ty::VariantKind::Tuple, + hir::VariantData::Unit(..) => ty::VariantKind::Unit, + } } } diff --git a/src/test/auxiliary/empty-struct.rs b/src/test/auxiliary/empty-struct.rs new file mode 100644 index 0000000000000..3b92bc3121792 --- /dev/null +++ b/src/test/auxiliary/empty-struct.rs @@ -0,0 +1,19 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(braced_empty_structs)] + +pub struct XEmpty1 {} +pub struct XEmpty2; + +pub enum XE { + XEmpty3 {}, + XEmpty4, +} diff --git a/src/test/compile-fail/empty-struct-braces-expr.rs b/src/test/compile-fail/empty-struct-braces-expr.rs index 67167086b9c4a..6ae0dad0e7bfb 100644 --- a/src/test/compile-fail/empty-struct-braces-expr.rs +++ b/src/test/compile-fail/empty-struct-braces-expr.rs @@ -10,17 +10,28 @@ // Can't use empty braced struct as constant or constructor function +// aux-build:empty-struct.rs + #![feature(braced_empty_structs)] +extern crate empty_struct; +use empty_struct::*; + struct Empty1 {} enum E { - Empty2 {} + Empty3 {} } fn main() { let e1 = Empty1; //~ ERROR `Empty1` is the name of a struct or struct variant let e1 = Empty1(); //~ ERROR `Empty1` is the name of a struct or struct variant - let e2 = E::Empty2; //~ ERROR `E::Empty2` is the name of a struct or struct variant - let e2 = E::Empty2(); //~ ERROR `E::Empty2` is the name of a struct or struct variant + let e3 = E::Empty3; //~ ERROR `E::Empty3` is the name of a struct or struct variant + let e3 = E::Empty3(); //~ ERROR `E::Empty3` is the name of a struct or struct variant + + // FIXME: non-local struct kind should be known early (e.g. kept in `DefStruct`) + // let xe1 = XEmpty1; // ERROR `XEmpty1` is the name of a struct or struct variant + let xe1 = XEmpty1(); //~ ERROR expected function, found `empty_struct::XEmpty1` + let xe3 = XE::Empty3; //~ ERROR no associated item named `Empty3` found for type + let xe3 = XE::Empty3(); //~ ERROR no associated item named `Empty3` found for type } diff --git a/src/test/compile-fail/empty-struct-braces-pat-1.rs b/src/test/compile-fail/empty-struct-braces-pat-1.rs index 6a6c3f16c04af..27c97a3a55096 100644 --- a/src/test/compile-fail/empty-struct-braces-pat-1.rs +++ b/src/test/compile-fail/empty-struct-braces-pat-1.rs @@ -10,22 +10,35 @@ // Can't use empty braced struct as constant pattern +// aux-build:empty-struct.rs + #![feature(braced_empty_structs)] +extern crate empty_struct; +use empty_struct::*; + struct Empty1 {} enum E { - Empty2 {} + Empty3 {} } fn main() { let e1 = Empty1 {}; - let e2 = E::Empty2 {}; + let e3 = E::Empty3 {}; + let xe1 = XEmpty1 {}; + let xe3 = XE::XEmpty3 {}; match e1 { Empty1 => () // Not an error, `Empty1` is interpreted as a new binding } - match e2 { - E::Empty2 => () //~ ERROR `E::Empty2` does not name a tuple variant or a tuple struct + match e3 { + E::Empty3 => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct + } + match xe1 { + XEmpty1 => () // Not an error, `XEmpty1` is interpreted as a new binding + } + match xe3 { + XE::XEmpty3 => () //~ ERROR no associated item named `XEmpty3` found for type } } diff --git a/src/test/compile-fail/empty-struct-braces-pat-2.rs b/src/test/compile-fail/empty-struct-braces-pat-2.rs index d98d64b712a8b..3436e2a2cd752 100644 --- a/src/test/compile-fail/empty-struct-braces-pat-2.rs +++ b/src/test/compile-fail/empty-struct-braces-pat-2.rs @@ -10,18 +10,30 @@ // Can't use empty braced struct as enum pattern +// aux-build:empty-struct.rs + #![feature(braced_empty_structs)] +extern crate empty_struct; +use empty_struct::*; + struct Empty1 {} fn main() { let e1 = Empty1 {}; + let xe1 = XEmpty1 {}; // Rejected by parser as yet // match e1 { // Empty1() => () // ERROR unresolved enum variant, struct or const `Empty1` // } + // match xe1 { + // XEmpty1() => () // ERROR unresolved enum variant, struct or const `XEmpty1` + // } match e1 { Empty1(..) => () //~ ERROR unresolved enum variant, struct or const `Empty1` } + match xe1 { + XEmpty1(..) => () //~ ERROR `XEmpty1` does not name a tuple variant or a tuple struct + } } diff --git a/src/test/compile-fail/empty-struct-braces-pat-3.rs b/src/test/compile-fail/empty-struct-braces-pat-3.rs index 9fae203f3894d..ca51a1cfc2186 100644 --- a/src/test/compile-fail/empty-struct-braces-pat-3.rs +++ b/src/test/compile-fail/empty-struct-braces-pat-3.rs @@ -10,20 +10,32 @@ // Can't use empty braced struct as enum pattern +// aux-build:empty-struct.rs + #![feature(braced_empty_structs)] +extern crate empty_struct; +use empty_struct::*; + enum E { - Empty2 {} + Empty3 {} } fn main() { - let e2 = E::Empty2 {}; + let e3 = E::Empty3 {}; + let xe3 = XE::XEmpty3 {}; // Rejected by parser as yet - // match e2 { - // E::Empty2() => () // ERROR `E::Empty2` does not name a tuple variant or a tuple struct + // match e3 { + // E::Empty3() => () // ERROR `E::Empty3` does not name a tuple variant or a tuple struct // } - match e2 { - E::Empty2(..) => () //~ ERROR `E::Empty2` does not name a tuple variant or a tuple struct + // match xe3 { + // E::Empty3() => () // ERROR `XE::XEmpty3` does not name a tuple variant or a tuple struct + // } + match e3 { + E::Empty3(..) => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct + } + match xe3 { + XE::XEmpty3(..) => () //~ ERROR no associated item named `XEmpty3` found for type } } diff --git a/src/test/compile-fail/empty-struct-unit-expr.rs b/src/test/compile-fail/empty-struct-unit-expr.rs index 199065665b9f6..822ee9e0dbc10 100644 --- a/src/test/compile-fail/empty-struct-unit-expr.rs +++ b/src/test/compile-fail/empty-struct-unit-expr.rs @@ -10,15 +10,22 @@ // Can't use unit struct as constructor function +// aux-build:empty-struct.rs + #![feature(braced_empty_structs)] -struct Empty1; +extern crate empty_struct; +use empty_struct::*; + +struct Empty2; enum E { - Empty2 + Empty4 } fn main() { - let e1 = Empty1(); //~ ERROR expected function, found `Empty1` - let e2 = E::Empty2(); //~ ERROR expected function, found `E` + let e2 = Empty2(); //~ ERROR expected function, found `Empty2` + let e4 = E::Empty4(); //~ ERROR expected function, found `E` + let xe2 = XEmpty2(); //~ ERROR expected function, found `empty_struct::XEmpty2` + let xe4 = XE::XEmpty4(); //~ ERROR expected function, found `empty_struct::XE` } diff --git a/src/test/compile-fail/empty-struct-unit-pat.rs b/src/test/compile-fail/empty-struct-unit-pat.rs index cffd9fd9b4938..0f54d1b736585 100644 --- a/src/test/compile-fail/empty-struct-unit-pat.rs +++ b/src/test/compile-fail/empty-struct-unit-pat.rs @@ -10,36 +10,59 @@ // Can't use unit struct as enum pattern +// aux-build:empty-struct.rs + #![feature(rustc_attrs)] // remove prior feature after warning cycle and promoting warnings to errors #![feature(braced_empty_structs)] -struct Empty1; +extern crate empty_struct; +use empty_struct::*; + +struct Empty2; enum E { - Empty2 + Empty4 } // remove attribute after warning cycle and promoting warnings to errors #[rustc_error] fn main() { //~ ERROR: compilation successful - let e1 = Empty1; - let e2 = E::Empty2; + let e2 = Empty2; + let e4 = E::Empty4; + let xe2 = XEmpty2; + let xe4 = XE::XEmpty4; // Rejected by parser as yet - // match e1 { - // Empty1() => () // ERROR `Empty1` does not name a tuple variant or a tuple struct + // match e2 { + // Empty2() => () // ERROR `Empty2` does not name a tuple variant or a tuple struct // } - match e1 { - Empty1(..) => () //~ WARN `Empty1` does not name a tuple variant or a tuple struct + // match xe2 { + // XEmpty2() => () // ERROR `XEmpty2` does not name a tuple variant or a tuple struct + // } + match e2 { + Empty2(..) => () //~ WARN `Empty2` does not name a tuple variant or a tuple struct + //~^ WARN hard error + } + match xe2 { + XEmpty2(..) => () //~ WARN `XEmpty2` does not name a tuple variant or a tuple struct //~^ WARN hard error } // Rejected by parser as yet - // match e2 { - // E::Empty2() => () // ERROR `E::Empty2` does not name a tuple variant or a tuple struct + // match e4 { + // E::Empty4() => () // ERROR `E::Empty4` does not name a tuple variant or a tuple struct // } - match e2 { - E::Empty2(..) => () //~ WARN `E::Empty2` does not name a tuple variant or a tuple struct + // match xe4 { + // XE::XEmpty4() => (), // ERROR `XE::XEmpty4` does not name a tuple variant or a tuple + // _ => {}, + // } + match e4 { + E::Empty4(..) => () //~ WARN `E::Empty4` does not name a tuple variant or a tuple struct + //~^ WARN hard error + } + match xe4 { + XE::XEmpty4(..) => (), //~ WARN `XE::XEmpty4` does not name a tuple variant or a tuple //~^ WARN hard error + _ => {}, } } diff --git a/src/test/run-pass/empty-struct-braces.rs b/src/test/run-pass/empty-struct-braces.rs index 80ea1bc3a0e49..b4ce1b97a4c00 100644 --- a/src/test/run-pass/empty-struct-braces.rs +++ b/src/test/run-pass/empty-struct-braces.rs @@ -11,8 +11,13 @@ // Empty struct defined with braces add names into type namespace // Empty struct defined without braces add names into both type and value namespaces +// aux-build:empty-struct.rs + #![feature(braced_empty_structs)] +extern crate empty_struct; +use empty_struct::*; + struct Empty1 {} struct Empty2; struct Empty3 {} @@ -23,7 +28,7 @@ enum E { Empty5, } -fn main() { +fn local() { let e1: Empty1 = Empty1 {}; let e2: Empty2 = Empty2 {}; let e2: Empty2 = Empty2; @@ -84,3 +89,59 @@ fn main() { let e22: Empty2 = Empty2 { ..e2 }; let e33: Empty3 = Empty3 { ..e3 }; } + +fn xcrate() { + let e1: XEmpty1 = XEmpty1 {}; + let e2: XEmpty2 = XEmpty2 {}; + let e2: XEmpty2 = XEmpty2; + let e3: XE = XE::XEmpty3 {}; + // FIXME: Commented out tests are waiting for PR 30882 (fixes for variant namespaces) + // let e4: XE = XE::XEmpty4 {}; + let e4: XE = XE::XEmpty4; + + match e1 { + XEmpty1 {} => {} + } + match e2 { + XEmpty2 {} => {} + } + match e3 { + XE::XEmpty3 {} => {} + _ => {} + } + // match e4 { + // XE::XEmpty4 {} => {} + // _ => {} + // } + + match e1 { + XEmpty1 { .. } => {} + } + match e2 { + XEmpty2 { .. } => {} + } + match e3 { + XE::XEmpty3 { .. } => {} + _ => {} + } + // match e4 { + // XE::XEmpty4 { .. } => {} + // _ => {} + // } + + match e2 { + XEmpty2 => {} + } + // match e4 { + // XE::XEmpty4 => {} + // _ => {} + // } + + let e11: XEmpty1 = XEmpty1 { ..e1 }; + let e22: XEmpty2 = XEmpty2 { ..e2 }; +} + +fn main() { + local(); + xcrate(); +}