rustc: Remove generalize_ty. Instead, maintain an explicit type parameter substitution list.

This commit is contained in:
Patrick Walton 2011-04-08 21:27:54 -07:00
parent ec5a60d5e2
commit 65b7578851
5 changed files with 554 additions and 364 deletions

View File

@ -742,6 +742,10 @@ fn type_of_inner(@crate_ctxt cx, @ty.t t, bool boxed) -> TypeRef {
case (ty.ty_param(_)) {
llty = T_i8();
}
case (ty.ty_bound_param(_)) {
log "ty_bound_param in trans.type_of";
fail;
}
case (ty.ty_type) { llty = T_ptr(T_tydesc(cx.tn)); }
}
@ -1144,6 +1148,7 @@ fn static_size_of_tag(@crate_ctxt cx, @ty.t t) -> uint {
auto tup_ty = ty.plain_tup_ty(args);
// Perform any type parameter substitutions.
tup_ty = ty.bind_params_in_type(tup_ty);
tup_ty = ty.substitute_type_params(subtys, tup_ty);
// Here we possibly do a recursive call.
@ -1216,7 +1221,8 @@ fn dynamic_size_of(@block_ctxt cx, @ty.t t) -> result {
let vec[@ty.t] raw_tys = variant.args;
let vec[@ty.t] tys = vec();
for (@ty.t raw_ty in raw_tys) {
auto t = ty.substitute_type_params(tps, raw_ty);
auto t = ty.bind_params_in_type(raw_ty);
t = ty.substitute_type_params(tps, t);
tys += vec(t);
}
@ -1390,7 +1396,8 @@ fn GEP_tag(@block_ctxt cx,
auto i = 0;
let vec[@ty.t] true_arg_tys = vec();
for (@ty.t aty in arg_tys) {
auto arg_ty = ty.substitute_type_params(ty_substs, aty);
auto arg_ty = ty.bind_params_in_type(aty);
arg_ty = ty.substitute_type_params(ty_substs, arg_ty);
true_arg_tys += vec(arg_ty);
if (i == ix) {
elem_ty = arg_ty;
@ -2118,8 +2125,9 @@ fn iter_structural_ty_full(@block_ctxt cx,
auto llfldp_b = rslt.val;
variant_cx = rslt.bcx;
auto ty_subst =
ty.substitute_type_params(tps, a.ty);
auto ty_subst = ty.bind_params_in_type(a.ty);
ty_subst =
ty.substitute_type_params(tps, ty_subst);
auto llfld_a =
load_if_immediate(variant_cx,
@ -2501,15 +2509,10 @@ fn target_type(@crate_ctxt cx, @ty.t t) -> @ty.t {
ret t;
}
// Converts an annotation to a type
fn node_ann_type(@crate_ctxt cx, &ast.ann a) -> @ty.t {
alt (a) {
case (ast.ann_none) {
cx.sess.bug("missing type annotation");
}
case (ast.ann_type(?t, _, _)) {
ret target_type(cx, t);
}
}
ret target_type(cx, ty.ann_to_monotype(a));
}
fn node_ann_ty_params(&ast.ann a) -> vec[@ty.t] {

View File

@ -15,6 +15,7 @@ import front.creader;
import util.common;
import util.common.new_def_hash;
import util.common.span;
import util.typestate_ann.ts_ann;
// Data types
@ -59,6 +60,7 @@ tag sty {
ty_var(int); // ephemeral type var
ty_local(ast.def_id); // type of a local var
ty_param(uint); // fn/tag type param
ty_bound_param(uint); // bound param, only paths
ty_type;
ty_native;
// TODO: ty_fn_arg(@t), for a possibly-aliased function argument
@ -67,10 +69,9 @@ tag sty {
// Data structures used in type unification
type unify_handler = obj {
fn resolve_local(ast.def_id id) -> @t;
fn record_local(ast.def_id id, @t ty);
fn unify_expected_param(uint id, @t expected, @t actual) -> unify_result;
fn unify_actual_param(uint id, @t expected, @t actual) -> unify_result;
fn resolve_local(ast.def_id id) -> option.t[@t];
fn record_local(ast.def_id id, @t ty); // TODO: -> unify_result
fn record_param(uint index, @t binding) -> unify_result;
};
tag type_err {
@ -249,6 +250,10 @@ fn ty_to_str(&@t typ) -> str {
case (ty_param(?id)) {
s += "'" + _str.unsafe_from_bytes(vec(('a' as u8) + (id as u8)));
}
case (ty_bound_param(?id)) {
s += "''" + _str.unsafe_from_bytes(vec(('a' as u8) + (id as u8)));
}
}
ret s;
@ -341,9 +346,10 @@ fn fold_ty(ty_fold fld, @t ty) -> @t {
}
ret rewrap(ty, ty_obj(new_methods));
}
case (ty_var(_)) { ret fld.fold_simple_ty(ty); }
case (ty_local(_)) { ret fld.fold_simple_ty(ty); }
case (ty_param(_)) { ret fld.fold_simple_ty(ty); }
case (ty_var(_)) { ret fld.fold_simple_ty(ty); }
case (ty_local(_)) { ret fld.fold_simple_ty(ty); }
case (ty_param(_)) { ret fld.fold_simple_ty(ty); }
case (ty_bound_param(_)) { ret fld.fold_simple_ty(ty); }
}
fail;
@ -603,6 +609,50 @@ fn ann_to_type(&ast.ann ann) -> @t {
}
}
fn ann_to_type_params(&ast.ann ann) -> vec[@t] {
alt (ann) {
case (ast.ann_none) {
log "ann_to_type_params() called on node with no type params";
fail;
}
case (ast.ann_type(_, ?tps, _)) {
alt (tps) {
case (none[vec[@ty.t]]) {
let vec[@t] result = vec();
ret result;
}
case (some[vec[@ty.t]](?tps)) { ret tps; }
}
}
}
}
// Returns the type of an annotation, with type parameter substitutions
// performed if applicable.
fn ann_to_monotype(ast.ann a) -> @ty.t {
// TODO: Refactor to use recursive pattern matching when we're more
// confident that it works.
alt (a) {
case (ast.ann_none) {
log "ann_to_monotype() called on expression with no type!";
fail;
}
case (ast.ann_type(?typ, ?tps_opt, _)) {
alt (tps_opt) {
case (none[vec[@ty.t]]) { ret typ; }
case (some[vec[@ty.t]](?tps)) {
ret substitute_type_params(tps, typ);
}
}
}
}
}
// Turns a type into an ann_type, using defaults for other fields.
fn triv_ann(@ty.t typ) -> ast.ann {
ret ast.ann_type(typ, none[vec[@ty.t]], none[@ts_ann]);
}
// Returns the number of distinct type parameters in the given type.
fn count_ty_params(@t ty) -> uint {
state obj ty_param_counter(@mutable vec[uint] param_indices) {
@ -631,6 +681,22 @@ fn count_ty_params(@t ty) -> uint {
ret _vec.len[uint](*param_indices);
}
fn type_contains_vars(@t typ) -> bool {
state obj ty_var_counter(@mutable bool flag) {
fn fold_simple_ty(@t typ) -> @t {
alt (typ.struct) {
case (ty_var(_)) { *flag = true; }
case (_) { /* fall through */ }
}
ret typ;
}
}
let @mutable bool flag = @mutable false;
fold_ty(ty_var_counter(flag), typ);
ret *flag;
}
// Type accessors for substructures of types
fn ty_fn_args(@t fty) -> vec[arg] {
@ -739,12 +805,14 @@ fn block_ty(&ast.block b) -> @t {
}
}
// Returns the type of a pattern as a monotype. Like @expr_ty, this function
// doesn't provide type parameter substitutions.
fn pat_ty(@ast.pat pat) -> @t {
alt (pat.node) {
case (ast.pat_wild(?ann)) { ret ann_to_type(ann); }
case (ast.pat_lit(_, ?ann)) { ret ann_to_type(ann); }
case (ast.pat_bind(_, _, ?ann)) { ret ann_to_type(ann); }
case (ast.pat_tag(_, _, _, ?ann)) { ret ann_to_type(ann); }
case (ast.pat_wild(?ann)) { ret ann_to_monotype(ann); }
case (ast.pat_lit(_, ?ann)) { ret ann_to_monotype(ann); }
case (ast.pat_bind(_, _, ?ann)) { ret ann_to_monotype(ann); }
case (ast.pat_tag(_, _, _, ?ann)) { ret ann_to_monotype(ann); }
}
fail; // not reached
}
@ -795,10 +863,83 @@ fn expr_ann(@ast.expr expr) -> option.t[ast.ann] {
fail;
}
// Returns the type of an expression as a monotype.
//
// NB: This type doesn't provide type parameter substitutions; e.g. if you
// ask for the type of "id" in "id(3)", it will return "fn(&int) -> int"
// instead of "fn(&T) -> T with T = int". If this isn't what you want, see
// expr_ty_params_and_ty() below.
fn expr_ty(@ast.expr expr) -> @t {
alt (expr_ann(expr)) {
case (none[ast.ann]) { ret plain_ty(ty_nil); }
case (some[ast.ann](?a)) { ret ann_to_type(a); }
case (none[ast.ann]) { ret plain_ty(ty_nil); }
case (some[ast.ann](?a)) { ret ann_to_monotype(a); }
}
}
fn expr_ty_params_and_ty(@ast.expr expr) -> tup(vec[@t], @t) {
alt (expr_ann(expr)) {
case (none[ast.ann]) {
let vec[@t] tps = vec();
ret tup(tps, plain_ty(ty_nil));
}
case (some[ast.ann](?a)) {
ret tup(ann_to_type_params(a), ann_to_type(a));
}
}
}
fn expr_has_ty_params(@ast.expr expr) -> bool {
// FIXME: Rewrite using complex patterns when they're trustworthy.
alt (expr_ann(expr)) {
case (none[ast.ann]) { fail; }
case (some[ast.ann](?a)) {
alt (a) {
case (ast.ann_none) { fail; }
case (ast.ann_type(_, ?tps_opt, _)) {
ret !option.is_none[vec[@t]](tps_opt);
}
}
}
}
}
// FIXME: At the moment this works only for call, bind, and path expressions.
fn replace_expr_type(@ast.expr expr, tup(vec[@t], @t) new_tyt) -> @ast.expr {
auto new_tps;
if (expr_has_ty_params(expr)) {
new_tps = some[vec[@t]](new_tyt._0);
} else {
new_tps = none[vec[@t]];
}
auto ann = ast.ann_type(new_tyt._1, new_tps, none[@ts_ann]);
alt (expr.node) {
case (ast.expr_call(?callee, ?args, _)) {
ret @fold.respan[ast.expr_](expr.span,
ast.expr_call(callee, args, ann));
}
case (ast.expr_self_method(?ident, _)) {
ret @fold.respan[ast.expr_](expr.span,
ast.expr_self_method(ident, ann));
}
case (ast.expr_bind(?callee, ?args, _)) {
ret @fold.respan[ast.expr_](expr.span,
ast.expr_bind(callee, args, ann));
}
case (ast.expr_field(?e, ?i, _)) {
ret @fold.respan[ast.expr_](expr.span,
ast.expr_field(e, i, ann));
}
case (ast.expr_path(?p, ?dopt, _)) {
ret @fold.respan[ast.expr_](expr.span,
ast.expr_path(p, dopt, ann));
}
case (_) {
log "unhandled expr type in replace_expr_type(): " +
pretty.pprust.expr_to_str(expr);
fail;
}
}
}
@ -1135,31 +1276,33 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
ret ures_ok(actual);
}
case (ty.ty_local(?actual_id)) {
auto actual_ty = handler.resolve_local(actual_id);
auto result = unify_step(bindings,
expected,
actual_ty,
handler);
alt (result) {
case (ures_ok(?result_ty)) {
handler.record_local(actual_id, result_ty);
auto result_ty;
alt (handler.resolve_local(actual_id)) {
case (none[@ty.t]) { result_ty = expected; }
case (some[@ty.t](?actual_ty)) {
auto result = unify_step(bindings,
expected,
actual_ty,
handler);
alt (result) {
case (ures_ok(?rty)) { result_ty = rty; }
case (_) { ret result; }
}
}
case (_) { /* empty */ }
}
ret result;
handler.record_local(actual_id, result_ty);
ret ures_ok(result_ty);
}
case (ty.ty_param(?actual_id)) {
case (ty.ty_bound_param(?actual_id)) {
alt (expected.struct) {
case (ty.ty_local(_)) {
log "TODO: bound param unifying with local";
fail;
}
// These two unify via logic lower down. Fall through.
case (ty.ty_local(_)) { }
case (ty.ty_var(_)) { }
// More-concrete types can unify against params here.
case (_) {
ret handler.unify_actual_param(actual_id,
expected,
actual);
ret handler.record_param(actual_id, expected);
}
}
}
@ -1177,6 +1320,7 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
case (ty.ty_str) { ret struct_cmp(expected, actual); }
case (ty.ty_type) { ret struct_cmp(expected, actual); }
case (ty.ty_native) { ret struct_cmp(expected, actual); }
case (ty.ty_param(_)) { ret struct_cmp(expected, actual); }
case (ty.ty_tag(?expected_id, ?expected_tps)) {
alt (actual.struct) {
@ -1510,23 +1654,27 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
}
case (ty.ty_local(?expected_id)) {
auto expected_ty = handler.resolve_local(expected_id);
auto result = unify_step(bindings,
expected_ty,
actual,
handler);
alt (result) {
case (ures_ok(?result_ty)) {
handler.record_local(expected_id, result_ty);
auto result_ty;
alt (handler.resolve_local(expected_id)) {
case (none[@ty.t]) { result_ty = actual; }
case (some[@ty.t](?expected_ty)) {
auto result = unify_step(bindings,
expected_ty,
actual,
handler);
alt (result) {
case (ures_ok(?rty)) { result_ty = rty; }
case (_) { ret result; }
}
}
case (_) { /* empty */ }
}
ret result;
handler.record_local(expected_id, result_ty);
ret ures_ok(result_ty);
}
case (ty.ty_param(?expected_id)) {
ret handler.unify_expected_param(expected_id, expected,
actual);
case (ty.ty_bound_param(?expected_id)) {
ret handler.record_param(expected_id, actual);
}
}
@ -1599,7 +1747,8 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
alt (ures) {
case (ures_ok(?t)) {
auto set_types = unify_sets(bindings);
ret ures_ok(substitute(bindings, set_types, t));
auto t2 = substitute(bindings, set_types, t);
ret ures_ok(t2);
}
case (_) { ret ures; }
}
@ -1652,58 +1801,15 @@ fn type_err_to_str(&ty.type_err err) -> str {
}
}
// Type parameter resolution, used in translation and typechecking
fn resolve_ty_params(ty_param_count_and_ty ty_params_and_polyty,
@t monoty) -> vec[@t] {
// TODO: Use a vector, not a hashmap here.
obj resolve_ty_params_handler(@hashmap[uint,@t] bindings) {
fn resolve_local(ast.def_id id) -> @t { log "resolve local"; fail; }
fn record_local(ast.def_id id, @t ty) { log "record local"; fail; }
fn unify_expected_param(uint id, @t expected, @t actual)
-> unify_result {
bindings.insert(id, actual);
ret ures_ok(actual);
}
fn unify_actual_param(uint id, @t expected, @t actual)
-> unify_result {
bindings.insert(id, expected);
ret ures_ok(expected);
}
}
auto bindings = @common.new_uint_hash[@t]();
auto handler = resolve_ty_params_handler(bindings);
auto unify_res = unify(ty_params_and_polyty._1, monoty, handler);
alt (unify_res) {
case (ures_ok(_)) { /* fall through */ }
case (ures_err(_,?exp,?act)) {
log "resolve_ty_params mismatch: " + ty_to_str(exp) + " " +
ty_to_str(act);
fail;
}
}
let vec[@t] result_tys = vec();
auto ty_param_count = ty_params_and_polyty._0;
auto i = 0u;
while (i < ty_param_count) {
check (bindings.contains_key(i));
result_tys += vec(bindings.get(i));
i += 1u;
}
ret result_tys;
}
// Performs type parameter replacement using the supplied mapping from
// Performs bound type parameter replacement using the supplied mapping from
// parameter IDs to types.
fn substitute_type_params(vec[@t] bindings, @t typ) -> @t {
state obj param_replacer(vec[@t] bindings) {
fn fold_simple_ty(@t typ) -> @t {
alt (typ.struct) {
case (ty_param(?param_index)) { ret bindings.(param_index); }
case (ty_bound_param(?param_index)) {
ret bindings.(param_index);
}
case (_) { ret typ; }
}
}
@ -1712,6 +1818,29 @@ fn substitute_type_params(vec[@t] bindings, @t typ) -> @t {
ret fold_ty(replacer, typ);
}
// Converts type parameters in a type to bound type parameters.
fn bind_params_in_type(@t typ) -> @t {
state obj folder(() env) {
fn fold_simple_ty(@t typ) -> @t {
alt (typ.struct) {
case (ty_bound_param(?index)) {
log "bind_params_in_type() called on type that already " +
"has bound params in it";
fail;
}
case (ty_param(?index)) {
ret plain_ty(ty_bound_param(index));
}
case (_) {
ret typ;
}
}
}
}
ret fold_ty(folder(()), typ);
}
fn def_has_ty_params(&ast.def def) -> bool {
alt (def) {

View File

@ -11,6 +11,7 @@ import util.common.span;
import middle.ty;
import middle.ty.ann_to_type;
import middle.ty.arg;
import middle.ty.bind_params_in_type;
import middle.ty.block_ty;
import middle.ty.expr_ty;
import middle.ty.field;
@ -19,6 +20,7 @@ import middle.ty.mode_is_alias;
import middle.ty.pat_ty;
import middle.ty.path_to_str;
import middle.ty.plain_ty;
import middle.ty.triv_ann;
import middle.ty.ty_to_str;
import middle.ty.type_is_integral;
import middle.ty.type_is_scalar;
@ -61,41 +63,12 @@ type fn_ctxt = rec(@ty.t ret_ty,
// Used for ast_ty_to_ty() below.
type ty_getter = fn(ast.def_id) -> ty.ty_param_count_and_ty;
// Turns a type into an ann_type, using defaults for other fields.
fn triv_ann(@ty.t t) -> ann {
ret ast.ann_type(t, none[vec[@ty.t]], none[@ts_ann]);
}
// Used to fill in the annotation for things that have uninteresting
// types
fn boring_ann() -> ann {
ret triv_ann(plain_ty(ty_nil));
}
// Replaces parameter types inside a type with type variables.
fn generalize_ty(@crate_ctxt cx, @ty.t t) -> @ty.t {
state obj ty_generalizer(@crate_ctxt cx,
@hashmap[uint,@ty.t] ty_params_to_ty_vars) {
fn fold_simple_ty(@ty.t t) -> @ty.t {
alt (t.struct) {
case (ty.ty_param(?pid)) {
if (ty_params_to_ty_vars.contains_key(pid)) {
ret ty_params_to_ty_vars.get(pid);
}
auto var_ty = next_ty_var(cx);
ty_params_to_ty_vars.insert(pid, var_ty);
ret var_ty;
}
case (_) { /* fall through */ }
}
ret t;
}
}
auto generalizer = ty_generalizer(cx, @common.new_uint_hash[@ty.t]());
ret ty.fold_ty(generalizer, t);
}
// Substitutes the user's explicit types for the parameters in a path
// expression.
fn substitute_ty_params(&@crate_ctxt ccx,
@ -106,7 +79,7 @@ fn substitute_ty_params(&@crate_ctxt ccx,
state obj ty_substituter(@crate_ctxt ccx, vec[@ty.t] supplied) {
fn fold_simple_ty(@ty.t typ) -> @ty.t {
alt (typ.struct) {
case (ty.ty_param(?pid)) { ret supplied.(pid); }
case (ty.ty_bound_param(?pid)) { ret supplied.(pid); }
case (_) { ret typ; }
}
}
@ -190,7 +163,7 @@ fn ty_param_count_and_ty_for_def(@fn_ctxt fcx, &ast.def defn)
fn instantiate_path(@fn_ctxt fcx, &ast.path pth, &ty_param_count_and_ty tpt,
&span sp) -> ast.ann {
auto ty_param_count = tpt._0;
auto t = tpt._1;
auto t = bind_params_in_type(tpt._1);
auto ty_substs_opt;
auto ty_substs_len = _vec.len[@ast.ty](pth.node.types);
@ -208,15 +181,15 @@ fn instantiate_path(@fn_ctxt fcx, &ast.path pth, &ty_param_count_and_ty tpt,
"parameters");
fail;
}
t = substitute_ty_params(fcx.ccx, t, ty_param_count, ty_substs, sp);
} else {
ty_substs_opt = none[vec[@ty.t]];
if (ty_param_count > 0u) {
// We will acquire the type parameters through unification.
t = generalize_ty(fcx.ccx, t);
// We will acquire the type parameters through unification.
let vec[@ty.t] ty_substs = vec();
auto i = 0u;
while (i < ty_param_count) {
ty_substs += vec(next_ty_var(fcx.ccx));
i += 1u;
}
ty_substs_opt = some[vec[@ty.t]](ty_substs);
}
ret ast.ann_type(t, ty_substs_opt, none[@ts_ann]);
@ -249,11 +222,12 @@ fn ast_ty_to_ty(ty_getter getter, &@ast.ty ast_ty) -> @ty.t {
//
// TODO: Make sure the number of supplied bindings matches the number
// of type parameters in the typedef. Emit a friendly error otherwise.
auto bound_ty = bind_params_in_type(params_opt_and_ty._1);
let vec[@ty.t] param_bindings = vec();
for (@ast.ty ast_ty in args) {
param_bindings += vec(ast_ty_to_ty(getter, ast_ty));
}
ret ty.substitute_type_params(param_bindings, params_opt_and_ty._1);
ret ty.substitute_type_params(param_bindings, bound_ty);
}
auto mut = ast.imm;
@ -337,7 +311,8 @@ fn ast_ty_to_ty(ty_getter getter, &@ast.ty ast_ty) -> @ty.t {
}
}
ret @rec(struct=sty, cname=cname);
auto typ = @rec(struct=sty, cname=cname);
ret typ;
}
// A convenience function to use a crate_ctxt to resolve names for
@ -843,43 +818,72 @@ fn collect_item_types(session.session sess, @ast.crate crate)
ret tup(crate_, type_cache, id_to_ty_item);
}
fn unify(&@fn_ctxt fcx, @ty.t expected, @ty.t actual) -> ty.unify_result {
obj unify_handler(@fn_ctxt fcx) {
fn resolve_local(ast.def_id id) -> @ty.t {
if (!fcx.locals.contains_key(id)) {
ret next_ty_var(fcx.ccx);
}
ret fcx.locals.get(id);
}
fn record_local(ast.def_id id, @ty.t t) {
fcx.locals.insert(id, t);
}
fn unify_expected_param(uint id, @ty.t expected, @ty.t actual)
-> ty.unify_result {
alt (actual.struct) {
case (ty.ty_param(?actual_id)) {
if (id == actual_id) { ret ty.ures_ok(expected); }
}
case (_) { /* fall through */ }
}
ret ty.ures_err(ty.terr_mismatch, expected, actual);
}
fn unify_actual_param(uint id, @ty.t expected, @ty.t actual)
-> ty.unify_result {
alt (expected.struct) {
case (ty.ty_param(?expected_id)) {
if (id == expected_id) { ret ty.ures_ok(actual); }
}
case (_) { /* fall through */ }
}
ret ty.ures_err(ty.terr_mismatch, expected, actual);
}
// Type unification
mod Unify {
fn simple(@fn_ctxt fcx, @ty.t expected, @ty.t actual) -> ty.unify_result {
// FIXME: horrid botch
let vec[mutable @ty.t] param_substs =
vec(mutable plain_ty(ty.ty_nil));
_vec.pop[mutable @ty.t](param_substs);
ret with_params(fcx, expected, actual, param_substs);
}
auto handler = unify_handler(fcx);
ret ty.unify(expected, actual, handler);
fn with_params(@fn_ctxt fcx, @ty.t expected, @ty.t actual,
vec[mutable @ty.t] param_substs) -> ty.unify_result {
obj unify_handler(@fn_ctxt fcx, vec[mutable @ty.t] param_substs) {
fn resolve_local(ast.def_id id) -> option.t[@ty.t] {
alt (fcx.locals.find(id)) {
case (none[@ty.t]) { ret none[@ty.t]; }
case (some[@ty.t](?existing_type)) {
if (ty.type_contains_vars(existing_type)) {
// Not fully resolved yet. The writeback phase
// will mop up.
ret none[@ty.t];
}
ret some[@ty.t](existing_type);
}
}
}
fn record_local(ast.def_id id, @ty.t new_type) {
auto unified_type;
alt (fcx.locals.find(id)) {
case (none[@ty.t]) { unified_type = new_type; }
case (some[@ty.t](?old_type)) {
alt (with_params(fcx, old_type, new_type,
param_substs)) {
case (ty.ures_ok(?ut)) { unified_type = ut; }
case (_) { fail; /* FIXME */ }
}
}
}
fcx.locals.insert(id, unified_type);
}
fn record_param(uint index, @ty.t binding) -> ty.unify_result {
// Unify with the appropriate type in the parameter
// substitution list.
auto old_subst = param_substs.(index);
auto result = with_params(fcx, old_subst, binding,
param_substs);
alt (result) {
case (ty.ures_ok(?new_subst)) {
param_substs.(index) = new_subst;
ret ty.ures_ok(plain_ty(ty.ty_bound_param(index)));
}
case (_) { ret result; }
}
}
}
auto handler = unify_handler(fcx, param_substs);
ret ty.unify(expected, actual, handler);
}
}
tag autoderef_kind {
AUTODEREF_OK;
NO_AUTODEREF;
@ -919,51 +923,107 @@ fn count_boxes(@ty.t t) -> uint {
}
fn demand(&@fn_ctxt fcx, &span sp, @ty.t expected, @ty.t actual) -> @ty.t {
be demand_full(fcx, sp, expected, actual, NO_AUTODEREF);
}
// Demands - procedures that require that two types unify and emit an error
// message if they don't.
type ty_param_substs_and_ty = tup(vec[@ty.t], @ty.t);
// Requires that the two types unify, and prints an error message if they
// don't. Returns the unified type.
fn demand_full(&@fn_ctxt fcx, &span sp,
@ty.t expected, @ty.t actual, autoderef_kind adk) -> @ty.t {
auto expected_1 = expected;
auto actual_1 = actual;
auto implicit_boxes = 0u;
if (adk == AUTODEREF_OK) {
expected_1 = strip_boxes(expected);
actual_1 = strip_boxes(actual);
implicit_boxes = count_boxes(actual);
mod Demand {
fn simple(@fn_ctxt fcx, &span sp, @ty.t expected, @ty.t actual) -> @ty.t {
let vec[@ty.t] tps = vec();
ret full(fcx, sp, expected, actual, tps, NO_AUTODEREF)._1;
}
alt (unify(fcx, expected_1, actual_1)) {
case (ty.ures_ok(?t)) { ret add_boxes(implicit_boxes, t); }
fn autoderef(@fn_ctxt fcx, &span sp, @ty.t expected, @ty.t actual,
autoderef_kind adk) -> @ty.t {
let vec[@ty.t] tps = vec();
ret full(fcx, sp, expected, actual, tps, adk)._1;
}
case (ty.ures_err(?err, ?expected, ?actual)) {
fcx.ccx.sess.span_err(sp, "mismatched types: expected "
+ ty_to_str(expected) + " but found "
+ ty_to_str(actual) + " (" +
ty.type_err_to_str(err) + ")");
// Requires that the two types unify, and prints an error message if they
// don't. Returns the unified type and the type parameter substitutions.
// TODO: In the future, try returning "expected", reporting the
// error, and continue.
fail;
fn full(@fn_ctxt fcx, &span sp, @ty.t expected, @ty.t actual,
vec[@ty.t] ty_param_substs_0, autoderef_kind adk)
-> ty_param_substs_and_ty {
auto expected_1 = expected;
auto actual_1 = actual;
auto implicit_boxes = 0u;
if (adk == AUTODEREF_OK) {
expected_1 = strip_boxes(expected_1);
actual_1 = strip_boxes(actual_1);
implicit_boxes = count_boxes(actual);
}
let vec[mutable @ty.t] ty_param_substs =
vec(mutable plain_ty(ty.ty_nil));
_vec.pop[mutable @ty.t](ty_param_substs); // FIXME: horrid botch
for (@ty.t ty_param_subst in ty_param_substs_0) {
ty_param_substs += vec(mutable ty_param_subst);
}
alt (Unify.with_params(fcx, expected_1, actual_1, ty_param_substs)) {
case (ty.ures_ok(?t)) {
// TODO: Use "freeze", when we have it.
let vec[@ty.t] result_ty_param_substs = vec();
for (mutable @ty.t ty_param_subst in ty_param_substs) {
result_ty_param_substs += vec(ty_param_subst);
}
ret tup(result_ty_param_substs, add_boxes(implicit_boxes, t));
}
case (ty.ures_err(?err, ?expected, ?actual)) {
fcx.ccx.sess.span_err(sp, "mismatched types: expected "
+ ty_to_str(expected) + " but found "
+ ty_to_str(actual) + " (" +
ty.type_err_to_str(err) + ")");
// TODO: In the future, try returning "expected", reporting
// the error, and continue.
fail;
}
}
}
}
// Returns true if the two types unify and false if they don't.
fn are_compatible(&@fn_ctxt fcx, @ty.t expected, @ty.t actual) -> bool {
alt (unify(fcx, expected, actual)) {
alt (Unify.simple(fcx, expected, actual)) {
case (ty.ures_ok(_)) { ret true; }
case (ty.ures_err(_, _, _)) { ret false; }
}
}
// Returns the types of the arguments to a tag variant.
fn variant_arg_types(@crate_ctxt ccx, &span sp, ast.def_id vid,
vec[@ty.t] tag_ty_params) -> vec[@ty.t] {
auto ty_param_count = _vec.len[@ty.t](tag_ty_params);
let vec[@ty.t] result = vec();
auto tpt = ty.lookup_item_type(ccx.sess, ccx.type_cache, vid);
alt (tpt._1.struct) {
case (ty.ty_fn(_, ?ins, _)) {
// N-ary variant.
for (ty.arg arg in ins) {
auto arg_ty = bind_params_in_type(arg.ty);
arg_ty = substitute_ty_params(ccx, arg_ty, ty_param_count,
tag_ty_params, sp);
result += vec(arg_ty);
}
}
case (_) {
// Nullary variant. Do nothing, as there are no arguments.
}
}
ret result;
}
// The "push-down" phase, which takes a typed grammar production and pushes
// its type down into its constituent parts.
@ -992,83 +1052,51 @@ mod Pushdown {
alt (pat.node) {
case (ast.pat_wild(?ann)) {
auto t = demand(fcx, pat.span, expected, ann_to_type(ann));
auto t = Demand.simple(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));
auto t = Demand.simple(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));
auto t = Demand.simple(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_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; }
// Take the variant's type parameters out of the expected
// type.
auto tag_tps;
alt (expected.struct) {
case (ty.ty_tag(_, ?tps)) { tag_tps = tps; }
case (_) {
log "pushdown_pat(): expected type for tag pat " +
"isn't actually a tag?!";
log "tag pattern type not 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.
// Get the types of the arguments of the variant.
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 arg_tys = variant_arg_types(fcx.ccx, pat.span, vdef._1,
tag_tps);
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]));
}
let vec[@ast.pat] subpats_1 = vec();
auto i = 0u;
for (@ast.pat subpat in subpats) {
subpats_1 += vec(pushdown_pat(fcx, arg_tys.(i), subpat));
i += 1u;
}
// TODO: push down type from "expected".
p_1 = ast.pat_tag(id, subpats_1, vdef_opt, ann);
}
}
@ -1087,14 +1115,15 @@ mod Pushdown {
}
fn pushdown_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
autoderef_kind adk) -> @ast.expr {
autoderef_kind adk) -> @ast.expr {
auto e_1;
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));
auto t = Demand.simple(fcx, e.span, expected,
ann_to_type(ann));
let vec[@ast.expr] es_1 = vec();
alt (t.struct) {
case (ty.ty_vec(?mt)) {
@ -1110,7 +1139,8 @@ mod Pushdown {
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));
auto t = Demand.simple(fcx, e.span, expected,
ann_to_type(ann));
let vec[ast.elt] elts_1 = vec();
alt (t.struct) {
case (ty.ty_tup(?mts)) {
@ -1133,7 +1163,8 @@ mod Pushdown {
auto base_1 = base_0;
auto t = demand(fcx, e.span, expected, ann_to_type(ann));
auto t = Demand.simple(fcx, e.span, expected,
ann_to_type(ann));
let vec[ast.field] fields_1 = vec();
alt (t.struct) {
case (ty.ty_rec(?field_mts)) {
@ -1186,43 +1217,49 @@ mod Pushdown {
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));
auto t = Demand.simple(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);
// NB: we call 'Demand.autoderef' 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.autoderef(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));
auto t = Demand.simple(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));
auto t = Demand.simple(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);
// See note in expr_unary for why we're calling
// Demand.autoderef.
auto t = Demand.autoderef(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));
auto t = Demand.simple(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));
auto t = Demand.simple(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 t = Demand.autoderef(fcx, e.span, expected,
ann_to_type(ann), adk);
auto then_1 = pushdown_block(fcx, expected, then_0);
auto else_1;
@ -1236,53 +1273,61 @@ mod Pushdown {
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));
auto t = Demand.simple(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));
auto t = Demand.simple(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));
auto t = Demand.simple(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));
auto t = Demand.simple(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);
auto t = Demand.autoderef(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 t = Demand.autoderef(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 t = Demand.autoderef(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);
auto t = Demand.autoderef(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);
auto t = Demand.autoderef(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);
auto tp_substs_0 = ty.ann_to_type_params(ann);
auto t_0 = ann_to_type(ann);
auto result_0 = Demand.full(fcx, e.span, expected, t_0,
tp_substs_0, adk);
auto t = result_0._1;
// Fill in the type parameter substitutions if they weren't
// provided by the programmer.
@ -1296,11 +1341,7 @@ mod Pushdown {
case (ast.ann_type(_, ?tps_opt, _)) {
alt (tps_opt) {
case (none[vec[@ty.t]]) {
auto defn = option.get[ast.def](d);
auto tpt =
ty_param_count_and_ty_for_def(fcx, defn);
auto tps = ty.resolve_ty_params(tpt, t);
ty_params_opt = some[vec[@ty.t]](tps);
ty_params_opt = none[vec[@ty.t]];
}
case (some[vec[@ty.t]](?tps)) {
ty_params_opt = some[vec[@ty.t]](tps);
@ -1314,8 +1355,8 @@ mod Pushdown {
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);
auto t = Demand.autoderef(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? */
@ -1329,12 +1370,14 @@ mod Pushdown {
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));
auto t = Demand.simple(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));
auto t = Demand.simple(fcx, e.span, expected,
ann_to_type(ann));
let @ast.expr es_1;
alt (t.struct) {
case (ty.ty_chan(?subty)) {
@ -1354,7 +1397,7 @@ mod Pushdown {
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));
t = Demand.simple(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);
@ -1404,7 +1447,7 @@ mod Pushdown {
ret fold.respan[ast.block_](bloc.span, block_);
}
case (none[@ast.expr]) {
demand(fcx, bloc.span, expected, plain_ty(ty.ty_nil));
Demand.simple(fcx, bloc.span, expected, plain_ty(ty.ty_nil));
ret bloc;
}
}
@ -1443,14 +1486,14 @@ fn resolve_local_types_in_annotation(&option.t[@fn_ctxt] env, ast.ann ann)
auto fcx = option.get[@fn_ctxt](env);
alt (ann) {
case (ast.ann_none) {
log "warning: no type for expression";
ret ann;
}
case (ast.ann_type(?typ, ?tps, ?ts_info)) {
auto new_type = ty.fold_ty(folder(fcx), ann_to_type(ann));
ret ast.ann_type(new_type, tps, ts_info);
}
case (ast.ann_none) {
log "warning: no type for expression";
ret ann;
}
case (ast.ann_type(?typ, ?tps, ?ts_info)) {
auto new_type = ty.fold_ty(folder(fcx), ann_to_type(ann));
ret ast.ann_type(new_type, tps, ts_info);
}
}
}
@ -1623,42 +1666,13 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
}
}
// Unify and write back to the function.
auto f_1 = Pushdown.pushdown_expr(fcx, t_0, f_0);
// Unify the callee and arguments.
auto tpt_0 = ty.expr_ty_params_and_ty(f_0);
auto tpt_1 = Demand.full(fcx, f.span, tpt_0._1, t_0, tpt_0._0,
NO_AUTODEREF);
auto f_1 = ty.replace_expr_type(f_0, tpt_1);
// Take the argument types out of the resulting function type.
auto t_1 = expr_ty(f_1);
if (!ty.is_fn_ty(t_1)) {
fcx.ccx.sess.span_err(f_1.span,
"mismatched types: callee has " +
"non-function type: " +
ty_to_str(t_1));
}
let vec[arg] arg_tys_1 = ty.ty_fn_args(t_1);
let @ty.t rt_1 = ty.ty_fn_ret(t_1);
// Unify and write back to the arguments.
auto i = 0u;
let vec[option.t[@ast.expr]] args_1 = vec();
while (i < _vec.len[option.t[@ast.expr]](args_0)) {
alt (args_0.(i)) {
case (some[@ast.expr](?e_0)) {
auto arg_ty_1 = arg_tys_1.(i);
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));
}
case (none[@ast.expr]) {
_vec.push[option.t[@ast.expr]](args_1, none[@ast.expr]);
}
}
i += 1u;
}
ret tup(f_1, args_1);
ret tup(f_1, args_0);
}
// A generic function for checking assignment expressions
@ -1767,10 +1781,25 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
auto t = plain_ty(ty.ty_nil);
check (defopt != none[ast.def]);
auto defn = option.get[ast.def](defopt);
auto tpt = ty_param_count_and_ty_for_def(fcx, defn);
auto ann = instantiate_path(fcx, pth, tpt, expr.span);
ret @fold.respan[ast.expr_](expr.span,
ast.expr_path(pth, defopt, ann));
if (ty.def_has_ty_params(defn)) {
auto ann = instantiate_path(fcx, pth, tpt, expr.span);
ret @fold.respan[ast.expr_](expr.span,
ast.expr_path(pth, defopt, ann));
}
// The definition doesn't take type parameters. If the programmer
// supplied some, that's an error.
if (_vec.len[@ast.ty](pth.node.types) > 0u) {
fcx.ccx.sess.span_err(expr.span, "this kind of value does " +
"not take type parameters");
fail;
}
auto e = ast.expr_path(pth, defopt, triv_ann(tpt._1));
ret @fold.respan[ast.expr_](expr.span, e);
}
case (ast.expr_ext(?p, ?args, ?body, ?expanded, _)) {
@ -1863,7 +1892,8 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
case (ast.expr_check_expr(?e, _)) {
auto expr_t = check_expr(fcx, e);
demand(fcx, expr.span, plain_ty(ty.ty_bool), expr_ty(expr_t));
Demand.simple(fcx, expr.span, plain_ty(ty.ty_bool),
expr_ty(expr_t));
ret @fold.respan[ast.expr_]
(expr.span, ast.expr_check_expr(expr_t, boring_ann()));
}
@ -2020,8 +2050,8 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
let vec[@ast.pat] pats_0 = vec();
for (ast.arm arm in arms) {
auto pat_0 = check_pat(fcx, arm.pat);
pattern_ty = demand(fcx, pat_0.span, pattern_ty,
pat_ty(pat_0));
pattern_ty = Demand.simple(fcx, pat_0.span, pattern_ty,
pat_ty(pat_0));
pats_0 += vec(pat_0);
}
@ -2036,8 +2066,8 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
let vec[ast.block] blocks_0 = vec();
for (ast.arm arm in arms) {
auto block_0 = check_block(fcx, arm.block);
result_ty = demand(fcx, block_0.span, result_ty,
block_ty(block_0));
result_ty = Demand.simple(fcx, block_0.span, result_ty,
block_ty(block_0));
blocks_0 += vec(block_0);
}
@ -2232,7 +2262,7 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
for (@ast.expr e in args) {
auto expr_1 = check_expr(fcx, e);
auto expr_t = expr_ty(expr_1);
demand(fcx, expr.span, t, expr_t);
Demand.simple(fcx, expr.span, t, expr_t);
_vec.push[@ast.expr](args_1,expr_1);
}
@ -2310,7 +2340,8 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
auto found = false;
for (ty.field bf in base_fields) {
if (_str.eq(f.ident, bf.ident)) {
demand(fcx, expr.span, f.mt.ty, bf.mt.ty);
Demand.simple(fcx, expr.span, f.mt.ty,
bf.mt.ty);
found = true;
}
}
@ -2378,9 +2409,9 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
}
case (_) {
fcx.ccx.sess.unimpl("base type for expr_field "
+ "in typeck.check_expr: "
+ ty_to_str(base_t));
fcx.ccx.sess.span_unimpl(expr.span,
"base type for expr_field in typeck.check_expr: " +
ty_to_str(base_t));
}
}
}
@ -2512,6 +2543,7 @@ fn check_decl_local(&@fn_ctxt fcx, &@ast.decl decl) -> @ast.decl {
expr_0);
}
}
auto init_0 = rec(expr = expr_1 with init);
initopt = some[ast.initializer](init_0);
}

View File

@ -50,6 +50,15 @@ fn expr_to_str(&@ast.expr e) -> str {
ret writer.get_str();
}
fn pat_to_str(&@ast.pat p) -> str {
auto writer = io.string_writer();
auto s = @rec(s=pp.mkstate(writer.get_writer(), 78u),
comments=option.none[vec[lexer.cmnt]],
mutable cur_cmnt=0u);
print_pat(s, p);
ret writer.get_str();
}
impure fn hbox(ps s) {
pp.hbox(s.s, indent_unit);
}

View File

@ -252,6 +252,23 @@ rust_task::start(uintptr_t exit_task_glue,
transition(&dom->newborn_tasks, &dom->running_tasks);
}
#if 0
void
rust_task::print_stack_trace()
{
void *addrs[256];
uintptr_t sp = this->rust_sp;
// We need to be careful to not use any Rust stack space here, since this
// may be called on stack overflow.
asm("xchgl %0, %%esp\n"
"pushl $256\n"
"pushl %1\n"
"calll %3\n"
"xchgl %%esp, %0\n"
}
#endif
void
rust_task::grow(size_t n_frame_bytes)
{