diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2012-05-03 14:42:34 -0700 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2012-05-03 14:42:34 -0700 |
| commit | cfa09d35a355dee59008306f98330ff0472eb09d (patch) | |
| tree | e9b157de0a53e056ebd63db17557e4af1ac17ef1 /src/rustc | |
| parent | 1ba4ca4c4a0153578e812baf5f7f5554d079de40 (diff) | |
Revert "allow fn exprs to omit arg types"
This reverts commit 1ba4ca4c4a0153578e812baf5f7f5554d079de40.
Diffstat (limited to 'src/rustc')
| -rw-r--r-- | src/rustc/middle/typeck.rs | 174 | ||||
| -rw-r--r-- | src/rustc/util/ppaux.rs | 15 |
2 files changed, 71 insertions, 118 deletions
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 5ca8ac04342..d8db45d8919 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -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 { - - 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)} - }; + self: AC, rscope: RS, a: ast::arg) -> ty::arg { - 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( diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs index 80af3229bc4..227dc0c8645 100644 --- a/src/rustc/util/ppaux.rs +++ b/src/rustc/util/ppaux.rs @@ -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: |
