rustc: Typecheck patterns from the top down; remove pushdown_pat
This commit is contained in:
parent
76bcbfd269
commit
ad9afefa10
@ -1098,97 +1098,6 @@ fn variant_arg_types(&@crate_ctxt ccx, &span sp, &ast::def_id vid,
|
||||
// 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(&@stmt_ctxt scx, &ty::t expected, &@ast::pat pat) {
|
||||
alt (pat.node) {
|
||||
case (ast::pat_wild(?ann)) {
|
||||
auto t = demand::simple(scx, pat.span, expected,
|
||||
ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
|
||||
write::ty_only_fixup(scx, ann.id, t);
|
||||
}
|
||||
case (ast::pat_lit(?lit, ?ann)) {
|
||||
auto t = demand::simple(scx, pat.span, expected,
|
||||
ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
|
||||
write::ty_only_fixup(scx, ann.id, t);
|
||||
}
|
||||
case (ast::pat_bind(?id, ?did, ?ann)) {
|
||||
auto t = demand::simple(scx, pat.span, expected,
|
||||
ann_to_type(scx.fcx.ccx.tcx.node_types, ann));
|
||||
scx.fcx.locals.insert(did, t);
|
||||
write::ty_only_fixup(scx, ann.id, t);
|
||||
}
|
||||
case (ast::pat_tag(?id, ?subpats, ?ann)) {
|
||||
// Take the variant's type parameters out of the expected
|
||||
// type.
|
||||
auto tag_tps;
|
||||
alt (struct(scx.fcx.ccx.tcx, expected)) {
|
||||
case (ty::ty_tag(_, ?tps)) { tag_tps = tps; }
|
||||
case (_) {
|
||||
scx.fcx.ccx.tcx.sess.span_err(pat.span,
|
||||
"Non-constructor used in a pattern");
|
||||
}
|
||||
}
|
||||
|
||||
// Get the types of the arguments of the variant.
|
||||
|
||||
let vec[ty::t] tparams = [];
|
||||
auto j = 0u;
|
||||
auto actual_ty_params =
|
||||
ty::ann_to_type_params(scx.fcx.ccx.tcx.node_types, ann);
|
||||
|
||||
for (ty::t some_ty in tag_tps) {
|
||||
let ty::t t1 = some_ty;
|
||||
let ty::t t2 = actual_ty_params.(j);
|
||||
|
||||
let ty::t res = demand::simple(scx, pat.span, t1, t2);
|
||||
|
||||
vec::push(tparams, res);
|
||||
j += 1u;
|
||||
}
|
||||
|
||||
auto arg_tys;
|
||||
alt (scx.fcx.ccx.tcx.def_map.get(ann.id)) {
|
||||
case (ast::def_variant(_, ?vdefid)) {
|
||||
arg_tys = variant_arg_types(scx.fcx.ccx, pat.span,
|
||||
vdefid, tparams);
|
||||
}
|
||||
}
|
||||
|
||||
auto i = 0u;
|
||||
for (@ast::pat subpat in subpats) {
|
||||
pushdown_pat(scx, arg_tys.(i), subpat);
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
auto tps =
|
||||
ty::ann_to_type_params(scx.fcx.ccx.tcx.node_types, ann);
|
||||
auto tt = ann_to_type(scx.fcx.ccx.tcx.node_types, ann);
|
||||
|
||||
let ty_param_substs_and_ty res_t = demand::full(scx, pat.span,
|
||||
expected, tt, tps, NO_AUTODEREF);
|
||||
|
||||
auto ty_params_subst = ty::ann_to_ty_param_substs_opt_and_ty
|
||||
(scx.fcx.ccx.tcx.node_types, ann);
|
||||
|
||||
auto ty_params_opt;
|
||||
alt (ty_params_subst._0) {
|
||||
case (none) {
|
||||
ty_params_opt = none[vec[ty::t]];
|
||||
}
|
||||
case (some(?tps)) {
|
||||
ty_params_opt = some[vec[ty::t]](tag_tps);
|
||||
}
|
||||
}
|
||||
|
||||
write::ty_fixup(scx, ann.id, tup(ty_params_opt, tt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Push-down over typed expressions. Note that the expression that you
|
||||
// pass to this function must have been passed to check_expr() first.
|
||||
//
|
||||
@ -1673,75 +1582,88 @@ fn check_lit(@crate_ctxt ccx, &@ast::lit lit) -> ty::t {
|
||||
fail; // not reached
|
||||
}
|
||||
|
||||
fn check_pat(&@stmt_ctxt scx, &@ast::pat pat) {
|
||||
// Pattern checking is top-down rather than bottom-up so that bindings get
|
||||
// their types immediately.
|
||||
fn check_pat(&@stmt_ctxt scx, &@ast::pat pat, ty::t expected) {
|
||||
alt (pat.node) {
|
||||
case (ast::pat_wild(?ann)) {
|
||||
auto typ = next_ty_var(scx);
|
||||
write::ty_only_fixup(scx, ann.id, typ);
|
||||
write::ty_only_fixup(scx, ann.id, expected);
|
||||
}
|
||||
case (ast::pat_lit(?lt, ?ann)) {
|
||||
auto typ = check_lit(scx.fcx.ccx, lt);
|
||||
typ = demand::simple(scx, pat.span, expected, typ);
|
||||
write::ty_only_fixup(scx, ann.id, typ);
|
||||
}
|
||||
case (ast::pat_bind(?id, ?def_id, ?a)) {
|
||||
auto typ = next_ty_var(scx);
|
||||
write::ty_only_fixup(scx, a.id, typ);
|
||||
case (ast::pat_bind(?id, ?def_id, ?ann)) {
|
||||
scx.fcx.locals.insert(def_id, expected);
|
||||
write::ty_only_fixup(scx, ann.id, expected);
|
||||
}
|
||||
case (ast::pat_tag(?p, ?subpats, ?old_ann)) {
|
||||
auto vdef = ast::variant_def_ids
|
||||
(scx.fcx.ccx.tcx.def_map.get(old_ann.id));
|
||||
auto t = ty::lookup_item_type(scx.fcx.ccx.tcx,
|
||||
vdef._1)._1;
|
||||
auto len = vec::len[ast::ident](p.node.idents);
|
||||
auto last_id = p.node.idents.(len - 1u);
|
||||
case (ast::pat_tag(?path, ?subpats, ?ann)) {
|
||||
// Typecheck the path.
|
||||
auto v_def = scx.fcx.ccx.tcx.def_map.get(ann.id);
|
||||
auto v_def_ids = ast::variant_def_ids(v_def);
|
||||
|
||||
auto tpt = ty::lookup_item_type(scx.fcx.ccx.tcx,
|
||||
vdef._0);
|
||||
auto tag_tpt = ty::lookup_item_type(scx.fcx.ccx.tcx,
|
||||
v_def_ids._0);
|
||||
auto path_tpot = instantiate_path(scx, path, tag_tpt, pat.span);
|
||||
|
||||
auto path_tpot = instantiate_path(scx, p, tpt, pat.span);
|
||||
|
||||
alt (struct(scx.fcx.ccx.tcx, t)) {
|
||||
// N-ary variants have function types.
|
||||
case (ty::ty_fn(_, ?args, ?tag_ty, _)) {
|
||||
auto arg_len = vec::len[arg](args);
|
||||
auto subpats_len = vec::len[@ast::pat](subpats);
|
||||
if (arg_len != subpats_len) {
|
||||
// TODO: pluralize properly
|
||||
auto err_msg = "tag type " + last_id + " has " +
|
||||
uint::to_str(arg_len, 10u) +
|
||||
" field(s), but this pattern has " +
|
||||
uint::to_str(subpats_len, 10u) +
|
||||
" field(s)";
|
||||
|
||||
scx.fcx.ccx.tcx.sess.span_err(pat.span, err_msg);
|
||||
fail; // TODO: recover
|
||||
}
|
||||
|
||||
for (@ast::pat subpat in subpats) {
|
||||
check_pat(scx, subpat);
|
||||
}
|
||||
|
||||
write::ty_fixup(scx, old_ann.id, path_tpot);
|
||||
}
|
||||
|
||||
// Nullary variants have tag types.
|
||||
case (ty::ty_tag(?tid, _)) {
|
||||
auto subpats_len = vec::len[@ast::pat](subpats);
|
||||
if (subpats_len > 0u) {
|
||||
// TODO: pluralize properly
|
||||
auto err_msg = "tag type " + last_id +
|
||||
" has no field(s)," +
|
||||
" but this pattern has " +
|
||||
uint::to_str(subpats_len, 10u) +
|
||||
" field(s)";
|
||||
|
||||
scx.fcx.ccx.tcx.sess.span_err(pat.span, err_msg);
|
||||
fail; // TODO: recover
|
||||
}
|
||||
|
||||
write::ty_fixup(scx, old_ann.id, path_tpot);
|
||||
// Take the tag type params out of `expected`.
|
||||
auto expected_tps;
|
||||
alt (struct(scx.fcx.ccx.tcx, expected)) {
|
||||
case (ty::ty_tag(_, ?tps)) { expected_tps = tps; }
|
||||
case (_) {
|
||||
// FIXME: Switch expected and actual in this message? I
|
||||
// can never tell.
|
||||
scx.fcx.ccx.tcx.sess.span_err(pat.span,
|
||||
#fmt("mismatched types: expected tag but found %s",
|
||||
ty::ty_to_str(scx.fcx.ccx.tcx, expected)));
|
||||
}
|
||||
}
|
||||
|
||||
// Unify with the expected tag type.
|
||||
auto path_tpt = demand::full(scx, pat.span, expected,
|
||||
path_tpot._1, expected_tps,
|
||||
NO_AUTODEREF);
|
||||
path_tpot = tup(some[vec[ty::t]](path_tpt._0), path_tpt._1);
|
||||
|
||||
// Get the number of arguments in this tag variant.
|
||||
auto arg_types = variant_arg_types(scx.fcx.ccx, pat.span,
|
||||
v_def_ids._1, expected_tps);
|
||||
|
||||
auto subpats_len = vec::len[@ast::pat](subpats);
|
||||
|
||||
if (vec::len[ty::t](arg_types) > 0u) {
|
||||
// N-ary variant.
|
||||
auto arg_len = vec::len[ty::t](arg_types);
|
||||
if (arg_len != subpats_len) {
|
||||
// TODO: note definition of tag variant
|
||||
// TODO (issue #448): Wrap a #fmt string over multiple
|
||||
// lines...
|
||||
scx.fcx.ccx.tcx.sess.span_err(pat.span, #fmt(
|
||||
"this pattern has %u field%s, but the corresponding variant has %u field%s",
|
||||
subpats_len,
|
||||
if (subpats_len == 0u) { "" } else { "s" },
|
||||
arg_len,
|
||||
if (arg_len == 0u) { "" } else { "s" }));
|
||||
}
|
||||
|
||||
// TODO: vec::iter2
|
||||
auto i = 0u;
|
||||
for (@ast::pat subpat in subpats) {
|
||||
check_pat(scx, subpat, arg_types.(i));
|
||||
i += 1u;
|
||||
}
|
||||
} else if (subpats_len > 0u) {
|
||||
// TODO: note definition of tag variant
|
||||
// TODO (issue #448): Wrap a #fmt string over multiple
|
||||
// lines...
|
||||
scx.fcx.ccx.tcx.sess.span_err(pat.span, #fmt(
|
||||
"this pattern has %u field%s, but the corresponding variant has no fields",
|
||||
subpats_len,
|
||||
if (subpats_len == 0u) { "" } else { "s" }));
|
||||
}
|
||||
|
||||
write::ty_fixup(scx, ann.id, path_tpot);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2247,20 +2169,14 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) {
|
||||
|
||||
// Typecheck the patterns first, so that we get types for all the
|
||||
// bindings.
|
||||
auto pattern_ty = expr_ty(scx.fcx.ccx.tcx, expr);
|
||||
auto pattern_ty = ty::expr_ty(scx.fcx.ccx.tcx, expr);
|
||||
|
||||
let vec[@ast::pat] pats = [];
|
||||
for (ast::arm arm in arms) {
|
||||
check_pat(scx, arm.pat);
|
||||
pattern_ty = demand::simple(scx, arm.pat.span, pattern_ty,
|
||||
pat_ty(scx.fcx.ccx.tcx, arm.pat));
|
||||
check_pat(scx, arm.pat, pattern_ty);
|
||||
pats += [arm.pat];
|
||||
}
|
||||
|
||||
for (@ast::pat pat in pats) {
|
||||
pushdown::pushdown_pat(scx, pattern_ty, pat);
|
||||
}
|
||||
|
||||
// Now typecheck the blocks.
|
||||
auto result_ty = next_ty_var(scx);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user