1
Fork 0

allow fn exprs to omit arg types

also, avoid using type variables for fn args with omitted types
unless necessary.  This will be important for bound regions in
fn types.

fixes #2093
This commit is contained in:
Niko Matsakis 2012-05-03 09:09:55 -07:00
parent 6e5c8a7fb8
commit 1ba4ca4c4a
10 changed files with 178 additions and 103 deletions

View file

@ -1096,6 +1096,14 @@ impl extensions<T> for [T] {
#[inline] #[inline]
fn map<U>(f: fn(T) -> U) -> [U] { map(self, f) } fn map<U>(f: fn(T) -> U) -> [U] { map(self, f) }
#[doc = " #[doc = "
Apply a function to the index and value of each element in the vector
and return the results
"]
fn mapi<U>(f: fn(uint, T) -> U) -> [U] {
let mut i = 0u;
self.map { |e| i += 1u; f(i - 1u, e) }
}
#[doc = "
Apply a function to each element of a vector and return a concatenation Apply a function to each element of a vector and return a concatenation
of each result vector of each result vector
"] "]

View file

@ -1206,7 +1206,7 @@ fn parse_capture_clause(p: parser) -> @ast::capture_clause {
fn parse_fn_expr(p: parser, proto: ast::proto) -> @ast::expr { fn parse_fn_expr(p: parser, proto: ast::proto) -> @ast::expr {
let lo = p.last_span.lo; let lo = p.last_span.lo;
let capture_clause = parse_capture_clause(p); let capture_clause = parse_capture_clause(p);
let decl = parse_fn_decl(p, ast::impure_fn); let decl = parse_fn_decl(p, ast::impure_fn, parse_fn_block_arg);
let body = parse_block(p); let body = parse_block(p);
ret mk_expr(p, lo, body.span.hi, ret mk_expr(p, lo, body.span.hi,
ast::expr_fn(proto, decl, body, capture_clause)); ast::expr_fn(proto, decl, body, capture_clause));
@ -1699,11 +1699,12 @@ fn parse_ty_params(p: parser) -> [ast::ty_param] {
} else { [] } } else { [] }
} }
fn parse_fn_decl(p: parser, purity: ast::purity) fn parse_fn_decl(p: parser, purity: ast::purity,
parse_arg_fn: fn(parser) -> ast::arg)
-> ast::fn_decl { -> ast::fn_decl {
let inputs: ast::spanned<[ast::arg]> = let inputs: ast::spanned<[ast::arg]> =
parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA), parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
parse_arg, p); parse_arg_fn, p);
// Use the args list to translate each bound variable // Use the args list to translate each bound variable
// mentioned in a constraint to an arg index. // mentioned in a constraint to an arg index.
// Seems weird to do this in the parser, but I'm not sure how else to. // Seems weird to do this in the parser, but I'm not sure how else to.
@ -1760,7 +1761,7 @@ fn parse_item_fn(p: parser, purity: ast::purity,
attrs: [ast::attribute]) -> @ast::item { attrs: [ast::attribute]) -> @ast::item {
let lo = p.last_span.lo; let lo = p.last_span.lo;
let t = parse_fn_header(p); let t = parse_fn_header(p);
let decl = parse_fn_decl(p, purity); let decl = parse_fn_decl(p, purity, parse_arg);
let (inner_attrs, body) = parse_inner_attrs_and_block(p, true); let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
let attrs = attrs + inner_attrs; let attrs = attrs + inner_attrs;
ret mk_item(p, lo, body.span.hi, t.ident, ret mk_item(p, lo, body.span.hi, t.ident,
@ -1785,7 +1786,7 @@ fn parse_method(p: parser, pr: ast::privacy) -> @ast::method {
let lo = p.span.lo, pur = parse_fn_purity(p); let lo = p.span.lo, pur = parse_fn_purity(p);
let ident = parse_method_name(p); let ident = parse_method_name(p);
let tps = parse_ty_params(p); let tps = parse_ty_params(p);
let decl = parse_fn_decl(p, pur); let decl = parse_fn_decl(p, pur, parse_arg);
let (inner_attrs, body) = parse_inner_attrs_and_block(p, true); let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
let attrs = attrs + inner_attrs; let attrs = attrs + inner_attrs;
@{ident: ident, attrs: attrs, tps: tps, decl: decl, body: body, @{ident: ident, attrs: attrs, tps: tps, decl: decl, body: body,
@ -1969,7 +1970,7 @@ fn parse_class_item(p:parser, class_name_with_tps: @ast::path)
let lo = p.last_span.lo; let lo = p.last_span.lo;
// Can ctors have attrs? // Can ctors have attrs?
// result type is always the type of the class // result type is always the type of the class
let decl_ = parse_fn_decl(p, ast::impure_fn); let decl_ = parse_fn_decl(p, ast::impure_fn, parse_arg);
let decl = {output: @{id: p.get_id(), let decl = {output: @{id: p.get_id(),
node: ast::ty_path(class_name_with_tps, p.get_id()), node: ast::ty_path(class_name_with_tps, p.get_id()),
span: decl_.output.span} span: decl_.output.span}
@ -2048,7 +2049,7 @@ fn parse_item_native_fn(p: parser, attrs: [ast::attribute],
purity: ast::purity) -> @ast::native_item { purity: ast::purity) -> @ast::native_item {
let lo = p.last_span.lo; let lo = p.last_span.lo;
let t = parse_fn_header(p); let t = parse_fn_header(p);
let decl = parse_fn_decl(p, purity); let decl = parse_fn_decl(p, purity, parse_arg);
let mut hi = p.span.hi; let mut hi = p.span.hi;
expect(p, token::SEMI); expect(p, token::SEMI);
ret @{ident: t.ident, ret @{ident: t.ident,

View file

@ -1351,13 +1351,6 @@ fn print_cap_clause(s: ps, cap_clause: ast::capture_clause) {
fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl) { fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl) {
popen(s); popen(s);
fn print_arg(s: ps, x: ast::arg) {
ibox(s, indent_unit);
print_arg_mode(s, x.mode);
word_space(s, x.ident + ":");
print_type(s, x.ty);
end(s);
}
commasep(s, inconsistent, decl.inputs, print_arg); commasep(s, inconsistent, decl.inputs, print_arg);
pclose(s); pclose(s);
word(s.s, constrs_str(decl.constraints, {|c| word(s.s, constrs_str(decl.constraints, {|c|
@ -1374,16 +1367,6 @@ fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl) {
fn print_fn_block_args(s: ps, decl: ast::fn_decl) { fn print_fn_block_args(s: ps, decl: ast::fn_decl) {
word(s.s, "|"); word(s.s, "|");
fn print_arg(s: ps, x: ast::arg) {
ibox(s, indent_unit);
print_arg_mode(s, x.mode);
word(s.s, x.ident);
if x.ty.node != ast::ty_infer {
word_space(s, ":");
print_type(s, x.ty);
}
end(s);
}
commasep(s, inconsistent, decl.inputs, print_arg); commasep(s, inconsistent, decl.inputs, print_arg);
word(s.s, "|"); word(s.s, "|");
if decl.output.node != ast::ty_infer { if decl.output.node != ast::ty_infer {
@ -1541,6 +1524,23 @@ fn print_mt(s: ps, mt: ast::mt) {
print_type(s, mt.ty); print_type(s, mt.ty);
} }
fn print_arg(s: ps, input: ast::arg) {
ibox(s, indent_unit);
print_arg_mode(s, input.mode);
alt input.ty.node {
ast::ty_infer {
word(s.s, input.ident);
}
_ {
if str::len(input.ident) > 0u {
word_space(s, input.ident + ":");
}
print_type(s, input.ty);
}
}
end(s);
}
fn print_ty_fn(s: ps, opt_proto: option<ast::proto>, fn print_ty_fn(s: ps, opt_proto: option<ast::proto>,
decl: ast::fn_decl, id: option<ast::ident>, decl: ast::fn_decl, id: option<ast::ident>,
tps: option<[ast::ty_param]>) { tps: option<[ast::ty_param]>) {
@ -1550,13 +1550,6 @@ fn print_ty_fn(s: ps, opt_proto: option<ast::proto>,
alt tps { some(tps) { print_type_params(s, tps); } _ { } } alt tps { some(tps) { print_type_params(s, tps); } _ { } }
zerobreak(s.s); zerobreak(s.s);
popen(s); popen(s);
fn print_arg(s: ps, input: ast::arg) {
print_arg_mode(s, input.mode);
if str::len(input.ident) > 0u {
word_space(s, input.ident + ":");
}
print_type(s, input.ty);
}
commasep(s, inconsistent, decl.inputs, print_arg); commasep(s, inconsistent, decl.inputs, print_arg);
pclose(s); pclose(s);
maybe_print_comment(s, decl.output.span.lo); maybe_print_comment(s, decl.output.span.lo);

View file

@ -275,7 +275,8 @@ fn instantiate_path(fcx: @fn_ctxt,
fcx.write_ty_substs(id, tpt.ty, substs); fcx.write_ty_substs(id, tpt.ty, substs);
} }
// Type tests // Resolves `typ` by a single level if `typ` is a type variable. If no
// resolution is possible, then an error is reported.
fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t { fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
alt infer::resolve_shallow(fcx.infcx, tp, false) { alt infer::resolve_shallow(fcx.infcx, tp, false) {
result::ok(t_s) if !ty::type_is_var(t_s) { ret t_s; } result::ok(t_s) if !ty::type_is_var(t_s) { ret t_s; }
@ -286,7 +287,6 @@ fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
} }
} }
// Returns the one-level-deep structure of the given type. // Returns the one-level-deep structure of the given type.
fn structure_of(fcx: @fn_ctxt, sp: span, typ: ty::t) -> ty::sty { fn structure_of(fcx: @fn_ctxt, sp: span, typ: ty::t) -> ty::sty {
ty::get(structurally_resolved_type(fcx, sp, typ)).struct 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) ty::mk_rec(tcx, flds)
} }
ast::ty_fn(proto, decl) { ast::ty_fn(proto, decl) {
ty::mk_fn(tcx, ty_of_fn_decl(self, rscope, proto, decl)) ty::mk_fn(tcx, ty_of_fn_decl(self, rscope, proto, decl, none))
} }
ast::ty_path(path, id) { ast::ty_path(path, id) {
let a_def = alt tcx.def_map.find(id) { let a_def = alt tcx.def_map.find(id) {
@ -777,7 +777,13 @@ 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) ty::mk_constr(tcx, ast_ty_to_ty(self, rscope, t), out_cs)
} }
ast::ty_infer { ast::ty_infer {
self.ty_infer(ast_ty.span) // 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");
} }
ast::ty_mac(_) { ast::ty_mac(_) {
tcx.sess.span_bug(ast_ty.span, tcx.sess.span_bug(ast_ty.span,
@ -850,7 +856,8 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
} }
ast::item_fn(decl, tps, _) { ast::item_fn(decl, tps, _) {
let bounds = ty_param_bounds(ccx, tps); let bounds = ty_param_bounds(ccx, tps);
let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare, decl); let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare,
decl, none);
let tpt = {bounds: bounds, let tpt = {bounds: bounds,
rp: ast::rp_none, // functions do not have a self rp: ast::rp_none, // functions do not have a self
ty: ty::mk_fn(ccx.tcx, tofd)}; ty: ty::mk_fn(ccx.tcx, tofd)};
@ -884,7 +891,8 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
} }
ast::item_res(decl, tps, _, _, _, rp) { ast::item_res(decl, tps, _, _, _, rp) {
let {bounds, substs} = mk_substs(ccx, tps, rp); let {bounds, substs} = mk_substs(ccx, tps, rp);
let t_arg = ty_of_arg(ccx, type_rscope(rp), decl.inputs[0]); let t_arg = ty_of_arg(ccx, type_rscope(rp),
decl.inputs[0], none);
let t = ty::mk_res(tcx, local_def(it.id), t_arg.ty, substs); let t = ty::mk_res(tcx, local_def(it.id), t_arg.ty, substs);
let t_res = {bounds: bounds, rp: rp, ty: t}; let t_res = {bounds: bounds, rp: rp, ty: t};
tcx.tcache.insert(local_def(it.id), t_res); tcx.tcache.insert(local_def(it.id), t_res);
@ -1027,16 +1035,27 @@ fn replace_bound_regions(
} }
fn ty_of_arg<AC: ast_conv, RS: region_scope copy>( fn ty_of_arg<AC: ast_conv, RS: region_scope copy>(
self: AC, rscope: RS, a: ast::arg) -> ty::arg { self: AC, rscope: RS, a: ast::arg,
expected_ty: option<ty::arg>) -> ty::arg {
fn arg_mode(tcx: ty::ctxt, m: ast::mode, ty: ty::t) -> ast::mode { let ty = alt a.ty.node {
alt m { 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))
}
ast::infer(_) { ast::infer(_) {
alt ty::get(ty).struct { alt ty::get(ty).struct {
// If the type is not specified, then this must be a fn expr. // If the type is not specified, then this must be a fn expr.
// Leave the mode as infer(_), it will get inferred based // Leave the mode as infer(_), it will get inferred based
// on constraints elsewhere. // on constraints elsewhere.
ty::ty_var(_) { m } ty::ty_var(_) {a.mode}
// If the type is known, then use the default for that type. // If the type is known, then use the default for that type.
// Here we unify m and the default. This should update the // Here we unify m and the default. This should update the
@ -1044,30 +1063,48 @@ fn ty_of_arg<AC: ast_conv, RS: region_scope copy>(
// will have been unified with m yet: // will have been unified with m yet:
_ { _ {
let m1 = ast::expl(ty::default_arg_mode_for_ty(ty)); let m1 = ast::expl(ty::default_arg_mode_for_ty(ty));
result::get(ty::unify_mode(tcx, m, m1)) result::get(ty::unify_mode(self.tcx(), a.mode, m1))
} }
} }
} }
ast::expl(_) { m } ast::expl(_) {a.mode}
} }
} };
let ty = ast_ty_to_ty(self, rscope, a.ty);
let mode = arg_mode(self.tcx(), a.mode, ty);
{mode: mode, ty: 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>( fn ty_of_fn_decl<AC: ast_conv, RS: region_scope copy>(
self: AC, rscope: RS, self: AC, rscope: RS,
proto: ast::proto, proto: ast::proto,
decl: ast::fn_decl) -> ty::fn_ty { decl: ast::fn_decl,
expected_tys: expected_tys) -> ty::fn_ty {
#debug["ty_of_fn_decl"]; #debug["ty_of_fn_decl"];
indent {|| indent {||
// new region names that appear inside of the fn decl are bound to // new region names that appear inside of the fn decl are bound to
// that function type // that function type
let rb = in_binding_rscope(rscope); let rb = in_binding_rscope(rscope);
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 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 out_constrs = vec::map(decl.constraints) {|constr| let out_constrs = vec::map(decl.constraints) {|constr|
ty::ast_constr_to_constr(self.tcx(), constr) ty::ast_constr_to_constr(self.tcx(), constr)
}; };
@ -1083,7 +1120,7 @@ fn ty_of_native_fn_decl(ccx: @crate_ctxt,
let bounds = ty_param_bounds(ccx, ty_params); let bounds = ty_param_bounds(ccx, ty_params);
let rb = in_binding_rscope(empty_rscope); let rb = in_binding_rscope(empty_rscope);
let input_tys = vec::map(decl.inputs) { |a| ty_of_arg(ccx, rb, a) }; let input_tys = decl.inputs.map { |a| ty_of_arg(ccx, rb, a, none) };
let output_ty = ast_ty_to_ty(ccx, rb, decl.output); let output_ty = ast_ty_to_ty(ccx, rb, decl.output);
let t_fn = ty::mk_fn(ccx.tcx, {proto: ast::proto_bare, let t_fn = ty::mk_fn(ccx.tcx, {proto: ast::proto_bare,
@ -1135,7 +1172,8 @@ fn ty_of_method(ccx: @crate_ctxt,
rp: ast::region_param) -> ty::method { rp: ast::region_param) -> ty::method {
{ident: m.ident, {ident: m.ident,
tps: ty_param_bounds(ccx, m.tps), tps: ty_param_bounds(ccx, m.tps),
fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare, m.decl), fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare,
m.decl, none),
purity: m.decl.purity, purity: m.decl.purity,
privacy: m.privacy} privacy: m.privacy}
} }
@ -1145,7 +1183,8 @@ fn ty_of_ty_method(self: @crate_ctxt,
rp: ast::region_param) -> ty::method { rp: ast::region_param) -> ty::method {
{ident: m.ident, {ident: m.ident,
tps: ty_param_bounds(self, m.tps), tps: ty_param_bounds(self, m.tps),
fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare, m.decl), fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare,
m.decl, none),
// assume public, because this is only invoked on iface methods // assume public, because this is only invoked on iface methods
purity: m.decl.purity, privacy: ast::pub} purity: m.decl.purity, privacy: ast::pub}
} }
@ -1649,7 +1688,8 @@ mod collect {
ast::item_res(decl, tps, _, dtor_id, ctor_id, rp) { ast::item_res(decl, tps, _, dtor_id, ctor_id, rp) {
let {bounds, substs} = mk_substs(ccx, tps, rp); let {bounds, substs} = mk_substs(ccx, tps, rp);
let def_id = local_def(it.id); let def_id = local_def(it.id);
let t_arg = ty_of_arg(ccx, type_rscope(rp), decl.inputs[0]); let t_arg = ty_of_arg(ccx, type_rscope(rp),
decl.inputs[0], none);
let t_res = ty::mk_res(tcx, def_id, t_arg.ty, substs); let t_res = ty::mk_res(tcx, def_id, t_arg.ty, substs);
let t_ctor = ty::mk_fn(tcx, { let t_ctor = ty::mk_fn(tcx, {
@ -1691,7 +1731,8 @@ mod collect {
ty_of_fn_decl(ccx, ty_of_fn_decl(ccx,
empty_rscope, empty_rscope,
ast::proto_any, ast::proto_any,
ctor.node.dec)); ctor.node.dec,
none));
write_ty_to_tcx(tcx, ctor.node.id, t_ctor); write_ty_to_tcx(tcx, ctor.node.id, t_ctor);
tcx.tcache.insert(local_def(ctor.node.id), tcx.tcache.insert(local_def(ctor.node.id),
{bounds: tpt.bounds, {bounds: tpt.bounds,
@ -2902,35 +2943,6 @@ 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, fn check_expr_with_unifier(fcx: @fn_ctxt,
expr: @ast::expr, expr: @ast::expr,
expected: option<ty::t>, expected: option<ty::t>,
@ -3227,6 +3239,11 @@ 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>, fn unpack_expected<O: copy>(fcx: @fn_ctxt, expected: option<ty::t>,
unpack: fn(ty::sty) -> option<O>) unpack: fn(ty::sty) -> option<O>)
-> option<O> { -> option<O> {
@ -3241,6 +3258,42 @@ 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 tcx = fcx.ccx.tcx;
let id = expr.id; let id = expr.id;
let mut bot = false; let mut bot = false;
@ -3511,8 +3564,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
fcx.write_ty(id, result_ty); fcx.write_ty(id, result_ty);
} }
ast::expr_fn(proto, decl, body, captures) { ast::expr_fn(proto, decl, body, captures) {
check_expr_fn_with_unifier(fcx, expr, proto, decl, body, check_expr_fn(fcx, expr, proto, decl, body, false, expected);
false, unifier);
capture::check_capture_clause(tcx, expr.id, proto, *captures); capture::check_capture_clause(tcx, expr.id, proto, *captures);
} }
ast::expr_fn_block(decl, body) { ast::expr_fn_block(decl, body) {
@ -3520,10 +3572,15 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
let proto = unpack_expected(fcx, expected, {|sty| let proto = unpack_expected(fcx, expected, {|sty|
alt sty { ty::ty_fn({proto, _}) { some(proto) } _ { none } } alt sty { ty::ty_fn({proto, _}) { some(proto) } _ { none } }
}).get_default(ast::proto_box); }).get_default(ast::proto_box);
check_expr_fn_with_unifier(fcx, expr, proto, decl, body, check_expr_fn(fcx, expr, proto, decl, body, false, expected);
false, unifier);
} }
ast::expr_loop_body(b) { 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 expected_sty = unpack_expected(fcx, expected, {|x|some(x)}).get();
let (inner_ty, proto) = alt expected_sty { let (inner_ty, proto) = alt expected_sty {
ty::ty_fn(fty) { ty::ty_fn(fty) {
@ -3545,9 +3602,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
}; };
alt check b.node { alt check b.node {
ast::expr_fn_block(decl, body) { ast::expr_fn_block(decl, body) {
check_expr_fn_with_unifier(fcx, b, proto, decl, body, true) {|| check_expr_fn(fcx, b, proto, decl, body, true, some(inner_ty));
demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b)); demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
}
} }
} }
let block_ty = structurally_resolved_type( let block_ty = structurally_resolved_type(

View file

@ -130,18 +130,9 @@ fn ty_to_str(cx: ctxt, typ: t) -> str {
} }
// if there is an id, print that instead of the structural type: // if there is an id, print that instead of the structural type:
alt ty::type_def_id(typ) { for ty::type_def_id(typ).each { |def_id|
some(def_id) { // note that this typedef cannot have type parameters
let cs = ast_map::path_to_str(ty::item_path(cx, def_id)); ret 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: // pretty print the structural type representation:

View file

@ -0,0 +1,2 @@
fn foo(x) { //! ERROR expecting ':' but found ')'
}

View file

@ -0,0 +1,9 @@
fn let_in<T>(x: T, f: fn(T)) {}
fn main() {
let_in(3u, fn&(i) { assert i == 3; });
//!^ ERROR expected `uint` but found `int`
let_in(3, fn&(i) { assert i == 3u; });
//!^ ERROR expected `int` but found `uint`
}

View file

@ -0,0 +1,8 @@
type foo = option<int>;
fn bar(_t: foo) {}
fn main() {
// we used to print foo<int>:
bar(some(3u)); //! ERROR mismatched types: expected `foo`
}

View file

@ -4,7 +4,6 @@ fn concat<T: copy>(v: [const [const T]]) -> [T] {
// Earlier versions of our type checker accepted this: // Earlier versions of our type checker accepted this:
vec::iter(v) {|&&inner: [T]| vec::iter(v) {|&&inner: [T]|
//!^ ERROR values differ in mutability //!^ ERROR values differ in mutability
//!^^ ERROR values differ in mutability
r += inner; r += inner;
} }

View file

@ -0,0 +1,8 @@
fn let_in<T>(x: T, f: fn(T)) {}
fn main() {
let_in(3u) { |i| assert i == 3u; };
let_in(3) { |i| assert i == 3; };
let_in(3u, fn&(i) { assert i == 3u; });
let_in(3, fn&(i) { assert i == 3; });
}