Implement empty struct with braces (RFC 218)
This commit is contained in:
parent
cff0411706
commit
5fa6e857c9
11 changed files with 114 additions and 133 deletions
|
@ -1218,7 +1218,6 @@ impl<'a> State<'a> {
|
||||||
fields: &[hir::Field],
|
fields: &[hir::Field],
|
||||||
wth: &Option<P<hir::Expr>>) -> io::Result<()> {
|
wth: &Option<P<hir::Expr>>) -> io::Result<()> {
|
||||||
try!(self.print_path(path, true, 0));
|
try!(self.print_path(path, true, 0));
|
||||||
if !(fields.is_empty() && wth.is_none()) {
|
|
||||||
try!(word(&mut self.s, "{"));
|
try!(word(&mut self.s, "{"));
|
||||||
try!(self.commasep_cmnt(
|
try!(self.commasep_cmnt(
|
||||||
Consistent,
|
Consistent,
|
||||||
|
@ -1242,10 +1241,11 @@ impl<'a> State<'a> {
|
||||||
try!(self.print_expr(&**expr));
|
try!(self.print_expr(&**expr));
|
||||||
try!(self.end());
|
try!(self.end());
|
||||||
}
|
}
|
||||||
_ => try!(word(&mut self.s, ",")),
|
_ => if !fields.is_empty() {
|
||||||
|
try!(word(&mut self.s, ","))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
try!(word(&mut self.s, "}"));
|
try!(word(&mut self.s, "}"));
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1473,14 +1473,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
_ => return None
|
_ => return None
|
||||||
};
|
};
|
||||||
|
|
||||||
if let ty::VariantKind::Dict = variant.kind() {
|
let var_kind = variant.kind();
|
||||||
|
if var_kind == ty::VariantKind::Dict || var_kind == ty::VariantKind::Unit {
|
||||||
Some((adt, variant))
|
Some((adt, variant))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn write_nil(&self, node_id: ast::NodeId) {
|
pub fn write_nil(&self, node_id: ast::NodeId) {
|
||||||
self.write_ty(node_id, self.tcx().mk_nil());
|
self.write_ty(node_id, self.tcx().mk_nil());
|
||||||
}
|
}
|
||||||
|
|
|
@ -2231,14 +2231,6 @@ impl<'a> Parser<'a> {
|
||||||
&[token::CloseDelim(token::Brace)]));
|
&[token::CloseDelim(token::Brace)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if fields.is_empty() && base.is_none() {
|
|
||||||
let last_span = self.last_span;
|
|
||||||
self.span_err(last_span,
|
|
||||||
"structure literal must either \
|
|
||||||
have at least one field or use \
|
|
||||||
structure update syntax");
|
|
||||||
}
|
|
||||||
|
|
||||||
hi = self.span.hi;
|
hi = self.span.hi;
|
||||||
try!(self.expect(&token::CloseDelim(token::Brace)));
|
try!(self.expect(&token::CloseDelim(token::Brace)));
|
||||||
ex = ExprStruct(pth, fields, base);
|
ex = ExprStruct(pth, fields, base);
|
||||||
|
@ -4713,14 +4705,14 @@ impl<'a> Parser<'a> {
|
||||||
(Vec::new(), Some(ast::DUMMY_NODE_ID))
|
(Vec::new(), Some(ast::DUMMY_NODE_ID))
|
||||||
} else {
|
} else {
|
||||||
// If we see: `struct Foo<T> where T: Copy { ... }`
|
// If we see: `struct Foo<T> where T: Copy { ... }`
|
||||||
(try!(self.parse_record_struct_body(&class_name)), None)
|
(try!(self.parse_record_struct_body()), None)
|
||||||
}
|
}
|
||||||
// No `where` so: `struct Foo<T>;`
|
// No `where` so: `struct Foo<T>;`
|
||||||
} else if try!(self.eat(&token::Semi) ){
|
} else if try!(self.eat(&token::Semi) ){
|
||||||
(Vec::new(), Some(ast::DUMMY_NODE_ID))
|
(Vec::new(), Some(ast::DUMMY_NODE_ID))
|
||||||
// Record-style struct definition
|
// Record-style struct definition
|
||||||
} else if self.token == token::OpenDelim(token::Brace) {
|
} else if self.token == token::OpenDelim(token::Brace) {
|
||||||
let fields = try!(self.parse_record_struct_body(&class_name));
|
let fields = try!(self.parse_record_struct_body());
|
||||||
(fields, None)
|
(fields, None)
|
||||||
// Tuple-style struct definition with optional where-clause.
|
// Tuple-style struct definition with optional where-clause.
|
||||||
} else if self.token == token::OpenDelim(token::Paren) {
|
} else if self.token == token::OpenDelim(token::Paren) {
|
||||||
|
@ -4740,20 +4732,13 @@ impl<'a> Parser<'a> {
|
||||||
None))
|
None))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_record_struct_body(&mut self,
|
pub fn parse_record_struct_body(&mut self) -> PResult<Vec<StructField>> {
|
||||||
class_name: &ast::Ident) -> PResult<Vec<StructField>> {
|
|
||||||
let mut fields = Vec::new();
|
let mut fields = Vec::new();
|
||||||
if try!(self.eat(&token::OpenDelim(token::Brace)) ){
|
if try!(self.eat(&token::OpenDelim(token::Brace)) ){
|
||||||
while self.token != token::CloseDelim(token::Brace) {
|
while self.token != token::CloseDelim(token::Brace) {
|
||||||
fields.push(try!(self.parse_struct_decl_field(true)));
|
fields.push(try!(self.parse_struct_decl_field(true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if fields.is_empty() {
|
|
||||||
return Err(self.fatal(&format!("unit-like struct definition should be \
|
|
||||||
written as `struct {};`",
|
|
||||||
class_name)));
|
|
||||||
}
|
|
||||||
|
|
||||||
try!(self.bump());
|
try!(self.bump());
|
||||||
} else {
|
} else {
|
||||||
let token_str = self.this_token_to_string();
|
let token_str = self.this_token_to_string();
|
||||||
|
|
|
@ -1855,7 +1855,6 @@ impl<'a> State<'a> {
|
||||||
fields: &[ast::Field],
|
fields: &[ast::Field],
|
||||||
wth: &Option<P<ast::Expr>>) -> io::Result<()> {
|
wth: &Option<P<ast::Expr>>) -> io::Result<()> {
|
||||||
try!(self.print_path(path, true, 0));
|
try!(self.print_path(path, true, 0));
|
||||||
if !(fields.is_empty() && wth.is_none()) {
|
|
||||||
try!(word(&mut self.s, "{"));
|
try!(word(&mut self.s, "{"));
|
||||||
try!(self.commasep_cmnt(
|
try!(self.commasep_cmnt(
|
||||||
Consistent,
|
Consistent,
|
||||||
|
@ -1879,10 +1878,11 @@ impl<'a> State<'a> {
|
||||||
try!(self.print_expr(&**expr));
|
try!(self.print_expr(&**expr));
|
||||||
try!(self.end());
|
try!(self.end());
|
||||||
}
|
}
|
||||||
_ => try!(word(&mut self.s, ",")),
|
_ => if !fields.is_empty() {
|
||||||
|
try!(word(&mut self.s, ","))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
try!(word(&mut self.s, "}"));
|
try!(word(&mut self.s, "}"));
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
// file at the top-level directory of this distribution and at
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
//
|
//
|
||||||
|
@ -8,13 +8,10 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
// Empty struct defined with braces shouldn't add names into value namespace
|
||||||
|
|
||||||
struct Foo;
|
struct Empty {}
|
||||||
|
|
||||||
fn f2() {
|
fn main() {
|
||||||
let _end_stmt = Foo { };
|
let e = Empty; //~ ERROR `Empty` is the name of a struct or struct variant
|
||||||
//~^ ERROR: structure literal must either have at least one field
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
// file at the top-level directory of this distribution and at
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
//
|
//
|
||||||
|
@ -8,13 +8,17 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
// Empty struct defined with braces shouldn't add names into value namespace
|
||||||
|
|
||||||
struct Foo;
|
#![deny(warnings)]
|
||||||
|
|
||||||
fn g3() {
|
struct Empty {}
|
||||||
let _mid_tuple = (Foo { }, 2);
|
|
||||||
//~^ ERROR: structure literal must either have at least one field
|
fn main() {
|
||||||
|
let e = Empty {};
|
||||||
|
|
||||||
|
match e {
|
||||||
|
Empty => () //~ ERROR unused variable: `Empty`
|
||||||
|
//~^ ERROR variable `Empty` should have a snake case name such as `empty`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
|
|
@ -22,8 +22,8 @@ fn main() {
|
||||||
let Foo { .. } = x; //~ ERROR `Foo` does not name a struct
|
let Foo { .. } = x; //~ ERROR `Foo` does not name a struct
|
||||||
|
|
||||||
let x = Bar;
|
let x = Bar;
|
||||||
Bar { ..x }; //~ ERROR `Bar` does not name a structure
|
Bar { ..x };
|
||||||
let Bar { .. } = x; //~ ERROR `Bar` does not name a struct
|
let Bar { .. } = x;
|
||||||
|
|
||||||
match Enum::Bar {
|
match Enum::Bar {
|
||||||
Enum::Bar { .. } //~ ERROR `Enum::Bar` does not name a struct
|
Enum::Bar { .. } //~ ERROR `Enum::Bar` does not name a struct
|
||||||
|
|
|
@ -1,20 +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.
|
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
|
||||||
|
|
||||||
struct Foo;
|
|
||||||
|
|
||||||
fn h4() {
|
|
||||||
let _end_of_tuple = (3, Foo { });
|
|
||||||
//~^ ERROR: structure literal must either have at least one field
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
|
@ -1,20 +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.
|
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
|
||||||
|
|
||||||
struct Foo;
|
|
||||||
|
|
||||||
fn i5() {
|
|
||||||
let _end_of_block = { Foo { } };
|
|
||||||
//~^ ERROR: structure literal must either have at least one field
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
31
src/test/run-pass/empty-struct-with-braces.rs
Normal file
31
src/test/run-pass/empty-struct-with-braces.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Empty struct defined with braces add names into type namespace
|
||||||
|
// Empty struct defined without braces add names into both type and value namespaces
|
||||||
|
|
||||||
|
struct Empty1 {}
|
||||||
|
struct Empty2;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let e1: Empty1 = Empty1 {};
|
||||||
|
let e2: Empty2 = Empty2 {};
|
||||||
|
let e2: Empty2 = Empty2;
|
||||||
|
|
||||||
|
match e1 {
|
||||||
|
Empty1 {} => ()
|
||||||
|
}
|
||||||
|
match e2 {
|
||||||
|
Empty2 {} => ()
|
||||||
|
}
|
||||||
|
match e2 {
|
||||||
|
Empty2 => ()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
// file at the top-level directory of this distribution and at
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
//
|
//
|
||||||
|
@ -8,9 +8,13 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
//`#[cfg]` on struct field permits empty unusable struct
|
||||||
|
|
||||||
struct Foo {}
|
struct S {
|
||||||
//~^ ERROR: unit-like struct definition should be written as `struct Foo;`
|
#[cfg(untrue)]
|
||||||
|
a: int,
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {
|
||||||
|
let s = S {};
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue