Revert "allow fn exprs to omit arg types"

This reverts commit 1ba4ca4c4a.
This commit is contained in:
Niko Matsakis
2012-05-03 14:42:34 -07:00
parent 1ba4ca4c4a
commit cfa09d35a3
10 changed files with 103 additions and 178 deletions

View File

@@ -275,8 +275,7 @@ fn instantiate_path(fcx: @fn_ctxt,
fcx.write_ty_substs(id, tpt.ty, substs);
}
// Resolves `typ` by a single level if `typ` is a type variable. If no
// resolution is possible, then an error is reported.
// Type tests
fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
alt infer::resolve_shallow(fcx.infcx, tp, false) {
result::ok(t_s) if !ty::type_is_var(t_s) { ret t_s; }
@@ -287,6 +286,7 @@ fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
}
}
// Returns the one-level-deep structure of the given type.
fn structure_of(fcx: @fn_ctxt, sp: span, typ: ty::t) -> ty::sty {
ty::get(structurally_resolved_type(fcx, sp, typ)).struct
@@ -689,7 +689,7 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
ty::mk_rec(tcx, flds)
}
ast::ty_fn(proto, decl) {
ty::mk_fn(tcx, ty_of_fn_decl(self, rscope, proto, decl, none))
ty::mk_fn(tcx, ty_of_fn_decl(self, rscope, proto, decl))
}
ast::ty_path(path, id) {
let a_def = alt tcx.def_map.find(id) {
@@ -777,13 +777,7 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
ty::mk_constr(tcx, ast_ty_to_ty(self, rscope, t), out_cs)
}
ast::ty_infer {
// ty_infer should only appear as the type of arguments or return
// values in a fn_expr, or as the type of local variables. Both of
// these cases are handled specially and should not descend into this
// routine.
self.tcx().sess.span_bug(
ast_ty.span,
"found `ty_infer` in unexpected place");
self.ty_infer(ast_ty.span)
}
ast::ty_mac(_) {
tcx.sess.span_bug(ast_ty.span,
@@ -856,8 +850,7 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
}
ast::item_fn(decl, tps, _) {
let bounds = ty_param_bounds(ccx, tps);
let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare,
decl, none);
let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare, decl);
let tpt = {bounds: bounds,
rp: ast::rp_none, // functions do not have a self
ty: ty::mk_fn(ccx.tcx, tofd)};
@@ -891,8 +884,7 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
}
ast::item_res(decl, tps, _, _, _, rp) {
let {bounds, substs} = mk_substs(ccx, tps, rp);
let t_arg = ty_of_arg(ccx, type_rscope(rp),
decl.inputs[0], none);
let t_arg = ty_of_arg(ccx, type_rscope(rp), decl.inputs[0]);
let t = ty::mk_res(tcx, local_def(it.id), t_arg.ty, substs);
let t_res = {bounds: bounds, rp: rp, ty: t};
tcx.tcache.insert(local_def(it.id), t_res);
@@ -1035,27 +1027,16 @@ fn replace_bound_regions(
}
fn ty_of_arg<AC: ast_conv, RS: region_scope copy>(
self: AC, rscope: RS, a: ast::arg,
expected_ty: option<ty::arg>) -> ty::arg {
self: AC, rscope: RS, a: ast::arg) -> ty::arg {
let ty = alt a.ty.node {
ast::ty_infer if expected_ty.is_some() {expected_ty.get().ty}
ast::ty_infer {self.ty_infer(a.ty.span)}
_ {ast_ty_to_ty(self, rscope, a.ty)}
};
let mode = {
alt a.mode {
ast::infer(_) if expected_ty.is_some() {
result::get(ty::unify_mode(self.tcx(), a.mode,
expected_ty.get().mode))
}
fn arg_mode(tcx: ty::ctxt, m: ast::mode, ty: ty::t) -> ast::mode {
alt m {
ast::infer(_) {
alt ty::get(ty).struct {
// If the type is not specified, then this must be a fn expr.
// Leave the mode as infer(_), it will get inferred based
// on constraints elsewhere.
ty::ty_var(_) {a.mode}
ty::ty_var(_) { m }
// If the type is known, then use the default for that type.
// Here we unify m and the default. This should update the
@@ -1063,48 +1044,30 @@ fn ty_of_arg<AC: ast_conv, RS: region_scope copy>(
// will have been unified with m yet:
_ {
let m1 = ast::expl(ty::default_arg_mode_for_ty(ty));
result::get(ty::unify_mode(self.tcx(), a.mode, m1))
result::get(ty::unify_mode(tcx, m, m1))
}
}
}
ast::expl(_) {a.mode}
ast::expl(_) { m }
}
};
}
let ty = ast_ty_to_ty(self, rscope, a.ty);
let mode = arg_mode(self.tcx(), a.mode, ty);
{mode: mode, ty: ty}
}
type expected_tys = option<{inputs: [ty::arg],
output: ty::t}>;
fn ty_of_fn_decl<AC: ast_conv, RS: region_scope copy>(
self: AC, rscope: RS,
proto: ast::proto,
decl: ast::fn_decl,
expected_tys: expected_tys) -> ty::fn_ty {
decl: ast::fn_decl) -> ty::fn_ty {
#debug["ty_of_fn_decl"];
indent {||
// new region names that appear inside of the fn decl are bound to
// that function type
let rb = in_binding_rscope(rscope);
let input_tys = decl.inputs.mapi { |i, a|
let expected_arg_ty = expected_tys.chain { |e|
// no guarantee that the correct number of expected args
// were supplied
if i < e.inputs.len() {some(e.inputs[i])} else {none}
};
ty_of_arg(self, rb, a, expected_arg_ty)
};
let expected_ret_ty = expected_tys.map { |e| e.output };
let output_ty = alt decl.output.node {
ast::ty_infer if expected_ret_ty.is_some() {expected_ret_ty.get()}
ast::ty_infer {self.ty_infer(decl.output.span)}
_ {ast_ty_to_ty(self, rb, decl.output)}
};
let input_tys = vec::map(decl.inputs) { |a| ty_of_arg(self, rb, a) };
let output_ty = ast_ty_to_ty(self, rb, decl.output);
let out_constrs = vec::map(decl.constraints) {|constr|
ty::ast_constr_to_constr(self.tcx(), constr)
};
@@ -1120,7 +1083,7 @@ fn ty_of_native_fn_decl(ccx: @crate_ctxt,
let bounds = ty_param_bounds(ccx, ty_params);
let rb = in_binding_rscope(empty_rscope);
let input_tys = decl.inputs.map { |a| ty_of_arg(ccx, rb, a, none) };
let input_tys = vec::map(decl.inputs) { |a| ty_of_arg(ccx, rb, a) };
let output_ty = ast_ty_to_ty(ccx, rb, decl.output);
let t_fn = ty::mk_fn(ccx.tcx, {proto: ast::proto_bare,
@@ -1172,8 +1135,7 @@ fn ty_of_method(ccx: @crate_ctxt,
rp: ast::region_param) -> ty::method {
{ident: m.ident,
tps: ty_param_bounds(ccx, m.tps),
fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare,
m.decl, none),
fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare, m.decl),
purity: m.decl.purity,
privacy: m.privacy}
}
@@ -1183,8 +1145,7 @@ fn ty_of_ty_method(self: @crate_ctxt,
rp: ast::region_param) -> ty::method {
{ident: m.ident,
tps: ty_param_bounds(self, m.tps),
fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare,
m.decl, none),
fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare, m.decl),
// assume public, because this is only invoked on iface methods
purity: m.decl.purity, privacy: ast::pub}
}
@@ -1688,8 +1649,7 @@ mod collect {
ast::item_res(decl, tps, _, dtor_id, ctor_id, rp) {
let {bounds, substs} = mk_substs(ccx, tps, rp);
let def_id = local_def(it.id);
let t_arg = ty_of_arg(ccx, type_rscope(rp),
decl.inputs[0], none);
let t_arg = ty_of_arg(ccx, type_rscope(rp), decl.inputs[0]);
let t_res = ty::mk_res(tcx, def_id, t_arg.ty, substs);
let t_ctor = ty::mk_fn(tcx, {
@@ -1731,8 +1691,7 @@ mod collect {
ty_of_fn_decl(ccx,
empty_rscope,
ast::proto_any,
ctor.node.dec,
none));
ctor.node.dec));
write_ty_to_tcx(tcx, ctor.node.id, t_ctor);
tcx.tcache.insert(local_def(ctor.node.id),
{bounds: tpt.bounds,
@@ -2943,6 +2902,35 @@ fn region_of(fcx: @fn_ctxt, expr: @ast::expr) -> ty::region {
}
}
fn check_expr_fn_with_unifier(fcx: @fn_ctxt,
expr: @ast::expr,
proto: ast::proto,
decl: ast::fn_decl,
body: ast::blk,
is_loop_body: bool,
unifier: fn()) {
let tcx = fcx.ccx.tcx;
let fty = ty::mk_fn(tcx, ty_of_fn_decl(fcx, fcx, proto, decl));
#debug("check_expr_fn_with_unifier %s fty=%s",
expr_to_str(expr), fcx.ty_to_str(fty));
fcx.write_ty(expr.id, fty);
// Unify the type of the function with the expected type before we
// typecheck the body so that we have more information about the
// argument types in the body. This is needed to make binops and
// record projection work on type inferred arguments.
unifier();
let ret_ty = ty::ty_fn_ret(fty);
let arg_tys = vec::map(ty::ty_fn_args(fty)) {|a| a.ty };
check_fn(fcx.ccx, proto, decl, body, expr.id,
ret_ty, arg_tys, is_loop_body, some(fcx),
fcx.self_ty);
}
fn check_expr_with_unifier(fcx: @fn_ctxt,
expr: @ast::expr,
expected: option<ty::t>,
@@ -3239,11 +3227,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
}
}
}
// Resolves `expected` by a single level if it is a variable and passes it
// through the `unpack` function. It there is no expected type or
// resolution is not possible (e.g., no constraints yet present), just
// returns `none`.
fn unpack_expected<O: copy>(fcx: @fn_ctxt, expected: option<ty::t>,
unpack: fn(ty::sty) -> option<O>)
-> option<O> {
@@ -3258,42 +3241,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
}
}
fn check_expr_fn(fcx: @fn_ctxt,
expr: @ast::expr,
proto: ast::proto,
decl: ast::fn_decl,
body: ast::blk,
is_loop_body: bool,
expected: option<ty::t>) {
let tcx = fcx.ccx.tcx;
let expected_tys = unpack_expected(fcx, expected) { |sty|
alt sty {
ty::ty_fn(fn_ty) {some({inputs:fn_ty.inputs,
output:fn_ty.output})}
_ {none}
}
};
// construct the function type
let fty = ty::mk_fn(tcx,
ty_of_fn_decl(fcx, fcx, proto, decl,
expected_tys));
#debug("check_expr_fn_with_unifier %s fty=%s",
expr_to_str(expr), fcx.ty_to_str(fty));
fcx.write_ty(expr.id, fty);
let ret_ty = ty::ty_fn_ret(fty);
let arg_tys = vec::map(ty::ty_fn_args(fty)) {|a| a.ty };
check_fn(fcx.ccx, proto, decl, body, expr.id,
ret_ty, arg_tys, is_loop_body, some(fcx),
fcx.self_ty);
}
let tcx = fcx.ccx.tcx;
let id = expr.id;
let mut bot = false;
@@ -3564,7 +3511,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
fcx.write_ty(id, result_ty);
}
ast::expr_fn(proto, decl, body, captures) {
check_expr_fn(fcx, expr, proto, decl, body, false, expected);
check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
false, unifier);
capture::check_capture_clause(tcx, expr.id, proto, *captures);
}
ast::expr_fn_block(decl, body) {
@@ -3572,15 +3520,10 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
let proto = unpack_expected(fcx, expected, {|sty|
alt sty { ty::ty_fn({proto, _}) { some(proto) } _ { none } }
}).get_default(ast::proto_box);
check_expr_fn(fcx, expr, proto, decl, body, false, expected);
check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
false, unifier);
}
ast::expr_loop_body(b) {
// a loop body is the special argument to a `for` loop. We know that
// there will be an expected type in this context because it can only
// appear in the context of a call, so we get the expected type of the
// parameter. The catch here is that we need to validate two things:
// 1. a closure that returns a bool is expected
// 2. the cloure that was given returns unit
let expected_sty = unpack_expected(fcx, expected, {|x|some(x)}).get();
let (inner_ty, proto) = alt expected_sty {
ty::ty_fn(fty) {
@@ -3602,8 +3545,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
};
alt check b.node {
ast::expr_fn_block(decl, body) {
check_expr_fn(fcx, b, proto, decl, body, true, some(inner_ty));
demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
check_expr_fn_with_unifier(fcx, b, proto, decl, body, true) {||
demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
}
}
}
let block_ty = structurally_resolved_type(

View File

@@ -130,9 +130,18 @@ fn ty_to_str(cx: ctxt, typ: t) -> str {
}
// if there is an id, print that instead of the structural type:
for ty::type_def_id(typ).each { |def_id|
// note that this typedef cannot have type parameters
ret ast_map::path_to_str(ty::item_path(cx, def_id));
alt ty::type_def_id(typ) {
some(def_id) {
let cs = ast_map::path_to_str(ty::item_path(cx, def_id));
ret alt ty::get(typ).struct {
ty_enum(_, substs) | ty_res(_, _, substs) | ty_class(_, substs) |
ty_iface(_, substs) {
parameterized(cx, cs, substs.self_r, substs.tps)
}
_ { cs }
};
}
none { /* fallthrough */}
}
// pretty print the structural type representation: