提交 59be332a 编写于 作者: V Vadim Petrochenkov

Remove restrictions from tuple structs/variants

Hard errors are turned into feature gates
上级 f55ac694
......@@ -197,27 +197,6 @@ fn visit_foreign_item(&mut self, fi: &ForeignItem) {
visit::walk_foreign_item(self, fi)
}
fn visit_variant_data(&mut self,
vdata: &VariantData,
_: Ident,
_: &Generics,
_: NodeId,
span: Span) {
if vdata.fields().is_empty() {
if vdata.is_tuple() {
self.err_handler()
.struct_span_err(span,
"empty tuple structs and enum variants are not allowed, use \
unit structs and enum variants instead")
.span_help(span,
"remove trailing `()` to make a unit struct or unit enum variant")
.emit();
}
}
visit::walk_struct_def(self, vdata)
}
fn visit_vis(&mut self, vis: &Visibility) {
match *vis {
Visibility::Restricted { ref path, .. } => {
......
......@@ -116,6 +116,7 @@
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::{self, Spanned};
use syntax::feature_gate::{GateIssue, emit_feature_err};
use syntax::parse::token::{self, InternedString, keywords};
use syntax::ptr::P;
use syntax::util::lev_distance::find_best_match_for_name;
......@@ -1700,7 +1701,12 @@ pub fn instantiate_type_path(&self,
node_id: ast::NodeId)
-> Ty<'tcx> {
debug!("instantiate_type_path(did={:?}, path={:?})", did, path);
let type_scheme = self.tcx.lookup_item_type(did);
let mut type_scheme = self.tcx.lookup_item_type(did);
if type_scheme.ty.is_fn() {
// Tuple variants have fn type even in type namespace, extract true variant type from it
let fn_ret = self.tcx.no_late_bound_regions(&type_scheme.ty.fn_ret()).unwrap().unwrap();
type_scheme = ty::TypeScheme { ty: fn_ret, generics: type_scheme.generics }
}
let type_predicates = self.tcx.lookup_predicates(did);
let substs = AstConv::ast_path_substs_for_ty(self, self,
path.span,
......@@ -3244,19 +3250,24 @@ pub fn check_struct_path(&self,
}
_ => None
};
if variant.is_none() || variant.unwrap().kind == ty::VariantKind::Tuple {
// Reject tuple structs for now, braced and unit structs are allowed.
if let Some(variant) = variant {
if variant.kind == ty::VariantKind::Tuple &&
!self.tcx.sess.features.borrow().relaxed_adts {
emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic,
"relaxed_adts", span, GateIssue::Language,
"tuple structs and variants in struct patterns are unstable");
}
let ty = self.instantiate_type_path(def.def_id(), path, node_id);
Some((variant, ty))
} else {
struct_span_err!(self.tcx.sess, path.span, E0071,
"`{}` does not name a struct or a struct variant",
pprust::path_to_string(path))
.span_label(path.span, &format!("not a struct"))
.emit();
return None;
None
}
let ty = self.instantiate_type_path(def.def_id(), path, node_id);
Some((variant.unwrap(), ty))
}
fn check_expr_struct(&self,
......
......@@ -280,7 +280,11 @@ pub fn new() -> Features {
(active, dotdot_in_tuple_patterns, "1.10.0", Some(33627)),
// Allows `impl Trait` in function return types.
(active, conservative_impl_trait, "1.12.0", Some(34511))
(active, conservative_impl_trait, "1.12.0", Some(34511)),
// Allows tuple structs and variants in more contexts,
// Permits numeric fields in struct expressions and patterns.
(active, relaxed_adts, "1.12.0", Some(35626))
);
declare_features! (
......@@ -1022,9 +1026,8 @@ fn visit_pat(&mut self, pattern: &ast::Pat) {
}
PatKind::TupleStruct(_, ref fields, ddpos)
if ddpos.is_none() && fields.is_empty() => {
self.context.span_handler.struct_span_err(pattern.span,
"nullary enum variants are written with \
no trailing `( )`").emit();
gate_feature_post!(&self, relaxed_adts, pattern.span,
"empty tuple structs patterns are unstable");
}
_ => {}
}
......@@ -1107,6 +1110,19 @@ fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
visit::walk_impl_item(self, ii);
}
fn visit_variant_data(&mut self, vdata: &ast::VariantData, _: ast::Ident,
_: &ast::Generics, _: NodeId, span: Span) {
if vdata.fields().is_empty() {
if vdata.is_tuple() {
gate_feature_post!(&self, relaxed_adts, span,
"empty tuple structs and enum variants are unstable, \
use unit structs and enum variants instead");
}
}
visit::walk_struct_def(self, vdata)
}
fn visit_vis(&mut self, vis: &ast::Visibility) {
let span = match *vis {
ast::Visibility::Crate(span) => span,
......
......@@ -8,11 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
enum Foo { FirstValue(i32) }
enum Foo {}
fn main() {
let u = Foo::FirstValue { value: 0 };
//~^ ERROR `Foo::FirstValue` does not name a struct or a struct variant [E0071]
let u = Foo { value: 0 };
//~^ ERROR `Foo` does not name a struct or a struct variant [E0071]
//~| NOTE not a struct
let t = u32 { value: 4 };
......
......@@ -8,10 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(relaxed_adts)]
pub struct XEmpty1 {}
pub struct XEmpty2;
pub struct XEmpty6();
pub enum XE {
XEmpty3 {},
XEmpty4,
XEmpty5(),
}
......@@ -12,6 +12,8 @@
// aux-build:empty-struct.rs
#![feature(relaxed_adts)]
extern crate empty_struct;
use empty_struct::*;
......@@ -21,13 +23,12 @@ 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 variant or struct `Empty1`
}
match xe1 {
XEmpty1() => () //~ ERROR unresolved variant or struct `XEmpty1`
}
match e1 {
Empty1(..) => () //~ ERROR unresolved variant or struct `Empty1`
}
......
......@@ -12,6 +12,8 @@
// aux-build:empty-struct.rs
#![feature(relaxed_adts)]
extern crate empty_struct;
use empty_struct::*;
......@@ -23,13 +25,12 @@ fn main() {
let e3 = E::Empty3 {};
let xe3 = XE::XEmpty3 {};
// Rejected by parser as yet
// match e3 {
// E::Empty3() => () // ERROR `E::Empty3` 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 `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
}
......
// 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 <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.
// Can't use unit struct as enum pattern
// aux-build:empty-struct.rs
#![feature(relaxed_adts)]
extern crate empty_struct;
use empty_struct::*;
struct Empty2();
enum E {
Empty4()
}
// remove attribute after warning cycle and promoting warnings to errors
fn main() {
let e2 = Empty2();
let e4 = E::Empty4();
let xe6 = XEmpty6();
let xe5 = XE::XEmpty5();
match e2 {
Empty2 => () //~ ERROR `Empty2` does not name a unit variant, unit struct or a constant
}
match xe6 {
XEmpty6 => () //~ ERROR `XEmpty6` does not name a unit variant, unit struct or a constant
}
match e4 {
E::Empty4 => () //~ ERROR `E::Empty4` does not name a unit variant, unit struct or a
}
match xe5 {
XE::XEmpty5 => (), //~ ERROR `XE::XEmpty5` does not name a unit variant, unit struct or a
_ => {},
}
}
......@@ -12,6 +12,8 @@
// aux-build:empty-struct.rs
#![feature(relaxed_adts)]
extern crate empty_struct;
use empty_struct::*;
......@@ -28,13 +30,6 @@ fn main() {
let xe2 = XEmpty2;
let xe4 = XE::XEmpty4;
// Rejected by parser as yet
// match e2 {
// Empty2() => () // ERROR `Empty2` 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(..) => () //~ ERROR `Empty2` does not name a tuple variant or a tuple struct
//~^ WARNING hard error
......@@ -43,14 +38,7 @@ fn main() {
XEmpty2(..) => () //~ ERROR `XEmpty2` does not name a tuple variant or a tuple struct
//~^ WARNING hard error
}
// Rejected by parser as yet
// match e4 {
// E::Empty4() => () // ERROR `E::Empty4` 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(..) => () //~ ERROR `E::Empty4` does not name a tuple variant or a tuple struct
//~^ WARNING hard error
......
......@@ -8,39 +8,40 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Feature gate test for empty struct with braces
// Can't use braced expressions and patterns with structs defined without braces
// Can't use unit struct as enum pattern
// aux-build:empty-struct.rs
#![feature(relaxed_adts)]
extern crate empty_struct;
use empty_struct::*;
struct Empty2;
enum E {
Empty5,
Empty4
}
// remove attribute after warning cycle and promoting warnings to errors
fn main() {
let e2: Empty2 = Empty2 {};
let e2: Empty2 = Empty2;
let e5: E = E::Empty5 {};
let e5: E = E::Empty5;
let e2 = Empty2;
let e4 = E::Empty4;
let xe2 = XEmpty2;
let xe4 = XE::XEmpty4;
match e2 {
Empty2 {} => {}
Empty2() => () //~ ERROR `Empty2` does not name a tuple variant or a tuple struct
}
match e2 {
Empty2 => {}
match xe2 {
XEmpty2() => () //~ ERROR `XEmpty2` does not name a tuple variant or a tuple struct
}
match e2 {
Empty2 { .. } => {}
}
match e5 {
E::Empty5 {} => {}
}
match e5 {
E::Empty5 => {}
match e4 {
E::Empty4() => () //~ ERROR `E::Empty4` does not name a tuple variant or a tuple struct
}
match e5 {
E::Empty5 { .. } => {}
match xe4 {
XE::XEmpty4() => (), //~ ERROR `XE::XEmpty4` does not name a tuple variant or a tuple
_ => {},
}
let e22 = Empty2 { ..e2 };
}
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
......@@ -8,27 +8,20 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
struct Foo(u32);
struct Bar;
struct Z(u8, u8);
enum Enum {
Foo(u32),
Bar
enum E {
U(u8, u8),
}
fn main() {
let x = Foo(1);
Foo { ..x }; //~ ERROR `Foo` does not name a struct or a struct variant
let Foo { .. } = x; //~ ERROR `Foo` does not name a struct
let x = Bar;
Bar { ..x };
let Bar { .. } = x;
match Enum::Bar {
Enum::Bar { .. }
=> {}
Enum::Foo { .. } //~ ERROR `Enum::Foo` does not name a struct
=> {}
match Z(0, 1) {
Z{..} => {} //~ ERROR tuple structs and variants in struct patterns are unstable
}
match E::U(0, 1) {
E::U{..} => {} //~ ERROR tuple structs and variants in struct patterns are unstable
}
let z1 = Z(0, 1);
let z2 = Z { ..z1 }; //~ ERROR tuple structs and variants in struct patterns are unstable
}
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
......@@ -8,16 +8,19 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Feature gate test for empty struct with braces
// Can't define an empty braced struct
struct Empty1 {}
struct Empty2;
struct S(); //~ ERROR empty tuple structs and enum variants are unstable
struct Z(u8, u8);
enum E {
Empty4 {},
Empty5,
V(), //~ ERROR empty tuple structs and enum variants are unstable
U(u8, u8),
}
fn main() {
match S() {
S() => {} //~ ERROR empty tuple structs patterns are unstable
}
match E::V() {
E::V() => {} //~ ERROR empty tuple structs patterns are unstable
}
}
// 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.
// For style and consistency reasons, non-parametrized enum variants must
// be used simply as `ident` instead of `ident ()`.
// This test-case covers enum declaration.
enum Foo {
Bar(), //~ ERROR empty tuple structs and enum variants are not allowed
//~^ HELP remove trailing `()` to make a unit struct or unit enum variant
Baz(), //~ ERROR empty tuple structs and enum variants are not allowed
//~^ HELP remove trailing `()` to make a unit struct or unit enum variant
Bazar
}
fn main() {
println!("{}", match Bar { Bar => 1, Baz => 2, Bazar => 3 }) //~ ERROR unresolved name `Bar`
}
// 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.
// compile-flags: -Z continue-parse-after-error
// For style and consistency reasons, non-parametrized enum variants must
// be used simply as `ident` instead of `ident ()`.
// This test-case covers enum matching.
enum Foo {
Bar,
Baz,
Bazar
}
fn main() {
println!("{}", match Bar {
Bar() => 1, //~ ERROR nullary enum variants are written with no trailing `( )`
Baz() => 2, //~ ERROR nullary enum variants are written with no trailing `( )`
Bazar => 3
})
}
......@@ -8,13 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
struct TS ( //~ ERROR empty tuple structs and enum variants are not allowed
struct TS ( //~ ERROR empty tuple structs and enum variants are unstable
#[cfg(untrue)]
i32,
);
enum E {
TV ( //~ ERROR empty tuple structs and enum variants are not allowed
TV ( //~ ERROR empty tuple structs and enum variants are unstable
#[cfg(untrue)]
i32,
)
......
......@@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(relaxed_adts)]
enum MyOption<T> {
MySome(T),
MyNone,
......@@ -16,7 +18,8 @@ enum MyOption<T> {
fn main() {
match MyOption::MySome(42) {
MyOption::MySome { x: 42 } => (),
//~^ ERROR `MyOption::MySome` does not name a struct or a struct variant
//~^ ERROR struct `MyOption::MySome` does not have a field named `x`
//~| ERROR pattern does not mention field `0`
_ => (),
}
}
......@@ -8,8 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(relaxed_adts)]
struct NonCopyable(());
fn main() {
let z = NonCopyable{ p: () }; //~ ERROR `NonCopyable` does not name a struct or a struct variant
let z = NonCopyable{ p: () }; //~ ERROR structure `NonCopyable` has no field named `p`
}
// 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.
struct Foo(); //~ ERROR empty tuple structs and enum variants are not allowed
fn main() {}
......@@ -8,10 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(relaxed_adts)]
pub struct XEmpty1 {}
pub struct XEmpty2;
pub struct XEmpty7();
pub enum XE {
XEmpty3 {},
XEmpty4,
XEmpty6(),
}
......@@ -13,11 +13,14 @@
// aux-build:empty-struct.rs
#![feature(relaxed_adts)]
extern crate empty_struct;
use empty_struct::*;
struct Empty1 {}
struct Empty2;
struct Empty7();
#[derive(PartialEq, Eq)]
struct Empty3 {}
......@@ -27,6 +30,7 @@ struct Empty3 {}
enum E {
Empty4 {},
Empty5,
Empty6(),
}
fn local() {
......@@ -38,6 +42,12 @@ fn local() {
let e4: E = E::Empty4 {};
let e5: E = E::Empty5 {};
let e5: E = E::Empty5;
let e6: E = E::Empty6 {};
let e6: E = E::Empty6();
let ctor6: fn() -> E = E::Empty6;
let e7: Empty7 = Empty7 {};
let e7: Empty7 = Empty7();
let ctor7: fn() -> Empty7 = Empty7;
match e1 {
Empty1 {} => {}
......@@ -56,6 +66,13 @@ fn local() {
E::Empty5 {} => {}
_ => {}
}
match e6 {
E::Empty6 {} => {}
_ => {}
}
match e7 {
Empty7 {} => {}
}
match e1 {
Empty1 { .. } => {}
......@@ -74,6 +91,13 @@ fn local() {
E::Empty5 { .. } => {}
_ => {}
}
match e6 {
E::Empty6 { .. } => {}
_ => {}
}
match e7 {
Empty7 { .. } => {}
}
match e2 {
Empty2 => {}
......@@ -85,10 +109,25 @@ fn local() {
E::Empty5 => {}
_ => {}
}
match e6 {
E::Empty6() => {}
_ => {}
}
match e6 {
E::Empty6(..) => {}
_ => {}
}
match e7 {
Empty7() => {}
}
match e7 {
Empty7(..) => {}
}
let e11: Empty1 = Empty1 { ..e1 };
let e22: Empty2 = Empty2 { ..e2 };
let e33: Empty3 = Empty3 { ..e3 };
let e77: Empty7 = Empty7 { ..e7 };
}
fn xcrate() {
......@@ -98,6 +137,12 @@ fn xcrate() {
let e3: XE = XE::XEmpty3 {};
let e4: XE = XE::XEmpty4 {};
let e4: XE = XE::XEmpty4;
let e6: XE = XE::XEmpty6 {};
let e6: XE = XE::XEmpty6();
let ctor6: fn() -> XE = XE::XEmpty6;
let e7: XEmpty7 = XEmpty7 {};
let e7: XEmpty7 = XEmpty7();
let ctor7: fn() -> XEmpty7 = XEmpty7;
match e1 {
XEmpty1 {} => {}
......@@ -113,6 +158,13 @@ fn xcrate() {
XE::XEmpty4 {} => {}
_ => {}
}
match e6 {
XE::XEmpty6 {} => {}
_ => {}
}
match e7 {
XEmpty7 {} => {}
}
match e1 {
XEmpty1 { .. } => {}
......@@ -128,6 +180,13 @@ fn xcrate() {
XE::XEmpty4 { .. } => {}
_ => {}
}
match e6 {
XE::XEmpty6 { .. } => {}
_ => {}
}
match e7 {
XEmpty7 { .. } => {}
}
match e2 {
XEmpty2 => {}
......@@ -136,9 +195,24 @@ fn xcrate() {
XE::XEmpty4 => {}
_ => {}
}
match e6 {
XE::XEmpty6() => {}
_ => {}
}
match e6 {
XE::XEmpty6(..) => {}
_ => {}
}
match e7 {
XEmpty7() => {}
}
match e7 {
XEmpty7(..) => {}
}
let e11: XEmpty1 = XEmpty1 { ..e1 };
let e22: XEmpty2 = XEmpty2 { ..e2 };
let e77: XEmpty7 = XEmpty7 { ..e7 };
}
fn main() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册