about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2011-04-08 16:20:06 -0700
committerPatrick Walton <pcwalton@mimiga.net>2011-04-08 16:22:03 -0700
commit129c8392af9711c747df35f2e6b13606bc2a985b (patch)
tree0d7f4e8571a74832d8a02122d6b42f3ea9335218 /src/comp
parent1af3174fe3b565371a5978381f604ea9c01e86d3 (diff)
downloadrust-129c8392af9711c747df35f2e6b13606bc2a985b.tar.gz
rust-129c8392af9711c747df35f2e6b13606bc2a985b.zip
rustc: Rename "demand" to "pushdown" in the typechecker and explain more clearly what it's for
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/middle/typeck.rs785
1 files changed, 409 insertions, 376 deletions
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index c29ea872171..98f71e20daa 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -1034,317 +1034,340 @@ fn are_compatible(&@fn_ctxt fcx, @ty.t expected, @ty.t actual) -> bool {
     }
 }
 
-// Type unification over typed patterns. Note that the pattern that you pass
-// to this function must have been passed to check_pat() first.
-//
-// TODO: enforce this via a predicate.
-
-fn demand_pat(&@fn_ctxt fcx, @ty.t expected, @ast.pat pat) -> @ast.pat {
-    auto p_1;
 
-    alt (pat.node) {
-        case (ast.pat_wild(?ann)) {
-            auto t = demand(fcx, pat.span, expected, ann_to_type(ann));
-            p_1 = ast.pat_wild(ast.ann_type(t, none[vec[@ty.t]],
-                                            none[@ts_ann]));
-        }
-        case (ast.pat_lit(?lit, ?ann)) {
-            auto t = demand(fcx, pat.span, expected, ann_to_type(ann));
-            p_1 = ast.pat_lit(lit, ast.ann_type(t, none[vec[@ty.t]],
+// The "push-down" phase, which takes a typed grammar production and pushes
+// its type down into its constituent parts.
+//
+// For example, consider "auto x; x = 352;". check_expr() doesn't know the
+// type of "x" at the time it sees it, so that function will simply store a
+// type variable for the type of "x". However, after checking the entire
+// assignment expression, check_expr() will assign the type of int to the
+// expression "x = 352" as a whole. In this case, then, the job of these
+// functions is to clean up by assigning the type of int to both sides of the
+// assignment expression.
+//
+// TODO: We only need to do this once per statement: check_expr() bubbles the
+// types up, and pushdown_expr() pushes the types down. However, in many cases
+// we're more eager than we need to be, calling pushdown_expr() and friends
+// directly inside check_expr(). This results in a quadratic algorithm.
+
+mod Pushdown {
+    // Push-down over typed patterns. Note that the pattern that you pass to
+    // this function must have been passed to check_pat() first.
+    //
+    // TODO: enforce this via a predicate.
+
+    fn pushdown_pat(&@fn_ctxt fcx, @ty.t expected, @ast.pat pat) -> @ast.pat {
+        auto p_1;
+
+        alt (pat.node) {
+            case (ast.pat_wild(?ann)) {
+                auto t = demand(fcx, pat.span, expected, ann_to_type(ann));
+                p_1 = ast.pat_wild(ast.ann_type(t, none[vec[@ty.t]],
                                                 none[@ts_ann]));
-        }
-        case (ast.pat_bind(?id, ?did, ?ann)) {
-            auto t = demand(fcx, pat.span, expected, ann_to_type(ann));
-            fcx.locals.insert(did, t);
-            p_1 = ast.pat_bind(id, did, ast.ann_type(t,
-                                                     none[vec[@ty.t]],
-                                                     none[@ts_ann]));
-        }
-        case (ast.pat_tag(?id, ?subpats, ?vdef_opt, ?ann)) {
-            auto t = demand(fcx, pat.span, expected, ann_to_type(ann));
-
-            // FIXME: This is probably more convoluted than it has to be.
-            // Refactor to use the type cache.
-
-            // Figure out the type parameters of the tag.
-            auto tag_id = option.get[ast.variant_def](vdef_opt)._0;
+            }
+            case (ast.pat_lit(?lit, ?ann)) {
+                auto t = demand(fcx, pat.span, expected, ann_to_type(ann));
+                p_1 = ast.pat_lit(lit, ast.ann_type(t, none[vec[@ty.t]],
+                                                    none[@ts_ann]));
+            }
+            case (ast.pat_bind(?id, ?did, ?ann)) {
+                auto t = demand(fcx, pat.span, expected, ann_to_type(ann));
+                fcx.locals.insert(did, t);
+                p_1 = ast.pat_bind(id, did, ast.ann_type(t,
+                                                         none[vec[@ty.t]],
+                                                         none[@ts_ann]));
+            }
+            case (ast.pat_tag(?id, ?subpats, ?vdef_opt, ?ann)) {
+                auto t = demand(fcx, pat.span, expected, ann_to_type(ann));
 
-            auto tpt = ty.lookup_generic_item_type(fcx.ccx.sess,
-                fcx.ccx.type_cache, tag_id);
-            auto ty_params = tpt._0;
+                // FIXME: This is probably more convoluted than it has to be.
+                // Refactor to use the type cache.
 
-            // Take the type parameters out of the expected type.
-            auto ty_param_substs;
-            alt (t.struct) {
-                case (ty.ty_tag(_, ?tps)) { ty_param_substs = tps; }
-                case (_) {
-                    log "demand_pat(): expected type for tag pat isn't " +
-                        "actually a tag?!";
-                    fail;
-                }
-            }
-            auto tps_opt = some[vec[@ty.t]](ty_param_substs);
+                // Figure out the type parameters of the tag.
+                auto tag_id = option.get[ast.variant_def](vdef_opt)._0;
 
-            // The type of the tag isn't enough; we also have to get the type
-            // of the variant, which is either a tag type in the case of
-            // nullary variants or a function type in the case of n-ary
-            // variants.
+                auto tpt = ty.lookup_generic_item_type(fcx.ccx.sess,
+                    fcx.ccx.type_cache, tag_id);
+                auto ty_params = tpt._0;
 
-            auto vdef = option.get[ast.variant_def](vdef_opt);
-            auto variant_ty = ty.lookup_item_type(fcx.ccx.sess,
-                                                  fcx.ccx.type_cache,
-                                                  vdef._1)._1;
-
-            auto subpats_len = _vec.len[@ast.pat](subpats);
-            alt (variant_ty.struct) {
-                case (ty.ty_tag(_, _)) {
-                    // Nullary tag variant.
-                    check (subpats_len == 0u);
-                    p_1 = ast.pat_tag(id, subpats, vdef_opt,
-                                      ast.ann_type(t, tps_opt,
-                                                   none[@ts_ann]));
+                // Take the type parameters out of the expected type.
+                auto ty_param_substs;
+                alt (t.struct) {
+                    case (ty.ty_tag(_, ?tps)) { ty_param_substs = tps; }
+                    case (_) {
+                        log "pushdown_pat(): expected type for tag pat " +
+                            "isn't actually a tag?!";
+                        fail;
+                    }
                 }
-                case (ty.ty_fn(_, ?args, ?tag_ty)) {
-                    // N-ary tag variant.
-                    let vec[@ast.pat] new_subpats = vec();
-                    auto i = 0u;
-                    for (arg a in args) {
-                        auto subpat_ty = substitute_ty_params(fcx.ccx, a.ty,
-                            ty_params, ty_param_substs, pat.span);
-                        auto new_subpat = demand_pat(fcx, subpat_ty,
-                                                     subpats.(i));
-                        new_subpats += vec(new_subpat);
-                        i += 1u;
+                auto tps_opt = some[vec[@ty.t]](ty_param_substs);
+
+                // The type of the tag isn't enough; we also have to get the
+                // type of the variant, which is either a tag type in the case
+                // of nullary variants or a function type in the case of n-ary
+                // variants.
+
+                auto vdef = option.get[ast.variant_def](vdef_opt);
+                auto variant_ty = ty.lookup_item_type(fcx.ccx.sess,
+                                                      fcx.ccx.type_cache,
+                                                      vdef._1)._1;
+
+                auto subpats_len = _vec.len[@ast.pat](subpats);
+                alt (variant_ty.struct) {
+                    case (ty.ty_tag(_, _)) {
+                        // Nullary tag variant.
+                        check (subpats_len == 0u);
+                        p_1 = ast.pat_tag(id, subpats, vdef_opt,
+                                          ast.ann_type(t, tps_opt,
+                                                       none[@ts_ann]));
+                    }
+                    case (ty.ty_fn(_, ?args, ?tag_ty)) {
+                        // N-ary tag variant.
+                        let vec[@ast.pat] new_subpats = vec();
+                        auto i = 0u;
+                        for (arg a in args) {
+                            auto subpat_ty = substitute_ty_params(fcx.ccx,
+                                a.ty, ty_params, ty_param_substs, pat.span);
+                            auto new_subpat = pushdown_pat(fcx, subpat_ty,
+                                                           subpats.(i));
+                            new_subpats += vec(new_subpat);
+                            i += 1u;
+                        }
+                        p_1 = ast.pat_tag(id, new_subpats, vdef_opt,
+                                          ast.ann_type(tag_ty, tps_opt,
+                                                       none[@ts_ann]));
                     }
-                    p_1 = ast.pat_tag(id, new_subpats, vdef_opt,
-                                      ast.ann_type(tag_ty, tps_opt,
-                                                   none[@ts_ann]));
                 }
             }
         }
+
+        ret @fold.respan[ast.pat_](pat.span, p_1);
     }
 
-    ret @fold.respan[ast.pat_](pat.span, p_1);
-}
+    // Push-down over typed expressions. Note that the expression that you
+    // pass to this function must have been passed to check_expr() first.
+    //
+    // TODO: enforce this via a predicate.
+    // TODO: This function is incomplete.
 
-// Type unification over typed expressions. Note that the expression that you
-// pass to this function must have been passed to check_expr() first.
-//
-// TODO: enforce this via a predicate.
-// TODO: propagate the types downward. This makes the typechecker quadratic,
-//       but we can mitigate that if expected == actual == unified.
-
-fn demand_expr(&@fn_ctxt fcx, @ty.t expected, @ast.expr e) -> @ast.expr {
-    be demand_expr_full(fcx, expected, e, NO_AUTODEREF);
-}
+    fn pushdown_expr(&@fn_ctxt fcx, @ty.t expected, @ast.expr e)
+            -> @ast.expr {
+        be pushdown_expr_full(fcx, expected, e, NO_AUTODEREF);
+    }
 
-fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
-                    autoderef_kind adk) -> @ast.expr {
-    auto e_1;
+    fn pushdown_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
+                        autoderef_kind adk) -> @ast.expr {
+        auto e_1;
 
-    alt (e.node) {
-        case (ast.expr_vec(?es_0, ?mut, ?ann)) {
-            // TODO: enforce mutability
+        alt (e.node) {
+            case (ast.expr_vec(?es_0, ?mut, ?ann)) {
+                // TODO: enforce mutability
 
-            auto t = demand(fcx, e.span, expected, ann_to_type(ann));
-            let vec[@ast.expr] es_1 = vec();
-            alt (t.struct) {
-                case (ty.ty_vec(?mt)) {
-                    for (@ast.expr e_0 in es_0) {
-                        es_1 += vec(demand_expr(fcx, mt.ty, e_0));
+                auto t = demand(fcx, e.span, expected, ann_to_type(ann));
+                let vec[@ast.expr] es_1 = vec();
+                alt (t.struct) {
+                    case (ty.ty_vec(?mt)) {
+                        for (@ast.expr e_0 in es_0) {
+                            es_1 += vec(pushdown_expr(fcx, mt.ty, e_0));
+                        }
                     }
-                }
-                case (_) {
-                    log "vec expr doesn't have a vec type!";
-                    fail;
-                }
-            }
-            e_1 = ast.expr_vec(es_1, mut, triv_ann(t));
-        }
-        case (ast.expr_tup(?es_0, ?ann)) {
-            auto t = demand(fcx, e.span, expected, ann_to_type(ann));
-            let vec[ast.elt] elts_1 = vec();
-            alt (t.struct) {
-                case (ty.ty_tup(?mts)) {
-                    auto i = 0u;
-                    for (ast.elt elt_0 in es_0) {
-                        auto e_1 = demand_expr(fcx, mts.(i).ty, elt_0.expr);
-                        elts_1 += vec(rec(mut=elt_0.mut, expr=e_1));
-                        i += 1u;
+                    case (_) {
+                        log "vec expr doesn't have a vec type!";
+                        fail;
                     }
                 }
-                case (_) {
-                    log "tup expr doesn't have a tup type!";
-                    fail;
+                e_1 = ast.expr_vec(es_1, mut, triv_ann(t));
+            }
+            case (ast.expr_tup(?es_0, ?ann)) {
+                auto t = demand(fcx, e.span, expected, ann_to_type(ann));
+                let vec[ast.elt] elts_1 = vec();
+                alt (t.struct) {
+                    case (ty.ty_tup(?mts)) {
+                        auto i = 0u;
+                        for (ast.elt elt_0 in es_0) {
+                            auto e_1 = pushdown_expr(fcx, mts.(i).ty,
+                                                     elt_0.expr);
+                            elts_1 += vec(rec(mut=elt_0.mut, expr=e_1));
+                            i += 1u;
+                        }
+                    }
+                    case (_) {
+                        log "tup expr doesn't have a tup type!";
+                        fail;
+                    }
                 }
+                e_1 = ast.expr_tup(elts_1, triv_ann(t));
             }
-            e_1 = ast.expr_tup(elts_1, triv_ann(t));
-        }
-        case (ast.expr_rec(?fields_0, ?base_0, ?ann)) {
+            case (ast.expr_rec(?fields_0, ?base_0, ?ann)) {
 
-            auto base_1 = base_0;
+                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_mts)) {
-                    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_mts.(i).ident));
-                                auto e_1 = demand_expr(fcx,
-                                                       field_mts.(i).mt.ty,
-                                                       field_0.expr);
-                                fields_1 += vec(rec(mut=field_0.mut,
-                                                    ident=field_0.ident,
-                                                    expr=e_1));
-                                i += 1u;
+                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_mts)) {
+                        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_mts.(i).ident));
+                                    auto e_1 =
+                                        pushdown_expr(fcx,
+                                                      field_mts.(i).mt.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_mts) {
-                                    if (_str.eq(field_0.ident, ft.ident)) {
-                                        auto e_1 = demand_expr(fcx, ft.mt.ty,
-                                                               field_0.expr);
-                                        fields_1 +=
-                                            vec(rec(mut=field_0.mut,
-                                                    ident=field_0.ident,
-                                                    expr=e_1));
+                            case (some[@ast.expr](?bx)) {
+
+                                base_1 = some[@ast.expr](pushdown_expr(fcx, t,
+                                                                       bx));
+
+                                let vec[field] base_fields = vec();
+
+                                for (ast.field field_0 in fields_0) {
+
+                                    for (ty.field ft in field_mts) {
+                                        if (_str.eq(field_0.ident,
+                                                    ft.ident)) {
+                                            auto e_1 =
+                                                pushdown_expr(fcx, ft.mt.ty,
+                                                              field_0.expr);
+                                            fields_1 +=
+                                                vec(rec(mut=field_0.mut,
+                                                        ident=field_0.ident,
+                                                        expr=e_1));
+                                        }
                                     }
                                 }
                             }
                         }
                     }
+                    case (_) {
+                        log "rec expr doesn't have a rec type!";
+                        fail;
+                    }
                 }
-                case (_) {
-                    log "rec expr doesn't have a rec type!";
-                    fail;
-                }
-            }
-            e_1 = ast.expr_rec(fields_1, base_1, triv_ann(t));
-        }
-        case (ast.expr_bind(?sube, ?es, ?ann)) {
-            auto t = demand(fcx, e.span, expected, ann_to_type(ann));
-            e_1 = ast.expr_bind(sube, es, triv_ann(t));
-        }
-        case (ast.expr_call(?sube, ?es, ?ann)) {
-            // NB: we call 'demand_full' and pass in adk only in cases where
-            // e is an expression that could *possibly* produce a box; things
-            // like expr_binary or expr_bind can't, so there's no need.
-            auto t = demand_full(fcx, e.span, expected,
-                                 ann_to_type(ann), adk);
-            e_1 = ast.expr_call(sube, es, triv_ann(t));
-        }
-        case (ast.expr_self_method(?id, ?ann)) {
-            auto t = demand(fcx, e.span, expected, ann_to_type(ann));
-            e_1 = ast.expr_self_method(id, triv_ann(t));
-        }
-        case (ast.expr_binary(?bop, ?lhs, ?rhs, ?ann)) {
-            auto t = demand(fcx, e.span, expected, ann_to_type(ann));
-            e_1 = ast.expr_binary(bop, lhs, rhs, triv_ann(t));
-        }
-        case (ast.expr_unary(?uop, ?sube, ?ann)) {
-            // See note in expr_unary for why we're calling demand_full.
-            auto t = demand_full(fcx, e.span, expected,
-                                 ann_to_type(ann), adk);
-            e_1 = ast.expr_unary(uop, sube, triv_ann(t));
-        }
-        case (ast.expr_lit(?lit, ?ann)) {
-            auto t = demand(fcx, e.span, expected, ann_to_type(ann));
-            e_1 = ast.expr_lit(lit, triv_ann(t));
-        }
-        case (ast.expr_cast(?sube, ?ast_ty, ?ann)) {
-            auto t = demand(fcx, e.span, expected, ann_to_type(ann));
-            e_1 = ast.expr_cast(sube, ast_ty, triv_ann(t));
-        }
-        case (ast.expr_if(?cond, ?then_0, ?else_0, ?ann)) {
-            auto t = demand_full(fcx, e.span, expected,
-                                 ann_to_type(ann), adk);
-            auto then_1 = demand_block(fcx, expected, then_0);
-
-            auto else_1;
-            alt (else_0) {
-                case (none[@ast.expr]) { else_1 = none[@ast.expr]; }
-                case (some[@ast.expr](?e_0)) {
-                    auto e_1 = demand_expr(fcx, expected, e_0);
-                    else_1 = some[@ast.expr](e_1);
-                }
-            }
-            e_1 = ast.expr_if(cond, then_1, else_1, triv_ann(t));
-        }
-        case (ast.expr_for(?decl, ?seq, ?bloc, ?ann)) {
-            auto t = demand(fcx, e.span, expected, ann_to_type(ann));
-            e_1 = ast.expr_for(decl, seq, bloc, triv_ann(t));
-        }
-        case (ast.expr_for_each(?decl, ?seq, ?bloc, ?ann)) {
-            auto t = demand(fcx, e.span, expected, ann_to_type(ann));
-            e_1 = ast.expr_for_each(decl, seq, bloc, triv_ann(t));
-        }
-        case (ast.expr_while(?cond, ?bloc, ?ann)) {
-            auto t = demand(fcx, e.span, expected, ann_to_type(ann));
-            e_1 = ast.expr_while(cond, bloc, triv_ann(t));
-        }
-        case (ast.expr_do_while(?bloc, ?cond, ?ann)) {
-            auto t = demand(fcx, e.span, expected, ann_to_type(ann));
-            e_1 = ast.expr_do_while(bloc, cond, triv_ann(t));
-        }
-        case (ast.expr_block(?bloc, ?ann)) {
-            auto t = demand_full(fcx, e.span, expected,
-                                 ann_to_type(ann), adk);
-            e_1 = ast.expr_block(bloc, triv_ann(t));
-        }
-        case (ast.expr_assign(?lhs_0, ?rhs_0, ?ann)) {
-            auto t = demand_full(fcx, e.span, expected,
-                                 ann_to_type(ann), adk);
-            auto lhs_1 = demand_expr(fcx, expected, lhs_0);
-            auto rhs_1 = demand_expr(fcx, expected, rhs_0);
-            e_1 = ast.expr_assign(lhs_1, rhs_1, triv_ann(t));
-        }
-        case (ast.expr_assign_op(?op, ?lhs_0, ?rhs_0, ?ann)) {
-            auto t = demand_full(fcx, e.span, expected,
-                                 ann_to_type(ann), adk);
-            auto lhs_1 = demand_expr(fcx, expected, lhs_0);
-            auto rhs_1 = demand_expr(fcx, expected, rhs_0);
-            e_1 = ast.expr_assign_op(op, lhs_1, rhs_1, triv_ann(t));
-        }
-        case (ast.expr_field(?lhs, ?rhs, ?ann)) {
-            auto t = demand_full(fcx, e.span, expected,
-                                 ann_to_type(ann), adk);
-            e_1 = ast.expr_field(lhs, rhs, triv_ann(t));
-        }
-        case (ast.expr_index(?base, ?index, ?ann)) {
-            auto t = demand_full(fcx, e.span, expected,
-                                 ann_to_type(ann), adk);
-            e_1 = ast.expr_index(base, index, triv_ann(t));
-        }
-        case (ast.expr_path(?pth, ?d, ?ann)) {
-            auto t = demand_full(fcx, e.span, expected,
-                                 ann_to_type(ann), adk);
-
-            // Fill in the type parameter substitutions if they weren't
-            // provided by the programmer.
-            auto ty_params_opt;
-            alt (ann) {
-                case (ast.ann_none) {
-                    log "demand_expr(): no type annotation for path expr; " +
-                        "did you pass it to check_expr() first?";
-                    fail;
+                e_1 = ast.expr_rec(fields_1, base_1, triv_ann(t));
+            }
+            case (ast.expr_bind(?sube, ?es, ?ann)) {
+                auto t = demand(fcx, e.span, expected, ann_to_type(ann));
+                e_1 = ast.expr_bind(sube, es, triv_ann(t));
+            }
+            case (ast.expr_call(?sube, ?es, ?ann)) {
+                // NB: we call 'demand_full' and pass in adk only in cases
+                // where e is an expression that could *possibly* produce a
+                // box; things like expr_binary or expr_bind can't, so there's
+                // no need.
+                auto t = demand_full(fcx, e.span, expected,
+                                     ann_to_type(ann), adk);
+                e_1 = ast.expr_call(sube, es, triv_ann(t));
+            }
+            case (ast.expr_self_method(?id, ?ann)) {
+                auto t = demand(fcx, e.span, expected, ann_to_type(ann));
+                e_1 = ast.expr_self_method(id, triv_ann(t));
+            }
+            case (ast.expr_binary(?bop, ?lhs, ?rhs, ?ann)) {
+                auto t = demand(fcx, e.span, expected, ann_to_type(ann));
+                e_1 = ast.expr_binary(bop, lhs, rhs, triv_ann(t));
+            }
+            case (ast.expr_unary(?uop, ?sube, ?ann)) {
+                // See note in expr_unary for why we're calling demand_full.
+                auto t = demand_full(fcx, e.span, expected,
+                                     ann_to_type(ann), adk);
+                e_1 = ast.expr_unary(uop, sube, triv_ann(t));
+            }
+            case (ast.expr_lit(?lit, ?ann)) {
+                auto t = demand(fcx, e.span, expected, ann_to_type(ann));
+                e_1 = ast.expr_lit(lit, triv_ann(t));
+            }
+            case (ast.expr_cast(?sube, ?ast_ty, ?ann)) {
+                auto t = demand(fcx, e.span, expected, ann_to_type(ann));
+                e_1 = ast.expr_cast(sube, ast_ty, triv_ann(t));
+            }
+            case (ast.expr_if(?cond, ?then_0, ?else_0, ?ann)) {
+                auto t = demand_full(fcx, e.span, expected,
+                                     ann_to_type(ann), adk);
+                auto then_1 = pushdown_block(fcx, expected, then_0);
+
+                auto else_1;
+                alt (else_0) {
+                    case (none[@ast.expr]) { else_1 = none[@ast.expr]; }
+                    case (some[@ast.expr](?e_0)) {
+                        auto e_1 = pushdown_expr(fcx, expected, e_0);
+                        else_1 = some[@ast.expr](e_1);
+                    }
                 }
-                case (ast.ann_type(_, ?tps_opt, _)) {
-                    alt (tps_opt) {
-                        case (none[vec[@ty.t]]) {
-                            auto defn = option.get[ast.def](d);
-                            alt (ty_params_for_item(fcx.ccx, defn)) {
+                e_1 = ast.expr_if(cond, then_1, else_1, triv_ann(t));
+            }
+            case (ast.expr_for(?decl, ?seq, ?bloc, ?ann)) {
+                auto t = demand(fcx, e.span, expected, ann_to_type(ann));
+                e_1 = ast.expr_for(decl, seq, bloc, triv_ann(t));
+            }
+            case (ast.expr_for_each(?decl, ?seq, ?bloc, ?ann)) {
+                auto t = demand(fcx, e.span, expected, ann_to_type(ann));
+                e_1 = ast.expr_for_each(decl, seq, bloc, triv_ann(t));
+            }
+            case (ast.expr_while(?cond, ?bloc, ?ann)) {
+                auto t = demand(fcx, e.span, expected, ann_to_type(ann));
+                e_1 = ast.expr_while(cond, bloc, triv_ann(t));
+            }
+            case (ast.expr_do_while(?bloc, ?cond, ?ann)) {
+                auto t = demand(fcx, e.span, expected, ann_to_type(ann));
+                e_1 = ast.expr_do_while(bloc, cond, triv_ann(t));
+            }
+            case (ast.expr_block(?bloc, ?ann)) {
+                auto t = demand_full(fcx, e.span, expected,
+                                     ann_to_type(ann), adk);
+                e_1 = ast.expr_block(bloc, triv_ann(t));
+            }
+            case (ast.expr_assign(?lhs_0, ?rhs_0, ?ann)) {
+                auto t = demand_full(fcx, e.span, expected,
+                                     ann_to_type(ann), adk);
+                auto lhs_1 = pushdown_expr(fcx, expected, lhs_0);
+                auto rhs_1 = pushdown_expr(fcx, expected, rhs_0);
+                e_1 = ast.expr_assign(lhs_1, rhs_1, triv_ann(t));
+            }
+            case (ast.expr_assign_op(?op, ?lhs_0, ?rhs_0, ?ann)) {
+                auto t = demand_full(fcx, e.span, expected,
+                                     ann_to_type(ann), adk);
+                auto lhs_1 = pushdown_expr(fcx, expected, lhs_0);
+                auto rhs_1 = pushdown_expr(fcx, expected, rhs_0);
+                e_1 = ast.expr_assign_op(op, lhs_1, rhs_1, triv_ann(t));
+            }
+            case (ast.expr_field(?lhs, ?rhs, ?ann)) {
+                auto t = demand_full(fcx, e.span, expected,
+                                     ann_to_type(ann), adk);
+                e_1 = ast.expr_field(lhs, rhs, triv_ann(t));
+            }
+            case (ast.expr_index(?base, ?index, ?ann)) {
+                auto t = demand_full(fcx, e.span, expected,
+                                     ann_to_type(ann), adk);
+                e_1 = ast.expr_index(base, index, triv_ann(t));
+            }
+            case (ast.expr_path(?pth, ?d, ?ann)) {
+                auto t = demand_full(fcx, e.span, expected,
+                                     ann_to_type(ann), adk);
+
+                // Fill in the type parameter substitutions if they weren't
+                // provided by the programmer.
+                auto ty_params_opt;
+                alt (ann) {
+                    case (ast.ann_none) {
+                        log "pushdown_expr(): no type annotation for path " +
+                            "expr; did you pass it to check_expr() first?";
+                        fail;
+                    }
+                    case (ast.ann_type(_, ?tps_opt, _)) {
+                        alt (tps_opt) {
+                            case (none[vec[@ty.t]]) {
+                                auto defn = option.get[ast.def](d);
+                                alt (ty_params_for_item(fcx.ccx, defn)) {
                                 case (none[ty.ty_params_and_ty]) {
                                     ty_params_opt = none[vec[@ty.t]];
                                 }
@@ -1352,95 +1375,98 @@ fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
                                     auto tps = ty.resolve_ty_params(tpt, t);
                                     ty_params_opt = some[vec[@ty.t]](tps);
                                 }
+                                }
+                            }
+                            case (some[vec[@ty.t]](?tps)) {
+                                ty_params_opt = some[vec[@ty.t]](tps);
                             }
-                        }
-                        case (some[vec[@ty.t]](?tps)) {
-                            ty_params_opt = some[vec[@ty.t]](tps);
                         }
                     }
                 }
-            }
-
-            e_1 = ast.expr_path(pth, d,
-                                ast.ann_type(t, ty_params_opt,
-                                             none[@ts_ann]));
-        }
-        case (ast.expr_ext(?p, ?args, ?body, ?expanded, ?ann)) {
-            auto t = demand_full(fcx, e.span, expected,
-                                 ann_to_type(ann), adk);
-            e_1 = ast.expr_ext(p, args, body, expanded, triv_ann(t));
-        }
-        /* FIXME: should this check the type annotations? */
-        case (ast.expr_fail(_))  { e_1 = e.node; } 
-        case (ast.expr_log(_,_)) { e_1 = e.node; } 
-        case (ast.expr_break(_)) { e_1 = e.node; }
-        case (ast.expr_cont(_))  { e_1 = e.node; }
-        case (ast.expr_ret(_,_)) { e_1 = e.node; }
-        case (ast.expr_put(_,_)) { e_1 = e.node; }
-        case (ast.expr_be(_,_))  { e_1 = e.node; }
-        case (ast.expr_check_expr(_,_)) { e_1 = e.node; }
 
-        case (ast.expr_port(?ann)) {
-            auto t = demand(fcx, e.span, expected, ann_to_type(ann));
-            e_1 = ast.expr_port(triv_ann(t));
-        }
-
-        case (ast.expr_chan(?es, ?ann)) {
-            auto t = demand(fcx, e.span, expected, ann_to_type(ann));
-            let @ast.expr es_1;
-            alt (t.struct) {
-                case (ty.ty_chan(?subty)) {
-                    auto pt = plain_ty(ty.ty_port(subty));
-                    es_1 = demand_expr(fcx, pt, es);
+                e_1 = ast.expr_path(pth, d,
+                                    ast.ann_type(t, ty_params_opt,
+                                                 none[@ts_ann]));
+            }
+            case (ast.expr_ext(?p, ?args, ?body, ?expanded, ?ann)) {
+                auto t = demand_full(fcx, e.span, expected,
+                                     ann_to_type(ann), adk);
+                e_1 = ast.expr_ext(p, args, body, expanded, triv_ann(t));
+            }
+            /* FIXME: should this check the type annotations? */
+            case (ast.expr_fail(_))  { e_1 = e.node; } 
+            case (ast.expr_log(_,_)) { e_1 = e.node; } 
+            case (ast.expr_break(_)) { e_1 = e.node; }
+            case (ast.expr_cont(_))  { e_1 = e.node; }
+            case (ast.expr_ret(_,_)) { e_1 = e.node; }
+            case (ast.expr_put(_,_)) { e_1 = e.node; }
+            case (ast.expr_be(_,_))  { e_1 = e.node; }
+            case (ast.expr_check_expr(_,_)) { e_1 = e.node; }
+
+            case (ast.expr_port(?ann)) {
+                auto t = demand(fcx, e.span, expected, ann_to_type(ann));
+                e_1 = ast.expr_port(triv_ann(t));
+            }
+
+            case (ast.expr_chan(?es, ?ann)) {
+                auto t = demand(fcx, e.span, expected, ann_to_type(ann));
+                let @ast.expr es_1;
+                alt (t.struct) {
+                    case (ty.ty_chan(?subty)) {
+                        auto pt = plain_ty(ty.ty_port(subty));
+                        es_1 = pushdown_expr(fcx, pt, es);
+                    }
+                    case (_) {
+                        log "chan expr doesn't have a chan type!";
+                        fail;
+                    }
                 }
-                case (_) {
-                    log "chan expr doesn't have a chan type!";
-                    fail;
+                e_1 = ast.expr_chan(es_1, triv_ann(t));
+            }
+
+            case (ast.expr_alt(?discrim, ?arms_0, ?ann)) {
+                auto t = expected;
+                let vec[ast.arm] arms_1 = vec();
+                for (ast.arm arm_0 in arms_0) {
+                    auto block_1 = pushdown_block(fcx, expected, arm_0.block);
+                    t = demand(fcx, e.span, t, block_ty(block_1));
+                    auto arm_1 = rec(pat=arm_0.pat, block=block_1,
+                                     index=arm_0.index);
+                    arms_1 += vec(arm_1);
                 }
+                e_1 = ast.expr_alt(discrim, arms_1, triv_ann(t));
             }
-            e_1 = ast.expr_chan(es_1, triv_ann(t));
-        }
 
-        case (ast.expr_alt(?discrim, ?arms_0, ?ann)) {
-            auto t = expected;
-            let vec[ast.arm] arms_1 = vec();
-            for (ast.arm arm_0 in arms_0) {
-                auto block_1 = demand_block(fcx, expected, arm_0.block);
-                t = demand(fcx, e.span, t, block_ty(block_1));
-                auto arm_1 = rec(pat=arm_0.pat, block=block_1,
-                                 index=arm_0.index);
-                arms_1 += vec(arm_1);
+            case (_) {
+                fcx.ccx.sess.span_unimpl(e.span,
+                    "type unification for expression variant");
+                fail;
             }
-            e_1 = ast.expr_alt(discrim, arms_1, triv_ann(t));
         }
 
-        case (_) {
-            fcx.ccx.sess.span_unimpl(e.span,
-                "type unification for expression variant");
-            fail;
-        }
+        ret @fold.respan[ast.expr_](e.span, e_1);
     }
 
-    ret @fold.respan[ast.expr_](e.span, e_1);
-}
-
-// Type unification over typed blocks.
-fn demand_block(&@fn_ctxt fcx, @ty.t expected, &ast.block bloc) -> ast.block {
-    alt (bloc.node.expr) {
-        case (some[@ast.expr](?e_0)) {
-            auto e_1 = demand_expr(fcx, expected, e_0);
-            auto block_ = rec(stmts=bloc.node.stmts,
-                              expr=some[@ast.expr](e_1),
-                              index=bloc.node.index);
-            ret fold.respan[ast.block_](bloc.span, block_);
-        }
-        case (none[@ast.expr]) {
-            demand(fcx, bloc.span, expected, plain_ty(ty.ty_nil));
-            ret bloc;
+    // Push-down over typed blocks.
+    fn pushdown_block(&@fn_ctxt fcx, @ty.t expected, &ast.block bloc)
+            -> ast.block {
+        alt (bloc.node.expr) {
+            case (some[@ast.expr](?e_0)) {
+                auto e_1 = pushdown_expr(fcx, expected, e_0);
+                auto block_ = rec(stmts=bloc.node.stmts,
+                                  expr=some[@ast.expr](e_1),
+                                  index=bloc.node.index);
+                ret fold.respan[ast.block_](bloc.span, block_);
+            }
+            case (none[@ast.expr]) {
+                demand(fcx, bloc.span, expected, plain_ty(ty.ty_nil));
+                ret bloc;
+            }
         }
     }
 }
 
+
 // Local variable resolution: the phase that finds all the types in the AST
 // and replaces opaque "ty_local" types with the resolved local types.
 
@@ -1653,7 +1679,7 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
         }
 
         // Unify and write back to the function.
-        auto f_1 = demand_expr(fcx, t_0, f_0);
+        auto f_1 = Pushdown.pushdown_expr(fcx, t_0, f_0);
 
         // Take the argument types out of the resulting function type.
         auto t_1 = expr_ty(f_1);
@@ -1675,7 +1701,7 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
             alt (args_0.(i)) {
                 case (some[@ast.expr](?e_0)) {
                     auto arg_ty_1 = arg_tys_1.(i);
-                    auto e_1 = demand_expr(fcx, arg_ty_1.ty, e_0);
+                    auto e_1 = Pushdown.pushdown_expr(fcx, arg_ty_1.ty, e_0);
                     _vec.push[option.t[@ast.expr]](args_1,
                                                    some[@ast.expr](e_1));
                 }
@@ -1698,8 +1724,8 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
         auto lhs_t0 = expr_ty(lhs_0);
         auto rhs_t0 = expr_ty(rhs_0);
 
-        auto lhs_1 = demand_expr(fcx, rhs_t0, lhs_0);
-        auto rhs_1 = demand_expr(fcx, expr_ty(lhs_1), rhs_0);
+        auto lhs_1 = Pushdown.pushdown_expr(fcx, rhs_t0, lhs_0);
+        auto rhs_1 = Pushdown.pushdown_expr(fcx, expr_ty(lhs_1), rhs_0);
 
         auto ann = triv_ann(rhs_t0);
         ret tup(lhs_1, rhs_1, ann);
@@ -1741,10 +1767,10 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
             auto rhs_t0 = expr_ty(rhs_0);
 
             // FIXME: Binops have a bit more subtlety than this.
-            auto lhs_1 = demand_expr_full(fcx, rhs_t0, lhs_0,
-                                          AUTODEREF_OK);
-            auto rhs_1 = demand_expr_full(fcx, expr_ty(lhs_1), rhs_0,
-                                          AUTODEREF_OK);
+            auto lhs_1 = Pushdown.pushdown_expr_full(fcx, rhs_t0, lhs_0,
+                                                     AUTODEREF_OK);
+            auto rhs_1 = Pushdown.pushdown_expr_full(fcx, expr_ty(lhs_1),
+                                                     rhs_0, AUTODEREF_OK);
 
             auto t = strip_boxes(lhs_t0);
             alt (binop) {
@@ -1842,7 +1868,8 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
 
                 case (some[@ast.expr](?e)) {
                     auto expr_0 = check_expr(fcx, e);
-                    auto expr_1 = demand_expr(fcx, fcx.ret_ty, expr_0);
+                    auto expr_1 = Pushdown.pushdown_expr(fcx, fcx.ret_ty,
+                                                         expr_0);
                     ret @fold.respan[ast.expr_]
                         (expr.span, ast.expr_ret(some(expr_1), boring_ann()));
                 }
@@ -1865,7 +1892,8 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
 
                 case (some[@ast.expr](?e)) {
                     auto expr_0 = check_expr(fcx, e);
-                    auto expr_1 = demand_expr(fcx, fcx.ret_ty, expr_0);
+                    auto expr_1 = Pushdown.pushdown_expr(fcx, fcx.ret_ty,
+                                                         expr_0);
                     ret @fold.respan[ast.expr_]
                         (expr.span, ast.expr_put(some(expr_1), boring_ann()));
                 }
@@ -1876,7 +1904,7 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
             /* FIXME: prove instead of check */
             check (ast.is_call_expr(e));
             auto expr_0 = check_expr(fcx, e);
-            auto expr_1 = demand_expr(fcx, fcx.ret_ty, expr_0);
+            auto expr_1 = Pushdown.pushdown_expr(fcx, fcx.ret_ty, expr_0);
             ret @fold.respan[ast.expr_](expr.span,
                                         ast.expr_be(expr_1,
                                                     boring_ann()));
@@ -1918,7 +1946,7 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
             auto rhs_t = expr_ty(rhs_0);
 
             auto chan_t = plain_ty(ty.ty_chan(rhs_t));
-            auto lhs_1 = demand_expr(fcx, chan_t, lhs_0);
+            auto lhs_1 = Pushdown.pushdown_expr(fcx, chan_t, lhs_0);
             auto item_t;
             alt (expr_ty(lhs_1).struct) {
                 case (ty.ty_chan(?it)) {
@@ -1928,7 +1956,7 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
                     fail;
                 }
             }
-            auto rhs_1 = demand_expr(fcx, item_t, rhs_0);
+            auto rhs_1 = Pushdown.pushdown_expr(fcx, item_t, rhs_0);
 
             auto ann = triv_ann(chan_t);
             auto newexpr = ast.expr_send(lhs_1, rhs_1, ann);
@@ -1941,7 +1969,7 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
             auto lhs_t1 = expr_ty(lhs_0);
 
             auto port_t = plain_ty(ty.ty_port(lhs_t1));
-            auto rhs_1 = demand_expr(fcx, port_t, rhs_0);
+            auto rhs_1 = Pushdown.pushdown_expr(fcx, port_t, rhs_0);
             auto item_t;
             alt (expr_ty(rhs_0).struct) {
                 case (ty.ty_port(?it)) {
@@ -1951,7 +1979,7 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
                     fail;
                 }
             }
-            auto lhs_1 = demand_expr(fcx, item_t, lhs_0);
+            auto lhs_1 = Pushdown.pushdown_expr(fcx, item_t, lhs_0);
 
             auto ann = triv_ann(item_t);
             auto newexpr = ast.expr_recv(lhs_1, rhs_1, ann);
@@ -1960,7 +1988,8 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
 
         case (ast.expr_if(?cond, ?thn, ?elsopt, _)) {
             auto cond_0 = check_expr(fcx, cond);
-            auto cond_1 = demand_expr(fcx, plain_ty(ty.ty_bool), cond_0);
+            auto cond_1 = Pushdown.pushdown_expr(fcx, plain_ty(ty.ty_bool),
+                                                 cond_0);
 
             auto thn_0 = check_block(fcx, thn);
             auto thn_t = block_ty(thn_0);
@@ -1970,7 +1999,7 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
             alt (elsopt) {
                 case (some[@ast.expr](?els)) {
                     auto els_0 = check_expr(fcx, els);
-                    auto els_1 = demand_expr(fcx, thn_t, els_0);
+                    auto els_1 = Pushdown.pushdown_expr(fcx, thn_t, els_0);
                     elsopt_1 = some[@ast.expr](els_1);
                     elsopt_t = expr_ty(els_1);
                 }
@@ -1980,7 +2009,7 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
                 }
             }
 
-            auto thn_1 = demand_block(fcx, elsopt_t, thn_0);
+            auto thn_1 = Pushdown.pushdown_block(fcx, elsopt_t, thn_0);
 
             auto ann = triv_ann(elsopt_t);
             ret @fold.respan[ast.expr_](expr.span,
@@ -2015,7 +2044,8 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
 
         case (ast.expr_while(?cond, ?body, _)) {
             auto cond_0 = check_expr(fcx, cond);
-            auto cond_1 = demand_expr(fcx, plain_ty(ty.ty_bool), cond_0);
+            auto cond_1 = Pushdown.pushdown_expr(fcx, plain_ty(ty.ty_bool),
+                                                 cond_0);
             auto body_1 = check_block(fcx, body);
 
             auto ann = triv_ann(plain_ty(ty.ty_nil));
@@ -2025,7 +2055,8 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
 
         case (ast.expr_do_while(?body, ?cond, _)) {
             auto cond_0 = check_expr(fcx, cond);
-            auto cond_1 = demand_expr(fcx, plain_ty(ty.ty_bool), cond_0);
+            auto cond_1 = Pushdown.pushdown_expr(fcx, plain_ty(ty.ty_bool),
+                                                 cond_0);
             auto body_1 = check_block(fcx, body);
 
             auto ann = triv_ann(block_ty(body_1));
@@ -2051,7 +2082,7 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
 
             let vec[@ast.pat] pats_1 = vec();
             for (@ast.pat pat_0 in pats_0) {
-                pats_1 += vec(demand_pat(fcx, pattern_ty, pat_0));
+                pats_1 += vec(Pushdown.pushdown_pat(fcx, pattern_ty, pat_0));
             }
 
             // Now typecheck the blocks.
@@ -2068,7 +2099,8 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
             let vec[ast.arm] arms_1 = vec();
             auto i = 0u;
             for (ast.block block_0 in blocks_0) {
-                auto block_1 = demand_block(fcx, result_ty, block_0);
+                auto block_1 = Pushdown.pushdown_block(fcx, result_ty,
+                                                       block_0);
                 auto pat_1 = pats_1.(i);
                 auto arm = arms.(i);
                 auto arm_1 = rec(pat=pat_1, block=block_1, index=arm.index);
@@ -2076,7 +2108,7 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
                 i += 1u;
             }
 
-            auto expr_1 = demand_expr(fcx, pattern_ty, expr_0);
+            auto expr_1 = Pushdown.pushdown_expr(fcx, pattern_ty, expr_0);
 
             auto ann = triv_ann(result_ty);
             ret @fold.respan[ast.expr_](expr.span,
@@ -2519,11 +2551,12 @@ fn check_decl_local(&@fn_ctxt fcx, &@ast.decl decl) -> @ast.decl {
                     auto expr_1;
                     alt (init.op) {
                         case (ast.init_assign) {
-                            expr_1 = demand_expr(fcx, lty, expr_0);
+                            expr_1 = Pushdown.pushdown_expr(fcx, lty, expr_0);
                         }
                         case (ast.init_recv) {
                             auto port_ty = plain_ty(ty.ty_port(lty));
-                            expr_1 = demand_expr(fcx, port_ty, expr_0);
+                            expr_1 = Pushdown.pushdown_expr(fcx, port_ty,
+                                                            expr_0);
                         }
                     }
                     auto init_0 = rec(expr = expr_1 with init);
@@ -2594,7 +2627,7 @@ fn check_const(&@crate_ctxt ccx, &span sp, ast.ident ident, @ast.ty t,
                             ccx = ccx);
     auto e_ = check_expr(fcx, e);
     // FIXME: necessary? Correct sequence?
-    demand_expr(fcx, rty, e_);
+    Pushdown.pushdown_expr(fcx, rty, e_);
     auto item = ast.item_const(ident, t, e_, id, ann);
     ret @fold.respan[ast.item_](sp, item);
 }