about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2011-02-15 15:07:55 -0800
committerGraydon Hoare <graydon@mozilla.com>2011-02-15 15:07:55 -0800
commit370c1ad00eaa0ff95c4e09a6e0545bf833d6668a (patch)
tree8658f64043b54d4d0483bbaa2772bc239ee965eb /src/comp
parent7a02798d1b3ccb04ee450b1171f31319f0c05467 (diff)
downloadrust-370c1ad00eaa0ff95c4e09a6e0545bf833d6668a.tar.gz
rust-370c1ad00eaa0ff95c4e09a6e0545bf833d6668a.zip
Handle record update in typeck.
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/middle/typeck.rs94
1 files changed, 80 insertions, 14 deletions
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 83caf891a03..9b7c9439625 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -912,23 +912,48 @@ fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
         }
         case (ast.expr_rec(?fields_0, ?base_0, ?ann)) {
 
-            // FIXME: handle presence of a nonempty base.
-            check (base_0 == none[@ast.expr]);
             auto base_1 = base_0;
 
             auto t = demand(fcx, e.span, expected, ann_to_type(ann));
             let vec[ast.field] fields_1 = vec();
             alt (t.struct) {
                 case (ty.ty_rec(?field_tys)) {
-                    auto i = 0u;
-                    for (ast.field field_0 in fields_0) {
-                        check (_str.eq(field_0.ident, field_tys.(i).ident));
-                        auto e_1 = demand_expr(fcx, field_tys.(i).ty,
-                                               field_0.expr);
-                        fields_1 += vec(rec(mut=field_0.mut,
-                                            ident=field_0.ident,
-                                            expr=e_1));
-                        i += 1u;
+                    alt (base_0) {
+                        case (none[@ast.expr]) {
+                            auto i = 0u;
+                            for (ast.field field_0 in fields_0) {
+                                check (_str.eq(field_0.ident,
+                                               field_tys.(i).ident));
+                                auto e_1 = demand_expr(fcx,
+                                                       field_tys.(i).ty,
+                                                       field_0.expr);
+                                fields_1 += vec(rec(mut=field_0.mut,
+                                                    ident=field_0.ident,
+                                                    expr=e_1));
+                                i += 1u;
+                            }
+                        }
+                        case (some[@ast.expr](?bx)) {
+
+                            base_1 =
+                                some[@ast.expr](demand_expr(fcx, t, bx));
+
+                            let vec[field] base_fields = vec();
+
+                            for (ast.field field_0 in fields_0) {
+
+                                for (ty.field ft in field_tys) {
+                                    if (_str.eq(field_0.ident, ft.ident)) {
+                                        auto e_1 = demand_expr(fcx, ft.ty,
+                                                               field_0.expr);
+                                        fields_1 +=
+                                            vec(rec(mut=field_0.mut,
+                                                    ident=field_0.ident,
+                                                    expr=e_1));
+                                    }
+                                }
+                            }
+                        }
                     }
                 }
                 case (_) {
@@ -1708,8 +1733,6 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
 
         case (ast.expr_rec(?fields, ?base, _)) {
 
-            // FIXME: handle presence of a nonempty base.
-            check (base == none[@ast.expr]);
             auto base_1 = base;
 
             let vec[ast.field] fields_1 = vec();
@@ -1725,7 +1748,50 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
                 append[field](fields_t, rec(ident=f.ident, ty=expr_t));
             }
 
-            auto ann = ast.ann_type(plain_ty(ty.ty_rec(fields_t)));
+            auto ann = ast.ann_none;
+
+            alt (base) {
+                case (none[@ast.expr]) {
+                    ann = ast.ann_type(plain_ty(ty.ty_rec(fields_t)));
+                }
+
+                case (some[@ast.expr](?bexpr)) {
+                    auto bexpr_1 = check_expr(fcx, bexpr);
+                    auto bexpr_t = expr_ty(bexpr_1);
+
+                    let vec[field] base_fields = vec();
+
+                    alt (bexpr_t.struct) {
+                        case (ty.ty_rec(?flds)) {
+                            base_fields = flds;
+                        }
+                        case (_) {
+                            fcx.ccx.sess.span_err
+                                (expr.span,
+                                 "record update non-record base");
+                        }
+                    }
+
+                    ann = ast.ann_type(bexpr_t);
+
+                    for (ty.field f in fields_t) {
+                        auto found = false;
+                        for (ty.field bf in base_fields) {
+                            if (_str.eq(f.ident, bf.ident)) {
+                                demand(fcx, expr.span, f.ty, bf.ty);
+                                found = true;
+                            }
+                        }
+                        if (!found) {
+                            fcx.ccx.sess.span_err
+                                (expr.span,
+                                 "unknown field in record update: "
+                                 + f.ident);
+                        }
+                    }
+                }
+            }
+
             ret @fold.respan[ast.expr_](expr.span,
                                         ast.expr_rec(fields_1, base_1, ann));
         }