Revert "allow fn exprs to omit arg types"
This reverts commit 1ba4ca4c4a
.
This commit is contained in:
parent
1ba4ca4c4a
commit
cfa09d35a3
10 changed files with 103 additions and 178 deletions
|
@ -1096,14 +1096,6 @@ 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
|
||||||
"]
|
"]
|
||||||
|
|
|
@ -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, parse_fn_block_arg);
|
let decl = parse_fn_decl(p, ast::impure_fn);
|
||||||
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,12 +1699,11 @@ 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_fn, p);
|
parse_arg, 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.
|
||||||
|
@ -1761,7 +1760,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, parse_arg);
|
let decl = parse_fn_decl(p, purity);
|
||||||
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,
|
||||||
|
@ -1786,7 +1785,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, parse_arg);
|
let decl = parse_fn_decl(p, pur);
|
||||||
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,
|
||||||
|
@ -1970,7 +1969,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, parse_arg);
|
let decl_ = parse_fn_decl(p, ast::impure_fn);
|
||||||
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}
|
||||||
|
@ -2049,7 +2048,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, parse_arg);
|
let decl = parse_fn_decl(p, purity);
|
||||||
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,
|
||||||
|
|
|
@ -1351,6 +1351,13 @@ 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|
|
||||||
|
@ -1367,6 +1374,16 @@ 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 {
|
||||||
|
@ -1524,23 +1541,6 @@ 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,6 +1550,13 @@ 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);
|
||||||
|
|
|
@ -275,8 +275,7 @@ fn instantiate_path(fcx: @fn_ctxt,
|
||||||
fcx.write_ty_substs(id, tpt.ty, substs);
|
fcx.write_ty_substs(id, tpt.ty, substs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolves `typ` by a single level if `typ` is a type variable. If no
|
// Type tests
|
||||||
// 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; }
|
||||||
|
@ -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.
|
// 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, none))
|
ty::mk_fn(tcx, ty_of_fn_decl(self, rscope, proto, decl))
|
||||||
}
|
}
|
||||||
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,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)
|
ty::mk_constr(tcx, ast_ty_to_ty(self, rscope, t), out_cs)
|
||||||
}
|
}
|
||||||
ast::ty_infer {
|
ast::ty_infer {
|
||||||
// ty_infer should only appear as the type of arguments or return
|
self.ty_infer(ast_ty.span)
|
||||||
// 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,
|
||||||
|
@ -856,8 +850,7 @@ 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,
|
let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare, decl);
|
||||||
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)};
|
||||||
|
@ -891,8 +884,7 @@ 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),
|
let t_arg = ty_of_arg(ccx, type_rscope(rp), decl.inputs[0]);
|
||||||
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);
|
||||||
|
@ -1035,27 +1027,16 @@ 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,
|
self: AC, rscope: RS, a: ast::arg) -> ty::arg {
|
||||||
expected_ty: option<ty::arg>) -> ty::arg {
|
|
||||||
|
|
||||||
let ty = alt a.ty.node {
|
fn arg_mode(tcx: ty::ctxt, m: ast::mode, ty: ty::t) -> ast::mode {
|
||||||
ast::ty_infer if expected_ty.is_some() {expected_ty.get().ty}
|
alt m {
|
||||||
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(_) {a.mode}
|
ty::ty_var(_) { m }
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -1063,48 +1044,30 @@ 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(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}
|
{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,
|
decl: ast::fn_decl) -> ty::fn_ty {
|
||||||
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 input_tys = decl.inputs.mapi { |i, a|
|
let output_ty = ast_ty_to_ty(self, rb, decl.output);
|
||||||
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)
|
||||||
};
|
};
|
||||||
|
@ -1120,7 +1083,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 = 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 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,
|
||||||
|
@ -1172,8 +1135,7 @@ 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,
|
fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare, m.decl),
|
||||||
m.decl, none),
|
|
||||||
purity: m.decl.purity,
|
purity: m.decl.purity,
|
||||||
privacy: m.privacy}
|
privacy: m.privacy}
|
||||||
}
|
}
|
||||||
|
@ -1183,8 +1145,7 @@ 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,
|
fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare, m.decl),
|
||||||
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}
|
||||||
}
|
}
|
||||||
|
@ -1688,8 +1649,7 @@ 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),
|
let t_arg = ty_of_arg(ccx, type_rscope(rp), decl.inputs[0]);
|
||||||
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, {
|
||||||
|
@ -1731,8 +1691,7 @@ 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,
|
||||||
|
@ -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,
|
fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||||
expr: @ast::expr,
|
expr: @ast::expr,
|
||||||
expected: option<ty::t>,
|
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>,
|
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> {
|
||||||
|
@ -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 tcx = fcx.ccx.tcx;
|
||||||
let id = expr.id;
|
let id = expr.id;
|
||||||
let mut bot = false;
|
let mut bot = false;
|
||||||
|
@ -3564,7 +3511,8 @@ 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(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);
|
capture::check_capture_clause(tcx, expr.id, proto, *captures);
|
||||||
}
|
}
|
||||||
ast::expr_fn_block(decl, body) {
|
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|
|
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(fcx, expr, proto, decl, body, false, expected);
|
check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
|
||||||
|
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) {
|
||||||
|
@ -3602,10 +3545,11 @@ 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(fcx, b, proto, decl, body, true, some(inner_ty));
|
check_expr_fn_with_unifier(fcx, b, proto, decl, body, true) {||
|
||||||
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(
|
||||||
fcx, expr.span, fcx.node_ty(b.id));
|
fcx, expr.span, fcx.node_ty(b.id));
|
||||||
alt check ty::get(block_ty).struct {
|
alt check ty::get(block_ty).struct {
|
||||||
|
|
|
@ -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:
|
// if there is an id, print that instead of the structural type:
|
||||||
for ty::type_def_id(typ).each { |def_id|
|
alt ty::type_def_id(typ) {
|
||||||
// note that this typedef cannot have type parameters
|
some(def_id) {
|
||||||
ret ast_map::path_to_str(ty::item_path(cx, 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:
|
// pretty print the structural type representation:
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
fn foo(x) { //! ERROR expecting ':' but found ')'
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
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`
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
type foo = option<int>;
|
|
||||||
|
|
||||||
fn bar(_t: foo) {}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// we used to print foo<int>:
|
|
||||||
bar(some(3u)); //! ERROR mismatched types: expected `foo`
|
|
||||||
}
|
|
|
@ -4,6 +4,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
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; });
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue