Implement field shorthands in struct literal expressions.
This commit is contained in:
parent
a5b6a9fa8a
commit
9908711e5e
15 changed files with 179 additions and 18 deletions
|
@ -543,6 +543,7 @@ impl<'a> LoweringContext<'a> {
|
||||||
name: respan(f.ident.span, f.ident.node.name),
|
name: respan(f.ident.span, f.ident.node.name),
|
||||||
expr: self.lower_expr(&f.expr),
|
expr: self.lower_expr(&f.expr),
|
||||||
span: f.span,
|
span: f.span,
|
||||||
|
is_shorthand: f.is_shorthand,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1682,6 +1683,7 @@ impl<'a> LoweringContext<'a> {
|
||||||
},
|
},
|
||||||
span: span,
|
span: span,
|
||||||
expr: expr,
|
expr: expr,
|
||||||
|
is_shorthand: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -817,6 +817,7 @@ pub struct Field {
|
||||||
pub name: Spanned<Name>,
|
pub name: Spanned<Name>,
|
||||||
pub expr: P<Expr>,
|
pub expr: P<Expr>,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
pub is_shorthand: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
|
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
|
||||||
|
|
|
@ -1229,8 +1229,10 @@ impl<'a> State<'a> {
|
||||||
&fields[..],
|
&fields[..],
|
||||||
|s, field| {
|
|s, field| {
|
||||||
s.ibox(indent_unit)?;
|
s.ibox(indent_unit)?;
|
||||||
|
if !field.is_shorthand {
|
||||||
s.print_name(field.name.node)?;
|
s.print_name(field.name.node)?;
|
||||||
s.word_space(":")?;
|
s.word_space(":")?;
|
||||||
|
}
|
||||||
s.print_expr(&field.expr)?;
|
s.print_expr(&field.expr)?;
|
||||||
s.end()
|
s.end()
|
||||||
},
|
},
|
||||||
|
|
|
@ -900,6 +900,7 @@ pub struct Field {
|
||||||
pub ident: SpannedIdent,
|
pub ident: SpannedIdent,
|
||||||
pub expr: P<Expr>,
|
pub expr: P<Expr>,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
pub is_shorthand: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type SpannedIdent = Spanned<Ident>;
|
pub type SpannedIdent = Spanned<Ident>;
|
||||||
|
|
|
@ -713,7 +713,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||||
self.expr(b.span, ast::ExprKind::Block(b))
|
self.expr(b.span, ast::ExprKind::Block(b))
|
||||||
}
|
}
|
||||||
fn field_imm(&self, span: Span, name: Ident, e: P<ast::Expr>) -> ast::Field {
|
fn field_imm(&self, span: Span, name: Ident, e: P<ast::Expr>) -> ast::Field {
|
||||||
ast::Field { ident: respan(span, name), expr: e, span: span }
|
ast::Field { ident: respan(span, name), expr: e, span: span, is_shorthand: false }
|
||||||
}
|
}
|
||||||
fn expr_struct(&self, span: Span, path: ast::Path, fields: Vec<ast::Field>) -> P<ast::Expr> {
|
fn expr_struct(&self, span: Span, path: ast::Path, fields: Vec<ast::Field>) -> P<ast::Expr> {
|
||||||
self.expr(span, ast::ExprKind::Struct(path, fields, None))
|
self.expr(span, ast::ExprKind::Struct(path, fields, None))
|
||||||
|
|
|
@ -306,6 +306,9 @@ declare_features! (
|
||||||
|
|
||||||
// Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
|
// Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
|
||||||
(active, generic_param_attrs, "1.11.0", Some(34761)),
|
(active, generic_param_attrs, "1.11.0", Some(34761)),
|
||||||
|
|
||||||
|
// Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
|
||||||
|
(active, field_init_shorthand, "1.14.0", Some(37340)),
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_features! (
|
declare_features! (
|
||||||
|
@ -1087,6 +1090,14 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
|
||||||
ast::ExprKind::InPlace(..) => {
|
ast::ExprKind::InPlace(..) => {
|
||||||
gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
|
gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
|
||||||
}
|
}
|
||||||
|
ast::ExprKind::Struct(_, ref fields, _) => {
|
||||||
|
for field in fields {
|
||||||
|
if field.is_shorthand {
|
||||||
|
gate_feature_post!(&self, field_init_shorthand, field.span,
|
||||||
|
"struct field shorthands are unstable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
visit::walk_expr(self, e);
|
visit::walk_expr(self, e);
|
||||||
|
|
|
@ -823,11 +823,12 @@ pub fn noop_fold_struct_field<T: Folder>(f: StructField, fld: &mut T) -> StructF
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn noop_fold_field<T: Folder>(Field {ident, expr, span}: Field, folder: &mut T) -> Field {
|
pub fn noop_fold_field<T: Folder>(f: Field, folder: &mut T) -> Field {
|
||||||
Field {
|
Field {
|
||||||
ident: respan(ident.span, folder.fold_ident(ident.node)),
|
ident: respan(f.ident.span, folder.fold_ident(f.ident.node)),
|
||||||
expr: folder.fold_expr(expr),
|
expr: folder.fold_expr(f.expr),
|
||||||
span: folder.new_span(span)
|
span: folder.new_span(f.span),
|
||||||
|
is_shorthand: f.is_shorthand,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2007,17 +2007,30 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse ident COLON expr
|
/// Parse ident (COLON expr)?
|
||||||
pub fn parse_field(&mut self) -> PResult<'a, Field> {
|
pub fn parse_field(&mut self) -> PResult<'a, Field> {
|
||||||
let lo = self.span.lo;
|
let lo = self.span.lo;
|
||||||
let i = self.parse_field_name()?;
|
let hi;
|
||||||
let hi = self.prev_span.hi;
|
|
||||||
self.expect(&token::Colon)?;
|
// Check if a colon exists one ahead. This means we're parsing a fieldname.
|
||||||
let e = self.parse_expr()?;
|
let (fieldname, expr, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) {
|
||||||
|
let fieldname = self.parse_field_name()?;
|
||||||
|
self.bump();
|
||||||
|
hi = self.prev_span.hi;
|
||||||
|
(fieldname, self.parse_expr()?, false)
|
||||||
|
} else {
|
||||||
|
let fieldname = self.parse_ident()?;
|
||||||
|
hi = self.prev_span.hi;
|
||||||
|
|
||||||
|
// Mimic `x: x` for the `x` field shorthand.
|
||||||
|
let path = ast::Path::from_ident(mk_sp(lo, hi), fieldname);
|
||||||
|
(fieldname, self.mk_expr(lo, hi, ExprKind::Path(None, path), ThinVec::new()), true)
|
||||||
|
};
|
||||||
Ok(ast::Field {
|
Ok(ast::Field {
|
||||||
ident: spanned(lo, hi, i),
|
ident: spanned(lo, hi, fieldname),
|
||||||
span: mk_sp(lo, e.span.hi),
|
span: mk_sp(lo, expr.span.hi),
|
||||||
expr: e,
|
expr: expr,
|
||||||
|
is_shorthand: is_shorthand,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1893,8 +1893,10 @@ impl<'a> State<'a> {
|
||||||
&fields[..],
|
&fields[..],
|
||||||
|s, field| {
|
|s, field| {
|
||||||
try!(s.ibox(INDENT_UNIT));
|
try!(s.ibox(INDENT_UNIT));
|
||||||
|
if !field.is_shorthand {
|
||||||
try!(s.print_ident(field.ident.node));
|
try!(s.print_ident(field.ident.node));
|
||||||
try!(s.word_space(":"));
|
try!(s.word_space(":"));
|
||||||
|
}
|
||||||
try!(s.print_expr(&field.expr));
|
try!(s.print_expr(&field.expr));
|
||||||
s.end()
|
s.end()
|
||||||
},
|
},
|
||||||
|
|
24
src/test/compile-fail/feature-gate-field-init-shorthand.rs
Normal file
24
src/test/compile-fail/feature-gate-field-init-shorthand.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 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 {
|
||||||
|
x: i32,
|
||||||
|
y: bool,
|
||||||
|
z: i32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (x, y, z) = (1, true, 2);
|
||||||
|
let _ = Foo {
|
||||||
|
x, //~ ERROR struct field shorthands are unstable
|
||||||
|
y: y,
|
||||||
|
z //~ ERROR struct field shorthands are unstable
|
||||||
|
};
|
||||||
|
}
|
24
src/test/compile-fail/struct-fields-shorthand-unresolved.rs
Normal file
24
src/test/compile-fail/struct-fields-shorthand-unresolved.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(field_init_shorthand)]
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
x: i32,
|
||||||
|
y: i32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = 0;
|
||||||
|
let foo = Foo {
|
||||||
|
x,
|
||||||
|
y //~ ERROR unresolved name `y`
|
||||||
|
};
|
||||||
|
}
|
24
src/test/compile-fail/struct-fields-shorthand.rs
Normal file
24
src/test/compile-fail/struct-fields-shorthand.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(field_init_shorthand)]
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
x: i32,
|
||||||
|
y: i32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (x, y, z) = (0, 1, 2);
|
||||||
|
let foo = Foo {
|
||||||
|
x, y, z //~ ERROR struct `Foo` has no field named `z`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -18,5 +18,5 @@ fn removed_with() {
|
||||||
|
|
||||||
let a = S { foo: (), bar: () };
|
let a = S { foo: (), bar: () };
|
||||||
let b = S { foo: (), with a };
|
let b = S { foo: (), with a };
|
||||||
//~^ ERROR expected `:`, found `a`
|
//~^ ERROR expected one of `,` or `}`, found `a`
|
||||||
}
|
}
|
||||||
|
|
19
src/test/parse-fail/struct-field-numeric-shorthand.rs
Normal file
19
src/test/parse-fail/struct-field-numeric-shorthand.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#![feature(field_init_shorthand)]
|
||||||
|
|
||||||
|
struct Rgb(u8, u8, u8);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = Rgb { 0, 1, 2 }; //~ ERROR expected identifier, found `0`
|
||||||
|
}
|
37
src/test/run-pass/struct-field-shorthand.rs
Normal file
37
src/test/run-pass/struct-field-shorthand.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#![feature(field_init_shorthand)]
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
x: i32,
|
||||||
|
y: bool,
|
||||||
|
z: i32
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bar {
|
||||||
|
x: i32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let (x, y, z) = (1, true, 2);
|
||||||
|
let a = Foo { x, y: y, z };
|
||||||
|
assert_eq!(a.x, x);
|
||||||
|
assert_eq!(a.y, y);
|
||||||
|
assert_eq!(a.z, z);
|
||||||
|
|
||||||
|
let b = Bar { x, };
|
||||||
|
assert_eq!(b.x, x);
|
||||||
|
|
||||||
|
let c = Foo { z, y, x };
|
||||||
|
assert_eq!(c.x, x);
|
||||||
|
assert_eq!(c.y, y);
|
||||||
|
assert_eq!(c.z, z);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue