Skip to content

Implement field shorthands in struct literal expressions. #11994

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 27, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ impl<'a> LoweringContext<'a> {
name: respan(f.ident.span, f.ident.node.name),
expr: self.lower_expr(&f.expr),
span: f.span,
is_shorthand: f.is_shorthand,
}
}

Expand Down Expand Up @@ -1682,6 +1683,7 @@ impl<'a> LoweringContext<'a> {
},
span: span,
expr: expr,
is_shorthand: false,
}
}

Expand Down
1 change: 1 addition & 0 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,7 @@ pub struct Field {
pub name: Spanned<Name>,
pub expr: P<Expr>,
pub span: Span,
pub is_shorthand: bool,
}

#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
Expand Down
6 changes: 4 additions & 2 deletions src/librustc/hir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1229,8 +1229,10 @@ impl<'a> State<'a> {
&fields[..],
|s, field| {
s.ibox(indent_unit)?;
s.print_name(field.name.node)?;
s.word_space(":")?;
if !field.is_shorthand {
s.print_name(field.name.node)?;
s.word_space(":")?;
}
s.print_expr(&field.expr)?;
s.end()
},
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,7 @@ pub struct Field {
pub ident: SpannedIdent,
pub expr: P<Expr>,
pub span: Span,
pub is_shorthand: bool,
}

pub type SpannedIdent = Spanned<Ident>;
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ext/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
self.expr(b.span, ast::ExprKind::Block(b))
}
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> {
self.expr(span, ast::ExprKind::Struct(path, fields, None))
Expand Down
11 changes: 11 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,9 @@ declare_features! (

// Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
(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! (
Expand Down Expand Up @@ -1087,6 +1090,14 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
ast::ExprKind::InPlace(..) => {
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);
Expand Down
9 changes: 5 additions & 4 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
ident: respan(ident.span, folder.fold_ident(ident.node)),
expr: folder.fold_expr(expr),
span: folder.new_span(span)
ident: respan(f.ident.span, folder.fold_ident(f.ident.node)),
expr: folder.fold_expr(f.expr),
span: folder.new_span(f.span),
is_shorthand: f.is_shorthand,
}
}

Expand Down
29 changes: 21 additions & 8 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
let lo = self.span.lo;
let i = self.parse_field_name()?;
let hi = self.prev_span.hi;
self.expect(&token::Colon)?;
let e = self.parse_expr()?;
let hi;

// Check if a colon exists one ahead. This means we're parsing a fieldname.
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 {
ident: spanned(lo, hi, i),
span: mk_sp(lo, e.span.hi),
expr: e,
ident: spanned(lo, hi, fieldname),
span: mk_sp(lo, expr.span.hi),
expr: expr,
is_shorthand: is_shorthand,
})
}

Expand Down
6 changes: 4 additions & 2 deletions src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1893,8 +1893,10 @@ impl<'a> State<'a> {
&fields[..],
|s, field| {
try!(s.ibox(INDENT_UNIT));
try!(s.print_ident(field.ident.node));
try!(s.word_space(":"));
if !field.is_shorthand {
try!(s.print_ident(field.ident.node));
try!(s.word_space(":"));
}
try!(s.print_expr(&field.expr));
s.end()
},
Expand Down
24 changes: 24 additions & 0 deletions src/test/compile-fail/feature-gate-field-init-shorthand.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 24 additions & 0 deletions src/test/compile-fail/struct-fields-shorthand-unresolved.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 24 additions & 0 deletions src/test/compile-fail/struct-fields-shorthand.rs
Original file line number Diff line number Diff line change
@@ -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`
};
}

2 changes: 1 addition & 1 deletion src/test/parse-fail/removed-syntax-with-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ fn removed_with() {

let a = S { foo: (), bar: () };
let b = S { foo: (), with a };
//~^ ERROR expected `:`, found `a`
//~^ ERROR expected one of `,` or `}`, found `a`
}
19 changes: 19 additions & 0 deletions src/test/parse-fail/struct-field-numeric-shorthand.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 37 additions & 0 deletions src/test/run-pass/struct-field-shorthand.rs
Original file line number Diff line number Diff line change
@@ -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);
}