rustc: Rename "demand" to "pushdown" in the typechecker and explain more clearly what it's for

This commit is contained in:
Patrick Walton 2011-04-08 16:20:06 -07:00
parent 1af3174fe3
commit 129c8392af

View File

@ -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.
// The "push-down" phase, which takes a typed grammar production and pushes
// its type down into its constituent parts.
//
// TODO: enforce this via a predicate.
// 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.
fn demand_pat(&@fn_ctxt fcx, @ty.t expected, @ast.pat pat) -> @ast.pat {
auto p_1;
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.
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]],
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;
auto tpt = ty.lookup_generic_item_type(fcx.ccx.sess,
fcx.ccx.type_cache, tag_id);
auto ty_params = tpt._0;
// 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);
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));
// 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.
// FIXME: This is probably more convoluted than it has to be.
// Refactor to use the type cache.
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;
// Figure out the type parameters of the tag.
auto tag_id = option.get[ast.variant_def](vdef_opt)._0;
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 = demand_pat(fcx, subpat_ty,
subpats.(i));
new_subpats += vec(new_subpat);
i += 1u;
auto tpt = ty.lookup_generic_item_type(fcx.ccx.sess,
fcx.ccx.type_cache, tag_id);
auto ty_params = tpt._0;
// 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;
}
}
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 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(&@fn_ctxt fcx, @ty.t expected, @ast.expr e) -> @ast.expr {
be demand_expr_full(fcx, expected, e, NO_AUTODEREF);
}
fn pushdown_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
autoderef_kind adk) -> @ast.expr {
auto e_1;
fn demand_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));
}
}
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 "tup expr doesn't have a tup type!";
fail;
}
}
e_1 = ast.expr_tup(elts_1, triv_ann(t));
}
case (ast.expr_rec(?fields_0, ?base_0, ?ann)) {
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.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 (some[@ast.expr](?bx)) {
}
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 = 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));
}
case (ast.expr_rec(?fields_0, ?base_0, ?ann)) {
base_1 =
some[@ast.expr](demand_expr(fcx, t, bx));
auto base_1 = base_0;
let vec[field] base_fields = vec();
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)) {
for (ast.field field_0 in fields_0) {
base_1 = some[@ast.expr](pushdown_expr(fcx, t,
bx));
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));
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));
}
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);
}
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));
}
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);
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);
// 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;
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));
}
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);
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));
}
case (_) {
fcx.ccx.sess.span_unimpl(e.span,
"type unification for expression variant");
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 = 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);
}
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);
}