about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2012-10-24 14:36:00 -0700
committerPatrick Walton <pcwalton@mimiga.net>2012-10-25 11:49:26 -0700
commit599b4208fb64b18aaddf9add5d8ce2319c7e7cfe (patch)
tree3b54245720a1450d324e0ae41756c5e35fe10bd0
parentce23a9992542f0c82e0f32c427b572caae790754 (diff)
downloadrust-599b4208fb64b18aaddf9add5d8ce2319c7e7cfe.tar.gz
rust-599b4208fb64b18aaddf9add5d8ce2319c7e7cfe.zip
rustc: Translate tuple struct constructors
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/ast_map.rs17
-rw-r--r--src/libsyntax/ast_util.rs6
-rw-r--r--src/libsyntax/fold.rs4
-rw-r--r--src/libsyntax/parse/parser.rs9
-rw-r--r--src/libsyntax/parse/token.rs1
-rw-r--r--src/rustc/middle/resolve.rs14
-rw-r--r--src/rustc/middle/trans/base.rs91
-rw-r--r--src/rustc/middle/trans/callee.rs5
-rw-r--r--src/rustc/middle/trans/monomorphize.rs13
-rw-r--r--src/rustc/middle/ty.rs12
-rw-r--r--src/rustc/middle/typeck/collect.rs59
-rw-r--r--src/test/run-pass/tuple-struct-construct.rs7
13 files changed, 192 insertions, 48 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index e25fb470bb9..60f22f1b844 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1480,7 +1480,7 @@ type struct_def = {
     dtor: Option<class_dtor>,
     /* ID of the constructor. This is only used for tuple- or enum-like
      * structs. */
-    ctor_id: node_id
+    ctor_id: Option<node_id>
 };
 
 /*
diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs
index bcda838b248..e63de5aefeb 100644
--- a/src/libsyntax/ast_map.rs
+++ b/src/libsyntax/ast_map.rs
@@ -74,6 +74,7 @@ enum ast_node {
     // Destructor for a class
     node_dtor(~[ty_param], @class_dtor, def_id, @path),
     node_block(blk),
+    node_struct_ctor(@struct_def, @item, @path)
 }
 
 type map = std::map::HashMap<node_id, ast_node>;
@@ -284,6 +285,19 @@ fn map_struct_def(struct_def: @ast::struct_def, parent_node: ast_node,
     for vec::each(struct_def.methods) |m| {
         map_method(d_id, p, *m, cx);
     }
+    // If this is a tuple-like struct, register the constructor.
+    match struct_def.ctor_id {
+        None => {}
+        Some(ctor_id) => {
+            match parent_node {
+                node_item(item, _) => {
+                    cx.map.insert(ctor_id,
+                                  node_struct_ctor(struct_def, item, p));
+                }
+                _ => fail ~"struct def parent wasn't an item"
+            }
+        }
+    }
 }
 
 fn map_view_item(vi: @view_item, cx: ctx, _v: vt) {
@@ -375,6 +389,9 @@ fn node_id_to_str(map: map, id: node_id, itr: @ident_interner) -> ~str {
       Some(node_block(_)) => {
         fmt!("block")
       }
+      Some(node_struct_ctor(*)) => {
+        fmt!("struct_ctor")
+      }
     }
 }
 // Local Variables:
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 6fd84c3317f..ea49cce5047 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -589,6 +589,12 @@ fn view_path_id(p: @view_path) -> node_id {
     }
 }
 
+/// Returns true if the given struct def is tuple-like; i.e. that its fields
+/// are unnamed.
+fn struct_def_is_tuple_like(struct_def: @ast::struct_def) -> bool {
+    struct_def.ctor_id.is_some()
+}
+
 // Local Variables:
 // mode: rust
 // fill-column: 78;
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index d1b97549225..e2b6e6daa2f 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -281,7 +281,7 @@ fn fold_struct_def(struct_def: @ast::struct_def, fld: ast_fold)
         fields: vec::map(struct_def.fields, |f| fold_struct_field(*f, fld)),
         methods: vec::map(struct_def.methods, |m| fld.fold_method(*m)),
         dtor: dtor,
-        ctor_id: fld.new_id(struct_def.ctor_id)
+        ctor_id: option::map(&struct_def.ctor_id, |cid| fld.new_id(*cid))
     };
 }
 
@@ -565,7 +565,7 @@ fn noop_fold_variant(v: variant_, fld: ast_fold) -> variant_ {
                 methods: vec::map(struct_def.methods,
                                   |m| fld.fold_method(*m)),
                 dtor: dtor,
-                ctor_id: fld.new_id(struct_def.ctor_id)
+                ctor_id: option::map(&struct_def.ctor_id, |c| fld.new_id(*c))
             })
         }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 1af516424de..23ddf61606d 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2659,9 +2659,11 @@ impl Parser {
         let mut fields: ~[@struct_field];
         let mut methods: ~[@method] = ~[];
         let mut the_dtor: Option<(blk, ~[attribute], codemap::span)> = None;
+        let is_tuple_like;
 
         if self.eat(token::LBRACE) {
             // It's a record-like struct.
+            is_tuple_like = false;
             fields = ~[];
             while self.token != token::RBRACE {
                 match self.parse_class_item() {
@@ -2694,6 +2696,7 @@ impl Parser {
             self.bump();
         } else if self.token == token::LPAREN {
             // It's a tuple-like struct.
+            is_tuple_like = true;
             fields = do self.parse_unspanned_seq(token::LPAREN, token::RPAREN,
                                                  seq_sep_trailing_allowed
                                                     (token::COMMA)) |p| {
@@ -2708,6 +2711,7 @@ impl Parser {
             self.expect(token::SEMI);
         } else if self.eat(token::SEMI) {
             // It's a unit-like struct.
+            is_tuple_like = true;
             fields = ~[];
         } else {
             self.fatal(fmt!("expected `{`, `(`, or `;` after struct name \
@@ -2723,13 +2727,14 @@ impl Parser {
                     body: d_body},
              span: d_s}};
         let _ = self.get_id();  // XXX: Workaround for crazy bug.
+        let new_id = self.get_id();
         (class_name,
          item_class(@{
              traits: traits,
              fields: move fields,
              methods: move methods,
              dtor: actual_dtor,
-             ctor_id: self.get_id()
+             ctor_id: if is_tuple_like { Some(new_id) } else { None }
          }, ty_params),
          None)
     }
@@ -3076,7 +3081,7 @@ impl Parser {
             fields: move fields,
             methods: move methods,
             dtor: actual_dtor,
-            ctor_id: self.get_id()
+            ctor_id: Some(self.get_id())
         };
     }
 
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 5151fd1bac8..53c1ce1c7f5 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -311,6 +311,7 @@ mod special_idents {
     const static : ident = ident { repr: 31u };
     const intrinsic : ident = ident { repr: 32u };
     const clownshoes_foreign_mod: ident = ident { repr: 33 };
+    const unnamed_field: ident = ident { repr: 34 };
 }
 
 struct ident_interner {
diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs
index 1f7b3b1c861..97551162de5 100644
--- a/src/rustc/middle/resolve.rs
+++ b/src/rustc/middle/resolve.rs
@@ -1187,12 +1187,14 @@ impl Resolver {
 
                 // If this struct is tuple-like or enum-like, define a name
                 // in the value namespace.
-                if struct_def.fields.len() == 0 ||
-                        struct_def.fields[0].node.kind == unnamed_field {
-                    name_bindings.define_value(
-                        privacy,
-                        def_class(local_def(struct_def.ctor_id)),
-                        sp);
+                match struct_def.ctor_id {
+                    None => {}
+                    Some(ctor_id) => {
+                        name_bindings.define_value(
+                            privacy,
+                            def_class(local_def(ctor_id)),
+                            sp);
+                    }
                 }
 
                 // Record the def ID of this struct.
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 3896fdf0e7a..822fb4f417a 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -1648,7 +1648,8 @@ fn trans_enum_variant(ccx: @crate_ctxt,
                       enum_id: ast::node_id,
                       variant: ast::variant,
                       args: ~[ast::variant_arg],
-                      disr: int, is_degen: bool,
+                      disr: int,
+                      is_degen: bool,
                       param_substs: Option<param_substs>,
                       llfndecl: ValueRef) {
     let _icx = ccx.insn_ctxt("trans_enum_variant");
@@ -1698,6 +1699,51 @@ fn trans_enum_variant(ccx: @crate_ctxt,
     finish_fn(fcx, lltop);
 }
 
+// NB: In theory this should be merged with the function above. But the AST
+// structures are completely different, so very little code would be shared.
+fn trans_tuple_struct(ccx: @crate_ctxt,
+                      fields: ~[@ast::struct_field],
+                      ctor_id: ast::node_id,
+                      param_substs: Option<param_substs>,
+                      llfndecl: ValueRef) {
+    let _icx = ccx.insn_ctxt("trans_tuple_struct");
+
+    // Translate struct fields to function arguments.
+    let fn_args = do fields.map |field| {
+        {
+            mode: ast::expl(ast::by_copy),
+            ty: field.node.ty,
+            ident: special_idents::arg,
+            id: field.node.id
+        }
+    };
+
+    let fcx = new_fn_ctxt_w_id(ccx, ~[], llfndecl, ctor_id, None,
+                               param_substs, None);
+    let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
+
+    let bcx = top_scope_block(fcx, None);
+    let lltop = bcx.llbb;
+    let arg_tys = ty::ty_fn_args(node_id_type(bcx, ctor_id));
+    let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
+
+    for fields.eachi |i, field| {
+        let lldestptr = GEPi(bcx, fcx.llretptr, [0, 0, i]);
+        let llarg = match fcx.llargs.get(field.node.id) {
+            local_mem(x) => x,
+            _ => {
+                ccx.tcx.sess.bug(~"trans_tuple_struct: llarg wasn't \
+                                   local_mem")
+            }
+        };
+        let arg_ty = arg_tys[i].ty;
+        memmove_ty(bcx, lldestptr, llarg, arg_ty);
+    }
+
+    build_return(bcx);
+    finish_fn(fcx, lltop);
+}
+
 fn trans_class_dtor(ccx: @crate_ctxt, path: path,
     body: ast::blk, dtor_id: ast::node_id,
     psubsts: Option<param_substs>,
@@ -1835,15 +1881,27 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
 fn trans_struct_def(ccx: @crate_ctxt, struct_def: @ast::struct_def,
                     tps: ~[ast::ty_param], path: @ast_map::path,
                     ident: ast::ident, id: ast::node_id) {
+    // If there are type parameters, the destructor and constructor will be
+    // monomorphized, so we don't translate them here.
     if tps.len() == 0u {
-      do option::iter(&struct_def.dtor) |dtor| {
-         trans_class_dtor(ccx, *path, dtor.node.body,
-           dtor.node.id, None, None, local_def(id));
-      };
+        // Translate the destructor.
+        do option::iter(&struct_def.dtor) |dtor| {
+            trans_class_dtor(ccx, *path, dtor.node.body,
+                             dtor.node.id, None, None, local_def(id));
+        };
+
+        // If this is a tuple-like struct, translate the constructor.
+        match struct_def.ctor_id {
+            None => {}
+            Some(ctor_id) => {
+                let llfndecl = get_item_val(ccx, ctor_id);
+                trans_tuple_struct(ccx, struct_def.fields, ctor_id, None,
+                                   llfndecl);
+            }
+        }
     }
-    // If there are ty params, the ctor will get monomorphized
 
-    // Translate methods
+    // Translate methods.
     meth::trans_impl(ccx, *path, ident, struct_def.methods, tps, None, id);
 }
 
@@ -2128,8 +2186,25 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
             set_inline_hint(llfn);
             llfn
           }
+
+          ast_map::node_struct_ctor(struct_def, struct_item, struct_path) => {
+            // Only register the constructor if this is a tuple-like struct.
+            match struct_def.ctor_id {
+                None => {
+                    ccx.tcx.sess.bug(~"attempt to register a constructor of \
+                                       a non-tuple-like struct")
+                }
+                Some(ctor_id) => {
+                    let llfn = register_fn(ccx, struct_item.span,
+                                           *struct_path, ctor_id);
+                    set_inline_hint(llfn);
+                    llfn
+                }
+            }
+          }
+
           _ => {
-            ccx.sess.bug(~"get_item_val(): unexpected variant");
+            ccx.sess.bug(~"get_item_val(): unexpected variant")
           }
         };
         if !(exprt || ccx.reachable.contains_key(id)) {
diff --git a/src/rustc/middle/trans/callee.rs b/src/rustc/middle/trans/callee.rs
index 175381a7bd1..2c1e9b21c6d 100644
--- a/src/rustc/middle/trans/callee.rs
+++ b/src/rustc/middle/trans/callee.rs
@@ -90,6 +90,9 @@ fn trans(bcx: block, expr: @ast::expr) -> Callee {
                                                 vid).args.len() > 0u;
                 fn_callee(bcx, trans_fn_ref(bcx, vid, ref_expr.id))
             }
+            ast::def_class(def_id) => {
+                fn_callee(bcx, trans_fn_ref(bcx, def_id, ref_expr.id))
+            }
             ast::def_arg(*) |
             ast::def_local(*) |
             ast::def_binding(*) |
@@ -99,7 +102,7 @@ fn trans(bcx: block, expr: @ast::expr) -> Callee {
             }
             ast::def_mod(*) | ast::def_foreign_mod(*) |
             ast::def_const(*) | ast::def_ty(*) | ast::def_prim_ty(*) |
-            ast::def_use(*) | ast::def_class(*) | ast::def_typaram_binder(*) |
+            ast::def_use(*) | ast::def_typaram_binder(*) |
             ast::def_region(*) | ast::def_label(*) | ast::def_ty_param(*) => {
                 bcx.tcx().sess.span_bug(
                     ref_expr.span,
diff --git a/src/rustc/middle/trans/monomorphize.rs b/src/rustc/middle/trans/monomorphize.rs
index c2f106f631b..4a569e2cf4d 100644
--- a/src/rustc/middle/trans/monomorphize.rs
+++ b/src/rustc/middle/trans/monomorphize.rs
@@ -96,6 +96,7 @@ fn monomorphic_fn(ccx: @crate_ctxt,
       ast_map::node_local(*) => {
           ccx.tcx.sess.bug(~"Can't monomorphize a local")
       }
+      ast_map::node_struct_ctor(_, i, pt) => (pt, i.ident, i.span)
     };
 
     // Look up the impl type if we're translating a default method.
@@ -208,6 +209,18 @@ fn monomorphic_fn(ccx: @crate_ctxt,
                            impl_did_opt.get());
         d
       }
+      ast_map::node_struct_ctor(struct_def, _, _) => {
+        let d = mk_lldecl();
+        set_inline_hint(d);
+        base::trans_tuple_struct(ccx,
+                                 struct_def.fields,
+                                 option::expect(struct_def.ctor_id,
+                                                ~"ast-mapped tuple struct \
+                                                  didn't have a ctor id"),
+                                 psubsts,
+                                 d);
+        d
+      }
 
       // Ugh -- but this ensures any new variants won't be forgotten
       ast_map::node_expr(*) |
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index 2daf40dbf84..d6364e5515e 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -3630,6 +3630,10 @@ fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path {
                 syntax::parse::token::special_idents::literally_dtor))
           }
 
+          ast_map::node_struct_ctor(_, item, path) => {
+            vec::append_one(*path, ast_map::path_name(item.ident))
+          }
+
           ast_map::node_stmt(*) | ast_map::node_expr(*) |
           ast_map::node_arg(*) | ast_map::node_local(*) |
           ast_map::node_export(*) | ast_map::node_block(*) => {
@@ -3874,7 +3878,13 @@ fn class_field_tys(fields: ~[@struct_field]) -> ~[field_ty] {
                            vis: visibility,
                            mutability: mutability});
             }
-            unnamed_field => {}
+            unnamed_field => {
+                rslt.push({ident:
+                    syntax::parse::token::special_idents::unnamed_field,
+                           id: ast_util::local_def(field.node.id),
+                           vis: ast::public,
+                           mutability: ast::class_immutable});
+            }
        }
     }
     rslt
diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs
index b6ae922ed1a..8610fb046b5 100644
--- a/src/rustc/middle/typeck/collect.rs
+++ b/src/rustc/middle/typeck/collect.rs
@@ -597,35 +597,40 @@ fn convert_struct(ccx: @crate_ctxt,
 
     // If this struct is enum-like or tuple-like, create the type of its
     // constructor.
-    if struct_def.fields.len() == 0 {
-        // Enum-like.
-        write_ty_to_tcx(tcx, struct_def.ctor_id, selfty);
-        tcx.tcache.insert(local_def(struct_def.ctor_id), tpt);
-    } else if struct_def.fields[0].node.kind == ast::unnamed_field {
-        // Tuple-like.
-        let ctor_fn_ty = ty::mk_fn(tcx, FnTyBase {
-            meta: FnMeta {
-                purity: ast::pure_fn,
-                proto: ty::proto_bare,
-                bounds: @~[],
-                ret_style: ast::return_val,
-            },
-            sig: FnSig {
-                inputs: do struct_def.fields.map |field| {
-                    {
-                        mode: ast::expl(ast::by_copy),
-                        ty: ccx.tcx.tcache.get(local_def(field.node.id)).ty
+    match struct_def.ctor_id {
+        None => {}
+        Some(ctor_id) => {
+            if struct_def.fields.len() == 0 {
+                // Enum-like.
+                write_ty_to_tcx(tcx, ctor_id, selfty);
+                tcx.tcache.insert(local_def(ctor_id), tpt);
+            } else if struct_def.fields[0].node.kind == ast::unnamed_field {
+                // Tuple-like.
+                let ctor_fn_ty = ty::mk_fn(tcx, FnTyBase {
+                    meta: FnMeta {
+                        purity: ast::pure_fn,
+                        proto: ty::proto_bare,
+                        bounds: @~[],
+                        ret_style: ast::return_val,
+                    },
+                    sig: FnSig {
+                        inputs: do struct_def.fields.map |field| {
+                            {
+                                mode: ast::expl(ast::by_copy),
+                                ty: ccx.tcx.tcache.get(local_def(field.node.id)).ty
+                            }
+                        },
+                        output: selfty
                     }
-                },
-                output: selfty
+                });
+                write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty);
+                tcx.tcache.insert(local_def(ctor_id), {
+                    bounds: tpt.bounds,
+                    region_param: tpt.region_param,
+                    ty: ctor_fn_ty
+                });
             }
-        });
-        write_ty_to_tcx(tcx, struct_def.ctor_id, ctor_fn_ty);
-        tcx.tcache.insert(local_def(struct_def.ctor_id), {
-            bounds: tpt.bounds,
-            region_param: tpt.region_param,
-            ty: ctor_fn_ty
-        });
+        }
     }
 }
 
diff --git a/src/test/run-pass/tuple-struct-construct.rs b/src/test/run-pass/tuple-struct-construct.rs
new file mode 100644
index 00000000000..3d2630e7a5c
--- /dev/null
+++ b/src/test/run-pass/tuple-struct-construct.rs
@@ -0,0 +1,7 @@
+struct Foo(int, int);
+
+fn main() {
+    let x = Foo(1, 2);
+    io::println(fmt!("%?", x));
+}
+