about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2016-10-27 03:15:13 +0300
committerEduard Burtescu <edy.burt@gmail.com>2016-10-27 03:15:13 +0300
commit9908711e5e985e322a9576b25f982835504ead5c (patch)
tree6b91bc41112bb0bedb7caf05cdb22ca76b155fbd
parenta5b6a9fa8ad2e13adbfcc5f3f624d9252379d745 (diff)
downloadrust-9908711e5e985e322a9576b25f982835504ead5c.tar.gz
rust-9908711e5e985e322a9576b25f982835504ead5c.zip
Implement field shorthands in struct literal expressions.
-rw-r--r--src/librustc/hir/lowering.rs2
-rw-r--r--src/librustc/hir/mod.rs1
-rw-r--r--src/librustc/hir/print.rs6
-rw-r--r--src/libsyntax/ast.rs1
-rw-r--r--src/libsyntax/ext/build.rs2
-rw-r--r--src/libsyntax/feature_gate.rs11
-rw-r--r--src/libsyntax/fold.rs9
-rw-r--r--src/libsyntax/parse/parser.rs29
-rw-r--r--src/libsyntax/print/pprust.rs6
-rw-r--r--src/test/compile-fail/feature-gate-field-init-shorthand.rs24
-rw-r--r--src/test/compile-fail/struct-fields-shorthand-unresolved.rs24
-rw-r--r--src/test/compile-fail/struct-fields-shorthand.rs24
-rw-r--r--src/test/parse-fail/removed-syntax-with-2.rs2
-rw-r--r--src/test/parse-fail/struct-field-numeric-shorthand.rs19
-rw-r--r--src/test/run-pass/struct-field-shorthand.rs37
15 files changed, 179 insertions, 18 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 562156e70bd..11f635847a0 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -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,
         }
     }
 
@@ -1682,6 +1683,7 @@ impl<'a> LoweringContext<'a> {
             },
             span: span,
             expr: expr,
+            is_shorthand: false,
         }
     }
 
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 1de4355ccdf..1ac0a48713a 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -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)]
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 90b92beb7a7..657c10bab12 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -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()
                            },
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index ae036e66c69..37e306de325 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -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>;
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index bdbc45471bb..0ef47bd6daa 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -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))
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 954fe330b54..02580331a99 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -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! (
@@ -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);
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 08c0637b2d9..16916ddd5d6 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -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,
     }
 }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 463ec334cc5..a5a081e08be 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -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,
         })
     }
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index c7248fe68fa..149112133b2 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -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()
             },
diff --git a/src/test/compile-fail/feature-gate-field-init-shorthand.rs b/src/test/compile-fail/feature-gate-field-init-shorthand.rs
new file mode 100644
index 00000000000..cd2dae7f461
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-field-init-shorthand.rs
@@ -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
+    };
+}
diff --git a/src/test/compile-fail/struct-fields-shorthand-unresolved.rs b/src/test/compile-fail/struct-fields-shorthand-unresolved.rs
new file mode 100644
index 00000000000..50a43f4a276
--- /dev/null
+++ b/src/test/compile-fail/struct-fields-shorthand-unresolved.rs
@@ -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`
+    };
+}
diff --git a/src/test/compile-fail/struct-fields-shorthand.rs b/src/test/compile-fail/struct-fields-shorthand.rs
new file mode 100644
index 00000000000..f764322cadb
--- /dev/null
+++ b/src/test/compile-fail/struct-fields-shorthand.rs
@@ -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`
+    };
+}
+
diff --git a/src/test/parse-fail/removed-syntax-with-2.rs b/src/test/parse-fail/removed-syntax-with-2.rs
index c58f42abb58..c4354c07604 100644
--- a/src/test/parse-fail/removed-syntax-with-2.rs
+++ b/src/test/parse-fail/removed-syntax-with-2.rs
@@ -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`
 }
diff --git a/src/test/parse-fail/struct-field-numeric-shorthand.rs b/src/test/parse-fail/struct-field-numeric-shorthand.rs
new file mode 100644
index 00000000000..2a5c25d1868
--- /dev/null
+++ b/src/test/parse-fail/struct-field-numeric-shorthand.rs
@@ -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`
+}
diff --git a/src/test/run-pass/struct-field-shorthand.rs b/src/test/run-pass/struct-field-shorthand.rs
new file mode 100644
index 00000000000..fe91db572d2
--- /dev/null
+++ b/src/test/run-pass/struct-field-shorthand.rs
@@ -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);
+}