From 2e4f7a2efd359c8c369f1b71d848d0a372379ace Mon Sep 17 00:00:00 2001 From: Paul Stansifer Date: Thu, 2 Jun 2011 18:58:23 -0700 Subject: [PATCH 01/64] Make the macro system more modular. --- src/comp/front/extenv.rs | 4 +- src/comp/front/extfmt.rs | 35 +-------- src/comp/front/parser.rs | 95 ++++++++++++++---------- src/test/compile-fail/ext-nonexistent.rs | 5 ++ 4 files changed, 64 insertions(+), 75 deletions(-) create mode 100644 src/test/compile-fail/ext-nonexistent.rs diff --git a/src/comp/front/extenv.rs b/src/comp/front/extenv.rs index 858f9f9f5689a..ecceabd9c07d8 100644 --- a/src/comp/front/extenv.rs +++ b/src/comp/front/extenv.rs @@ -14,9 +14,9 @@ import std::generic_os; export expand_syntax_ext; // FIXME: Need to thread parser through here to handle errors correctly -fn expand_syntax_ext(parser::parser p, +fn expand_syntax_ext(&parser::parser p, common::span sp, - vec[@ast::expr] args, + &vec[@ast::expr] args, option::t[str] body) -> @ast::expr { if (vec::len[@ast::expr](args) != 1u) { diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index f6ad1d04a39de..672de538510fa 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -13,41 +13,12 @@ import std::option; import std::option::none; import std::option::some; -import std::extfmt::ct::signedness; -import std::extfmt::ct::signed; -import std::extfmt::ct::unsigned; -import std::extfmt::ct::caseness; -import std::extfmt::ct::case_upper; -import std::extfmt::ct::case_lower; -import std::extfmt::ct::ty; -import std::extfmt::ct::ty_bool; -import std::extfmt::ct::ty_str; -import std::extfmt::ct::ty_char; -import std::extfmt::ct::ty_int; -import std::extfmt::ct::ty_bits; -import std::extfmt::ct::ty_hex; -import std::extfmt::ct::ty_octal; -import std::extfmt::ct::flag; -import std::extfmt::ct::flag_left_justify; -import std::extfmt::ct::flag_left_zero_pad; -import std::extfmt::ct::flag_space_for_sign; -import std::extfmt::ct::flag_sign_always; -import std::extfmt::ct::flag_alternate; -import std::extfmt::ct::count; -import std::extfmt::ct::count_is; -import std::extfmt::ct::count_is_param; -import std::extfmt::ct::count_is_next_param; -import std::extfmt::ct::count_implied; -import std::extfmt::ct::conv; -import std::extfmt::ct::piece; -import std::extfmt::ct::piece_string; -import std::extfmt::ct::piece_conv; -import std::extfmt::ct::parse_fmt_string; +import std::extfmt::ct::*; export expand_syntax_ext; -fn expand_syntax_ext(parser p, - vec[@ast::expr] args, +fn expand_syntax_ext(&parser p, common::span sp, + &vec[@ast::expr] args, option::t[str] body) -> @ast::expr { if (vec::len[@ast::expr](args) == 0u) { diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 688bfb01e1920..cb6ee0623d4fa 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -27,32 +27,41 @@ tag file_type { type ty_or_bang = util::common::ty_or_bang[@ast::ty]; +// Temporary: to introduce a tag in order to make a recursive type work +tag xmacro { + x(macro); +} + state type parser = state obj { - fn peek() -> token::token; - fn bump(); - fn err(str s) -> !; - fn restrict(restriction r); - fn get_restriction() -> restriction; - fn get_file_type() -> file_type; - fn get_env() -> eval::env; - fn get_session() -> session::session; - fn get_span() -> common::span; - fn get_lo_pos() -> uint; - fn get_hi_pos() -> uint; - fn get_last_lo_pos() -> uint; - fn next_def_id() -> ast::def_id; - fn set_def(ast::def_num); - fn get_prec_table() -> vec[op_spec]; - fn get_str(token::str_num) -> str; - fn get_reader() -> lexer::reader; - fn get_filemap() -> codemap::filemap; - fn get_bad_expr_words() -> std::map::hashmap[str, ()]; - fn get_chpos() -> uint; - fn get_ann() -> ast::ann; - fn next_ann_num() -> uint; + fn peek() -> token::token; + fn bump(); + fn err(str s) -> !; + fn restrict(restriction r); + fn get_restriction() -> restriction; + fn get_file_type() -> file_type; + fn get_env() -> eval::env; + fn get_session() -> session::session; + fn get_span() -> common::span; + fn get_lo_pos() -> uint; + fn get_hi_pos() -> uint; + fn get_last_lo_pos() -> uint; + fn next_def_id() -> ast::def_id; + fn set_def(ast::def_num); + fn get_prec_table() -> vec[op_spec]; + fn get_str(token::str_num) -> str; + fn get_reader() -> lexer::reader; + fn get_filemap() -> codemap::filemap; + fn get_bad_expr_words() -> std::map::hashmap[str, ()]; + fn get_macros() -> std::map::hashmap[str, xmacro]; + fn get_chpos() -> uint; + fn get_ann() -> ast::ann; + fn next_ann_num() -> uint; }; +type macro = fn(&parser, common::span, &vec[@ast::expr], option::t[str]) + -> @ast::expr; + fn new_parser(session::session sess, eval::env env, ast::def_id initial_def, @@ -70,7 +79,8 @@ fn new_parser(session::session sess, lexer::reader rdr, vec[op_spec] precs, mutable uint next_ann_var, - std::map::hashmap[str, ()] bad_words) + std::map::hashmap[str, ()] bad_words, + std::map::hashmap[str, xmacro] macros) { fn peek() -> token::token { ret tok; @@ -143,6 +153,10 @@ fn new_parser(session::session sess, ret bad_words; } + fn get_macros() -> std::map::hashmap[str, xmacro] { + ret macros; + } + fn get_chpos() -> uint {ret rdr.get_chpos();} fn get_ann() -> ast::ann { @@ -169,7 +183,7 @@ fn new_parser(session::session sess, ret stdio_parser(sess, env, ftype, lexer::next_token(rdr), npos, npos, npos, initial_def._1, UNRESTRICTED, initial_def._0, rdr, prec_table(), next_ann, - bad_expr_word_table()); + bad_expr_word_table(), macro_table()); } // These are the words that shouldn't be allowed as value identifiers, @@ -213,6 +227,13 @@ fn bad_expr_word_table() -> std::map::hashmap[str, ()] { ret words; } +fn macro_table() -> std::map::hashmap[str, xmacro] { + auto macros = new_str_hash[xmacro](); + macros.insert("fmt", x(extfmt::expand_syntax_ext)); + macros.insert("env", x(extenv::expand_syntax_ext)); + ret macros; +} + fn unexpected(&parser p, token::token t) -> ! { let str s = "unexpected token: "; s += token::to_str(p.get_reader(), t); @@ -1032,23 +1053,15 @@ fn expand_syntax_ext(&parser p, common::span sp, assert (vec::len[ast::ident](path.node.idents) > 0u); auto extname = path.node.idents.(0); - if (str::eq(extname, "fmt")) { - auto expanded = extfmt::expand_syntax_ext(p, args, body); - auto newexpr = ast::expr_ext(path, args, body, - expanded, - p.get_ann()); - - ret newexpr; - } else if (str::eq(extname, "env")) { - auto expanded = extenv::expand_syntax_ext(p, sp, args, body); - auto newexpr = ast::expr_ext(path, args, body, - expanded, - p.get_ann()); - - ret newexpr; - } else { - p.err("unknown syntax extension"); - fail; + + alt (p.get_macros().find(extname)) { + case (none[xmacro]) { + p.err("unknown macro: '" + extname + "'"); + } + case (some[xmacro](x(?ext))) { + ret ast::expr_ext(path, args, body, ext(p, sp, args, body), + p.get_ann()); + } } } diff --git a/src/test/compile-fail/ext-nonexistent.rs b/src/test/compile-fail/ext-nonexistent.rs new file mode 100644 index 0000000000000..df913ece3801d --- /dev/null +++ b/src/test/compile-fail/ext-nonexistent.rs @@ -0,0 +1,5 @@ + +// error-pattern:unknown macro +fn main() { + #iamnotanextensionthatexists(""); +} \ No newline at end of file From 72e11fdc069b0c1a653303209285a0036268911f Mon Sep 17 00:00:00 2001 From: Paul Stansifer Date: Fri, 3 Jun 2011 17:47:38 -0700 Subject: [PATCH 02/64] "macro" -> "syntax extension" for now --- src/comp/front/parser.rs | 44 ++++++++++++------------ src/test/compile-fail/ext-nonexistent.rs | 2 +- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index cb6ee0623d4fa..49da8108c8666 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -28,8 +28,8 @@ tag file_type { type ty_or_bang = util::common::ty_or_bang[@ast::ty]; // Temporary: to introduce a tag in order to make a recursive type work -tag xmacro { - x(macro); +tag syntax_extension { + x(syntax_expander); } state type parser = @@ -52,15 +52,15 @@ state type parser = fn get_str(token::str_num) -> str; fn get_reader() -> lexer::reader; fn get_filemap() -> codemap::filemap; - fn get_bad_expr_words() -> std::map::hashmap[str, ()]; - fn get_macros() -> std::map::hashmap[str, xmacro]; + fn get_bad_expr_words() -> hashmap[str, ()]; + fn get_syntax_expanders() -> hashmap[str, syntax_extension]; fn get_chpos() -> uint; fn get_ann() -> ast::ann; fn next_ann_num() -> uint; }; -type macro = fn(&parser, common::span, &vec[@ast::expr], option::t[str]) - -> @ast::expr; +type syntax_expander = fn(&parser, common::span, &vec[@ast::expr], + option::t[str]) -> @ast::expr; fn new_parser(session::session sess, eval::env env, @@ -79,8 +79,8 @@ fn new_parser(session::session sess, lexer::reader rdr, vec[op_spec] precs, mutable uint next_ann_var, - std::map::hashmap[str, ()] bad_words, - std::map::hashmap[str, xmacro] macros) + hashmap[str, ()] bad_words, + hashmap[str, syntax_extension] syntax_expanders) { fn peek() -> token::token { ret tok; @@ -149,12 +149,12 @@ fn new_parser(session::session sess, ret rdr.get_filemap(); } - fn get_bad_expr_words() -> std::map::hashmap[str, ()] { + fn get_bad_expr_words() -> hashmap[str, ()] { ret bad_words; } - fn get_macros() -> std::map::hashmap[str, xmacro] { - ret macros; + fn get_syntax_expanders() -> hashmap[str, syntax_extension] { + ret syntax_expanders; } fn get_chpos() -> uint {ret rdr.get_chpos();} @@ -183,13 +183,13 @@ fn new_parser(session::session sess, ret stdio_parser(sess, env, ftype, lexer::next_token(rdr), npos, npos, npos, initial_def._1, UNRESTRICTED, initial_def._0, rdr, prec_table(), next_ann, - bad_expr_word_table(), macro_table()); + bad_expr_word_table(), syntax_expander_table()); } // These are the words that shouldn't be allowed as value identifiers, // because, if used at the start of a line, they will cause the line to be // interpreted as a specific kind of statement, which would be confusing. -fn bad_expr_word_table() -> std::map::hashmap[str, ()] { +fn bad_expr_word_table() -> hashmap[str, ()] { auto words = new_str_hash[()](); words.insert("mod", ()); words.insert("if", ()); @@ -227,11 +227,11 @@ fn bad_expr_word_table() -> std::map::hashmap[str, ()] { ret words; } -fn macro_table() -> std::map::hashmap[str, xmacro] { - auto macros = new_str_hash[xmacro](); - macros.insert("fmt", x(extfmt::expand_syntax_ext)); - macros.insert("env", x(extenv::expand_syntax_ext)); - ret macros; +fn syntax_expander_table() -> hashmap[str, syntax_extension] { + auto syntax_expanders = new_str_hash[syntax_extension](); + syntax_expanders.insert("fmt", x(extfmt::expand_syntax_ext)); + syntax_expanders.insert("env", x(extenv::expand_syntax_ext)); + ret syntax_expanders; } fn unexpected(&parser p, token::token t) -> ! { @@ -1054,11 +1054,11 @@ fn expand_syntax_ext(&parser p, common::span sp, assert (vec::len[ast::ident](path.node.idents) > 0u); auto extname = path.node.idents.(0); - alt (p.get_macros().find(extname)) { - case (none[xmacro]) { - p.err("unknown macro: '" + extname + "'"); + alt (p.get_syntax_expanders().find(extname)) { + case (none[syntax_extension]) { + p.err("unknown syntax expander: '" + extname + "'"); } - case (some[xmacro](x(?ext))) { + case (some[syntax_extension](x(?ext))) { ret ast::expr_ext(path, args, body, ext(p, sp, args, body), p.get_ann()); } diff --git a/src/test/compile-fail/ext-nonexistent.rs b/src/test/compile-fail/ext-nonexistent.rs index df913ece3801d..e068bb3c4a4d6 100644 --- a/src/test/compile-fail/ext-nonexistent.rs +++ b/src/test/compile-fail/ext-nonexistent.rs @@ -1,5 +1,5 @@ -// error-pattern:unknown macro +// error-pattern:unknown syntax expander fn main() { #iamnotanextensionthatexists(""); } \ No newline at end of file From 9a65c167f8c1a20c527d31086df23418b6e4464f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 2 Jun 2011 18:07:30 -0700 Subject: [PATCH 03/64] rustc: Typecheck patterns from the top down; remove pushdown_pat --- src/comp/middle/typeck.rs | 228 ++++++++++++-------------------------- 1 file changed, 72 insertions(+), 156 deletions(-) diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index d3786d8aad44f..8d8f0151df247 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1098,97 +1098,6 @@ fn variant_arg_types(&@crate_ctxt ccx, &span sp, &ast::def_id vid, // directly inside check_expr(). This results in a quadratic algorithm. mod pushdown { - // Push-down over typed patterns. Note that the pattern that you pass to - // this function must have been passed to check_pat() first. - // - // TODO: enforce this via a predicate. - - fn pushdown_pat(&@stmt_ctxt scx, &ty::t expected, &@ast::pat pat) { - alt (pat.node) { - case (ast::pat_wild(?ann)) { - auto t = demand::simple(scx, pat.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::pat_lit(?lit, ?ann)) { - auto t = demand::simple(scx, pat.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::pat_bind(?id, ?did, ?ann)) { - auto t = demand::simple(scx, pat.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); - scx.fcx.locals.insert(did, t); - write::ty_only_fixup(scx, ann.id, t); - } - case (ast::pat_tag(?id, ?subpats, ?ann)) { - // Take the variant's type parameters out of the expected - // type. - auto tag_tps; - alt (struct(scx.fcx.ccx.tcx, expected)) { - case (ty::ty_tag(_, ?tps)) { tag_tps = tps; } - case (_) { - scx.fcx.ccx.tcx.sess.span_err(pat.span, - "Non-constructor used in a pattern"); - } - } - - // Get the types of the arguments of the variant. - - let vec[ty::t] tparams = []; - auto j = 0u; - auto actual_ty_params = - ty::ann_to_type_params(scx.fcx.ccx.tcx.node_types, ann); - - for (ty::t some_ty in tag_tps) { - let ty::t t1 = some_ty; - let ty::t t2 = actual_ty_params.(j); - - let ty::t res = demand::simple(scx, pat.span, t1, t2); - - vec::push(tparams, res); - j += 1u; - } - - auto arg_tys; - alt (scx.fcx.ccx.tcx.def_map.get(ann.id)) { - case (ast::def_variant(_, ?vdefid)) { - arg_tys = variant_arg_types(scx.fcx.ccx, pat.span, - vdefid, tparams); - } - } - - auto i = 0u; - for (@ast::pat subpat in subpats) { - pushdown_pat(scx, arg_tys.(i), subpat); - i += 1u; - } - - auto tps = - ty::ann_to_type_params(scx.fcx.ccx.tcx.node_types, ann); - auto tt = ann_to_type(scx.fcx.ccx.tcx.node_types, ann); - - let ty_param_substs_and_ty res_t = demand::full(scx, pat.span, - expected, tt, tps, NO_AUTODEREF); - - auto ty_params_subst = ty::ann_to_ty_param_substs_opt_and_ty - (scx.fcx.ccx.tcx.node_types, ann); - - auto ty_params_opt; - alt (ty_params_subst._0) { - case (none) { - ty_params_opt = none[vec[ty::t]]; - } - case (some(?tps)) { - ty_params_opt = some[vec[ty::t]](tag_tps); - } - } - - write::ty_fixup(scx, ann.id, tup(ty_params_opt, tt)); - } - } - } - // Push-down over typed expressions. Note that the expression that you // pass to this function must have been passed to check_expr() first. // @@ -1673,75 +1582,88 @@ fn check_lit(@crate_ctxt ccx, &@ast::lit lit) -> ty::t { fail; // not reached } -fn check_pat(&@stmt_ctxt scx, &@ast::pat pat) { +// Pattern checking is top-down rather than bottom-up so that bindings get +// their types immediately. +fn check_pat(&@stmt_ctxt scx, &@ast::pat pat, ty::t expected) { alt (pat.node) { case (ast::pat_wild(?ann)) { - auto typ = next_ty_var(scx); - write::ty_only_fixup(scx, ann.id, typ); + write::ty_only_fixup(scx, ann.id, expected); } case (ast::pat_lit(?lt, ?ann)) { auto typ = check_lit(scx.fcx.ccx, lt); + typ = demand::simple(scx, pat.span, expected, typ); write::ty_only_fixup(scx, ann.id, typ); } - case (ast::pat_bind(?id, ?def_id, ?a)) { - auto typ = next_ty_var(scx); - write::ty_only_fixup(scx, a.id, typ); + case (ast::pat_bind(?id, ?def_id, ?ann)) { + scx.fcx.locals.insert(def_id, expected); + write::ty_only_fixup(scx, ann.id, expected); } - case (ast::pat_tag(?p, ?subpats, ?old_ann)) { - auto vdef = ast::variant_def_ids - (scx.fcx.ccx.tcx.def_map.get(old_ann.id)); - auto t = ty::lookup_item_type(scx.fcx.ccx.tcx, - vdef._1)._1; - auto len = vec::len[ast::ident](p.node.idents); - auto last_id = p.node.idents.(len - 1u); - - auto tpt = ty::lookup_item_type(scx.fcx.ccx.tcx, - vdef._0); - - auto path_tpot = instantiate_path(scx, p, tpt, pat.span); - - alt (struct(scx.fcx.ccx.tcx, t)) { - // N-ary variants have function types. - case (ty::ty_fn(_, ?args, ?tag_ty, _)) { - auto arg_len = vec::len[arg](args); - auto subpats_len = vec::len[@ast::pat](subpats); - if (arg_len != subpats_len) { - // TODO: pluralize properly - auto err_msg = "tag type " + last_id + " has " + - uint::to_str(arg_len, 10u) + - " field(s), but this pattern has " + - uint::to_str(subpats_len, 10u) + - " field(s)"; - - scx.fcx.ccx.tcx.sess.span_err(pat.span, err_msg); - fail; // TODO: recover - } - - for (@ast::pat subpat in subpats) { - check_pat(scx, subpat); - } + case (ast::pat_tag(?path, ?subpats, ?ann)) { + // Typecheck the path. + auto v_def = scx.fcx.ccx.tcx.def_map.get(ann.id); + auto v_def_ids = ast::variant_def_ids(v_def); - write::ty_fixup(scx, old_ann.id, path_tpot); - } - - // Nullary variants have tag types. - case (ty::ty_tag(?tid, _)) { - auto subpats_len = vec::len[@ast::pat](subpats); - if (subpats_len > 0u) { - // TODO: pluralize properly - auto err_msg = "tag type " + last_id + - " has no field(s)," + - " but this pattern has " + - uint::to_str(subpats_len, 10u) + - " field(s)"; - - scx.fcx.ccx.tcx.sess.span_err(pat.span, err_msg); - fail; // TODO: recover - } + auto tag_tpt = ty::lookup_item_type(scx.fcx.ccx.tcx, + v_def_ids._0); + auto path_tpot = instantiate_path(scx, path, tag_tpt, pat.span); - write::ty_fixup(scx, old_ann.id, path_tpot); + // Take the tag type params out of `expected`. + auto expected_tps; + alt (struct(scx.fcx.ccx.tcx, expected)) { + case (ty::ty_tag(_, ?tps)) { expected_tps = tps; } + case (_) { + // FIXME: Switch expected and actual in this message? I + // can never tell. + scx.fcx.ccx.tcx.sess.span_err(pat.span, + #fmt("mismatched types: expected tag but found %s", + ty::ty_to_str(scx.fcx.ccx.tcx, expected))); + } + } + + // Unify with the expected tag type. + auto path_tpt = demand::full(scx, pat.span, expected, + path_tpot._1, expected_tps, + NO_AUTODEREF); + path_tpot = tup(some[vec[ty::t]](path_tpt._0), path_tpt._1); + + // Get the number of arguments in this tag variant. + auto arg_types = variant_arg_types(scx.fcx.ccx, pat.span, + v_def_ids._1, expected_tps); + + auto subpats_len = vec::len[@ast::pat](subpats); + + if (vec::len[ty::t](arg_types) > 0u) { + // N-ary variant. + auto arg_len = vec::len[ty::t](arg_types); + if (arg_len != subpats_len) { + // TODO: note definition of tag variant + // TODO (issue #448): Wrap a #fmt string over multiple + // lines... + scx.fcx.ccx.tcx.sess.span_err(pat.span, #fmt( + "this pattern has %u field%s, but the corresponding variant has %u field%s", + subpats_len, + if (subpats_len == 0u) { "" } else { "s" }, + arg_len, + if (arg_len == 0u) { "" } else { "s" })); + } + + // TODO: vec::iter2 + auto i = 0u; + for (@ast::pat subpat in subpats) { + check_pat(scx, subpat, arg_types.(i)); + i += 1u; } + } else if (subpats_len > 0u) { + // TODO: note definition of tag variant + // TODO (issue #448): Wrap a #fmt string over multiple + // lines... + scx.fcx.ccx.tcx.sess.span_err(pat.span, #fmt( +"this pattern has %u field%s, but the corresponding variant has no fields", + subpats_len, + if (subpats_len == 0u) { "" } else { "s" })); } + + write::ty_fixup(scx, ann.id, path_tpot); } } } @@ -2247,20 +2169,14 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { // Typecheck the patterns first, so that we get types for all the // bindings. - auto pattern_ty = expr_ty(scx.fcx.ccx.tcx, expr); + auto pattern_ty = ty::expr_ty(scx.fcx.ccx.tcx, expr); let vec[@ast::pat] pats = []; for (ast::arm arm in arms) { - check_pat(scx, arm.pat); - pattern_ty = demand::simple(scx, arm.pat.span, pattern_ty, - pat_ty(scx.fcx.ccx.tcx, arm.pat)); + check_pat(scx, arm.pat, pattern_ty); pats += [arm.pat]; } - for (@ast::pat pat in pats) { - pushdown::pushdown_pat(scx, pattern_ty, pat); - } - // Now typecheck the blocks. auto result_ty = next_ty_var(scx); From c974cc3b9edece4b63b6949f645af33c7f47b5ae Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Thu, 2 Jun 2011 18:10:18 -0700 Subject: [PATCH 04/64] Removing redundant "fail"s. --- src/comp/middle/ty.rs | 25 ++++++++----------------- src/comp/middle/typeck.rs | 2 -- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 5f0c9a90362ab..e7c5001f824e9 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -423,7 +423,6 @@ fn mk_mach(&ctxt cx, &util::common::ty_mach tm) -> t { case (ty_f32) { ret idx_f32; } case (ty_f64) { ret idx_f64; } } - fail; } fn mk_char(&ctxt cx) -> t { ret idx_char; } @@ -895,7 +894,6 @@ fn type_is_structural(&ctxt cx, &t ty) -> bool { case (ty_obj(_)) { ret true; } case (_) { ret false; } } - fail; } fn type_is_sequence(&ctxt cx, &t ty) -> bool { @@ -904,14 +902,17 @@ fn type_is_sequence(&ctxt cx, &t ty) -> bool { case (ty_vec(_)) { ret true; } case (_) { ret false; } } - fail; } fn sequence_element_type(&ctxt cx, &t ty) -> t { alt (struct(cx, ty)) { case (ty_str) { ret mk_mach(cx, common::ty_u8); } case (ty_vec(?mt)) { ret mt.ty; } + // NB: This is not exhaustive. } + + // FIXME: add sess.err or sess.span_err explaining failure (issue + // #444) fail; } @@ -923,7 +924,6 @@ fn type_is_tup_like(&ctxt cx, &t ty) -> bool { case (ty_tag(_,_)) { ret true; } case (_) { ret false; } } - fail; } fn get_element_type(&ctxt cx, &t ty, uint i) -> t { @@ -935,7 +935,11 @@ fn get_element_type(&ctxt cx, &t ty, uint i) -> t { case (ty_rec(?flds)) { ret flds.(i).mt.ty; } + // NB: This is not exhaustive -- struct(cx, ty) could be a box or a + // tag. } + + // FIXME: add sess.err or sess.span_err explaining failure (issue #444) fail; } @@ -944,7 +948,6 @@ fn type_is_box(&ctxt cx, &t ty) -> bool { case (ty_box(_)) { ret true; } case (_) { ret false; } } - fail; } fn type_is_boxed(&ctxt cx, &t ty) -> bool { @@ -957,7 +960,6 @@ fn type_is_boxed(&ctxt cx, &t ty) -> bool { case (ty_task) { ret true; } case (_) { ret false; } } - fail; } fn type_is_scalar(&ctxt cx, &t ty) -> bool { @@ -973,10 +975,8 @@ fn type_is_scalar(&ctxt cx, &t ty) -> bool { case (ty_native) { ret true; } case (_) { ret false; } } - fail; } - fn type_has_pointers(&ctxt cx, &t ty) -> bool { alt (struct(cx, ty)) { // scalar types @@ -1017,7 +1017,6 @@ fn type_has_pointers(&ctxt cx, &t ty) -> bool { } case (_) { ret true; } } - fail; } @@ -1028,7 +1027,6 @@ fn type_is_native(&ctxt cx, &t ty) -> bool { case (ty_native) { ret true; } case (_) { ret false; } } - fail; } fn type_has_dynamic_size(&ctxt cx, &t ty) -> bool { @@ -1083,7 +1081,6 @@ fn type_is_integral(&ctxt cx, &t ty) -> bool { case (ty_char) { ret true; } case (_) { ret false; } } - fail; } fn type_is_fp(&ctxt cx, &t ty) -> bool { @@ -1100,7 +1097,6 @@ fn type_is_fp(&ctxt cx, &t ty) -> bool { } case (_) { ret false; } } - fail; } fn type_is_signed(&ctxt cx, &t ty) -> bool { @@ -1117,7 +1113,6 @@ fn type_is_signed(&ctxt cx, &t ty) -> bool { } case (_) { ret false; } } - fail; } fn type_param(&ctxt cx, &t ty) -> option::t[uint] { @@ -1656,7 +1651,6 @@ fn is_fn_ty(&ctxt cx, &t fty) -> bool { case (ty::ty_native_fn(_, _, _)) { ret true; } case (_) { ret false; } } - ret false; } @@ -2642,9 +2636,6 @@ mod unify { ret cx.handler.record_param(expected_id, actual); } } - - // TODO: remove me once match-exhaustiveness checking works - fail; } // Performs type binding substitution. diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 8d8f0151df247..551184b037dda 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1578,8 +1578,6 @@ fn check_lit(@crate_ctxt ccx, &@ast::lit lit) -> ty::t { case (ast::lit_nil) { ret ty::mk_nil(ccx.tcx); } case (ast::lit_bool(_)) { ret ty::mk_bool(ccx.tcx); } } - - fail; // not reached } // Pattern checking is top-down rather than bottom-up so that bindings get From c94c9e8b6bd4aed5bb5bf64ce3a17bed8071402a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 3 Jun 2011 10:23:13 +0200 Subject: [PATCH 05/64] Temporarily xfail compile-fail/pattern-tyvar So that the tinderboxes can go green again. Patrick, please look into this at some point. --- src/test/compile-fail/pattern-tyvar.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/compile-fail/pattern-tyvar.rs b/src/test/compile-fail/pattern-tyvar.rs index cb94ee5c173e6..70da34713c7f5 100644 --- a/src/test/compile-fail/pattern-tyvar.rs +++ b/src/test/compile-fail/pattern-tyvar.rs @@ -1,3 +1,6 @@ +// xfail-stage0 +// xfail-stage1 +// xfail-stage2 // -*- rust -*- use std; import std::option; From b3d6ead85966e7360e3b6028d78ec98b46aaf2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20=C3=81vila=20de=20Esp=C3=ADndola?= Date: Fri, 3 Jun 2011 14:34:19 -0400 Subject: [PATCH 06/64] Accept *foo as a pointer to foo. This is accepted everywhere, since just passing a pointer is safe. --- src/comp/front/ast.rs | 1 + src/comp/front/parser.rs | 5 +++++ src/test/run-pass/type-ptr.rs | 6 ++++++ 3 files changed, 12 insertions(+) create mode 100644 src/test/run-pass/type-ptr.rs diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index da94195ab931f..85e525e88233c 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -323,6 +323,7 @@ tag ty_ { ty_str; ty_box(mt); ty_vec(mt); + ty_ptr(mt); ty_task; ty_port(@ty); ty_chan(@ty); diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 49da8108c8666..a3bd41855b4c9 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -532,6 +532,11 @@ fn parse_ty(&parser p) -> @ast::ty { auto mt = parse_mt(p); hi = mt.ty.span.hi; t = ast::ty_box(mt); + } else if (p.peek() == token::BINOP(token::STAR)) { + p.bump(); + auto mt = parse_mt(p); + hi = mt.ty.span.hi; + t = ast::ty_ptr(mt); } else if (eat_word(p, "vec")) { expect(p, token::LBRACKET); t = ast::ty_vec(parse_mt(p)); diff --git a/src/test/run-pass/type-ptr.rs b/src/test/run-pass/type-ptr.rs new file mode 100644 index 0000000000000..8ccbba9218de7 --- /dev/null +++ b/src/test/run-pass/type-ptr.rs @@ -0,0 +1,6 @@ +fn f(*int a) { +} + +fn main(vec[str] args) { + ret; +} From d258852d141a7c1982df9cbc1e04cd7407c402e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20=C3=81vila=20de=20Esp=C3=ADndola?= Date: Fri, 3 Jun 2011 15:02:58 -0400 Subject: [PATCH 07/64] Boilerplate for pointers. Sorry for missing this on the first patch. --- src/comp/middle/metadata.rs | 1 + src/comp/middle/trans.rs | 3 +++ src/comp/middle/ty.rs | 12 ++++++++++++ src/comp/middle/typeck.rs | 3 +++ src/comp/middle/walk.rs | 1 + 5 files changed, 20 insertions(+) diff --git a/src/comp/middle/metadata.rs b/src/comp/middle/metadata.rs index bee1cd17ade1d..e2e60b8007528 100644 --- a/src/comp/middle/metadata.rs +++ b/src/comp/middle/metadata.rs @@ -174,6 +174,7 @@ mod Encode { w.write_char(']'); } case (ty::ty_box(?mt)) {w.write_char('@'); enc_mt(w, cx, mt); } + case (ty::ty_ptr(?mt)) {w.write_char('*'); enc_mt(w, cx, mt); } case (ty::ty_vec(?mt)) {w.write_char('V'); enc_mt(w, cx, mt); } case (ty::ty_port(?t)) {w.write_char('P'); enc_ty(w, cx, t); } case (ty::ty_chan(?t)) {w.write_char('C'); enc_ty(w, cx, t); } diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index acabb05661757..3712ed7475d6a 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -882,6 +882,9 @@ fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef { case (ty::ty_vec(?mt)) { llty = T_ptr(T_vec(type_of_inner(cx, sp, mt.ty))); } + case (ty::ty_ptr(?mt)) { + llty = T_ptr(type_of_inner(cx, sp, mt.ty)); + } case (ty::ty_port(?t)) { llty = T_ptr(T_port(type_of_inner(cx, sp, t))); } diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index e7c5001f824e9..d10cbd338ade5 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -109,6 +109,7 @@ tag sty { ty_tag(ast::def_id, vec[t]); ty_box(mt); ty_vec(mt); + ty_ptr(mt); ty_port(t); ty_chan(t); ty_task; @@ -436,6 +437,10 @@ fn mk_box(&ctxt cx, &mt tm) -> t { ret gen_ty(cx, ty_box(tm)); } +fn mk_ptr(&ctxt cx, &mt tm) -> t { + ret gen_ty(cx, ty_ptr(tm)); +} + fn mk_imm_box(&ctxt cx, &t ty) -> t { ret mk_box(cx, rec(ty=ty, mut=ast::imm)); } @@ -1225,6 +1230,7 @@ fn hash_type_structure(&sty st) -> uint { case (ty_type) { ret 32u; } case (ty_native) { ret 33u; } case (ty_bot) { ret 34u; } + case (ty_ptr(?mt)) { ret hash_subty(35u, mt.ty); } } } @@ -1356,6 +1362,12 @@ fn equal_type_structures(&sty a, &sty b) -> bool { case (_) { ret false; } } } + case (ty_ptr(?mt_a)) { + alt (b) { + case (ty_ptr(?mt_b)) { ret equal_mt(mt_a, mt_b); } + case (_) { ret false; } + } + } case (ty_port(?t_a)) { alt (b) { case (ty_port(?t_b)) { ret eq_ty(t_a, t_b); } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 551184b037dda..e952908a6ba61 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -284,6 +284,9 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { case (ast::ty_vec(?mt)) { typ = ty::mk_vec(tcx, ast_mt_to_mt(tcx, getter, mt)); } + case (ast::ty_ptr(?mt)) { + typ = ty::mk_ptr(tcx, ast_mt_to_mt(tcx, getter, mt)); + } case (ast::ty_task) { typ = ty::mk_task(tcx); } case (ast::ty_port(?t)) { typ = ty::mk_port(tcx, ast_ty_to_ty(tcx, getter, t)); diff --git a/src/comp/middle/walk.rs b/src/comp/middle/walk.rs index e08a27f2dbade..76b027fd8f9be 100644 --- a/src/comp/middle/walk.rs +++ b/src/comp/middle/walk.rs @@ -156,6 +156,7 @@ fn walk_ty(&ast_visitor v, @ast::ty t) { case (ast::ty_str) {} case (ast::ty_box(?mt)) { walk_ty(v, mt.ty); } case (ast::ty_vec(?mt)) { walk_ty(v, mt.ty); } + case (ast::ty_ptr(?mt)) { walk_ty(v, mt.ty); } case (ast::ty_task) {} case (ast::ty_port(?t)) { walk_ty(v, t); } case (ast::ty_chan(?t)) { walk_ty(v, t); } From 92e246a1ee268233805bc4887228e3d6649b13d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20=C3=81vila=20de=20Esp=C3=ADndola?= Date: Fri, 3 Jun 2011 15:13:10 -0400 Subject: [PATCH 08/64] Parse pointers in metadata. --- src/comp/front/creader.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/comp/front/creader.rs b/src/comp/front/creader.rs index 9ad6b51632a07..cae53bc74bf88 100644 --- a/src/comp/front/creader.rs +++ b/src/comp/front/creader.rs @@ -105,6 +105,7 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t { } case ('p') { ret ty::mk_param(st.tcx, parse_int(st) as uint); } case ('@') { ret ty::mk_box(st.tcx, parse_mt(st, sd)); } + case ('*') { ret ty::mk_ptr(st.tcx, parse_mt(st, sd)); } case ('V') { ret ty::mk_vec(st.tcx, parse_mt(st, sd)); } case ('a') { ret ty::mk_task(st.tcx); } case ('P') { ret ty::mk_port(st.tcx, parse_ty(st, sd)); } From 99ccd02fcb992210cc992a4bfb3658abf66afa55 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Thu, 2 Jun 2011 17:36:28 -0700 Subject: [PATCH 09/64] Tidy up printing of ty_fn. --- src/comp/pretty/pprust.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index 926435d29282d..f58c9fd45e486 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -1208,9 +1208,13 @@ fn print_ty_fn(&ps s, &ast::proto proto, &option::t[str] id, if (proto == ast::proto_fn) {word(s.s, "fn");} else {word(s.s, "iter");} alt (id) { - case (some(?id)) {space(s.s); word(s.s, id);} + case (some(?id)) { + word(s.s, " "); + word(s.s, id); + } case (_) {} } + zerobreak(s.s); popen(s); fn print_arg(&ps s, &ast::ty_arg input) { if (input.mode == ast::alias) {word(s.s, "&");} From 60d730f6bccd6420bdff21b4d811942b51d0cd83 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Fri, 3 Jun 2011 15:26:03 -0700 Subject: [PATCH 10/64] Add spans to fields, args, methods. Improve pp of same. --- src/comp/front/ast.rs | 10 +++++++--- src/comp/front/parser.rs | 20 ++++++++++---------- src/comp/middle/typeck.rs | 20 ++++++++++---------- src/comp/middle/walk.rs | 10 +++++----- src/comp/pretty/pprust.rs | 18 ++++++++---------- 5 files changed, 40 insertions(+), 38 deletions(-) diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 85e525e88233c..92f12c3dc1b4e 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -300,11 +300,15 @@ tag lit_ { // type structure in middle/ty.rs as well. type mt = rec(@ty ty, mutability mut); -type ty_field = rec(ident ident, mt mt); -type ty_arg = rec(mode mode, @ty ty); -type ty_method = rec(proto proto, ident ident, +type ty_field_ = rec(ident ident, mt mt); +type ty_arg_ = rec(mode mode, @ty ty); +type ty_method_ = rec(proto proto, ident ident, vec[ty_arg] inputs, @ty output, controlflow cf); +type ty_field = spanned[ty_field_]; +type ty_arg = spanned[ty_arg_]; +type ty_method = spanned[ty_method_]; + type ty = spanned[ty_]; tag ty_ { ty_nil; diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index a3bd41855b4c9..eb4742939d3d8 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -308,7 +308,6 @@ fn eat_word(&parser p, &str word) -> bool { p.bump(); ret true; } else { ret false; } - } case (_) { ret false; } } @@ -333,7 +332,8 @@ fn check_bad_word(&parser p) { fn parse_ty_fn(ast::proto proto, &parser p, uint lo) -> ast::ty_ { - fn parse_fn_input_ty(&parser p) -> rec(ast::mode mode, @ast::ty ty) { + fn parse_fn_input_ty(&parser p) -> ast::ty_arg { + auto lo = p.get_lo_pos(); auto mode; if (p.peek() == token::BINOP(token::AND)) { p.bump(); @@ -353,14 +353,12 @@ fn parse_ty_fn(ast::proto proto, &parser p, uint lo) case (_) { /* no param name present */ } } - ret rec(mode=mode, ty=t); + ret spanned(lo, t.span.hi, rec(mode=mode, ty=t)); } auto lo = p.get_lo_pos(); - - auto f = parse_fn_input_ty; // FIXME: trans_const_lval bug - auto inputs = parse_seq[rec(ast::mode mode, @ast::ty ty)](token::LPAREN, - token::RPAREN, some(token::COMMA), f, p); + auto inputs = parse_seq(token::LPAREN, token::RPAREN, + some(token::COMMA), parse_fn_input_ty, p); // FIXME: dropping constrs on the floor at the moment. // pick them up when they're used by typestate pass. @@ -404,8 +402,9 @@ fn parse_ty_obj(&parser p, &mutable uint hi) -> ast::ty_ { expect(p, token::SEMI); alt (f) { case (ast::ty_fn(?proto, ?inputs, ?output, ?cf)) { - ret rec(proto=proto, ident=ident, - inputs=inputs, output=output, cf=cf); + ret spanned(flo, output.span.hi, + rec(proto=proto, ident=ident, + inputs=inputs, output=output, cf=cf)); } } fail; @@ -426,9 +425,10 @@ fn parse_mt(&parser p) -> ast::mt { } fn parse_ty_field(&parser p) -> ast::ty_field { + auto lo = p.get_lo_pos(); auto mt = parse_mt(p); auto id = parse_ident(p); - ret rec(ident=id, mt=mt); + ret spanned(lo, mt.ty.span.hi, rec(ident=id, mt=mt)); } fn parse_constr_arg(&parser p) -> @ast::constr_arg { diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index e952908a6ba61..b93e0765d0d0b 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -229,10 +229,10 @@ fn ast_mode_to_mode(ast::mode mode) -> ty::mode { fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { fn ast_arg_to_arg(&ty::ctxt tcx, &ty_getter getter, - &rec(ast::mode mode, @ast::ty ty) arg) + &ast::ty_arg arg) -> rec(ty::mode mode, ty::t ty) { - auto ty_mode = ast_mode_to_mode(arg.mode); - ret rec(mode=ty_mode, ty=ast_ty_to_ty(tcx, getter, arg.ty)); + auto ty_mode = ast_mode_to_mode(arg.node.mode); + ret rec(mode=ty_mode, ty=ast_ty_to_ty(tcx, getter, arg.node.ty)); } fn ast_mt_to_mt(&ty::ctxt tcx, @@ -306,8 +306,8 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { case (ast::ty_rec(?fields)) { let vec[field] flds = []; for (ast::ty_field f in fields) { - auto tm = ast_mt_to_mt(tcx, getter, f.mt); - vec::push[field](flds, rec(ident=f.ident, mt=tm)); + auto tm = ast_mt_to_mt(tcx, getter, f.node.mt); + vec::push[field](flds, rec(ident=f.node.ident, mt=tm)); } typ = ty::mk_rec(tcx, flds); } @@ -342,14 +342,14 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { let vec[ty::method] tmeths = []; auto f = bind ast_arg_to_arg(tcx, getter, _); for (ast::ty_method m in meths) { - auto ins = vec::map[ast::ty_arg, arg](f, m.inputs); - auto out = ast_ty_to_ty(tcx, getter, m.output); + auto ins = vec::map[ast::ty_arg, arg](f, m.node.inputs); + auto out = ast_ty_to_ty(tcx, getter, m.node.output); let ty::method new_m = - rec(proto=m.proto, - ident=m.ident, + rec(proto=m.node.proto, + ident=m.node.ident, inputs=ins, output=out, - cf=m.cf); + cf=m.node.cf); vec::push[ty::method](tmeths, new_m); } diff --git a/src/comp/middle/walk.rs b/src/comp/middle/walk.rs index 76b027fd8f9be..426f72d9bed71 100644 --- a/src/comp/middle/walk.rs +++ b/src/comp/middle/walk.rs @@ -167,21 +167,21 @@ fn walk_ty(&ast_visitor v, @ast::ty t) { } case (ast::ty_rec(?flds)) { for (ast::ty_field f in flds) { - walk_ty(v, f.mt.ty); + walk_ty(v, f.node.mt.ty); } } case (ast::ty_fn(_, ?args, ?out, _)) { for (ast::ty_arg a in args) { - walk_ty(v, a.ty); + walk_ty(v, a.node.ty); } walk_ty(v, out); } case (ast::ty_obj(?tmeths)) { for (ast::ty_method m in tmeths) { - for (ast::ty_arg a in m.inputs) { - walk_ty(v, a.ty); + for (ast::ty_arg a in m.node.inputs) { + walk_ty(v, a.node.ty); } - walk_ty(v, m.output); + walk_ty(v, m.node.output); } } case (ast::ty_path(?p, _)) { diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index f58c9fd45e486..dad990fe4437c 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -268,16 +268,13 @@ fn print_type(&ps s, &ast::ty ty) { popen(s); fn print_field(&ps s, &ast::ty_field f) { cbox(s, indent_unit); - print_mt(s, f.mt); + print_mt(s, f.node.mt); space(s.s); - word(s.s, f.ident); + word(s.s, f.node.ident); end(s); } fn get_span(&ast::ty_field f) -> common::span { - // Try to reconstruct the span for this field - auto sp = f.mt.ty.span; - auto hi = sp.hi + str::char_len(f.ident) + 1u; - ret rec(hi=hi with sp); + ret f.span; } auto f = print_field; auto gs = get_span; @@ -290,8 +287,9 @@ fn print_type(&ps s, &ast::ty ty) { for (ast::ty_method m in methods) { hardbreak(s.s); cbox(s, indent_unit); - print_ty_fn(s, m.proto, some(m.ident), - m.inputs, m.output, m.cf); + maybe_print_comment(s, m.span.lo); + print_ty_fn(s, m.node.proto, some(m.node.ident), + m.node.inputs, m.node.output, m.node.cf); word(s.s, ";"); end(s); } @@ -1217,8 +1215,8 @@ fn print_ty_fn(&ps s, &ast::proto proto, &option::t[str] id, zerobreak(s.s); popen(s); fn print_arg(&ps s, &ast::ty_arg input) { - if (input.mode == ast::alias) {word(s.s, "&");} - print_type(s, *input.ty); + if (input.node.mode == ast::alias) {word(s.s, "&");} + print_type(s, *input.node.ty); } auto f = print_arg; commasep[ast::ty_arg](s, inconsistent, inputs, f); From 884acabb165031fbefae5e79877fdd5c07b3e6ca Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 3 Jun 2011 16:14:29 -0700 Subject: [PATCH 11/64] rustc: Add a "smallintmap" implementation --- src/lib/smallintmap.rs | 40 ++++++++++++++++++++++++++++++++++++++++ src/lib/std.rc | 1 + src/lib/vec.rs | 13 +++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 src/lib/smallintmap.rs diff --git a/src/lib/smallintmap.rs b/src/lib/smallintmap.rs new file mode 100644 index 0000000000000..ca586eb6f05e6 --- /dev/null +++ b/src/lib/smallintmap.rs @@ -0,0 +1,40 @@ +/// A simple map based on a vector for small integer keys. Space requirements +/// are O(highest integer key). + +import option::none; +import option::some; + +type smallintmap[T] = rec(mutable vec[mutable option::t[T]] v); + +fn mk[T]() -> smallintmap[T] { + let vec[mutable option::t[T]] v = [mutable]; + ret rec(mutable v=v); +} + +fn insert[T](&smallintmap[T] m, uint key, &T val) { + vec::grow_set[option::t[T]](m.v, key, none[T], some[T](val)); +} + +fn find[T](&smallintmap[T] m, uint key) -> option::t[T] { + if (key < vec::len[option::t[T]](m.v)) { ret m.v.(key); } + ret none[T]; +} + +fn get[T](&smallintmap[T] m, uint key) -> T { + alt (find[T](m, key)) { + case (none[T]) { + log_err "smallintmap::get(): key not present"; + fail; + } + case (some[T](?v)) { ret v; } + } +} + +fn contains_key[T](&smallintmap[T] m, uint key) -> bool { + ret !option::is_none(find[T](m, key)); +} + +fn truncate[T](&smallintmap[T] m, uint len) { + m.v = vec::slice_mut[option::t[T]](m.v, 0u, len); +} + diff --git a/src/lib/std.rc b/src/lib/std.rc index c0839ce90980d..3619ede40f833 100644 --- a/src/lib/std.rc +++ b/src/lib/std.rc @@ -76,6 +76,7 @@ mod box; mod getopts; mod term; mod time; +mod smallintmap; // Local Variables: // mode: rust; diff --git a/src/lib/vec.rs b/src/lib/vec.rs index 969fca9a17ed5..8259e494e2532 100644 --- a/src/lib/vec.rs +++ b/src/lib/vec.rs @@ -163,6 +163,19 @@ fn slice[T](array[T] v, uint start, uint end) -> vec[T] { ret result; } +// FIXME: Should go away eventually. +fn slice_mut[T](array[T] v, uint start, uint end) -> vec[mutable T] { + assert (start <= end); + assert (end <= len[T](v)); + auto result = alloc_mut[T](end - start); + let uint i = start; + while (i < end) { + result += [mutable v.(i)]; + i += 1u; + } + ret result; +} + fn shift[T](&mutable array[T] v) -> T { auto ln = len[T](v); assert (ln > 0u); From 86c3e16024d4844bac8bb49efe607a616c4ef86d Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Fri, 3 Jun 2011 17:09:50 -0700 Subject: [PATCH 12/64] Comments and cleanup. --- src/comp/middle/trans.rs | 95 +++++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 31 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 3712ed7475d6a..9cfe8a51fbb20 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -160,8 +160,8 @@ state type fn_ctxt = rec( // The three implicit arguments that arrive in the function we're // creating. For instance, foo(int, int) is really foo(ret*, task*, env*, // int, int). These are also available via llvm::LLVMGetParam(llfn, uint) - // where uint = 2, 0, 1 respectively, but we unpack them here for - // convenience. + // where uint = 1, 2, 0 respectively, but we unpack them into these fields + // for convenience. ValueRef lltaskptr, ValueRef llenv, ValueRef llretptr, @@ -7000,6 +7000,7 @@ fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ast::def_id fid, &vec[ast::ty_param] ty_params, &ast::ann ann) { auto llfndecl = cx.ccx.item_ids.get(fid); + // Set up arguments to the function. auto fcx = new_fn_ctxt(cx, sp, llfndecl); create_llargs_for_fn_args(fcx, f.proto, ty_self, ret_ty_of_fn(cx.ccx, ann), @@ -7018,9 +7019,10 @@ fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ast::def_id fid, auto arg_tys = arg_tys_of_fn(fcx.lcx.ccx, ann); copy_args_to_allocas(fcx, f.decl.inputs, arg_tys); + // Create the first basic block in the function and keep a handle on it to + // pass to finish_fn later. auto bcx = new_top_block_ctxt(fcx); add_cleanups_for_args(bcx, f.decl.inputs, arg_tys); - auto lltop = bcx.llbb; auto block_ty = node_ann_type(cx.ccx, f.body.node.a); @@ -7041,9 +7043,12 @@ fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ast::def_id fid, res.bcx.build.RetVoid(); } + // Insert the mandatory first few basic blocks before lltop. finish_fn(fcx, lltop); } +// Create a vtable for an object being translated. Returns a pointer into +// read-only memory. fn create_vtbl(@local_ctxt cx, TypeRef llself_ty, ty::t self_ty, @@ -7136,13 +7141,15 @@ fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::def_id oid, // starting with an ast::_obj rather than an ast::_fn, we have some setup // work to do. - // Translate obj ctor args to function arguments. + // The fields of our object will become the arguments to the function + // we're creating. let vec[ast::arg] fn_args = []; for (ast::obj_field f in ob.fields) { fn_args += [rec(mode=ast::alias, ty=f.ty, ident=f.ident, id=f.id)]; } - auto fcx = new_fn_ctxt(cx, sp, llctor_decl); + + // Both regular arguments and type parameters are handled here. create_llargs_for_fn_args(fcx, ast::proto_fn, none[ty_self_pair], ret_ty_of_fn(ccx, ann), @@ -7151,78 +7158,103 @@ fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::def_id oid, let vec[ty::arg] arg_tys = arg_tys_of_fn(ccx, ann); copy_args_to_allocas(fcx, fn_args, arg_tys); - // Make the first block context in the function and keep a handle on it + // Create the first block context in the function and keep a handle on it // to pass to finish_fn later. auto bcx = new_top_block_ctxt(fcx); auto lltop = bcx.llbb; + // Pick up the type of this object by looking at our own output type, that + // is, the output type of the object constructor we're building. auto self_ty = ret_ty_of_fn(ccx, ann); auto llself_ty = type_of(ccx, sp, self_ty); - auto pair = bcx.fcx.llretptr; - auto vtbl = create_vtbl(cx, llself_ty, self_ty, ob, ty_params); + // Set up the two-word pair that we're going to return from the object + // constructor we're building. The two elements of this pair will be a + // vtable pointer and a body pointer. (llretptr already points to the + // place where this two-word pair should go; it was pre-allocated by the + // caller of the function.) + auto pair = bcx.fcx.llretptr; + // Grab onto the first and second elements of the pair. + // abi::obj_field_vtbl and abi::obj_field_box simply specify words 0 and 1 + // of 'pair'. auto pair_vtbl = bcx.build.GEP(pair, [C_int(0), - C_int(abi::obj_field_vtbl)]); + C_int(abi::obj_field_vtbl)]); auto pair_box = bcx.build.GEP(pair, [C_int(0), - C_int(abi::obj_field_box)]); + C_int(abi::obj_field_box)]); + + // Make a vtable for this object: a static array of pointers to functions. + // It will be located in the read-only memory of the executable we're + // creating and will contain ValueRefs for all of this object's methods. + // create_vtbl returns a pointer to the vtable, which we store. + auto vtbl = create_vtbl(cx, llself_ty, self_ty, ob, ty_params); bcx.build.Store(vtbl, pair_vtbl); - let TypeRef llbox_ty = T_opaque_obj_ptr(ccx.tn); + // Next we have to take care of the other half of the pair we're + // returning: a boxed (reference-counted) tuple containing a tydesc, + // typarams, and fields. - // FIXME we should probably also allocate a box for empty objs that have a - // dtor, since otherwise they are never dropped, and the dtor never runs + // FIXME: What about with_obj? Do we have to think about it here? + // (Pertains to issue #417.) + + let TypeRef llbox_ty = T_opaque_obj_ptr(ccx.tn); + + // FIXME: we should probably also allocate a box for empty objs that have + // a dtor, since otherwise they are never dropped, and the dtor never + // runs. if (vec::len[ast::ty_param](ty_params) == 0u && vec::len[ty::arg](arg_tys) == 0u) { + // If the object we're translating has no fields or type parameters, + // there's not much to do. + // Store null into pair, if no args or typarams. bcx.build.Store(C_null(llbox_ty), pair_box); } else { - // Malloc a box for the body and copy args in. + // Otherwise, we have to synthesize a big structural type for the + // object body. let vec[ty::t] obj_fields = []; for (ty::arg a in arg_tys) { vec::push[ty::t](obj_fields, a.ty); } - // Synthesize an obj body type. + // Tuple type for fields: [field, ...] + let ty::t fields_ty = ty::mk_imm_tup(ccx.tcx, obj_fields); + + // Tuple type for typarams: [typaram, ...] auto tydesc_ty = ty::mk_type(ccx.tcx); let vec[ty::t] tps = []; for (ast::ty_param tp in ty_params) { vec::push[ty::t](tps, tydesc_ty); } - - // typarams_ty = [typaram_ty, ...] let ty::t typarams_ty = ty::mk_imm_tup(ccx.tcx, tps); - - // fields_ty = [field_ty, ...] - let ty::t fields_ty = ty::mk_imm_tup(ccx.tcx, obj_fields); - - // body_ty = [tydesc_ty, [typaram_ty, ...], [field_ty, ...]] + + // Tuple type for body: [tydesc_ty, [typaram, ...], [field, ...]] let ty::t body_ty = ty::mk_imm_tup(ccx.tcx, [tydesc_ty, typarams_ty, fields_ty]); - // boxed_body_ty = [[tydesc_ty, [typaram_ty, ...], [field_ty, ...]]] - let ty::t boxed_body_ty = ty::mk_imm_box(ccx.tcx, body_ty); - - // Malloc a box for the body. + // Hand this thing we've constructed off to trans_malloc_boxed, which + // makes space for the refcount. auto box = trans_malloc_boxed(bcx, body_ty); bcx = box.bcx; + + // And mk_imm_box throws a refcount into the type we're synthesizing: + // [rc, [tydesc_ty, [typaram, ...], [field, ...]]] + let ty::t boxed_body_ty = ty::mk_imm_box(ccx.tcx, body_ty); + auto rc = GEP_tup_like(bcx, boxed_body_ty, box.val, - [0, abi::box_rc_field_refcnt]); + [0, + abi::box_rc_field_refcnt]); bcx = rc.bcx; - // We've now created a structure that looks like: - // [refcount, [tydesc_ty, [typaram_ty, ...], [field_ty, ...]]] - auto body = GEP_tup_like(bcx, boxed_body_ty, box.val, [0, abi::box_rc_field_body]); bcx = body.bcx; - bcx.build.Store(C_int(1), rc.val); // Put together a tydesc for the body, so that the object can later be @@ -7285,6 +7317,7 @@ fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::def_id oid, } bcx.build.RetVoid(); + // Insert the mandatory first few basic blocks before lltop. finish_fn(fcx, lltop); } From c66ffa04e6e7a4c15a48b47952024051bfe19197 Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Fri, 3 Jun 2011 17:16:28 -0700 Subject: [PATCH 13/64] More comments. --- src/comp/middle/trans.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 9cfe8a51fbb20..975f3a7eb26c0 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -1641,6 +1641,8 @@ fn GEP_tag(@block_ctxt cx, } +// trans_raw_malloc: expects a type indicating which pointer type we want and +// a size indicating how much space we want malloc'd. fn trans_raw_malloc(&@block_ctxt cx, TypeRef llptr_ty, ValueRef llsize) -> result { // FIXME: need a table to collect tydesc globals. @@ -1650,14 +1652,29 @@ fn trans_raw_malloc(&@block_ctxt cx, TypeRef llptr_ty, ValueRef llsize) ret res(cx, cx.build.PointerCast(rval, llptr_ty)); } + +// trans_malloc_boxed: expects an unboxed type and returns a pointer to enough +// space for something of that type, along with space for a reference count; +// in other words, it allocates a box for something of that type. fn trans_malloc_boxed(&@block_ctxt cx, ty::t t) -> result { // Synthesize a fake box type structurally so we have something // to measure the size of. + + // We synthesize two types here because we want both the type of the + // pointer and the pointee. boxed_body is the type that we measure the + // size of; box_ptr is the type that's converted to a TypeRef and used as + // the pointer cast target in trans_raw_malloc. auto boxed_body = ty::mk_imm_tup(cx.fcx.lcx.ccx.tcx, + // The mk_int here is the space being + // reserved for the refcount. [ty::mk_int(cx.fcx.lcx.ccx.tcx), t]); auto box_ptr = ty::mk_imm_box(cx.fcx.lcx.ccx.tcx, t); auto sz = size_of(cx, boxed_body); + + // Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc + // wants. auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, box_ptr); + ret trans_raw_malloc(sz.bcx, llty, sz.val); } From 7d02fb47bfb175fc863aeefba106fda4a61e61ee Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Fri, 3 Jun 2011 17:24:05 -0700 Subject: [PATCH 14/64] Make pp more conservative about inserting trailing comments mid-list. --- src/comp/pretty/pprust.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index dad990fe4437c..87e40bdbcd68c 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -204,7 +204,8 @@ fn commasep_cmnt[IN](&ps s, breaks b, vec[IN] elts, fn(&ps, &IN) op, i += 1u; if (i < len) { word(s.s, ","); - maybe_print_trailing_comment(s, get_span(elt)); + maybe_print_trailing_comment(s, get_span(elt), + some(get_span(elts.(i)).hi)); space(s.s); } } @@ -404,7 +405,7 @@ fn print_item(&ps s, &@ast::item item) { pclose(s); } word(s.s, ";"); - maybe_print_trailing_comment(s, v.span); + maybe_print_trailing_comment(s, v.span, none[uint]); } bclose(s, item.span); } @@ -469,13 +470,12 @@ fn print_stmt(&ps s, &ast::stmt st) { } } if (front::parser::stmt_ends_with_semi(st)) {word(s.s, ";");} - maybe_print_trailing_comment(s, st.span); + maybe_print_trailing_comment(s, st.span, none[uint]); } fn print_block(&ps s, ast::block blk) { maybe_print_comment(s, blk.span.lo); bopen(s); - auto first = true; for (@ast::stmt st in blk.node.stmts) { print_stmt(s, *st) @@ -484,7 +484,8 @@ fn print_block(&ps s, ast::block blk) { case (some(?expr)) { space(s.s); print_expr(s, expr); - maybe_print_trailing_comment(s, expr.span); + maybe_print_trailing_comment(s, expr.span, + some(blk.span.hi)); } case (_) {} } @@ -1264,7 +1265,8 @@ fn maybe_print_comment(&ps s, uint pos) { } } -fn maybe_print_trailing_comment(&ps s, common::span span) { +fn maybe_print_trailing_comment(&ps s, common::span span, + option::t[uint] next_pos) { auto cm; alt (s.cm) { case (some(?ccm)) { @@ -1278,9 +1280,14 @@ fn maybe_print_trailing_comment(&ps s, common::span span) { auto span_line = codemap::lookup_pos(cm, span.hi); auto comment_line = codemap::lookup_pos(cm, cmnt.pos); + auto next = cmnt.pos + 1u; + alt (next_pos) { + case (none) { } + case (some(?p)) { next = p; } + } if (span.hi < cmnt.pos && + cmnt.pos < next && span_line.line == comment_line.line) { - word(s.s, " "); print_comment(s, cmnt); s.cur_cmnt += 1u; } @@ -1327,6 +1334,7 @@ fn print_comment(&ps s, lexer::cmnt cmnt) { } case (lexer::trailing) { + word(s.s, " "); if (vec::len(cmnt.lines) == 1u) { word(s.s, cmnt.lines.(0)); hardbreak(s.s); From c41eada9536cc6177d54bdc149bbf8134136b503 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Fri, 3 Jun 2011 17:32:22 -0700 Subject: [PATCH 15/64] Remove zerobreak between foo and ( on a call expr. Never looks right. --- src/comp/pretty/pprust.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index 87e40bdbcd68c..be492d03a1ae7 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -624,7 +624,6 @@ fn print_expr(&ps s, &@ast::expr expr) { } case (ast::expr_call(?func,?args,_)) { print_expr(s, func); - zerobreak(s.s); popen(s); commasep_exprs(s, inconsistent, args); pclose(s); From 1c5f6c9abc5125f0ddb264dfc3d99e1bda64a13d Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Fri, 3 Jun 2011 18:47:08 -0700 Subject: [PATCH 16/64] Register new snapshots. --- src/snapshots.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/snapshots.txt b/src/snapshots.txt index ab954d630f7dc..d64be8bffe1fd 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,8 @@ +S 2011-06-03 f29d046 + linux-i386 76e4ee5b9148aae30ebfaabb12791bfee4fa8727 + macos-i386 e146fa18f4b0f22fe4fd7fd104242837569d7702 + winnt-i386 d1d4560c449d675c22601a1377b3c12389272e5d + S 2011-06-01 a6ca9c2 linux-i386 64569e47e1693a6e100d62fd31258c1d6ba3ea17 macos-i386 e36a8d3d8365bc353ed2477d5c52656c1e8541df From b55a99cb36193808b8cad1958981c50325c22ba0 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 4 Jun 2011 15:41:45 -0400 Subject: [PATCH 17/64] rustc: Introduce ext module. Move some things from parser to ext. Introduce an ext_ctxt record to provide a span_err method for use while expanding syntax extensions. Hopefully it will be useful for other things. --- src/comp/front/ext.rs | 49 ++++++++++++++++++++++++++++++++++++++++ src/comp/front/extenv.rs | 5 +++- src/comp/front/extfmt.rs | 5 +++- src/comp/front/parser.rs | 32 ++++++++------------------ src/comp/rustc.rc | 1 + 5 files changed, 68 insertions(+), 24 deletions(-) create mode 100644 src/comp/front/ext.rs diff --git a/src/comp/front/ext.rs b/src/comp/front/ext.rs new file mode 100644 index 0000000000000..428ac1bf295e9 --- /dev/null +++ b/src/comp/front/ext.rs @@ -0,0 +1,49 @@ +import std::option; +import std::map::hashmap; + +import driver::session::session; +import util::common::span; +import util::common::new_str_hash; + +type syntax_expander = fn(&ext_ctxt, &parser::parser, span, + &vec[@ast::expr], + option::t[str]) -> @ast::expr; + +// Temporary: to introduce a tag in order to make a recursive type work +tag syntax_extension { + x(syntax_expander); +} + +// A temporary hard-coded map of methods for expanding syntax extension +// AST nodes into full ASTs +fn syntax_expander_table() -> hashmap[str, syntax_extension] { + auto syntax_expanders = new_str_hash[syntax_extension](); + syntax_expanders.insert("fmt", x(extfmt::expand_syntax_ext)); + syntax_expanders.insert("env", x(extenv::expand_syntax_ext)); + ret syntax_expanders; +} + +type span_err_fn = fn (span sp, str msg) -> !; + +// Provides a limited set of services necessary for syntax extensions +// to do their thing +type ext_ctxt = rec(span_err_fn span_err); + +fn mk_ctxt(session sess) -> ext_ctxt { + fn ext_span_err_(session sess, span sp, str err) -> ! { + sess.span_err(sp, err); + } + auto ext_span_err = bind ext_span_err_(sess, _, _); + ret rec(span_err = ext_span_err); +} + +// +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: +// diff --git a/src/comp/front/extenv.rs b/src/comp/front/extenv.rs index ecceabd9c07d8..fc7d889d8f6f5 100644 --- a/src/comp/front/extenv.rs +++ b/src/comp/front/extenv.rs @@ -11,10 +11,13 @@ import std::vec; import std::option; import std::generic_os; +import ext::*; + export expand_syntax_ext; // FIXME: Need to thread parser through here to handle errors correctly -fn expand_syntax_ext(&parser::parser p, +fn expand_syntax_ext(&ext_ctxt cx, + &parser::parser p, common::span sp, &vec[@ast::expr] args, option::t[str] body) -> @ast::expr { diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index 672de538510fa..a2fdd6742aece 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -15,9 +15,12 @@ import std::option::some; import std::extfmt::ct::*; +import ext::*; + export expand_syntax_ext; -fn expand_syntax_ext(&parser p, common::span sp, +fn expand_syntax_ext(&ext_ctxt cx, + &parser p, common::span sp, &vec[@ast::expr] args, option::t[str] body) -> @ast::expr { diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index eb4742939d3d8..a07838d03e7c9 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -27,11 +27,6 @@ tag file_type { type ty_or_bang = util::common::ty_or_bang[@ast::ty]; -// Temporary: to introduce a tag in order to make a recursive type work -tag syntax_extension { - x(syntax_expander); -} - state type parser = state obj { fn peek() -> token::token; @@ -53,15 +48,12 @@ state type parser = fn get_reader() -> lexer::reader; fn get_filemap() -> codemap::filemap; fn get_bad_expr_words() -> hashmap[str, ()]; - fn get_syntax_expanders() -> hashmap[str, syntax_extension]; + fn get_syntax_expanders() -> hashmap[str, ext::syntax_extension]; fn get_chpos() -> uint; fn get_ann() -> ast::ann; fn next_ann_num() -> uint; }; -type syntax_expander = fn(&parser, common::span, &vec[@ast::expr], - option::t[str]) -> @ast::expr; - fn new_parser(session::session sess, eval::env env, ast::def_id initial_def, @@ -80,7 +72,8 @@ fn new_parser(session::session sess, vec[op_spec] precs, mutable uint next_ann_var, hashmap[str, ()] bad_words, - hashmap[str, syntax_extension] syntax_expanders) + hashmap[str, ext::syntax_extension] + syntax_expanders) { fn peek() -> token::token { ret tok; @@ -153,7 +146,7 @@ fn new_parser(session::session sess, ret bad_words; } - fn get_syntax_expanders() -> hashmap[str, syntax_extension] { + fn get_syntax_expanders() -> hashmap[str, ext::syntax_extension] { ret syntax_expanders; } @@ -183,7 +176,7 @@ fn new_parser(session::session sess, ret stdio_parser(sess, env, ftype, lexer::next_token(rdr), npos, npos, npos, initial_def._1, UNRESTRICTED, initial_def._0, rdr, prec_table(), next_ann, - bad_expr_word_table(), syntax_expander_table()); + bad_expr_word_table(), ext::syntax_expander_table()); } // These are the words that shouldn't be allowed as value identifiers, @@ -227,13 +220,6 @@ fn bad_expr_word_table() -> hashmap[str, ()] { ret words; } -fn syntax_expander_table() -> hashmap[str, syntax_extension] { - auto syntax_expanders = new_str_hash[syntax_extension](); - syntax_expanders.insert("fmt", x(extfmt::expand_syntax_ext)); - syntax_expanders.insert("env", x(extenv::expand_syntax_ext)); - ret syntax_expanders; -} - fn unexpected(&parser p, token::token t) -> ! { let str s = "unexpected token: "; s += token::to_str(p.get_reader(), t); @@ -1060,11 +1046,13 @@ fn expand_syntax_ext(&parser p, common::span sp, auto extname = path.node.idents.(0); alt (p.get_syntax_expanders().find(extname)) { - case (none[syntax_extension]) { + case (none) { p.err("unknown syntax expander: '" + extname + "'"); } - case (some[syntax_extension](x(?ext))) { - ret ast::expr_ext(path, args, body, ext(p, sp, args, body), + case (some(ext::x(?ext))) { + auto ext_cx = ext::mk_ctxt(p.get_session()); + ret ast::expr_ext(path, args, body, + ext(ext_cx, p, sp, args, body), p.get_ann()); } } diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index 7fe5d603585e6..55683ba7ffa30 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -38,6 +38,7 @@ mod pretty { mod front { mod ast; mod creader; + mod ext; mod extfmt; mod extenv; mod codemap; From 462e47e26d9a09c9d7b69651fc14e4555a56a4da Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 4 Jun 2011 15:57:13 -0400 Subject: [PATCH 18/64] rustc: Pass the correct span to syntax extensions --- src/comp/front/parser.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index a07838d03e7c9..5706d11782d94 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -933,7 +933,8 @@ fn parse_bottom_expr(&parser p) -> @ast::expr { some(token::COMMA), pf, p); hi = es.span.hi; - ex = expand_syntax_ext(p, es.span, pth, es.node, + auto ext_span = rec(lo=lo, hi=hi); + ex = expand_syntax_ext(p, ext_span, pth, es.node, none[str]); } else if (eat_word(p, "fail")) { ex = ast::expr_fail(p.get_ann()); From cd88b51dc6f45c258241f5789e76ab7e33233393 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 4 Jun 2011 16:34:26 -0400 Subject: [PATCH 19/64] rustc: Return the correct span from parse_seq --- src/comp/front/parser.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 5706d11782d94..f23a1eece2dc8 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -608,7 +608,6 @@ fn parse_arg(&parser p) -> ast::arg { fn parse_seq_to_end[T](token::token ket, option::t[token::token] sep, (fn(&parser) -> T) f, - uint hi, &parser p) -> vec[T] { let bool first = true; let vec[T] v = []; @@ -628,7 +627,6 @@ fn parse_seq_to_end[T](token::token ket, let T t = f(p); v += [t]; } - hi = p.get_hi_pos(); expect(p, ket); ret v; } @@ -639,9 +637,9 @@ fn parse_seq[T](token::token bra, (fn(&parser) -> T) f, &parser p) -> util::common::spanned[vec[T]] { auto lo = p.get_lo_pos(); - auto hi = p.get_hi_pos(); expect(p, bra); - auto result = parse_seq_to_end[T](ket, sep, f, hi, p); + auto result = parse_seq_to_end[T](ket, sep, f, p); + auto hi = p.get_hi_pos(); ret spanned(lo, hi, result); } @@ -823,7 +821,7 @@ fn parse_bottom_expr(&parser p) -> @ast::expr { auto es = parse_seq_to_end[@ast::expr](token::RBRACKET, some(token::COMMA), - pf, hi, p); + pf, p); ex = ast::expr_vec(es, mut, p.get_ann()); } else if (eat_word(p, "obj")) { // Anonymous object @@ -836,7 +834,6 @@ fn parse_bottom_expr(&parser p) -> @ast::expr { none[vec[ast::obj_field]]; if (p.peek() == token::LPAREN) { auto pf = parse_obj_field; - hi = p.get_hi_pos(); expect(p, token::LPAREN); @@ -844,7 +841,7 @@ fn parse_bottom_expr(&parser p) -> @ast::expr { (parse_seq_to_end[ast::obj_field] (token::RPAREN, some(token::COMMA), - pf, hi, p)); + pf, p)); } let vec[@ast::method] meths = []; From 3e72b2331da8ce73b92a621239bb5c45aeab9363 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 4 Jun 2011 16:04:40 -0400 Subject: [PATCH 20/64] rustc: Use spans on extfmt error messages Issue #444 --- src/comp/front/extfmt.rs | 60 ++++++++++--------- src/test/compile-fail/extfmt-no-args.rs | 6 ++ src/test/compile-fail/extfmt-non-literal2.rs | 9 +++ .../compile-fail/extfmt-not-enough-args.rs | 8 +++ src/test/compile-fail/extfmt-unsigned-plus.rs | 7 +++ .../compile-fail/extfmt-unsigned-space.rs | 7 +++ 6 files changed, 68 insertions(+), 29 deletions(-) create mode 100644 src/test/compile-fail/extfmt-no-args.rs create mode 100644 src/test/compile-fail/extfmt-non-literal2.rs create mode 100644 src/test/compile-fail/extfmt-not-enough-args.rs create mode 100644 src/test/compile-fail/extfmt-unsigned-plus.rs create mode 100644 src/test/compile-fail/extfmt-unsigned-space.rs diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index a2fdd6742aece..e15bd3becf522 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -25,12 +25,10 @@ fn expand_syntax_ext(&ext_ctxt cx, option::t[str] body) -> @ast::expr { if (vec::len[@ast::expr](args) == 0u) { - // FIXME: Handle error correctly. - log_err "malformed #fmt call"; - fail; + cx.span_err(sp, "#fmt requires a format string"); } - auto fmt = expr_to_str(args.(0)); + auto fmt = expr_to_str(cx, args.(0)); // log "Format string:"; // log fmt; @@ -38,31 +36,34 @@ fn expand_syntax_ext(&ext_ctxt cx, auto pieces = parse_fmt_string(fmt); auto args_len = vec::len[@ast::expr](args); auto fmt_args = vec::slice[@ast::expr](args, 1u, args_len - 1u); - ret pieces_to_expr(p, pieces, args); + ret pieces_to_expr(cx, p, sp, pieces, args); } -fn expr_to_str(@ast::expr expr) -> str { +fn expr_to_str(&ext_ctxt cx, @ast::expr expr) -> str { + auto err_msg = "first argument to #fmt must be a string literal"; alt (expr.node) { case (ast::expr_lit(?l, _)) { alt (l.node) { case (ast::lit_str(?s)) { ret s; } - case (_) { /* fallthrough */ } + case (_) { + cx.span_err(l.span, err_msg); + } } } - case (_) { /* fallthrough */ } + case (_) { + cx.span_err(expr.span, err_msg); + } } - log_err "first argument to #fmt must be a string literal"; - fail; } // FIXME: A lot of these functions for producing expressions can probably // be factored out in common with other code that builds expressions. // FIXME: Probably should be using the parser's span functions // FIXME: Cleanup the naming of these functions -fn pieces_to_expr(parser p, vec[piece] pieces, vec[@ast::expr] args) - -> @ast::expr { +fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, + vec[piece] pieces, vec[@ast::expr] args) -> @ast::expr { fn make_new_lit(parser p, common::span sp, ast::lit_ lit) -> @ast::expr { auto sp_lit = @rec(node=lit, span=sp); @@ -263,7 +264,8 @@ fn pieces_to_expr(parser p, vec[piece] pieces, vec[@ast::expr] args) ret make_call(p, arg.span, path, args); } - fn make_new_conv(parser p, conv cnv, @ast::expr arg) -> @ast::expr { + fn make_new_conv(&ext_ctxt cx, parser p, common::span sp, + conv cnv, @ast::expr arg) -> @ast::expr { // FIXME: Extract all this validation into extfmt::ct fn is_signed_type(conv cnv) -> bool { @@ -301,15 +303,14 @@ fn pieces_to_expr(parser p, vec[piece] pieces, vec[@ast::expr] args) } case (flag_sign_always) { if (!is_signed_type(cnv)) { - log_err "+ flag only valid in signed #fmt conversion"; - fail; + cx.span_err(sp, "+ flag only valid in " + + "signed #fmt conversion"); } } case (flag_space_for_sign) { if (!is_signed_type(cnv)) { - log_err "space flag only valid in " - + "signed #fmt conversions"; - fail; + cx.span_err(sp, "space flag only valid in " + + "signed #fmt conversions"); } } case (flag_left_zero_pad) { @@ -471,7 +472,7 @@ fn pieces_to_expr(parser p, vec[piece] pieces, vec[@ast::expr] args) } } - auto sp = args.(0).span; + auto fmt_sp = args.(0).span; auto n = 0u; auto tmp_expr = make_new_str(p, sp, ""); auto nargs = vec::len[@ast::expr](args); @@ -479,32 +480,33 @@ fn pieces_to_expr(parser p, vec[piece] pieces, vec[@ast::expr] args) for (piece pc in pieces) { alt (pc) { case (piece_string(?s)) { - auto s_expr = make_new_str(p, sp, s); - tmp_expr = make_add_expr(p, sp, tmp_expr, s_expr); + auto s_expr = make_new_str(p, fmt_sp, s); + tmp_expr = make_add_expr(p, fmt_sp, tmp_expr, s_expr); } case (piece_conv(?conv)) { + n += 1u; + if (n >= nargs) { - log_err "too many conversions in #fmt string"; - fail; + cx.span_err(sp, "not enough arguments to #fmt " + + "for the given format string"); } // TODO: Remove debug logging //log "Building conversion:"; //log_conv(conv); - n += 1u; auto arg_expr = args.(n); - auto c_expr = make_new_conv(p, conv, arg_expr); - tmp_expr = make_add_expr(p, sp, tmp_expr, c_expr); + auto c_expr = make_new_conv(cx, p, fmt_sp, conv, arg_expr); + tmp_expr = make_add_expr(p, fmt_sp, tmp_expr, c_expr); } } } auto expected_nargs = n + 1u; // n conversions + the fmt string if (expected_nargs < nargs) { - log_err #fmt("too many arguments to #fmt. found %u, expected %u", - nargs, expected_nargs); - fail; + cx.span_err(sp, + #fmt("too many arguments to #fmt. found %u, expected %u", + nargs, expected_nargs)); } // TODO: Remove this debug logging diff --git a/src/test/compile-fail/extfmt-no-args.rs b/src/test/compile-fail/extfmt-no-args.rs new file mode 100644 index 0000000000000..d31939ead1b25 --- /dev/null +++ b/src/test/compile-fail/extfmt-no-args.rs @@ -0,0 +1,6 @@ +// xfail-stage0 +// error-pattern:format string + +fn main() { + #fmt(); +} diff --git a/src/test/compile-fail/extfmt-non-literal2.rs b/src/test/compile-fail/extfmt-non-literal2.rs new file mode 100644 index 0000000000000..218263973d6b2 --- /dev/null +++ b/src/test/compile-fail/extfmt-non-literal2.rs @@ -0,0 +1,9 @@ +// xfail-stage0 +// error-pattern: literal + +fn main() { + // #fmt's first argument must be a literal. Hopefully this + // restriction can be eased eventually to just require a + // compile-time constant. + auto x = #fmt(20); +} diff --git a/src/test/compile-fail/extfmt-not-enough-args.rs b/src/test/compile-fail/extfmt-not-enough-args.rs new file mode 100644 index 0000000000000..80aad7bc03c5a --- /dev/null +++ b/src/test/compile-fail/extfmt-not-enough-args.rs @@ -0,0 +1,8 @@ +// xfail-stage0 +// error-pattern:not enough arguments + +use std; + +fn main() { + auto s = #fmt("%s%s%s", "test", "test"); +} diff --git a/src/test/compile-fail/extfmt-unsigned-plus.rs b/src/test/compile-fail/extfmt-unsigned-plus.rs new file mode 100644 index 0000000000000..a74f4dbfca0b1 --- /dev/null +++ b/src/test/compile-fail/extfmt-unsigned-plus.rs @@ -0,0 +1,7 @@ +// xfail-stage0 +// error-pattern:only valid in signed #fmt conversion + +fn main() { + // Can't use a sign on unsigned conversions + #fmt("%+u", 10u); +} diff --git a/src/test/compile-fail/extfmt-unsigned-space.rs b/src/test/compile-fail/extfmt-unsigned-space.rs new file mode 100644 index 0000000000000..bd1b6c97968e0 --- /dev/null +++ b/src/test/compile-fail/extfmt-unsigned-space.rs @@ -0,0 +1,7 @@ +// xfail-stage0 +// error-pattern:only valid in signed #fmt conversion + +fn main() { + // Can't use a space on unsigned conversions + #fmt("% u", 10u); +} From fe51ceed3bce7f466224cdb2702678128a426a1f Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 4 Jun 2011 16:55:32 -0400 Subject: [PATCH 21/64] rustc: Add a span_unimpl method to ext_ctxt --- src/comp/front/ext.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/comp/front/ext.rs b/src/comp/front/ext.rs index 428ac1bf295e9..f1c065eeeb46d 100644 --- a/src/comp/front/ext.rs +++ b/src/comp/front/ext.rs @@ -23,18 +23,26 @@ fn syntax_expander_table() -> hashmap[str, syntax_extension] { ret syntax_expanders; } -type span_err_fn = fn (span sp, str msg) -> !; +type span_msg_fn = fn (span sp, str msg) -> !; // Provides a limited set of services necessary for syntax extensions // to do their thing -type ext_ctxt = rec(span_err_fn span_err); +type ext_ctxt = rec(span_msg_fn span_err, + span_msg_fn span_unimpl); fn mk_ctxt(session sess) -> ext_ctxt { - fn ext_span_err_(session sess, span sp, str err) -> ! { - sess.span_err(sp, err); + fn ext_span_err_(session sess, span sp, str msg) -> ! { + sess.span_err(sp, msg); } auto ext_span_err = bind ext_span_err_(sess, _, _); - ret rec(span_err = ext_span_err); + + fn ext_span_unimpl_(session sess, span sp, str msg) -> ! { + sess.span_unimpl(sp, msg); + } + auto ext_span_unimpl = bind ext_span_unimpl_(sess, _, _); + + ret rec(span_err = ext_span_err, + span_unimpl = ext_span_unimpl); } // From 457b6ba63e5d56bd8a06a2b2d6baee786da8e2a6 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 4 Jun 2011 16:59:57 -0400 Subject: [PATCH 22/64] rustc: Report unimplemented #fmt features with spans --- src/comp/front/extfmt.rs | 48 ++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index e15bd3becf522..ed9636bd163c9 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -149,7 +149,8 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, // Produces an AST expression that represents a RT::conv record, // which tells the RT::conv* functions how to perform the conversion - fn make_rt_conv_expr(parser p, common::span sp, &conv cnv) -> @ast::expr { + fn make_rt_conv_expr(&ext_ctxt cx, + parser p, common::span sp, &conv cnv) -> @ast::expr { fn make_flags(parser p, common::span sp, vec[flag] flags) -> @ast::expr { @@ -186,7 +187,8 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, ret make_vec_expr(p, sp, flagexprs); } - fn make_count(parser p, common::span sp, &count cnt) -> @ast::expr { + fn make_count(&ext_ctxt cx, + parser p, common::span sp, &count cnt) -> @ast::expr { alt (cnt) { case (count_implied) { ret make_rt_path_expr(p, sp, "count_implied"); @@ -198,8 +200,7 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, ret make_call(p, sp, count_is_path, count_is_args); } case (_) { - log_err "not implemented"; - fail; + cx.span_unimpl(sp, "unimplemented #fmt conversion"); } } } @@ -244,8 +245,8 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, } auto rt_conv_flags = make_flags(p, sp, cnv.flags); - auto rt_conv_width = make_count(p, sp, cnv.width); - auto rt_conv_precision = make_count(p, sp, cnv.precision); + auto rt_conv_width = make_count(cx, p, sp, cnv.width); + auto rt_conv_precision = make_count(cx, p, sp, cnv.precision); auto rt_conv_ty = make_ty(p, sp, cnv.ty); ret make_conv_rec(p, sp, @@ -255,11 +256,11 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, rt_conv_ty); } - fn make_conv_call(parser p, common::span sp, str conv_type, + fn make_conv_call(&ext_ctxt cx, parser p, common::span sp, str conv_type, &conv cnv, @ast::expr arg) -> @ast::expr { auto fname = "conv_" + conv_type; auto path = make_path_vec(fname); - auto cnv_expr = make_rt_conv_expr(p, sp, cnv); + auto cnv_expr = make_rt_conv_expr(cx, p, sp, cnv); auto args = [cnv_expr, arg]; ret make_call(p, arg.span, path, args); } @@ -292,8 +293,7 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, case (option::none) { } case (_) { - log_err unsupported; - fail; + cx.span_unimpl(sp, unsupported); } } @@ -316,8 +316,7 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, case (flag_left_zero_pad) { } case (_) { - log_err unsupported; - fail; + cx.span_unimpl(sp, unsupported); } } } @@ -328,8 +327,7 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, case (count_is(_)) { } case (_) { - log_err unsupported; - fail; + cx.span_unimpl(sp, unsupported); } } @@ -339,43 +337,41 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, case (count_is(_)) { } case (_) { - log_err unsupported; - fail; + cx.span_unimpl(sp, unsupported); } } alt (cnv.ty) { case (ty_str) { - ret make_conv_call(p, arg.span, "str", cnv, arg); + ret make_conv_call(cx, p, arg.span, "str", cnv, arg); } case (ty_int(?sign)) { alt (sign) { case (signed) { - ret make_conv_call(p, arg.span, "int", cnv, arg); + ret make_conv_call(cx, p, arg.span, "int", cnv, arg); } case (unsigned) { - ret make_conv_call(p, arg.span, "uint", cnv, arg); + ret make_conv_call(cx, p, arg.span, "uint", cnv, arg); } } } case (ty_bool) { - ret make_conv_call(p, arg.span, "bool", cnv, arg); + ret make_conv_call(cx, p, arg.span, "bool", cnv, arg); } case (ty_char) { - ret make_conv_call(p, arg.span, "char", cnv, arg); + ret make_conv_call(cx, p, arg.span, "char", cnv, arg); } case (ty_hex(_)) { - ret make_conv_call(p, arg.span, "uint", cnv, arg); + ret make_conv_call(cx, p, arg.span, "uint", cnv, arg); } case (ty_bits) { - ret make_conv_call(p, arg.span, "uint", cnv, arg); + ret make_conv_call(cx, p, arg.span, "uint", cnv, arg); } case (ty_octal) { - ret make_conv_call(p, arg.span, "uint", cnv, arg); + ret make_conv_call(cx, p, arg.span, "uint", cnv, arg); } case (_) { - log_err unsupported; - fail; + cx.span_unimpl(sp, unsupported); } } } From dac75ff70a6f45cffd0779f125eb324f6a2cbeff Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 4 Jun 2011 17:08:50 -0400 Subject: [PATCH 23/64] rustc: Use spans for #env errors Issue #444 --- src/comp/front/extenv.rs | 14 +++++++++----- src/test/compile-fail/extenv-no-args.rs | 5 +++++ src/test/compile-fail/extenv-not-string-literal.rs | 5 +++++ src/test/compile-fail/extenv-too-many-args.rs | 5 +++++ 4 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/extenv-no-args.rs create mode 100644 src/test/compile-fail/extenv-not-string-literal.rs create mode 100644 src/test/compile-fail/extenv-too-many-args.rs diff --git a/src/comp/front/extenv.rs b/src/comp/front/extenv.rs index fc7d889d8f6f5..d92c5eb7dbd68 100644 --- a/src/comp/front/extenv.rs +++ b/src/comp/front/extenv.rs @@ -23,13 +23,13 @@ fn expand_syntax_ext(&ext_ctxt cx, option::t[str] body) -> @ast::expr { if (vec::len[@ast::expr](args) != 1u) { - p.err("malformed #env call"); + cx.span_err(sp, "malformed #env call"); } // FIXME: if this was more thorough it would manufacture an // option::t[str] rather than just an maybe-empty string. - auto var = expr_to_str(p, args.(0)); + auto var = expr_to_str(cx, p, args.(0)); alt (generic_os::getenv(var)) { case (option::none) { ret make_new_str(p, sp, ""); @@ -42,7 +42,7 @@ fn expand_syntax_ext(&ext_ctxt cx, // FIXME: duplicate code copied from extfmt: -fn expr_to_str(parser::parser p, +fn expr_to_str(&ext_ctxt cx, parser::parser p, @ast::expr expr) -> str { alt (expr.node) { case (ast::expr_lit(?l, _)) { @@ -50,11 +50,15 @@ fn expr_to_str(parser::parser p, case (ast::lit_str(?s)) { ret s; } + case (_) { + cx.span_err(l.span, "malformed #env call"); + } } } + case (_) { + cx.span_err(expr.span, "malformed #env call"); + } } - p.err("malformed #env call"); - fail; } fn make_new_lit(parser::parser p, common::span sp, ast::lit_ lit) diff --git a/src/test/compile-fail/extenv-no-args.rs b/src/test/compile-fail/extenv-no-args.rs new file mode 100644 index 0000000000000..2503a631c048a --- /dev/null +++ b/src/test/compile-fail/extenv-no-args.rs @@ -0,0 +1,5 @@ +// error-pattern:malformed #env call + +fn main() { + #env(); +} diff --git a/src/test/compile-fail/extenv-not-string-literal.rs b/src/test/compile-fail/extenv-not-string-literal.rs new file mode 100644 index 0000000000000..885924c83781e --- /dev/null +++ b/src/test/compile-fail/extenv-not-string-literal.rs @@ -0,0 +1,5 @@ +// error-pattern:malformed #env call + +fn main() { + #env(10); +} diff --git a/src/test/compile-fail/extenv-too-many-args.rs b/src/test/compile-fail/extenv-too-many-args.rs new file mode 100644 index 0000000000000..e71d0ec3c724e --- /dev/null +++ b/src/test/compile-fail/extenv-too-many-args.rs @@ -0,0 +1,5 @@ +// error-pattern:malformed #env call + +fn main() { + #env("one", "two"); +} From a77cc7f359c8ddbb49b7d7e6f37e4b86b33061f3 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 4 Jun 2011 17:31:44 -0400 Subject: [PATCH 24/64] rustc: Add a next_ann method to ext_ctxt After this we can remove the parser from the syntax extensions, at least for now. --- src/comp/front/ext.rs | 15 ++++++++++++--- src/comp/front/parser.rs | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/comp/front/ext.rs b/src/comp/front/ext.rs index f1c065eeeb46d..0d34c8389cb76 100644 --- a/src/comp/front/ext.rs +++ b/src/comp/front/ext.rs @@ -2,6 +2,7 @@ import std::option; import std::map::hashmap; import driver::session::session; +import front::parser::parser; import util::common::span; import util::common::new_str_hash; @@ -24,13 +25,17 @@ fn syntax_expander_table() -> hashmap[str, syntax_extension] { } type span_msg_fn = fn (span sp, str msg) -> !; +type next_ann_fn = fn () -> ast::ann; // Provides a limited set of services necessary for syntax extensions // to do their thing type ext_ctxt = rec(span_msg_fn span_err, - span_msg_fn span_unimpl); + span_msg_fn span_unimpl, + next_ann_fn next_ann); + +fn mk_ctxt(parser parser) -> ext_ctxt { + auto sess = parser.get_session(); -fn mk_ctxt(session sess) -> ext_ctxt { fn ext_span_err_(session sess, span sp, str msg) -> ! { sess.span_err(sp, msg); } @@ -41,8 +46,12 @@ fn mk_ctxt(session sess) -> ext_ctxt { } auto ext_span_unimpl = bind ext_span_unimpl_(sess, _, _); + fn ext_next_ann_(parser parser) -> ast::ann { parser.get_ann() } + auto ext_next_ann = bind ext_next_ann_(parser); + ret rec(span_err = ext_span_err, - span_unimpl = ext_span_unimpl); + span_unimpl = ext_span_unimpl, + next_ann = ext_next_ann); } // diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index f23a1eece2dc8..1663585971a05 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -1048,7 +1048,7 @@ fn expand_syntax_ext(&parser p, common::span sp, p.err("unknown syntax expander: '" + extname + "'"); } case (some(ext::x(?ext))) { - auto ext_cx = ext::mk_ctxt(p.get_session()); + auto ext_cx = ext::mk_ctxt(p); ret ast::expr_ext(path, args, body, ext(ext_cx, p, sp, args, body), p.get_ann()); From 81899ce5e19d6e91a5f7938fa4908174709910bb Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 4 Jun 2011 17:39:55 -0400 Subject: [PATCH 25/64] rustc: Generate extension annotations from ext_ctxt instead of parser --- src/comp/front/extenv.rs | 18 +++---- src/comp/front/extfmt.rs | 114 ++++++++++++++++++++------------------- 2 files changed, 67 insertions(+), 65 deletions(-) diff --git a/src/comp/front/extenv.rs b/src/comp/front/extenv.rs index d92c5eb7dbd68..a99ef94e07f83 100644 --- a/src/comp/front/extenv.rs +++ b/src/comp/front/extenv.rs @@ -15,7 +15,7 @@ import ext::*; export expand_syntax_ext; -// FIXME: Need to thread parser through here to handle errors correctly + fn expand_syntax_ext(&ext_ctxt cx, &parser::parser p, common::span sp, @@ -29,20 +29,20 @@ fn expand_syntax_ext(&ext_ctxt cx, // FIXME: if this was more thorough it would manufacture an // option::t[str] rather than just an maybe-empty string. - auto var = expr_to_str(cx, p, args.(0)); + auto var = expr_to_str(cx, args.(0)); alt (generic_os::getenv(var)) { case (option::none) { - ret make_new_str(p, sp, ""); + ret make_new_str(cx, sp, ""); } case (option::some(?s)) { - ret make_new_str(p, sp, s); + ret make_new_str(cx, sp, s); } } } // FIXME: duplicate code copied from extfmt: -fn expr_to_str(&ext_ctxt cx, parser::parser p, +fn expr_to_str(&ext_ctxt cx, @ast::expr expr) -> str { alt (expr.node) { case (ast::expr_lit(?l, _)) { @@ -61,16 +61,16 @@ fn expr_to_str(&ext_ctxt cx, parser::parser p, } } -fn make_new_lit(parser::parser p, common::span sp, ast::lit_ lit) +fn make_new_lit(&ext_ctxt cx, common::span sp, ast::lit_ lit) -> @ast::expr { auto sp_lit = @rec(node=lit, span=sp); - auto expr = ast::expr_lit(sp_lit, p.get_ann()); + auto expr = ast::expr_lit(sp_lit, cx.next_ann()); ret @rec(node=expr, span=sp); } -fn make_new_str(parser::parser p, common::span sp, str s) -> @ast::expr { +fn make_new_str(&ext_ctxt cx, common::span sp, str s) -> @ast::expr { auto lit = ast::lit_str(s); - ret make_new_lit(p, sp, lit); + ret make_new_lit(cx, sp, lit); } // diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index ed9636bd163c9..c2f7cd793087a 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -65,59 +65,60 @@ fn expr_to_str(&ext_ctxt cx, @ast::expr expr) -> str { fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, vec[piece] pieces, vec[@ast::expr] args) -> @ast::expr { - fn make_new_lit(parser p, common::span sp, ast::lit_ lit) -> @ast::expr { + fn make_new_lit(&ext_ctxt cx, + common::span sp, ast::lit_ lit) -> @ast::expr { auto sp_lit = @rec(node=lit, span=sp); - auto expr = ast::expr_lit(sp_lit, p.get_ann()); + auto expr = ast::expr_lit(sp_lit, cx.next_ann()); ret @rec(node=expr, span=sp); } - fn make_new_str(parser p, common::span sp, str s) -> @ast::expr { + fn make_new_str(&ext_ctxt cx, common::span sp, str s) -> @ast::expr { auto lit = ast::lit_str(s); - ret make_new_lit(p, sp, lit); + ret make_new_lit(cx, sp, lit); } - fn make_new_int(parser p, common::span sp, int i) -> @ast::expr { + fn make_new_int(&ext_ctxt cx, common::span sp, int i) -> @ast::expr { auto lit = ast::lit_int(i); - ret make_new_lit(p, sp, lit); + ret make_new_lit(cx, sp, lit); } - fn make_new_uint(parser p, common::span sp, uint u) -> @ast::expr { + fn make_new_uint(&ext_ctxt cx, common::span sp, uint u) -> @ast::expr { auto lit = ast::lit_uint(u); - ret make_new_lit(p, sp, lit); + ret make_new_lit(cx, sp, lit); } - fn make_add_expr(parser p, common::span sp, + fn make_add_expr(&ext_ctxt cx, common::span sp, @ast::expr lhs, @ast::expr rhs) -> @ast::expr { - auto binexpr = ast::expr_binary(ast::add, lhs, rhs, p.get_ann()); + auto binexpr = ast::expr_binary(ast::add, lhs, rhs, cx.next_ann()); ret @rec(node=binexpr, span=sp); } - fn make_path_expr(parser p, common::span sp, vec[ast::ident] idents) + fn make_path_expr(&ext_ctxt cx, common::span sp, vec[ast::ident] idents) -> @ast::expr { let vec[@ast::ty] types = []; auto path = rec(idents=idents, types=types); auto sp_path = rec(node=path, span=sp); - auto pathexpr = ast::expr_path(sp_path, p.get_ann()); + auto pathexpr = ast::expr_path(sp_path, cx.next_ann()); auto sp_pathexpr = @rec(node=pathexpr, span=sp); ret sp_pathexpr; } - fn make_vec_expr(parser p, common::span sp, vec[@ast::expr] exprs) + fn make_vec_expr(&ext_ctxt cx, common::span sp, vec[@ast::expr] exprs) -> @ast::expr { - auto vecexpr = ast::expr_vec(exprs, ast::imm, p.get_ann()); + auto vecexpr = ast::expr_vec(exprs, ast::imm, cx.next_ann()); auto sp_vecexpr = @rec(node=vecexpr, span=sp); ret sp_vecexpr; } - fn make_call(parser p, common::span sp, vec[ast::ident] fn_path, + fn make_call(&ext_ctxt cx, common::span sp, vec[ast::ident] fn_path, vec[@ast::expr] args) -> @ast::expr { - auto pathexpr = make_path_expr(p, sp, fn_path); - auto callexpr = ast::expr_call(pathexpr, args, p.get_ann()); + auto pathexpr = make_path_expr(cx, sp, fn_path); + auto callexpr = ast::expr_call(pathexpr, args, cx.next_ann()); auto sp_callexpr = @rec(node=callexpr, span=sp); ret sp_callexpr; } - fn make_rec_expr(parser p, common::span sp, + fn make_rec_expr(&ext_ctxt cx, common::span sp, vec[tup(ast::ident, @ast::expr)] fields) -> @ast::expr { let vec[ast::field] astfields = []; for (tup(ast::ident, @ast::expr) field in fields) { @@ -131,7 +132,7 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, auto recexpr = ast::expr_rec(astfields, option::none[@ast::expr], - p.get_ann()); + cx.next_ann()); auto sp_recexpr = @rec(node=recexpr, span=sp); ret sp_recexpr; } @@ -142,17 +143,18 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, ret ["std", "extfmt", "rt", ident]; } - fn make_rt_path_expr(parser p, common::span sp, str ident) -> @ast::expr { + fn make_rt_path_expr(&ext_ctxt cx, + common::span sp, str ident) -> @ast::expr { auto path = make_path_vec(ident); - ret make_path_expr(p, sp, path); + ret make_path_expr(cx, sp, path); } // Produces an AST expression that represents a RT::conv record, // which tells the RT::conv* functions how to perform the conversion fn make_rt_conv_expr(&ext_ctxt cx, - parser p, common::span sp, &conv cnv) -> @ast::expr { + common::span sp, &conv cnv) -> @ast::expr { - fn make_flags(parser p, common::span sp, vec[flag] flags) + fn make_flags(&ext_ctxt cx, common::span sp, vec[flag] flags) -> @ast::expr { let vec[@ast::expr] flagexprs = []; for (flag f in flags) { @@ -174,30 +176,30 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, fstr = "flag_alternate"; } } - flagexprs += [make_rt_path_expr(p, sp, fstr)]; + flagexprs += [make_rt_path_expr(cx, sp, fstr)]; } // FIXME: 0-length vectors can't have their type inferred // through the rec that these flags are a member of, so // this is a hack placeholder flag if (vec::len[@ast::expr](flagexprs) == 0u) { - flagexprs += [make_rt_path_expr(p, sp, "flag_none")]; + flagexprs += [make_rt_path_expr(cx, sp, "flag_none")]; } - ret make_vec_expr(p, sp, flagexprs); + ret make_vec_expr(cx, sp, flagexprs); } fn make_count(&ext_ctxt cx, - parser p, common::span sp, &count cnt) -> @ast::expr { + common::span sp, &count cnt) -> @ast::expr { alt (cnt) { case (count_implied) { - ret make_rt_path_expr(p, sp, "count_implied"); + ret make_rt_path_expr(cx, sp, "count_implied"); } case (count_is(?c)) { - auto count_lit = make_new_int(p, sp, c); + auto count_lit = make_new_int(cx, sp, c); auto count_is_path = make_path_vec("count_is"); auto count_is_args = [count_lit]; - ret make_call(p, sp, count_is_path, count_is_args); + ret make_call(cx, sp, count_is_path, count_is_args); } case (_) { cx.span_unimpl(sp, "unimplemented #fmt conversion"); @@ -205,7 +207,7 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, } } - fn make_ty(parser p, common::span sp, &ty t) -> @ast::expr { + fn make_ty(&ext_ctxt cx, common::span sp, &ty t) -> @ast::expr { auto rt_type; alt (t) { case (ty_hex(?c)) { @@ -229,26 +231,26 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, } } - ret make_rt_path_expr(p, sp, rt_type); + ret make_rt_path_expr(cx, sp, rt_type); } - fn make_conv_rec(parser p, + fn make_conv_rec(&ext_ctxt cx, common::span sp, @ast::expr flags_expr, @ast::expr width_expr, @ast::expr precision_expr, @ast::expr ty_expr) -> @ast::expr { - ret make_rec_expr(p, sp, [tup("flags", flags_expr), + ret make_rec_expr(cx, sp, [tup("flags", flags_expr), tup("width", width_expr), tup("precision", precision_expr), tup("ty", ty_expr)]); } - auto rt_conv_flags = make_flags(p, sp, cnv.flags); - auto rt_conv_width = make_count(cx, p, sp, cnv.width); - auto rt_conv_precision = make_count(cx, p, sp, cnv.precision); - auto rt_conv_ty = make_ty(p, sp, cnv.ty); - ret make_conv_rec(p, + auto rt_conv_flags = make_flags(cx, sp, cnv.flags); + auto rt_conv_width = make_count(cx, sp, cnv.width); + auto rt_conv_precision = make_count(cx, sp, cnv.precision); + auto rt_conv_ty = make_ty(cx, sp, cnv.ty); + ret make_conv_rec(cx, sp, rt_conv_flags, rt_conv_width, @@ -256,16 +258,16 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, rt_conv_ty); } - fn make_conv_call(&ext_ctxt cx, parser p, common::span sp, str conv_type, + fn make_conv_call(&ext_ctxt cx, common::span sp, str conv_type, &conv cnv, @ast::expr arg) -> @ast::expr { auto fname = "conv_" + conv_type; auto path = make_path_vec(fname); - auto cnv_expr = make_rt_conv_expr(cx, p, sp, cnv); + auto cnv_expr = make_rt_conv_expr(cx, sp, cnv); auto args = [cnv_expr, arg]; - ret make_call(p, arg.span, path, args); + ret make_call(cx, arg.span, path, args); } - fn make_new_conv(&ext_ctxt cx, parser p, common::span sp, + fn make_new_conv(&ext_ctxt cx, common::span sp, conv cnv, @ast::expr arg) -> @ast::expr { // FIXME: Extract all this validation into extfmt::ct @@ -343,32 +345,32 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, alt (cnv.ty) { case (ty_str) { - ret make_conv_call(cx, p, arg.span, "str", cnv, arg); + ret make_conv_call(cx, arg.span, "str", cnv, arg); } case (ty_int(?sign)) { alt (sign) { case (signed) { - ret make_conv_call(cx, p, arg.span, "int", cnv, arg); + ret make_conv_call(cx, arg.span, "int", cnv, arg); } case (unsigned) { - ret make_conv_call(cx, p, arg.span, "uint", cnv, arg); + ret make_conv_call(cx, arg.span, "uint", cnv, arg); } } } case (ty_bool) { - ret make_conv_call(cx, p, arg.span, "bool", cnv, arg); + ret make_conv_call(cx, arg.span, "bool", cnv, arg); } case (ty_char) { - ret make_conv_call(cx, p, arg.span, "char", cnv, arg); + ret make_conv_call(cx, arg.span, "char", cnv, arg); } case (ty_hex(_)) { - ret make_conv_call(cx, p, arg.span, "uint", cnv, arg); + ret make_conv_call(cx, arg.span, "uint", cnv, arg); } case (ty_bits) { - ret make_conv_call(cx, p, arg.span, "uint", cnv, arg); + ret make_conv_call(cx, arg.span, "uint", cnv, arg); } case (ty_octal) { - ret make_conv_call(cx, p, arg.span, "uint", cnv, arg); + ret make_conv_call(cx, arg.span, "uint", cnv, arg); } case (_) { cx.span_unimpl(sp, unsupported); @@ -470,14 +472,14 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, auto fmt_sp = args.(0).span; auto n = 0u; - auto tmp_expr = make_new_str(p, sp, ""); + auto tmp_expr = make_new_str(cx, sp, ""); auto nargs = vec::len[@ast::expr](args); for (piece pc in pieces) { alt (pc) { case (piece_string(?s)) { - auto s_expr = make_new_str(p, fmt_sp, s); - tmp_expr = make_add_expr(p, fmt_sp, tmp_expr, s_expr); + auto s_expr = make_new_str(cx, fmt_sp, s); + tmp_expr = make_add_expr(cx, fmt_sp, tmp_expr, s_expr); } case (piece_conv(?conv)) { n += 1u; @@ -492,8 +494,8 @@ fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, //log_conv(conv); auto arg_expr = args.(n); - auto c_expr = make_new_conv(cx, p, fmt_sp, conv, arg_expr); - tmp_expr = make_add_expr(p, fmt_sp, tmp_expr, c_expr); + auto c_expr = make_new_conv(cx, fmt_sp, conv, arg_expr); + tmp_expr = make_add_expr(cx, fmt_sp, tmp_expr, c_expr); } } } From 6b2a8cd5f623af3d52adf94e0af4669c79066b62 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 4 Jun 2011 17:47:36 -0400 Subject: [PATCH 26/64] rustc: Hide the parser from syntax extensions Eventually extensions will probably need access to the parser again, but it'll be in a different form. --- src/comp/front/ext.rs | 2 +- src/comp/front/extenv.rs | 2 -- src/comp/front/extfmt.rs | 8 +++----- src/comp/front/parser.rs | 2 +- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/comp/front/ext.rs b/src/comp/front/ext.rs index 0d34c8389cb76..d08fc3ef7d5ec 100644 --- a/src/comp/front/ext.rs +++ b/src/comp/front/ext.rs @@ -6,7 +6,7 @@ import front::parser::parser; import util::common::span; import util::common::new_str_hash; -type syntax_expander = fn(&ext_ctxt, &parser::parser, span, +type syntax_expander = fn(&ext_ctxt, span, &vec[@ast::expr], option::t[str]) -> @ast::expr; diff --git a/src/comp/front/extenv.rs b/src/comp/front/extenv.rs index a99ef94e07f83..62e39c8488b40 100644 --- a/src/comp/front/extenv.rs +++ b/src/comp/front/extenv.rs @@ -15,9 +15,7 @@ import ext::*; export expand_syntax_ext; - fn expand_syntax_ext(&ext_ctxt cx, - &parser::parser p, common::span sp, &vec[@ast::expr] args, option::t[str] body) -> @ast::expr { diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index c2f7cd793087a..0b5e399f3323d 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -4,7 +4,6 @@ * compiler syntax extension plugin interface. */ -import front::parser::parser; import util::common; import std::str; @@ -20,7 +19,7 @@ import ext::*; export expand_syntax_ext; fn expand_syntax_ext(&ext_ctxt cx, - &parser p, common::span sp, + common::span sp, &vec[@ast::expr] args, option::t[str] body) -> @ast::expr { @@ -36,7 +35,7 @@ fn expand_syntax_ext(&ext_ctxt cx, auto pieces = parse_fmt_string(fmt); auto args_len = vec::len[@ast::expr](args); auto fmt_args = vec::slice[@ast::expr](args, 1u, args_len - 1u); - ret pieces_to_expr(cx, p, sp, pieces, args); + ret pieces_to_expr(cx, sp, pieces, args); } fn expr_to_str(&ext_ctxt cx, @ast::expr expr) -> str { @@ -60,9 +59,8 @@ fn expr_to_str(&ext_ctxt cx, @ast::expr expr) -> str { // FIXME: A lot of these functions for producing expressions can probably // be factored out in common with other code that builds expressions. -// FIXME: Probably should be using the parser's span functions // FIXME: Cleanup the naming of these functions -fn pieces_to_expr(&ext_ctxt cx, parser p, common::span sp, +fn pieces_to_expr(&ext_ctxt cx, common::span sp, vec[piece] pieces, vec[@ast::expr] args) -> @ast::expr { fn make_new_lit(&ext_ctxt cx, diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 1663585971a05..62ba7325f9999 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -1050,7 +1050,7 @@ fn expand_syntax_ext(&parser p, common::span sp, case (some(ext::x(?ext))) { auto ext_cx = ext::mk_ctxt(p); ret ast::expr_ext(path, args, body, - ext(ext_cx, p, sp, args, body), + ext(ext_cx, sp, args, body), p.get_ann()); } } From 6689e577bbf9eb7e9c00b37e1fece7d95c848a34 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 4 Jun 2011 17:53:17 -0400 Subject: [PATCH 27/64] rustc: Reenable debug logging in extfmt This is not obnoxious now that logging is off by default --- src/comp/front/extfmt.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index 0b5e399f3323d..1856b81ce584e 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -29,8 +29,8 @@ fn expand_syntax_ext(&ext_ctxt cx, auto fmt = expr_to_str(cx, args.(0)); - // log "Format string:"; - // log fmt; + log "Format string:"; + log fmt; auto pieces = parse_fmt_string(fmt); auto args_len = vec::len[@ast::expr](args); @@ -465,6 +465,9 @@ fn pieces_to_expr(&ext_ctxt cx, common::span sp, } } } + case (ty_octal) { + log "type: octal"; + } } } @@ -487,9 +490,8 @@ fn pieces_to_expr(&ext_ctxt cx, common::span sp, + "for the given format string"); } - // TODO: Remove debug logging - //log "Building conversion:"; - //log_conv(conv); + log "Building conversion:"; + log_conv(conv); auto arg_expr = args.(n); auto c_expr = make_new_conv(cx, fmt_sp, conv, arg_expr); @@ -505,9 +507,6 @@ fn pieces_to_expr(&ext_ctxt cx, common::span sp, nargs, expected_nargs)); } - // TODO: Remove this debug logging - // log "dumping expanded ast:"; - // log pretty::print_expr(tmp_expr); ret tmp_expr; } From 5a9aa5fd27650479f6597e12ca557a85d178445a Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 4 Jun 2011 18:23:06 -0400 Subject: [PATCH 28/64] stdlib: Use spans for #fmt errors originating in std Issue #444 --- src/comp/front/extfmt.rs | 8 ++++++- src/lib/extfmt.rs | 22 ++++++++++--------- src/test/compile-fail/extfmt-missing-type.rs | 5 +++++ src/test/compile-fail/extfmt-unknown-type.rs | 5 +++++ .../compile-fail/extfmt-unterminated-conv.rs | 5 +++++ 5 files changed, 34 insertions(+), 11 deletions(-) create mode 100644 src/test/compile-fail/extfmt-missing-type.rs create mode 100644 src/test/compile-fail/extfmt-unknown-type.rs create mode 100644 src/test/compile-fail/extfmt-unterminated-conv.rs diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index 1856b81ce584e..c3d4fffcbab86 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -28,11 +28,17 @@ fn expand_syntax_ext(&ext_ctxt cx, } auto fmt = expr_to_str(cx, args.(0)); + auto fmtspan = args.(0).span; log "Format string:"; log fmt; - auto pieces = parse_fmt_string(fmt); + fn parse_fmt_err_(&ext_ctxt cx, common::span sp, str msg) -> ! { + cx.span_err(sp, msg); + } + + auto parse_fmt_err = bind parse_fmt_err_(cx, fmtspan, _); + auto pieces = parse_fmt_string(fmt, parse_fmt_err); auto args_len = vec::len[@ast::expr](args); auto fmt_args = vec::slice[@ast::expr](args, 1u, args_len - 1u); ret pieces_to_expr(cx, sp, pieces, args); diff --git a/src/lib/extfmt.rs b/src/lib/extfmt.rs index 2df831c0cab73..43ff490757b3d 100644 --- a/src/lib/extfmt.rs +++ b/src/lib/extfmt.rs @@ -78,7 +78,9 @@ mod ct { piece_conv(conv); } - fn parse_fmt_string(str s) -> vec[piece] { + type error_fn = fn (str) -> !; + + fn parse_fmt_string(str s, error_fn error) -> vec[piece] { let vec[piece] pieces = []; auto lim = str::byte_len(s); auto buf = ""; @@ -97,15 +99,14 @@ mod ct { if (str::eq(curr, "%")) { i += 1u; if (i >= lim) { - log_err "unterminated conversion at end of string"; - fail; + error("unterminated conversion at end of string"); } auto curr2 = str::substr(s, i, 1u); if (str::eq(curr2, "%")) { i += 1u; } else { buf = flush_buf(buf, pieces); - auto res = parse_conversion(s, i, lim); + auto res = parse_conversion(s, i, lim, error); pieces += [res._0]; i = res._1; } @@ -141,12 +142,13 @@ mod ct { }; } - fn parse_conversion(str s, uint i, uint lim) -> tup(piece, uint) { + fn parse_conversion(str s, uint i, uint lim, + error_fn error) -> tup(piece, uint) { auto parm = parse_parameter(s, i, lim); auto flags = parse_flags(s, parm._1, lim); auto width = parse_count(s, flags._1, lim); auto prec = parse_precision(s, width._1, lim); - auto ty = parse_type(s, prec._1, lim); + auto ty = parse_type(s, prec._1, lim, error); ret tup(piece_conv(rec(param = parm._0, flags = flags._0, width = width._0, @@ -258,10 +260,9 @@ mod ct { }; } - fn parse_type(str s, uint i, uint lim) -> tup(ty, uint) { + fn parse_type(str s, uint i, uint lim, error_fn error) -> tup(ty, uint) { if (i >= lim) { - log_err "missing type in conversion"; - fail; + error("missing type in conversion"); } auto tstr = str::substr(s, i, 1u); @@ -287,7 +288,8 @@ mod ct { } else if (str::eq(tstr, "o")) { ty_octal } else { - log_err "unknown type in conversion"; + // FIXME: Shouldn't need explicit fail here. Issue #542 + error("unknown type in conversion: " + tstr); fail }; diff --git a/src/test/compile-fail/extfmt-missing-type.rs b/src/test/compile-fail/extfmt-missing-type.rs new file mode 100644 index 0000000000000..8f82e3317e19e --- /dev/null +++ b/src/test/compile-fail/extfmt-missing-type.rs @@ -0,0 +1,5 @@ +// error-pattern:missing type + +fn main() { + #fmt("%+"); +} diff --git a/src/test/compile-fail/extfmt-unknown-type.rs b/src/test/compile-fail/extfmt-unknown-type.rs new file mode 100644 index 0000000000000..08d5da0a496a6 --- /dev/null +++ b/src/test/compile-fail/extfmt-unknown-type.rs @@ -0,0 +1,5 @@ +// error-pattern:unknown type + +fn main() { + #fmt("%w"); +} diff --git a/src/test/compile-fail/extfmt-unterminated-conv.rs b/src/test/compile-fail/extfmt-unterminated-conv.rs new file mode 100644 index 0000000000000..8c75c75f9fda4 --- /dev/null +++ b/src/test/compile-fail/extfmt-unterminated-conv.rs @@ -0,0 +1,5 @@ +// error-pattern:unterminated conversion + +fn main() { + #fmt("%"); +} From ba0044aad0a45bd1a62a5b490234f9f6050a1149 Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Sat, 4 Jun 2011 18:13:00 -0700 Subject: [PATCH 29/64] Remove redundant 'fail' exprs and dead code; use sess.bug or sess.span_err instead of 'fail'. (issue #444) --- src/comp/middle/resolve.rs | 12 +++---- src/comp/middle/trans.rs | 69 ++++++++++++-------------------------- src/comp/middle/ty.rs | 3 -- src/comp/middle/typeck.rs | 10 +----- 4 files changed, 27 insertions(+), 67 deletions(-) diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index f7ff7fdde7b2e..56d8d3450ae03 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -308,7 +308,6 @@ fn resolve_names(&@env e, &ast::crate c) { case (_) { e.sess.span_err(p.span, "not a tag variant: " + str::connect(p.node.idents, "::")); - fail; } } for (@ast::pat child in children) { @@ -412,7 +411,6 @@ fn follow_import(&env e, &list[scope] sc, vec[ident] path, &span sp) case (_) { e.sess.span_err(sp, str::connect(path, "::") + " does not name a module."); - fail; } } } @@ -508,12 +506,13 @@ fn lookup_in_scope_strict(&env e, list[scope] sc, &span sp, &ident id, alt (lookup_in_scope(e, sc, sp, id, ns)) { case (none) { unresolved(e, sp, id, ns_name(ns)); - fail; } case (some(?d)) { ret d; } } + + fail; // fools the return-checker } fn scope_is_fn(&scope sc) -> bool { @@ -640,7 +639,6 @@ fn lookup_in_scope(&env e, list[scope] sc, &span sp, &ident id, namespace ns) } } e.sess.bug("reached unreachable code in lookup_in_scope"); // sigh - fail; } fn lookup_in_ty_params(&ident id, &vec[ast::ty_param] ty_params) @@ -790,12 +788,13 @@ fn lookup_in_mod_strict(&env e, def m, &span sp, &ident id, alt (lookup_in_mod(e, m, sp, id, ns, dr)) { case (none) { unresolved(e, sp, id, ns_name(ns)); - fail; } case (some(?d)) { ret d; } } + + fail; // fools the return-checker } fn lookup_in_mod(&env e, def m, &span sp, &ident id, namespace ns, dir dr) @@ -855,7 +854,7 @@ fn lookup_import(&env e, def_id defid, namespace ns) -> option::t[def] { case (ns_module) { md } }; } } - fail; + fail; // fools the return-checker } @@ -915,7 +914,6 @@ fn lookup_glob_in_mod(&env e, @indexed_mod info, &span sp, } e.sess.span_err(sp, "'" + id + "' is glob-imported from" + " multiple different modules."); - fail; } } // since we don't know what names we have in advance, diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 975f3a7eb26c0..a5ec52b40c8bd 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -715,7 +715,6 @@ fn type_of(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef { cx.sess.span_err (sp, "type_of() called on a type with dynamic size: " + ty::ty_to_str(cx.tcx, t)); - fail; } ret type_of_inner(cx, sp, t); @@ -937,14 +936,14 @@ fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef { llty = abs_pair; } case (ty::ty_var(_)) { - cx.tcx.sess.span_err(sp, "ty_var in trans::type_of"); + cx.tcx.sess.span_err(sp, "trans::type_of called on ty_var"); } case (ty::ty_param(_)) { llty = T_i8(); } case (ty::ty_bound_param(_)) { - log_err "ty_bound_param in trans::type_of"; - fail; + cx.tcx.sess.span_err(sp, + "trans::type_of called on ty_bound_param"); } case (ty::ty_type) { llty = T_ptr(T_tydesc(cx.tn)); } } @@ -1212,21 +1211,12 @@ fn find_scope_cx(&@block_ctxt cx) -> @block_ctxt { be find_scope_cx(b); } case (parent_none) { - fail; + cx.fcx.lcx.ccx.sess.bug("trans::find_scope_cx() " + + "called on parentless block_ctxt"); } } -} -fn find_outer_scope_cx(&@block_ctxt cx) -> @block_ctxt { - auto scope_cx = find_scope_cx(cx); - alt (cx.parent) { - case (parent_some(?b)) { - be find_scope_cx(b); - } - case (parent_none) { - fail; - } - } + fail; // fools the return-checker } fn umax(&@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef { @@ -1320,8 +1310,8 @@ fn simplify_type(&@crate_ctxt ccx, &ty::t typ) -> ty::t { // Computes the size of the data part of a non-dynamically-sized tag. fn static_size_of_tag(&@crate_ctxt cx, &span sp, &ty::t t) -> uint { if (ty::type_has_dynamic_size(cx.tcx, t)) { - log_err "dynamically sized type passed to static_size_of_tag()"; - fail; + cx.tcx.sess.span_err(sp, "dynamically sized type passed to " + + "static_size_of_tag()"); } if (cx.tag_sizes.contains_key(t)) { @@ -1336,8 +1326,8 @@ fn static_size_of_tag(&@crate_ctxt cx, &span sp, &ty::t t) -> uint { subtys = subtys_; } case (_) { - log_err "non-tag passed to static_size_of_tag()"; - fail; + cx.tcx.sess.span_err(sp, "non-tag passed to " + + "static_size_of_tag()"); } } @@ -2570,7 +2560,8 @@ fn make_scalar_cmp_glue(&@block_ctxt cx, ValueRef lhs, ValueRef rhs, } case (_) { // Should never get here, because t is scalar. - fail; + cx.fcx.lcx.ccx.sess.bug("non-scalar type passed to " + + "make_scalar_cmp_glue"); } } } @@ -2812,7 +2803,6 @@ fn iter_structural_ty_full(&@block_ctxt cx, j += 1; } } - case (_) { fail; } } variant_cx.build.Br(next_cx.llbb); @@ -2984,7 +2974,6 @@ fn iter_sequence(@block_ctxt cx, cx.fcx.lcx.ccx.sess.bug("unexpected type in " + "trans::iter_sequence: " + ty::ty_to_str(cx.fcx.lcx.ccx.tcx, t)); - fail; } } } @@ -3329,7 +3318,6 @@ fn copy_val(&@block_ctxt cx, cx.fcx.lcx.ccx.sess.bug("unexpected type in trans::copy_val: " + ty::ty_to_str(cx.fcx.lcx.ccx.tcx, t)); - fail; } // This works like copy_val, except that it deinitializes the source. @@ -3367,7 +3355,6 @@ fn move_val(&@block_ctxt cx, cx.fcx.lcx.ccx.sess.bug("unexpected type in trans::move_val: " + ty::ty_to_str(cx.fcx.lcx.ccx.tcx, t)); - fail; } @@ -3490,12 +3477,11 @@ fn trans_unary(&@block_ctxt cx, ast::unop op, ret res(sub.bcx, box); } case (ast::deref) { - log_err "deref expressions should have been translated using " + - "trans_lval(), not trans_unary()"; - fail; + cx.fcx.lcx.ccx.sess.bug("deref expressions should have been " + + "translated using trans_lval(), not " + + "trans_unary()"); } } - fail; } fn trans_compare(&@block_ctxt cx0, ast::binop op, &ty::t t0, @@ -3659,7 +3645,6 @@ fn trans_eager_binop(&@block_ctxt cx, ast::binop op, &ty::t intype, ret trans_compare(cx, op, intype, lhs, rhs); } } - fail; } fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result { @@ -3783,7 +3768,6 @@ fn trans_binary(&@block_ctxt cx, ast::binop op, autoderefed_ty(cx.fcx.lcx.ccx, lhty), lhs.val, rhs.val); } } - fail; } fn join_results(&@block_ctxt parent_cx, @@ -4211,7 +4195,6 @@ fn trans_for_each(&@block_ctxt cx, ret res(r.bcx, C_nil()); } } - fail; } @@ -4325,8 +4308,6 @@ fn trans_pat_match(&@block_ctxt cx, &@ast::pat pat, ValueRef llval, ret res(matched_cx, llval); } } - - fail; } fn trans_pat_binding(&@block_ctxt cx, &@ast::pat pat, @@ -4650,7 +4631,6 @@ fn trans_field(&@block_ctxt cx, &span sp, ValueRef v, &ty::t t0, } case (_) {cx.fcx.lcx.ccx.sess.unimpl("field variant in trans_field");} } - fail; } fn trans_index(&@block_ctxt cx, &span sp, &@ast::expr base, @@ -4747,7 +4727,9 @@ fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result { } case (_) { // Shouldn't happen. - fail; + cx.fcx.lcx.ccx.sess.bug( + "trans_lval called on expr_self_method in a context" + + "without llself"); } } @@ -4758,7 +4740,6 @@ fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result { + pretty::pprust::expr_to_str(e)); } } - fail; } fn int_cast(&@block_ctxt bcx, TypeRef lldsttype, TypeRef llsrctype, @@ -5898,7 +5879,6 @@ fn trans_log(int lvl, &@block_ctxt cx, &@ast::expr e) -> result { cx.fcx.lcx.ccx.sess.span_err(e.span, "log called on unsupported type " + ty::ty_to_str(cx.fcx.lcx.ccx.tcx, e_ty)); - fail; } } } @@ -6017,7 +5997,9 @@ fn trans_break_cont(&@block_ctxt cx, bool to_end) -> result { } } } - fail; + + // If we get here without returning, it's a bug + cx.fcx.lcx.ccx.sess.bug("in trans::trans_break_cont()"); } fn trans_break(&@block_ctxt cx) -> result { @@ -6085,7 +6067,6 @@ fn trans_port(&@block_ctxt cx, &ast::ann ann) -> result { } case (_) { cx.fcx.lcx.ccx.sess.bug("non-port type in trans_port"); - fail; } } @@ -6310,7 +6291,6 @@ fn trans_send(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs, } case (_) { bcx.fcx.lcx.ccx.sess.bug("non-chan type in trans_send"); - fail; } } @@ -6432,7 +6412,6 @@ fn trans_anon_obj(&@block_ctxt cx, &span sp, // TODO: everything else. cx.fcx.lcx.ccx.sess.unimpl("support for anonymous objects"); - fail; } fn init_local(&@block_ctxt cx, &@ast::local local) -> result { @@ -6917,7 +6896,6 @@ fn arg_tys_of_fn(&@crate_ctxt ccx, ast::ann ann) -> vec[ty::arg] { ret arg_tys; } } - fail; } fn ret_ty_of_fn_ty(&@crate_ctxt ccx, ty::t t) -> ty::t { @@ -6926,7 +6904,6 @@ fn ret_ty_of_fn_ty(&@crate_ctxt ccx, ty::t t) -> ty::t { ret ret_ty; } } - fail; } @@ -7515,7 +7492,6 @@ fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, } case (_) { ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!"); - fail; } } @@ -7558,7 +7534,6 @@ fn native_fn_ty_param_count(&@crate_ctxt cx, &ast::def_id id) -> uint { case (ast::native_item_ty(_,_)) { cx.sess.bug("decl_native_fn_and_pair(): native fn isn't " + "actually a fn?!"); - fail; } case (ast::native_item_fn(_, _, _, ?tps, _, _)) { count = vec::len[ast::ty_param](tps); @@ -7574,7 +7549,6 @@ fn native_fn_wrapper_type(&@crate_ctxt cx, &span sp, uint ty_param_count, ret type_of_fn(cx, sp, ast::proto_fn, args, out, ty_param_count); } } - fail; } fn decl_native_fn_and_pair(&@crate_ctxt ccx, @@ -8013,7 +7987,6 @@ fn find_main_fn(&@crate_ctxt cx) -> ValueRef { cx.sess.err("multiple main fns found"); } } - fail; } fn trans_main_fn(@local_ctxt cx, ValueRef crate_map) { diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index d10cbd338ade5..6dd5ae76ff912 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -1895,7 +1895,6 @@ fn field_idx(&session::session sess, &span sp, i += 1u; } sess.span_err(sp, "unknown field '" + id + "' of record"); - fail; } fn method_idx(&session::session sess, &span sp, @@ -1908,7 +1907,6 @@ fn method_idx(&session::session sess, &span sp, i += 1u; } sess.span_err(sp, "unknown method '" + id + "' of obj"); - fail; } fn sort_methods(&vec[method] meths) -> vec[method] { @@ -2904,7 +2902,6 @@ fn tag_variants(&ctxt cx, &ast::def_id id) -> vec[variant_info] { } } } - fail; // not reached } // Returns information about the tag variant with the given ID: diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index b93e0765d0d0b..c373c27fc18a9 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -102,7 +102,6 @@ fn substitute_ty_params(&@crate_ctxt ccx, uint::to_str(ty_param_count, 10u) + " type parameter(s) but found " + uint::to_str(supplied_len, 10u) + " parameter(s)"); - fail; } if (!ty::type_contains_bound_params(ccx.tcx, typ)) { @@ -162,13 +161,11 @@ fn ty_param_count_and_ty_for_def(&@fn_ctxt fcx, &span sp, &ast::def defn) case (ast::def_ty(_)) { fcx.ccx.tcx.sess.span_err(sp, "expected value but found type"); - fail; } case (_) { // FIXME: handle other names. fcx.ccx.tcx.sess.unimpl("definition variant"); - fail; } } } @@ -332,7 +329,7 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { case (_) { tcx.sess.span_err(ast_ty.span, "found type name used as a variable"); - fail; } + } } cname = some(path_to_str(path)); @@ -1041,7 +1038,6 @@ mod demand { // TODO: In the future, try returning "expected", reporting // the error, and continue. - fail; } } } @@ -1437,7 +1433,6 @@ mod pushdown { scx.fcx.ccx.tcx.sess.span_unimpl(e.span, #fmt("type unification for expression variant: %s", pretty::pprust::expr_to_str(e))); - fail; } } } @@ -1468,7 +1463,6 @@ mod writeback { case (none) { fcx.ccx.tcx.sess.span_err(sp, "unable to determine type of local: " + local.ident); - fail; } case (some(?lt)) { local_ty = lt; @@ -1774,7 +1768,6 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { + " instead having: " + ty_to_str(scx.fcx.ccx.tcx, expr_ty(scx.fcx.ccx.tcx, f))); - fail; } } @@ -1903,7 +1896,6 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { if (vec::len[@ast::ty](pth.node.types) > 0u) { scx.fcx.ccx.tcx.sess.span_err(expr.span, "this kind of value does not take type parameters"); - fail; } write::ty_only_fixup(scx, old_ann.id, tpt._1); From 103317dacc61691e675cf690755b619434d971ec Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Sat, 4 Jun 2011 19:38:11 -0700 Subject: [PATCH 30/64] Adding comments; removing dead code. --- src/comp/middle/trans.rs | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index a5ec52b40c8bd..9ffc6d429c0a3 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -7231,15 +7231,16 @@ fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::def_id oid, typarams_ty, fields_ty]); - // Hand this thing we've constructed off to trans_malloc_boxed, which - // makes space for the refcount. + // Hand this type we've synthesized off to trans_malloc_boxed, which + // allocates a box, including space for a refcount. auto box = trans_malloc_boxed(bcx, body_ty); bcx = box.bcx; - // And mk_imm_box throws a refcount into the type we're synthesizing: - // [rc, [tydesc_ty, [typaram, ...], [field, ...]]] + // mk_imm_box throws a refcount into the type we're synthesizing, so + // that it looks like: [rc, [tydesc_ty, [typaram, ...], [field, ...]]] let ty::t boxed_body_ty = ty::mk_imm_box(ccx.tcx, body_ty); + // Grab onto the refcount and body parts of the box we allocated. auto rc = GEP_tup_like(bcx, boxed_body_ty, box.val, [0, abi::box_rc_field_refcnt]); @@ -7253,6 +7254,12 @@ fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::def_id oid, // Put together a tydesc for the body, so that the object can later be // freed by calling through its tydesc. + + // Every object (not just those with type parameters) needs to have a + // tydesc to describe its body, since all objects have unknown type to + // the user of the object. So the tydesc is needed to keep track of + // the types of the object's fields, so that the fields can be freed + // later. auto body_tydesc = GEP_tup_like(bcx, body_ty, body.val, [0, abi::obj_body_elt_tydesc]); @@ -7263,17 +7270,16 @@ fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::def_id oid, lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti); lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti); - auto dtor = C_null(T_ptr(T_glue_fn(ccx.tn))); - alt (ob.dtor) { - case (some(?d)) { - dtor = trans_dtor(cx, llself_ty, self_ty, ty_params, d); - } - case (none) {} - } - bcx = body_td.bcx; bcx.build.Store(body_td.val, body_tydesc.val); + // Copy the object's type parameters and fields into the space we + // allocated for the object body. (This is something like saving the + // lexical environment of a function in its closure: the "captured + // typarams" are any type parameters that are passed to the object + // constructor and are then available to the object's methods. + // Likewise for the object's fields.) + // Copy typarams into captured typarams. auto body_typarams = GEP_tup_like(bcx, body_ty, body.val, From bcfa0d16cdd0a678a4340b3ee73ff01a5f5688a3 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 5 Jun 2011 00:11:17 -0400 Subject: [PATCH 31/64] rustc: Make resolve::unresolved return !. Remove redundant fails --- src/comp/middle/resolve.rs | 7 +------ src/comp/middle/trans.rs | 2 -- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index 56d8d3450ae03..12dd167e635c5 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -481,7 +481,7 @@ fn ns_name(namespace ns) -> str { } } -fn unresolved(&env e, &span sp, &ident id, &str kind) { +fn unresolved(&env e, &span sp, &ident id, &str kind) -> ! { e.sess.span_err(sp, "unresolved " + kind + ": " + id); } @@ -511,8 +511,6 @@ fn lookup_in_scope_strict(&env e, list[scope] sc, &span sp, &ident id, ret d; } } - - fail; // fools the return-checker } fn scope_is_fn(&scope sc) -> bool { @@ -793,8 +791,6 @@ fn lookup_in_mod_strict(&env e, def m, &span sp, &ident id, ret d; } } - - fail; // fools the return-checker } fn lookup_in_mod(&env e, def m, &span sp, &ident id, namespace ns, dir dr) @@ -854,7 +850,6 @@ fn lookup_import(&env e, def_id defid, namespace ns) -> option::t[def] { case (ns_module) { md } }; } } - fail; // fools the return-checker } diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 9ffc6d429c0a3..0db0413005207 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -1215,8 +1215,6 @@ fn find_scope_cx(&@block_ctxt cx) -> @block_ctxt { + "called on parentless block_ctxt"); } } - - fail; // fools the return-checker } fn umax(&@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef { From 3d165ba50236dba5bc673f8a47581f6a94cd53ff Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 6 Jun 2011 20:23:35 +0200 Subject: [PATCH 32/64] Change unsafe aliases This litters aberrations like 'alt({foo.bar}) { ... }' and f({*baz}) though the code (mostly in trans.rs). These are a way to explicitly copy the given value so that it can be safely aliased. At some point we'll probably want a more explicit copy operator. --- src/comp/middle/resolve.rs | 34 +++++++++++------------ src/comp/middle/trans.rs | 57 ++++++++++++++++++++------------------ src/comp/middle/ty.rs | 2 +- src/comp/middle/typeck.rs | 8 ++++-- 4 files changed, 53 insertions(+), 48 deletions(-) diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index 12dd167e635c5..8ec4dfe6297ef 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -150,7 +150,7 @@ fn map_crate(&@env e, &ast::crate c) { fn index_vi(@env e, @mutable list[scope] sc, &@ast::view_item i) { alt (i.node) { case (ast::view_item_import(_, ?ids, ?defid)) { - e.imports.insert(defid._1, todo(i, *sc)); + e.imports.insert(defid._1, todo(i, {*sc})); } case (_) {} } @@ -231,7 +231,7 @@ fn map_crate(&@env e, &ast::crate c) { //if it really is a glob import, that is case (ast::view_item_import_glob(?path, _)) { find_mod(e, *sc).glob_imports - += [follow_import(*e, *sc, path, vi.span)]; + += [follow_import(*e, {*sc}, path, vi.span)]; } case (_) {} } @@ -275,8 +275,8 @@ fn resolve_names(&@env e, &ast::crate c) { push_env_for_expr(sc, exp); alt (exp.node) { case (ast::expr_path(?p, ?a)) { - auto df = lookup_path_strict(*e, *sc, exp.span, p.node.idents, - ns_value); + auto df = lookup_path_strict(*e, {*sc}, exp.span, + p.node.idents, ns_value); e.def_map.insert(a.id, df); } case (_) {} @@ -285,7 +285,7 @@ fn resolve_names(&@env e, &ast::crate c) { fn walk_ty(@env e, @mutable list[scope] sc, &@ast::ty t) { alt (t.node) { case (ast::ty_path(?p, ?a)) { - auto new_def = lookup_path_strict(*e, *sc, t.span, + auto new_def = lookup_path_strict(*e, {*sc}, t.span, p.node.idents, ns_type); e.def_map.insert(a.id, new_def); } @@ -293,7 +293,7 @@ fn resolve_names(&@env e, &ast::crate c) { } } fn walk_arm(@env e, @mutable list[scope] sc, &ast::arm a) { - walk_pat(*e, *sc, a.pat); + walk_pat(*e, {*sc}, a.pat); push_env_for_arm(sc, a); } fn walk_pat(&env e, &list[scope] sc, &@ast::pat pat) { @@ -325,14 +325,14 @@ fn push_env_for_crate(@mutable list[scope] sc, &ast::crate c) { *sc = cons[scope](scope_crate(@c), @*sc); } fn pop_env_for_crate(@mutable list[scope] sc, &ast::crate c) { - *sc = std::list::cdr(*sc); + *sc = std::list::cdr({*sc}); } fn push_env_for_item(@mutable list[scope] sc, &@ast::item i) { *sc = cons[scope](scope_item(i), @*sc); } fn pop_env_for_item(@mutable list[scope] sc, &@ast::item i) { - *sc = std::list::cdr(*sc); + *sc = std::list::cdr({*sc}); } fn push_env_for_method(@mutable list[scope] sc, &@ast::method m) { @@ -346,21 +346,21 @@ fn push_env_for_method(@mutable list[scope] sc, &@ast::method m) { *sc = cons[scope](scope_item(i), @*sc); } fn pop_env_for_method(@mutable list[scope] sc, &@ast::method m) { - *sc = std::list::cdr(*sc); + *sc = std::list::cdr({*sc}); } fn push_env_for_n_item(@mutable list[scope] sc, &@ast::native_item i) { *sc = cons[scope](scope_native_item(i), @*sc); } fn pop_env_for_n_item(@mutable list[scope] sc, &@ast::native_item i) { - *sc = std::list::cdr(*sc); + *sc = std::list::cdr({*sc}); } fn push_env_for_block(@mutable list[scope] sc, &ast::block b) { *sc = cons[scope](scope_block(b), @*sc); } fn pop_env_for_block(@mutable list[scope] sc, &ast::block b) { - *sc = std::list::cdr(*sc); + *sc = std::list::cdr({*sc}); } fn push_env_for_expr(@mutable list[scope] sc, &@ast::expr x) { @@ -377,10 +377,10 @@ fn push_env_for_expr(@mutable list[scope] sc, &@ast::expr x) { fn pop_env_for_expr(@mutable list[scope] sc, &@ast::expr x) { alt (x.node) { case (ast::expr_for(?d, _, _, _)) { - *sc = std::list::cdr(*sc); + *sc = std::list::cdr({*sc}); } case (ast::expr_for_each(?d, _, _, _)) { - *sc = std::list::cdr(*sc); + *sc = std::list::cdr({*sc}); } case (_) {} } @@ -390,7 +390,7 @@ fn push_env_for_arm(@mutable list[scope] sc, &ast::arm p) { *sc = cons[scope](scope_arm(p), @*sc); } fn pop_env_for_arm(@mutable list[scope] sc, &ast::arm p) { - *sc = std::list::cdr(*sc); + *sc = std::list::cdr({*sc}); } fn follow_import(&env e, &list[scope] sc, vec[ident] path, &span sp) @@ -613,7 +613,7 @@ fn lookup_in_scope(&env e, list[scope] sc, &span sp, &ident id, namespace ns) // Used to determine whether obj fields are in scope auto left_fn_level2 = false; while (true) { - alt (sc) { + alt ({sc}) { case (nil) { ret none[def]; } @@ -869,7 +869,7 @@ fn lookup_in_local_mod(&env e, def_id defid, &span sp, case (none) { } case (some(?lst)) { while (true) { - alt (lst) { + alt ({lst}) { case (nil) { break; } case (cons(?hd, ?tl)) { auto found = lookup_in_mie(e, hd, ns); @@ -1126,7 +1126,7 @@ fn check_mod_name(&env e, &ident name, &list[mod_index_entry] entries) { } while (true) { - alt (entries) { + alt ({entries}) { case (cons(?entry, ?rest)) { if (!option::is_none(lookup_in_mie(e, entry, ns_value))) { if (saw_value) { dup(e, mie_span(entry), "", name); } diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 0db0413005207..61de9459fac4a 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -150,7 +150,7 @@ type val_self_pair = rec(ValueRef v, ty::t t); type ty_self_pair = tup(TypeRef, ty::t); // Function context. Every LLVM function we create will have one of these. -state type fn_ctxt = rec( +type fn_ctxt = rec( // The ValueRef returned from a call to llvm::LLVMAddFunction; the address // of the first instruction in the sequence of instructions for this // function that will go in the .text section of the executable we're @@ -305,8 +305,8 @@ tag block_parent { } -state type result = rec(mutable @block_ctxt bcx, - mutable ValueRef val); +state type result = rec(@block_ctxt bcx, + ValueRef val); fn sep() -> str { ret "_"; @@ -364,8 +364,8 @@ fn mangle_name_by_seq(&@crate_ctxt ccx, &vec[str] path, } fn res(@block_ctxt bcx, ValueRef val) -> result { - ret rec(mutable bcx = bcx, - mutable val = val); + ret rec(bcx = bcx, + val = val); } fn ty_str(type_names tn, TypeRef t) -> str { @@ -2019,7 +2019,7 @@ fn emit_tydescs(&@crate_ctxt ccx) { auto ti = pair._1; - auto take_glue = alt (ti.take_glue) { + auto take_glue = alt ({ti.take_glue}) { case (none) { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) @@ -2030,7 +2030,7 @@ fn emit_tydescs(&@crate_ctxt ccx) { } }; - auto drop_glue = alt (ti.drop_glue) { + auto drop_glue = alt ({ti.drop_glue}) { case (none) { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) @@ -2041,7 +2041,7 @@ fn emit_tydescs(&@crate_ctxt ccx) { } }; - auto free_glue = alt (ti.free_glue) { + auto free_glue = alt ({ti.free_glue}) { case (none) { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) @@ -2052,7 +2052,7 @@ fn emit_tydescs(&@crate_ctxt ccx) { } }; - auto cmp_glue = alt (ti.cmp_glue) { + auto cmp_glue = alt ({ti.cmp_glue}) { case (none) { ccx.stats.n_null_glues += 1u; C_null(cmp_fn_ty) @@ -2998,7 +2998,7 @@ fn lazily_emit_tydesc_glue(&@block_ctxt cx, int field, case (some(?ti)) { if(field == abi::tydesc_field_take_glue) { - alt (ti.take_glue) { + alt ({ti.take_glue}) { case (some(_)) {} case (none) { log #fmt("+++ lazily_emit_tydesc_glue TAKE %s", @@ -3019,7 +3019,7 @@ fn lazily_emit_tydesc_glue(&@block_ctxt cx, int field, } } } else if (field == abi::tydesc_field_drop_glue) { - alt (ti.drop_glue) { + alt ({ti.drop_glue}) { case (some(_)) { } case (none) { log #fmt("+++ lazily_emit_tydesc_glue DROP %s", @@ -3039,7 +3039,7 @@ fn lazily_emit_tydesc_glue(&@block_ctxt cx, int field, } } else if (field == abi::tydesc_field_free_glue) { - alt (ti.free_glue) { + alt ({ti.free_glue}) { case (some(_)) { } case (none) { log #fmt("+++ lazily_emit_tydesc_glue FREE %s", @@ -3060,7 +3060,7 @@ fn lazily_emit_tydesc_glue(&@block_ctxt cx, int field, } } else if (field == abi::tydesc_field_cmp_glue) { - alt (ti.cmp_glue) { + alt ({ti.cmp_glue}) { case (some(_)) { } case (none) { log #fmt("+++ lazily_emit_tydesc_glue CMP %s", @@ -3931,7 +3931,7 @@ fn trans_for(&@block_ctxt cx, fn collect_upvars(&@block_ctxt cx, &ast::block bloc, &ast::def_id initial_decl) -> vec[ast::def_id] { type env = @rec( - mutable vec[ast::def_id] refs, + vec[ast::def_id] refs, hashmap[ast::def_id,()] decls, resolve::def_map def_map ); @@ -3965,7 +3965,7 @@ fn collect_upvars(&@block_ctxt cx, &ast::block bloc, let vec[ast::def_id] refs = []; let hashmap[ast::def_id,()] decls = new_def_hash[()](); decls.insert(initial_decl, ()); - let env e = @rec(mutable refs=refs, + let env e = @rec(refs=refs, decls=decls, def_map=cx.fcx.lcx.ccx.tcx.def_map); @@ -4717,7 +4717,7 @@ fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result { ret lval_mem(sub.bcx, val); } case (ast::expr_self_method(?ident, ?ann)) { - alt (cx.fcx.llself) { + alt ({cx.fcx.llself}) { case (some(?pair)) { auto r = pair.v; auto t = pair.t; @@ -4765,12 +4765,15 @@ fn trans_cast(&@block_ctxt cx, &@ast::expr e, &ast::ann ann) -> result { // TODO: native-to-native casts if (ty::type_is_native(cx.fcx.lcx.ccx.tcx, ty::expr_ty(cx.fcx.lcx.ccx.tcx, e))) { - e_res.val = e_res.bcx.build.PtrToInt(e_res.val, lldsttype); + e_res = res(e_res.bcx, + e_res.bcx.build.PtrToInt(e_res.val, lldsttype)); } else if (ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) { - e_res.val = e_res.bcx.build.IntToPtr(e_res.val, lldsttype); + e_res = res(e_res.bcx, + e_res.bcx.build.IntToPtr(e_res.val, lldsttype)); } else { - e_res.val = int_cast(e_res.bcx, lldsttype, llsrctype, e_res.val, - ty::type_is_signed(cx.fcx.lcx.ccx.tcx, t)); + e_res = res(e_res.bcx, + int_cast(e_res.bcx, lldsttype, llsrctype, e_res.val, + ty::type_is_signed(cx.fcx.lcx.ccx.tcx, t))); } } else { cx.fcx.lcx.ccx.sess.unimpl("fp cast"); @@ -5767,7 +5770,7 @@ fn with_out_method(fn(&out_method) -> result work, &@block_ctxt cx, find_scope_cx(cx).cleanups += [clean(cleanup)]; auto done = work(save_in(res_alloca.val)); - done.val = load_if_immediate(done.bcx, res_alloca.val, tp); + done = res(done.bcx, load_if_immediate(done.bcx, res_alloca.val, tp)); ret done; } } @@ -5932,7 +5935,7 @@ fn trans_put(&@block_ctxt cx, &option::t[@ast::expr] e) -> result { auto llcallee = C_nil(); auto llenv = C_nil(); - alt (cx.fcx.lliterbody) { + alt ({cx.fcx.lliterbody}) { case (some(?lli)) { auto slot = alloca(cx, val_ty(lli)); cx.build.Store(lli, slot); @@ -5971,7 +5974,7 @@ fn trans_break_cont(&@block_ctxt cx, bool to_end) -> result { auto cleanup_cx = cx; while (true) { bcx = trans_block_cleanups(bcx, cleanup_cx); - alt (cleanup_cx.kind) { + alt ({cleanup_cx.kind}) { case (LOOP_SCOPE_BLOCK(?_cont, ?_break)) { if (to_end) { bcx.build.Br(_break.llbb); @@ -5989,7 +5992,7 @@ fn trans_break_cont(&@block_ctxt cx, bool to_end) -> result { C_nil()); } case (_) { - alt (cleanup_cx.parent) { + alt ({cleanup_cx.parent}) { case (parent_some(?cx)) { cleanup_cx = cx; } } } @@ -6033,7 +6036,7 @@ fn trans_ret(&@block_ctxt cx, &option::t[@ast::expr] e) -> result { auto cleanup_cx = cx; while (more_cleanups) { bcx = trans_block_cleanups(bcx, cleanup_cx); - alt (cleanup_cx.parent) { + alt ({cleanup_cx.parent}) { case (parent_some(?b)) { cleanup_cx = b; } @@ -6831,7 +6834,7 @@ fn copy_any_self_to_alloca(@fn_ctxt fcx, auto bcx = llallocas_block_ctxt(fcx); - alt (fcx.llself) { + alt ({fcx.llself}) { case (some(?pair)) { alt (ty_self) { case (some[ty_self_pair](?tt)) { @@ -7000,7 +7003,7 @@ fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ast::def_id fid, copy_any_self_to_alloca(fcx, ty_self); - alt (fcx.llself) { + alt ({fcx.llself}) { case (some(?llself)) { populate_fn_ctxt_from_llself(fcx, llself); } diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 6dd5ae76ff912..3b7061bb987b1 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -1540,7 +1540,7 @@ fn eq_ty(&t a, &t b) -> bool { ret a == b; } fn ann_to_ty_param_substs_opt_and_ty(&node_type_table ntt, &ast::ann ann) -> ty_param_substs_opt_and_ty { - alt (ntt.(ann.id)) { + alt ({ntt.(ann.id)}) { case (none) { log_err "ann_to_ty_param_substs_opt_and_ty() called on an " + "untyped node"; diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index c373c27fc18a9..11fbab4ddde44 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -379,11 +379,13 @@ fn ast_ty_to_ty_crate(@crate_ctxt ccx, &@ast::ty ast_ty) -> ty::t { mod write { fn inner(&node_type_table ntt, uint node_id, &ty_param_substs_opt_and_ty tpot) { + auto ntt_ = *ntt; vec::grow_set[option::t[ty::ty_param_substs_opt_and_ty]] - (*ntt, + (ntt_, node_id, none[ty_param_substs_opt_and_ty], some[ty_param_substs_opt_and_ty](tpot)); + *ntt = ntt_; } // Writes a type parameter count and type pair into the node type table. @@ -792,7 +794,7 @@ mod collect { // type of the native item. We simply write it into the node type // table. auto tpt = ty_of_native_item(cx, i, - option::get[ast::native_abi](*abi)); + option::get[ast::native_abi]({*abi})); alt (i.node) { case (ast::native_item_ty(_,_)) { @@ -921,7 +923,7 @@ mod unify { auto result = ty::unify::unify(expected, actual, handler, bindings, scx.fcx.ccx.tcx); - alt (result) { + alt ({result}) { case (ures_ok(?rty)) { if (ty::type_contains_vars(scx.fcx.ccx.tcx, rty)) { result = ty::unify::fixup(scx.fcx.ccx.tcx, bindings, rty); From bc8fcf1db73d6d4578fbe2241f2030814d7847ff Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 6 Jun 2011 15:22:13 +0200 Subject: [PATCH 33/64] First take on an alias-safety checker The alias checker works by ensuring that any value to which an alias is created is rooted in some way that ensures it outlives the alias. It is now disallowed to create an alias to the content of a mutable box, or to a box hanging off a mutable field. There is also machinery in place to prevent assignment to local variables whenever they are the root of a live alias. --- src/comp/driver/rustc.rs | 3 + src/comp/middle/alias.rs | 255 ++++++++++++++++++++++++++ src/comp/rustc.rc | 1 + src/test/compile-fail/unsafe-alias.rs | 10 + src/test/compile-fail/unsafe-alt.rs | 16 ++ 5 files changed, 285 insertions(+) create mode 100644 src/comp/middle/alias.rs create mode 100644 src/test/compile-fail/unsafe-alias.rs create mode 100644 src/test/compile-fail/unsafe-alt.rs diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index 0d5223d870233..e33a2e1c35dec 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -109,6 +109,9 @@ fn compile_input(session::session sess, bind middle::tstate::ck::check_crate(ty_cx, crate)); } + time(time_passes, "alias checking", + bind middle::alias::check_crate(@ty_cx, def_map, crate)); + auto llmod = time[llvm::llvm::ModuleRef](time_passes, "translation", bind trans::trans_crate(sess, crate, diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs new file mode 100644 index 0000000000000..9de830075ed9c --- /dev/null +++ b/src/comp/middle/alias.rs @@ -0,0 +1,255 @@ +import front::ast; +import front::ast::ident; +import front::ast::def_id; +import std::vec; +import std::str; +import std::option; +import std::option::some; +import std::option::none; + +tag deref_t { + field(ident); + index; + unbox; +} +type deref = rec(bool mut, deref_t t); + +type ctx = @rec(@ty::ctxt tcx, + resolve::def_map dm, + // The current blacklisted (non-assignable) locals + mutable vec[vec[def_id]] bl, + // A stack of blacklists for outer function scopes + mutable vec[vec[vec[def_id]]] blstack); + +fn check_crate(@ty::ctxt tcx, resolve::def_map dm, &@ast::crate crate) { + auto cx = @rec(tcx = tcx, + dm = dm, + mutable bl = vec::empty[vec[def_id]](), + mutable blstack = vec::empty[vec[vec[def_id]]]()); + auto v = rec(visit_item_pre = bind enter_item(cx, _), + visit_item_post = bind leave_item(cx, _), + visit_method_pre = bind enter_method(cx, _), + visit_method_post = bind leave_method(cx, _), + visit_expr_pre = bind check_expr(cx, _), + visit_expr_post = bind leave_expr(cx, _) + with walk::default_visitor()); + walk::walk_crate(v, *crate); +} + +fn enter_item(ctx cx, &@ast::item it) { + alt (it.node) { + case (ast::item_fn(_, _, _, _, _)) { + vec::push(cx.blstack, cx.bl); + cx.bl = []; + } + case (_) {} + } +} +fn leave_item(ctx cx, &@ast::item it) { + alt (it.node) { + case (ast::item_fn(_, _, _, _, _)) { + cx.bl = vec::pop(cx.blstack); + } + case (_) {} + } +} + +fn enter_method(ctx cx, &@ast::method mt) { + vec::push(cx.blstack, cx.bl); + cx.bl = []; +} +fn leave_method(ctx cx, &@ast::method mt) { + cx.bl = vec::pop(cx.blstack); +} + +fn check_expr(ctx cx, &@ast::expr ex) { + alt (ex.node) { + case (ast::expr_call(?f, ?args, _)) { + auto fty = ty::expr_ty(*cx.tcx, f); + auto argtys = alt (ty::struct(*cx.tcx, fty)) { + case (ty::ty_fn(_, ?args, _, _)) { args } + case (ty::ty_native_fn(_, ?args, _)) { args } + }; + auto i = 0u; + let vec[def_id] listed = []; + for (ty::arg argty in argtys) { + // FIXME Treat mo_either specially here? + if (argty.mode != ty::mo_val) { + alt (check_rooted(cx, args.(i), false)) { + case (some(?did)) { + vec::push(listed, did); + } + case (_) {} + } + } + i += 1u; + } + // FIXME when mutable aliases can be distinguished, go over the + // args again and ensure that we're not passing a blacklisted + // variable by mutable alias (using 'listed' and the context + // blacklist). + } + case (ast::expr_put(?val, _)) { + alt (val) { + case (some(?ex)) { check_rooted(cx, ex, false); } + case (_) {} + } + } + case (ast::expr_alt(?input, _, _)) { + vec::push(cx.bl, alt (check_rooted(cx, input, true)) { + case (some(?did)) { [did] } + case (_) { vec::empty[def_id]() } + }); + } + + case (ast::expr_move(?dest, _, _)) { check_assign(cx, dest); } + case (ast::expr_assign(?dest, _, _)) { check_assign(cx, dest); } + case (ast::expr_assign_op(_, ?dest, _, _)) { check_assign(cx, dest); } + case (_) {} + } +} + +fn leave_expr(ctx cx, &@ast::expr ex) { + alt (ex.node) { + case (ast::expr_alt(_, _, _)) { vec::pop(cx.bl); } + case (_) {} + } +} + +fn check_assign(&ctx cx, &@ast::expr ex) { + alt (ex.node) { + case (ast::expr_path(?pt, ?ann)) { + auto did = ast::def_id_of_def(cx.dm.get(ann.id)); + for (vec[def_id] layer in cx.bl) { + for (def_id black in layer) { + if (did == black) { + cx.tcx.sess.span_err + (ex.span, str::connect(pt.node.idents, "::") + + " is being aliased and may not be assigned to"); + } + } + } + } + case (_) {} + } +} + +fn check_rooted(&ctx cx, &@ast::expr ex, bool autoderef) + -> option::t[def_id] { + auto root = expr_root(cx, ex, autoderef); + if (has_unsafe_box(root.ds)) { + cx.tcx.sess.span_err + (ex.span, "can not create alias to improperly anchored value"); + } + alt (root.ex.node) { + case (ast::expr_path(_, ?ann)) { + ret some(ast::def_id_of_def(cx.dm.get(ann.id))); + } + case (_) { + ret none[def_id]; + } + } +} + +fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) + -> rec(@ast::expr ex, vec[deref] ds) { + let vec[deref] ds = []; + if (autoderef) { + auto auto_unbox = maybe_auto_unbox(cx, ex); + if (auto_unbox.done) { + vec::push(ds, rec(mut=auto_unbox.mut, t=unbox)); + } + } + while (true) { + alt ({ex.node}) { + case (ast::expr_field(?base, ?ident, _)) { + auto auto_unbox = maybe_auto_unbox(cx, base); + alt (auto_unbox.t) { + case (ty::ty_tup(?fields)) { + auto fnm = ty::field_num(cx.tcx.sess, ex.span, ident); + auto mt = fields.(fnm).mut != ast::imm; + vec::push(ds, rec(mut=mt, t=field(ident))); + } + case (ty::ty_rec(?fields)) { + for (ty::field fld in fields) { + if (str::eq(ident, fld.ident)) { + auto mt = fld.mt.mut != ast::imm; + vec::push(ds, rec(mut=mt, t=field(ident))); + break; + } + } + } + case (ty::ty_obj(_)) { + vec::push(ds, rec(mut=false, t=field(ident))); + } + } + if (auto_unbox.done) { + vec::push(ds, rec(mut=auto_unbox.mut, t=unbox)); + } + ex = base; + } + case (ast::expr_index(?base, _, _)) { + auto auto_unbox = maybe_auto_unbox(cx, base); + alt (auto_unbox.t) { + case (ty::ty_vec(?mt)) { + vec::push(ds, rec(mut=mt.mut != ast::imm, t=index)); + } + } + if (auto_unbox.done) { + vec::push(ds, rec(mut=auto_unbox.mut, t=unbox)); + } + ex = base; + } + case (ast::expr_unary(?op, ?base, _)) { + if (op == ast::deref) { + alt (ty::struct(*cx.tcx, ty::expr_ty(*cx.tcx, base))) { + case (ty::ty_box(?mt)) { + vec::push(ds, rec(mut=mt.mut!=ast::imm, t=unbox)); + } + } + ex = base; + } else { + break; + } + } + case (_) { break; } + } + } + vec::reverse(ds); + ret rec(ex = ex, ds = ds); +} + +fn maybe_auto_unbox(&ctx cx, &@ast::expr ex) + -> rec(ty::sty t, bool done, bool mut) { + auto tp = ty::struct(*cx.tcx, ty::expr_ty(*cx.tcx, ex)); + alt (tp) { + case (ty::ty_box(?mt)) { + ret rec(t=ty::struct(*cx.tcx, mt.ty), + done=true, mut=mt.mut != ast::imm); + } + case (_) { ret rec(t=tp, done=false, mut=false); } + } +} + +fn has_unsafe_box(&vec[deref] ds) -> bool { + auto saw_mut = false; + for (deref d in ds) { + if (d.mut) { saw_mut = true; } + if (d.t == unbox) { + // Directly aliasing the content of a mutable box is never okay, + // and any box living under mutable connection may be severed from + // its root and freed. + if (saw_mut) { ret true; } + } + } + ret false; +} + +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index 55683ba7ffa30..b7911a634b59b 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -16,6 +16,7 @@ mod middle { mod metadata; mod resolve; mod typeck; + mod alias; mod tstate { mod ck; diff --git a/src/test/compile-fail/unsafe-alias.rs b/src/test/compile-fail/unsafe-alias.rs new file mode 100644 index 0000000000000..e4ff5f86da2c2 --- /dev/null +++ b/src/test/compile-fail/unsafe-alias.rs @@ -0,0 +1,10 @@ +// error-pattern:can not create alias + +fn foo(&int x) { + log x; +} + +fn main() { + auto box = @mutable 1; + foo(*box); +} diff --git a/src/test/compile-fail/unsafe-alt.rs b/src/test/compile-fail/unsafe-alt.rs new file mode 100644 index 0000000000000..a0342d87c867a --- /dev/null +++ b/src/test/compile-fail/unsafe-alt.rs @@ -0,0 +1,16 @@ +// error-pattern:x is being aliased + +tag foo { + left(int); + right(bool); +} + +fn main() { + auto x = left(10); + alt (x) { + case (left(?i)) { + x = right(false); + } + case (_) {} + } +} From 543717e467ad90d57f200a58c75adc796d3fa95d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20=C3=81vila=20de=20Esp=C3=ADndola?= Date: Mon, 6 Jun 2011 16:33:42 -0400 Subject: [PATCH 34/64] Implement enough support for pointer to get an identity function working. --- src/comp/middle/ty.rs | 6 ++++++ src/test/run-pass/type-ptr.rs | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 3b7061bb987b1..9095f9e9c5277 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -615,6 +615,7 @@ fn ty_to_str(&ctxt cx, &t typ) -> str { case (ty_char) { s += "char"; } case (ty_str) { s += "str"; } case (ty_box(?tm)) { s += "@" + mt_to_str(cx, tm); } + case (ty_ptr(?tm)) { s += "*" + mt_to_str(cx, tm); } case (ty_vec(?tm)) { s += "vec[" + mt_to_str(cx, tm) + "]"; } case (ty_port(?t)) { s += "port[" + ty_to_str(cx, t) + "]"; } case (ty_chan(?t)) { s += "chan[" + ty_to_str(cx, t) + "]"; } @@ -781,6 +782,10 @@ fn fold_ty(&ctxt cx, ty_fold fld, t ty_0) -> t { ty = copy_cname(cx, mk_box(cx, rec(ty=fold_ty(cx, fld, tm.ty), mut=tm.mut)), ty); } + case (ty_ptr(?tm)) { + ty = copy_cname(cx, mk_ptr(cx, rec(ty=fold_ty(cx, fld, tm.ty), + mut=tm.mut)), ty); + } case (ty_vec(?tm)) { ty = copy_cname(cx, mk_vec(cx, rec(ty=fold_ty(cx, fld, tm.ty), mut=tm.mut)), ty); @@ -978,6 +983,7 @@ fn type_is_scalar(&ctxt cx, &t ty) -> bool { case (ty_char) { ret true; } case (ty_type) { ret true; } case (ty_native) { ret true; } + case (ty_ptr(_)) { ret true; } case (_) { ret false; } } } diff --git a/src/test/run-pass/type-ptr.rs b/src/test/run-pass/type-ptr.rs index 8ccbba9218de7..3743fb115e884 100644 --- a/src/test/run-pass/type-ptr.rs +++ b/src/test/run-pass/type-ptr.rs @@ -1,4 +1,10 @@ -fn f(*int a) { +fn f(*int a) -> *int { + ret a; +} + +fn g(*int a) -> *int { + auto b = f(a); + ret b; } fn main(vec[str] args) { From 70b1d6e74278c388daa6e43d87350bb82ec09cb2 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Mon, 6 Jun 2011 15:48:36 -0700 Subject: [PATCH 35/64] Begin tidying up name-mangling rules. --- src/comp/middle/trans.rs | 124 +++++++++++++++++++++------------------ src/lib/vec.rs | 6 ++ 2 files changed, 72 insertions(+), 58 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 61de9459fac4a..4230032f7ee67 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -118,6 +118,7 @@ state type crate_ctxt = rec(session::session sess, hashmap[ast::def_id, @ast::native_item] native_items, hashmap[ast::def_id, str] item_symbols, + mutable option::t[ValueRef] main_fn, // TODO: hashmap[tup(tag_id,subtys), @tag_info] hashmap[ty::t, uint] tag_sizes, hashmap[ast::def_id, ValueRef] discrims, @@ -308,19 +309,10 @@ tag block_parent { state type result = rec(@block_ctxt bcx, ValueRef val); -fn sep() -> str { - ret "_"; -} - fn extend_path(@local_ctxt cx, &str name) -> @local_ctxt { ret @rec(path = cx.path + [name] with *cx); } -fn path_name(&vec[str] path) -> str { - ret str::connect(path, sep()); -} - - fn get_type_sha1(&@crate_ctxt ccx, &ty::t t) -> str { auto hash = ""; alt (ccx.type_sha1s.find(t)) { @@ -336,15 +328,31 @@ fn get_type_sha1(&@crate_ctxt ccx, &ty::t t) -> str { ccx.sha.input_str(metadata::Encode::ty_str(cx, t)); hash = str::substr(ccx.sha.result_str(), 0u, 16u); + // Prefix with _ so that it never blends into adjacent digits + hash = "_" + hash; ccx.type_sha1s.insert(t, hash); } } ret hash; } +fn mangle(&vec[str] ss) -> str { + + // Follow C++ namespace-mangling style + + auto n = "_ZN"; // Begin name-sequence. + + for (str s in ss) { + n += #fmt("%u%s", str::byte_len(s), s); + } + + n += "E"; // End name-sequence. + ret n; +} + fn mangle_name_by_type(&@crate_ctxt ccx, &vec[str] path, &ty::t t) -> str { auto hash = get_type_sha1(ccx, t); - ret sep() + "rust" + sep() + hash + sep() + path_name(path); + ret mangle(path + [hash]); } fn mangle_name_by_type_only(&@crate_ctxt ccx, &ty::t t, &str name) -> str { @@ -353,14 +361,20 @@ fn mangle_name_by_type_only(&@crate_ctxt ccx, &ty::t t, &str name) -> str { auto s = ty::ty_to_short_str(ccx.tcx, t); auto hash = get_type_sha1(ccx, t); - ret sep() + "rust" + sep() + hash + sep() + name + "_" + s; + ret mangle([name, s, hash]); +} + +fn mangle_name_by_path_and_seq(&@crate_ctxt ccx, &vec[str] path, + &str flav) -> str { + ret mangle(path + [ccx.names.next(flav)]); +} + +fn mangle_name_by_path(&@crate_ctxt ccx, &vec[str] path) -> str { + ret mangle(path); } -fn mangle_name_by_seq(&@crate_ctxt ccx, &vec[str] path, - &str flav) -> str { - ret sep() + "rust" + sep() - + ccx.names.next(flav) + sep() - + path_name(path); +fn mangle_name_by_seq(&@crate_ctxt ccx, &str flav) -> str { + ret ccx.names.next(flav); } fn res(@block_ctxt bcx, ValueRef val) -> result { @@ -1903,7 +1917,7 @@ fn declare_tydesc(&@local_ctxt cx, &span sp, &ty::t t, name = mangle_name_by_type_only(cx.ccx, t, "tydesc"); name = sanitize(name); } else { - name = mangle_name_by_seq(cx.ccx, cx.path, "tydesc"); + name = mangle_name_by_seq(cx.ccx, "tydesc"); } auto gvar = llvm::LLVMAddGlobal(ccx.llmod, T_tydesc(ccx.tn), @@ -1937,7 +1951,7 @@ fn declare_generic_glue(&@local_ctxt cx, fn_nm = mangle_name_by_type_only(cx.ccx, t, "glue_" + name); fn_nm = sanitize(fn_nm); } else { - fn_nm = mangle_name_by_seq(cx.ccx, cx.path, "glue_" + name); + fn_nm = mangle_name_by_seq(cx.ccx, "glue_" + name); } auto llfn = decl_fastcall_fn(cx.ccx.llmod, fn_nm, llfnty); set_glue_inlining(cx, llfn, t); @@ -4093,7 +4107,7 @@ fn trans_for_each(&@block_ctxt cx, // Step 2: Declare foreach body function. - let str s = mangle_name_by_seq(lcx.ccx, lcx.path, "foreach"); + let str s = mangle_name_by_path_and_seq(lcx.ccx, lcx.path, "foreach"); // The 'env' arg entering the body function is a fake env member (as in // the env-part of the normal rust calling convention) that actually @@ -4792,7 +4806,7 @@ fn trans_bind_thunk(&@local_ctxt cx, // Construct a thunk-call with signature incoming_fty, and that copies // args forward into a call to outgoing_fty: - let str s = mangle_name_by_seq(cx.ccx, cx.path, "thunk"); + let str s = mangle_name_by_path_and_seq(cx.ccx, cx.path, "thunk"); let TypeRef llthunk_ty = get_pair_fn_ty(type_of(cx.ccx, sp, incoming_fty)); let ValueRef llthunk = decl_internal_fastcall_fn(cx.ccx.llmod, @@ -6225,9 +6239,10 @@ fn mk_spawn_wrapper(&@block_ctxt cx, 0u); // TODO: construct a name based on tname - let str wrap_name = mangle_name_by_seq(cx.fcx.lcx.ccx, - [""], - "spawn_wrapper"); + let str wrap_name = + mangle_name_by_path_and_seq(cx.fcx.lcx.ccx, + cx.fcx.lcx.path, + "spawn_wrapper"); auto llfndecl = decl_fastcall_fn(llmod, wrap_name, wrapper_fn_type); @@ -7078,8 +7093,9 @@ fn create_vtbl(@local_ctxt cx, } } - let @local_ctxt mcx = extend_path(cx, m.node.ident); - let str s = mangle_name_by_seq(mcx.ccx, mcx.path, "method"); + let @local_ctxt mcx = @rec(path = cx.path + ["method", + m.node.ident] with *cx); + let str s = mangle_name_by_path(mcx.ccx, mcx.path); let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty); cx.ccx.item_ids.insert(m.node.id, llfn); @@ -7091,7 +7107,7 @@ fn create_vtbl(@local_ctxt cx, methods += [llfn]; } auto vtbl = C_struct(methods); - auto vtbl_name = mangle_name_by_seq(cx.ccx, cx.path, "vtbl"); + auto vtbl_name = mangle_name_by_path(cx.ccx, cx.path + ["vtbl"]); auto gvar = llvm::LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl), str::buf(vtbl_name)); llvm::LLVMSetInitializer(gvar, vtbl); @@ -7108,13 +7124,12 @@ fn trans_dtor(@local_ctxt cx, &@ast::method dtor) -> ValueRef { auto llfnty = T_dtor(cx.ccx, dtor.span, llself_ty); - let @local_ctxt dcx = extend_path(cx, "drop"); - let str s = mangle_name_by_seq(dcx.ccx, dcx.path, "drop"); + let str s = mangle_name_by_path(cx.ccx, cx.path + ["drop"]); let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty); cx.ccx.item_ids.insert(dtor.node.id, llfn); cx.ccx.item_symbols.insert(dtor.node.id, s); - trans_fn(dcx, dtor.span, dtor.node.meth, dtor.node.id, + trans_fn(cx, dtor.span, dtor.node.meth, dtor.node.id, some[ty_self_pair](tup(llself_ty, self_ty)), ty_params, dtor.node.ann); @@ -7503,13 +7518,22 @@ fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, } // Declare the function itself. - let str s = mangle_name_by_seq(ccx, path, flav); + let str s = mangle_name_by_path(ccx, path); let ValueRef llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfty); // Declare the global constant pair that points to it. let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann)); register_fn_pair(ccx, ps, llpairty, llfn, id); + + if (str::eq(vec::top(path), "main") && + !ccx.sess.get_opts().shared) { + if (ccx.main_fn != none[ValueRef]) { + ccx.sess.span_err(sp, "multiple 'main' functions"); + } + log #fmt("registering %s as main function for crate", ps); + ccx.main_fn = some(llfn); + } } fn register_fn_pair(&@crate_ctxt cx, str ps, TypeRef llpairty, ValueRef llfn, @@ -7569,7 +7593,7 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, // Declare the wrapper. auto t = node_ann_type(ccx, ann); auto wrapper_type = native_fn_wrapper_type(ccx, sp, num_ty_param, t); - let str s = mangle_name_by_seq(ccx, path, "wrapper"); + let str s = mangle_name_by_path(ccx, path); let ValueRef wrapper_fn = decl_internal_fastcall_fn(ccx.llmod, s, wrapper_type); @@ -7912,9 +7936,8 @@ fn trans_constant(&@crate_ctxt ccx, @walk_ctxt wcx, &@ast::item it) { auto discrim_val = C_int(i as int); - auto s = mangle_name_by_seq(ccx, wcx.path, - #fmt("_rust_tag_discrim_%s_%u", - ident, i)); + auto p = wcx.path + [ident, variant.node.name, "discrim"]; + auto s = mangle_name_by_type(ccx, p, ty::mk_int(ccx.tcx)); auto discrim_gvar = llvm::LLVMAddGlobal(ccx.llmod, T_int(), str::buf(s)); @@ -7973,29 +7996,6 @@ fn create_typedefs(&@crate_ctxt cx) { llvm::LLVMAddTypeName(cx.llmod, str::buf("tydesc"), T_tydesc(cx.tn)); } -fn find_main_fn(&@crate_ctxt cx) -> ValueRef { - auto e = sep() + "main"; - let ValueRef v = C_nil(); - let uint n = 0u; - for each (@tup(ast::def_id, str) i in cx.item_symbols.items()) { - if (str::ends_with(i._1, e)) { - n += 1u; - v = cx.item_ids.get(i._0); - } - } - alt (n) { - case (0u) { - cx.sess.err("main fn not found"); - } - case (1u) { - ret v; - } - case (_) { - cx.sess.err("multiple main fns found"); - } - } -} - fn trans_main_fn(@local_ctxt cx, ValueRef crate_map) { auto T_main_args = [T_int(), T_int()]; auto T_rust_start_args = [T_int(), T_int(), T_int(), T_int()]; @@ -8015,7 +8015,14 @@ fn trans_main_fn(@local_ctxt cx, ValueRef crate_map) { auto llargc = llvm::LLVMGetParam(llmain, 0u); auto llargv = llvm::LLVMGetParam(llmain, 1u); - auto llrust_main = find_main_fn(cx.ccx); + auto llrust_main = alt (cx.ccx.main_fn) { + case (none) { + cx.ccx.sess.err("missing 'main' function"); + // FIXME: shouldn't sess.err's ! result unify with f? + C_nil() + } + case (some(?f)) { f } + }; // // Emit the moral equivalent of: @@ -8283,6 +8290,7 @@ fn trans_crate(&session::session sess, &@ast::crate crate, items = new_def_hash[@ast::item](), native_items = new_def_hash[@ast::native_item](), item_symbols = new_def_hash[str](), + mutable main_fn = none[ValueRef], tag_sizes = tag_sizes, discrims = new_def_hash[ValueRef](), discrim_symbols = new_def_hash[str](), diff --git a/src/lib/vec.rs b/src/lib/vec.rs index 8259e494e2532..374b55ed9be36 100644 --- a/src/lib/vec.rs +++ b/src/lib/vec.rs @@ -193,6 +193,12 @@ fn pop[T](&mutable array[T] v) -> T { ret e; } +fn top[T](&array[T] v) -> T { + auto ln = len[T](v); + assert (ln > 0u); + ret v.(ln-1u); +} + fn push[T](&mutable array[T] v, &T t) { v += [t]; } From 7458a07b36a1066db099c5ab78cdb47f248c49c8 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Tue, 7 Jun 2011 04:53:47 -0400 Subject: [PATCH 36/64] Add multiline, whitespace-eating strings. --- src/comp/front/lexer.rs | 3 +++ src/test/run-pass/str-multiline.rs | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 src/test/run-pass/str-multiline.rs diff --git a/src/comp/front/lexer.rs b/src/comp/front/lexer.rs index b6f5ab9e9c3a6..08409bea14c32 100644 --- a/src/comp/front/lexer.rs +++ b/src/comp/front/lexer.rs @@ -632,6 +632,9 @@ fn next_token(&reader rdr) -> token::token { case ('"') { str::push_byte(accum_str, '"' as u8); } + case ('\n') { + consume_whitespace(rdr); + } case ('x') { str::push_char(accum_str, diff --git a/src/test/run-pass/str-multiline.rs b/src/test/run-pass/str-multiline.rs new file mode 100644 index 0000000000000..c5ad5b15119cf --- /dev/null +++ b/src/test/run-pass/str-multiline.rs @@ -0,0 +1,15 @@ +// -*- rust -*- + +use std; +import std::str; + +fn main() { + let str a = "this \ +is a test"; + let str b = "this \ + is \ + another \ + test"; + assert (str::eq(a, "this is a test")); + assert (str::eq(b, "this is another test")); +} \ No newline at end of file From 5251ea504e05657c3b1e6cec6b84f548f0129998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20=C3=81vila=20de=20Esp=C3=ADndola?= Date: Tue, 7 Jun 2011 16:41:19 -0400 Subject: [PATCH 37/64] Don't put a copy of main (the C one) in each binary we produce. This is a step in getting a driver that works on all linux systems. Sorry for the linker hacks, I will remove them after snapshotting a new compiler. --- Makefile.in | 6 +-- mk/clean.mk | 2 + mk/rt.mk | 12 ++++++ mk/stage1.mk | 2 +- mk/stage2.mk | 2 +- mk/stage3.mk | 4 +- mk/tests.mk | 6 +-- src/comp/middle/trans.rs | 85 ++++++++++++++-------------------------- src/rt/main.ll.in | 24 ++++++++++++ 9 files changed, 77 insertions(+), 66 deletions(-) create mode 100644 src/rt/main.ll.in diff --git a/Makefile.in b/Makefile.in index ecff84dc4c002..362b97ea03656 100644 --- a/Makefile.in +++ b/Makefile.in @@ -144,9 +144,9 @@ COMPILER_INPUTS := $(wildcard $(addprefix $(S)src/comp/, \ ###################################################################### LREQ := rt/$(CFG_RUNTIME) rustllvm/$(CFG_RUSTLLVM) -SREQ0 := stage0/rustc$(X) $(LREQ) stage1/glue.o stage1/$(CFG_STDLIB) -SREQ1 := stage1/rustc$(X) $(LREQ) stage2/glue.o stage2/$(CFG_STDLIB) -SREQ2 := stage2/rustc$(X) $(LREQ) stage3/glue.o stage3/$(CFG_STDLIB) +SREQ0 := stage0/rustc$(X) $(LREQ) rt/main.a stage1/glue.o stage1/$(CFG_STDLIB) +SREQ1 := stage1/rustc$(X) $(LREQ) rt/main.a stage2/glue.o stage2/$(CFG_STDLIB) +SREQ2 := stage2/rustc$(X) $(LREQ) rt/main.a stage3/glue.o stage3/$(CFG_STDLIB) ###################################################################### diff --git a/mk/clean.mk b/mk/clean.mk index 3f19953929e55..305b06b5e0a38 100644 --- a/mk/clean.mk +++ b/mk/clean.mk @@ -28,6 +28,8 @@ clean: $(Q)rm -f stage3/rustc$(X) stage3/$(CFG_STDLIB) stage3/glue* $(Q)rm -f rustllvm/$(CFG_RUSTLLVM) rustllvm/rustllvmbits.a $(Q)rm -f rt/$(CFG_RUNTIME) + $(Q)rm -f rt/main.o + $(Q)rm -f rt/main.a $(Q)rm -Rf $(PKG_NAME)-*.tar.gz dist $(Q)rm -f $(foreach ext,o a d bc s exe,$(wildcard stage*/*.$(ext))) $(Q)rm -Rf $(foreach ext,out out.tmp \ diff --git a/mk/rt.mk b/mk/rt.mk index 8139f9e4e794e..1cc6dfb57f45f 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -76,6 +76,18 @@ rt/%.o: rt/%.s $(MKFILES) @$(call E, compile: $@) $(Q)$(call CFG_COMPILE_C, $@, $(RUNTIME_INCS)) $< +ifdef CFG_WINDOWSY +rt/main.ll: rt/main.ll.in + sed 's/MAIN/WinMain@16/' < $^ > $@ +else +rt/main.ll: rt/main.ll.in + sed 's/MAIN/main/' < $^ > $@ +endif + +rt/main.a: rt/main.o + rm -f $@ + ar crs $@ $^ + rt/%.o: rt/%.ll $(MKFILES) @$(call E, llc: $@) $(Q)$(LLC) -filetype=obj -relocation-model=pic -march=x86 -o $@ $< diff --git a/mk/stage1.mk b/mk/stage1.mk index f2ca6321d9455..c98882e41a872 100644 --- a/mk/stage1.mk +++ b/mk/stage1.mk @@ -44,7 +44,7 @@ stage1/%.o: stage1/%.s stage1/%$(X): stage1/%.o $(SREQ0) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage1/glue.o -o $@ $< \ - -Lstage1 -Lrustllvm -Lrt -lrustrt -lrustllvm -lstd -lm + -Lstage1 -Lrustllvm -Lrt rt/main.a -lrustrt -lrustllvm -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. diff --git a/mk/stage2.mk b/mk/stage2.mk index e084a19a8d3a7..0d87400c1e298 100644 --- a/mk/stage2.mk +++ b/mk/stage2.mk @@ -44,7 +44,7 @@ stage2/%.o: stage2/%.s stage2/%$(X): stage2/%.o $(SREQ1) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage2/glue.o -o $@ $< \ - -Lstage2 -Lrustllvm -Lrt -lrustrt -lrustllvm -lstd -lm + -Lstage2 -Lrustllvm -Lrt rt/main.a -lrustrt -lrustllvm -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. diff --git a/mk/stage3.mk b/mk/stage3.mk index dc2792446e21e..77d09440883e7 100644 --- a/mk/stage3.mk +++ b/mk/stage3.mk @@ -23,7 +23,7 @@ stage3/rustc.o: $(COMPILER_CRATE) $(COMPILER_INPUTS) $(SREQ2) $(STAGE2) -c -o $@ $< stage3/glue.o: stage2/rustc$(X) stage2/$(CFG_STDLIB) stage2/intrinsics.bc \ - rustllvm/$(CFG_RUSTLLVM) rt/$(CFG_RUNTIME) + rustllvm/$(CFG_RUSTLLVM) rt/$(CFG_RUNTIME) @$(call E, generate: $@) $(STAGE2) -c -o $@ --glue @@ -44,7 +44,7 @@ stage3/%.o: stage3/%.s stage3/%$(X): stage3/%.o $(SREQ2) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage3/glue.o -o $@ $< \ - -Lstage3 -Lrustllvm -Lrt -lrustrt -lrustllvm -lstd -lm + -Lstage3 -Lrustllvm -Lrt rt/main.a -lrustrt -lrustllvm -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. diff --git a/mk/tests.mk b/mk/tests.mk index 5e30b352dfa5b..db7a3dd4d33cf 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -185,7 +185,7 @@ compile-check: tidy \ %.stage0$(X): %.stage0.o $(SREQ0) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage1/glue.o -o $@ $< \ - -Lstage1 -Lrt -lrustrt -lstd -lm + -Lstage1 -Lrt rt/main.a -lrustrt -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. @@ -194,7 +194,7 @@ compile-check: tidy \ %.stage1$(X): %.stage1.o $(SREQ1) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage2/glue.o -o $@ $< \ - -Lstage2 -Lrt -lrustrt -lstd -lm + -Lstage2 -Lrt rt/main.a -lrustrt -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. @@ -203,7 +203,7 @@ compile-check: tidy \ %.stage2$(X): %.stage2.o $(SREQ2) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage3/glue.o -o $@ $< \ - -Lstage3 -Lrt -lrustrt -lstd -lm + -Lstage3 -Lrt rt/main.a -lrustrt -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 4230032f7ee67..a65b1403b38a8 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -338,6 +338,9 @@ fn get_type_sha1(&@crate_ctxt ccx, &ty::t t) -> str { fn mangle(&vec[str] ss) -> str { + if (vec::len(ss) > 0u && str::eq(vec::top(ss), "main")) { + ret "_rust_main"; + } // Follow C++ namespace-mangling style auto n = "_ZN"; // Begin name-sequence. @@ -369,7 +372,7 @@ fn mangle_name_by_path_and_seq(&@crate_ctxt ccx, &vec[str] path, ret mangle(path + [ccx.names.next(flav)]); } -fn mangle_name_by_path(&@crate_ctxt ccx, &vec[str] path) -> str { +fn mangle_name_by_path(&vec[str] path) -> str { ret mangle(path); } @@ -7095,7 +7098,7 @@ fn create_vtbl(@local_ctxt cx, let @local_ctxt mcx = @rec(path = cx.path + ["method", m.node.ident] with *cx); - let str s = mangle_name_by_path(mcx.ccx, mcx.path); + let str s = mangle_name_by_path(mcx.path); let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty); cx.ccx.item_ids.insert(m.node.id, llfn); @@ -7107,7 +7110,7 @@ fn create_vtbl(@local_ctxt cx, methods += [llfn]; } auto vtbl = C_struct(methods); - auto vtbl_name = mangle_name_by_path(cx.ccx, cx.path + ["vtbl"]); + auto vtbl_name = mangle_name_by_path(cx.path + ["vtbl"]); auto gvar = llvm::LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl), str::buf(vtbl_name)); llvm::LLVMSetInitializer(gvar, vtbl); @@ -7124,7 +7127,7 @@ fn trans_dtor(@local_ctxt cx, &@ast::method dtor) -> ValueRef { auto llfnty = T_dtor(cx.ccx, dtor.span, llself_ty); - let str s = mangle_name_by_path(cx.ccx, cx.path + ["drop"]); + let str s = mangle_name_by_path(cx.path + ["drop"]); let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty); cx.ccx.item_ids.insert(dtor.node.id, llfn); cx.ccx.item_symbols.insert(dtor.node.id, s); @@ -7518,7 +7521,7 @@ fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, } // Declare the function itself. - let str s = mangle_name_by_path(ccx, path); + let str s = mangle_name_by_path(path); let ValueRef llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfty); // Declare the global constant pair that points to it. @@ -7532,6 +7535,8 @@ fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, ccx.sess.span_err(sp, "multiple 'main' functions"); } log #fmt("registering %s as main function for crate", ps); + llvm::LLVMSetLinkage(llfn, lib::llvm::LLVMExternalLinkage + as llvm::Linkage); ccx.main_fn = some(llfn); } } @@ -7593,7 +7598,7 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, // Declare the wrapper. auto t = node_ann_type(ccx, ann); auto wrapper_type = native_fn_wrapper_type(ccx, sp, num_ty_param, t); - let str s = mangle_name_by_path(ccx, path); + let str s = mangle_name_by_path(path); let ValueRef wrapper_fn = decl_internal_fastcall_fn(ccx.llmod, s, wrapper_type); @@ -7996,51 +8001,6 @@ fn create_typedefs(&@crate_ctxt cx) { llvm::LLVMAddTypeName(cx.llmod, str::buf("tydesc"), T_tydesc(cx.tn)); } -fn trans_main_fn(@local_ctxt cx, ValueRef crate_map) { - auto T_main_args = [T_int(), T_int()]; - auto T_rust_start_args = [T_int(), T_int(), T_int(), T_int()]; - - auto main_name; - if (str::eq(std::os::target_os(), "win32")) { - main_name = "WinMain@16"; - } else { - main_name = "main"; - } - - auto llmain = - decl_cdecl_fn(cx.ccx.llmod, main_name, T_fn(T_main_args, T_int())); - - auto llrust_start = decl_cdecl_fn(cx.ccx.llmod, "rust_start", - T_fn(T_rust_start_args, T_int())); - - auto llargc = llvm::LLVMGetParam(llmain, 0u); - auto llargv = llvm::LLVMGetParam(llmain, 1u); - auto llrust_main = alt (cx.ccx.main_fn) { - case (none) { - cx.ccx.sess.err("missing 'main' function"); - // FIXME: shouldn't sess.err's ! result unify with f? - C_nil() - } - case (some(?f)) { f } - }; - - // - // Emit the moral equivalent of: - // - // main(int argc, char **argv) { - // rust_start(&_rust.main, argc, argv); - // } - // - - let BasicBlockRef llbb = - llvm::LLVMAppendBasicBlock(llmain, str::buf("")); - auto b = new_builder(llbb); - - auto start_args = [p2i(llrust_main), llargc, llargv, p2i(crate_map)]; - - b.Ret(b.Call(llrust_start, start_args)); -} - fn declare_intrinsics(ModuleRef llmod) -> hashmap[str,ValueRef] { let vec[TypeRef] T_memmove32_args = [T_ptr(T_i8()), T_ptr(T_i8()), @@ -8211,8 +8171,6 @@ fn create_module_map(&@crate_ctxt ccx) -> ValueRef { auto maptype = T_array(elttype, ccx.module_data.size() + 1u); auto map = llvm::LLVMAddGlobal(ccx.llmod, maptype, str::buf("_rust_mod_map")); - llvm::LLVMSetLinkage(map, lib::llvm::LLVMInternalLinkage - as llvm::Linkage); let vec[ValueRef] elts = []; for each (@tup(str, ValueRef) item in ccx.module_data.items()) { auto elt = C_struct([p2i(C_cstr(ccx, item._0)), p2i(item._1)]); @@ -8245,7 +8203,14 @@ fn create_crate_map(&@crate_ctxt ccx) -> ValueRef { i += 1; } vec::push[ValueRef](subcrates, C_int(0)); - auto sym_name = "_rust_crate_map_" + crate_name(ccx, "__none__"); + auto cname = crate_name(ccx, "__none__"); + auto mapname; + if (ccx.sess.get_opts().shared) { + mapname = cname; + } else { + mapname = "toplevel"; + } + auto sym_name = "_rust_crate_map_" + mapname; auto arrtype = T_array(T_int(), vec::len[ValueRef](subcrates)); auto maptype = T_struct([T_int(), arrtype]); auto map = llvm::LLVMAddGlobal(ccx.llmod, maptype, str::buf(sym_name)); @@ -8322,9 +8287,17 @@ fn trans_crate(&session::session sess, &@ast::crate crate, trans_constants(ccx, crate); trans_mod(cx, crate.node.module); auto crate_map = create_crate_map(ccx); + if (!sess.get_opts().shared) { - trans_main_fn(cx, crate_map); - } + auto gvar = llvm::LLVMAddGlobal(cx.ccx.llmod, T_ptr(T_int()), + str::buf("_rust_fetch_this_object_hack")); + + auto gvar2 = llvm::LLVMAddGlobal(cx.ccx.llmod, T_ptr(T_ptr(T_int())), + str::buf("_rust_fetch_this_object_hack2")); + llvm::LLVMSetInitializer(gvar2, gvar); + llvm::LLVMSetGlobalConstant(gvar, True); + llvm::LLVMSetGlobalConstant(gvar2, True); + } emit_tydescs(ccx); diff --git a/src/rt/main.ll.in b/src/rt/main.ll.in new file mode 100644 index 0000000000000..d956fb8681724 --- /dev/null +++ b/src/rt/main.ll.in @@ -0,0 +1,24 @@ +%0 = type { i32, [1 x i32] } +%1 = type { i32, i32 } +%2 = type { i32, %3 } +%3 = type { %tydesc*, %4, i1, {} } +%4 = type { i1*, i1* } +%5 = type { i32, i32, i32, i32, [0 x %6*] } +%6 = type { i32, i32, i32, i32, [0 x i8] } + + +@_rust_crate_map_toplevel = external global %0 + +declare fastcc void @_rust_main(i1* nocapture, %task*, %2* nocapture, %5*); +declare i32 @rust_start(i32, i32, i32, i32) + +%tydesc = type { %tydesc**, i32, i32, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*)*, void (i1*, %task*, i1*, %tydesc**, i8*, i8*, i8)* } + +%task = type { i32, i32, i32, i32, i32, i32, i32, i32 } + +@_rust_fetch_this_object_hack = global i32 0 + +define i32 @"MAIN"(i32, i32) { + %3 = tail call i32 @rust_start(i32 ptrtoint (void (i1*, %task*, %2*, %5*)* @_rust_main to i32), i32 %0, i32 %1, i32 ptrtoint (%0* @_rust_crate_map_toplevel to i32)) + ret i32 %3 +} From 1d2f0e5332ee5656725ae30d86cdc7fafd3b72fa Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Tue, 7 Jun 2011 13:50:30 -0700 Subject: [PATCH 38/64] Removing dead code and redundant fails; changing fails to sess.bug calls (issue #444). --- src/comp/middle/trans.rs | 32 +++--- src/comp/middle/tstate/auxiliary.rs | 2 +- src/comp/middle/ty.rs | 146 ++++++++-------------------- src/comp/middle/typeck.rs | 69 ++++++------- src/comp/pretty/pprust.rs | 2 +- 5 files changed, 93 insertions(+), 158 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index a65b1403b38a8..7333375b902c6 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -3687,13 +3687,11 @@ fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result { v1 = load_if_immediate(cx, v1, t1); } - case (_) { - ret res(cx, v1); - } + case (_) { break; } } } - fail; // fools the return-checker + ret res(cx, v1); } fn autoderefed_ty(&@crate_ctxt ccx, &ty::t t) -> ty::t { @@ -3704,13 +3702,11 @@ fn autoderefed_ty(&@crate_ctxt ccx, &ty::t t) -> ty::t { case (ty::ty_box(?mt)) { t1 = mt.ty; } - case (_) { - ret t1; - } + case (_) { break; } } } - fail; // fools the return-checker + ret t1; } fn trans_binary(&@block_ctxt cx, ast::binop op, @@ -3876,7 +3872,7 @@ fn trans_if(&@block_ctxt cx, &@ast::expr cond, } // FIXME: This isn't quite right, particularly re: dynamic types - auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx.node_types, + auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann); if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) { expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn); @@ -4260,7 +4256,7 @@ fn trans_pat_match(&@block_ctxt cx, &@ast::pat pat, ValueRef llval, case (ast::pat_lit(?lt, ?ann)) { auto lllit = trans_lit(cx.fcx.lcx.ccx, *lt, ann); - auto lltype = ty::ann_to_type(cx.fcx.lcx.ccx.tcx.node_types, ann); + auto lltype = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann); auto lleq = trans_compare(cx, ast::eq, lltype, llval, lllit); auto matched_cx = new_sub_block_ctxt(lleq.bcx, "matched_cx"); @@ -4298,7 +4294,7 @@ fn trans_pat_match(&@block_ctxt cx, &@ast::pat pat, ValueRef llval, cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb); auto ty_params = - ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx.node_types, ann); + ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx, ann); if (vec::len[@ast::pat](subpats) > 0u) { auto llblobptr = matched_cx.build.GEP(lltagptr, @@ -4359,7 +4355,7 @@ fn trans_pat_binding(&@block_ctxt cx, &@ast::pat pat, auto llblobptr = cx.build.GEP(lltagptr, [C_int(0), C_int(1)]); auto ty_param_substs = - ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx.node_types, ann); + ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx, ann); auto this_cx = cx; auto i = 0; @@ -4408,7 +4404,7 @@ fn trans_alt(&@block_ctxt cx, &@ast::expr expr, "non-exhaustive match failure"); // FIXME: This isn't quite right, particularly re: dynamic types - auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx.node_types, ann); + auto expr_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann); auto expr_llty; if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, expr_ty)) { expr_llty = T_typaram_ptr(cx.fcx.lcx.ccx.tn); @@ -4473,8 +4469,8 @@ fn lval_generic_fn(&@block_ctxt cx, lv = trans_external_path(cx, fn_id, tpt); } - auto tys = ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx.node_types, ann); - auto monoty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx.node_types, ann); + auto tys = ty::ann_to_type_params(cx.fcx.lcx.ccx.tcx, ann); + auto monoty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann); if (vec::len[ty::t](tys) != 0u) { auto bcx = lv.res.bcx; @@ -5361,7 +5357,7 @@ fn trans_call(&@block_ctxt cx, &@ast::expr f, } - auto ret_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx.node_types, ann); + auto ret_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann); auto args_res = trans_args(f_res.res.bcx, llenv, f_res.llobj, f_res.generic, @@ -6910,7 +6906,7 @@ fn is_terminated(&@block_ctxt cx) -> bool { } fn arg_tys_of_fn(&@crate_ctxt ccx, ast::ann ann) -> vec[ty::arg] { - alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx.node_types, ann))) { + alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx, ann))) { case (ty::ty_fn(_, ?arg_tys, _, _)) { ret arg_tys; } @@ -6927,7 +6923,7 @@ fn ret_ty_of_fn_ty(&@crate_ctxt ccx, ty::t t) -> ty::t { fn ret_ty_of_fn(&@crate_ctxt ccx, ast::ann ann) -> ty::t { - ret ret_ty_of_fn_ty(ccx, ty::ann_to_type(ccx.tcx.node_types, ann)); + ret ret_ty_of_fn_ty(ccx, ty::ann_to_type(ccx.tcx, ann)); } fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, val_self_pair llself) { diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs index 4aa178d6c5c12..b801954b933e3 100644 --- a/src/comp/middle/tstate/auxiliary.rs +++ b/src/comp/middle/tstate/auxiliary.rs @@ -482,7 +482,7 @@ fn controlflow_def_id(&crate_ctxt ccx, &def_id d) -> controlflow { If it has a function type with a ! annotation, the answer is noreturn. */ fn controlflow_expr(&crate_ctxt ccx, @expr e) -> controlflow { - alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx.node_types, + alt (ty::struct(ccx.tcx, ty::ann_to_type(ccx.tcx, expr_ann(e)))) { case (ty::ty_fn(_,_,_,?cf)) { ret cf; diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 9095f9e9c5277..206eb24501c43 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -921,9 +921,7 @@ fn sequence_element_type(&ctxt cx, &t ty) -> t { // NB: This is not exhaustive. } - // FIXME: add sess.err or sess.span_err explaining failure (issue - // #444) - fail; + cx.sess.bug("sequence_element_type called on non-sequence value"); } fn type_is_tup_like(&ctxt cx, &t ty) -> bool { @@ -949,8 +947,8 @@ fn get_element_type(&ctxt cx, &t ty, uint i) -> t { // tag. } - // FIXME: add sess.err or sess.span_err explaining failure (issue #444) - fail; + cx.sess.bug("get_element_type called on a value other than a " + + "tuple or record"); } fn type_is_box(&ctxt cx, &t ty) -> bool { @@ -1544,24 +1542,25 @@ fn eq_ty(&t a, &t b) -> bool { ret a == b; } // Type lookups -fn ann_to_ty_param_substs_opt_and_ty(&node_type_table ntt, &ast::ann ann) - -> ty_param_substs_opt_and_ty { - alt ({ntt.(ann.id)}) { +fn ann_to_ty_param_substs_opt_and_ty(&ty_ctxt tcx, &ast::ann ann) + -> ty_param_substs_opt_and_ty { + + // Pull out the node type table. + alt ({tcx.node_types.(ann.id)}) { case (none) { - log_err "ann_to_ty_param_substs_opt_and_ty() called on an " + - "untyped node"; - fail; + tcx.sess.bug("ann_to_ty_param_substs_opt_and_ty() called on an " + + "untyped node"); } case (some(?tpot)) { ret tpot; } } } -fn ann_to_type(&node_type_table ntt, &ast::ann ann) -> t { - ret ann_to_ty_param_substs_opt_and_ty(ntt, ann)._1; +fn ann_to_type(&ty_ctxt tcx, &ast::ann ann) -> t { + ret ann_to_ty_param_substs_opt_and_ty(tcx, ann)._1; } -fn ann_to_type_params(&node_type_table ntt, &ast::ann ann) -> vec[t] { - alt (ann_to_ty_param_substs_opt_and_ty(ntt, ann)._0) { +fn ann_to_type_params(&ty_ctxt tcx, &ast::ann ann) -> vec[t] { + alt (ann_to_ty_param_substs_opt_and_ty(tcx, ann)._0) { case (none) { let vec[t] result = []; ret result; @@ -1570,8 +1569,8 @@ fn ann_to_type_params(&node_type_table ntt, &ast::ann ann) -> vec[t] { } } -fn ann_has_type_params(&node_type_table ntt, &ast::ann ann) -> bool { - auto tpt = ann_to_ty_param_substs_opt_and_ty(ntt, ann); +fn ann_has_type_params(&ty_ctxt tcx, &ast::ann ann) -> bool { + auto tpt = ann_to_ty_param_substs_opt_and_ty(tcx, ann); ret !option::is_none[vec[t]](tpt._0); } @@ -1579,7 +1578,7 @@ fn ann_has_type_params(&node_type_table ntt, &ast::ann ann) -> bool { // Returns the type of an annotation, with type parameter substitutions // performed if applicable. fn ann_to_monotype(&ctxt cx, ast::ann a) -> t { - auto tpot = ann_to_ty_param_substs_opt_and_ty(cx.node_types, a); + auto tpot = ann_to_ty_param_substs_opt_and_ty(cx, a); alt (tpot._0) { case (none) { ret tpot._1; } case (some(?tps)) { @@ -1638,21 +1637,21 @@ fn ty_fn_args(&ctxt cx, &t fty) -> vec[arg] { case (ty::ty_fn(_, ?a, _, _)) { ret a; } case (ty::ty_native_fn(_, ?a, _)) { ret a; } } - fail; + cx.sess.bug("ty_fn_args() called on non-fn type"); } fn ty_fn_proto(&ctxt cx, &t fty) -> ast::proto { alt (struct(cx, fty)) { case (ty::ty_fn(?p, _, _, _)) { ret p; } } - fail; + cx.sess.bug("ty_fn_proto() called on non-fn type"); } fn ty_fn_abi(&ctxt cx, &t fty) -> ast::native_abi { alt (struct(cx, fty)) { case (ty::ty_native_fn(?a, _, _)) { ret a; } } - fail; + cx.sess.bug("ty_fn_abi() called on non-native-fn type"); } fn ty_fn_ret(&ctxt cx, &t fty) -> t { @@ -1660,7 +1659,7 @@ fn ty_fn_ret(&ctxt cx, &t fty) -> t { case (ty::ty_fn(_, _, ?r, _)) { ret r; } case (ty::ty_native_fn(_, _, ?r)) { ret r; } } - fail; + cx.sess.bug("ty_fn_ret() called on non-fn type"); } fn is_fn_ty(&ctxt cx, &t fty) -> bool { @@ -1674,66 +1673,8 @@ fn is_fn_ty(&ctxt cx, &t fty) -> bool { // Type accessors for AST nodes -// Given an item, returns the associated type as well as the number of type -// parameters it has. -fn native_item_ty(&node_type_table ntt, &@ast::native_item it) - -> ty_param_count_and_ty { - auto ty_param_count; - auto result_ty; - alt (it.node) { - case (ast::native_item_fn(_, _, _, ?tps, _, ?ann)) { - ty_param_count = vec::len[ast::ty_param](tps); - result_ty = ann_to_type(ntt, ann); - } - } - ret tup(ty_param_count, result_ty); -} - -fn item_ty(&node_type_table ntt, &@ast::item it) -> ty_param_count_and_ty { - auto ty_param_count; - auto result_ty; - alt (it.node) { - case (ast::item_const(_, _, _, _, ?ann)) { - ty_param_count = 0u; - result_ty = ann_to_type(ntt, ann); - } - case (ast::item_fn(_, _, ?tps, _, ?ann)) { - ty_param_count = vec::len[ast::ty_param](tps); - result_ty = ann_to_type(ntt, ann); - } - case (ast::item_mod(_, _, _)) { - fail; // modules are typeless - } - case (ast::item_ty(_, _, ?tps, _, ?ann)) { - ty_param_count = vec::len[ast::ty_param](tps); - result_ty = ann_to_type(ntt, ann); - } - case (ast::item_tag(_, _, ?tps, ?did, ?ann)) { - ty_param_count = vec::len[ast::ty_param](tps); - result_ty = ann_to_type(ntt, ann); - } - case (ast::item_obj(_, _, ?tps, _, ?ann)) { - ty_param_count = vec::len[ast::ty_param](tps); - result_ty = ann_to_type(ntt, ann); - } - } - - ret tup(ty_param_count, result_ty); -} - -fn stmt_ty(&ctxt cx, &@ast::stmt s) -> t { - alt (s.node) { - case (ast::stmt_expr(?e,_)) { - ret expr_ty(cx, e); - } - case (_) { - ret mk_nil(cx); - } - } -} - fn block_ty(&ctxt cx, &ast::block b) -> t { - ret ann_to_type(cx.node_types, b.node.a); + ret ann_to_type(cx, b.node.a); } // Returns the type of a pattern as a monotype. Like @expr_ty, this function @@ -1820,18 +1761,18 @@ fn expr_ty_params_and_ty(&ctxt cx, &@ast::expr expr) -> tup(vec[t], t) { auto a = expr_ann(expr); - ret tup(ann_to_type_params(cx.node_types, a), - ann_to_type(cx.node_types, a)); + ret tup(ann_to_type_params(cx, a), + ann_to_type(cx, a)); } -fn expr_has_ty_params(&node_type_table ntt, &@ast::expr expr) -> bool { - ret ann_has_type_params(ntt, expr_ann(expr)); +fn expr_has_ty_params(&ty_ctxt tcx, &@ast::expr expr) -> bool { + ret ann_has_type_params(tcx, expr_ann(expr)); } fn decl_local_ty(&ctxt cx, &@ast::decl d) -> t { alt (d.node) { case (ast::decl_local(?l)) { - ret ann_to_type(cx.node_types, l.ann); + ret ann_to_type(cx, l.ann); } case (_) { cx.sess.bug("decl_local_ty called on an item decl"); @@ -2281,8 +2222,9 @@ mod unify { case (ty::ty_bound_param(?actual_id)) { alt (struct(cx.tcx, expected)) { case (ty::ty_local(_)) { - log_err "TODO: bound param unifying with local"; - fail; + // TODO: bound param unifying with local + cx.tcx.sess.unimpl("TODO: bound param unifying with " + + "local"); } case (_) { @@ -2686,18 +2628,15 @@ mod unify { } fn unify_sets[T](&ty_ctxt tcx, &@bindings[T] bindings) -> set_result { - obj handler() { + obj handler(ty_ctxt tcx) { fn resolve_local(ast::def_id id) -> option::t[t] { - log_err "resolve_local in unify_sets"; - fail; + tcx.sess.bug("resolve_local in unify_sets"); } fn record_local(ast::def_id id, t ty) { - log_err "record_local in unify_sets"; - fail; + tcx.sess.bug("record_local in unify_sets"); } fn record_param(uint index, t binding) -> unify::result { - log_err "record_param in unify_sets"; - fail; + tcx.sess.bug("record_param in unify_sets"); } } @@ -2718,8 +2657,8 @@ mod unify { // FIXME: Is this right? auto bindings = mk_bindings[int](int::hash, int::eq_alias); - alt (unify(expected, actual, handler(), bindings, - tcx)) { + alt (unify(expected, actual, handler(tcx), + bindings, tcx)) { case (ures_ok(?result_ty)) { results.(i) = some[t](result_ty); } @@ -2840,9 +2779,8 @@ fn bind_params_in_type(&ctxt cx, &t typ) -> t { fn binder(&ctxt cx, t typ) -> t { alt (struct(cx, typ)) { case (ty_bound_param(?index)) { - log_err "bind_params_in_type() called on type that already " + - "has bound params in it"; - fail; + cx.sess.bug("bind_params_in_type() called on type that " + + "already has bound params in it"); } case (ty_param(?index)) { ret mk_bound_param(cx, index); } case (_) { ret typ; } @@ -2924,9 +2862,9 @@ fn tag_variant_with_id(&ctxt cx, } i += 1u; } + + cx.sess.bug("tag_variant_with_id(): no variant exists with that ID"); - log_err "tag_variant_with_id(): no variant exists with that ID"; - fail; } // If the given item is in an external crate, looks up its type and adds it to @@ -2954,13 +2892,13 @@ fn ret_ty_of_fn_ty(ty_ctxt tcx, t a_ty) -> t { ret ret_ty; } case (_) { - fail; + tcx.sess.bug("ret_ty_of_fn_ty() called on non-function type"); } } } fn ret_ty_of_fn(ty_ctxt tcx, ast::ann ann) -> t { - ret ret_ty_of_fn_ty(tcx, ann_to_type(tcx.node_types, ann)); + ret ret_ty_of_fn_ty(tcx, ann_to_type(tcx, ann)); } // Local Variables: diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 11fbab4ddde44..c07e76f8332e2 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1116,7 +1116,7 @@ mod pushdown { // TODO: enforce mutability auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, ann)); alt (struct(scx.fcx.ccx.tcx, t)) { case (ty::ty_vec(?mt)) { for (@ast::expr e_0 in es_0) { @@ -1132,7 +1132,7 @@ mod pushdown { } case (ast::expr_tup(?es_0, ?ann)) { auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, ann)); alt (struct(scx.fcx.ccx.tcx, t)) { case (ty::ty_tup(?mts)) { auto i = 0u; @@ -1151,7 +1151,7 @@ mod pushdown { case (ast::expr_rec(?fields_0, ?base_0, ?ann)) { auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, ann)); alt (struct(scx.fcx.ccx.tcx, t)) { case (ty::ty_rec(?field_mts)) { alt (base_0) { @@ -1192,7 +1192,7 @@ mod pushdown { } case (ast::expr_bind(?sube, ?es, ?ann)) { auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, ann)); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_call(?sube, ?es, ?ann)) { @@ -1201,24 +1201,24 @@ mod pushdown { // produce a box; things like expr_binary or expr_bind can't, // so there's no need. auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_self_method(?id, ?ann)) { auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, ann)); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_binary(?bop, ?lhs, ?rhs, ?ann)) { auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, ann)); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_unary(?uop, ?sube, ?ann)) { // See note in expr_unary for why we're calling // demand::autoderef. auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); write::ty_only_fixup(scx, ann.id, t); /* The following is a bit special-cased, but takes care of @@ -1248,17 +1248,17 @@ mod pushdown { } case (ast::expr_lit(?lit, ?ann)) { auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, ann)); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_cast(?sube, ?ast_ty, ?ann)) { auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, ann)); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_if(?cond, ?then_0, ?else_0, ?ann)) { auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); auto then_t = ty::block_ty(scx.fcx.ccx.tcx, then_0); pushdown_block(scx, expected, then_0); @@ -1274,65 +1274,65 @@ mod pushdown { } case (ast::expr_for(?decl, ?seq, ?bloc, ?ann)) { auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, ann)); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_for_each(?decl, ?seq, ?bloc, ?ann)) { auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, ann)); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_while(?cond, ?bloc, ?ann)) { auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, ann)); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_do_while(?bloc, ?cond, ?ann)) { auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, ann)); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_block(?bloc, ?ann)) { auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); write::ty_only_fixup(scx, ann.id, t); pushdown_block(scx, t, bloc); } case (ast::expr_move(?lhs_0, ?rhs_0, ?ann)) { auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); pushdown_expr(scx, expected, lhs_0); pushdown_expr(scx, expected, rhs_0); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_assign(?lhs_0, ?rhs_0, ?ann)) { auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); pushdown_expr(scx, expected, lhs_0); pushdown_expr(scx, expected, rhs_0); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_assign_op(?op, ?lhs_0, ?rhs_0, ?ann)) { auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); pushdown_expr(scx, expected, lhs_0); pushdown_expr(scx, expected, rhs_0); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_field(?lhs, ?rhs, ?ann)) { auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_index(?base, ?index, ?ann)) { auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_path(?pth, ?ann)) { auto tp_substs_0 = - ty::ann_to_type_params(scx.fcx.ccx.tcx.node_types, ann); - auto t_0 = ann_to_type(scx.fcx.ccx.tcx.node_types, ann); + ty::ann_to_type_params(scx.fcx.ccx.tcx, ann); + auto t_0 = ann_to_type(scx.fcx.ccx.tcx, ann); auto result_0 = demand::full(scx, e.span, expected, t_0, tp_substs_0, adk); @@ -1341,8 +1341,9 @@ mod pushdown { // Fill in the type parameter substitutions if they weren't // provided by the programmer. auto ty_params_opt; + alt (ty::ann_to_ty_param_substs_opt_and_ty - (scx.fcx.ccx.tcx.node_types, ann)._0) { + (scx.fcx.ccx.tcx, ann)._0) { case (none) { ty_params_opt = none[vec[ty::t]]; } @@ -1355,7 +1356,7 @@ mod pushdown { } case (ast::expr_ext(?p, ?args, ?body, ?expanded, ?ann)) { auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); write::ty_only_fixup(scx, ann.id, t); } /* FIXME: should this check the type annotations? */ @@ -1371,13 +1372,13 @@ mod pushdown { case (ast::expr_port(?ann)) { auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, ann)); write::ty_only_fixup(scx, ann.id, t); } case (ast::expr_chan(?es, ?ann)) { auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann)); + ann_to_type(scx.fcx.ccx.tcx, ann)); alt (struct(scx.fcx.ccx.tcx, t)) { case (ty::ty_chan(?subty)) { auto pt = ty::mk_port(scx.fcx.ccx.tcx, subty); @@ -1419,7 +1420,7 @@ mod pushdown { // produce a box; things like expr_binary or expr_bind can't, // so there's no need. auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); write::ty_only_fixup(scx, ann.id, t); } @@ -1427,7 +1428,7 @@ mod pushdown { // NB: Not sure if this is correct, but not worrying too much // about it since pushdown is going away anyway. auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, ann), adk); + ann_to_type(scx.fcx.ccx.tcx, ann), adk); write::ty_only_fixup(scx, ann.id, t); } @@ -1450,7 +1451,7 @@ mod pushdown { } } demand::simple(scx, bloc.span, expected, - ann_to_type(scx.fcx.ccx.tcx.node_types, bloc.node.a)); + ann_to_type(scx.fcx.ccx.tcx, bloc.node.a)); } } @@ -1488,7 +1489,7 @@ mod writeback { } auto tpot = - ty::ann_to_ty_param_substs_opt_and_ty(fcx.ccx.tcx.node_types, + ty::ann_to_ty_param_substs_opt_and_ty(fcx.ccx.tcx, ann); auto tt = tpot._1; if (!ty::type_contains_locals(fcx.ccx.tcx, tt)) { ret; } @@ -1553,7 +1554,7 @@ fn replace_expr_type(&@stmt_ctxt scx, &@ast::expr expr, &tup(vec[ty::t], ty::t) new_tyt) { auto new_tps; - if (ty::expr_has_ty_params(scx.fcx.ccx.tcx.node_types, expr)) { + if (ty::expr_has_ty_params(scx.fcx.ccx.tcx, expr)) { new_tps = some[vec[ty::t]](new_tyt._0); } else { new_tps = none[vec[ty::t]]; @@ -2722,7 +2723,7 @@ fn check_block(&@stmt_ctxt scx, &ast::block block) { fn check_const(&@crate_ctxt ccx, &span sp, &@ast::expr e, &ast::ann ann) { // FIXME: this is kinda a kludge; we manufacture a fake function context // and statement context for checking the initializer expression. - auto rty = ann_to_type(ccx.tcx.node_types, ann); + auto rty = ann_to_type(ccx.tcx, ann); let @fn_ctxt fcx = @rec(ret_ty = rty, purity = ast::pure_fn, locals = @common::new_def_hash[ty::t](), @@ -2742,7 +2743,7 @@ fn check_fn(&@crate_ctxt ccx, &ast::fn_decl decl, ast::proto proto, alt (get_obj_info(ccx)) { case (option::some(?oinfo)) { for (ast::obj_field f in oinfo.obj_fields) { - auto field_ty = ty::ann_to_type(ccx.tcx.node_types, f.ann); + auto field_ty = ty::ann_to_type(ccx.tcx, f.ann); local_ty_table.insert(f.id, field_ty); } } diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index be492d03a1ae7..2c7e65dcb2200 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -945,7 +945,7 @@ fn print_decl(&ps s, &@ast::decl decl) { case (mo_untyped) { /* no-op */ } case (mo_typed(?tcx)) { auto lty = - ty::ann_to_type(tcx.node_types, loc.ann); + ty::ann_to_type(tcx, loc.ann); word_space(s, ty::ty_to_str(tcx, lty)); } case (mo_identified) { /* no-op */ } From 9a2546fa2f71e95d6da76f4ce55042e822585c9d Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Tue, 7 Jun 2011 15:07:27 -0700 Subject: [PATCH 39/64] For consistency, use ctxt instead of ty_ctxt outside of unify. --- src/comp/middle/ty.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 206eb24501c43..0200cdd30f862 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -1542,25 +1542,25 @@ fn eq_ty(&t a, &t b) -> bool { ret a == b; } // Type lookups -fn ann_to_ty_param_substs_opt_and_ty(&ty_ctxt tcx, &ast::ann ann) +fn ann_to_ty_param_substs_opt_and_ty(&ctxt cx, &ast::ann ann) -> ty_param_substs_opt_and_ty { // Pull out the node type table. - alt ({tcx.node_types.(ann.id)}) { + alt ({cx.node_types.(ann.id)}) { case (none) { - tcx.sess.bug("ann_to_ty_param_substs_opt_and_ty() called on an " + - "untyped node"); + cx.sess.bug("ann_to_ty_param_substs_opt_and_ty() called on an " + + "untyped node"); } case (some(?tpot)) { ret tpot; } } } -fn ann_to_type(&ty_ctxt tcx, &ast::ann ann) -> t { - ret ann_to_ty_param_substs_opt_and_ty(tcx, ann)._1; +fn ann_to_type(&ctxt cx, &ast::ann ann) -> t { + ret ann_to_ty_param_substs_opt_and_ty(cx, ann)._1; } -fn ann_to_type_params(&ty_ctxt tcx, &ast::ann ann) -> vec[t] { - alt (ann_to_ty_param_substs_opt_and_ty(tcx, ann)._0) { +fn ann_to_type_params(&ctxt cx, &ast::ann ann) -> vec[t] { + alt (ann_to_ty_param_substs_opt_and_ty(cx, ann)._0) { case (none) { let vec[t] result = []; ret result; @@ -1569,8 +1569,8 @@ fn ann_to_type_params(&ty_ctxt tcx, &ast::ann ann) -> vec[t] { } } -fn ann_has_type_params(&ty_ctxt tcx, &ast::ann ann) -> bool { - auto tpt = ann_to_ty_param_substs_opt_and_ty(tcx, ann); +fn ann_has_type_params(&ctxt cx, &ast::ann ann) -> bool { + auto tpt = ann_to_ty_param_substs_opt_and_ty(cx, ann); ret !option::is_none[vec[t]](tpt._0); } @@ -1765,8 +1765,8 @@ fn expr_ty_params_and_ty(&ctxt cx, &@ast::expr expr) ann_to_type(cx, a)); } -fn expr_has_ty_params(&ty_ctxt tcx, &@ast::expr expr) -> bool { - ret ann_has_type_params(tcx, expr_ann(expr)); +fn expr_has_ty_params(&ctxt cx, &@ast::expr expr) -> bool { + ret ann_has_type_params(cx, expr_ann(expr)); } fn decl_local_ty(&ctxt cx, &@ast::decl d) -> t { @@ -2886,19 +2886,19 @@ fn lookup_item_type(ctxt cx, ast::def_id did) -> ty_param_count_and_ty { } } -fn ret_ty_of_fn_ty(ty_ctxt tcx, t a_ty) -> t { - alt (ty::struct(tcx, a_ty)) { +fn ret_ty_of_fn_ty(ctxt cx, t a_ty) -> t { + alt (ty::struct(cx, a_ty)) { case (ty::ty_fn(_, _, ?ret_ty, _)) { ret ret_ty; } case (_) { - tcx.sess.bug("ret_ty_of_fn_ty() called on non-function type"); + cx.sess.bug("ret_ty_of_fn_ty() called on non-function type"); } } } -fn ret_ty_of_fn(ty_ctxt tcx, ast::ann ann) -> t { - ret ret_ty_of_fn_ty(tcx, ann_to_type(tcx, ann)); +fn ret_ty_of_fn(ctxt cx, ast::ann ann) -> t { + ret ret_ty_of_fn_ty(cx, ann_to_type(cx, ann)); } // Local Variables: From bc0ea9120e2b5a0bed5f423b3f972adb36c0a045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20=C3=81vila=20de=20Esp=C3=ADndola?= Date: Tue, 7 Jun 2011 20:40:31 -0400 Subject: [PATCH 40/64] Update the snapshot. --- src/snapshots.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/snapshots.txt b/src/snapshots.txt index d64be8bffe1fd..5b41fb5a15874 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,8 @@ +S 2011-06-07 a4ca75e + linux-i386 3de95184c59f5b0554df3da995090aaba26a190f + macos-i386 1537f2e01c746dc6ca2a9bfb4b2e81256bb01e96 + winnt-i386 538765c5c4c31dfe8d6e998ef7503beb5cfa1525 + S 2011-06-03 f29d046 linux-i386 76e4ee5b9148aae30ebfaabb12791bfee4fa8727 macos-i386 e146fa18f4b0f22fe4fd7fd104242837569d7702 From 7d47d9304fd33c7fd5571a24ab3e9425ec75066e Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Tue, 7 Jun 2011 17:54:22 -0700 Subject: [PATCH 41/64] More work on proper linkage name-mangling. Almost right, aside from version numbers. --- src/comp/back/link.rs | 246 ++++++++++++++++++++++++++++++++++++- src/comp/driver/session.rs | 43 ++++--- src/comp/front/ast.rs | 7 +- src/comp/front/eval.rs | 9 +- src/comp/front/parser.rs | 6 +- src/comp/middle/trans.rs | 189 +++++++++++----------------- src/comp/middle/walk.rs | 2 +- src/lib/fs.rs | 14 +++ src/lib/std.rc | 8 +- 9 files changed, 381 insertions(+), 143 deletions(-) diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index 2ae7b6a6fab30..6469bbd3ced25 100644 --- a/src/comp/back/link.rs +++ b/src/comp/back/link.rs @@ -1,8 +1,18 @@ import driver::session; import lib::llvm::llvm; import middle::trans; +import middle::metadata; +import middle::ty; import std::str; import std::fs; +import std::vec; +import std::option; +import option::some; +import option::none; +import std::sha1::sha1; +import std::sort; +import trans::crate_ctxt; +import front::ast; import lib::llvm::llvm::ModuleRef; import lib::llvm::llvm::ValueRef; @@ -49,7 +59,7 @@ fn link_intrinsics(session::session sess, ModuleRef llmod) { auto linkres = llvm::LLVMLinkModules(llmod, llintrinsicsmod); llvm::LLVMDisposeModule(llintrinsicsmod); - + if (linkres == False) { llvm_err(sess, "couldn't link the module with the intrinsics"); fail; @@ -58,7 +68,7 @@ fn link_intrinsics(session::session sess, ModuleRef llmod) { mod write { fn is_object_or_assembly_or_exe(output_type ot) -> bool { - if ( (ot == output_type_assembly) || + if ( (ot == output_type_assembly) || (ot == output_type_object) || (ot == output_type_exe) ) { ret true; @@ -218,3 +228,235 @@ mod write { } } +/* + * Name mangling and its relationship to metadata. This is complex. Read + * carefully. + * + * The semantic model of Rust linkage is, broadly, that "there's no global + * namespace" between crates. Our aim is to preserve the illusion of this + * model despite the fact that it's not *quite* possible to implement on + * modern linkers. We initially didn't use system linkers at all, but have + * been convinced of their utility. + * + * There are a few issues to handle: + * + * - Linkers operate on a flat namespace, so we have to flatten names. + * We do this using the C++ namespace-mangling technique. Foo::bar + * symbols and such. + * + * - Symbols with the same name but different types need to get different + * linkage-names. We do this by hashing a string-encoding of the type into + * a fixed-size (currently 16-byte hex) cryptographic hash function (CHF: + * we use SHA1) to "prevent collisions". This is not airtight but 16 hex + * digits on uniform probability means you're going to need 2**32 same-name + * symbols in the same process before you're even hitting birthday-paradox + * collision probability. + * + * - Symbols in dirrerent crates but with same names "within" the crate need + * to get different linkage-names. + * + * So here is what we do: + * + * - Separate the meta tags into two sets: exported and local. Only work with + * the exported ones when considering linkage. + * + * - Consider two exported tags as special (and madatory): name and vers. + * Every crate gets them; if it doesn't name them explicitly we infer them + * as basename(crate) and "0.1", respectively. Call these CNAME, CVERS. + * + * - Define CMETA as all the non-name, non-vers exported meta tags in the + * crate (in sorted order). + * + * - Define CMH as hash(CMETA). + * + * - Compile our crate to lib CNAME-CMH-CVERS.so + * + * - Define STH(sym) as hash(CNAME, CMH, type_str(sym)) + * + * - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the + * name, non-name metadata, and type sense, and versioned in the way + * system linkers understand. + * + */ + + +iter crate_export_metas(ast::crate c) -> @ast::meta_item { + for (@ast::crate_directive cdir in c.node.directives) { + alt (cdir.node) { + case (ast::cdir_meta(?v, ?mis)) { + if (v == ast::export_meta) { + for (@ast::meta_item mi in mis) { + put mi; + } + } + } + case (_) {} + } + } +} +fn get_crate_meta(&session::session sess, + &ast::crate c, str k, str default, + bool warn_default) -> str { + let vec[@ast::meta_item] v = []; + for each (@ast::meta_item mi in crate_export_metas(c)) { + if (mi.node.name == k) { + v += [mi]; + } + } + alt (vec::len(v)) { + case (0u) { + if (warn_default) { + sess.warn(#fmt("missing meta '%s', using '%s' as default", + k, default)); + } + ret default; + } + case (1u) { + ret v.(0).node.value; + } + case (_) { + sess.span_err(v.(1).span, #fmt("duplicate meta '%s'", k)); + } + } +} + +// This calculates CMH as defined above +fn crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str { + fn lteq(&@ast::meta_item ma, + &@ast::meta_item mb) -> bool { + ret ma.node.name <= mb.node.name; + } + + fn len_and_str(&str s) -> str { + ret #fmt("%u_%s", str::byte_len(s), s); + } + + let vec[mutable @ast::meta_item] v = [mutable]; + for each (@ast::meta_item mi in crate_export_metas(crate)) { + if (mi.node.name != "name" && + mi.node.name != "vers") { + v += [mutable mi]; + } + } + sort::quick_sort(lteq, v); + sha.reset(); + for (@ast::meta_item m in v) { + sha.input_str(len_and_str(m.node.name)); + sha.input_str(len_and_str(m.node.value)); + } + ret truncated_sha1_result(sha); +} + +fn crate_meta_name(&session::session sess, &ast::crate crate, + &str output) -> str { + auto os = str::split(fs::basename(output), '.' as u8); + assert vec::len(os) >= 2u; + vec::pop(os); + ret get_crate_meta(sess, crate, "name", str::connect(os, "."), + sess.get_opts().shared); +} + +fn crate_meta_vers(&session::session sess, &ast::crate crate) -> str { + ret get_crate_meta(sess, crate, "vers", "0.0", + sess.get_opts().shared); +} + +fn truncated_sha1_result(sha1 sha) -> str { + ret str::substr(sha.result_str(), 0u, 16u); +} + + + +// This calculates STH for a symbol, as defined above +fn symbol_hash(ty::ctxt tcx, sha1 sha, &ty::t t, + str crate_meta_name, + str crate_meta_extras_hash) -> str { + // NB: do *not* use abbrevs here as we want the symbol names + // to be independent of one another in the crate. + auto cx = @rec(ds=metadata::def_to_str, tcx=tcx, + abbrevs=metadata::ac_no_abbrevs); + sha.reset(); + sha.input_str(crate_meta_name); + sha.input_str("-"); + sha.input_str(crate_meta_name); + sha.input_str("-"); + sha.input_str(metadata::Encode::ty_str(cx, t)); + auto hash = truncated_sha1_result(sha); + // Prefix with _ so that it never blends into adjacent digits + ret "_" + hash; +} + +fn get_symbol_hash(&@crate_ctxt ccx, &ty::t t) -> str { + auto hash = ""; + alt (ccx.type_sha1s.find(t)) { + case (some(?h)) { hash = h; } + case (none) { + hash = symbol_hash(ccx.tcx, ccx.sha, t, + ccx.crate_meta_name, + ccx.crate_meta_extras_hash); + ccx.type_sha1s.insert(t, hash); + } + } + ret hash; +} + + +fn mangle(&vec[str] ss) -> str { + + // Follow C++ namespace-mangling style + + auto n = "_ZN"; // Begin name-sequence. + + for (str s in ss) { + n += #fmt("%u%s", str::byte_len(s), s); + } + + n += "E"; // End name-sequence. + ret n; +} + + +fn exported_name(&vec[str] path, &str hash, &str vers) -> str { + // FIXME: versioning isn't working yet + ret mangle(path + [hash]); // + "@" + vers; +} + +fn mangle_exported_name(&@crate_ctxt ccx, &vec[str] path, + &ty::t t) -> str { + auto hash = get_symbol_hash(ccx, t); + ret exported_name(path, hash, ccx.crate_meta_vers); +} + +fn mangle_internal_name_by_type_only(&@crate_ctxt ccx, &ty::t t, + &str name) -> str { + auto f = metadata::def_to_str; + auto cx = @rec(ds=f, tcx=ccx.tcx, abbrevs=metadata::ac_no_abbrevs); + auto s = ty::ty_to_short_str(ccx.tcx, t); + + auto hash = get_symbol_hash(ccx, t); + ret mangle([name, s, hash]); +} + +fn mangle_internal_name_by_path_and_seq(&@crate_ctxt ccx, &vec[str] path, + &str flav) -> str { + ret mangle(path + [ccx.names.next(flav)]); +} + +fn mangle_internal_name_by_path(&@crate_ctxt ccx, &vec[str] path) -> str { + ret mangle(path); +} + +fn mangle_internal_name_by_seq(&@crate_ctxt ccx, &str flav) -> str { + ret ccx.names.next(flav); +} + +// +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: +// diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs index 9f025849402e6..e0080ca265156 100644 --- a/src/comp/driver/session.rs +++ b/src/comp/driver/session.rs @@ -6,6 +6,9 @@ import std::uint; import std::term; import std::io; import std::map; +import std::option; +import std::option::some; +import std::option::none; tag os { os_win32; @@ -48,9 +51,16 @@ fn span_to_str(span sp, codemap::codemap cm) -> str { lo.col, hi.line, hi.col)); } -fn emit_diagnostic(span sp, str msg, str kind, u8 color, +fn emit_diagnostic(option::t[span] sp, str msg, str kind, u8 color, codemap::codemap cm) { - io::stdout().write_str(span_to_str(sp, cm) + ": "); + auto ss = ":0:0:0:0"; + alt (sp) { + case (some(?ssp)) { + ss = span_to_str(ssp, cm); + } + case (none) {} + } + io::stdout().write_str(ss + ": "); if (term::color_supported()) { term::fg(io::stdout().get_buf_writer(), color); @@ -85,12 +95,12 @@ state obj session(ast::crate_num cnum, fn span_err(span sp, str msg) -> ! { // FIXME: Use constants, but rustboot doesn't know how to export them. - emit_diagnostic(sp, msg, "error", 9u8, cm); + emit_diagnostic(some(sp), msg, "error", 9u8, cm); fail; } fn err(str msg) -> ! { - log_err #fmt("error: %s", msg); + emit_diagnostic(none[span], msg, "error", 9u8, cm); fail; } @@ -103,29 +113,32 @@ state obj session(ast::crate_num cnum, fn span_warn(span sp, str msg) { // FIXME: Use constants, but rustboot doesn't know how to export them. - emit_diagnostic(sp, msg, "warning", 11u8, cm); + emit_diagnostic(some(sp), msg, "warning", 11u8, cm); + } + + fn warn(str msg) { + emit_diagnostic(none[span], msg, "warning", 11u8, cm); } fn span_note(span sp, str msg) { // FIXME: Use constants, but rustboot doesn't know how to export them. - emit_diagnostic(sp, msg, "note", 10u8, cm); + emit_diagnostic(some(sp), msg, "note", 10u8, cm); + } + + fn span_bug(span sp, str msg) -> ! { + self.span_err(sp, #fmt("internal compiler error %s", msg)); } fn bug(str msg) -> ! { - log_err #fmt("error: internal compiler error %s", msg); - fail; + self.err(#fmt("internal compiler error %s", msg)); } fn span_unimpl(span sp, str msg) -> ! { - // FIXME: Use constants, but rustboot doesn't know how to export them. - emit_diagnostic(sp, "internal compiler error: unimplemented " + msg, - "error", 9u8, cm); - fail; + self.span_bug(sp, "unimplemented " + msg); } - + fn unimpl(str msg) -> ! { - log_err #fmt("error: unimplemented %s", msg); - fail; + self.bug("unimplemented " + msg); } fn get_external_crate(int num) -> crate_metadata { diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 92f12c3dc1b4e..f670c2760a7c5 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -71,6 +71,11 @@ type crate = spanned[crate_]; type crate_ = rec(vec[@crate_directive] directives, _mod module); +tag meta_visibility { + export_meta; + local_meta; +} + tag crate_directive_ { cdir_expr(@expr); // FIXME: cdir_let should be eliminated @@ -80,7 +85,7 @@ tag crate_directive_ { cdir_src_mod(ident, option::t[filename]); cdir_dir_mod(ident, option::t[filename], vec[@crate_directive]); cdir_view_item(@view_item); - cdir_meta(vec[@meta_item]); + cdir_meta(meta_visibility, vec[@meta_item]); cdir_syntax(path); cdir_auth(path, _auth); } diff --git a/src/comp/front/eval.rs b/src/comp/front/eval.rs index d5a76372846d6..a8e881ee036c3 100644 --- a/src/comp/front/eval.rs +++ b/src/comp/front/eval.rs @@ -418,8 +418,13 @@ fn eval_crate_directive(ctx cx, vec::push[@ast::view_item](view_items, vi); } - case (ast::cdir_meta(?mi)) { - cx.sess.add_metadata(mi); + case (ast::cdir_meta(?vi, ?mi)) { + // FIXME: we should actually record, for documentation-sake, + // the metadata that's not exported. It would be nice to have + // compiled-in to the target crate, not just in theh AST. + if (vi == ast::export_meta) { + cx.sess.add_metadata(mi); + } } case (ast::cdir_syntax(?pth)) {} diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 62ba7325f9999..b84a740a917de 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -2362,10 +2362,14 @@ fn parse_crate_directive(&parser p) -> ast::crate_directive expect(p, token::SEMI); ret spanned(lo, hi, ast::cdir_auth(n, a)); } else if (eat_word(p, "meta")) { + auto mv = ast::local_meta; + if (eat_word(p, "export")) { + mv = ast::export_meta; + } auto mis = parse_meta(p); auto hi = p.get_hi_pos(); expect(p, token::SEMI); - ret spanned(lo, hi, ast::cdir_meta(mis)); + ret spanned(lo, hi, ast::cdir_meta(mv, mis)); } else if (eat_word(p, "mod")) { auto id = parse_ident(p); auto file_opt = none[filename]; diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 7333375b902c6..1687a62fa5777 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -6,7 +6,7 @@ // particular definition to the LLVM IR output we're producing. // // Hopefully useful general knowledge about trans: -// +// // * There's no way to find out the ty::t type of a ValueRef. Doing so // would be "trying to get the eggs out of an omelette" (credit: // pcwalton). You can, instead, find out its TypeRef by calling val_ty, @@ -24,6 +24,7 @@ import std::map::hashmap; import std::option; import std::option::some; import std::option::none; +import std::fs; import front::ast; import front::creader; @@ -62,6 +63,15 @@ import lib::llvm::False; import lib::llvm::True; import lib::llvm::Bool; +import link::mangle_internal_name_by_type_only; +import link::mangle_internal_name_by_seq; +import link::mangle_internal_name_by_path; +import link::mangle_internal_name_by_path_and_seq; +import link::mangle_exported_name; +import link::crate_meta_name; +import link::crate_meta_vers; +import link::crate_meta_extras_hash; + state obj namegen(mutable int i) { fn next(str prefix) -> str { i += 1; @@ -119,6 +129,9 @@ state type crate_ctxt = rec(session::session sess, @ast::native_item] native_items, hashmap[ast::def_id, str] item_symbols, mutable option::t[ValueRef] main_fn, + str crate_meta_name, + str crate_meta_vers, + str crate_meta_extras_hash, // TODO: hashmap[tup(tag_id,subtys), @tag_info] hashmap[ty::t, uint] tag_sizes, hashmap[ast::def_id, ValueRef] discrims, @@ -166,14 +179,14 @@ type fn_ctxt = rec( ValueRef lltaskptr, ValueRef llenv, ValueRef llretptr, - + // The next three elements: "hoisted basic blocks" containing // administrative activities that have to happen in only one place in the // function, due to LLVM's quirks. // A block for all the function's allocas, so that LLVM will coalesce them // into a single alloca call. - mutable BasicBlockRef llallocas, + mutable BasicBlockRef llallocas, // A block containing code that copies incoming arguments to space already // allocated by code in the llallocas block. (LLVM requires that @@ -313,73 +326,6 @@ fn extend_path(@local_ctxt cx, &str name) -> @local_ctxt { ret @rec(path = cx.path + [name] with *cx); } -fn get_type_sha1(&@crate_ctxt ccx, &ty::t t) -> str { - auto hash = ""; - alt (ccx.type_sha1s.find(t)) { - case (some(?h)) { hash = h; } - case (none) { - ccx.sha.reset(); - auto f = metadata::def_to_str; - // NB: do *not* use abbrevs here as we want the symbol names - // to be independent of one another in the crate. - auto cx = @rec(ds=f, - tcx=ccx.tcx, - abbrevs=metadata::ac_no_abbrevs); - - ccx.sha.input_str(metadata::Encode::ty_str(cx, t)); - hash = str::substr(ccx.sha.result_str(), 0u, 16u); - // Prefix with _ so that it never blends into adjacent digits - hash = "_" + hash; - ccx.type_sha1s.insert(t, hash); - } - } - ret hash; -} - -fn mangle(&vec[str] ss) -> str { - - if (vec::len(ss) > 0u && str::eq(vec::top(ss), "main")) { - ret "_rust_main"; - } - // Follow C++ namespace-mangling style - - auto n = "_ZN"; // Begin name-sequence. - - for (str s in ss) { - n += #fmt("%u%s", str::byte_len(s), s); - } - - n += "E"; // End name-sequence. - ret n; -} - -fn mangle_name_by_type(&@crate_ctxt ccx, &vec[str] path, &ty::t t) -> str { - auto hash = get_type_sha1(ccx, t); - ret mangle(path + [hash]); -} - -fn mangle_name_by_type_only(&@crate_ctxt ccx, &ty::t t, &str name) -> str { - auto f = metadata::def_to_str; - auto cx = @rec(ds=f, tcx=ccx.tcx, abbrevs=metadata::ac_no_abbrevs); - auto s = ty::ty_to_short_str(ccx.tcx, t); - - auto hash = get_type_sha1(ccx, t); - ret mangle([name, s, hash]); -} - -fn mangle_name_by_path_and_seq(&@crate_ctxt ccx, &vec[str] path, - &str flav) -> str { - ret mangle(path + [ccx.names.next(flav)]); -} - -fn mangle_name_by_path(&vec[str] path) -> str { - ret mangle(path); -} - -fn mangle_name_by_seq(&@crate_ctxt ccx, &str flav) -> str { - ret ccx.names.next(flav); -} - fn res(@block_ctxt bcx, ValueRef val) -> result { ret rec(bcx = bcx, val = val); @@ -1917,10 +1863,10 @@ fn declare_tydesc(&@local_ctxt cx, &span sp, &ty::t t, auto name; if (cx.ccx.sess.get_opts().debuginfo) { - name = mangle_name_by_type_only(cx.ccx, t, "tydesc"); + name = mangle_internal_name_by_type_only(cx.ccx, t, "tydesc"); name = sanitize(name); } else { - name = mangle_name_by_seq(cx.ccx, "tydesc"); + name = mangle_internal_name_by_seq(cx.ccx, "tydesc"); } auto gvar = llvm::LLVMAddGlobal(ccx.llmod, T_tydesc(ccx.tn), @@ -1951,10 +1897,12 @@ fn declare_generic_glue(&@local_ctxt cx, &str name) -> ValueRef { auto fn_nm; if (cx.ccx.sess.get_opts().debuginfo) { - fn_nm = mangle_name_by_type_only(cx.ccx, t, "glue_" + name); + fn_nm = mangle_internal_name_by_type_only(cx.ccx, t, + "glue_" + name); fn_nm = sanitize(fn_nm); } else { - fn_nm = mangle_name_by_seq(cx.ccx, "glue_" + name); + fn_nm = mangle_internal_name_by_seq(cx.ccx, + "glue_" + name); } auto llfn = decl_fastcall_fn(cx.ccx.llmod, fn_nm, llfnty); set_glue_inlining(cx, llfn, t); @@ -4106,7 +4054,8 @@ fn trans_for_each(&@block_ctxt cx, // Step 2: Declare foreach body function. - let str s = mangle_name_by_path_and_seq(lcx.ccx, lcx.path, "foreach"); + let str s = mangle_internal_name_by_path_and_seq(lcx.ccx, lcx.path, + "foreach"); // The 'env' arg entering the body function is a fake env member (as in // the env-part of the normal rust calling convention) that actually @@ -4805,7 +4754,8 @@ fn trans_bind_thunk(&@local_ctxt cx, // Construct a thunk-call with signature incoming_fty, and that copies // args forward into a call to outgoing_fty: - let str s = mangle_name_by_path_and_seq(cx.ccx, cx.path, "thunk"); + let str s = mangle_internal_name_by_path_and_seq(cx.ccx, cx.path, + "thunk"); let TypeRef llthunk_ty = get_pair_fn_ty(type_of(cx.ccx, sp, incoming_fty)); let ValueRef llthunk = decl_internal_fastcall_fn(cx.ccx.llmod, @@ -5823,13 +5773,17 @@ fn load_if_immediate(&@block_ctxt cx, ValueRef v, &ty::t t) -> ValueRef { fn trans_log(int lvl, &@block_ctxt cx, &@ast::expr e) -> result { auto lcx = cx.fcx.lcx; - auto modname = str::connect(lcx.module_path, "::"); + auto modname = link::mangle_internal_name_by_path(lcx.ccx, + lcx.module_path); auto global; if (lcx.ccx.module_data.contains_key(modname)) { global = lcx.ccx.module_data.get(modname); } else { - global = llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), - str::buf("_rust_mod_log_" + modname)); + auto s = + link::mangle_internal_name_by_path_and_seq(lcx.ccx, + lcx.module_path, + "loglevel"); + global = llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), str::buf(s)); llvm::LLVMSetGlobalConstant(global, False); llvm::LLVMSetInitializer(global, C_null(T_int())); llvm::LLVMSetLinkage(global, lib::llvm::LLVMInternalLinkage @@ -6225,8 +6179,8 @@ fn trans_spawn(&@block_ctxt cx, ret res(bcx, new_task); } -fn mk_spawn_wrapper(&@block_ctxt cx, - &@ast::expr func, +fn mk_spawn_wrapper(&@block_ctxt cx, + &@ast::expr func, &ty::t args_ty) -> result { auto llmod = cx.fcx.lcx.ccx.llmod; let TypeRef args_ty_tref = type_of(cx.fcx.lcx.ccx, cx.sp, args_ty); @@ -6239,9 +6193,9 @@ fn mk_spawn_wrapper(&@block_ctxt cx, // TODO: construct a name based on tname let str wrap_name = - mangle_name_by_path_and_seq(cx.fcx.lcx.ccx, - cx.fcx.lcx.path, - "spawn_wrapper"); + mangle_internal_name_by_path_and_seq(cx.fcx.lcx.ccx, + cx.fcx.lcx.path, + "spawn_wrapper"); auto llfndecl = decl_fastcall_fn(llmod, wrap_name, wrapper_fn_type); @@ -6252,7 +6206,7 @@ fn mk_spawn_wrapper(&@block_ctxt cx, // 3u to skip the three implicit args let ValueRef arg = llvm::LLVMGetParam(fcx.llfn, 3u); - let vec[ValueRef] child_args = + let vec[ValueRef] child_args = [llvm::LLVMGetParam(fcx.llfn, 0u), llvm::LLVMGetParam(fcx.llfn, 1u), llvm::LLVMGetParam(fcx.llfn, 2u)]; @@ -6271,19 +6225,19 @@ fn mk_spawn_wrapper(&@block_ctxt cx, } } } - + // Find the function auto fnptr = trans_lval(fbcx, func).res; fbcx = fnptr.bcx; - + auto llfnptr = fbcx.build.GEP(fnptr.val, [C_int(0), C_int(0)]); auto llfn = fbcx.build.Load(llfnptr); - + fbcx.build.FastCall(llfn, child_args); fbcx.build.RetVoid(); - + finish_fn(fcx, fbcx.llbb); // TODO: make sure we clean up everything we need to. @@ -6719,7 +6673,7 @@ fn new_local_ctxt(&@crate_ctxt ccx) -> @local_ctxt { let vec[ast::ty_param] obj_typarams = []; let vec[ast::obj_field] obj_fields = []; ret @rec(path=pth, - module_path=[crate_name(ccx, "main")], + module_path=[ccx.crate_meta_name], obj_typarams = obj_typarams, obj_fields = obj_fields, ccx = ccx); @@ -7094,7 +7048,7 @@ fn create_vtbl(@local_ctxt cx, let @local_ctxt mcx = @rec(path = cx.path + ["method", m.node.ident] with *cx); - let str s = mangle_name_by_path(mcx.path); + let str s = mangle_internal_name_by_path(mcx.ccx, mcx.path); let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty); cx.ccx.item_ids.insert(m.node.id, llfn); @@ -7106,7 +7060,8 @@ fn create_vtbl(@local_ctxt cx, methods += [llfn]; } auto vtbl = C_struct(methods); - auto vtbl_name = mangle_name_by_path(cx.path + ["vtbl"]); + auto vtbl_name = mangle_internal_name_by_path(cx.ccx, + cx.path + ["vtbl"]); auto gvar = llvm::LLVMAddGlobal(cx.ccx.llmod, val_ty(vtbl), str::buf(vtbl_name)); llvm::LLVMSetInitializer(gvar, vtbl); @@ -7123,7 +7078,7 @@ fn trans_dtor(@local_ctxt cx, &@ast::method dtor) -> ValueRef { auto llfnty = T_dtor(cx.ccx, dtor.span, llself_ty); - let str s = mangle_name_by_path(cx.path + ["drop"]); + let str s = mangle_internal_name_by_path(cx.ccx, cx.path + ["drop"]); let ValueRef llfn = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty); cx.ccx.item_ids.insert(dtor.node.id, llfn); cx.ccx.item_symbols.insert(dtor.node.id, s); @@ -7516,25 +7471,29 @@ fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, } } + let bool is_main = (str::eq(vec::top(path), "main") && + !ccx.sess.get_opts().shared); + // Declare the function itself. - let str s = mangle_name_by_path(path); + let str s = + if (is_main) { "_rust_main" } + else { mangle_internal_name_by_path(ccx, path) }; + let ValueRef llfn = decl_internal_fastcall_fn(ccx.llmod, s, llfty); // Declare the global constant pair that points to it. - let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann)); - + let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann)); register_fn_pair(ccx, ps, llpairty, llfn, id); - if (str::eq(vec::top(path), "main") && - !ccx.sess.get_opts().shared) { + if (is_main) { if (ccx.main_fn != none[ValueRef]) { ccx.sess.span_err(sp, "multiple 'main' functions"); } - log #fmt("registering %s as main function for crate", ps); llvm::LLVMSetLinkage(llfn, lib::llvm::LLVMExternalLinkage as llvm::Linkage); ccx.main_fn = some(llfn); } + } fn register_fn_pair(&@crate_ctxt cx, str ps, TypeRef llpairty, ValueRef llfn, @@ -7565,7 +7524,7 @@ fn native_fn_ty_param_count(&@crate_ctxt cx, &ast::def_id id) -> uint { alt (native_item.node) { case (ast::native_item_ty(_,_)) { cx.sess.bug("decl_native_fn_and_pair(): native fn isn't " + - "actually a fn?!"); + "actually a fn"); } case (ast::native_item_fn(_, _, _, ?tps, _, _)) { count = vec::len[ast::ty_param](tps); @@ -7594,13 +7553,13 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, // Declare the wrapper. auto t = node_ann_type(ccx, ann); auto wrapper_type = native_fn_wrapper_type(ccx, sp, num_ty_param, t); - let str s = mangle_name_by_path(path); + let str s = mangle_internal_name_by_path(ccx, path); let ValueRef wrapper_fn = decl_internal_fastcall_fn(ccx.llmod, s, wrapper_type); // Declare the global constant pair that points to it. auto wrapper_pair_type = T_fn_pair(ccx.tn, wrapper_type); - let str ps = mangle_name_by_type(ccx, path, node_ann_type(ccx, ann)); + let str ps = mangle_exported_name(ccx, path, node_ann_type(ccx, ann)); register_fn_pair(ccx, ps, wrapper_pair_type, wrapper_fn, id); @@ -7938,7 +7897,7 @@ fn trans_constant(&@crate_ctxt ccx, @walk_ctxt wcx, &@ast::item it) { auto discrim_val = C_int(i as int); auto p = wcx.path + [ident, variant.node.name, "discrim"]; - auto s = mangle_name_by_type(ccx, p, ty::mk_int(ccx.tcx)); + auto s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx)); auto discrim_gvar = llvm::LLVMAddGlobal(ccx.llmod, T_int(), str::buf(s)); @@ -7957,8 +7916,8 @@ fn trans_constant(&@crate_ctxt ccx, @walk_ctxt wcx, &@ast::item it) { // with consts. auto v = C_int(1); ccx.item_ids.insert(cid, v); - auto s = mangle_name_by_type(ccx, wcx.path + [name], - node_ann_type(ccx, ann)); + auto s = mangle_exported_name(ccx, wcx.path + [name], + node_ann_type(ccx, ann)); ccx.item_symbols.insert(cid, s); } @@ -8178,15 +8137,6 @@ fn create_module_map(&@crate_ctxt ccx) -> ValueRef { ret map; } -fn crate_name(&@crate_ctxt ccx, &str deflt) -> str { - for (@ast::meta_item item in ccx.sess.get_metadata()) { - if (str::eq(item.node.name, "name")) { - ret item.node.value; - } - } - ret deflt; -} - // FIXME use hashed metadata instead of crate names once we have that fn create_crate_map(&@crate_ctxt ccx) -> ValueRef { let vec[ValueRef] subcrates = []; @@ -8199,10 +8149,9 @@ fn create_crate_map(&@crate_ctxt ccx) -> ValueRef { i += 1; } vec::push[ValueRef](subcrates, C_int(0)); - auto cname = crate_name(ccx, "__none__"); auto mapname; if (ccx.sess.get_opts().shared) { - mapname = cname; + mapname = ccx.crate_meta_name; } else { mapname = "toplevel"; } @@ -8240,7 +8189,7 @@ fn trans_crate(&session::session sess, &@ast::crate crate, auto sha1s = map::mk_hashmap[ty::t,str](hasher, eqer); auto abbrevs = map::mk_hashmap[ty::t,metadata::ty_abbrev](hasher, eqer); auto short_names = map::mk_hashmap[ty::t,str](hasher, eqer); - + auto sha = std::sha1::mk_sha1(); auto ccx = @rec(sess = sess, llmod = llmod, td = td, @@ -8252,6 +8201,10 @@ fn trans_crate(&session::session sess, &@ast::crate crate, native_items = new_def_hash[@ast::native_item](), item_symbols = new_def_hash[str](), mutable main_fn = none[ValueRef], + crate_meta_name = crate_meta_name(sess, *crate, output), + crate_meta_vers = crate_meta_vers(sess, *crate), + crate_meta_extras_hash = + crate_meta_extras_hash(sha, *crate), tag_sizes = tag_sizes, discrims = new_def_hash[ValueRef](), discrim_symbols = new_def_hash[str](), @@ -8263,7 +8216,7 @@ fn trans_crate(&session::session sess, &@ast::crate crate, lltypes = lltypes, glues = glues, names = namegen(0), - sha = std::sha1::mk_sha1(), + sha = sha, type_sha1s = sha1s, type_abbrevs = abbrevs, type_short_names = short_names, diff --git a/src/comp/middle/walk.rs b/src/comp/middle/walk.rs index 426f72d9bed71..1ecafe1f02fe5 100644 --- a/src/comp/middle/walk.rs +++ b/src/comp/middle/walk.rs @@ -68,7 +68,7 @@ fn walk_crate_directive(&ast_visitor v, @ast::crate_directive cd) { case (ast::cdir_view_item(?vi)) { walk_view_item(v, vi); } - case (ast::cdir_meta(_)) {} + case (ast::cdir_meta(_,_)) {} case (ast::cdir_syntax(_)) {} case (ast::cdir_auth(_, _)) {} } diff --git a/src/lib/fs.rs b/src/lib/fs.rs index d051d574fd2f1..92e90e62cbf42 100644 --- a/src/lib/fs.rs +++ b/src/lib/fs.rs @@ -19,6 +19,20 @@ fn dirname(path p) -> path { ret str::substr(p, 0u, i as uint); } +fn basename(path p) -> path { + let int i = str::rindex(p, os_fs::path_sep as u8); + if (i == -1) { + i = str::rindex(p, os_fs::alt_path_sep as u8); + if (i == -1) { + ret p; + } + } + auto len = str::byte_len(p); + if ((i+1) as uint >= len) { ret p; } + + ret str::slice(p, i+1 as uint, len); +} + // FIXME: Need some typestate to avoid bounds check when len(pre) == 0 fn connect(path pre, path post) -> path { auto len = str::byte_len(pre); diff --git a/src/lib/std.rc b/src/lib/std.rc index 3619ede40f833..b35b150528d9c 100644 --- a/src/lib/std.rc +++ b/src/lib/std.rc @@ -1,8 +1,10 @@ meta (name = "std", - desc = "Rust standard library", + vers = "0.1", uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297", - url = "http://rust-lang.org/src/std", - ver = "0.0.1"); + url = "http://rust-lang.org/src/std"); + +meta (comment = "Rust standard library", + license = "BSD"); // Built-in types support modules. From 4b3755b9a0556c9eb9e8d8ea708427e7915669e4 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 20 May 2011 18:36:35 -0700 Subject: [PATCH 42/64] rustc: Use a set-based approach to unification; remove ty_bound_param and ty_local. Sorry, big perf regression; will fix soon. --- src/comp/driver/rustc.rs | 2 +- src/comp/middle/metadata.rs | 11 - src/comp/middle/trans.rs | 24 +- src/comp/middle/ty.rs | 671 ++++------ src/comp/middle/typeck.rs | 1546 +++++++++++----------- src/lib/smallintmap.rs | 4 + src/lib/ufind.rs | 15 +- src/lib/uint.rs | 5 + src/lib/vec.rs | 10 +- src/test/compile-fail/ext-nonexistent.rs | 3 +- 10 files changed, 1106 insertions(+), 1185 deletions(-) diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index e33a2e1c35dec..a33416c8638b4 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -125,7 +125,7 @@ fn pretty_print_input(session::session sess, eval::env env, str input, pp_mode ppm) { auto def = tup(ast::local_crate, 0); auto p = front::parser::new_parser(sess, env, def, input, 0u, 0u); - auto crate = front::parser::parse_crate_from_source_file(p); + auto crate = parse_input(sess, p, input); auto mode; alt (ppm) { diff --git a/src/comp/middle/metadata.rs b/src/comp/middle/metadata.rs index e2e60b8007528..59f3cf56387c5 100644 --- a/src/comp/middle/metadata.rs +++ b/src/comp/middle/metadata.rs @@ -230,17 +230,6 @@ mod Encode { } case (ty::ty_type) {w.write_char('Y');} case (ty::ty_task) {w.write_char('a');} - - // These two don't appear in crate metadata, but are here because - // `hash_ty()` uses this function. - case (ty::ty_bound_param(?id)) { - w.write_char('o'); - w.write_str(common::uistr(id)); - } - case (ty::ty_local(?def)) { - w.write_char('L'); - w.write_str(cx.ds(def)); - } } } diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 1687a62fa5777..01192deb8da7f 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -904,10 +904,6 @@ fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef { case (ty::ty_param(_)) { llty = T_i8(); } - case (ty::ty_bound_param(_)) { - cx.tcx.sess.span_err(sp, - "trans::type_of called on ty_bound_param"); - } case (ty::ty_type) { llty = T_ptr(T_tydesc(cx.tn)); } } @@ -1299,7 +1295,6 @@ fn static_size_of_tag(&@crate_ctxt cx, &span sp, &ty::t t) -> uint { auto tup_ty = simplify_type(cx, ty::mk_imm_tup(cx.tcx, variant.args)); // Perform any type parameter substitutions. - tup_ty = ty::bind_params_in_type(cx.tcx, tup_ty); tup_ty = ty::substitute_type_params(cx.tcx, subtys, tup_ty); // Here we possibly do a recursive call. @@ -1373,10 +1368,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 = []; for (ty::t raw_ty in raw_tys) { - auto t = ty::bind_params_in_type(cx.fcx.lcx.ccx.tcx, - raw_ty); - t = ty::substitute_type_params(cx.fcx.lcx.ccx.tcx, tps, - t); + auto t = ty::substitute_type_params(cx.fcx.lcx.ccx.tcx, + tps, raw_ty); tys += [t]; } @@ -1553,9 +1546,8 @@ fn GEP_tag(@block_ctxt cx, auto i = 0; let vec[ty::t] true_arg_tys = []; for (ty::t aty in arg_tys) { - auto arg_ty = ty::bind_params_in_type(cx.fcx.lcx.ccx.tcx, aty); - arg_ty = ty::substitute_type_params(cx.fcx.lcx.ccx.tcx, ty_substs, - arg_ty); + auto arg_ty = ty::substitute_type_params(cx.fcx.lcx.ccx.tcx, + ty_substs, aty); true_arg_tys += [arg_ty]; if (i == ix) { elem_ty = arg_ty; @@ -2745,10 +2737,8 @@ fn iter_structural_ty_full(&@block_ctxt cx, auto llfldp_b = rslt.val; variant_cx = rslt.bcx; - auto ty_subst = ty::bind_params_in_type( - cx.fcx.lcx.ccx.tcx, a.ty); - ty_subst = ty::substitute_type_params( - cx.fcx.lcx.ccx.tcx, tps, ty_subst); + auto ty_subst = ty::substitute_type_params( + cx.fcx.lcx.ccx.tcx, tps, a.ty); auto llfld_a = load_if_immediate(variant_cx, @@ -5308,6 +5298,7 @@ fn trans_call(&@block_ctxt cx, &@ast::expr f, } auto ret_ty = ty::ann_to_type(cx.fcx.lcx.ccx.tcx, ann); + auto args_res = trans_args(f_res.res.bcx, llenv, f_res.llobj, f_res.generic, @@ -7552,6 +7543,7 @@ fn decl_native_fn_and_pair(&@crate_ctxt ccx, // Declare the wrapper. auto t = node_ann_type(ccx, ann); + auto wrapper_type = native_fn_wrapper_type(ccx, sp, num_ty_param, t); let str s = mangle_internal_name_by_path(ccx, path); let ValueRef wrapper_fn = decl_internal_fastcall_fn(ccx.llmod, s, diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 0200cdd30f862..53b3c8fce077b 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -9,6 +9,7 @@ import std::map::hashmap; import std::option; import std::option::none; import std::option::some; +import std::smallintmap; import driver::session; import front::ast; @@ -88,9 +89,7 @@ type raw_t = rec(sty struct, option::t[str] cname, uint hash, bool has_params, - bool has_bound_params, - bool has_vars, - bool has_locals); + bool has_vars); type t = uint; @@ -118,10 +117,8 @@ tag sty { ty_fn(ast::proto, vec[arg], t, controlflow); ty_native_fn(ast::native_abi, vec[arg], t); ty_obj(vec[method]); - ty_var(int); // ephemeral type var - ty_local(ast::def_id); // type of a local var + ty_var(int); // type variable 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 @@ -129,12 +126,6 @@ tag sty { // Data structures used in type unification -type unify_handler = obj { - 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 { terr_mismatch; terr_controlflow_mismatch; @@ -259,132 +250,101 @@ fn mk_raw_ty(&ctxt cx, &sty st, &option::t[str] cname) -> raw_t { auto h = hash_type_info(st, cname); let bool has_params = false; - let bool has_bound_params = false; let bool has_vars = false; - let bool has_locals = false; fn derive_flags_t(&ctxt cx, &mutable bool has_params, - &mutable bool has_bound_params, &mutable bool has_vars, - &mutable bool has_locals, &t tt) { auto rt = interner::get[raw_t](*cx.ts, tt); has_params = has_params || rt.has_params; - has_bound_params = has_bound_params || rt.has_bound_params; has_vars = has_vars || rt.has_vars; - has_locals = has_locals || rt.has_locals; } fn derive_flags_mt(&ctxt cx, &mutable bool has_params, - &mutable bool has_bound_params, &mutable bool has_vars, - &mutable bool has_locals, &mt m) { - derive_flags_t(cx, has_params, has_bound_params, - has_vars, has_locals, m.ty); + derive_flags_t(cx, has_params, has_vars, m.ty); } fn derive_flags_arg(&ctxt cx, &mutable bool has_params, - &mutable bool has_bound_params, &mutable bool has_vars, - &mutable bool has_locals, &arg a) { - derive_flags_t(cx, has_params, has_bound_params, - has_vars, has_locals, a.ty); + derive_flags_t(cx, has_params, has_vars, a.ty); } fn derive_flags_sig(&ctxt cx, &mutable bool has_params, - &mutable bool has_bound_params, &mutable bool has_vars, - &mutable bool has_locals, &vec[arg] args, &t tt) { for (arg a in args) { - derive_flags_arg(cx, has_params, has_bound_params, - has_vars, has_locals, a); + derive_flags_arg(cx, has_params, has_vars, a); } - derive_flags_t(cx, has_params, has_bound_params, - has_vars, has_locals, tt); + derive_flags_t(cx, has_params, has_vars, tt); } alt (st) { case (ty_param(_)) { has_params = true; } - case (ty_bound_param(_)) { - has_bound_params = true; - } case (ty_var(_)) { has_vars = true; } - case (ty_local(_)) { has_locals = true; } case (ty_tag(_, ?tys)) { for (t tt in tys) { - derive_flags_t(cx, has_params, has_bound_params, - has_vars, has_locals, tt); + derive_flags_t(cx, has_params, has_vars, tt); } } case (ty_box(?m)) { - derive_flags_mt(cx, has_params, has_bound_params, - has_vars, has_locals, m); + derive_flags_mt(cx, has_params, has_vars, m); } case (ty_vec(?m)) { - derive_flags_mt(cx, has_params, has_bound_params, - has_vars, has_locals, m); + derive_flags_mt(cx, has_params, has_vars, m); } case (ty_port(?tt)) { - derive_flags_t(cx, has_params, has_bound_params, - has_vars, has_locals, tt); + derive_flags_t(cx, has_params, has_vars, tt); } case (ty_chan(?tt)) { - derive_flags_t(cx, has_params, has_bound_params, - has_vars, has_locals, tt); + derive_flags_t(cx, has_params, has_vars, tt); } case (ty_tup(?mts)) { for (mt m in mts) { - derive_flags_mt(cx, has_params, has_bound_params, - has_vars, has_locals, m); + derive_flags_mt(cx, has_params, has_vars, m); } } case (ty_rec(?flds)) { for (field f in flds) { - derive_flags_mt(cx, has_params, has_bound_params, - has_vars, has_locals, f.mt); + derive_flags_mt(cx, has_params, has_vars, f.mt); } } case (ty_fn(_, ?args, ?tt, _)) { - derive_flags_sig(cx, has_params, has_bound_params, - has_vars, has_locals, args, tt); + derive_flags_sig(cx, has_params, has_vars, args, tt); } case (ty_native_fn(_, ?args, ?tt)) { - derive_flags_sig(cx, has_params, has_bound_params, - has_vars, has_locals, args, tt); + derive_flags_sig(cx, has_params, has_vars, args, tt); } case (ty_obj(?meths)) { for (method m in meths) { - derive_flags_sig(cx, has_params, has_bound_params, - has_vars, has_locals, m.inputs, m.output); + derive_flags_sig(cx, has_params, has_vars, m.inputs, + m.output); } } case (_) { } } ret rec(struct=st, cname=cname, hash=h, - has_params = has_params, - has_bound_params = has_bound_params, - has_vars = has_vars, - has_locals = has_locals); + has_params=has_params, + has_vars=has_vars); } fn intern(&ctxt cx, &sty st, &option::t[str] cname) { @@ -485,18 +445,10 @@ fn mk_var(&ctxt cx, int v) -> t { ret gen_ty(cx, ty_var(v)); } -fn mk_local(&ctxt cx, ast::def_id did) -> t { - ret gen_ty(cx, ty_local(did)); -} - fn mk_param(&ctxt cx, uint n) -> t { ret gen_ty(cx, ty_param(n)); } -fn mk_bound_param(&ctxt cx, uint n) -> t { - ret gen_ty(cx, ty_bound_param(n)); -} - fn mk_type(&ctxt cx) -> t { ret idx_type; } fn mk_native(&ctxt cx) -> t { ret idx_native; } @@ -594,12 +546,12 @@ fn ty_to_str(&ctxt cx, &t typ) -> str { ret mstr + ty_to_str(cx, m.ty); } - alt (cname(cx, typ)) { + /*alt (cname(cx, typ)) { case (some(?cs)) { ret cs; } case (_) { } - } + }*/ auto s = ""; @@ -664,20 +616,10 @@ fn ty_to_str(&ctxt cx, &t typ) -> str { s += ""; } - case (ty_local(?id)) { - s += ""; - } - case (ty_param(?id)) { s += "'" + str::unsafe_from_bytes([('a' as u8) + (id as u8)]); } - case (ty_bound_param(?id)) { - s += "''" + str::unsafe_from_bytes([('a' as u8) + - (id as u8)]); - } - case (_) { s += ty_to_short_str(cx, typ); } @@ -753,9 +695,7 @@ fn walk_ty(&ctxt cx, ty_walk walker, t ty) { } } case (ty_var(_)) { /* no-op */ } - case (ty_local(_)) { /* no-op */ } case (ty_param(_)) { /* no-op */ } - case (ty_bound_param(_)) { /* no-op */ } } walker(ty); @@ -853,9 +793,7 @@ fn fold_ty(&ctxt cx, ty_fold fld, t ty_0) -> t { ty = copy_cname(cx, mk_obj(cx, new_methods), ty); } case (ty_var(_)) { /* no-op */ } - case (ty_local(_)) { /* no-op */ } case (ty_param(_)) { /* no-op */ } - case (ty_bound_param(_)) { /* no-op */ } } ret fld(ty); @@ -1018,7 +956,6 @@ fn type_has_pointers(&ctxt cx, &t ty) -> bool { for (variant_info variant in variants) { auto tup_ty = mk_imm_tup(cx, variant.args); // Perform any type parameter substitutions. - tup_ty = bind_params_in_type(cx, tup_ty); tup_ty = substitute_type_params(cx, tps, tup_ty); if (type_has_pointers(cx, tup_ty)) { ret true; } } @@ -1228,13 +1165,11 @@ fn hash_type_structure(&sty st) -> uint { ret h; } case (ty_var(?v)) { ret hash_uint(28u, v as uint); } - case (ty_local(?did)) { ret hash_def(29u, did); } - case (ty_param(?pid)) { ret hash_uint(30u, pid); } - case (ty_bound_param(?pid)) { ret hash_uint(31u, pid); } - case (ty_type) { ret 32u; } - case (ty_native) { ret 33u; } - case (ty_bot) { ret 34u; } - case (ty_ptr(?mt)) { ret hash_subty(35u, mt.ty); } + case (ty_param(?pid)) { ret hash_uint(29u, pid); } + case (ty_type) { ret 30u; } + case (ty_native) { ret 31u; } + case (ty_bot) { ret 32u; } + case (ty_ptr(?mt)) { ret hash_subty(33u, mt.ty); } } } @@ -1470,24 +1405,12 @@ fn equal_type_structures(&sty a, &sty b) -> bool { case (_) { ret false; } } } - case (ty_local(?did_a)) { - alt (b) { - case (ty_local(?did_b)) { ret equal_def(did_a, did_b); } - case (_) { ret false; } - } - } case (ty_param(?pid_a)) { alt (b) { case (ty_param(?pid_b)) { ret pid_a == pid_b; } case (_) { ret false; } } } - case (ty_bound_param(?pid_a)) { - alt (b) { - case (ty_bound_param(?pid_b)) { ret pid_a == pid_b; } - case (_) { ret false; } - } - } case (ty_type) { alt (b) { case (ty_type) { ret true; } @@ -1575,16 +1498,21 @@ fn ann_has_type_params(&ctxt cx, &ast::ann ann) -> bool { } +// Returns a type with type parameter substitutions performed if applicable. +fn ty_param_substs_opt_and_ty_to_monotype(&ctxt cx, + &ty_param_substs_opt_and_ty tpot) + -> t { + alt (tpot._0) { + case (none) { ret tpot._1; } + case (some(?tps)) { ret substitute_type_params(cx, tps, tpot._1); } + } +} + // Returns the type of an annotation, with type parameter substitutions // performed if applicable. fn ann_to_monotype(&ctxt cx, ast::ann a) -> t { auto tpot = ann_to_ty_param_substs_opt_and_ty(cx, a); - alt (tpot._0) { - case (none) { ret tpot._1; } - case (some(?tps)) { - ret substitute_type_params(cx, tps, tpot._1); - } - } + ret ty_param_substs_opt_and_ty_to_monotype(cx, tpot); } @@ -1618,18 +1546,10 @@ fn type_contains_vars(&ctxt cx, &t typ) -> bool { ret interner::get[raw_t](*cx.ts, typ).has_vars; } -fn type_contains_locals(&ctxt cx, &t typ) -> bool { - ret interner::get[raw_t](*cx.ts, typ).has_locals; -} - fn type_contains_params(&ctxt cx, &t typ) -> bool { ret interner::get[raw_t](*cx.ts, typ).has_params; } -fn type_contains_bound_params(&ctxt cx, &t typ) -> bool { - ret interner::get[raw_t](*cx.ts, typ).has_bound_params; -} - // Type accessors for substructures of types fn ty_fn_args(&ctxt cx, &t fty) -> vec[arg] { @@ -1670,6 +1590,13 @@ fn is_fn_ty(&ctxt cx, &t fty) -> bool { } } +fn ty_var_id(&ctxt cx, t typ) -> int { + alt (struct(cx, typ)) { + case (ty::ty_var(?vid)) { ret vid; } + case (_) { log_err "ty_var_id called on non-var ty"; fail; } + } +} + // Type accessors for AST nodes @@ -1882,55 +1809,88 @@ fn is_lval(&@ast::expr expr) -> bool { mod unify { tag result { ures_ok(t); - ures_err(type_err, t, t); + ures_err(type_err); + } + + tag union_result { + unres_ok; + unres_err(type_err); } - tag set_result { - usr_ok(vec[t]); - usr_err(type_err, t, t); + tag fixup_result { + fix_ok(t); // fixup succeeded + fix_err(int); // fixup failed because a type variable was unresolved } - type bindings[T] = rec(ufind::ufind sets, - hashmap[T,uint] ids, - mutable vec[mutable option::t[t]] types); + type var_bindings = rec(ufind::ufind sets, + smallintmap::smallintmap[t] types); + + type ctxt = rec(@var_bindings vb, ty_ctxt tcx); - fn mk_bindings[T](map::hashfn[T] hasher, map::eqfn[T] eqer) - -> @bindings[T] { - let vec[mutable option::t[t]] types = [mutable]; - ret @rec(sets=ufind::make(), - ids=map::mk_hashmap[T,uint](hasher, eqer), - mutable types=types); + fn mk_var_bindings() -> @var_bindings { + ret @rec(sets=ufind::make(), types=smallintmap::mk[t]()); } - fn record_binding[T](&@ctxt cx, &@bindings[T] bindings, &T key, t typ) - -> result { - auto n = get_or_create_set[T](bindings, key); + // Unifies two sets. + fn union(&@ctxt cx, uint set_a, uint set_b) -> union_result { + ufind::grow(cx.vb.sets, uint::max(set_a, set_b) + 1u); - auto result_type = typ; - if (n < vec::len[option::t[t]](bindings.types)) { - alt (bindings.types.(n)) { - case (some(?old_type)) { - alt (unify_step(cx, old_type, typ)) { - case (ures_ok(?unified_type)) { - result_type = unified_type; + auto root_a = ufind::find(cx.vb.sets, set_a); + auto root_b = ufind::find(cx.vb.sets, set_b); + ufind::union(cx.vb.sets, set_a, set_b); + auto root_c = ufind::find(cx.vb.sets, set_a); + + alt (smallintmap::find[t](cx.vb.types, root_a)) { + case (none[t]) { + alt (smallintmap::find[t](cx.vb.types, root_b)) { + case (none[t]) { ret unres_ok; } + case (some[t](?t_b)) { + smallintmap::insert[t](cx.vb.types, root_c, t_b); + ret unres_ok; + } + } + } + case (some[t](?t_a)) { + alt (smallintmap::find[t](cx.vb.types, root_b)) { + case (none[t]) { + smallintmap::insert[t](cx.vb.types, root_c, t_a); + ret unres_ok; + } + case (some[t](?t_b)) { + alt (unify_step(cx, t_a, t_b)) { + case (ures_ok(?t_c)) { + smallintmap::insert[t](cx.vb.types, root_c, + t_c); + ret unres_ok; + } + case (ures_err(?terr)) { ret unres_err(terr); } } - case (?res) { ret res; } } } - case (none) { /* fall through */ } } } + } + + fn record_var_binding(&@ctxt cx, int key, t typ) -> result { + ufind::grow(cx.vb.sets, (key as uint) + 1u); - vec::grow_set[option::t[t]](bindings.types, n, none[t], - some[t](result_type)); + auto result_type = typ; + alt (smallintmap::find[t](cx.vb.types, key as uint)) { + case (some(?old_type)) { + alt (unify_step(cx, old_type, typ)) { + case (ures_ok(?unified_type)) { + result_type = unified_type; + } + case (?res) { ret res; } + } + } + case (none) { /* fall through */ } + } + smallintmap::insert[t](cx.vb.types, key as uint, result_type); ret ures_ok(typ); } - type ctxt = rec(@bindings[int] bindings, - unify_handler handler, - ty_ctxt tcx); - // Wraps the given type in an appropriate cname. // // TODO: This doesn't do anything yet. We should carry the cname up from @@ -1944,7 +1904,7 @@ mod unify { ret ures_ok(expected); } - ret ures_err(terr_mismatch, expected, actual); + ret ures_err(terr_mismatch); } // Unifies two mutability flags. @@ -1976,8 +1936,7 @@ mod unify { auto expected_len = vec::len[arg](expected_inputs); auto actual_len = vec::len[arg](actual_inputs); if (expected_len != actual_len) { - ret fn_common_res_err(ures_err(terr_arg_count, - expected, actual)); + ret fn_common_res_err(ures_err(terr_arg_count)); } // TODO: as above, we should have an iter2 iterator. @@ -1995,8 +1954,7 @@ mod unify { result_mode = expected_input.mode; } else if (expected_input.mode != actual_input.mode) { // FIXME this is the wrong error - ret fn_common_res_err(ures_err(terr_arg_count, - expected, actual)); + ret fn_common_res_err(ures_err(terr_arg_count)); } else { result_mode = expected_input.mode; } @@ -2040,7 +1998,7 @@ mod unify { -> result { if (e_proto != a_proto) { - ret ures_err(terr_mismatch, expected, actual); + ret ures_err(terr_mismatch); } alt (expected_cf) { case (ast::return) { } // ok @@ -2055,8 +2013,7 @@ mod unify { this check is necessary to ensure that the annotation in an object method matches the declared object type */ - ret ures_err(terr_controlflow_mismatch, - expected, actual); + ret ures_err(terr_controlflow_mismatch); } } } @@ -2084,9 +2041,7 @@ mod unify { &vec[arg] expected_inputs, &t expected_output, &vec[arg] actual_inputs, &t actual_output) -> result { - if (e_abi != a_abi) { - ret ures_err(terr_mismatch, expected, actual); - } + if (e_abi != a_abi) { ret ures_err(terr_mismatch); } auto t = unify_fn_common(cx, expected, actual, expected_inputs, expected_output, @@ -2113,16 +2068,13 @@ mod unify { let uint expected_len = vec::len[method](expected_meths); let uint actual_len = vec::len[method](actual_meths); - if (expected_len != actual_len) { - ret ures_err(terr_meth_count, expected, actual); - } + if (expected_len != actual_len) { ret ures_err(terr_meth_count); } while (i < expected_len) { auto e_meth = expected_meths.(i); auto a_meth = actual_meths.(i); if (! str::eq(e_meth.ident, a_meth.ident)) { - ret ures_err(terr_obj_meths(e_meth.ident, a_meth.ident), - expected, actual); + ret ures_err(terr_obj_meths(e_meth.ident, a_meth.ident)); } auto r = unify_fn(cx, e_meth.proto, a_meth.proto, @@ -2151,16 +2103,42 @@ mod unify { ret ures_ok(t); } - fn get_or_create_set[T](&@bindings[T] bindings, &T key) -> uint { - auto set_num; - alt (bindings.ids.find(key)) { - case (none) { - set_num = ufind::make_set(bindings.sets); - bindings.ids.insert(key, set_num); + // FIXME: This function should not be necessary, but it is for now until + // we eliminate pushdown. The typechecker should never rely on early + // resolution of type variables. + fn resolve_all_vars(&ty_ctxt tcx, &@var_bindings vb, t typ) -> t { + fn folder(ty_ctxt tcx, @var_bindings vb, @bool success, t typ) -> t { + alt (struct(tcx, typ)) { + case (ty_var(?vid)) { + // It's possible that we haven't even created the var set. + // Handle this case gracefully. + if ((vid as uint) >= ufind::set_count(vb.sets)) { + *success = false; ret typ; + } + + auto root_id = ufind::find(vb.sets, vid as uint); + alt (smallintmap::find[t](vb.types, root_id)) { + case (some[t](?typ2)) { + ret fold_ty(tcx, bind folder(tcx, vb, success, _), + typ2); + } + case (none[t]) { *success = false; ret typ; } + } + log ""; // fixes ambiguity + *success = false; ret typ; + } + + case (_) { ret typ; } } - case (some(?n)) { set_num = n; } } - ret set_num; + + auto success = @true; + auto rty = fold_ty(tcx, bind folder(tcx, vb, success, _), typ); + /*if (*success) { ret rty; } + log_err "*** failed! type " + ty::ty_to_str(tcx, typ) + " => " + + ty::ty_to_str(tcx, rty); + ret typ;*/ + ret rty; } fn unify_step(&@ctxt cx, &t expected, &t actual) -> result { @@ -2173,72 +2151,57 @@ mod unify { // Fast path. if (eq_ty(expected, actual)) { ret ures_ok(expected); } - alt (struct(cx.tcx, actual)) { + // Stage 1: Handle the cases in which one side or another is a type + // variable. - // a _|_ type can be used anywhere - case (ty::ty_bot) { - ret ures_ok(expected); - } - + alt (struct(cx.tcx, actual)) { // If the RHS is a variable type, then just do the appropriate // binding. case (ty::ty_var(?actual_id)) { - auto actual_n = get_or_create_set[int](cx.bindings, - actual_id); + auto actual_n = actual_id as uint; alt (struct(cx.tcx, expected)) { case (ty::ty_var(?expected_id)) { - auto expected_n = get_or_create_set[int](cx.bindings, - expected_id); - ufind::union(cx.bindings.sets, expected_n, actual_n); + auto expected_n = expected_id as uint; + union(cx, expected_n, actual_n); } - case (_) { // Just bind the type variable to the expected type. - alt (record_binding[int](cx, cx.bindings, actual_id, - expected)) { + alt (record_var_binding(cx, actual_id, expected)) { case (ures_ok(_)) { /* fall through */ } case (?res) { ret res; } } } } - ret ures_ok(actual); - } - case (ty::ty_local(?actual_id)) { - auto result_ty; - alt (cx.handler.resolve_local(actual_id)) { - case (none) { result_ty = expected; } - case (some(?actual_ty)) { - auto result = unify_step(cx, expected, actual_ty); - alt (result) { - case (ures_ok(?rty)) { result_ty = rty; } - case (_) { ret result; } - } - } - } - - cx.handler.record_local(actual_id, result_ty); - ret ures_ok(result_ty); + ret ures_ok(mk_var(cx.tcx, actual_id)); } - case (ty::ty_bound_param(?actual_id)) { - alt (struct(cx.tcx, expected)) { - case (ty::ty_local(_)) { - // TODO: bound param unifying with local - cx.tcx.sess.unimpl("TODO: bound param unifying with " - + "local"); - } - case (_) { - ret cx.handler.record_param(actual_id, expected); - } + case (_) { /* empty */ } + } + + alt (struct(cx.tcx, expected)) { + case (ty::ty_var(?expected_id)) { + // Add a binding. (`actual` can't actually be a var here.) + alt (record_var_binding(cx, expected_id, actual)) { + case (ures_ok(_)) { /* fall through */ } + case (?res) { ret res; } } + ret ures_ok(mk_var(cx.tcx, expected_id)); } - case (_) { /* empty */ } + + case (_) { /* fall through */ } + } + + // Stage 2: Handle all other cases. + + alt (struct(cx.tcx, actual)) { + case (ty::ty_bot) { ret ures_ok(expected); } + case (_) { /* fall through */ } } alt (struct(cx.tcx, expected)) { case (ty::ty_nil) { ret struct_cmp(cx, expected, actual); } // _|_ unifies with anything - case (ty::ty_bot) { ret ures_ok(expected); } + case (ty::ty_bot) { ret ures_ok(actual); } case (ty::ty_bool) { ret struct_cmp(cx, expected, actual); } case (ty::ty_int) { ret struct_cmp(cx, expected, actual); } case (ty::ty_uint) { ret struct_cmp(cx, expected, actual); } @@ -2255,7 +2218,7 @@ mod unify { case (ty::ty_tag(?actual_id, ?actual_tps)) { if (expected_id._0 != actual_id._0 || expected_id._1 != actual_id._1) { - ret ures_err(terr_mismatch, expected, actual); + ret ures_err(terr_mismatch); } // TODO: factor this cruft out, see the TODO in the @@ -2288,7 +2251,7 @@ mod unify { case (_) { /* fall through */ } } - ret ures_err(terr_mismatch, expected, actual); + ret ures_err(terr_mismatch); } case (ty::ty_box(?expected_mt)) { @@ -2296,10 +2259,7 @@ mod unify { case (ty::ty_box(?actual_mt)) { auto mut; alt (unify_mut(expected_mt.mut, actual_mt.mut)) { - case (none) { - ret ures_err(terr_box_mutability, expected, - actual); - } + case (none) { ret ures_err(terr_box_mutability); } case (some(?m)) { mut = m; } } @@ -2317,9 +2277,7 @@ mod unify { } } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2328,10 +2286,7 @@ mod unify { case (ty::ty_vec(?actual_mt)) { auto mut; alt (unify_mut(expected_mt.mut, actual_mt.mut)) { - case (none) { - ret ures_err(terr_vec_mutability, expected, - actual); - } + case (none) { ret ures_err(terr_vec_mutability); } case (some(?m)) { mut = m; } } @@ -2349,9 +2304,7 @@ mod unify { } } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2371,9 +2324,7 @@ mod unify { } } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2393,9 +2344,7 @@ mod unify { } } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2407,7 +2356,7 @@ mod unify { if (expected_len != actual_len) { auto err = terr_tuple_size(expected_len, actual_len); - ret ures_err(err, expected, actual); + ret ures_err(err); } // TODO: implement an iterator that can iterate over @@ -2423,7 +2372,7 @@ mod unify { actual_elem.mut)) { case (none) { auto err = terr_tuple_mutability; - ret ures_err(err, expected, actual); + ret ures_err(err); } case (some(?m)) { mut = m; } } @@ -2447,9 +2396,7 @@ mod unify { ret ures_ok(mk_tup(cx.tcx, result_elems)); } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2461,7 +2408,7 @@ mod unify { if (expected_len != actual_len) { auto err = terr_record_size(expected_len, actual_len); - ret ures_err(err, expected, actual); + ret ures_err(err); } // TODO: implement an iterator that can iterate over @@ -2476,8 +2423,7 @@ mod unify { alt (unify_mut(expected_field.mt.mut, actual_field.mt.mut)) { case (none) { - ret ures_err(terr_record_mutability, - expected, actual); + ret ures_err(terr_record_mutability); } case (some(?m)) { mut = m; } } @@ -2487,7 +2433,7 @@ mod unify { auto err = terr_record_fields(expected_field.ident, actual_field.ident); - ret ures_err(err, expected, actual); + ret ures_err(err); } auto result = unify_step(cx, @@ -2511,9 +2457,7 @@ mod unify { ret ures_ok(mk_rec(cx.tcx, result_fields)); } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2529,9 +2473,7 @@ mod unify { expected_cf, actual_cf); } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2545,9 +2487,7 @@ mod unify { expected_inputs, expected_output, actual_inputs, actual_output); } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } @@ -2557,147 +2497,82 @@ mod unify { ret unify_obj(cx, expected, actual, expected_meths, actual_meths); } - case (_) { - ret ures_err(terr_mismatch, expected, actual); - } + case (_) { ret ures_err(terr_mismatch); } } } + } + } - case (ty::ty_var(?expected_id)) { - // Add a binding. (`actual` can't actually be a var here.) - alt (record_binding[int](cx, cx.bindings, expected_id, - actual)) { - case (ures_ok(_)) { /* fall through */ } - case (?res) { ret res; } - } - ret ures_ok(expected); - } + fn unify(&t expected, + &t actual, + &@var_bindings vb, + &ty_ctxt tcx) -> result { + auto cx = @rec(vb=vb, tcx=tcx); + ret unify_step(cx, expected, actual); + } - case (ty::ty_local(?expected_id)) { - auto result_ty; - alt (cx.handler.resolve_local(expected_id)) { - case (none) { result_ty = actual; } - case (some(?expected_ty)) { - auto result = unify_step(cx, expected_ty, actual); - alt (result) { - case (ures_ok(?rty)) { result_ty = rty; } - case (_) { ret result; } - } - } + fn dump_var_bindings(ty_ctxt tcx, @var_bindings vb) { + auto i = 0u; + while (i < vec::len[ufind::node](vb.sets.nodes)) { + auto sets = ""; + auto j = 0u; + while (j < vec::len[option::t[uint]](vb.sets.nodes)) { + if (ufind::find(vb.sets, j) == i) { sets += #fmt(" %u", j); } + j += 1u; + } + + auto typespec; + alt (smallintmap::find[t](vb.types, i)) { + case (none[t]) { typespec = ""; } + case (some[t](?typ)) { + typespec = " =" + ty_to_str(tcx, typ); } - - cx.handler.record_local(expected_id, result_ty); - ret ures_ok(result_ty); } - case (ty::ty_bound_param(?expected_id)) { - ret cx.handler.record_param(expected_id, actual); - } + log_err #fmt("set %u:%s%s", i, typespec, sets); + i += 1u; } } - // Performs type binding substitution. - fn substitute(&ty_ctxt tcx, - &@bindings[int] bindings, - &vec[t] set_types, - &t typ) -> t { - if (!type_contains_vars(tcx, typ)) { - ret typ; - } + // Fixups and substitutions - fn substituter(ty_ctxt tcx, - @bindings[int] bindings, - vec[t] types, - t typ) -> t { + fn fixup_vars(ty_ctxt tcx, @var_bindings vb, t typ) -> fixup_result { + fn subst_vars(ty_ctxt tcx, @var_bindings vb, t typ) -> t { alt (struct(tcx, typ)) { - case (ty_var(?id)) { - alt (bindings.ids.find(id)) { - case (some(?n)) { - auto root = ufind::find(bindings.sets, n); - ret types.(root); + case (ty::ty_var(?vid)) { + auto root_id = ufind::find(vb.sets, vid as uint); + alt (smallintmap::find[t](vb.types, root_id)) { + case (none[t]) { + log_err "unresolved type variable"; + fail; + } + case (some[t](?rt)) { + ret fold_ty(tcx, bind subst_vars(tcx, vb, _), rt); } - case (none) { ret typ; } } } case (_) { ret typ; } } } - auto f = bind substituter(tcx, bindings, set_types, _); - ret fold_ty(tcx, f, typ); + // FIXME: Report errors better. + ret fix_ok(fold_ty(tcx, bind subst_vars(tcx, vb, _), typ)); } - fn unify_sets[T](&ty_ctxt tcx, &@bindings[T] bindings) -> set_result { - obj handler(ty_ctxt tcx) { - fn resolve_local(ast::def_id id) -> option::t[t] { - tcx.sess.bug("resolve_local in unify_sets"); - } - fn record_local(ast::def_id id, t ty) { - tcx.sess.bug("record_local in unify_sets"); - } - fn record_param(uint index, t binding) -> unify::result { - tcx.sess.bug("record_param in unify_sets"); - } - } - - auto node_count = vec::len[option::t[t]](bindings.types); - - let vec[option::t[t]] results = - vec::init_elt[option::t[t]](none[t], node_count); - - auto i = 0u; - while (i < node_count) { - auto root = ufind::find(bindings.sets, i); - alt (bindings.types.(i)) { - case (none) { /* nothing to do */ } - case (some(?actual)) { - alt (results.(root)) { - case (none) { results.(root) = some[t](actual); } - case (some(?expected)) { - // FIXME: Is this right? - auto bindings = mk_bindings[int](int::hash, - int::eq_alias); - alt (unify(expected, actual, handler(tcx), - bindings, tcx)) { - case (ures_ok(?result_ty)) { - results.(i) = some[t](result_ty); - } - case (ures_err(?e, ?t_a, ?t_b)) { - ret usr_err(e, t_a, t_b); - } - } - } + fn resolve_type_var(&ty_ctxt tcx, &@var_bindings vb, int vid) -> t { + auto root_id = ufind::find(vb.sets, vid as uint); + alt (smallintmap::find[t](vb.types, root_id)) { + case (none[t]) { ret mk_var(tcx, vid); } + case (some[t](?rt)) { + alt (fixup_vars(tcx, vb, rt)) { + case (fix_ok(?rty)) { ret rty; } + case (fix_err(_)) { + // TODO: antisocial + log_err "failed to resolve type var"; + fail; } } } - i += 1u; - } - - // FIXME: This is equivalent to map(option::get, results) but it - // causes an assertion in typeck at the moment. - let vec[t] real_results = []; - for (option::t[t] typ in results) { - real_results += [option::get[t](typ)]; - } - - ret usr_ok(real_results); - } - - fn unify(&t expected, - &t actual, - &unify_handler handler, - &@bindings[int] bindings, - &ty_ctxt tcx) -> result { - auto cx = @rec(bindings=bindings, handler=handler, tcx=tcx); - ret unify_step(cx, expected, actual); - } - - fn fixup(&ty_ctxt tcx, &@bindings[int] bindings, t typ) -> result { - alt (unify_sets[int](tcx, bindings)) { - case (usr_ok(?set_types)) { - ret ures_ok(substitute(tcx, bindings, set_types, typ)); - } - case (usr_err(?terr, ?t0, ?t1)) { ret ures_err(terr, t0, t1); } } } } @@ -2752,46 +2627,46 @@ fn type_err_to_str(&ty::type_err err) -> str { } } -// Performs bound type parameter replacement using the supplied mapping from -// parameter IDs to types. -fn substitute_type_params(&ctxt cx, &vec[t] bindings, &t typ) -> t { - if (!type_contains_bound_params(cx, typ)) { - ret typ; +// Converts type parameters in a type to type variables and returns the +// resulting type along with a list of type variable IDs. +fn bind_params_in_type(&ctxt cx, fn()->int next_ty_var, t typ, + uint ty_param_count) + -> tup(vec[int], t) { + let vec[int] param_var_ids = []; + auto i = 0u; + while (i < ty_param_count) { + param_var_ids += [next_ty_var()]; + i += 1u; } - fn replacer(&ctxt cx, vec[t] bindings, t typ) -> t { + + fn binder(ctxt cx, vec[int] param_var_ids, fn()->int next_ty_var, t typ) + -> t { alt (struct(cx, typ)) { - case (ty_bound_param(?param_index)) { - ret bindings.(param_index); - } + case (ty_param(?index)) { ret mk_var(cx, param_var_ids.(index)); } case (_) { ret typ; } } } - auto f = bind replacer(cx, bindings, _); - ret fold_ty(cx, f, typ); + auto f = bind binder(cx, param_var_ids, next_ty_var, _); + auto new_typ = fold_ty(cx, f, typ); + ret tup(param_var_ids, new_typ); } -// Converts type parameters in a type to bound type parameters. -fn bind_params_in_type(&ctxt cx, &t typ) -> t { - if (!type_contains_params(cx, typ)) { - ret typ; - } - fn binder(&ctxt cx, t typ) -> t { +// Replaces type parameters in the given type using the given list of +// substitions. +fn substitute_type_params(&ctxt cx, vec[ty::t] substs, t typ) -> t { + if (!type_contains_params(cx, typ)) { ret typ; } + + fn substituter(ctxt cx, vec[ty::t] substs, t typ) -> t { alt (struct(cx, typ)) { - case (ty_bound_param(?index)) { - cx.sess.bug("bind_params_in_type() called on type that " - + "already has bound params in it"); - } - case (ty_param(?index)) { ret mk_bound_param(cx, index); } + case (ty_param(?idx)) { ret substs.(idx); } case (_) { ret typ; } } } - auto f = bind binder(cx, _); - ret fold_ty(cx, f, typ); + ret fold_ty(cx, bind substituter(cx, substs, _), typ); } - fn def_has_ty_params(&ast::def def) -> bool { alt (def) { case (ast::def_fn(_)) { ret true; } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index c07e76f8332e2..d604ad9a39062 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -31,9 +31,13 @@ import middle::ty::ty_param_count_and_ty; import middle::ty::ty_nil; import middle::ty::unify::ures_ok; import middle::ty::unify::ures_err; +import middle::ty::unify::fixup_result; +import middle::ty::unify::fix_ok; +import middle::ty::unify::fix_err; import std::int; import std::str; +import std::ufind; import std::uint; import std::vec; import std::map; @@ -62,76 +66,41 @@ type crate_ctxt = rec(mutable vec[obj_info] obj_infos, type fn_ctxt = rec(ty::t ret_ty, ast::purity purity, - @ty_table locals, + @ty::unify::var_bindings var_bindings, + hashmap[ast::def_id,int] locals, + hashmap[ast::def_id,ast::ident] local_names, + mutable int next_var_id, + mutable vec[uint] fixups, @crate_ctxt ccx); -type stmt_ctxt = rec(@fn_ctxt fcx, - mutable int next_var_id, - mutable vec[uint] fixups); - // Used for ast_ty_to_ty() below. type ty_getter = fn(&ast::def_id) -> ty::ty_param_count_and_ty; -// Creates a statement context and passes it to the given thunk, then runs -// fixups. This function has the signature it does so that the caller can -// never forget to run fixups! -fn with_stmt_ctxt(&@fn_ctxt fcx, fn(&@stmt_ctxt) f) { - let vec[uint] fixups = []; - auto scx = @rec(fcx=fcx, mutable next_var_id=0, mutable fixups=fixups); - f(scx); - // TODO: run fixups -} - -// Substitutes the user's explicit types for the parameters in a path -// expression. -fn substitute_ty_params(&@crate_ctxt ccx, - &ty::t typ, - uint ty_param_count, - &vec[ty::t] supplied, - &span sp) -> ty::t { - fn substituter(@crate_ctxt ccx, vec[ty::t] supplied, ty::t typ) -> ty::t { - alt (struct(ccx.tcx, typ)) { - case (ty::ty_bound_param(?pid)) { ret supplied.(pid); } - case (_) { ret typ; } - } - } - - auto supplied_len = vec::len[ty::t](supplied); - if (ty_param_count != supplied_len) { - ccx.tcx.sess.span_err(sp, "expected " + - uint::to_str(ty_param_count, 10u) + - " type parameter(s) but found " + - uint::to_str(supplied_len, 10u) + " parameter(s)"); - } - - if (!ty::type_contains_bound_params(ccx.tcx, typ)) { - ret typ; - } - - auto f = bind substituter(ccx, supplied, _); - ret ty::fold_ty(ccx.tcx, f, typ); -} - // Returns the type parameter count and the type for the given definition. fn ty_param_count_and_ty_for_def(&@fn_ctxt fcx, &span sp, &ast::def defn) -> ty_param_count_and_ty { alt (defn) { case (ast::def_arg(?id)) { - // assert (fcx.locals.contains_key(id)); - ret tup(0u, fcx.locals.get(id)); + assert (fcx.locals.contains_key(id)); + auto typ = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(id)); + typ = ty::unify::resolve_all_vars(fcx.ccx.tcx, fcx.var_bindings, + typ); + ret tup(0u, typ); } case (ast::def_local(?id)) { - auto t; - alt (fcx.locals.find(id)) { - case (some(?t1)) { t = t1; } - case (none) { t = ty::mk_local(fcx.ccx.tcx, id); } - } - ret tup(0u, t); + assert (fcx.locals.contains_key(id)); + auto typ = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(id)); + typ = ty::unify::resolve_all_vars(fcx.ccx.tcx, fcx.var_bindings, + typ); + ret tup(0u, typ); } case (ast::def_obj_field(?id)) { - // assert (fcx.locals.contains_key(id)); - ret tup(0u, fcx.locals.get(id)); + assert (fcx.locals.contains_key(id)); + auto typ = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(id)); + typ = ty::unify::resolve_all_vars(fcx.ccx.tcx, fcx.var_bindings, + typ); + ret tup(0u, typ); } case (ast::def_fn(?id)) { ret ty::lookup_item_type(fcx.ccx.tcx, id); @@ -146,8 +115,11 @@ fn ty_param_count_and_ty_for_def(&@fn_ctxt fcx, &span sp, &ast::def defn) ret ty::lookup_item_type(fcx.ccx.tcx, vid); } case (ast::def_binding(?id)) { - // assert (fcx.locals.contains_key(id)); - ret tup(0u, fcx.locals.get(id)); + assert (fcx.locals.contains_key(id)); + auto typ = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(id)); + typ = ty::unify::resolve_all_vars(fcx.ccx.tcx, fcx.var_bindings, + typ); + ret tup(0u, typ); } case (ast::def_obj(?id)) { ret ty::lookup_item_type(fcx.ccx.tcx, id); @@ -172,12 +144,18 @@ fn ty_param_count_and_ty_for_def(&@fn_ctxt fcx, &span sp, &ast::def defn) // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. -fn instantiate_path(&@stmt_ctxt scx, +fn instantiate_path(&@fn_ctxt fcx, &ast::path pth, &ty_param_count_and_ty tpt, &span sp) -> ty_param_substs_opt_and_ty { auto ty_param_count = tpt._0; - auto t = bind_params_in_type(scx.fcx.ccx.tcx, tpt._1); + + auto bind_result = bind_params_in_type(fcx.ccx.tcx, + bind next_ty_var_id(fcx), + tpt._1, + ty_param_count); + auto ty_param_vars = bind_result._0; + auto t = bind_result._1; auto ty_substs_opt; auto ty_substs_len = vec::len[@ast::ty](pth.node.types); @@ -185,16 +163,20 @@ fn instantiate_path(&@stmt_ctxt scx, let vec[ty::t] ty_substs = []; auto i = 0u; while (i < ty_substs_len) { - ty_substs += [ast_ty_to_ty_crate(scx.fcx.ccx, - pth.node.types.(i))]; + // TODO: Report an error if the number of type params in the item + // and the supplied number of type params don't match. + auto ty_var = ty::mk_var(fcx.ccx.tcx, ty_param_vars.(i)); + auto ty_subst = ast_ty_to_ty_crate(fcx.ccx, + pth.node.types.(i)); + auto res_ty = demand::simple(fcx, pth.span, ty_var, ty_subst); + ty_substs += [res_ty]; i += 1u; } ty_substs_opt = some[vec[ty::t]](ty_substs); if (ty_param_count == 0u) { - scx.fcx.ccx.tcx.sess.span_err(sp, - "this item does not take type " + - "parameters"); + fcx.ccx.tcx.sess.span_err(sp, "this item does not take type " + + "parameters"); fail; } } else { @@ -202,13 +184,13 @@ fn instantiate_path(&@stmt_ctxt scx, let vec[ty::t] ty_substs = []; auto i = 0u; while (i < ty_param_count) { - ty_substs += [next_ty_var(scx)]; + ty_substs += [ty::mk_var(fcx.ccx.tcx, ty_param_vars.(i))]; i += 1u; } ty_substs_opt = some[vec[ty::t]](ty_substs); } - ret tup(ty_substs_opt, t); + ret tup(ty_substs_opt, tpt._1); } fn ast_mode_to_mode(ast::mode mode) -> ty::mode { @@ -245,7 +227,6 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t { // TODO: maybe record cname chains so we can do // "foo = int" like OCaml? auto params_opt_and_ty = getter(id); - if (params_opt_and_ty._0 == 0u) { ret params_opt_and_ty._1; } @@ -254,12 +235,14 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &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(tcx, params_opt_and_ty._1); let vec[ty::t] param_bindings = []; for (@ast::ty ast_ty in args) { param_bindings += [ast_ty_to_ty(tcx, getter, ast_ty)]; } - ret ty::substitute_type_params(tcx, param_bindings, bound_ty); + + auto typ = ty::substitute_type_params(tcx, param_bindings, + params_opt_and_ty._1); + ret typ; } auto mut = ast::imm; @@ -398,11 +381,11 @@ mod write { // Writes a type parameter count and type pair into the node type table. // This function allows for the possibility of type variables, which will // be rewritten later during the fixup phase. - fn ty_fixup(&@stmt_ctxt scx, uint node_id, + fn ty_fixup(@fn_ctxt fcx, uint node_id, &ty_param_substs_opt_and_ty tpot) { - inner(scx.fcx.ccx.tcx.node_types, node_id, tpot); - if (ty::type_contains_vars(scx.fcx.ccx.tcx, tpot._1)) { - scx.fixups += [node_id]; + inner(fcx.ccx.tcx.node_types, node_id, tpot); + if (ty::type_contains_vars(fcx.ccx.tcx, tpot._1)) { + fcx.fixups += [node_id]; } } @@ -413,8 +396,8 @@ mod write { // Writes a type with no type parameters into the node type table. This // function allows for the possibility of type variables. - fn ty_only_fixup(&@stmt_ctxt scx, uint node_id, ty::t typ) { - be ty_fixup(scx, node_id, tup(none[vec[ty::t]], typ)); + fn ty_only_fixup(@fn_ctxt fcx, uint node_id, ty::t typ) { + be ty_fixup(fcx, node_id, tup(none[vec[ty::t]], typ)); } // Writes a nil type into the node type table. @@ -835,105 +818,32 @@ mod collect { // Type unification mod unify { - fn simple(&@stmt_ctxt scx, &ty::t expected, &ty::t actual) + fn simple(&@fn_ctxt fcx, &ty::t expected, &ty::t actual) -> ty::unify::result { - // FIXME: horrid botch - let vec[mutable ty::t] param_substs = - [mutable ty::mk_nil(scx.fcx.ccx.tcx)]; - vec::pop(param_substs); - ret with_params(scx, expected, actual, param_substs); - } - - fn with_params(&@stmt_ctxt scx, - &ty::t expected, - &ty::t actual, - &vec[mutable ty::t] param_substs) -> ty::unify::result { - auto cache_key = tup(expected, actual, param_substs); - alt (scx.fcx.ccx.unify_cache.find(cache_key)) { + /*auto cache_key = tup(expected, actual, param_substs); + alt (fcx.ccx.unify_cache.find(cache_key)) { case (some(?r)) { - scx.fcx.ccx.cache_hits += 1u; + fcx.ccx.cache_hits += 1u; ret r; } case (none) { - scx.fcx.ccx.cache_misses += 1u; - } - } - - obj unify_handler(@stmt_ctxt scx, vec[mutable ty::t] param_substs) { - fn resolve_local(ast::def_id id) -> option::t[ty::t] { - alt (scx.fcx.locals.find(id)) { - case (none) { ret none[ty::t]; } - case (some(?existing_type)) { - if (ty::type_contains_vars(scx.fcx.ccx.tcx, - 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 (scx.fcx.locals.find(id)) { - case (none) { unified_type = new_type; } - case (some(?old_type)) { - alt (with_params(scx, old_type, new_type, - param_substs)) { - case (ures_ok(?ut)) { unified_type = ut; } - case (_) { fail; /* FIXME */ } - } - } - } - - // TODO: "freeze" - let vec[ty::t] param_substs_1 = []; - for (ty::t subst in param_substs) { - param_substs_1 += [subst]; - } - - unified_type = ty::substitute_type_params(scx.fcx.ccx.tcx, - param_substs_1, - unified_type); - scx.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(scx, old_subst, binding, - param_substs); - alt (result) { - case (ures_ok(?new_subst)) { - param_substs.(index) = new_subst; - ret ures_ok(ty::mk_bound_param(scx.fcx.ccx.tcx, - index)); - } - case (_) { ret result; } - } + fcx.ccx.cache_misses += 1u; } - } + }*/ + auto result = ty::unify::unify(expected, actual, fcx.var_bindings, + fcx.ccx.tcx); - auto handler = unify_handler(scx, param_substs); + //fcx.ccx.unify_cache.insert(cache_key, result); - auto bindings = ty::unify::mk_bindings[int](int::hash, int::eq_alias); - auto result = ty::unify::unify(expected, actual, handler, bindings, - scx.fcx.ccx.tcx); - - alt ({result}) { - case (ures_ok(?rty)) { - if (ty::type_contains_vars(scx.fcx.ccx.tcx, rty)) { - result = ty::unify::fixup(scx.fcx.ccx.tcx, bindings, rty); - } + // FIXME: Shouldn't be necessary, but is until we remove pushdown. + alt (result) { + case (ures_ok(?typ)) { + ret ures_ok(ty::unify::resolve_all_vars(fcx.ccx.tcx, + fcx.var_bindings, typ)); } - case (_) { /* nothing */ } + case (_) { ret result; } } - - scx.fcx.ccx.unify_cache.insert(cache_key, result); - ret result; } } @@ -983,22 +893,22 @@ fn count_boxes(&ty::ctxt tcx, &ty::t t) -> uint { type ty_param_substs_and_ty = tup(vec[ty::t], ty::t); mod demand { - fn simple(&@stmt_ctxt scx, &span sp, &ty::t expected, &ty::t actual) + fn simple(&@fn_ctxt fcx, &span sp, &ty::t expected, &ty::t actual) -> ty::t { let vec[ty::t] tps = []; - ret full(scx, sp, expected, actual, tps, NO_AUTODEREF)._1; + ret full(fcx, sp, expected, actual, tps, NO_AUTODEREF)._1; } - fn autoderef(&@stmt_ctxt scx, &span sp, &ty::t expected, &ty::t actual, + fn autoderef(&@fn_ctxt fcx, &span sp, &ty::t expected, &ty::t actual, autoderef_kind adk) -> ty::t { let vec[ty::t] tps = []; - ret full(scx, sp, expected, actual, tps, adk)._1; + ret full(fcx, sp, expected, actual, tps, adk)._1; } // Requires that the two types unify, and prints an error message if they // don't. Returns the unified type and the type parameter substitutions. - fn full(&@stmt_ctxt scx, &span sp, &ty::t expected, &ty::t actual, + 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 { @@ -1007,35 +917,41 @@ mod demand { auto implicit_boxes = 0u; if (adk == AUTODEREF_OK) { - expected_1 = strip_boxes(scx.fcx.ccx.tcx, expected_1); - actual_1 = strip_boxes(scx.fcx.ccx.tcx, actual_1); - implicit_boxes = count_boxes(scx.fcx.ccx.tcx, actual); + expected_1 = strip_boxes(fcx.ccx.tcx, expected_1); + actual_1 = strip_boxes(fcx.ccx.tcx, actual_1); + implicit_boxes = count_boxes(fcx.ccx.tcx, actual); } - let vec[mutable ty::t] ty_param_substs = - [mutable ty::mk_nil(scx.fcx.ccx.tcx)]; - vec::pop(ty_param_substs); // FIXME: horrid botch + let vec[mutable ty::t] ty_param_substs = [mutable]; + let vec[int] ty_param_subst_var_ids = []; for (ty::t ty_param_subst in ty_param_substs_0) { - ty_param_substs += [mutable ty_param_subst]; + // Generate a type variable and unify it with the type parameter + // substitution. We will then pull out these type variables. + auto t_0 = next_ty_var(fcx); + ty_param_substs += [mutable t_0]; + ty_param_subst_var_ids += [ty::ty_var_id(fcx.ccx.tcx, t_0)]; + + simple(fcx, sp, ty_param_subst, t_0); } - alt (unify::with_params(scx, expected_1, actual_1, ty_param_substs)) { + alt (unify::simple(fcx, expected_1, actual_1)) { case (ures_ok(?t)) { - // TODO: Use "freeze", when we have it. let vec[ty::t] result_ty_param_substs = []; - for (ty::t ty_param_subst in ty_param_substs) { - result_ty_param_substs += [ty_param_subst]; + for (int var_id in ty_param_subst_var_ids) { + auto tp_subst = ty::unify::resolve_all_vars(fcx.ccx.tcx, + fcx.var_bindings, ty::mk_var(fcx.ccx.tcx, var_id)); + result_ty_param_substs += [tp_subst]; } ret tup(result_ty_param_substs, - add_boxes(scx.fcx.ccx, implicit_boxes, t)); + add_boxes(fcx.ccx, implicit_boxes, t)); } - case (ures_err(?err, ?expected, ?actual)) { - scx.fcx.ccx.tcx.sess.span_err + case (ures_err(?err)) { + fcx.ccx.tcx.sess.span_err (sp, "mismatched types: expected " - + ty_to_str(scx.fcx.ccx.tcx, expected) + " but found " - + ty_to_str(scx.fcx.ccx.tcx, actual) + " (" + + ty_to_str(fcx.ccx.tcx, expected_1) + " but found " + + ty_to_str(fcx.ccx.tcx, actual_1) + " (" + ty::type_err_to_str(err) + ")"); // TODO: In the future, try returning "expected", reporting @@ -1047,10 +963,10 @@ mod demand { // Returns true if the two types unify and false if they don't. -fn are_compatible(&@stmt_ctxt scx, &ty::t expected, &ty::t actual) -> bool { - alt (unify::simple(scx, expected, actual)) { - case (ures_ok(_)) { ret true; } - case (ures_err(_, _, _)) { ret false; } +fn are_compatible(&@fn_ctxt fcx, &ty::t expected, &ty::t actual) -> bool { + alt (unify::simple(fcx, expected, actual)) { + case (ures_ok(_)) { ret true; } + case (ures_err(_)) { ret false; } } } @@ -1066,9 +982,8 @@ fn variant_arg_types(&@crate_ctxt ccx, &span sp, &ast::def_id vid, case (ty::ty_fn(_, ?ins, _, _)) { // N-ary variant. for (ty::arg arg in ins) { - auto arg_ty = bind_params_in_type(ccx.tcx, arg.ty); - arg_ty = substitute_ty_params(ccx, arg_ty, ty_param_count, - tag_ty_params, sp); + auto arg_ty = ty::substitute_type_params(ccx.tcx, + tag_ty_params, arg.ty); result += [arg_ty]; } } @@ -1105,22 +1020,22 @@ mod pushdown { // TODO: enforce this via a predicate. // TODO: This function is incomplete. - fn pushdown_expr(&@stmt_ctxt scx, &ty::t expected, &@ast::expr e) { - be pushdown_expr_full(scx, expected, e, NO_AUTODEREF); + fn pushdown_expr(&@fn_ctxt fcx, &ty::t expected, &@ast::expr e) { + be pushdown_expr_full(fcx, expected, e, NO_AUTODEREF); } - fn pushdown_expr_full(&@stmt_ctxt scx, &ty::t expected, &@ast::expr e, + fn pushdown_expr_full(&@fn_ctxt fcx, &ty::t expected, &@ast::expr e, autoderef_kind adk) { alt (e.node) { case (ast::expr_vec(?es_0, ?mut, ?ann)) { // TODO: enforce mutability - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann)); - alt (struct(scx.fcx.ccx.tcx, t)) { + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + alt (struct(fcx.ccx.tcx, t)) { case (ty::ty_vec(?mt)) { for (@ast::expr e_0 in es_0) { - pushdown_expr(scx, mt.ty, e_0); + pushdown_expr(fcx, mt.ty, e_0); } } case (_) { @@ -1128,16 +1043,16 @@ mod pushdown { fail; } } - write::ty_only_fixup(scx, ann.id, t); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_tup(?es_0, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann)); - alt (struct(scx.fcx.ccx.tcx, t)) { + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + alt (struct(fcx.ccx.tcx, t)) { case (ty::ty_tup(?mts)) { auto i = 0u; for (ast::elt elt_0 in es_0) { - pushdown_expr(scx, mts.(i).ty, elt_0.expr); + pushdown_expr(fcx, mts.(i).ty, elt_0.expr); i += 1u; } } @@ -1146,13 +1061,13 @@ mod pushdown { fail; } } - write::ty_only_fixup(scx, ann.id, t); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_rec(?fields_0, ?base_0, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann)); - alt (struct(scx.fcx.ccx.tcx, t)) { + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + alt (struct(fcx.ccx.tcx, t)) { case (ty::ty_rec(?field_mts)) { alt (base_0) { case (none) { @@ -1160,7 +1075,7 @@ mod pushdown { for (ast::field field_0 in fields_0) { assert (str::eq(field_0.node.ident, field_mts.(i).ident)); - pushdown_expr(scx, + pushdown_expr(fcx, field_mts.(i).mt.ty, field_0.node.expr); i += 1u; @@ -1175,7 +1090,7 @@ mod pushdown { for (ty::field ft in field_mts) { if (str::eq(field_0.node.ident, ft.ident)) { - pushdown_expr(scx, ft.mt.ty, + pushdown_expr(fcx, ft.mt.ty, field_0.node.expr); } } @@ -1188,162 +1103,163 @@ mod pushdown { fail; } } - write::ty_only_fixup(scx, ann.id, t); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_bind(?sube, ?es, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_call(?sube, ?es, ?ann)) { // 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(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_self_method(?id, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_binary(?bop, ?lhs, ?rhs, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_unary(?uop, ?sube, ?ann)) { // See note in expr_unary for why we're calling // demand::autoderef. - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + write::ty_only_fixup(fcx, ann.id, t); /* The following is a bit special-cased, but takes care of the case where we say let @vec[whatever] v = @[]; */ auto inner_ty = t; alt (uop) { case (ast::box(?mut)) { - alt (struct(scx.fcx.ccx.tcx, t)) { + alt (struct(fcx.ccx.tcx, t)) { case (ty::ty_box(?inner)) { inner_ty = inner.ty; } case (_) { - scx.fcx.ccx.tcx.sess.span_err(e.span, - "Expecting an application of box" - + " to have a box type"); + fcx.ccx.tcx.sess.span_err(e.span, + "Expecting an application of box " + + "to have a box type; it had type " + + ty::ty_to_str(fcx.ccx.tcx, t)); } } } case (ast::deref) { - inner_ty = ty::mk_box(scx.fcx.ccx.tcx, + inner_ty = ty::mk_box(fcx.ccx.tcx, // maybe_mut should work because it'll unify with // the existing type? rec(ty=t, mut=ast::maybe_mut)); } - case (_) { inner_ty = strip_boxes(scx.fcx.ccx.tcx, t); } + case (_) { inner_ty = strip_boxes(fcx.ccx.tcx, t); } } - pushdown_expr(scx, inner_ty, sube); + pushdown_expr(fcx, inner_ty, sube); } case (ast::expr_lit(?lit, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_cast(?sube, ?ast_ty, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_if(?cond, ?then_0, ?else_0, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann), adk); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); - auto then_t = ty::block_ty(scx.fcx.ccx.tcx, then_0); - pushdown_block(scx, expected, then_0); + auto then_t = ty::block_ty(fcx.ccx.tcx, then_0); + pushdown_block(fcx, expected, then_0); alt (else_0) { case (none) { /* no-op */ } case (some(?e_0)) { - auto else_t = ty::expr_ty(scx.fcx.ccx.tcx, e_0); - pushdown_expr(scx, expected, e_0); + auto else_t = ty::expr_ty(fcx.ccx.tcx, e_0); + pushdown_expr(fcx, expected, e_0); } } - write::ty_only_fixup(scx, ann.id, t); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_for(?decl, ?seq, ?bloc, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_for_each(?decl, ?seq, ?bloc, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_while(?cond, ?bloc, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_do_while(?bloc, ?cond, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_block(?bloc, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(scx, ann.id, t); - pushdown_block(scx, t, bloc); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + write::ty_only_fixup(fcx, ann.id, t); + pushdown_block(fcx, t, bloc); } case (ast::expr_move(?lhs_0, ?rhs_0, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann), adk); - pushdown_expr(scx, expected, lhs_0); - pushdown_expr(scx, expected, rhs_0); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + pushdown_expr(fcx, expected, lhs_0); + pushdown_expr(fcx, expected, rhs_0); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_assign(?lhs_0, ?rhs_0, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann), adk); - pushdown_expr(scx, expected, lhs_0); - pushdown_expr(scx, expected, rhs_0); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + pushdown_expr(fcx, expected, lhs_0); + pushdown_expr(fcx, expected, rhs_0); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_assign_op(?op, ?lhs_0, ?rhs_0, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann), adk); - pushdown_expr(scx, expected, lhs_0); - pushdown_expr(scx, expected, rhs_0); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + pushdown_expr(fcx, expected, lhs_0); + pushdown_expr(fcx, expected, rhs_0); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_field(?lhs, ?rhs, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_index(?base, ?index, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_path(?pth, ?ann)) { auto tp_substs_0 = - ty::ann_to_type_params(scx.fcx.ccx.tcx, ann); - auto t_0 = ann_to_type(scx.fcx.ccx.tcx, ann); + ty::ann_to_type_params(fcx.ccx.tcx, ann); + auto t_0 = ty::ann_to_monotype(fcx.ccx.tcx, ann); - auto result_0 = demand::full(scx, e.span, expected, t_0, + auto result_0 = demand::full(fcx, e.span, expected, t_0, tp_substs_0, adk); - auto t = result_0._1; + auto t = ann_to_type(fcx.ccx.tcx, ann); // Fill in the type parameter substitutions if they weren't // provided by the programmer. auto ty_params_opt; - alt (ty::ann_to_ty_param_substs_opt_and_ty - (scx.fcx.ccx.tcx, ann)._0) { + alt (ty::ann_to_ty_param_substs_opt_and_ty(fcx.ccx.tcx, + ann)._0) { case (none) { ty_params_opt = none[vec[ty::t]]; } @@ -1352,12 +1268,12 @@ mod pushdown { } } - write::ty_fixup(scx, ann.id, tup(ty_params_opt, t)); + write::ty_fixup(fcx, ann.id, tup(ty_params_opt, t)); } case (ast::expr_ext(?p, ?args, ?body, ?expanded, ?ann)) { - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + write::ty_only_fixup(fcx, ann.id, t); } /* FIXME: should this check the type annotations? */ case (ast::expr_fail(_)) { /* no-op */ } @@ -1371,47 +1287,47 @@ mod pushdown { case (ast::expr_assert(_,_)) { /* no-op */ } case (ast::expr_port(?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann)); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_chan(?es, ?ann)) { - auto t = demand::simple(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann)); - alt (struct(scx.fcx.ccx.tcx, t)) { + auto t = demand::simple(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann)); + alt (struct(fcx.ccx.tcx, t)) { case (ty::ty_chan(?subty)) { - auto pt = ty::mk_port(scx.fcx.ccx.tcx, subty); - pushdown_expr(scx, pt, es); + auto pt = ty::mk_port(fcx.ccx.tcx, subty); + pushdown_expr(fcx, pt, es); } case (_) { log "chan expr doesn't have a chan type!"; fail; } } - write::ty_only_fixup(scx, ann.id, t); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_alt(?discrim, ?arms_0, ?ann)) { auto t = expected; for (ast::arm arm_0 in arms_0) { - pushdown_block(scx, expected, arm_0.block); - auto bty = block_ty(scx.fcx.ccx.tcx, arm_0.block); - t = demand::simple(scx, e.span, t, bty); + pushdown_block(fcx, expected, arm_0.block); + auto bty = block_ty(fcx.ccx.tcx, arm_0.block); + t = demand::simple(fcx, e.span, t, bty); } - write::ty_only_fixup(scx, ann.id, t); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_recv(?lval, ?expr, ?ann)) { - pushdown_expr(scx, next_ty_var(scx), lval); - auto t = expr_ty(scx.fcx.ccx.tcx, lval); - write::ty_only_fixup(scx, ann.id, t); + pushdown_expr(fcx, next_ty_var(fcx), lval); + auto t = expr_ty(fcx.ccx.tcx, lval); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_send(?lval, ?expr, ?ann)) { - pushdown_expr(scx, next_ty_var(scx), expr); - auto t = expr_ty(scx.fcx.ccx.tcx, expr); - pushdown_expr(scx, ty::mk_chan(scx.fcx.ccx.tcx, t), lval); + pushdown_expr(fcx, next_ty_var(fcx), expr); + auto t = expr_ty(fcx.ccx.tcx, expr); + pushdown_expr(fcx, ty::mk_chan(fcx.ccx.tcx, t), lval); } case (ast::expr_spawn(?dom, ?name, ?func, ?args, ?ann)) { @@ -1419,21 +1335,21 @@ mod pushdown { // 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(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + write::ty_only_fixup(fcx, ann.id, t); } case (ast::expr_anon_obj(?anon_obj, ?tps, ?odid, ?ann)) { // NB: Not sure if this is correct, but not worrying too much // about it since pushdown is going away anyway. - auto t = demand::autoderef(scx, e.span, expected, - ann_to_type(scx.fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(scx, ann.id, t); + auto t = demand::autoderef(fcx, e.span, expected, + ann_to_type(fcx.ccx.tcx, ann), adk); + write::ty_only_fixup(fcx, ann.id, t); } case (_) { - scx.fcx.ccx.tcx.sess.span_unimpl(e.span, + fcx.ccx.tcx.sess.span_unimpl(e.span, #fmt("type unification for expression variant: %s", pretty::pprust::expr_to_str(e))); } @@ -1441,89 +1357,94 @@ mod pushdown { } // Push-down over typed blocks. - fn pushdown_block(&@stmt_ctxt scx, &ty::t expected, &ast::block bloc) { + fn pushdown_block(&@fn_ctxt fcx, &ty::t expected, &ast::block bloc) { alt (bloc.node.expr) { case (some(?e_0)) { - pushdown_expr(scx, expected, e_0); + pushdown_expr(fcx, expected, e_0); } case (none) { /* empty */ } } - demand::simple(scx, bloc.span, expected, - ann_to_type(scx.fcx.ccx.tcx, bloc.node.a)); + demand::simple(fcx, bloc.span, expected, ann_to_type(fcx.ccx.tcx, + bloc.node.a)); } } -// Local variable resolution: the phase that finds all the types in the AST -// and replaces opaque "ty_local" types with the resolved local types. +// Type resolution: the phase that finds all the types in the AST with +// unresolved type variables and replaces "ty_var" types with their +// substitutions. +// +// TODO: inefficient since not all types have vars in them. It would be better +// to maintain a list of fixups. mod writeback { - fn wb_local(&@fn_ctxt fcx, &span sp, &@ast::local local) { - auto local_ty; - alt (fcx.locals.find(local.id)) { - case (none) { - fcx.ccx.tcx.sess.span_err(sp, - "unable to determine type of local: " + local.ident); - } - case (some(?lt)) { - local_ty = lt; - } - } + fn resolve_type_vars_in_type(&@fn_ctxt fcx, &span sp, ty::t typ) + -> ty::t { + if (!ty::type_contains_vars(fcx.ccx.tcx, typ)) { ret typ; } - if (ty::type_contains_vars(fcx.ccx.tcx, local_ty)) { - fcx.ccx.tcx.sess.span_err(sp, - "Ambiguous type " + ty_to_str(fcx.ccx.tcx, local_ty) - + "\n(Try adding more type annotations.)"); + alt (ty::unify::fixup_vars(fcx.ccx.tcx, fcx.var_bindings, typ)) { + case (fix_ok(?new_type)) { ret new_type; } + case (fix_err(?vid)) { + // TODO: We should try to do a variable ID -> local lookup if + // we can and display this in terms of the local that had an + // incomplete type. + fcx.ccx.tcx.sess.span_err(sp, #fmt( + "cannot determine type of variable ID `%d`", vid)); + } } - write::ty_only(fcx.ccx.tcx, local.ann.id, local_ty); } - fn resolve_local_types(&@fn_ctxt fcx, &ast::ann ann) { - fn resolver(@fn_ctxt fcx, ty::t typ) -> ty::t { - alt (struct(fcx.ccx.tcx, typ)) { - case (ty::ty_local(?lid)) { ret fcx.locals.get(lid); } - case (_) { ret typ; } + fn resolve_type_vars_for_node(&@fn_ctxt fcx, &span sp, &ast::ann ann) { + auto tpot = ty::ann_to_ty_param_substs_opt_and_ty(fcx.ccx.tcx, ann); + auto new_ty = resolve_type_vars_in_type(fcx, sp, tpot._1); + + auto new_substs_opt; + alt (tpot._0) { + case (none[vec[ty::t]]) { new_substs_opt = none[vec[ty::t]]; } + case (some[vec[ty::t]](?substs)) { + let vec[ty::t] new_substs = []; + for (ty::t subst in substs) { + new_substs += [resolve_type_vars_in_type(fcx, sp, subst)]; + } + new_substs_opt = some[vec[ty::t]](new_substs); } } - auto tpot = - ty::ann_to_ty_param_substs_opt_and_ty(fcx.ccx.tcx, - ann); - auto tt = tpot._1; - if (!ty::type_contains_locals(fcx.ccx.tcx, tt)) { ret; } - - auto f = bind resolver(fcx, _); - auto new_type = ty::fold_ty(fcx.ccx.tcx, f, tt); - write::ty(fcx.ccx.tcx, ann.id, tup(tpot._0, new_type)); + write::ty(fcx.ccx.tcx, ann.id, tup(new_substs_opt, new_ty)); } fn visit_stmt_pre(@fn_ctxt fcx, &@ast::stmt s) { - resolve_local_types(fcx, ty::stmt_ann(s)); + resolve_type_vars_for_node(fcx, s.span, ty::stmt_ann(s)); } fn visit_expr_pre(@fn_ctxt fcx, &@ast::expr e) { - resolve_local_types(fcx, ty::expr_ann(e)); + resolve_type_vars_for_node(fcx, e.span, ty::expr_ann(e)); } fn visit_block_pre(@fn_ctxt fcx, &ast::block b) { - resolve_local_types(fcx, b.node.a); + resolve_type_vars_for_node(fcx, b.span, b.node.a); } - fn visit_arm_pre(@fn_ctxt fcx, &ast::arm a) { - // FIXME: Need a visit_pat_pre - resolve_local_types(fcx, ty::pat_ann(a.pat)); + fn visit_pat_pre(@fn_ctxt fcx, &@ast::pat p) { + resolve_type_vars_for_node(fcx, p.span, ty::pat_ann(p)); } fn visit_decl_pre(@fn_ctxt fcx, &@ast::decl d) { alt (d.node) { - case (ast::decl_local(?l)) { wb_local(fcx, d.span, l); } - case (ast::decl_item(_)) { /* no annotation */ } + case (ast::decl_local(?l)) { + // FIXME: Report errors better. + auto var_id = fcx.locals.get(l.id); + auto lty = ty::unify::resolve_type_var(fcx.ccx.tcx, + fcx.var_bindings, var_id); + write::ty_only(fcx.ccx.tcx, l.ann.id, lty); + } + case (_) { /* no-op */ } } } - fn resolve_local_types_in_block(&@fn_ctxt fcx, &ast::block block) { + fn resolve_type_vars_in_block(&@fn_ctxt fcx, &ast::block block) { // A trick to ignore any contained items. auto ignore = @mutable false; fn visit_item_pre(@mutable bool ignore, &@ast::item item) { @@ -1540,7 +1461,7 @@ mod writeback { visit_stmt_pre=bind visit_stmt_pre(fcx, _), visit_expr_pre=bind visit_expr_pre(fcx, _), visit_block_pre=bind visit_block_pre(fcx, _), - visit_arm_pre=bind visit_arm_pre(fcx, _), + visit_pat_pre=bind visit_pat_pre(fcx, _), visit_decl_pre=bind visit_decl_pre(fcx, _) with walk::default_visitor()); walk::walk_block(visit, block); @@ -1548,19 +1469,151 @@ mod writeback { } +// Local variable gathering. We gather up all locals and create variable IDs +// for them before typechecking the function. + +type gather_result = rec( + @ty::unify::var_bindings var_bindings, + hashmap[ast::def_id,int] locals, + hashmap[ast::def_id,ast::ident] local_names, + int next_var_id +); + +fn gather_locals(&@crate_ctxt ccx, &ast::fn_decl decl, &ast::block body, + &ast::ann ann) -> gather_result { + fn next_var_id(@mutable int nvi) -> int { + auto rv = *nvi; + *nvi += 1; + ret rv; + } + + fn assign(&ty::ctxt tcx, + &@ty::unify::var_bindings var_bindings, + &hashmap[ast::def_id,int] locals, + &hashmap[ast::def_id,ast::ident] local_names, + @mutable int nvi, + ast::def_id lid, + &ast::ident ident, + option::t[ty::t] ty_opt) { + auto var_id = next_var_id(nvi); + locals.insert(lid, var_id); + local_names.insert(lid, ident); + + alt (ty_opt) { + case (none[ty::t]) { /* nothing to do */ } + case (some[ty::t](?typ)) { + ty::unify::unify(ty::mk_var(tcx, var_id), typ, var_bindings, + tcx); + } + } + } + + auto vb = ty::unify::mk_var_bindings(); + auto locals = new_def_hash[int](); + auto local_names = new_def_hash[ast::ident](); + auto nvi = @mutable 0; + + // Add object fields, if any. + alt (get_obj_info(ccx)) { + case (option::some(?oinfo)) { + for (ast::obj_field f in oinfo.obj_fields) { + auto field_ty = ty::ann_to_type(ccx.tcx, f.ann); + assign(ccx.tcx, vb, locals, local_names, nvi, f.id, f.ident, + some[ty::t](field_ty)); + } + } + case (option::none) { /* no fields */ } + } + + // Add formal parameters. + auto args = ty::ty_fn_args(ccx.tcx, ty::ann_to_type(ccx.tcx, ann)); + auto i = 0u; + for (ty::arg arg in args) { + assign(ccx.tcx, vb, locals, local_names, nvi, decl.inputs.(i).id, + decl.inputs.(i).ident, some[ty::t](arg.ty)); + i += 1u; + } + + // Add explicitly-declared locals. + fn visit_decl_pre(@crate_ctxt ccx, + @ty::unify::var_bindings vb, + hashmap[ast::def_id,int] locals, + hashmap[ast::def_id,ast::ident] local_names, + @mutable int nvi, + &@ast::decl d) { + alt (d.node) { + case (ast::decl_local(?local)) { + alt (local.ty) { + case (none) { + // Auto slot. + assign(ccx.tcx, vb, locals, local_names, nvi, + local.id, local.ident, none[ty::t]); + } + case (some(?ast_ty)) { + // Explicitly typed slot. + auto local_ty = ast_ty_to_ty_crate(ccx, ast_ty); + assign(ccx.tcx, vb, locals, local_names, nvi, + local.id, local.ident, some[ty::t](local_ty)); + } + } + } + case (_) { /* no-op */ } + } + } + + // Add pattern bindings. + fn visit_pat_pre(@crate_ctxt ccx, + @ty::unify::var_bindings vb, + hashmap[ast::def_id,int] locals, + hashmap[ast::def_id,ast::ident] local_names, + @mutable int nvi, + &@ast::pat p) { + alt (p.node) { + case (ast::pat_bind(?ident, ?did, _)) { + assign(ccx.tcx, vb, locals, local_names, nvi, did, ident, + none[ty::t]); + } + case (_) { /* no-op */ } + } + } + + auto visit = + rec(visit_decl_pre=bind visit_decl_pre(ccx, vb, locals, local_names, + nvi, _), + visit_pat_pre=bind visit_pat_pre(ccx, vb, locals, local_names, + nvi, _) + with walk::default_visitor()); + walk::walk_block(visit, body); + + ret rec( + var_bindings=vb, + locals=locals, + local_names=local_names, + next_var_id=*nvi + ); +} + + // AST fragment utilities -fn replace_expr_type(&@stmt_ctxt scx, +fn replace_expr_type(&@fn_ctxt fcx, &@ast::expr expr, &tup(vec[ty::t], ty::t) new_tyt) { auto new_tps; - if (ty::expr_has_ty_params(scx.fcx.ccx.tcx, expr)) { + if (ty::expr_has_ty_params(fcx.ccx.tcx, expr)) { new_tps = some[vec[ty::t]](new_tyt._0); } else { new_tps = none[vec[ty::t]]; } - write::ty_fixup(scx, ty::expr_ann(expr).id, tup(new_tps, new_tyt._1)); + write::ty_fixup(fcx, ty::expr_ann(expr).id, tup(new_tps, new_tyt._1)); +} + +fn replace_node_type_only(&ty::ctxt tcx, uint fixup, ty::t new_t) { + auto fixup_opt = tcx.node_types.(fixup); + auto tps = option::get[ty::ty_param_substs_opt_and_ty](fixup_opt)._0; + tcx.node_types.(fixup) = + some[ty::ty_param_substs_opt_and_ty](tup(tps, new_t)); } @@ -1582,50 +1635,53 @@ fn check_lit(@crate_ctxt ccx, &@ast::lit lit) -> ty::t { // Pattern checking is top-down rather than bottom-up so that bindings get // their types immediately. -fn check_pat(&@stmt_ctxt scx, &@ast::pat pat, ty::t expected) { +fn check_pat(&@fn_ctxt fcx, &@ast::pat pat, ty::t expected) { alt (pat.node) { case (ast::pat_wild(?ann)) { - write::ty_only_fixup(scx, ann.id, expected); + write::ty_only_fixup(fcx, ann.id, expected); } case (ast::pat_lit(?lt, ?ann)) { - auto typ = check_lit(scx.fcx.ccx, lt); - typ = demand::simple(scx, pat.span, expected, typ); - write::ty_only_fixup(scx, ann.id, typ); + auto typ = check_lit(fcx.ccx, lt); + typ = demand::simple(fcx, pat.span, expected, typ); + write::ty_only_fixup(fcx, ann.id, typ); } case (ast::pat_bind(?id, ?def_id, ?ann)) { - scx.fcx.locals.insert(def_id, expected); - write::ty_only_fixup(scx, ann.id, expected); + auto vid = fcx.locals.get(def_id); + auto typ = ty::mk_var(fcx.ccx.tcx, vid); + typ = demand::simple(fcx, pat.span, expected, typ); + write::ty_only_fixup(fcx, ann.id, typ); } case (ast::pat_tag(?path, ?subpats, ?ann)) { // Typecheck the path. - auto v_def = scx.fcx.ccx.tcx.def_map.get(ann.id); + auto v_def = fcx.ccx.tcx.def_map.get(ann.id); auto v_def_ids = ast::variant_def_ids(v_def); - auto tag_tpt = ty::lookup_item_type(scx.fcx.ccx.tcx, + auto tag_tpt = ty::lookup_item_type(fcx.ccx.tcx, v_def_ids._0); - auto path_tpot = instantiate_path(scx, path, tag_tpt, pat.span); + auto path_tpot = instantiate_path(fcx, path, tag_tpt, pat.span); // Take the tag type params out of `expected`. auto expected_tps; - alt (struct(scx.fcx.ccx.tcx, expected)) { + alt (struct(fcx.ccx.tcx, expected)) { case (ty::ty_tag(_, ?tps)) { expected_tps = tps; } case (_) { // FIXME: Switch expected and actual in this message? I // can never tell. - scx.fcx.ccx.tcx.sess.span_err(pat.span, + fcx.ccx.tcx.sess.span_err(pat.span, #fmt("mismatched types: expected tag but found %s", - ty::ty_to_str(scx.fcx.ccx.tcx, expected))); + ty::ty_to_str(fcx.ccx.tcx, expected))); } } // Unify with the expected tag type. - auto path_tpt = demand::full(scx, pat.span, expected, - path_tpot._1, expected_tps, - NO_AUTODEREF); + auto ctor_ty = ty::ty_param_substs_opt_and_ty_to_monotype( + fcx.ccx.tcx, path_tpot); + auto path_tpt = demand::full(fcx, pat.span, expected, ctor_ty, + expected_tps, NO_AUTODEREF); path_tpot = tup(some[vec[ty::t]](path_tpt._0), path_tpt._1); // Get the number of arguments in this tag variant. - auto arg_types = variant_arg_types(scx.fcx.ccx, pat.span, + auto arg_types = variant_arg_types(fcx.ccx, pat.span, v_def_ids._1, expected_tps); auto subpats_len = vec::len[@ast::pat](subpats); @@ -1637,7 +1693,7 @@ fn check_pat(&@stmt_ctxt scx, &@ast::pat pat, ty::t expected) { // TODO: note definition of tag variant // TODO (issue #448): Wrap a #fmt string over multiple // lines... - scx.fcx.ccx.tcx.sess.span_err(pat.span, #fmt( + fcx.ccx.tcx.sess.span_err(pat.span, #fmt( "this pattern has %u field%s, but the corresponding variant has %u field%s", subpats_len, if (subpats_len == 0u) { "" } else { "s" }, @@ -1648,20 +1704,20 @@ fn check_pat(&@stmt_ctxt scx, &@ast::pat pat, ty::t expected) { // TODO: vec::iter2 auto i = 0u; for (@ast::pat subpat in subpats) { - check_pat(scx, subpat, arg_types.(i)); + check_pat(fcx, subpat, arg_types.(i)); i += 1u; } } else if (subpats_len > 0u) { // TODO: note definition of tag variant // TODO (issue #448): Wrap a #fmt string over multiple // lines... - scx.fcx.ccx.tcx.sess.span_err(pat.span, #fmt( + fcx.ccx.tcx.sess.span_err(pat.span, #fmt( "this pattern has %u field%s, but the corresponding variant has no fields", subpats_len, if (subpats_len == 0u) { "" } else { "s" })); } - write::ty_fixup(scx, ann.id, path_tpot); + write::ty_fixup(fcx, ann.id, path_tpot); } } } @@ -1728,16 +1784,16 @@ fn require_pure_function(@crate_ctxt ccx, &ast::def_id d_id, &span sp) -> () { } } -fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { - // scx.fcx.ccx.tcx.sess.span_warn(expr.span, "typechecking expr " + +fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { + // fcx.ccx.tcx.sess.span_warn(expr.span, "typechecking expr " + // pretty::pprust::expr_to_str(expr)); // A generic function to factor out common logic from call and bind // expressions. - fn check_call_or_bind(&@stmt_ctxt scx, &@ast::expr f, + fn check_call_or_bind(&@fn_ctxt fcx, &@ast::expr f, &vec[option::t[@ast::expr]] args) { // Check the function. - check_expr(scx, f); + check_expr(fcx, f); // Check the arguments and generate the argument signature. let vec[option::t[@ast::expr]] args_0 = []; @@ -1745,223 +1801,225 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { for (option::t[@ast::expr] a_opt in args) { alt (a_opt) { case (some(?a)) { - check_expr(scx, a); - auto typ = expr_ty(scx.fcx.ccx.tcx, a); + check_expr(fcx, a); + auto typ = expr_ty(fcx.ccx.tcx, a); vec::push[arg](arg_tys_0, rec(mode=mo_either, ty=typ)); } case (none) { - auto typ = next_ty_var(scx); + auto typ = next_ty_var(fcx); vec::push[arg](arg_tys_0, rec(mode=mo_either, ty=typ)); } } } - auto rt_0 = next_ty_var(scx); + auto rt_0 = next_ty_var(fcx); auto t_0; - alt (struct(scx.fcx.ccx.tcx, expr_ty(scx.fcx.ccx.tcx, f))) { + alt (struct(fcx.ccx.tcx, expr_ty(fcx.ccx.tcx, f))) { case (ty::ty_fn(?proto, _, _, ?cf)) { - t_0 = ty::mk_fn(scx.fcx.ccx.tcx, proto, arg_tys_0, rt_0, cf); + t_0 = ty::mk_fn(fcx.ccx.tcx, proto, arg_tys_0, rt_0, cf); } case (ty::ty_native_fn(?abi, _, _)) { - t_0 = ty::mk_native_fn(scx.fcx.ccx.tcx, abi, arg_tys_0, rt_0); + t_0 = ty::mk_native_fn(fcx.ccx.tcx, abi, arg_tys_0, rt_0); } case (?u) { - scx.fcx.ccx.tcx.sess.span_err(f.span, + fcx.ccx.tcx.sess.span_err(f.span, "check_call_or_bind(): fn expr doesn't have fn type," + " instead having: " + - ty_to_str(scx.fcx.ccx.tcx, - expr_ty(scx.fcx.ccx.tcx, f))); + ty_to_str(fcx.ccx.tcx, + expr_ty(fcx.ccx.tcx, f))); } } // Unify the callee and arguments. - auto tpt_0 = ty::expr_ty_params_and_ty(scx.fcx.ccx.tcx, f); - auto tpt_1 = demand::full(scx, f.span, tpt_0._1, t_0, tpt_0._0, + auto f_ty = ty::expr_ty(fcx.ccx.tcx, f); + auto f_tps = ty::expr_ty_params_and_ty(fcx.ccx.tcx, f)._0; + auto tpt_1 = demand::full(fcx, f.span, f_ty, t_0, f_tps, NO_AUTODEREF); - replace_expr_type(scx, f, tpt_1); + //replace_expr_type(fcx, f, tpt_1); } // A generic function for checking assignment expressions - fn check_assignment(&@stmt_ctxt scx, &@ast::expr lhs, &@ast::expr rhs, + fn check_assignment(&@fn_ctxt fcx, &@ast::expr lhs, &@ast::expr rhs, &ast::ann a) { - check_expr(scx, lhs); - check_expr(scx, rhs); - auto lhs_t0 = expr_ty(scx.fcx.ccx.tcx, lhs); - auto rhs_t0 = expr_ty(scx.fcx.ccx.tcx, rhs); + check_expr(fcx, lhs); + check_expr(fcx, rhs); + auto lhs_t0 = expr_ty(fcx.ccx.tcx, lhs); + auto rhs_t0 = expr_ty(fcx.ccx.tcx, rhs); - pushdown::pushdown_expr(scx, rhs_t0, lhs); - auto lhs_t1 = expr_ty(scx.fcx.ccx.tcx, lhs); - pushdown::pushdown_expr(scx, lhs_t1, rhs); - auto rhs_t1 = expr_ty(scx.fcx.ccx.tcx, rhs); + pushdown::pushdown_expr(fcx, rhs_t0, lhs); + auto lhs_t1 = expr_ty(fcx.ccx.tcx, lhs); + pushdown::pushdown_expr(fcx, lhs_t1, rhs); + auto rhs_t1 = expr_ty(fcx.ccx.tcx, rhs); - write::ty_only_fixup(scx, a.id, rhs_t1); + write::ty_only_fixup(fcx, a.id, rhs_t1); } // A generic function for checking call expressions - fn check_call(&@stmt_ctxt scx, &@ast::expr f, &vec[@ast::expr] args) { + fn check_call(&@fn_ctxt fcx, &@ast::expr f, &vec[@ast::expr] args) { let vec[option::t[@ast::expr]] args_opt_0 = []; for (@ast::expr arg in args) { args_opt_0 += [some[@ast::expr](arg)]; } // Call the generic checker. - check_call_or_bind(scx, f, args_opt_0); + check_call_or_bind(fcx, f, args_opt_0); } // A generic function for checking for or for-each loops - fn check_for_or_for_each(&@stmt_ctxt scx, &@ast::decl decl, + fn check_for_or_for_each(&@fn_ctxt fcx, &@ast::decl decl, &ty::t element_ty, &ast::block body, uint node_id) { - check_decl_local(scx.fcx, decl); - check_block(scx, body); + check_decl_local(fcx, decl); + check_block(fcx, body); // Unify type of decl with element type of the seq - demand::simple(scx, decl.span, ty::decl_local_ty(scx.fcx.ccx.tcx, + demand::simple(fcx, decl.span, ty::decl_local_ty(fcx.ccx.tcx, decl), element_ty); - auto typ = ty::mk_nil(scx.fcx.ccx.tcx); - write::ty_only_fixup(scx, node_id, typ); + auto typ = ty::mk_nil(fcx.ccx.tcx); + write::ty_only_fixup(fcx, node_id, typ); } alt (expr.node) { case (ast::expr_lit(?lit, ?a)) { - auto typ = check_lit(scx.fcx.ccx, lit); - write::ty_only_fixup(scx, a.id, typ); + auto typ = check_lit(fcx.ccx, lit); + write::ty_only_fixup(fcx, a.id, typ); } case (ast::expr_binary(?binop, ?lhs, ?rhs, ?a)) { - check_expr(scx, lhs); - check_expr(scx, rhs); - auto lhs_t0 = expr_ty(scx.fcx.ccx.tcx, lhs); - auto rhs_t0 = expr_ty(scx.fcx.ccx.tcx, rhs); + check_expr(fcx, lhs); + check_expr(fcx, rhs); + auto lhs_t0 = expr_ty(fcx.ccx.tcx, lhs); + auto rhs_t0 = expr_ty(fcx.ccx.tcx, rhs); // FIXME: Binops have a bit more subtlety than this. - pushdown::pushdown_expr_full(scx, rhs_t0, lhs, AUTODEREF_OK); - auto lhs_t1 = expr_ty(scx.fcx.ccx.tcx, lhs); - pushdown::pushdown_expr_full(scx, lhs_t1, rhs, AUTODEREF_OK); + pushdown::pushdown_expr_full(fcx, rhs_t0, lhs, AUTODEREF_OK); + auto lhs_t1 = expr_ty(fcx.ccx.tcx, lhs); + pushdown::pushdown_expr_full(fcx, lhs_t1, rhs, AUTODEREF_OK); - auto t = strip_boxes(scx.fcx.ccx.tcx, lhs_t0); + auto t = strip_boxes(fcx.ccx.tcx, lhs_t0); alt (binop) { - case (ast::eq) { t = ty::mk_bool(scx.fcx.ccx.tcx); } - case (ast::lt) { t = ty::mk_bool(scx.fcx.ccx.tcx); } - case (ast::le) { t = ty::mk_bool(scx.fcx.ccx.tcx); } - case (ast::ne) { t = ty::mk_bool(scx.fcx.ccx.tcx); } - case (ast::ge) { t = ty::mk_bool(scx.fcx.ccx.tcx); } - case (ast::gt) { t = ty::mk_bool(scx.fcx.ccx.tcx); } + case (ast::eq) { t = ty::mk_bool(fcx.ccx.tcx); } + case (ast::lt) { t = ty::mk_bool(fcx.ccx.tcx); } + case (ast::le) { t = ty::mk_bool(fcx.ccx.tcx); } + case (ast::ne) { t = ty::mk_bool(fcx.ccx.tcx); } + case (ast::ge) { t = ty::mk_bool(fcx.ccx.tcx); } + case (ast::gt) { t = ty::mk_bool(fcx.ccx.tcx); } case (_) { /* fall through */ } } - write::ty_only_fixup(scx, a.id, t); + write::ty_only_fixup(fcx, a.id, t); } case (ast::expr_unary(?unop, ?oper, ?a)) { - check_expr(scx, oper); + check_expr(fcx, oper); - auto oper_t = expr_ty(scx.fcx.ccx.tcx, oper); + auto oper_t = expr_ty(fcx.ccx.tcx, oper); alt (unop) { case (ast::box(?mut)) { - oper_t = ty::mk_box(scx.fcx.ccx.tcx, + oper_t = ty::mk_box(fcx.ccx.tcx, rec(ty=oper_t, mut=mut)); } case (ast::deref) { - alt (struct(scx.fcx.ccx.tcx, oper_t)) { + alt (struct(fcx.ccx.tcx, oper_t)) { case (ty::ty_box(?inner)) { oper_t = inner.ty; } case (_) { - scx.fcx.ccx.tcx.sess.span_err + fcx.ccx.tcx.sess.span_err (expr.span, "dereferencing non-box type: " - + ty_to_str(scx.fcx.ccx.tcx, oper_t)); + + ty_to_str(fcx.ccx.tcx, oper_t)); } } } - case (_) { oper_t = strip_boxes(scx.fcx.ccx.tcx, oper_t); } + case (_) { oper_t = strip_boxes(fcx.ccx.tcx, oper_t); } } - write::ty_only_fixup(scx, a.id, oper_t); + write::ty_only_fixup(fcx, a.id, oper_t); } case (ast::expr_path(?pth, ?old_ann)) { - auto t = ty::mk_nil(scx.fcx.ccx.tcx); - auto defn = scx.fcx.ccx.tcx.def_map.get(old_ann.id); + auto t = ty::mk_nil(fcx.ccx.tcx); + auto defn = fcx.ccx.tcx.def_map.get(old_ann.id); - auto tpt = ty_param_count_and_ty_for_def(scx.fcx, expr.span, + auto tpt = ty_param_count_and_ty_for_def(fcx, expr.span, defn); if (ty::def_has_ty_params(defn)) { - auto path_tpot = instantiate_path(scx, pth, tpt, expr.span); - write::ty_fixup(scx, old_ann.id, path_tpot); + auto path_tpot = instantiate_path(fcx, pth, tpt, expr.span); + write::ty_fixup(fcx, old_ann.id, path_tpot); ret; } // 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) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "this kind of value does not take type parameters"); } - write::ty_only_fixup(scx, old_ann.id, tpt._1); + write::ty_only_fixup(fcx, old_ann.id, tpt._1); } case (ast::expr_ext(?p, ?args, ?body, ?expanded, ?a)) { - check_expr(scx, expanded); - auto t = expr_ty(scx.fcx.ccx.tcx, expanded); - write::ty_only_fixup(scx, a.id, t); + check_expr(fcx, expanded); + auto t = expr_ty(fcx.ccx.tcx, expanded); + write::ty_only_fixup(fcx, a.id, t); } case (ast::expr_fail(?a)) { - write::bot_ty(scx.fcx.ccx.tcx, a.id); + write::bot_ty(fcx.ccx.tcx, a.id); } case (ast::expr_break(?a)) { - write::bot_ty(scx.fcx.ccx.tcx, a.id); + write::bot_ty(fcx.ccx.tcx, a.id); } case (ast::expr_cont(?a)) { - write::bot_ty(scx.fcx.ccx.tcx, a.id); + write::bot_ty(fcx.ccx.tcx, a.id); } case (ast::expr_ret(?expr_opt, ?a)) { alt (expr_opt) { case (none) { - auto nil = ty::mk_nil(scx.fcx.ccx.tcx); - if (!are_compatible(scx, scx.fcx.ret_ty, nil)) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + auto nil = ty::mk_nil(fcx.ccx.tcx); + if (!are_compatible(fcx, fcx.ret_ty, nil)) { + fcx.ccx.tcx.sess.span_err(expr.span, "ret; in function returning non-nil"); } - write::bot_ty(scx.fcx.ccx.tcx, a.id); + write::bot_ty(fcx.ccx.tcx, a.id); } case (some(?e)) { - check_expr(scx, e); - pushdown::pushdown_expr(scx, scx.fcx.ret_ty, e); + check_expr(fcx, e); + + pushdown::pushdown_expr(fcx, fcx.ret_ty, e); - write::bot_ty(scx.fcx.ccx.tcx, a.id); + write::bot_ty(fcx.ccx.tcx, a.id); } } } case (ast::expr_put(?expr_opt, ?a)) { - require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span); + require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); alt (expr_opt) { case (none) { - auto nil = ty::mk_nil(scx.fcx.ccx.tcx); - if (!are_compatible(scx, scx.fcx.ret_ty, nil)) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + auto nil = ty::mk_nil(fcx.ccx.tcx); + if (!are_compatible(fcx, fcx.ret_ty, nil)) { + fcx.ccx.tcx.sess.span_err(expr.span, "put; in iterator yielding non-nil"); } - write::nil_ty(scx.fcx.ccx.tcx, a.id); + write::nil_ty(fcx.ccx.tcx, a.id); } case (some(?e)) { - check_expr(scx, e); - pushdown::pushdown_expr(scx, scx.fcx.ret_ty, e); + check_expr(fcx, e); + pushdown::pushdown_expr(fcx, fcx.ret_ty, e); - write::nil_ty(scx.fcx.ccx.tcx, a.id); + write::nil_ty(fcx.ccx.tcx, a.id); } } } @@ -1970,21 +2028,21 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { // FIXME: prove instead of assert assert (ast::is_call_expr(e)); - check_expr(scx, e); - pushdown::pushdown_expr(scx, scx.fcx.ret_ty, e); + check_expr(fcx, e); + pushdown::pushdown_expr(fcx, fcx.ret_ty, e); - write::nil_ty(scx.fcx.ccx.tcx, a.id); + write::nil_ty(fcx.ccx.tcx, a.id); } case (ast::expr_log(?l, ?e, ?a)) { - auto expr_t = check_expr(scx, e); - write::nil_ty(scx.fcx.ccx.tcx, a.id); + auto expr_t = check_expr(fcx, e); + write::nil_ty(fcx.ccx.tcx, a.id); } case (ast::expr_check(?e, ?a)) { - check_expr(scx, e); - demand::simple(scx, expr.span, ty::mk_bool(scx.fcx.ccx.tcx), - expr_ty(scx.fcx.ccx.tcx, e)); + check_expr(fcx, e); + demand::simple(fcx, expr.span, ty::mk_bool(fcx.ccx.tcx), + expr_ty(fcx.ccx.tcx, e)); /* e must be a call expr where all arguments are either literals or slots */ alt (e.node) { @@ -1992,237 +2050,237 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { alt (operator.node) { case (ast::expr_path(?oper_name, ?ann)) { auto d_id; - alt (scx.fcx.ccx.tcx.def_map.get(ann.id)) { + alt (fcx.ccx.tcx.def_map.get(ann.id)) { case (ast::def_fn(?_d_id)) { d_id = _d_id; } } for (@ast::expr operand in operands) { if (! ast::is_constraint_arg(operand)) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "Constraint args must be " + "slot variables or literals"); } } - require_pure_function(scx.fcx.ccx, d_id, + require_pure_function(fcx.ccx, d_id, expr.span); - write::nil_ty(scx.fcx.ccx.tcx, a.id); + write::nil_ty(fcx.ccx.tcx, a.id); } case (_) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "In a constraint, expected the constraint name " + "to be an explicit name"); } } } case (_) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "check on non-predicate"); } } } case (ast::expr_assert(?e, ?a)) { - check_expr(scx, e); - auto ety = expr_ty(scx.fcx.ccx.tcx, e); - demand::simple(scx, expr.span, ty::mk_bool(scx.fcx.ccx.tcx), ety); + check_expr(fcx, e); + auto ety = expr_ty(fcx.ccx.tcx, e); + demand::simple(fcx, expr.span, ty::mk_bool(fcx.ccx.tcx), ety); - write::nil_ty(scx.fcx.ccx.tcx, a.id); + write::nil_ty(fcx.ccx.tcx, a.id); } case (ast::expr_move(?lhs, ?rhs, ?a)) { - require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span); - check_assignment(scx, lhs, rhs, a); + require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); + check_assignment(fcx, lhs, rhs, a); } case (ast::expr_assign(?lhs, ?rhs, ?a)) { - require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span); - check_assignment(scx, lhs, rhs, a); + require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); + check_assignment(fcx, lhs, rhs, a); } case (ast::expr_assign_op(?op, ?lhs, ?rhs, ?a)) { - require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span); - check_assignment(scx, lhs, rhs, a); + require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); + check_assignment(fcx, lhs, rhs, a); } case (ast::expr_send(?lhs, ?rhs, ?a)) { - require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span); + require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); - check_expr(scx, lhs); - check_expr(scx, rhs); - auto rhs_t = expr_ty(scx.fcx.ccx.tcx, rhs); + check_expr(fcx, lhs); + check_expr(fcx, rhs); + auto rhs_t = expr_ty(fcx.ccx.tcx, rhs); - auto chan_t = ty::mk_chan(scx.fcx.ccx.tcx, rhs_t); - pushdown::pushdown_expr(scx, chan_t, lhs); + auto chan_t = ty::mk_chan(fcx.ccx.tcx, rhs_t); + pushdown::pushdown_expr(fcx, chan_t, lhs); auto item_t; - auto lhs_t = expr_ty(scx.fcx.ccx.tcx, lhs); - alt (struct(scx.fcx.ccx.tcx, lhs_t)) { + auto lhs_t = expr_ty(fcx.ccx.tcx, lhs); + alt (struct(fcx.ccx.tcx, lhs_t)) { case (ty::ty_chan(?it)) { item_t = it; } case (_) { fail; } } - pushdown::pushdown_expr(scx, item_t, rhs); + pushdown::pushdown_expr(fcx, item_t, rhs); - write::ty_only_fixup(scx, a.id, chan_t); + write::ty_only_fixup(fcx, a.id, chan_t); } case (ast::expr_recv(?lhs, ?rhs, ?a)) { - require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span); + require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); - check_expr(scx, lhs); - check_expr(scx, rhs); - auto lhs_t1 = expr_ty(scx.fcx.ccx.tcx, lhs); + check_expr(fcx, lhs); + check_expr(fcx, rhs); + auto lhs_t1 = expr_ty(fcx.ccx.tcx, lhs); - auto port_t = ty::mk_port(scx.fcx.ccx.tcx, lhs_t1); - pushdown::pushdown_expr(scx, port_t, rhs); + auto port_t = ty::mk_port(fcx.ccx.tcx, lhs_t1); + pushdown::pushdown_expr(fcx, port_t, rhs); auto item_t; - auto rhs_t = expr_ty(scx.fcx.ccx.tcx, rhs); - alt (struct(scx.fcx.ccx.tcx, rhs_t)) { + auto rhs_t = expr_ty(fcx.ccx.tcx, rhs); + alt (struct(fcx.ccx.tcx, rhs_t)) { case (ty::ty_port(?it)) { item_t = it; } case (_) { fail; } } - pushdown::pushdown_expr(scx, item_t, lhs); + pushdown::pushdown_expr(fcx, item_t, lhs); - write::ty_only_fixup(scx, a.id, item_t); + write::ty_only_fixup(fcx, a.id, item_t); } case (ast::expr_if(?cond, ?thn, ?elsopt, ?a)) { - check_expr(scx, cond); - pushdown::pushdown_expr(scx, ty::mk_bool(scx.fcx.ccx.tcx), + check_expr(fcx, cond); + pushdown::pushdown_expr(fcx, ty::mk_bool(fcx.ccx.tcx), cond); - check_block(scx, thn); + check_block(fcx, thn); auto if_t = alt (elsopt) { case (some(?els)) { - check_expr(scx, els); + check_expr(fcx, els); - auto thn_t = block_ty(scx.fcx.ccx.tcx, thn); - auto elsopt_t = expr_ty(scx.fcx.ccx.tcx, els); - if (!ty::type_is_bot(scx.fcx.ccx.tcx, elsopt_t)) { + auto thn_t = block_ty(fcx.ccx.tcx, thn); + auto elsopt_t = expr_ty(fcx.ccx.tcx, els); + if (!ty::type_is_bot(fcx.ccx.tcx, elsopt_t)) { elsopt_t } else { thn_t } } case (none) { - ty::mk_nil(scx.fcx.ccx.tcx) + ty::mk_nil(fcx.ccx.tcx) } }; - write::ty_only_fixup(scx, a.id, if_t); + write::ty_only_fixup(fcx, a.id, if_t); } case (ast::expr_for(?decl, ?seq, ?body, ?a)) { - check_expr(scx, seq); - alt (struct (scx.fcx.ccx.tcx, - expr_ty(scx.fcx.ccx.tcx, seq))) { + check_expr(fcx, seq); + alt (struct (fcx.ccx.tcx, + expr_ty(fcx.ccx.tcx, seq))) { // FIXME: I include the check_for_or_each call in // each case because of a bug in typestate. // The bug is fixed; once there's a new snapshot, // the call can be moved out of the alt expression case (ty::ty_vec(?vec_elt_ty)) { auto elt_ty = vec_elt_ty.ty; - check_for_or_for_each(scx, decl, elt_ty, body, a.id); + check_for_or_for_each(fcx, decl, elt_ty, body, a.id); } case (ty::ty_str) { - auto elt_ty = ty::mk_mach(scx.fcx.ccx.tcx, + auto elt_ty = ty::mk_mach(fcx.ccx.tcx, util::common::ty_u8); - check_for_or_for_each(scx, decl, elt_ty, body, a.id); + check_for_or_for_each(fcx, decl, elt_ty, body, a.id); } case (_) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "type of for loop iterator is not a vector or string"); } } } case (ast::expr_for_each(?decl, ?seq, ?body, ?a)) { - check_expr(scx, seq); - check_for_or_for_each(scx, decl, expr_ty(scx.fcx.ccx.tcx, seq), + check_expr(fcx, seq); + check_for_or_for_each(fcx, decl, expr_ty(fcx.ccx.tcx, seq), body, a.id); } case (ast::expr_while(?cond, ?body, ?a)) { - check_expr(scx, cond); - pushdown::pushdown_expr(scx, ty::mk_bool(scx.fcx.ccx.tcx), cond); - check_block(scx, body); + check_expr(fcx, cond); + pushdown::pushdown_expr(fcx, ty::mk_bool(fcx.ccx.tcx), cond); + check_block(fcx, body); - auto typ = ty::mk_nil(scx.fcx.ccx.tcx); - write::ty_only_fixup(scx, a.id, typ); + auto typ = ty::mk_nil(fcx.ccx.tcx); + write::ty_only_fixup(fcx, a.id, typ); } case (ast::expr_do_while(?body, ?cond, ?a)) { - check_expr(scx, cond); - pushdown::pushdown_expr(scx, ty::mk_bool(scx.fcx.ccx.tcx), cond); - check_block(scx, body); + check_expr(fcx, cond); + pushdown::pushdown_expr(fcx, ty::mk_bool(fcx.ccx.tcx), cond); + check_block(fcx, body); - auto typ = block_ty(scx.fcx.ccx.tcx, body); - write::ty_only_fixup(scx, a.id, typ); + auto typ = block_ty(fcx.ccx.tcx, body); + write::ty_only_fixup(fcx, a.id, typ); } case (ast::expr_alt(?expr, ?arms, ?a)) { - check_expr(scx, expr); + check_expr(fcx, expr); // Typecheck the patterns first, so that we get types for all the // bindings. - auto pattern_ty = ty::expr_ty(scx.fcx.ccx.tcx, expr); + auto pattern_ty = ty::expr_ty(fcx.ccx.tcx, expr); let vec[@ast::pat] pats = []; for (ast::arm arm in arms) { - check_pat(scx, arm.pat, pattern_ty); + check_pat(fcx, arm.pat, pattern_ty); pats += [arm.pat]; } // Now typecheck the blocks. - auto result_ty = next_ty_var(scx); + auto result_ty = next_ty_var(fcx); let vec[ast::block] blocks = []; for (ast::arm arm in arms) { - check_block(scx, arm.block); + check_block(fcx, arm.block); - auto bty = block_ty(scx.fcx.ccx.tcx, arm.block); + auto bty = block_ty(fcx.ccx.tcx, arm.block); // Failing alt arms don't need to have a matching type - if (!ty::type_is_bot(scx.fcx.ccx.tcx, bty)) { - result_ty = demand::simple(scx, arm.block.span, + if (!ty::type_is_bot(fcx.ccx.tcx, bty)) { + result_ty = demand::simple(fcx, arm.block.span, result_ty, bty); } } auto i = 0u; for (ast::block bloc in blocks) { - pushdown::pushdown_block(scx, result_ty, bloc); + pushdown::pushdown_block(fcx, result_ty, bloc); } - pushdown::pushdown_expr(scx, pattern_ty, expr); + pushdown::pushdown_expr(fcx, pattern_ty, expr); - write::ty_only_fixup(scx, a.id, result_ty); + write::ty_only_fixup(fcx, a.id, result_ty); } case (ast::expr_block(?b, ?a)) { - check_block(scx, b); + check_block(fcx, b); alt (b.node.expr) { case (some(?expr)) { - auto typ = expr_ty(scx.fcx.ccx.tcx, expr); - write::ty_only_fixup(scx, a.id, typ); + auto typ = expr_ty(fcx.ccx.tcx, expr); + write::ty_only_fixup(fcx, a.id, typ); } case (none) { - auto typ = ty::mk_nil(scx.fcx.ccx.tcx); - write::ty_only_fixup(scx, a.id, typ); + auto typ = ty::mk_nil(fcx.ccx.tcx); + write::ty_only_fixup(fcx, a.id, typ); } } } case (ast::expr_bind(?f, ?args, ?a)) { // Call the generic checker. - check_call_or_bind(scx, f, args); + check_call_or_bind(fcx, f, args); // Pull the argument and return types out. auto proto_1; let vec[ty::arg] arg_tys_1 = []; auto rt_1; - auto fty = expr_ty(scx.fcx.ccx.tcx, f); + auto fty = expr_ty(fcx.ccx.tcx, f); auto t_1; - alt (struct(scx.fcx.ccx.tcx, fty)) { + alt (struct(fcx.ccx.tcx, fty)) { case (ty::ty_fn(?proto, ?arg_tys, ?rt, ?cf)) { proto_1 = proto; rt_1 = rt; @@ -2239,7 +2297,7 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { } i += 1u; } - t_1 = ty::mk_fn(scx.fcx.ccx.tcx, proto_1, arg_tys_1, rt_1, + t_1 = ty::mk_fn(fcx.ccx.tcx, proto_1, arg_tys_1, rt_1, cf); } case (_) { @@ -2247,7 +2305,7 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { fail; } } - write::ty_only_fixup(scx, a.id, t_1); + write::ty_only_fixup(fcx, a.id, t_1); } case (ast::expr_call(?f, ?args, ?a)) { @@ -2255,14 +2313,14 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { need to restrict it to being an explicit expr_path if we're inside a pure function, and need an environment mapping from function name onto purity-designation */ - require_pure_call(scx.fcx.ccx, scx.fcx.purity, f, expr.span); + require_pure_call(fcx.ccx, fcx.purity, f, expr.span); - check_call(scx, f, args); + check_call(fcx, f, args); // Pull the return type out of the type of the function. - auto rt_1 = ty::mk_nil(scx.fcx.ccx.tcx); // FIXME: typestate botch - auto fty = expr_ty(scx.fcx.ccx.tcx, f); - alt (struct(scx.fcx.ccx.tcx, fty)) { + auto rt_1 = ty::mk_nil(fcx.ccx.tcx); // FIXME: typestate botch + auto fty = ty::expr_ty(fcx.ccx.tcx, f); + alt (struct(fcx.ccx.tcx, fty)) { case (ty::ty_fn(_,_,?rt,_)) { rt_1 = rt; } case (ty::ty_native_fn(_, _, ?rt)) { rt_1 = rt; } case (_) { @@ -2271,14 +2329,14 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { } } - write::ty_only_fixup(scx, a.id, rt_1); + write::ty_only_fixup(fcx, a.id, rt_1); } case (ast::expr_self_method(?id, ?a)) { - auto t = ty::mk_nil(scx.fcx.ccx.tcx); + auto t = ty::mk_nil(fcx.ccx.tcx); let ty::t this_obj_ty; - let option::t[obj_info] this_obj_info = get_obj_info(scx.fcx.ccx); + let option::t[obj_info] this_obj_info = get_obj_info(fcx.ccx); alt (this_obj_info) { // If we're inside a current object, grab its type. @@ -2286,7 +2344,7 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { // FIXME: In the case of anonymous objects with methods // containing self-calls, this lookup fails because // obj_info.this_obj is not in the type cache - this_obj_ty = ty::lookup_item_type(scx.fcx.ccx.tcx, + this_obj_ty = ty::lookup_item_type(fcx.ccx.tcx, obj_info.this_obj)._1; } @@ -2294,11 +2352,11 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { } // Grab this method's type out of the current object type. - alt (struct(scx.fcx.ccx.tcx, this_obj_ty)) { + alt (struct(fcx.ccx.tcx, this_obj_ty)) { case (ty::ty_obj(?methods)) { for (ty::method method in methods) { if (method.ident == id) { - t = ty::method_ty_to_fn_ty(scx.fcx.ccx.tcx, + t = ty::method_ty_to_fn_ty(fcx.ccx.tcx, method); } } @@ -2306,86 +2364,86 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { case (_) { fail; } } - write::ty_only_fixup(scx, a.id, t); + write::ty_only_fixup(fcx, a.id, t); - require_impure(scx.fcx.ccx.tcx.sess, scx.fcx.purity, expr.span); + require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); } case (ast::expr_spawn(_, _, ?f, ?args, ?a)) { - check_call(scx, f, args); + check_call(fcx, f, args); - auto fty = expr_ty(scx.fcx.ccx.tcx, f); - auto ret_ty = ty::ret_ty_of_fn_ty(scx.fcx.ccx.tcx, fty); + auto fty = expr_ty(fcx.ccx.tcx, f); + auto ret_ty = ty::ret_ty_of_fn_ty(fcx.ccx.tcx, fty); - demand::simple(scx, f.span, ty::mk_nil(scx.fcx.ccx.tcx), ret_ty); + demand::simple(fcx, f.span, ty::mk_nil(fcx.ccx.tcx), ret_ty); // FIXME: Other typechecks needed - auto typ = ty::mk_task(scx.fcx.ccx.tcx); - write::ty_only_fixup(scx, a.id, typ); + auto typ = ty::mk_task(fcx.ccx.tcx); + write::ty_only_fixup(fcx, a.id, typ); } case (ast::expr_cast(?e, ?t, ?a)) { - check_expr(scx, e); - auto t_1 = ast_ty_to_ty_crate(scx.fcx.ccx, t); + check_expr(fcx, e); + auto t_1 = ast_ty_to_ty_crate(fcx.ccx, t); // FIXME: there are more forms of cast to support, eventually. - if (! (type_is_scalar(scx.fcx.ccx.tcx, - expr_ty(scx.fcx.ccx.tcx, e)) && - type_is_scalar(scx.fcx.ccx.tcx, t_1))) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + if (! (type_is_scalar(fcx.ccx.tcx, + expr_ty(fcx.ccx.tcx, e)) && + type_is_scalar(fcx.ccx.tcx, t_1))) { + fcx.ccx.tcx.sess.span_err(expr.span, "non-scalar cast: " + - ty_to_str(scx.fcx.ccx.tcx, - expr_ty(scx.fcx.ccx.tcx, e)) + - " as " + ty_to_str(scx.fcx.ccx.tcx, t_1)); + ty_to_str(fcx.ccx.tcx, + expr_ty(fcx.ccx.tcx, e)) + + " as " + ty_to_str(fcx.ccx.tcx, t_1)); } - write::ty_only_fixup(scx, a.id, t_1); + write::ty_only_fixup(fcx, a.id, t_1); } case (ast::expr_vec(?args, ?mut, ?a)) { let ty::t t; if (vec::len[@ast::expr](args) == 0u) { - t = next_ty_var(scx); + t = next_ty_var(fcx); } else { - check_expr(scx, args.(0)); - t = expr_ty(scx.fcx.ccx.tcx, args.(0)); + check_expr(fcx, args.(0)); + t = expr_ty(fcx.ccx.tcx, args.(0)); } for (@ast::expr e in args) { - check_expr(scx, e); - auto expr_t = expr_ty(scx.fcx.ccx.tcx, e); - demand::simple(scx, expr.span, t, expr_t); + check_expr(fcx, e); + auto expr_t = expr_ty(fcx.ccx.tcx, e); + demand::simple(fcx, expr.span, t, expr_t); } - auto typ = ty::mk_vec(scx.fcx.ccx.tcx, rec(ty=t, mut=mut)); - write::ty_only_fixup(scx, a.id, typ); + auto typ = ty::mk_vec(fcx.ccx.tcx, rec(ty=t, mut=mut)); + write::ty_only_fixup(fcx, a.id, typ); } case (ast::expr_tup(?elts, ?a)) { let vec[ty::mt] elts_mt = []; for (ast::elt e in elts) { - check_expr(scx, e.expr); - auto ety = expr_ty(scx.fcx.ccx.tcx, e.expr); + check_expr(fcx, e.expr); + auto ety = expr_ty(fcx.ccx.tcx, e.expr); elts_mt += [rec(ty=ety, mut=e.mut)]; } - auto typ = ty::mk_tup(scx.fcx.ccx.tcx, elts_mt); - write::ty_only_fixup(scx, a.id, typ); + auto typ = ty::mk_tup(fcx.ccx.tcx, elts_mt); + write::ty_only_fixup(fcx, a.id, typ); } case (ast::expr_rec(?fields, ?base, ?a)) { alt (base) { case (none) { /* no-op */} - case (some(?b_0)) { check_expr(scx, b_0); } + case (some(?b_0)) { check_expr(fcx, b_0); } } let vec[field] fields_t = []; for (ast::field f in fields) { - check_expr(scx, f.node.expr); - auto expr_t = expr_ty(scx.fcx.ccx.tcx, f.node.expr); + check_expr(fcx, f.node.expr); + auto expr_t = expr_ty(fcx.ccx.tcx, f.node.expr); auto expr_mt = rec(ty=expr_t, mut=f.node.mut); vec::push[field](fields_t, rec(ident=f.node.ident, @@ -2394,38 +2452,38 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { alt (base) { case (none) { - auto typ = ty::mk_rec(scx.fcx.ccx.tcx, fields_t); - write::ty_only_fixup(scx, a.id, typ); + auto typ = ty::mk_rec(fcx.ccx.tcx, fields_t); + write::ty_only_fixup(fcx, a.id, typ); } case (some(?bexpr)) { - check_expr(scx, bexpr); - auto bexpr_t = expr_ty(scx.fcx.ccx.tcx, bexpr); + check_expr(fcx, bexpr); + auto bexpr_t = expr_ty(fcx.ccx.tcx, bexpr); let vec[field] base_fields = []; - alt (struct(scx.fcx.ccx.tcx, bexpr_t)) { + alt (struct(fcx.ccx.tcx, bexpr_t)) { case (ty::ty_rec(?flds)) { base_fields = flds; } case (_) { - scx.fcx.ccx.tcx.sess.span_err + fcx.ccx.tcx.sess.span_err (expr.span, "record update non-record base"); } } - write::ty_only_fixup(scx, a.id, bexpr_t); + write::ty_only_fixup(fcx, a.id, bexpr_t); for (ty::field f in fields_t) { auto found = false; for (ty::field bf in base_fields) { if (str::eq(f.ident, bf.ident)) { - demand::simple(scx, expr.span, f.mt.ty, + demand::simple(fcx, expr.span, f.mt.ty, bf.mt.ty); found = true; } } if (!found) { - scx.fcx.ccx.tcx.sess.span_err + fcx.ccx.tcx.sess.span_err (expr.span, "unknown field in record update: " + f.ident); @@ -2436,106 +2494,108 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { } case (ast::expr_field(?base, ?field, ?a)) { - check_expr(scx, base); - auto base_t = expr_ty(scx.fcx.ccx.tcx, base); - base_t = strip_boxes(scx.fcx.ccx.tcx, base_t); - alt (struct(scx.fcx.ccx.tcx, base_t)) { + check_expr(fcx, base); + auto base_t = expr_ty(fcx.ccx.tcx, base); + base_t = strip_boxes(fcx.ccx.tcx, base_t); + base_t = ty::unify::resolve_all_vars(fcx.ccx.tcx, + fcx.var_bindings, base_t); + alt (struct(fcx.ccx.tcx, base_t)) { case (ty::ty_tup(?args)) { - let uint ix = ty::field_num(scx.fcx.ccx.tcx.sess, + let uint ix = ty::field_num(fcx.ccx.tcx.sess, expr.span, field); if (ix >= vec::len[ty::mt](args)) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "bad index on tuple"); } - write::ty_only_fixup(scx, a.id, args.(ix).ty); + write::ty_only_fixup(fcx, a.id, args.(ix).ty); } case (ty::ty_rec(?fields)) { - let uint ix = ty::field_idx(scx.fcx.ccx.tcx.sess, + let uint ix = ty::field_idx(fcx.ccx.tcx.sess, expr.span, field, fields); if (ix >= vec::len[ty::field](fields)) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "bad index on record"); } - write::ty_only_fixup(scx, a.id, fields.(ix).mt.ty); + write::ty_only_fixup(fcx, a.id, fields.(ix).mt.ty); } case (ty::ty_obj(?methods)) { - let uint ix = ty::method_idx(scx.fcx.ccx.tcx.sess, + let uint ix = ty::method_idx(fcx.ccx.tcx.sess, expr.span, field, methods); if (ix >= vec::len[ty::method](methods)) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "bad index on obj"); } auto meth = methods.(ix); - auto t = ty::mk_fn(scx.fcx.ccx.tcx, meth.proto, + auto t = ty::mk_fn(fcx.ccx.tcx, meth.proto, meth.inputs, meth.output, meth.cf); - write::ty_only_fixup(scx, a.id, t); + write::ty_only_fixup(fcx, a.id, t); } case (_) { - scx.fcx.ccx.tcx.sess.span_unimpl(expr.span, + fcx.ccx.tcx.sess.span_unimpl(expr.span, "base type for expr_field in typeck::check_expr: " + - ty_to_str(scx.fcx.ccx.tcx, base_t)); + ty_to_str(fcx.ccx.tcx, base_t)); } } } case (ast::expr_index(?base, ?idx, ?a)) { - check_expr(scx, base); - auto base_t = expr_ty(scx.fcx.ccx.tcx, base); - base_t = strip_boxes(scx.fcx.ccx.tcx, base_t); + check_expr(fcx, base); + auto base_t = expr_ty(fcx.ccx.tcx, base); + base_t = strip_boxes(fcx.ccx.tcx, base_t); - check_expr(scx, idx); - auto idx_t = expr_ty(scx.fcx.ccx.tcx, idx); - alt (struct(scx.fcx.ccx.tcx, base_t)) { + check_expr(fcx, idx); + auto idx_t = expr_ty(fcx.ccx.tcx, idx); + alt (struct(fcx.ccx.tcx, base_t)) { case (ty::ty_vec(?mt)) { - if (! type_is_integral(scx.fcx.ccx.tcx, idx_t)) { - scx.fcx.ccx.tcx.sess.span_err + if (! type_is_integral(fcx.ccx.tcx, idx_t)) { + fcx.ccx.tcx.sess.span_err (idx.span, "non-integral type of vec index: " - + ty_to_str(scx.fcx.ccx.tcx, idx_t)); + + ty_to_str(fcx.ccx.tcx, idx_t)); } - write::ty_only_fixup(scx, a.id, mt.ty); + write::ty_only_fixup(fcx, a.id, mt.ty); } case (ty::ty_str) { - if (! type_is_integral(scx.fcx.ccx.tcx, idx_t)) { - scx.fcx.ccx.tcx.sess.span_err + if (! type_is_integral(fcx.ccx.tcx, idx_t)) { + fcx.ccx.tcx.sess.span_err (idx.span, "non-integral type of str index: " - + ty_to_str(scx.fcx.ccx.tcx, idx_t)); + + ty_to_str(fcx.ccx.tcx, idx_t)); } - auto typ = ty::mk_mach(scx.fcx.ccx.tcx, common::ty_u8); - write::ty_only_fixup(scx, a.id, typ); + auto typ = ty::mk_mach(fcx.ccx.tcx, common::ty_u8); + write::ty_only_fixup(fcx, a.id, typ); } case (_) { - scx.fcx.ccx.tcx.sess.span_err + fcx.ccx.tcx.sess.span_err (expr.span, "vector-indexing bad type: " - + ty_to_str(scx.fcx.ccx.tcx, base_t)); + + ty_to_str(fcx.ccx.tcx, base_t)); } } } case (ast::expr_port(?a)) { - auto t = next_ty_var(scx); - auto pt = ty::mk_port(scx.fcx.ccx.tcx, t); - write::ty_only_fixup(scx, a.id, pt); + auto t = next_ty_var(fcx); + auto pt = ty::mk_port(fcx.ccx.tcx, t); + write::ty_only_fixup(fcx, a.id, pt); } case (ast::expr_chan(?x, ?a)) { - check_expr(scx, x); - auto port_t = expr_ty(scx.fcx.ccx.tcx, x); - alt (struct(scx.fcx.ccx.tcx, port_t)) { + check_expr(fcx, x); + auto port_t = expr_ty(fcx.ccx.tcx, x); + alt (struct(fcx.ccx.tcx, port_t)) { case (ty::ty_port(?subtype)) { - auto ct = ty::mk_chan(scx.fcx.ccx.tcx, subtype); - write::ty_only_fixup(scx, a.id, ct); + auto ct = ty::mk_chan(fcx.ccx.tcx, subtype); + write::ty_only_fixup(fcx, a.id, ct); } case (_) { - scx.fcx.ccx.tcx.sess.span_err(expr.span, + fcx.ccx.tcx.sess.span_err(expr.span, "bad port type: " + - ty_to_str(scx.fcx.ccx.tcx, port_t)); + ty_to_str(fcx.ccx.tcx, port_t)); } } } @@ -2552,7 +2612,7 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { } let ast::def_id di = obj_def_ids.ty; - vec::push[obj_info](scx.fcx.ccx.obj_infos, + vec::push[obj_info](fcx.ccx.obj_infos, rec(obj_fields=fields, this_obj=di)); // Typecheck 'with_obj', if it exists. @@ -2563,16 +2623,16 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { // This had better have object type. TOOD: report an // error if the user is trying to extend a non-object // with_obj. - check_expr(scx, e); + check_expr(fcx, e); } } // Typecheck the methods. for (@ast::method method in anon_obj.methods) { - check_method(scx.fcx.ccx, method); + check_method(fcx.ccx, method); } - auto t = next_ty_var(scx); + auto t = next_ty_var(fcx); // FIXME: These next three functions are largely ripped off from @@ -2600,46 +2660,50 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) { anon_obj.methods); } - auto methods = get_anon_obj_method_types(scx.fcx.ccx, anon_obj); - auto ot = ty::mk_obj(scx.fcx.ccx.tcx, + auto methods = get_anon_obj_method_types(fcx.ccx, anon_obj); + auto ot = ty::mk_obj(fcx.ccx.tcx, ty::sort_methods(methods)); - write::ty_only_fixup(scx, a.id, ot); + write::ty_only_fixup(fcx, a.id, ot); // Now remove the info from the stack. - vec::pop[obj_info](scx.fcx.ccx.obj_infos); + vec::pop[obj_info](fcx.ccx.obj_infos); } case (_) { - scx.fcx.ccx.tcx.sess.unimpl("expr type in typeck::check_expr"); + fcx.ccx.tcx.sess.unimpl("expr type in typeck::check_expr"); } } } -fn next_ty_var(&@stmt_ctxt scx) -> ty::t { - auto t = ty::mk_var(scx.fcx.ccx.tcx, scx.next_var_id); - scx.next_var_id += 1; - ret t; +fn next_ty_var_id(@fn_ctxt fcx) -> int { + auto id = fcx.next_var_id; + fcx.next_var_id += 1; + ret id; +} + +fn next_ty_var(&@fn_ctxt fcx) -> ty::t { + ret ty::mk_var(fcx.ccx.tcx, next_ty_var_id(fcx)); } fn get_obj_info(&@crate_ctxt ccx) -> option::t[obj_info] { ret vec::last[obj_info](ccx.obj_infos); } -fn check_decl_initializer(&@stmt_ctxt scx, &ast::def_id lid, +fn check_decl_initializer(&@fn_ctxt fcx, &ast::def_id lid, &ast::initializer init) { - check_expr(scx, init.expr); + check_expr(fcx, init.expr); - auto lty = ty::mk_local(scx.fcx.ccx.tcx, lid); + auto lty = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(lid)); alt (init.op) { case (ast::init_assign) { - pushdown::pushdown_expr(scx, lty, init.expr); + pushdown::pushdown_expr(fcx, lty, init.expr); } case (ast::init_move) { - pushdown::pushdown_expr(scx, lty, init.expr); + pushdown::pushdown_expr(fcx, lty, init.expr); } case (ast::init_recv) { - auto port_ty = ty::mk_port(scx.fcx.ccx.tcx, lty); - pushdown::pushdown_expr(scx, port_ty, init.expr); + auto port_ty = ty::mk_port(fcx.ccx.tcx, lty); + pushdown::pushdown_expr(fcx, port_ty, init.expr); } } } @@ -2647,41 +2711,27 @@ fn check_decl_initializer(&@stmt_ctxt scx, &ast::def_id lid, fn check_decl_local(&@fn_ctxt fcx, &@ast::decl decl) -> @ast::decl { alt (decl.node) { case (ast::decl_local(?local)) { - auto t = ty::mk_nil(fcx.ccx.tcx); - - alt (local.ty) { - case (none) { - // Auto slot. Do nothing for now. - } - - case (some(?ast_ty)) { - auto local_ty = ast_ty_to_ty_crate(fcx.ccx, ast_ty); - fcx.locals.insert(local.id, local_ty); - t = local_ty; - } - } - auto a_res = local.ann; - write::ty_only(fcx.ccx.tcx, a_res.id, t); + auto t = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(local.id)); + write::ty_only_fixup(fcx, a_res.id, t); auto initopt = local.init; alt (local.init) { case (some(?init)) { - with_stmt_ctxt(fcx, - bind check_decl_initializer(_, local.id, init)); + check_decl_initializer(fcx, local.id, init); } case (_) { /* fall through */ } } - auto local_1 = @rec(init = initopt, ann = a_res with *local); + auto local_1 = @rec(init=initopt, ann=a_res with *local); ret @rec(node=ast::decl_local(local_1) with *decl); } } } -fn check_and_pushdown_expr(&@stmt_ctxt scx, &@ast::expr expr) { - check_expr(scx, expr); - auto ety = expr_ty(scx.fcx.ccx.tcx, expr); - pushdown::pushdown_expr(scx, ety, expr); +fn check_and_pushdown_expr(&@fn_ctxt fcx, &@ast::expr expr) { + check_expr(fcx, expr); + auto ety = expr_ty(fcx.ccx.tcx, expr); + pushdown::pushdown_expr(fcx, ety, expr); } fn check_stmt(&@fn_ctxt fcx, &@ast::stmt stmt) { @@ -2696,25 +2746,25 @@ fn check_stmt(&@fn_ctxt fcx, &@ast::stmt stmt) { } case (ast::stmt_expr(?expr,?a)) { node_id = a.id; - with_stmt_ctxt(fcx, bind check_and_pushdown_expr(_, expr)); + check_and_pushdown_expr(fcx, expr); } } write::nil_ty(fcx.ccx.tcx, node_id); } -fn check_block(&@stmt_ctxt scx, &ast::block block) { - for (@ast::stmt s in block.node.stmts) { check_stmt(scx.fcx, s); } +fn check_block(&@fn_ctxt fcx, &ast::block block) { + for (@ast::stmt s in block.node.stmts) { check_stmt(fcx, s); } alt (block.node.expr) { case (none) { - write::nil_ty(scx.fcx.ccx.tcx, block.node.a.id); + write::nil_ty(fcx.ccx.tcx, block.node.a.id); } case (some(?e)) { - check_expr(scx, e); - auto ety = expr_ty(scx.fcx.ccx.tcx, e); - pushdown::pushdown_expr(scx, ety, e); - write::ty_only_fixup(scx, block.node.a.id, ety); + check_expr(fcx, e); + auto ety = expr_ty(fcx.ccx.tcx, e); + pushdown::pushdown_expr(fcx, ety, e); + write::ty_only_fixup(fcx, block.node.a.id, ety); } } @@ -2724,45 +2774,35 @@ fn check_const(&@crate_ctxt ccx, &span sp, &@ast::expr e, &ast::ann ann) { // FIXME: this is kinda a kludge; we manufacture a fake function context // and statement context for checking the initializer expression. auto rty = ann_to_type(ccx.tcx, ann); - let @fn_ctxt fcx = @rec(ret_ty = rty, - purity = ast::pure_fn, - locals = @common::new_def_hash[ty::t](), - ccx = ccx); - - with_stmt_ctxt(fcx, bind check_and_pushdown_expr(_, e)); + let vec[uint] fixups = []; + let @fn_ctxt fcx = @rec(ret_ty=rty, + purity=ast::pure_fn, + var_bindings=ty::unify::mk_var_bindings(), + locals=new_def_hash[int](), + local_names=new_def_hash[ast::ident](), + mutable next_var_id=0, + mutable fixups=fixups, + ccx=ccx); + + check_and_pushdown_expr(fcx, e); } fn check_fn(&@crate_ctxt ccx, &ast::fn_decl decl, ast::proto proto, - &ast::block body) { - auto local_ty_table = @common::new_def_hash[ty::t](); + &ast::block body, &ast::ann ann) { + auto gather_result = gather_locals(ccx, decl, body, ann); - // FIXME: duplicate work: the item annotation already has the arg types - // and return type translated to typeck::ty values. We don't need do to it - // again here, we can extract them. - - alt (get_obj_info(ccx)) { - case (option::some(?oinfo)) { - for (ast::obj_field f in oinfo.obj_fields) { - auto field_ty = ty::ann_to_type(ccx.tcx, f.ann); - local_ty_table.insert(f.id, field_ty); - } - } - case (option::none) { /* no fields */ } - } - - // Store the type of each argument in the table. - for (ast::arg arg in decl.inputs) { - auto input_ty = ast_ty_to_ty_crate(ccx, arg.ty); - local_ty_table.insert(arg.id, input_ty); - } - - let @fn_ctxt fcx = @rec(ret_ty = ast_ty_to_ty_crate(ccx, decl.output), - purity = decl.purity, - locals = local_ty_table, - ccx = ccx); + let vec[uint] fixups = []; + let @fn_ctxt fcx = @rec(ret_ty=ast_ty_to_ty_crate(ccx, decl.output), + purity=decl.purity, + var_bindings=gather_result.var_bindings, + locals=gather_result.locals, + local_names=gather_result.local_names, + mutable next_var_id=gather_result.next_var_id, + mutable fixups=fixups, + ccx=ccx); // TODO: Make sure the type of the block agrees with the function type. - with_stmt_ctxt(fcx, bind check_block(_, body)); + check_block(fcx, body); alt (decl.purity) { case (ast::pure_fn) { @@ -2776,12 +2816,12 @@ fn check_fn(&@crate_ctxt ccx, &ast::fn_decl decl, ast::proto proto, case (_) {} } - writeback::resolve_local_types_in_block(fcx, body); + writeback::resolve_type_vars_in_block(fcx, body); } fn check_method(&@crate_ctxt ccx, &@ast::method method) { - check_fn(ccx, method.node.meth.decl, method.node.meth.proto, - method.node.meth.body); + auto m = method.node.meth; + check_fn(ccx, m.decl, m.proto, m.body, method.node.ann); } fn check_item(@crate_ctxt ccx, &@ast::item it) { @@ -2789,8 +2829,8 @@ fn check_item(@crate_ctxt ccx, &@ast::item it) { case (ast::item_const(_, _, ?e, _, ?a)) { check_const(ccx, it.span, e, a); } - case (ast::item_fn(_, ?f, _, _, _)) { - check_fn(ccx, f.decl, f.proto, f.body); + case (ast::item_fn(_, ?f, _, _, ?a)) { + check_fn(ccx, f.decl, f.proto, f.body, a); } case (ast::item_obj(_, ?ob, _, ?obj_def_ids, _)) { // We're entering an object, so gather up the info we need. diff --git a/src/lib/smallintmap.rs b/src/lib/smallintmap.rs index ca586eb6f05e6..49e9efa20f4c5 100644 --- a/src/lib/smallintmap.rs +++ b/src/lib/smallintmap.rs @@ -38,3 +38,7 @@ fn truncate[T](&smallintmap[T] m, uint len) { m.v = vec::slice_mut[option::t[T]](m.v, 0u, len); } +fn max_key[T](&smallintmap[T] m) -> uint { + ret vec::len[option::t[T]](m.v); +} + diff --git a/src/lib/ufind.rs b/src/lib/ufind.rs index 7dfa861c6ed30..275efd813e487 100644 --- a/src/lib/ufind.rs +++ b/src/lib/ufind.rs @@ -20,6 +20,12 @@ fn make_set(&ufind ufnd) -> uint { ret idx; } +/// Creates sets as necessary to ensure that least `n` sets are present in the +/// data structure. +fn grow(&ufind ufnd, uint n) { + while (set_count(ufnd) < n) { make_set(ufnd); } +} + fn find(&ufind ufnd, uint n) -> uint { alt (ufnd.nodes.(n)) { case (none) { ret n; } @@ -37,12 +43,17 @@ fn union(&ufind ufnd, uint m, uint n) { } } +fn set_count(&ufind ufnd) -> uint { + ret vec::len[node](ufnd.nodes); +} + // Removes all sets with IDs greater than or equal to the given value. fn prune(&ufind ufnd, uint n) { // TODO: Use "slice" once we get rid of "mutable?" - while (n != 0u) { + auto len = vec::len[node](ufnd.nodes); + while (len != n) { vec::pop[node](ufnd.nodes); - n -= 1u; + len -= 1u; } } diff --git a/src/lib/uint.rs b/src/lib/uint.rs index 044eeff4fc4d4..c5aeb49d80b72 100644 --- a/src/lib/uint.rs +++ b/src/lib/uint.rs @@ -12,6 +12,11 @@ fn ne(uint x, uint y) -> bool { ret x != y; } fn ge(uint x, uint y) -> bool { ret x >= y; } fn gt(uint x, uint y) -> bool { ret x > y; } +fn max(uint x, uint y) -> uint { + if (x > y) { ret x; } + ret y; +} + iter range(uint lo, uint hi) -> uint { auto lo_ = lo; while (lo_ < hi) { diff --git a/src/lib/vec.rs b/src/lib/vec.rs index 374b55ed9be36..2f82f330446eb 100644 --- a/src/lib/vec.rs +++ b/src/lib/vec.rs @@ -210,7 +210,7 @@ fn unshift[T](&mutable array[T] v, &T t) { v = res; } -fn grow[T](&array[T] v, uint n, &T initval) { +fn grow[T](&mutable array[T] v, uint n, &T initval) { let uint i = n; while (i > 0u) { i -= 1u; @@ -218,7 +218,7 @@ fn grow[T](&array[T] v, uint n, &T initval) { } } -fn grow_set[T](&vec[mutable T] v, uint index, &T initval, &T val) { +fn grow_set[T](&mutable vec[mutable T] v, uint index, &T initval, &T val) { auto length = vec::len(v); if (index >= length) { grow(v, index - length + 1u, initval); @@ -393,6 +393,12 @@ fn reversed[T](vec[T] v) -> vec[T] { ret res; } +/// Truncates the vector to length `new_len`. +/// FIXME: This relies on a typechecker bug (covariance vs. invariance). +fn truncate[T](&mutable vec[mutable? T] v, uint new_len) { + v = slice[T](v, 0u, new_len); +} + // Local Variables: // mode: rust; // fill-column: 78; diff --git a/src/test/compile-fail/ext-nonexistent.rs b/src/test/compile-fail/ext-nonexistent.rs index e068bb3c4a4d6..9a7591ab7cebd 100644 --- a/src/test/compile-fail/ext-nonexistent.rs +++ b/src/test/compile-fail/ext-nonexistent.rs @@ -1,5 +1,4 @@ - // error-pattern:unknown syntax expander fn main() { #iamnotanextensionthatexists(""); -} \ No newline at end of file +} From 2200d6e8f674f1ec5c630f9d7e87dfb444f11ac5 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 7 Jun 2011 23:03:41 -0700 Subject: [PATCH 43/64] rustc: Print out a real error message on unresolved types. Puts out burning tinderbox. --- src/comp/middle/ty.rs | 41 +++++++++++++++----------- src/comp/middle/typeck.rs | 21 ++++++++----- src/test/compile-fail/vector-no-ann.rs | 2 +- 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 53b3c8fce077b..3d0c612a085c4 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -2537,17 +2537,24 @@ mod unify { // Fixups and substitutions fn fixup_vars(ty_ctxt tcx, @var_bindings vb, t typ) -> fixup_result { - fn subst_vars(ty_ctxt tcx, @var_bindings vb, t typ) -> t { + fn subst_vars(ty_ctxt tcx, @var_bindings vb, + @mutable option::t[int] unresolved, t typ) -> t { alt (struct(tcx, typ)) { case (ty::ty_var(?vid)) { + if ((vid as uint) >= ufind::set_count(vb.sets)) { + *unresolved = some[int](vid); + ret typ; + } + auto root_id = ufind::find(vb.sets, vid as uint); alt (smallintmap::find[t](vb.types, root_id)) { case (none[t]) { - log_err "unresolved type variable"; - fail; + *unresolved = some[int](vid); + ret typ; } case (some[t](?rt)) { - ret fold_ty(tcx, bind subst_vars(tcx, vb, _), rt); + ret fold_ty(tcx, + bind subst_vars(tcx, vb, unresolved, _), rt); } } } @@ -2555,24 +2562,22 @@ mod unify { } } - // FIXME: Report errors better. - ret fix_ok(fold_ty(tcx, bind subst_vars(tcx, vb, _), typ)); + auto unresolved = @mutable none[int]; + auto rty = fold_ty(tcx, bind subst_vars(tcx, vb, unresolved, _), typ); + + auto ur = *unresolved; + alt (ur) { + case (none[int]) { ret fix_ok(rty); } + case (some[int](?var_id)) { ret fix_err(var_id); } + } } - fn resolve_type_var(&ty_ctxt tcx, &@var_bindings vb, int vid) -> t { + fn resolve_type_var(&ty_ctxt tcx, &@var_bindings vb, int vid) + -> fixup_result { auto root_id = ufind::find(vb.sets, vid as uint); alt (smallintmap::find[t](vb.types, root_id)) { - case (none[t]) { ret mk_var(tcx, vid); } - case (some[t](?rt)) { - alt (fixup_vars(tcx, vb, rt)) { - case (fix_ok(?rty)) { ret rty; } - case (fix_err(_)) { - // TODO: antisocial - log_err "failed to resolve type var"; - fail; - } - } - } + case (none[t]) { ret fix_ok(mk_var(tcx, vid)); } + case (some[t](?rt)) { ret fixup_vars(tcx, vb, rt); } } } } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index d604ad9a39062..db3f3ede0c701 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1387,11 +1387,8 @@ mod writeback { alt (ty::unify::fixup_vars(fcx.ccx.tcx, fcx.var_bindings, typ)) { case (fix_ok(?new_type)) { ret new_type; } case (fix_err(?vid)) { - // TODO: We should try to do a variable ID -> local lookup if - // we can and display this in terms of the local that had an - // incomplete type. - fcx.ccx.tcx.sess.span_err(sp, #fmt( - "cannot determine type of variable ID `%d`", vid)); + fcx.ccx.tcx.sess.span_err(sp, + "cannot determine a type for this expression"); } } } @@ -1434,11 +1431,19 @@ mod writeback { fn visit_decl_pre(@fn_ctxt fcx, &@ast::decl d) { alt (d.node) { case (ast::decl_local(?l)) { - // FIXME: Report errors better. auto var_id = fcx.locals.get(l.id); - auto lty = ty::unify::resolve_type_var(fcx.ccx.tcx, + auto fix_rslt = ty::unify::resolve_type_var(fcx.ccx.tcx, fcx.var_bindings, var_id); - write::ty_only(fcx.ccx.tcx, l.ann.id, lty); + alt (fix_rslt) { + case (fix_ok(?lty)) { + write::ty_only(fcx.ccx.tcx, l.ann.id, lty); + } + case (fix_err(_)) { + fcx.ccx.tcx.sess.span_err(d.span, + "cannot determine a type for this local " + + "variable"); + } + } } case (_) { /* no-op */ } } diff --git a/src/test/compile-fail/vector-no-ann.rs b/src/test/compile-fail/vector-no-ann.rs index 912fb0a388ace..b492f103c2034 100644 --- a/src/test/compile-fail/vector-no-ann.rs +++ b/src/test/compile-fail/vector-no-ann.rs @@ -1,6 +1,6 @@ // xfail-stage0 -// error-pattern:Ambiguous type +// error-pattern:cannot determine a type fn main() -> () { auto foo = []; } From fa306d704a0d49fcad23c32e4fd928190e41772a Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Wed, 8 Jun 2011 03:58:52 -0400 Subject: [PATCH 44/64] Add optional message to fail. --- src/comp/front/ast.rs | 2 +- src/comp/front/parser.rs | 15 ++++++++++++--- src/comp/middle/trans.rs | 13 +++++++++++-- src/comp/middle/tstate/pre_post_conditions.rs | 2 +- src/comp/middle/tstate/states.rs | 2 +- src/comp/middle/ty.rs | 2 +- src/comp/middle/typeck.rs | 4 ++-- src/comp/middle/walk.rs | 2 +- src/comp/pretty/pprust.rs | 7 ++++++- src/test/run-fail/explicit-fail-msg.rs | 5 +++++ 10 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 src/test/run-fail/explicit-fail-msg.rs diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index f670c2760a7c5..4f83ee7fa8d72 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -272,7 +272,7 @@ tag expr_ { expr_index(@expr, @expr, ann); expr_path(path, ann); expr_ext(path, vec[@expr], option::t[str], @expr, ann); - expr_fail(ann); + expr_fail(ann, option::t[str]); expr_break(ann); expr_cont(ann); expr_ret(option::t[@expr], ann); diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index b84a740a917de..562bc0cc32e37 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -256,7 +256,6 @@ fn parse_value_ident(&parser p) -> ast::ident { ret parse_ident(p); } - /* FIXME: gross hack copied from rustboot to make certain configuration-based * decisions work at build-time. We should probably change it to use a * lexical sytnax-extension or something similar. For now we just imitate @@ -934,7 +933,17 @@ fn parse_bottom_expr(&parser p) -> @ast::expr { ex = expand_syntax_ext(p, ext_span, pth, es.node, none[str]); } else if (eat_word(p, "fail")) { - ex = ast::expr_fail(p.get_ann()); + auto msg; + alt (p.peek()) { + case (token::LIT_STR(?s)) { + msg = some[str](p.get_str(s)); + p.bump(); + } + case (_) { + msg = none[str]; + } + } + ex = ast::expr_fail(p.get_ann(), msg); } else if (eat_word(p, "log")) { auto e = parse_expr(p); auto hi = e.span.hi; @@ -1643,7 +1652,7 @@ fn stmt_ends_with_semi(&ast::stmt stmt) -> bool { case (ast::expr_field(_,_,_)) { ret true; } case (ast::expr_index(_,_,_)) { ret true; } case (ast::expr_path(_,_)) { ret true; } - case (ast::expr_fail(_)) { ret true; } + case (ast::expr_fail(_,_)) { ret true; } case (ast::expr_break(_)) { ret true; } case (ast::expr_cont(_)) { ret true; } case (ast::expr_ret(_,_)) { ret true; } diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 01192deb8da7f..0fac5651f1458 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -5628,8 +5628,17 @@ fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output) ret trans_expr(cx, expanded); } - case (ast::expr_fail(_)) { - ret trans_fail(cx, some(e.span), "explicit failure"); + case (ast::expr_fail(_, ?str)) { + auto failmsg; + alt (str) { + case (some(?msg)) { + failmsg = msg; + } + case (_) { + failmsg = "explicit failure"; + } + } + ret trans_fail(cx, some(e.span), failmsg); } case (ast::expr_log(?lvl, ?a, _)) { diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index d1df649f7a61e..da4e333f0a625 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -459,7 +459,7 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () { find_pre_post_expr(fcx, operator); copy_pre_post(fcx.ccx, a, operator); } - case (expr_fail(?a)) { + case (expr_fail(?a, _)) { set_pre_and_post(fcx.ccx, a, /* if execution continues after fail, then everything is true! */ diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index 37cc40b5c9eb5..369f307aa819b 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -508,7 +508,7 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool { expr_poststate(fcx.ccx, operand)) || changed; ret changed; } - case (expr_fail(?a)) { + case (expr_fail(?a, _)) { changed = extend_prestate_ann(fcx.ccx, a, pres) || changed; /* if execution continues after fail, then everything is true! woo! */ changed = set_poststate_ann(fcx.ccx, a, diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 3d0c612a085c4..3487af785610e 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -1657,7 +1657,7 @@ fn expr_ann(&@ast::expr e) -> ast::ann { case (ast::expr_index(_,_,?a)) { ret a; } case (ast::expr_path(_,?a)) { ret a; } case (ast::expr_ext(_,_,_,_,?a)) { ret a; } - case (ast::expr_fail(?a)) { ret a; } + case (ast::expr_fail(?a,_)) { ret a; } case (ast::expr_ret(_,?a)) { ret a; } case (ast::expr_put(_,?a)) { ret a; } case (ast::expr_be(_,?a)) { ret a; } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index db3f3ede0c701..afafde4e916b6 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1276,7 +1276,7 @@ mod pushdown { write::ty_only_fixup(fcx, ann.id, t); } /* FIXME: should this check the type annotations? */ - case (ast::expr_fail(_)) { /* no-op */ } + case (ast::expr_fail(_,_)) { /* no-op */ } case (ast::expr_log(_,_,_)) { /* no-op */ } case (ast::expr_break(_)) { /* no-op */ } case (ast::expr_cont(_)) { /* no-op */ } @@ -1972,7 +1972,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { write::ty_only_fixup(fcx, a.id, t); } - case (ast::expr_fail(?a)) { + case (ast::expr_fail(?a, _)) { write::bot_ty(fcx.ccx.tcx, a.id); } diff --git a/src/comp/middle/walk.rs b/src/comp/middle/walk.rs index 1ecafe1f02fe5..214846a5ecf7a 100644 --- a/src/comp/middle/walk.rs +++ b/src/comp/middle/walk.rs @@ -431,7 +431,7 @@ fn walk_expr(&ast_visitor v, @ast::expr e) { // Only walk expansion, not args/body. walk_expr(v, expansion); } - case (ast::expr_fail(_)) { } + case (ast::expr_fail(_, _)) { } case (ast::expr_break(_)) { } case (ast::expr_cont(_)) { } case (ast::expr_ret(?eo, _)) { diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index 2c7e65dcb2200..db6d62bdbc848 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -825,8 +825,13 @@ fn print_expr(&ps s, &@ast::expr expr) { case (ast::expr_path(?path,_)) { print_path(s, path); } - case (ast::expr_fail(_)) { + case (ast::expr_fail(_, ?str)) { word(s.s, "fail"); + alt (str) { + case (some(?msg)) { + word(s.s, #fmt("\"%s\"", msg)); + } + } } case (ast::expr_break(_)) { word(s.s, "break"); diff --git a/src/test/run-fail/explicit-fail-msg.rs b/src/test/run-fail/explicit-fail-msg.rs new file mode 100644 index 0000000000000..e37cf5d58f516 --- /dev/null +++ b/src/test/run-fail/explicit-fail-msg.rs @@ -0,0 +1,5 @@ +// error-pattern:woooo + +fn main() { + fail "woooo"; +} From 64c0631cb2c3f05019ea4da785ec2a0e525b6f9f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 8 Jun 2011 09:09:50 -0700 Subject: [PATCH 45/64] authors: Add Josh Matthews to AUTHORS --- AUTHORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index 38bfb6e90b6b4..e7efbd7aeaa69 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -17,6 +17,7 @@ Jason Orendorff Jeff Balogh Jeff Muizelaar Jeffrey Yasskin +Josh Matthews Kelly Wilson Lindsey Kuper Marijn Haverbeke From 04ffefbe552298143b9a47505cba836d75d7479c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20=C3=81vila=20de=20Esp=C3=ADndola?= Date: Wed, 8 Jun 2011 13:33:35 -0400 Subject: [PATCH 46/64] Use main.o directly now that stage0 is ok with it. --- Makefile.in | 6 +++--- mk/clean.mk | 1 - mk/rt.mk | 4 ---- mk/stage1.mk | 2 +- mk/stage2.mk | 2 +- mk/stage3.mk | 2 +- mk/tests.mk | 6 +++--- 7 files changed, 9 insertions(+), 14 deletions(-) diff --git a/Makefile.in b/Makefile.in index 362b97ea03656..50224f62a0d8a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -144,9 +144,9 @@ COMPILER_INPUTS := $(wildcard $(addprefix $(S)src/comp/, \ ###################################################################### LREQ := rt/$(CFG_RUNTIME) rustllvm/$(CFG_RUSTLLVM) -SREQ0 := stage0/rustc$(X) $(LREQ) rt/main.a stage1/glue.o stage1/$(CFG_STDLIB) -SREQ1 := stage1/rustc$(X) $(LREQ) rt/main.a stage2/glue.o stage2/$(CFG_STDLIB) -SREQ2 := stage2/rustc$(X) $(LREQ) rt/main.a stage3/glue.o stage3/$(CFG_STDLIB) +SREQ0 := stage0/rustc$(X) $(LREQ) rt/main.o stage1/glue.o stage1/$(CFG_STDLIB) +SREQ1 := stage1/rustc$(X) $(LREQ) rt/main.o stage2/glue.o stage2/$(CFG_STDLIB) +SREQ2 := stage2/rustc$(X) $(LREQ) rt/main.o stage3/glue.o stage3/$(CFG_STDLIB) ###################################################################### diff --git a/mk/clean.mk b/mk/clean.mk index 305b06b5e0a38..5353006fe7caf 100644 --- a/mk/clean.mk +++ b/mk/clean.mk @@ -29,7 +29,6 @@ clean: $(Q)rm -f rustllvm/$(CFG_RUSTLLVM) rustllvm/rustllvmbits.a $(Q)rm -f rt/$(CFG_RUNTIME) $(Q)rm -f rt/main.o - $(Q)rm -f rt/main.a $(Q)rm -Rf $(PKG_NAME)-*.tar.gz dist $(Q)rm -f $(foreach ext,o a d bc s exe,$(wildcard stage*/*.$(ext))) $(Q)rm -Rf $(foreach ext,out out.tmp \ diff --git a/mk/rt.mk b/mk/rt.mk index 1cc6dfb57f45f..566e5f285d4e0 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -84,10 +84,6 @@ rt/main.ll: rt/main.ll.in sed 's/MAIN/main/' < $^ > $@ endif -rt/main.a: rt/main.o - rm -f $@ - ar crs $@ $^ - rt/%.o: rt/%.ll $(MKFILES) @$(call E, llc: $@) $(Q)$(LLC) -filetype=obj -relocation-model=pic -march=x86 -o $@ $< diff --git a/mk/stage1.mk b/mk/stage1.mk index c98882e41a872..d3a2ca52853dc 100644 --- a/mk/stage1.mk +++ b/mk/stage1.mk @@ -44,7 +44,7 @@ stage1/%.o: stage1/%.s stage1/%$(X): stage1/%.o $(SREQ0) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage1/glue.o -o $@ $< \ - -Lstage1 -Lrustllvm -Lrt rt/main.a -lrustrt -lrustllvm -lstd -lm + -Lstage1 -Lrustllvm -Lrt rt/main.o -lrustrt -lrustllvm -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. diff --git a/mk/stage2.mk b/mk/stage2.mk index 0d87400c1e298..a1c8da05ba3e4 100644 --- a/mk/stage2.mk +++ b/mk/stage2.mk @@ -44,7 +44,7 @@ stage2/%.o: stage2/%.s stage2/%$(X): stage2/%.o $(SREQ1) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage2/glue.o -o $@ $< \ - -Lstage2 -Lrustllvm -Lrt rt/main.a -lrustrt -lrustllvm -lstd -lm + -Lstage2 -Lrustllvm -Lrt rt/main.o -lrustrt -lrustllvm -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. diff --git a/mk/stage3.mk b/mk/stage3.mk index 77d09440883e7..3654c17aa4451 100644 --- a/mk/stage3.mk +++ b/mk/stage3.mk @@ -44,7 +44,7 @@ stage3/%.o: stage3/%.s stage3/%$(X): stage3/%.o $(SREQ2) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage3/glue.o -o $@ $< \ - -Lstage3 -Lrustllvm -Lrt rt/main.a -lrustrt -lrustllvm -lstd -lm + -Lstage3 -Lrustllvm -Lrt rt/main.o -lrustrt -lrustllvm -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. diff --git a/mk/tests.mk b/mk/tests.mk index db7a3dd4d33cf..79ab8d3774b62 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -185,7 +185,7 @@ compile-check: tidy \ %.stage0$(X): %.stage0.o $(SREQ0) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage1/glue.o -o $@ $< \ - -Lstage1 -Lrt rt/main.a -lrustrt -lstd -lm + -Lstage1 -Lrt rt/main.o -lrustrt -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. @@ -194,7 +194,7 @@ compile-check: tidy \ %.stage1$(X): %.stage1.o $(SREQ1) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage2/glue.o -o $@ $< \ - -Lstage2 -Lrt rt/main.a -lrustrt -lstd -lm + -Lstage2 -Lrt rt/main.o -lrustrt -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. @@ -203,7 +203,7 @@ compile-check: tidy \ %.stage2$(X): %.stage2.o $(SREQ2) @$(call E, link [gcc]: $@) $(Q)gcc $(CFG_GCCISH_CFLAGS) stage3/glue.o -o $@ $< \ - -Lstage3 -Lrt rt/main.a -lrustrt -lstd -lm + -Lstage3 -Lrt rt/main.o -lrustrt -lstd -lm @# dsymutil sometimes fails or prints a warning, but the @# program still runs. Since it simplifies debugging other @# programs, I\'ll live with the noise. From 9bedc39e2199668a3ac007206ade8075d58b6004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20=C3=81vila=20de=20Esp=C3=ADndola?= Date: Wed, 8 Jun 2011 13:47:21 -0400 Subject: [PATCH 47/64] Don't force the fetch of main.o from main.a, we are not using main.a anymore. --- src/comp/middle/trans.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 0fac5651f1458..3780d2c86fb23 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -8238,17 +8238,6 @@ fn trans_crate(&session::session sess, &@ast::crate crate, trans_mod(cx, crate.node.module); auto crate_map = create_crate_map(ccx); - if (!sess.get_opts().shared) { - auto gvar = llvm::LLVMAddGlobal(cx.ccx.llmod, T_ptr(T_int()), - str::buf("_rust_fetch_this_object_hack")); - - auto gvar2 = llvm::LLVMAddGlobal(cx.ccx.llmod, T_ptr(T_ptr(T_int())), - str::buf("_rust_fetch_this_object_hack2")); - llvm::LLVMSetInitializer(gvar2, gvar); - llvm::LLVMSetGlobalConstant(gvar, True); - llvm::LLVMSetGlobalConstant(gvar2, True); - } - emit_tydescs(ccx); // Translate the metadata: From dc39dd43ca4bc2c60081cc017d7aba34b0d22203 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 8 Jun 2011 10:51:43 -0700 Subject: [PATCH 48/64] rustc: Remove all traces of the unification cache --- src/comp/middle/typeck.rs | 60 --------------------------------------- 1 file changed, 60 deletions(-) diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index afafde4e916b6..ee3ca30095b4c 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -52,16 +52,10 @@ import middle::tstate::ann::ts_ann; type ty_table = hashmap[ast::def_id, ty::t]; type fn_purity_table = hashmap[ast::def_id, ast::purity]; -type unify_cache_entry = tup(ty::t,ty::t,vec[mutable ty::t]); -type unify_cache = hashmap[unify_cache_entry,ty::unify::result]; - type obj_info = rec(vec[ast::obj_field] obj_fields, ast::def_id this_obj); type crate_ctxt = rec(mutable vec[obj_info] obj_infos, @fn_purity_table fn_purity_table, - unify_cache unify_cache, - mutable uint cache_hits, - mutable uint cache_misses, ty::ctxt tcx); type fn_ctxt = rec(ty::t ret_ty, @@ -820,22 +814,9 @@ mod collect { mod unify { fn simple(&@fn_ctxt fcx, &ty::t expected, &ty::t actual) -> ty::unify::result { - /*auto cache_key = tup(expected, actual, param_substs); - alt (fcx.ccx.unify_cache.find(cache_key)) { - case (some(?r)) { - fcx.ccx.cache_hits += 1u; - ret r; - } - case (none) { - fcx.ccx.cache_misses += 1u; - } - }*/ - auto result = ty::unify::unify(expected, actual, fcx.var_bindings, fcx.ccx.tcx); - //fcx.ccx.unify_cache.insert(cache_key, result); - // FIXME: Shouldn't be necessary, but is until we remove pushdown. alt (result) { case (ures_ok(?typ)) { @@ -2856,37 +2837,6 @@ fn check_item(@crate_ctxt ccx, &@ast::item it) { } } -// Utilities for the unification cache - -fn hash_unify_cache_entry(&unify_cache_entry uce) -> uint { - auto h = ty::hash_ty(uce._0); - h += h << 5u + ty::hash_ty(uce._1); - - auto i = 0u; - auto tys_len = vec::len(uce._2); - while (i < tys_len) { - h += h << 5u + ty::hash_ty(uce._2.(i)); - i += 1u; - } - - ret h; -} - -fn eq_unify_cache_entry(&unify_cache_entry a, &unify_cache_entry b) -> bool { - if (!ty::eq_ty(a._0, b._0) || !ty::eq_ty(a._1, b._1)) { ret false; } - - auto i = 0u; - auto tys_len = vec::len(a._2); - if (vec::len(b._2) != tys_len) { ret false; } - - while (i < tys_len) { - if (!ty::eq_ty(a._2.(i), b._2.(i))) { ret false; } - i += 1u; - } - - ret true; -} - fn mk_fn_purity_table(&@ast::crate crate) -> @fn_purity_table { auto res = @new_def_hash[ast::purity](); @@ -2914,26 +2864,16 @@ fn check_crate(&ty::ctxt tcx, &@ast::crate crate) { let vec[obj_info] obj_infos = []; - auto hasher = hash_unify_cache_entry; - auto eqer = eq_unify_cache_entry; - auto unify_cache = - map::mk_hashmap[unify_cache_entry,ty::unify::result](hasher, eqer); auto fpt = mk_fn_purity_table(crate); // use a variation on collect auto ccx = @rec(mutable obj_infos=obj_infos, fn_purity_table=fpt, - unify_cache=unify_cache, - mutable cache_hits=0u, - mutable cache_misses=0u, tcx=tcx); auto visit = rec(visit_item_pre = bind check_item(ccx, _) with walk::default_visitor()); walk::walk_crate(visit, *crate); - - log #fmt("cache hit rate: %u/%u", ccx.cache_hits, - ccx.cache_hits + ccx.cache_misses); } // From b33bf32fe810fce9a0224d362959052936d7d505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20=C3=81vila=20de=20Esp=C3=ADndola?= Date: Tue, 24 May 2011 13:47:27 -0400 Subject: [PATCH 49/64] Update rust to build with newer llvm versions. --- src/comp/back/link.rs | 1 - src/comp/lib/llvm.rs | 2 +- src/comp/middle/trans.rs | 6 ++++++ src/rustllvm/Passes2.cpp | 29 ++++++++++++++++++----------- src/rustllvm/RustWrapper.cpp | 3 +-- 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index 6469bbd3ced25..b637b7e41b851 100644 --- a/src/comp/back/link.rs +++ b/src/comp/back/link.rs @@ -153,7 +153,6 @@ mod write { True, // unit-at-a-time True, // unroll loops True, // simplify lib calls - True, // have exceptions threshold); // inline threshold } diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs index 0de35b9f006a4..505e07e3f3fa0 100644 --- a/src/comp/lib/llvm.rs +++ b/src/comp/lib/llvm.rs @@ -88,6 +88,7 @@ const uint LLVMNoImplicitFloatAttribute = 8388608u; const uint LLVMNakedAttribute = 16777216u; const uint LLVMInlineHintAttribute = 33554432u; const uint LLVMStackAttribute = 469762048u; // 7 << 26 +const uint LLVMUWTableAttribute = 1073741824u; // 1 << 30 // Consts for the LLVM IntPredicate type, pre-cast to uint. @@ -813,7 +814,6 @@ native mod llvm = llvm_lib { Bool UnitAtATime, Bool UnrollLoops, Bool SimplifyLibCalls, - Bool HaveExceptions, uint InliningThreshold); /** Destroys a memory buffer. */ diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 3780d2c86fb23..f08d450e81d83 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -1820,6 +1820,11 @@ fn set_no_inline(ValueRef f) { lib::llvm::llvm::Attribute); } +fn set_uwtable(ValueRef f) { + llvm::LLVMAddFunctionAttr(f, lib::llvm::LLVMUWTableAttribute as + lib::llvm::llvm::Attribute); +} + fn set_always_inline(ValueRef f) { llvm::LLVMAddFunctionAttr(f, lib::llvm::LLVMAlwaysInlineAttribute as lib::llvm::llvm::Attribute); @@ -6962,6 +6967,7 @@ fn trans_fn(@local_ctxt cx, &span sp, &ast::_fn f, ast::def_id fid, option::t[ty_self_pair] ty_self, &vec[ast::ty_param] ty_params, &ast::ann ann) { auto llfndecl = cx.ccx.item_ids.get(fid); + set_uwtable(llfndecl); // Set up arguments to the function. auto fcx = new_fn_ctxt(cx, sp, llfndecl); diff --git a/src/rustllvm/Passes2.cpp b/src/rustllvm/Passes2.cpp index c4ead0de5aa92..dcc549b511f6b 100644 --- a/src/rustllvm/Passes2.cpp +++ b/src/rustllvm/Passes2.cpp @@ -1,5 +1,5 @@ #include "llvm/Analysis/Passes.h" -#include "llvm/Support/StandardPasses.h" +#include "llvm/Support/PassManagerBuilder.h" #include "llvm/PassManager.h" #include "llvm-c/Core.h" #include @@ -8,22 +8,29 @@ using namespace llvm; extern "C" void LLVMAddStandardFunctionPasses(LLVMPassManagerRef PM, unsigned int OptimizationLevel) { - createStandardFunctionPasses(unwrap(PM), OptimizationLevel); + PassManagerBuilder PMBuilder; + PMBuilder.OptLevel = OptimizationLevel; + FunctionPassManager *FPM = (FunctionPassManager*) unwrap(PM); + PMBuilder.populateFunctionPassManager(*FPM); } extern "C" void LLVMAddStandardModulePasses(LLVMPassManagerRef PM, unsigned int OptimizationLevel, LLVMBool OptimizeSize, LLVMBool UnitAtATime, LLVMBool UnrollLoops, LLVMBool SimplifyLibCalls, - LLVMBool HaveExceptions, unsigned int InliningThreshold) { - Pass *InliningPass; + unsigned int InliningThreshold) { + + PassManagerBuilder PMBuilder; + PMBuilder.OptLevel = OptimizationLevel; + PMBuilder.SizeLevel = OptimizeSize; + PMBuilder.DisableUnitAtATime = !UnitAtATime; + PMBuilder.DisableUnrollLoops = !UnrollLoops; + + PMBuilder.DisableSimplifyLibCalls = !SimplifyLibCalls; + if (InliningThreshold) - InliningPass = createFunctionInliningPass(InliningThreshold); - else - InliningPass = NULL; + PMBuilder.Inliner = createFunctionInliningPass(InliningThreshold); - createStandardModulePasses(unwrap(PM), OptimizationLevel, OptimizeSize, - UnitAtATime, UnrollLoops, SimplifyLibCalls, - HaveExceptions, InliningPass); + PassManager *MPM = (PassManager*) unwrap(PM); + PMBuilder.populateModulePassManager(*MPM); } - diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 2c50a6ccfa732..eb06398c48e64 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -47,7 +47,7 @@ extern "C" const char *LLVMRustGetLastError(void) { extern "C" void LLVMAddBasicAliasAnalysisPass(LLVMPassManagerRef PM); extern "C" void LLVMAddStandardModulePasses(LLVMPassManagerRef PM, unsigned int OptimizationLevel, bool OptimizeSize, bool UnitAtATime, - bool UnrollLoops, bool SimplifyLibCalls, bool HaveExceptions, + bool UnrollLoops, bool SimplifyLibCalls, unsigned int InliningThreshold); int *RustHackToFetchPassesO = (int*)LLVMAddBasicAliasAnalysisPass; @@ -80,7 +80,6 @@ extern "C" void LLVMRustWriteOutputFile(LLVMPassManagerRef PMR, LLVMCodeGenFileType FileType) { // Set compilation options. - llvm::UnwindTablesMandatory = true; llvm::NoFramePointerElim = true; InitializeAllTargets(); From ba6f6705d4467834d73a73d5beb8bc7867c633de Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 8 Jun 2011 12:23:44 -0700 Subject: [PATCH 50/64] rustc: Remove pushdown. 15 second improvement. --- src/comp/middle/ty.rs | 4 +- src/comp/middle/typeck.rs | 469 +++----------------------------------- 2 files changed, 30 insertions(+), 443 deletions(-) diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 3487af785610e..97c2157b20ac1 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -2574,9 +2574,11 @@ mod unify { fn resolve_type_var(&ty_ctxt tcx, &@var_bindings vb, int vid) -> fixup_result { + if ((vid as uint) >= ufind::set_count(vb.sets)) { ret fix_err(vid); } + auto root_id = ufind::find(vb.sets, vid as uint); alt (smallintmap::find[t](vb.types, root_id)) { - case (none[t]) { ret fix_ok(mk_var(tcx, vid)); } + case (none[t]) { ret fix_err(vid); } case (some[t](?rt)) { ret fixup_vars(tcx, vb, rt); } } } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index ee3ca30095b4c..276c08f309469 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -978,381 +978,6 @@ fn variant_arg_types(&@crate_ctxt ccx, &span sp, &ast::def_id vid, } -// The "push-down" phase, which takes a typed grammar production and pushes -// its type down into its constituent parts. -// -// For example, consider "auto x; x = 352;". check_expr() doesn't know the -// type of "x" at the time it sees it, so that function will simply store a -// type variable for the type of "x". However, after checking the entire -// assignment expression, check_expr() will assign the type of int to the -// expression "x = 352" as a whole. In this case, then, the job of these -// functions is to clean up by assigning the type of int to both sides of the -// assignment expression. -// -// TODO: We only need to do this once per statement: check_expr() bubbles the -// types up, and pushdown_expr() pushes the types down. However, in many cases -// we're more eager than we need to be, calling pushdown_expr() and friends -// directly inside check_expr(). This results in a quadratic algorithm. - -mod pushdown { - // Push-down over typed expressions. Note that the expression that you - // pass to this function must have been passed to check_expr() first. - // - // TODO: enforce this via a predicate. - // TODO: This function is incomplete. - - fn pushdown_expr(&@fn_ctxt fcx, &ty::t expected, &@ast::expr e) { - be pushdown_expr_full(fcx, expected, e, NO_AUTODEREF); - } - - fn pushdown_expr_full(&@fn_ctxt fcx, &ty::t expected, &@ast::expr e, - autoderef_kind adk) { - alt (e.node) { - case (ast::expr_vec(?es_0, ?mut, ?ann)) { - // TODO: enforce mutability - - auto t = demand::simple(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann)); - alt (struct(fcx.ccx.tcx, t)) { - case (ty::ty_vec(?mt)) { - for (@ast::expr e_0 in es_0) { - pushdown_expr(fcx, mt.ty, e_0); - } - } - case (_) { - log_err "vec expr doesn't have a vec type!"; - fail; - } - } - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_tup(?es_0, ?ann)) { - auto t = demand::simple(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann)); - alt (struct(fcx.ccx.tcx, t)) { - case (ty::ty_tup(?mts)) { - auto i = 0u; - for (ast::elt elt_0 in es_0) { - pushdown_expr(fcx, mts.(i).ty, elt_0.expr); - i += 1u; - } - } - case (_) { - log_err "tup expr doesn't have a tup type!"; - fail; - } - } - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_rec(?fields_0, ?base_0, ?ann)) { - - auto t = demand::simple(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann)); - alt (struct(fcx.ccx.tcx, t)) { - case (ty::ty_rec(?field_mts)) { - alt (base_0) { - case (none) { - auto i = 0u; - for (ast::field field_0 in fields_0) { - assert (str::eq(field_0.node.ident, - field_mts.(i).ident)); - pushdown_expr(fcx, - field_mts.(i).mt.ty, - field_0.node.expr); - i += 1u; - } - } - case (some(?bx)) { - - let vec[field] base_fields = []; - - for (ast::field field_0 in fields_0) { - - for (ty::field ft in field_mts) { - if (str::eq(field_0.node.ident, - ft.ident)) { - pushdown_expr(fcx, ft.mt.ty, - field_0.node.expr); - } - } - } - } - } - } - case (_) { - log_err "rec expr doesn't have a rec type!"; - fail; - } - } - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_bind(?sube, ?es, ?ann)) { - auto t = demand::simple(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann)); - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_call(?sube, ?es, ?ann)) { - // 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(fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_self_method(?id, ?ann)) { - auto t = demand::simple(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann)); - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_binary(?bop, ?lhs, ?rhs, ?ann)) { - auto t = demand::simple(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann)); - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_unary(?uop, ?sube, ?ann)) { - // See note in expr_unary for why we're calling - // demand::autoderef. - auto t = demand::autoderef(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(fcx, ann.id, t); - - /* The following is a bit special-cased, but takes care of - the case where we say let @vec[whatever] v = @[]; */ - auto inner_ty = t; - alt (uop) { - case (ast::box(?mut)) { - alt (struct(fcx.ccx.tcx, t)) { - case (ty::ty_box(?inner)) { inner_ty = inner.ty; } - case (_) { - fcx.ccx.tcx.sess.span_err(e.span, - "Expecting an application of box " + - "to have a box type; it had type " + - ty::ty_to_str(fcx.ccx.tcx, t)); - } - } - } - case (ast::deref) { - inner_ty = ty::mk_box(fcx.ccx.tcx, - // maybe_mut should work because it'll unify with - // the existing type? - rec(ty=t, mut=ast::maybe_mut)); - } - case (_) { inner_ty = strip_boxes(fcx.ccx.tcx, t); } - } - - pushdown_expr(fcx, inner_ty, sube); - } - case (ast::expr_lit(?lit, ?ann)) { - auto t = demand::simple(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann)); - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_cast(?sube, ?ast_ty, ?ann)) { - auto t = demand::simple(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann)); - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_if(?cond, ?then_0, ?else_0, ?ann)) { - auto t = demand::autoderef(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann), adk); - - auto then_t = ty::block_ty(fcx.ccx.tcx, then_0); - pushdown_block(fcx, expected, then_0); - - alt (else_0) { - case (none) { /* no-op */ } - case (some(?e_0)) { - auto else_t = ty::expr_ty(fcx.ccx.tcx, e_0); - pushdown_expr(fcx, expected, e_0); - } - } - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_for(?decl, ?seq, ?bloc, ?ann)) { - auto t = demand::simple(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann)); - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_for_each(?decl, ?seq, ?bloc, ?ann)) { - auto t = demand::simple(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann)); - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_while(?cond, ?bloc, ?ann)) { - auto t = demand::simple(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann)); - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_do_while(?bloc, ?cond, ?ann)) { - auto t = demand::simple(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann)); - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_block(?bloc, ?ann)) { - auto t = demand::autoderef(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(fcx, ann.id, t); - pushdown_block(fcx, t, bloc); - } - case (ast::expr_move(?lhs_0, ?rhs_0, ?ann)) { - auto t = demand::autoderef(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann), adk); - pushdown_expr(fcx, expected, lhs_0); - pushdown_expr(fcx, expected, rhs_0); - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_assign(?lhs_0, ?rhs_0, ?ann)) { - auto t = demand::autoderef(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann), adk); - pushdown_expr(fcx, expected, lhs_0); - pushdown_expr(fcx, expected, rhs_0); - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_assign_op(?op, ?lhs_0, ?rhs_0, ?ann)) { - auto t = demand::autoderef(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann), adk); - pushdown_expr(fcx, expected, lhs_0); - pushdown_expr(fcx, expected, rhs_0); - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_field(?lhs, ?rhs, ?ann)) { - auto t = demand::autoderef(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_index(?base, ?index, ?ann)) { - auto t = demand::autoderef(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(fcx, ann.id, t); - } - case (ast::expr_path(?pth, ?ann)) { - auto tp_substs_0 = - ty::ann_to_type_params(fcx.ccx.tcx, ann); - auto t_0 = ty::ann_to_monotype(fcx.ccx.tcx, ann); - - auto result_0 = demand::full(fcx, e.span, expected, t_0, - tp_substs_0, adk); - auto t = ann_to_type(fcx.ccx.tcx, ann); - - // Fill in the type parameter substitutions if they weren't - // provided by the programmer. - auto ty_params_opt; - - alt (ty::ann_to_ty_param_substs_opt_and_ty(fcx.ccx.tcx, - ann)._0) { - case (none) { - ty_params_opt = none[vec[ty::t]]; - } - case (some(?tps)) { - ty_params_opt = some[vec[ty::t]](tps); - } - } - - write::ty_fixup(fcx, ann.id, tup(ty_params_opt, t)); - } - case (ast::expr_ext(?p, ?args, ?body, ?expanded, ?ann)) { - auto t = demand::autoderef(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(fcx, ann.id, t); - } - /* FIXME: should this check the type annotations? */ - case (ast::expr_fail(_,_)) { /* no-op */ } - case (ast::expr_log(_,_,_)) { /* no-op */ } - case (ast::expr_break(_)) { /* no-op */ } - case (ast::expr_cont(_)) { /* no-op */ } - case (ast::expr_ret(_,_)) { /* no-op */ } - case (ast::expr_put(_,_)) { /* no-op */ } - case (ast::expr_be(_,_)) { /* no-op */ } - case (ast::expr_check(_,_)) { /* no-op */ } - case (ast::expr_assert(_,_)) { /* no-op */ } - - case (ast::expr_port(?ann)) { - auto t = demand::simple(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann)); - write::ty_only_fixup(fcx, ann.id, t); - } - - case (ast::expr_chan(?es, ?ann)) { - auto t = demand::simple(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann)); - alt (struct(fcx.ccx.tcx, t)) { - case (ty::ty_chan(?subty)) { - auto pt = ty::mk_port(fcx.ccx.tcx, subty); - pushdown_expr(fcx, pt, es); - } - case (_) { - log "chan expr doesn't have a chan type!"; - fail; - } - } - write::ty_only_fixup(fcx, ann.id, t); - } - - case (ast::expr_alt(?discrim, ?arms_0, ?ann)) { - auto t = expected; - for (ast::arm arm_0 in arms_0) { - pushdown_block(fcx, expected, arm_0.block); - auto bty = block_ty(fcx.ccx.tcx, arm_0.block); - t = demand::simple(fcx, e.span, t, bty); - } - write::ty_only_fixup(fcx, ann.id, t); - } - - case (ast::expr_recv(?lval, ?expr, ?ann)) { - pushdown_expr(fcx, next_ty_var(fcx), lval); - auto t = expr_ty(fcx.ccx.tcx, lval); - write::ty_only_fixup(fcx, ann.id, t); - } - - case (ast::expr_send(?lval, ?expr, ?ann)) { - pushdown_expr(fcx, next_ty_var(fcx), expr); - auto t = expr_ty(fcx.ccx.tcx, expr); - pushdown_expr(fcx, ty::mk_chan(fcx.ccx.tcx, t), lval); - } - - case (ast::expr_spawn(?dom, ?name, ?func, ?args, ?ann)) { - // 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(fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(fcx, ann.id, t); - } - - case (ast::expr_anon_obj(?anon_obj, ?tps, ?odid, ?ann)) { - // NB: Not sure if this is correct, but not worrying too much - // about it since pushdown is going away anyway. - auto t = demand::autoderef(fcx, e.span, expected, - ann_to_type(fcx.ccx.tcx, ann), adk); - write::ty_only_fixup(fcx, ann.id, t); - } - - case (_) { - fcx.ccx.tcx.sess.span_unimpl(e.span, - #fmt("type unification for expression variant: %s", - pretty::pprust::expr_to_str(e))); - } - } - } - - // Push-down over typed blocks. - fn pushdown_block(&@fn_ctxt fcx, &ty::t expected, &ast::block bloc) { - alt (bloc.node.expr) { - case (some(?e_0)) { - pushdown_expr(fcx, expected, e_0); - } - case (none) { - /* empty */ - } - } - demand::simple(fcx, bloc.span, expected, ann_to_type(fcx.ccx.tcx, - bloc.node.a)); - } -} - - // Type resolution: the phase that finds all the types in the AST with // unresolved type variables and replaces "ty_var" types with their // substitutions. @@ -1825,19 +1450,14 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { } // A generic function for checking assignment expressions - fn check_assignment(&@fn_ctxt fcx, &@ast::expr lhs, &@ast::expr rhs, - &ast::ann a) { + fn check_assignment(&@fn_ctxt fcx, &span sp, &@ast::expr lhs, + &@ast::expr rhs, &ast::ann a) { check_expr(fcx, lhs); check_expr(fcx, rhs); - auto lhs_t0 = expr_ty(fcx.ccx.tcx, lhs); - auto rhs_t0 = expr_ty(fcx.ccx.tcx, rhs); - - pushdown::pushdown_expr(fcx, rhs_t0, lhs); - auto lhs_t1 = expr_ty(fcx.ccx.tcx, lhs); - pushdown::pushdown_expr(fcx, lhs_t1, rhs); - auto rhs_t1 = expr_ty(fcx.ccx.tcx, rhs); - - write::ty_only_fixup(fcx, a.id, rhs_t1); + auto typ = demand::simple(fcx, sp, + expr_ty(fcx.ccx.tcx, lhs), + expr_ty(fcx.ccx.tcx, rhs)); + write::ty_only_fixup(fcx, a.id, typ); } // A generic function for checking call expressions @@ -1876,15 +1496,11 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { case (ast::expr_binary(?binop, ?lhs, ?rhs, ?a)) { check_expr(fcx, lhs); check_expr(fcx, rhs); - auto lhs_t0 = expr_ty(fcx.ccx.tcx, lhs); - auto rhs_t0 = expr_ty(fcx.ccx.tcx, rhs); - // FIXME: Binops have a bit more subtlety than this. - pushdown::pushdown_expr_full(fcx, rhs_t0, lhs, AUTODEREF_OK); - auto lhs_t1 = expr_ty(fcx.ccx.tcx, lhs); - pushdown::pushdown_expr_full(fcx, lhs_t1, rhs, AUTODEREF_OK); + auto lhs_t = expr_ty(fcx.ccx.tcx, lhs); - auto t = strip_boxes(fcx.ccx.tcx, lhs_t0); + // FIXME: Binops have a bit more subtlety than this. + auto t = strip_boxes(fcx.ccx.tcx, lhs_t); alt (binop) { case (ast::eq) { t = ty::mk_bool(fcx.ccx.tcx); } case (ast::lt) { t = ty::mk_bool(fcx.ccx.tcx); } @@ -1979,9 +1595,8 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { case (some(?e)) { check_expr(fcx, e); - - pushdown::pushdown_expr(fcx, fcx.ret_ty, e); - + demand::simple(fcx, expr.span, fcx.ret_ty, + expr_ty(fcx.ccx.tcx, e)); write::bot_ty(fcx.ccx.tcx, a.id); } } @@ -2003,8 +1618,6 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { case (some(?e)) { check_expr(fcx, e); - pushdown::pushdown_expr(fcx, fcx.ret_ty, e); - write::nil_ty(fcx.ccx.tcx, a.id); } } @@ -2015,8 +1628,6 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { assert (ast::is_call_expr(e)); check_expr(fcx, e); - pushdown::pushdown_expr(fcx, fcx.ret_ty, e); - write::nil_ty(fcx.ccx.tcx, a.id); } @@ -2076,17 +1687,17 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { case (ast::expr_move(?lhs, ?rhs, ?a)) { require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); - check_assignment(fcx, lhs, rhs, a); + check_assignment(fcx, expr.span, lhs, rhs, a); } case (ast::expr_assign(?lhs, ?rhs, ?a)) { require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); - check_assignment(fcx, lhs, rhs, a); + check_assignment(fcx, expr.span, lhs, rhs, a); } case (ast::expr_assign_op(?op, ?lhs, ?rhs, ?a)) { require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span); - check_assignment(fcx, lhs, rhs, a); + check_assignment(fcx, expr.span, lhs, rhs, a); } case (ast::expr_send(?lhs, ?rhs, ?a)) { @@ -2097,14 +1708,13 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { auto rhs_t = expr_ty(fcx.ccx.tcx, rhs); auto chan_t = ty::mk_chan(fcx.ccx.tcx, rhs_t); - pushdown::pushdown_expr(fcx, chan_t, lhs); + auto item_t; auto lhs_t = expr_ty(fcx.ccx.tcx, lhs); alt (struct(fcx.ccx.tcx, lhs_t)) { case (ty::ty_chan(?it)) { item_t = it; } case (_) { fail; } } - pushdown::pushdown_expr(fcx, item_t, rhs); write::ty_only_fixup(fcx, a.id, chan_t); } @@ -2114,26 +1724,16 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { check_expr(fcx, lhs); check_expr(fcx, rhs); - auto lhs_t1 = expr_ty(fcx.ccx.tcx, lhs); - auto port_t = ty::mk_port(fcx.ccx.tcx, lhs_t1); - pushdown::pushdown_expr(fcx, port_t, rhs); - auto item_t; - auto rhs_t = expr_ty(fcx.ccx.tcx, rhs); - alt (struct(fcx.ccx.tcx, rhs_t)) { - case (ty::ty_port(?it)) { item_t = it; } - case (_) { fail; } - } - pushdown::pushdown_expr(fcx, item_t, lhs); + auto item_t = expr_ty(fcx.ccx.tcx, lhs); + auto port_t = ty::mk_port(fcx.ccx.tcx, item_t); + demand::simple(fcx, expr.span, port_t, expr_ty(fcx.ccx.tcx, rhs)); write::ty_only_fixup(fcx, a.id, item_t); } case (ast::expr_if(?cond, ?thn, ?elsopt, ?a)) { check_expr(fcx, cond); - pushdown::pushdown_expr(fcx, ty::mk_bool(fcx.ccx.tcx), - cond); - check_block(fcx, thn); auto if_t = alt (elsopt) { @@ -2188,7 +1788,6 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { case (ast::expr_while(?cond, ?body, ?a)) { check_expr(fcx, cond); - pushdown::pushdown_expr(fcx, ty::mk_bool(fcx.ccx.tcx), cond); check_block(fcx, body); auto typ = ty::mk_nil(fcx.ccx.tcx); @@ -2197,7 +1796,6 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { case (ast::expr_do_while(?body, ?cond, ?a)) { check_expr(fcx, cond); - pushdown::pushdown_expr(fcx, ty::mk_bool(fcx.ccx.tcx), cond); check_block(fcx, body); auto typ = block_ty(fcx.ccx.tcx, body); @@ -2232,13 +1830,6 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { } } - auto i = 0u; - for (ast::block bloc in blocks) { - pushdown::pushdown_block(fcx, result_ty, bloc); - } - - pushdown::pushdown_expr(fcx, pattern_ty, expr); - write::ty_only_fixup(fcx, a.id, result_ty); } @@ -2682,14 +2273,17 @@ fn check_decl_initializer(&@fn_ctxt fcx, &ast::def_id lid, auto lty = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(lid)); alt (init.op) { case (ast::init_assign) { - pushdown::pushdown_expr(fcx, lty, init.expr); + demand::simple(fcx, init.expr.span, lty, + expr_ty(fcx.ccx.tcx, init.expr)); } case (ast::init_move) { - pushdown::pushdown_expr(fcx, lty, init.expr); + demand::simple(fcx, init.expr.span, lty, + expr_ty(fcx.ccx.tcx, init.expr)); } case (ast::init_recv) { auto port_ty = ty::mk_port(fcx.ccx.tcx, lty); - pushdown::pushdown_expr(fcx, port_ty, init.expr); + demand::simple(fcx, init.expr.span, port_ty, + expr_ty(fcx.ccx.tcx, init.expr)); } } } @@ -2714,12 +2308,6 @@ fn check_decl_local(&@fn_ctxt fcx, &@ast::decl decl) -> @ast::decl { } } -fn check_and_pushdown_expr(&@fn_ctxt fcx, &@ast::expr expr) { - check_expr(fcx, expr); - auto ety = expr_ty(fcx.ccx.tcx, expr); - pushdown::pushdown_expr(fcx, ety, expr); -} - fn check_stmt(&@fn_ctxt fcx, &@ast::stmt stmt) { auto node_id; alt (stmt.node) { @@ -2732,7 +2320,7 @@ fn check_stmt(&@fn_ctxt fcx, &@ast::stmt stmt) { } case (ast::stmt_expr(?expr,?a)) { node_id = a.id; - check_and_pushdown_expr(fcx, expr); + check_expr(fcx, expr); } } @@ -2743,13 +2331,10 @@ fn check_block(&@fn_ctxt fcx, &ast::block block) { for (@ast::stmt s in block.node.stmts) { check_stmt(fcx, s); } alt (block.node.expr) { - case (none) { - write::nil_ty(fcx.ccx.tcx, block.node.a.id); - } + case (none) { write::nil_ty(fcx.ccx.tcx, block.node.a.id); } case (some(?e)) { check_expr(fcx, e); auto ety = expr_ty(fcx.ccx.tcx, e); - pushdown::pushdown_expr(fcx, ety, e); write::ty_only_fixup(fcx, block.node.a.id, ety); } } @@ -2770,7 +2355,7 @@ fn check_const(&@crate_ctxt ccx, &span sp, &@ast::expr e, &ast::ann ann) { mutable fixups=fixups, ccx=ccx); - check_and_pushdown_expr(fcx, e); + check_expr(fcx, e); } fn check_fn(&@crate_ctxt ccx, &ast::fn_decl decl, ast::proto proto, From 0dafbf65e5082ea0ee5b9cf80672c011291171ff Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 8 Jun 2011 12:52:36 -0700 Subject: [PATCH 51/64] test: Add a test case for issue #362, "ret none". --- src/test/run-pass/ret-none.rs | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/test/run-pass/ret-none.rs diff --git a/src/test/run-pass/ret-none.rs b/src/test/run-pass/ret-none.rs new file mode 100644 index 0000000000000..cc9f3020f4dcb --- /dev/null +++ b/src/test/run-pass/ret-none.rs @@ -0,0 +1,6 @@ +tag option[T] { none; some(T); } + +fn f[T]() -> option[T] { ret none; } + +fn main() { f[int](); } + From 1a880df339895db1eb8e65b810633f46f7fe10c4 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 8 Jun 2011 14:56:18 -0700 Subject: [PATCH 52/64] Register new snapshots. --- src/snapshots.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/snapshots.txt b/src/snapshots.txt index 5b41fb5a15874..e1199383ea6a5 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,8 @@ +S 2011-06-08 f54f279 + linux-i386 4a13693dc548c764e3b662a90d52e57359e3bc91 + macos-i386 e0bd0fd650a194c361881cf62c4af33c78276939 + winnt-i386 5c3c2a634ad2fed5b3987fb0e9de7fd75c510bd4 + S 2011-06-07 a4ca75e linux-i386 3de95184c59f5b0554df3da995090aaba26a190f macos-i386 1537f2e01c746dc6ca2a9bfb4b2e81256bb01e96 From bc59dfa432417f693ae40ebd647d79072b52114f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 8 Jun 2011 15:32:32 -0700 Subject: [PATCH 53/64] rustc: Add some miscellaneous demands that pushdown had previously caught; put out burning tinderbox --- src/comp/middle/typeck.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 276c08f309469..17c9111349f79 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1628,6 +1628,8 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { assert (ast::is_call_expr(e)); check_expr(fcx, e); + demand::simple(fcx, e.span, fcx.ret_ty, expr_ty(fcx.ccx.tcx, e)); + write::nil_ty(fcx.ccx.tcx, a.id); } @@ -1713,7 +1715,11 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { auto lhs_t = expr_ty(fcx.ccx.tcx, lhs); alt (struct(fcx.ccx.tcx, lhs_t)) { case (ty::ty_chan(?it)) { item_t = it; } - case (_) { fail; } + case (_) { + fcx.ccx.tcx.sess.span_err(expr.span, + #fmt("mismatched types: expected chan but found %s", + ty_to_str(fcx.ccx.tcx, lhs_t))); + } } write::ty_only_fixup(fcx, a.id, chan_t); @@ -1742,6 +1748,9 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { auto thn_t = block_ty(fcx.ccx.tcx, thn); auto elsopt_t = expr_ty(fcx.ccx.tcx, els); + + demand::simple(fcx, expr.span, thn_t, elsopt_t); + if (!ty::type_is_bot(fcx.ccx.tcx, elsopt_t)) { elsopt_t } else { @@ -1790,6 +1799,9 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { check_expr(fcx, cond); check_block(fcx, body); + demand::simple(fcx, cond.span, ty::mk_bool(fcx.ccx.tcx), + expr_ty(fcx.ccx.tcx, cond)); + auto typ = ty::mk_nil(fcx.ccx.tcx); write::ty_only_fixup(fcx, a.id, typ); } From 16896508003d40fb629d5fd7ce816248407aa952 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 8 Jun 2011 15:49:46 -0700 Subject: [PATCH 54/64] rustc: Use cnames in ty_to_str again; debugging code crept in --- src/comp/middle/ty.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 97c2157b20ac1..78a3f69068f4b 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -546,12 +546,10 @@ fn ty_to_str(&ctxt cx, &t typ) -> str { ret mstr + ty_to_str(cx, m.ty); } - /*alt (cname(cx, typ)) { - case (some(?cs)) { - ret cs; - } - case (_) { } - }*/ + alt (cname(cx, typ)) { + case (some(?cs)) { ret cs; } + case (_) { /* fall through */ } + } auto s = ""; From 53248ce2e7b1a2fe92d0d2b6ac263e4da6140629 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 8 Jun 2011 15:57:56 -0700 Subject: [PATCH 55/64] Tidy up 'export meta' situation now that snapshot understands it. --- src/comp/rustc.rc | 13 ++++++++----- src/lib/std.rc | 8 ++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index b7911a634b59b..e082222fd4692 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -1,11 +1,14 @@ // -*- rust -*- -meta (name = "rustc", - desc = "The Rust compiler", - uuid = "0ce89b41-2f92-459e-bbc1-8f5fe32f16cf", - url = "http://rust-lang.org/src/rustc", - ver = "0.0.1"); +meta export (name = "rustc", + uuid = "0ce89b41-2f92-459e-bbc1-8f5fe32f16cf", + url = "http://rust-lang.org/src/rustc", + ver = "0.1"); + +meta (desc = "The Rust compiler", + license = "BSD"); + use std; diff --git a/src/lib/std.rc b/src/lib/std.rc index b35b150528d9c..ec6b23d866caf 100644 --- a/src/lib/std.rc +++ b/src/lib/std.rc @@ -1,7 +1,7 @@ -meta (name = "std", - vers = "0.1", - uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297", - url = "http://rust-lang.org/src/std"); +meta export (name = "std", + vers = "0.1", + uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297", + url = "http://rust-lang.org/src/std"); meta (comment = "Rust standard library", license = "BSD"); From 1a72745a0e6bd6511c5001c2c797165331268a0f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 8 Jun 2011 17:57:06 -0700 Subject: [PATCH 56/64] rustc: Don't generate so many variables when typechecking functions; remove mo_either --- src/comp/middle/alias.rs | 1 - src/comp/middle/ty.rs | 10 +---- src/comp/middle/typeck.rs | 90 +++++++++++++++++++++------------------ 3 files changed, 51 insertions(+), 50 deletions(-) diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index 9de830075ed9c..b433799ac3689 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -73,7 +73,6 @@ fn check_expr(ctx cx, &@ast::expr ex) { auto i = 0u; let vec[def_id] listed = []; for (ty::arg argty in argtys) { - // FIXME Treat mo_either specially here? if (argty.mode != ty::mo_val) { alt (check_rooted(cx, args.(i), false)) { case (some(?did)) { diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 78a3f69068f4b..0aa4a5c382190 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -42,7 +42,6 @@ import util::data::interner; tag mode { mo_val; mo_alias; - mo_either; } type arg = rec(mode mode, t ty); @@ -486,7 +485,6 @@ fn ty_to_str(&ctxt cx, &t typ) -> str { alt (input.mode) { case (mo_val) { s = ""; } case (mo_alias) { s = "&"; } - case (mo_either) { s = "?"; } } ret s + ty_to_str(cx, input.ty); @@ -1944,13 +1942,9 @@ mod unify { auto expected_input = expected_inputs.(i); auto actual_input = actual_inputs.(i); - // Unify the result modes. "mo_either" unifies with both modes. + // Unify the result modes. auto result_mode; - if (expected_input.mode == mo_either) { - result_mode = actual_input.mode; - } else if (actual_input.mode == mo_either) { - result_mode = expected_input.mode; - } else if (expected_input.mode != actual_input.mode) { + if (expected_input.mode != actual_input.mode) { // FIXME this is the wrong error ret fn_common_res_err(ures_err(terr_arg_count)); } else { diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 17c9111349f79..2f475b9a464fe 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -18,7 +18,6 @@ import middle::ty::field; import middle::ty::method; import middle::ty::mo_val; import middle::ty::mo_alias; -import middle::ty::mo_either; import middle::ty::node_type_table; import middle::ty::pat_ty; import middle::ty::path_to_str; @@ -1401,52 +1400,60 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { // A generic function to factor out common logic from call and bind // expressions. - fn check_call_or_bind(&@fn_ctxt fcx, &@ast::expr f, + fn check_call_or_bind(&@fn_ctxt fcx, &span sp, &@ast::expr f, &vec[option::t[@ast::expr]] args) { // Check the function. check_expr(fcx, f); - // Check the arguments and generate the argument signature. - let vec[option::t[@ast::expr]] args_0 = []; - let vec[arg] arg_tys_0 = []; + // Get the function type. We need to have resolved it enough to know + // it's a ty_fn or ty_native_fn. + auto fty = expr_ty(fcx.ccx.tcx, f); + fty = ty::unify::resolve_all_vars(fcx.ccx.tcx, fcx.var_bindings, fty); + + // Grab the argument types and the return type. + auto arg_tys; + alt (ty::struct(fcx.ccx.tcx, fty)) { + case (ty::ty_fn(_, ?arg_tys_0, _, _)) { + arg_tys = arg_tys_0; + } + case (ty::ty_native_fn(_, ?arg_tys_0, _)) { + arg_tys = arg_tys_0; + } + case (_) { + fcx.ccx.tcx.sess.span_err(f.span, "mismatched types: " + + "expected function or native function but found " + + ty_to_str(fcx.ccx.tcx, fty)); + } + } + + // Check that the correct number of arguments were supplied. + auto expected_arg_count = vec::len[ty::arg](arg_tys); + auto supplied_arg_count = vec::len[option::t[@ast::expr]](args); + if (expected_arg_count != supplied_arg_count) { + fcx.ccx.tcx.sess.span_err(sp, + #fmt("this function takes %u parameter%s but %u parameter%s \ + supplied", + expected_arg_count, + if (expected_arg_count == 1u) { "" } else { "s" }, + supplied_arg_count, + if (supplied_arg_count == 1u) { " was" } + else { "s were" })); + } + + // Check the arguments. + // TODO: iter2 + auto i = 0u; for (option::t[@ast::expr] a_opt in args) { alt (a_opt) { case (some(?a)) { check_expr(fcx, a); - auto typ = expr_ty(fcx.ccx.tcx, a); - vec::push[arg](arg_tys_0, rec(mode=mo_either, ty=typ)); + demand::simple(fcx, a.span, arg_tys.(i).ty, + expr_ty(fcx.ccx.tcx, a)); } - case (none) { - auto typ = next_ty_var(fcx); - vec::push[arg](arg_tys_0, rec(mode=mo_either, ty=typ)); - } - } - } - - auto rt_0 = next_ty_var(fcx); - auto t_0; - alt (struct(fcx.ccx.tcx, expr_ty(fcx.ccx.tcx, f))) { - case (ty::ty_fn(?proto, _, _, ?cf)) { - t_0 = ty::mk_fn(fcx.ccx.tcx, proto, arg_tys_0, rt_0, cf); - } - case (ty::ty_native_fn(?abi, _, _)) { - t_0 = ty::mk_native_fn(fcx.ccx.tcx, abi, arg_tys_0, rt_0); - } - case (?u) { - fcx.ccx.tcx.sess.span_err(f.span, - "check_call_or_bind(): fn expr doesn't have fn type," - + " instead having: " + - ty_to_str(fcx.ccx.tcx, - expr_ty(fcx.ccx.tcx, f))); + case (none) { /* no-op */ } } + i += 1u; } - - // Unify the callee and arguments. - auto f_ty = ty::expr_ty(fcx.ccx.tcx, f); - auto f_tps = ty::expr_ty_params_and_ty(fcx.ccx.tcx, f)._0; - auto tpt_1 = demand::full(fcx, f.span, f_ty, t_0, f_tps, - NO_AUTODEREF); - //replace_expr_type(fcx, f, tpt_1); } // A generic function for checking assignment expressions @@ -1461,14 +1468,15 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { } // A generic function for checking call expressions - fn check_call(&@fn_ctxt fcx, &@ast::expr f, &vec[@ast::expr] args) { + fn check_call(&@fn_ctxt fcx, &span sp, &@ast::expr f, + &vec[@ast::expr] args) { let vec[option::t[@ast::expr]] args_opt_0 = []; for (@ast::expr arg in args) { args_opt_0 += [some[@ast::expr](arg)]; } // Call the generic checker. - check_call_or_bind(fcx, f, args_opt_0); + check_call_or_bind(fcx, sp, f, args_opt_0); } // A generic function for checking for or for-each loops @@ -1861,7 +1869,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { case (ast::expr_bind(?f, ?args, ?a)) { // Call the generic checker. - check_call_or_bind(fcx, f, args); + check_call_or_bind(fcx, expr.span, f, args); // Pull the argument and return types out. auto proto_1; @@ -1904,7 +1912,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { function name onto purity-designation */ require_pure_call(fcx.ccx, fcx.purity, f, expr.span); - check_call(fcx, f, args); + check_call(fcx, expr.span, f, args); // Pull the return type out of the type of the function. auto rt_1 = ty::mk_nil(fcx.ccx.tcx); // FIXME: typestate botch @@ -1959,7 +1967,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { } case (ast::expr_spawn(_, _, ?f, ?args, ?a)) { - check_call(fcx, f, args); + check_call(fcx, expr.span, f, args); auto fty = expr_ty(fcx.ccx.tcx, f); auto ret_ty = ty::ret_ty_of_fn_ty(fcx.ccx.tcx, fty); From 9eb40818d30f147b3cb2c49068a63835f7bb82f9 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 8 Jun 2011 18:05:06 -0700 Subject: [PATCH 57/64] rustc: Make resolve_all_vars() check to see whether the type actually has vars before folding over it; also remove some debug code. 2x typechecking speedup. --- src/comp/middle/ty.rs | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 0aa4a5c382190..021f8e32b6c53 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -2099,38 +2099,31 @@ mod unify { // we eliminate pushdown. The typechecker should never rely on early // resolution of type variables. fn resolve_all_vars(&ty_ctxt tcx, &@var_bindings vb, t typ) -> t { - fn folder(ty_ctxt tcx, @var_bindings vb, @bool success, t typ) -> t { + if (!type_contains_vars(tcx, typ)) { ret typ; } + + fn folder(ty_ctxt tcx, @var_bindings vb, t typ) -> t { alt (struct(tcx, typ)) { case (ty_var(?vid)) { // It's possible that we haven't even created the var set. // Handle this case gracefully. if ((vid as uint) >= ufind::set_count(vb.sets)) { - *success = false; ret typ; + ret typ; } auto root_id = ufind::find(vb.sets, vid as uint); alt (smallintmap::find[t](vb.types, root_id)) { case (some[t](?typ2)) { - ret fold_ty(tcx, bind folder(tcx, vb, success, _), - typ2); + ret fold_ty(tcx, bind folder(tcx, vb, _), typ2); } - case (none[t]) { *success = false; ret typ; } + case (none[t]) { ret typ; } } - log ""; // fixes ambiguity - *success = false; ret typ; } case (_) { ret typ; } } } - auto success = @true; - auto rty = fold_ty(tcx, bind folder(tcx, vb, success, _), typ); - /*if (*success) { ret rty; } - log_err "*** failed! type " + ty::ty_to_str(tcx, typ) + " => " + - ty::ty_to_str(tcx, rty); - ret typ;*/ - ret rty; + ret fold_ty(tcx, bind folder(tcx, vb, _), typ); } fn unify_step(&@ctxt cx, &t expected, &t actual) -> result { From dbb3471af0ef6d94afdc2b88f92dd58c22d6f474 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 8 Jun 2011 18:41:46 -0700 Subject: [PATCH 58/64] rustc: Fix error pattern in compile-fail/arg-count-mismatch.rs --- src/test/compile-fail/arg-count-mismatch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/arg-count-mismatch.rs b/src/test/compile-fail/arg-count-mismatch.rs index 18f4104e33cae..103335380b21b 100644 --- a/src/test/compile-fail/arg-count-mismatch.rs +++ b/src/test/compile-fail/arg-count-mismatch.rs @@ -1,4 +1,4 @@ -// error-pattern: mismatched types +// error-pattern: parameters were supplied fn f(int x) { } From 7b09e2d3d2e4d9d0a880d0e2063c386b30e42cf8 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 8 Jun 2011 18:39:34 -0700 Subject: [PATCH 59/64] rustc: Don't eagerly resolve type variables after unification --- src/comp/middle/ty.rs | 19 ++++++++++ src/comp/middle/typeck.rs | 80 +++++++++++++++++++-------------------- 2 files changed, 59 insertions(+), 40 deletions(-) diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 021f8e32b6c53..3cd2602ed819f 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -2126,6 +2126,25 @@ mod unify { ret fold_ty(tcx, bind folder(tcx, vb, _), typ); } + // If the given type is a variable, returns the structure of that type. + fn resolve_type_structure(&ty_ctxt tcx, &@var_bindings vb, t typ) + -> fixup_result { + alt (struct(tcx, typ)) { + case (ty_var(?vid)) { + if ((vid as uint) >= ufind::set_count(vb.sets)) { + ret fix_err(vid); + } + + auto root_id = ufind::find(vb.sets, vid as uint); + alt (smallintmap::find[t](vb.types, root_id)) { + case (none[t]) { ret fix_err(vid); } + case (some[t](?rt)) { ret fix_ok(rt); } + } + } + case (_) { ret fix_ok(typ); } + } + } + fn unify_step(&@ctxt cx, &t expected, &t actual) -> result { // TODO: rewrite this using tuple pattern matching when available, to // avoid all this rightward drift and spikiness. diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 2f475b9a464fe..a76a377eae844 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -21,7 +21,6 @@ import middle::ty::mo_alias; import middle::ty::node_type_table; import middle::ty::pat_ty; import middle::ty::path_to_str; -import middle::ty::struct; import middle::ty::ty_param_substs_opt_and_ty; import middle::ty::ty_to_str; import middle::ty::type_is_integral; @@ -195,6 +194,19 @@ fn ast_mode_to_mode(ast::mode mode) -> ty::mode { ret ty_mode; } +// Returns the one-level-deep structure of the given type. +fn structure_of(&@fn_ctxt fcx, &span sp, ty::t typ) -> ty::sty { + auto r = ty::unify::resolve_type_structure(fcx.ccx.tcx, fcx.var_bindings, + typ); + alt (r) { + case (fix_ok(?typ_s)) { ret ty::struct(fcx.ccx.tcx, typ_s); } + case (fix_err(_)) { + fcx.ccx.tcx.sess.span_err(sp, "the type of this value must be " + + "known in this context"); + } + } +} + // Parses the programmer's textual representation of a type into our internal // notion of a type. `getter` is a function that returns the type // corresponding to a definition ID: @@ -810,20 +822,11 @@ mod collect { // Type unification +// TODO: rename to just "unify" mod unify { fn simple(&@fn_ctxt fcx, &ty::t expected, &ty::t actual) -> ty::unify::result { - auto result = ty::unify::unify(expected, actual, fcx.var_bindings, - fcx.ccx.tcx); - - // FIXME: Shouldn't be necessary, but is until we remove pushdown. - alt (result) { - case (ures_ok(?typ)) { - ret ures_ok(ty::unify::resolve_all_vars(fcx.ccx.tcx, - fcx.var_bindings, typ)); - } - case (_) { ret result; } - } + ret ty::unify::unify(expected, actual, fcx.var_bindings, fcx.ccx.tcx); } } @@ -833,10 +836,10 @@ tag autoderef_kind { NO_AUTODEREF; } -fn strip_boxes(&ty::ctxt tcx, &ty::t t) -> ty::t { +fn strip_boxes(&@fn_ctxt fcx, &span sp, &ty::t t) -> ty::t { auto t1 = t; while (true) { - alt (struct(tcx, t1)) { + alt (structure_of(fcx, sp, t1)) { case (ty::ty_box(?inner)) { t1 = inner.ty; } case (_) { ret t1; } } @@ -854,11 +857,11 @@ fn add_boxes(&@crate_ctxt ccx, uint n, &ty::t t) -> ty::t { } -fn count_boxes(&ty::ctxt tcx, &ty::t t) -> uint { +fn count_boxes(&@fn_ctxt fcx, &span sp, &ty::t t) -> uint { auto n = 0u; auto t1 = t; while (true) { - alt (struct(tcx, t1)) { + alt (structure_of(fcx, sp, t1)) { case (ty::ty_box(?inner)) { n += 1u; t1 = inner.ty; } case (_) { ret n; } } @@ -897,9 +900,9 @@ mod demand { auto implicit_boxes = 0u; if (adk == AUTODEREF_OK) { - expected_1 = strip_boxes(fcx.ccx.tcx, expected_1); - actual_1 = strip_boxes(fcx.ccx.tcx, actual_1); - implicit_boxes = count_boxes(fcx.ccx.tcx, actual); + expected_1 = strip_boxes(fcx, sp, expected_1); + actual_1 = strip_boxes(fcx, sp, actual_1); + implicit_boxes = count_boxes(fcx, sp, actual); } let vec[mutable ty::t] ty_param_substs = [mutable]; @@ -958,7 +961,7 @@ fn variant_arg_types(&@crate_ctxt ccx, &span sp, &ast::def_id vid, let vec[ty::t] result = []; auto tpt = ty::lookup_item_type(ccx.tcx, vid); - alt (struct(ccx.tcx, tpt._1)) { + alt (ty::struct(ccx.tcx, tpt._1)) { case (ty::ty_fn(_, ?ins, _, _)) { // N-ary variant. for (ty::arg arg in ins) { @@ -1272,7 +1275,7 @@ fn check_pat(&@fn_ctxt fcx, &@ast::pat pat, ty::t expected) { // Take the tag type params out of `expected`. auto expected_tps; - alt (struct(fcx.ccx.tcx, expected)) { + alt (structure_of(fcx, pat.span, expected)) { case (ty::ty_tag(_, ?tps)) { expected_tps = tps; } case (_) { // FIXME: Switch expected and actual in this message? I @@ -1405,14 +1408,12 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { // Check the function. check_expr(fcx, f); - // Get the function type. We need to have resolved it enough to know - // it's a ty_fn or ty_native_fn. + // Get the function type. auto fty = expr_ty(fcx.ccx.tcx, f); - fty = ty::unify::resolve_all_vars(fcx.ccx.tcx, fcx.var_bindings, fty); // Grab the argument types and the return type. auto arg_tys; - alt (ty::struct(fcx.ccx.tcx, fty)) { + alt (structure_of(fcx, sp, fty)) { case (ty::ty_fn(_, ?arg_tys_0, _, _)) { arg_tys = arg_tys_0; } @@ -1508,7 +1509,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { auto lhs_t = expr_ty(fcx.ccx.tcx, lhs); // FIXME: Binops have a bit more subtlety than this. - auto t = strip_boxes(fcx.ccx.tcx, lhs_t); + auto t = strip_boxes(fcx, expr.span, lhs_t); alt (binop) { case (ast::eq) { t = ty::mk_bool(fcx.ccx.tcx); } case (ast::lt) { t = ty::mk_bool(fcx.ccx.tcx); } @@ -1532,7 +1533,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { rec(ty=oper_t, mut=mut)); } case (ast::deref) { - alt (struct(fcx.ccx.tcx, oper_t)) { + alt (structure_of(fcx, expr.span, oper_t)) { case (ty::ty_box(?inner)) { oper_t = inner.ty; } case (_) { fcx.ccx.tcx.sess.span_err @@ -1542,7 +1543,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { } } } - case (_) { oper_t = strip_boxes(fcx.ccx.tcx, oper_t); } + case (_) { oper_t = strip_boxes(fcx, expr.span, oper_t); } } write::ty_only_fixup(fcx, a.id, oper_t); @@ -1721,7 +1722,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { auto item_t; auto lhs_t = expr_ty(fcx.ccx.tcx, lhs); - alt (struct(fcx.ccx.tcx, lhs_t)) { + alt (structure_of(fcx, expr.span, lhs_t)) { case (ty::ty_chan(?it)) { item_t = it; } case (_) { fcx.ccx.tcx.sess.span_err(expr.span, @@ -1775,8 +1776,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { case (ast::expr_for(?decl, ?seq, ?body, ?a)) { check_expr(fcx, seq); - alt (struct (fcx.ccx.tcx, - expr_ty(fcx.ccx.tcx, seq))) { + alt (structure_of(fcx, expr.span, expr_ty(fcx.ccx.tcx, seq))) { // FIXME: I include the check_for_or_each call in // each case because of a bug in typestate. // The bug is fixed; once there's a new snapshot, @@ -1877,7 +1877,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { auto rt_1; auto fty = expr_ty(fcx.ccx.tcx, f); auto t_1; - alt (struct(fcx.ccx.tcx, fty)) { + alt (structure_of(fcx, expr.span, fty)) { case (ty::ty_fn(?proto, ?arg_tys, ?rt, ?cf)) { proto_1 = proto; rt_1 = rt; @@ -1917,7 +1917,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { // Pull the return type out of the type of the function. auto rt_1 = ty::mk_nil(fcx.ccx.tcx); // FIXME: typestate botch auto fty = ty::expr_ty(fcx.ccx.tcx, f); - alt (struct(fcx.ccx.tcx, fty)) { + alt (structure_of(fcx, expr.span, fty)) { case (ty::ty_fn(_,_,?rt,_)) { rt_1 = rt; } case (ty::ty_native_fn(_, _, ?rt)) { rt_1 = rt; } case (_) { @@ -1949,7 +1949,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { } // Grab this method's type out of the current object type. - alt (struct(fcx.ccx.tcx, this_obj_ty)) { + alt (structure_of(fcx, expr.span, this_obj_ty)) { case (ty::ty_obj(?methods)) { for (ty::method method in methods) { if (method.ident == id) { @@ -2059,7 +2059,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { let vec[field] base_fields = []; - alt (struct(fcx.ccx.tcx, bexpr_t)) { + alt (structure_of(fcx, expr.span, bexpr_t)) { case (ty::ty_rec(?flds)) { base_fields = flds; } case (_) { fcx.ccx.tcx.sess.span_err @@ -2093,10 +2093,10 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { case (ast::expr_field(?base, ?field, ?a)) { check_expr(fcx, base); auto base_t = expr_ty(fcx.ccx.tcx, base); - base_t = strip_boxes(fcx.ccx.tcx, base_t); + base_t = strip_boxes(fcx, expr.span, base_t); base_t = ty::unify::resolve_all_vars(fcx.ccx.tcx, fcx.var_bindings, base_t); - alt (struct(fcx.ccx.tcx, base_t)) { + alt (structure_of(fcx, expr.span, base_t)) { case (ty::ty_tup(?args)) { let uint ix = ty::field_num(fcx.ccx.tcx.sess, expr.span, field); @@ -2142,11 +2142,11 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { case (ast::expr_index(?base, ?idx, ?a)) { check_expr(fcx, base); auto base_t = expr_ty(fcx.ccx.tcx, base); - base_t = strip_boxes(fcx.ccx.tcx, base_t); + base_t = strip_boxes(fcx, expr.span, base_t); check_expr(fcx, idx); auto idx_t = expr_ty(fcx.ccx.tcx, idx); - alt (struct(fcx.ccx.tcx, base_t)) { + alt (structure_of(fcx, expr.span, base_t)) { case (ty::ty_vec(?mt)) { if (! type_is_integral(fcx.ccx.tcx, idx_t)) { fcx.ccx.tcx.sess.span_err @@ -2184,7 +2184,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { case (ast::expr_chan(?x, ?a)) { check_expr(fcx, x); auto port_t = expr_ty(fcx.ccx.tcx, x); - alt (struct(fcx.ccx.tcx, port_t)) { + alt (structure_of(fcx, expr.span, port_t)) { case (ty::ty_port(?subtype)) { auto ct = ty::mk_chan(fcx.ccx.tcx, subtype); write::ty_only_fixup(fcx, a.id, ct); From da4e3b95c79c2795af4bdd8f008d9ad6697108e7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 8 Jun 2011 22:48:19 +0200 Subject: [PATCH 60/64] Add new visitor framework --- src/comp/middle/visit.rs | 381 ++++++++++++++++++++++++++++ src/comp/rustc.rc | 1 + src/test/compile-fail/unsafe-for.rs | 9 + 3 files changed, 391 insertions(+) create mode 100644 src/comp/middle/visit.rs create mode 100644 src/test/compile-fail/unsafe-for.rs diff --git a/src/comp/middle/visit.rs b/src/comp/middle/visit.rs new file mode 100644 index 0000000000000..79f74c8f3e890 --- /dev/null +++ b/src/comp/middle/visit.rs @@ -0,0 +1,381 @@ +import front::ast::*; +import std::option; +import std::option::some; +import std::option::none; +import util::common::span; + +// Lots of redundant indirection and refcounting. Our typesystem doesn't do +// circular types, so the visitor record can not hold functions that take +// visitors. A tag breaks the cycle. +tag vt[E] { vtor(visitor[E]); } +fn vt[E](&vt[E] x) -> visitor[E] { + alt (x) { case (vtor(?v)) { ret v; } } +} + +type visitor[E] = + @rec(fn(&_mod m, &span sp, &E e, &vt[E] v) visit_mod, + fn(&@native_item i, &E e, &vt[E] v) visit_native_item, + fn(&@item i, &E e, &vt[E] v) visit_item, + fn(&block b, &E e, &vt[E] v) visit_block, + fn(&@stmt s, &E e, &vt[E] v) visit_stmt, + fn(&arm a, &E e, &vt[E] v) visit_arm, + fn(&@pat p, &E e, &vt[E] v) visit_pat, + fn(&@decl d, &E e, &vt[E] v) visit_decl, + fn(&@expr ex, &E e, &vt[E] v) visit_expr, + fn(&@ty t, &E e, &vt[E] v) visit_ty, + fn(&_fn f, &span sp, &ident name, + &def_id d_id, &ann a, + &E e, &vt[E] v) visit_fn); + +fn default_visitor[E]() -> visitor[E] { + ret @rec(visit_mod = bind visit_mod[E](_, _, _, _), + visit_native_item = bind visit_native_item[E](_, _, _), + visit_item = bind visit_item[E](_, _, _), + visit_block = bind visit_block[E](_, _, _), + visit_stmt = bind visit_stmt[E](_, _, _), + visit_arm = bind visit_arm[E](_, _, _), + visit_pat = bind visit_pat[E](_, _, _), + visit_decl = bind visit_decl[E](_, _, _), + visit_expr = bind visit_expr[E](_, _, _), + visit_ty = bind visit_ty[E](_, _, _), + visit_fn = bind visit_fn[E](_, _, _, _, _, _, _)); +} + +fn visit_crate[E](&crate c, &E e, &vt[E] v) { + vt(v).visit_mod(c.node.module, c.span, e, v); +} + +fn visit_mod[E](&_mod m, &span sp, &E e, &vt[E] v) { + for (@item i in m.items) { + vt(v).visit_item(i, e, v); + } +} + +fn visit_item[E](&@item i, &E e, &vt[E] v) { + alt (i.node) { + case (item_const(_, ?t, ?ex, _, _)) { + vt(v).visit_ty(t, e, v); + vt(v).visit_expr(ex, e, v); + } + case (item_fn(?nm, ?f, _, ?d, ?a)) { + vt(v).visit_fn(f, i.span, nm, d, a, e, v); + } + case (item_mod(_, ?m, _)) { + vt(v).visit_mod(m, i.span, e, v); + } + case (item_native_mod(_, ?nm, _)) { + for (@native_item ni in nm.items) { + vt(v).visit_native_item(ni, e, v); + } + } + case (item_ty(_, ?t, _, _, _)) { + vt(v).visit_ty(t, e, v); + } + case (item_tag(_, ?variants, _, _, _)) { + for (variant vr in variants) { + for (variant_arg va in vr.node.args) { + vt(v).visit_ty(va.ty, e, v); + } + } + } + case (item_obj(_, ?ob, _, _, _)) { + for (obj_field f in ob.fields) { + vt(v).visit_ty(f.ty, e, v); + } + for (@method m in ob.methods) { + vt(v).visit_fn(m.node.meth, m.span, m.node.ident, m.node.id, + m.node.ann, e, v); + } + alt (ob.dtor) { + case (none) {} + case (some(?m)) { + vt(v).visit_fn(m.node.meth, m.span, m.node.ident, + m.node.id, m.node.ann, e, v); + } + } + } + + } +} + +fn visit_ty[E](&@ty t, &E e, &vt[E] v) { + alt (t.node) { + case (ty_box(?mt)) { vt(v).visit_ty(mt.ty, e, v); } + case (ty_vec(?mt)) { vt(v).visit_ty(mt.ty, e, v); } + case (ty_ptr(?mt)) { vt(v).visit_ty(mt.ty, e, v); } + case (ty_port(?t)) { vt(v).visit_ty(t, e, v); } + case (ty_chan(?t)) { vt(v).visit_ty(t, e, v); } + case (ty_tup(?mts)) { + for (mt mt in mts) { + vt(v).visit_ty(mt.ty, e, v); + } + } + case (ty_rec(?flds)) { + for (ty_field f in flds) { + vt(v).visit_ty(f.node.mt.ty, e, v); + } + } + case (ty_fn(_, ?args, ?out, _)) { + for (ty_arg a in args) { + vt(v).visit_ty(a.node.ty, e, v); + } + vt(v).visit_ty(out, e, v); + } + case (ty_obj(?tmeths)) { + for (ty_method m in tmeths) { + for (ty_arg a in m.node.inputs) { + vt(v).visit_ty(a.node.ty, e, v); + } + vt(v).visit_ty(m.node.output, e, v); + } + } + case (ty_path(?p, _)) { + for (@ty tp in p.node.types) { + vt(v).visit_ty(tp, e, v); + } + } + case (ty_constr(?t, _)) { vt(v).visit_ty(t, e, v); } + case (_) {} + } +} + +fn visit_pat[E](&@pat p, &E e, &vt[E] v) { + alt (p.node) { + case (pat_tag(?path, ?children, _)) { + for (@pat child in children) { + vt(v).visit_pat(child, e, v); + } + } + case (_) {} + } +} + +fn visit_native_item[E](&@native_item ni, &E e, &vt[E] v) { + alt (ni.node) { + case (native_item_fn(_, _, ?fd, _, _, _)) { + visit_fn_decl(fd, e, v); + } + case (native_item_ty(_, _)) {} + } +} + +fn visit_fn_decl[E](&fn_decl fd, &E e, &vt[E] v) { + for (arg a in fd.inputs) { + vt(v).visit_ty(a.ty, e, v); + } + vt(v).visit_ty(fd.output, e, v); +} + +fn visit_fn[E](&_fn f, &span sp, &ident i, &def_id d, &ann a, + &E e, &vt[E] v) { + visit_fn_decl(f.decl, e, v); + vt(v).visit_block(f.body, e, v); +} + +fn visit_block[E](&block b, &E e, &vt[E] v) { + for (@stmt s in b.node.stmts) { vt(v).visit_stmt(s, e, v); } + visit_expr_opt(b.node.expr, e, v); +} + +fn visit_stmt[E](&@stmt s, &E e, &vt[E] v) { + alt (s.node) { + case (stmt_decl(?d, _)) { vt(v).visit_decl(d, e, v); } + case (stmt_expr(?ex, _)) { vt(v).visit_expr(ex, e, v); } + case (stmt_crate_directive(?cdir)) {} + } +} + +fn visit_decl[E](&@decl d, &E e, &vt[E] v) { + alt (d.node) { + case (decl_local(?loc)) { + alt (loc.ty) { + case (none) {} + case (some(?t)) { vt(v).visit_ty(t, e, v); } + } + alt (loc.init) { + case (none) {} + case (some(?i)) { vt(v).visit_expr(i.expr, e, v); } + } + } + case (decl_item(?it)) { vt(v).visit_item(it, e, v); } + } +} + +fn visit_expr_opt[E](option::t[@expr] eo, &E e, &vt[E] v) { + alt (eo) { + case (none) {} + case (some(?ex)) { vt(v).visit_expr(ex, e, v); + } + } +} + +fn visit_exprs[E](vec[@expr] exprs, &E e, &vt[E] v) { + for (@expr ex in exprs) { vt(v).visit_expr(ex, e, v); } +} + +fn visit_expr[E](&@expr ex, &E e, &vt[E] v) { + alt (ex.node) { + case (expr_vec(?es, _, _)) { + visit_exprs(es, e, v); + } + case (expr_tup(?elts, _)) { + for (elt el in elts) { vt(v).visit_expr(el.expr, e, v); } + } + case (expr_rec(?flds, ?base, _)) { + for (field f in flds) { vt(v).visit_expr(f.node.expr, e, v); } + visit_expr_opt(base, e, v); + } + case (expr_call(?callee, ?args, _)) { + vt(v).visit_expr(callee, e, v); + visit_exprs(args, e, v); + } + case (expr_self_method(_, _)) { } + case (expr_bind(?callee, ?args, _)) { + vt(v).visit_expr(callee, e, v); + for (option::t[@expr] eo in args) { visit_expr_opt(eo, e, v); } + } + case (expr_spawn(_, _, ?callee, ?args, _)) { + vt(v).visit_expr(callee, e, v); + visit_exprs(args, e, v); + } + case (expr_binary(_, ?a, ?b, _)) { + vt(v).visit_expr(a, e, v); + vt(v).visit_expr(b, e, v); + } + case (expr_unary(_, ?a, _)) { + vt(v).visit_expr(a, e, v); + } + case (expr_lit(_, _)) { } + case (expr_cast(?x, ?t, _)) { + vt(v).visit_expr(x, e, v); + vt(v).visit_ty(t, e, v); + } + case (expr_if(?x, ?b, ?eo, _)) { + vt(v).visit_expr(x, e, v); + vt(v).visit_block(b, e, v); + visit_expr_opt(eo, e, v); + } + case (expr_while(?x, ?b, _)) { + vt(v).visit_expr(x, e, v); + vt(v).visit_block(b, e, v); + } + case (expr_for(?dcl, ?x, ?b, _)) { + vt(v).visit_decl(dcl, e, v); + vt(v).visit_expr(x, e, v); + vt(v).visit_block(b, e, v); + } + case (expr_for_each(?dcl, ?x, ?b, _)) { + vt(v).visit_decl(dcl, e, v); + vt(v).visit_expr(x, e, v); + vt(v).visit_block(b, e, v); + } + case (expr_do_while(?b, ?x, _)) { + vt(v).visit_block(b, e, v); + vt(v).visit_expr(x, e, v); + } + case (expr_alt(?x, ?arms, _)) { + vt(v).visit_expr(x, e, v); + for (arm a in arms) { + vt(v).visit_arm(a, e, v); + } + } + case (expr_block(?b, _)) { + vt(v).visit_block(b, e, v); + } + case (expr_assign(?a, ?b, _)) { + vt(v).visit_expr(b, e, v); + vt(v).visit_expr(a, e, v); + } + case (expr_move(?a, ?b, _)) { + vt(v).visit_expr(b, e, v); + vt(v).visit_expr(a, e, v); + } + case (expr_assign_op(_, ?a, ?b, _)) { + vt(v).visit_expr(b, e, v); + vt(v).visit_expr(a, e, v); + } + case (expr_send(?a, ?b, _)) { + vt(v).visit_expr(a, e, v); + vt(v).visit_expr(b, e, v); + } + case (expr_recv(?a, ?b, _)) { + vt(v).visit_expr(a, e, v); + vt(v).visit_expr(b, e, v); + } + case (expr_field(?x, _, _)) { + vt(v).visit_expr(x, e, v); + } + case (expr_index(?a, ?b, _)) { + vt(v).visit_expr(a, e, v); + vt(v).visit_expr(b, e, v); + } + case (expr_path(?p, _)) { + for (@ty tp in p.node.types) { + vt(v).visit_ty(tp, e, v); + } + } + case (expr_ext(_, _, _, ?expansion, _)) { + vt(v).visit_expr(expansion, e, v); + } + case (expr_fail(_, _)) { } + case (expr_break(_)) { } + case (expr_cont(_)) { } + case (expr_ret(?eo, _)) { + visit_expr_opt(eo, e, v); + } + case (expr_put(?eo, _)) { + visit_expr_opt(eo, e, v); + } + case (expr_be(?x, _)) { + vt(v).visit_expr(x, e, v); + } + case (expr_log(_,?x, _)) { + vt(v).visit_expr(x, e, v); + } + case (expr_check(?x, _)) { + vt(v).visit_expr(x, e, v); + } + case (expr_assert(?x, _)) { + vt(v).visit_expr(x, e, v); + } + case (expr_port(_)) { } + case (expr_chan(?x, _)) { + vt(v).visit_expr(x, e, v); + } + + case (expr_anon_obj(?anon_obj,_,_,_)) { + alt (anon_obj.fields) { + case (none) { } + case (some(?fields)) { + for (obj_field f in fields) { + vt(v).visit_ty(f.ty, e, v); + } + } + } + alt (anon_obj.with_obj) { + case (none) { } + case (some(?ex)) { + vt(v).visit_expr(ex, e, v); + } + } + for (@method m in anon_obj.methods) { + vt(v).visit_fn(m.node.meth, m.span, m.node.ident, + m.node.id, m.node.ann, e, v); + } + } + } +} + +fn visit_arm[E](&arm a, &E e, &vt[E] v) { + vt(v).visit_pat(a.pat, e, v); + vt(v).visit_block(a.block, e, v); +} + +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index e082222fd4692..1b323182cf0cd 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -16,6 +16,7 @@ mod middle { mod trans; mod ty; mod walk; + mod visit; mod metadata; mod resolve; mod typeck; diff --git a/src/test/compile-fail/unsafe-for.rs b/src/test/compile-fail/unsafe-for.rs new file mode 100644 index 0000000000000..bc050173bc0df --- /dev/null +++ b/src/test/compile-fail/unsafe-for.rs @@ -0,0 +1,9 @@ +// error-pattern:invalidate alias x + +fn main() { + let vec[mutable int] v = [mutable 1, 2, 3]; + for (int x in v) { + v.(0) = 10; + log x; + } +} From 5335ffd84d6a2111f58a18e4b2faf7629239de55 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 9 Jun 2011 09:30:46 +0200 Subject: [PATCH 61/64] Some more workarounds to please the alias checker Some of the vec utilities now only work on immutable vecs, since they would have to be rewritten to do a lot more copying to be alias-safe. Some forced copying was added to map.rs, showing a weakness in the alias checker (or maybe the alias system): when fn args are passed into a function, calling them must assume all aliases that are not immutably rooted (directly connected to a local or temporary without any mutable edges) become invalid. This will be a drag on functional programming in Rust. Work around alias issues in the stdlib --- src/comp/back/link.rs | 3 ++- src/lib/map.rs | 18 ++++++++++++------ src/lib/sort.rs | 12 ++++++------ src/lib/ufind.rs | 2 +- src/lib/vec.rs | 12 ++++++------ 5 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index b637b7e41b851..81c0f5a265a15 100644 --- a/src/comp/back/link.rs +++ b/src/comp/back/link.rs @@ -339,7 +339,8 @@ fn crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str { } sort::quick_sort(lteq, v); sha.reset(); - for (@ast::meta_item m in v) { + for (@ast::meta_item m_ in v) { + auto m = m_; sha.input_str(len_and_str(m.node.name)); sha.input_str(len_and_str(m.node.value)); } diff --git a/src/lib/map.rs b/src/lib/map.rs index 3b7f01acbe19c..396835bc1d693 100644 --- a/src/lib/map.rs +++ b/src/lib/map.rs @@ -76,8 +76,10 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] { let uint j = hash(h, nbkts, i); alt (bkts.(j)) { case (some(?k, _)) { - if (eqer(key, k)) { - bkts.(j) = some[K, V](k, val); + // Copy key to please alias analysis. + auto k_ = k; + if (eqer(key, k_)) { + bkts.(j) = some[K, V](k_, val); ret false; } i += 1u; @@ -104,8 +106,11 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] { let uint j = (hash(h, nbkts, i)); alt (bkts.(j)) { case (some(?k, ?v)) { - if (eqer(key, k)) { - ret option::some[V](v); + // Copy to please alias analysis. + auto k_ = k; + auto v_ = v; + if (eqer(key, k_)) { + ret option::some[V](v_); } } case (nil) { @@ -190,10 +195,11 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] { let uint j = (hash(h, nbkts, i)); alt (bkts.(j)) { case (some(?k, ?v)) { - if (eqer(key, k)) { + auto k_ = k; auto vo = option::some(v); + if (eqer(key, k_)) { bkts.(j) = deleted[K, V]; nelts -= 1u; - ret option::some[V](v); + ret vo; } } case (deleted) { } diff --git a/src/lib/sort.rs b/src/lib/sort.rs index ede8d229fa599..8a16c1858becb 100644 --- a/src/lib/sort.rs +++ b/src/lib/sort.rs @@ -58,7 +58,7 @@ fn part[T](lteq[T] compare_func, vec[mutable T] arr, uint left, let uint storage_index = left; let uint i = left; while (i uint { alt (ufnd.nodes.(n)) { case (none) { ret n; } - case (some(?m)) { be find(ufnd, m); } + case (some(?m)) { auto m_ = m; be find(ufnd, m_); } } } diff --git a/src/lib/vec.rs b/src/lib/vec.rs index 2f82f330446eb..3cc4db83b5498 100644 --- a/src/lib/vec.rs +++ b/src/lib/vec.rs @@ -241,7 +241,7 @@ fn grow_init_fn_set[T](&array[T] v, uint index, fn()->T init_fn, &T val) { } -fn map[T, U](&fn(&T) -> U f, &array[T] v) -> vec[U] { +fn map[T, U](&fn(&T) -> U f, &vec[T] v) -> vec[U] { let vec[U] res = alloc[U](len[T](v)); for (T ve in v) { res += [f(ve)]; @@ -249,8 +249,8 @@ fn map[T, U](&fn(&T) -> U f, &array[T] v) -> vec[U] { ret res; } -fn filter_map[T, U](&fn(&T) -> option::t[U] f, &array[T] v) -> vec[U] { - let vec[U] res = []; //TODO does this work these days? +fn filter_map[T, U](&fn(&T) -> option::t[U] f, &vec[T] v) -> vec[U] { + let vec[U] res = []; for(T ve in v) { alt(f(ve)) { case (some(?elt)) { res += [elt]; } @@ -260,7 +260,7 @@ fn filter_map[T, U](&fn(&T) -> option::t[U] f, &array[T] v) -> vec[U] { ret res; } -fn map2[T,U,V](&operator2[T,U,V] f, &array[T] v0, &array[U] v1) -> vec[V] { +fn map2[T,U,V](&operator2[T,U,V] f, &vec[T] v0, &vec[U] v1) -> vec[V] { auto v0_len = len[T](v0); if (v0_len != len[U](v1)) { fail; @@ -269,14 +269,14 @@ fn map2[T,U,V](&operator2[T,U,V] f, &array[T] v0, &array[U] v1) -> vec[V] { let vec[V] u = alloc[V](v0_len); auto i = 0u; while (i < v0_len) { - u += [f(v0.(i), v1.(i))]; + u += [f({v0.(i)}, {v1.(i)})]; i += 1u; } ret u; } -fn find[T](fn (&T) -> bool f, &array[T] v) -> option::t[T] { +fn find[T](fn (&T) -> bool f, &vec[T] v) -> option::t[T] { for (T elt in v) { if (f(elt)) { ret some[T](elt); From 25b033866096fb492d570ba653f82457a3f01804 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 9 Jun 2011 10:58:31 +0200 Subject: [PATCH 62/64] Add vec::member --- src/lib/vec.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib/vec.rs b/src/lib/vec.rs index 3cc4db83b5498..742562f17a93f 100644 --- a/src/lib/vec.rs +++ b/src/lib/vec.rs @@ -286,6 +286,13 @@ fn find[T](fn (&T) -> bool f, &vec[T] v) -> option::t[T] { ret none[T]; } +fn member[T](&T x, &array[T] v) -> bool { + for (T elt in v) { + if (x == elt) { ret true; } + } + ret false; +} + fn foldl[T, U](fn (&U, &T) -> U p, &U z, &vec[T] v) -> U { auto sz = len[T](v); From c70792dfae60e0dfa275da8300ed1df05e5233ff Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 7 Jun 2011 11:20:51 +0200 Subject: [PATCH 63/64] A revised, improved alias-checker The old system tried to ensure that the location an alias pointed at would retain its type. That turned out to not be strong enough in the face of aliases to the inside of tags. The new system instead proves that values pointed to by aliases are not replaced (or invalidated in some other way) at all. It knows of two sufficient conditions for this, and tries to prove at least of them: A) The alias is 'immutably rooted' in a local, and this local is not reassigned for the lifetime of the alias. Immutably rooted means the alias refers to the local itself, or to something reachable from the local through immutable dereferencing. B) No value whose type might include the type of the 'inner mutable element' of the thing the alias refers to (for example, the box in rec(mutable x = @mutable int)) is from the outer scope is accessed for the lifetime of the alias. This means for functions, no other argument types may include the alias's inner mutable type. For alt, for each, and for, it means the body does not refer to any locals originating from outside their scope that include this type. The lifetime of an alias in an alt, for each, or for body is defined as the range from its definition to its last use, not to the point where it goes out of scope. This makes working around these restrictions somewhat less annoying. For example, you can assign to your alt-ed value you don't refer to any bindings afterwards. --- src/comp/front/ast.rs | 4 + src/comp/middle/alias.rs | 543 +++++++++++++++++------- src/comp/middle/resolve.rs | 2 +- src/test/compile-fail/unsafe-alias-2.rs | 15 + src/test/compile-fail/unsafe-alias.rs | 10 +- src/test/compile-fail/unsafe-alt.rs | 3 +- 6 files changed, 423 insertions(+), 154 deletions(-) create mode 100644 src/test/compile-fail/unsafe-alias-2.rs diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 4f83ee7fa8d72..fce15a556c6fd 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -11,6 +11,10 @@ type ident = str; type path_ = rec(vec[ident] idents, vec[@ty] types); type path = spanned[path_]; +fn path_name(&path p) -> str { + ret str::connect(p.node.idents, "::"); +} + type crate_num = int; const crate_num local_crate = 0; type def_num = int; diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index b433799ac3689..fa978ef53c03b 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -1,209 +1,388 @@ import front::ast; import front::ast::ident; -import front::ast::def_id; +import front::ast::def_num; +import util::common::span; +import visit::vt; import std::vec; import std::str; import std::option; import std::option::some; import std::option::none; +import std::option::is_none; -tag deref_t { - field(ident); - index; - unbox; +tag valid { + valid; + overwritten(span, ast::path); + val_taken(span, ast::path); } -type deref = rec(bool mut, deref_t t); -type ctx = @rec(@ty::ctxt tcx, - resolve::def_map dm, - // The current blacklisted (non-assignable) locals - mutable vec[vec[def_id]] bl, - // A stack of blacklists for outer function scopes - mutable vec[vec[vec[def_id]]] blstack); +type restrict = @rec(vec[def_num] root_vars, + def_num block_defnum, + vec[def_num] bindings, + vec[ty::t] tys, + mutable valid ok); + +type scope = vec[restrict]; +type ctx = rec(@ty::ctxt tcx, + resolve::def_map dm); fn check_crate(@ty::ctxt tcx, resolve::def_map dm, &@ast::crate crate) { - auto cx = @rec(tcx = tcx, - dm = dm, - mutable bl = vec::empty[vec[def_id]](), - mutable blstack = vec::empty[vec[vec[def_id]]]()); - auto v = rec(visit_item_pre = bind enter_item(cx, _), - visit_item_post = bind leave_item(cx, _), - visit_method_pre = bind enter_method(cx, _), - visit_method_post = bind leave_method(cx, _), - visit_expr_pre = bind check_expr(cx, _), - visit_expr_post = bind leave_expr(cx, _) - with walk::default_visitor()); - walk::walk_crate(v, *crate); -} - -fn enter_item(ctx cx, &@ast::item it) { - alt (it.node) { - case (ast::item_fn(_, _, _, _, _)) { - vec::push(cx.blstack, cx.bl); - cx.bl = []; - } - case (_) {} - } -} -fn leave_item(ctx cx, &@ast::item it) { - alt (it.node) { - case (ast::item_fn(_, _, _, _, _)) { - cx.bl = vec::pop(cx.blstack); - } - case (_) {} - } + auto cx = @rec(tcx = tcx, dm = dm); + auto v = @rec(visit_fn = visit_fn, + visit_expr = bind visit_expr(cx, _, _, _) + with *visit::default_visitor[scope]()); + visit::visit_crate(*crate, [], visit::vtor(v)); } -fn enter_method(ctx cx, &@ast::method mt) { - vec::push(cx.blstack, cx.bl); - cx.bl = []; -} -fn leave_method(ctx cx, &@ast::method mt) { - cx.bl = vec::pop(cx.blstack); +fn visit_fn(&ast::_fn f, &span sp, &ident name, &ast::def_id d_id, + &ast::ann a, &scope sc, &vt[scope] v) { + visit::visit_fn_decl(f.decl, sc, v); + vt(v).visit_block(f.body, [], v); } -fn check_expr(ctx cx, &@ast::expr ex) { +fn visit_expr(&@ctx cx, &@ast::expr ex, &scope sc, &vt[scope] v) { + auto handled = false; alt (ex.node) { case (ast::expr_call(?f, ?args, _)) { - auto fty = ty::expr_ty(*cx.tcx, f); - auto argtys = alt (ty::struct(*cx.tcx, fty)) { - case (ty::ty_fn(_, ?args, _, _)) { args } - case (ty::ty_native_fn(_, ?args, _)) { args } - }; - auto i = 0u; - let vec[def_id] listed = []; - for (ty::arg argty in argtys) { - if (argty.mode != ty::mo_val) { - alt (check_rooted(cx, args.(i), false)) { - case (some(?did)) { - vec::push(listed, did); - } - case (_) {} - } - } - i += 1u; - } - // FIXME when mutable aliases can be distinguished, go over the - // args again and ensure that we're not passing a blacklisted - // variable by mutable alias (using 'listed' and the context - // blacklist). + check_call(*cx, f, args, sc); + } + case (ast::expr_alt(?input, ?arms, _)) { + check_alt(*cx, input, arms, sc, v); + handled = true; } case (ast::expr_put(?val, _)) { alt (val) { - case (some(?ex)) { check_rooted(cx, ex, false); } + case (some(?ex)) { + auto root = expr_root(*cx, ex, false); + if (!is_none(root.inner_mut)) { + cx.tcx.sess.span_err + (ex.span, + "result of put must be immutably rooted"); + } + visit_expr(cx, ex, sc, v); + } case (_) {} } + handled = true; + } + case (ast::expr_for_each(?decl, ?call, ?block, _)) { + check_for_each(*cx, decl, call, block, sc, v); + handled = true; } - case (ast::expr_alt(?input, _, _)) { - vec::push(cx.bl, alt (check_rooted(cx, input, true)) { - case (some(?did)) { [did] } - case (_) { vec::empty[def_id]() } - }); + case (ast::expr_for(?decl, ?seq, ?block, _)) { + check_for(*cx, decl, seq, block, sc, v); + handled = true; + } + + case (ast::expr_path(?pt, ?ann)) { + check_var(*cx, ex, pt, ann, false, sc); + } + case (ast::expr_move(?dest, ?src, _)) { + check_assign(cx, dest, src, sc, v); + handled = true; + } + case (ast::expr_assign(?dest, ?src, _)) { + check_assign(cx, dest, src, sc, v); + handled = true; + } + case (ast::expr_assign_op(_, ?dest, ?src, _)) { + check_assign(cx, dest, src, sc, v); + handled = true; } - case (ast::expr_move(?dest, _, _)) { check_assign(cx, dest); } - case (ast::expr_assign(?dest, _, _)) { check_assign(cx, dest); } - case (ast::expr_assign_op(_, ?dest, _, _)) { check_assign(cx, dest); } case (_) {} } + if (!handled) { visit::visit_expr(ex, sc, v); } } -fn leave_expr(ctx cx, &@ast::expr ex) { - alt (ex.node) { - case (ast::expr_alt(_, _, _)) { vec::pop(cx.bl); } - case (_) {} +fn check_call(&ctx cx, &@ast::expr f, &vec[@ast::expr] args, &scope sc) + -> rec(vec[def_num] root_vars, vec[ty::t] unsafe_ts) { + auto fty = ty::expr_ty(*cx.tcx, f); + auto arg_ts = alt (ty::struct(*cx.tcx, fty)) { + case (ty::ty_fn(_, ?args, _, _)) { args } + case (ty::ty_native_fn(_, ?args, _)) { args } + }; + + auto i = 0u; + let vec[def_num] roots = []; + let vec[ty::t] unsafe_ts = []; + let vec[uint] unsafe_t_offsets = []; + for (ty::arg arg_t in arg_ts) { + if (arg_t.mode != ty::mo_val) { + auto root = expr_root(cx, args.(i), false); + alt (path_def_id(cx, root.ex)) { + case (some(?did)) { vec::push(roots, did._1); } + case (_) {} + } + alt (root.inner_mut) { + case (some(?t)) { + vec::push(unsafe_ts, t); + vec::push(unsafe_t_offsets, i); + } + case (_) {} + } + } + i += 1u; } + + if (vec::len(unsafe_ts) > 0u) { + alt (f.node) { + case (ast::expr_path(_, ?ann)) { + if (def_is_local(cx.dm.get(ann.id))) { + cx.tcx.sess.span_err + (f.span, #fmt("function may alias with argument \ + %u, which is not immutably rooted", + unsafe_t_offsets.(0))); + } + } + case (_) {} + } + } + auto j = 0u; + for (ty::t unsafe in unsafe_ts) { + auto offset = unsafe_t_offsets.(j); + j += 1u; + auto i = 0u; + for (ty::arg arg_t in arg_ts) { + if (i != offset && + // FIXME false should be replace with mutability of alias + ty_can_unsafely_include(cx, unsafe, arg_t.ty, false)) { + cx.tcx.sess.span_err + (args.(i).span, #fmt("argument %u may alias with \ + argument %u, which is not immutably rooted", i, offset)); + } + i += 1u; + } + } + // FIXME when mutable aliases can be distinguished, go over the args again + // and ensure that we're not passing a root variable by mutable alias + // (using roots and the scope root vars). + + ret rec(root_vars = roots, unsafe_ts = unsafe_ts); } -fn check_assign(&ctx cx, &@ast::expr ex) { - alt (ex.node) { - case (ast::expr_path(?pt, ?ann)) { - auto did = ast::def_id_of_def(cx.dm.get(ann.id)); - for (vec[def_id] layer in cx.bl) { - for (def_id black in layer) { - if (did == black) { - cx.tcx.sess.span_err - (ex.span, str::connect(pt.node.idents, "::") + - " is being aliased and may not be assigned to"); - } +fn check_alt(&ctx cx, &@ast::expr input, &vec[ast::arm] arms, + &scope sc, &vt[scope] v) { + visit::visit_expr(input, sc, v); + auto root = expr_root(cx, input, true); + auto roots = alt (path_def_id(cx, root.ex)) { + case (some(?did)) { [did._1] } + case (_) { [] } + }; + let vec[ty::t] forbidden_tp = alt (root.inner_mut) { + case (some(?t)) { [t] } + case (_) { [] } + }; + + for (ast::arm a in arms) { + auto dnums = arm_defnums(a); + auto new_sc = sc; + if (vec::len(dnums) > 0u) { + vec::push(new_sc, @rec(root_vars=roots, + block_defnum=dnums.(0), + bindings=dnums, + tys=forbidden_tp, + mutable ok=valid)); + } + visit::visit_arm(a, new_sc, v); + } +} + +fn arm_defnums(&ast::arm arm) -> vec[def_num] { + auto dnums = []; + fn walk_pat(&mutable vec[def_num] found, &@ast::pat p) { + alt (p.node) { + case (ast::pat_bind(_, ?did, _)) { + vec::push(found, did._1); + } + case (ast::pat_tag(_, ?children, _)) { + for (@ast::pat child in children) { + walk_pat(found, child); } } + case (_) {} } - case (_) {} } + walk_pat(dnums, arm.pat); + ret dnums; } -fn check_rooted(&ctx cx, &@ast::expr ex, bool autoderef) - -> option::t[def_id] { - auto root = expr_root(cx, ex, autoderef); - if (has_unsafe_box(root.ds)) { - cx.tcx.sess.span_err - (ex.span, "can not create alias to improperly anchored value"); +fn check_for_each(&ctx cx, &@ast::decl decl, &@ast::expr call, + &ast::block block, &scope sc, &vt[scope] v) { + visit::visit_expr(call, sc, v); + alt (call.node) { + case (ast::expr_call(?f, ?args, _)) { + auto data = check_call(cx, f, args, sc); + auto defnum = alt (decl.node) { + case (ast::decl_local(?l)) { l.id._1 } + }; + + auto new_sc = @rec(root_vars=data.root_vars, + block_defnum=defnum, + bindings=[defnum], + tys=data.unsafe_ts, + mutable ok=valid); + visit::visit_block(block, sc + [new_sc], v); + } } - alt (root.ex.node) { - case (ast::expr_path(_, ?ann)) { - ret some(ast::def_id_of_def(cx.dm.get(ann.id))); +} + +fn check_for(&ctx cx, &@ast::decl decl, &@ast::expr seq, + &ast::block block, &scope sc, &vt[scope] v) { + visit::visit_expr(seq, sc, v); + auto defnum = alt (decl.node) { + case (ast::decl_local(?l)) { l.id._1 } + }; + + auto root = expr_root(cx, seq, false); + auto root_def = alt (path_def_id(cx, root.ex)) { + case (some(?did)) { [did._1] } + case (_) { [] } + }; + auto unsafe = alt (root.inner_mut) { + case (some(?t)) { [t] } + case (_) { [] } + }; + // If this is a mutable vector, don't allow it to be touched. + auto seq_t = ty::expr_ty(*cx.tcx, seq); + alt (ty::struct(*cx.tcx, seq_t)) { + case (ty::ty_vec(?mt)) { + if (mt.mut != ast::imm) { unsafe = [seq_t]; } } - case (_) { - ret none[def_id]; + case (ty::ty_str) {} + } + + auto new_sc = @rec(root_vars=root_def, + block_defnum=defnum, + bindings=[defnum], + tys=unsafe, + mutable ok=valid); + visit::visit_block(block, sc + [new_sc], v); +} + +fn check_var(&ctx cx, &@ast::expr ex, &ast::path p, ast::ann ann, bool assign, + &scope sc) { + auto def = cx.dm.get(ann.id); + if (!def_is_local(def)) { ret; } + auto my_defnum = ast::def_id_of_def(def)._1; + auto var_t = ty::expr_ty(*cx.tcx, ex); + for (restrict r in sc) { + // excludes variables introduced since the alias was made + if (my_defnum < r.block_defnum) { + for (ty::t t in r.tys) { + if (ty_can_unsafely_include(cx, t, var_t, assign)) { + r.ok = val_taken(ex.span, p); + } + } + } else if (r.ok != valid && vec::member(my_defnum, r.bindings)) { + fail_alias(cx, r.ok, p); } } } -fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) - -> rec(@ast::expr ex, vec[deref] ds) { - let vec[deref] ds = []; - if (autoderef) { - auto auto_unbox = maybe_auto_unbox(cx, ex); - if (auto_unbox.done) { - vec::push(ds, rec(mut=auto_unbox.mut, t=unbox)); +fn fail_alias(&ctx cx, valid issue, &ast::path pt) { + auto base = " will invalidate alias " + ast::path_name(pt) + + ", which is still used"; + alt (issue) { + case (overwritten(?sp, ?wpt)) { + cx.tcx.sess.span_err + (sp, "overwriting " + ast::path_name(wpt) + base); + } + case (val_taken(?sp, ?vpt)) { + cx.tcx.sess.span_err + (sp, "taking the value of " + ast::path_name(vpt) + + base); + } + } +} + +fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src, + &scope sc, &vt[scope] v) { + visit_expr(cx, src, sc, v); + alt (dest.node) { + case (ast::expr_path(?p, ?ann)) { + auto dnum = ast::def_id_of_def(cx.dm.get(ann.id))._1; + auto var_t = ty::expr_ty(*cx.tcx, dest); + for (restrict r in sc) { + if (vec::member(dnum, r.root_vars)) { + r.ok = overwritten(dest.span, p); + } + } + check_var(*cx, dest, p, ann, true, sc); + } + case (_) { + visit_expr(cx, dest, sc, v); } } +} + +fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) + -> rec(@ast::expr ex, option::t[ty::t] inner_mut, bool mut_in_box) { + let option::t[ty::t] mut = none; + // This is not currently used but would make it possible to be more + // liberal -- only stuff in a mutable box needs full type-inclusion + // checking, things that aren't in a box need only be checked against + // locally live aliases and their root. + auto mut_in_box = false; while (true) { alt ({ex.node}) { case (ast::expr_field(?base, ?ident, _)) { - auto auto_unbox = maybe_auto_unbox(cx, base); - alt (auto_unbox.t) { + auto base_t = ty::expr_ty(*cx.tcx, base); + auto auto_unbox = maybe_auto_unbox(cx, base_t); + alt (ty::struct(*cx.tcx, auto_unbox.t)) { case (ty::ty_tup(?fields)) { auto fnm = ty::field_num(cx.tcx.sess, ex.span, ident); - auto mt = fields.(fnm).mut != ast::imm; - vec::push(ds, rec(mut=mt, t=field(ident))); + if (fields.(fnm).mut != ast::imm && is_none(mut)) { + mut = some(auto_unbox.t); + } } case (ty::ty_rec(?fields)) { for (ty::field fld in fields) { if (str::eq(ident, fld.ident)) { - auto mt = fld.mt.mut != ast::imm; - vec::push(ds, rec(mut=mt, t=field(ident))); + if (fld.mt.mut != ast::imm && is_none(mut)) { + mut = some(auto_unbox.t); + } break; } } } - case (ty::ty_obj(_)) { - vec::push(ds, rec(mut=false, t=field(ident))); - } + case (ty::ty_obj(_)) {} } if (auto_unbox.done) { - vec::push(ds, rec(mut=auto_unbox.mut, t=unbox)); + if (!is_none(mut)) { mut_in_box = true; } + else if (auto_unbox.mut) { mut = some(base_t); } } ex = base; } case (ast::expr_index(?base, _, _)) { - auto auto_unbox = maybe_auto_unbox(cx, base); - alt (auto_unbox.t) { + auto base_t = ty::expr_ty(*cx.tcx, base); + auto auto_unbox = maybe_auto_unbox(cx, base_t); + alt (ty::struct(*cx.tcx, auto_unbox.t)) { case (ty::ty_vec(?mt)) { - vec::push(ds, rec(mut=mt.mut != ast::imm, t=index)); + if (mt.mut != ast::imm && is_none(mut)) { + mut = some(auto_unbox.t); + } } } if (auto_unbox.done) { - vec::push(ds, rec(mut=auto_unbox.mut, t=unbox)); + if (!is_none(mut)) { mut_in_box = true; } + else if (auto_unbox.mut) { mut = some(base_t); } + } + if (auto_unbox.done && !is_none(mut)) { } ex = base; } case (ast::expr_unary(?op, ?base, _)) { if (op == ast::deref) { - alt (ty::struct(*cx.tcx, ty::expr_ty(*cx.tcx, base))) { + auto base_t = ty::expr_ty(*cx.tcx, base); + alt (ty::struct(*cx.tcx, base_t)) { case (ty::ty_box(?mt)) { - vec::push(ds, rec(mut=mt.mut!=ast::imm, t=unbox)); + if (mt.mut != ast::imm && is_none(mut)) { + mut = some(base_t); + } + if (!is_none(mut)) { + mut_in_box = true; + } } } ex = base; @@ -214,34 +393,100 @@ fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) case (_) { break; } } } - vec::reverse(ds); - ret rec(ex = ex, ds = ds); + if (autoderef) { + auto ex_t = ty::expr_ty(*cx.tcx, ex); + auto auto_unbox = maybe_auto_unbox(cx, ex_t); + if (auto_unbox.done) { + if (!is_none(mut)) { mut_in_box = true; } + else if (auto_unbox.mut) { mut = some(ex_t); } + } + } + ret rec(ex = ex, inner_mut = mut, mut_in_box = mut_in_box); } -fn maybe_auto_unbox(&ctx cx, &@ast::expr ex) - -> rec(ty::sty t, bool done, bool mut) { - auto tp = ty::struct(*cx.tcx, ty::expr_ty(*cx.tcx, ex)); - alt (tp) { +fn maybe_auto_unbox(&ctx cx, &ty::t t) + -> rec(ty::t t, bool done, bool mut) { + alt (ty::struct(*cx.tcx, t)) { case (ty::ty_box(?mt)) { - ret rec(t=ty::struct(*cx.tcx, mt.ty), - done=true, mut=mt.mut != ast::imm); + ret rec(t=mt.ty, done=true, mut=mt.mut != ast::imm); + } + case (_) { + ret rec(t=t, done=false, mut=false); } - case (_) { ret rec(t=tp, done=false, mut=false); } } } -fn has_unsafe_box(&vec[deref] ds) -> bool { - auto saw_mut = false; - for (deref d in ds) { - if (d.mut) { saw_mut = true; } - if (d.t == unbox) { - // Directly aliasing the content of a mutable box is never okay, - // and any box living under mutable connection may be severed from - // its root and freed. - if (saw_mut) { ret true; } +fn path_def_id(&ctx cx, &@ast::expr ex) -> option::t[ast::def_id] { + alt (ex.node) { + case (ast::expr_path(_, ?ann)) { + ret some(ast::def_id_of_def(cx.dm.get(ann.id))); + } + case (_) { + ret none; } } - ret false; +} + +fn ty_can_unsafely_include(&ctx cx, ty::t needle, ty::t haystack, bool mut) + -> bool { + fn get_mut(bool cur, &ty::mt mt) -> bool { + ret cur || mt.mut != ast::imm; + } + fn helper(&ty::ctxt tcx, ty::t needle, ty::t haystack, bool mut) -> bool { + if (needle == haystack) { ret true; } + alt (ty::struct(tcx, haystack)) { + case (ty::ty_tag(_, ?ts)) { + for (ty::t t in ts) { + if (helper(tcx, needle, t, mut)) { ret true; } + } + ret false; + } + case (ty::ty_box(?mt)) { + ret helper(tcx, needle, mt.ty, get_mut(mut, mt)); + } + case (ty::ty_vec(?mt)) { + ret helper(tcx, needle, mt.ty, get_mut(mut, mt)); + } + case (ty::ty_ptr(?mt)) { + ret helper(tcx, needle, mt.ty, get_mut(mut, mt)); + } + case (ty::ty_tup(?mts)) { + for (ty::mt mt in mts) { + if (helper(tcx, needle, mt.ty, get_mut(mut, mt))) { + ret true; + } + } + ret false; + } + case (ty::ty_rec(?fields)) { + for (ty::field f in fields) { + if (helper(tcx, needle, f.mt.ty, get_mut(mut, f.mt))) { + ret true; + } + } + ret false; + } + // These may contain anything. + case (ty::ty_fn(_, _, _, _)) { ret true; } + case (ty::ty_obj(_)) { ret true; } + // A type param may include everything, but can only be treated as + // opaque downstream, and is thus safe unless we saw mutable + // fields, in which case the whole thing can be overwritten. + case (ty::ty_param(_)) { ret mut; } + case (_) { ret false; } + } + } + ret helper(*cx.tcx, needle, haystack, mut); +} + +fn def_is_local(&ast::def d) -> bool { + ret alt (d) { + case (ast::def_local(_)) { true } + case (ast::def_arg(_)) { true } + case (ast::def_obj_field(_)) { true } + case (ast::def_binding(_)) { true } + case (_) { false } + }; } // Local Variables: diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index 8ec4dfe6297ef..1bd7307a5abf5 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -307,7 +307,7 @@ fn resolve_names(&@env e, &ast::crate c) { } case (_) { e.sess.span_err(p.span, "not a tag variant: " + - str::connect(p.node.idents, "::")); + ast::path_name(p)); } } for (@ast::pat child in children) { diff --git a/src/test/compile-fail/unsafe-alias-2.rs b/src/test/compile-fail/unsafe-alias-2.rs new file mode 100644 index 0000000000000..4a9551a9130f1 --- /dev/null +++ b/src/test/compile-fail/unsafe-alias-2.rs @@ -0,0 +1,15 @@ +// error-pattern:invalidate alias x + +fn whoknows(@mutable int x) { + *x = 10; +} + +fn main() { + auto box = @mutable 1; + alt (*box) { + case (?x) { + whoknows(box); + log_err x; + } + } +} diff --git a/src/test/compile-fail/unsafe-alias.rs b/src/test/compile-fail/unsafe-alias.rs index e4ff5f86da2c2..a81b490266d84 100644 --- a/src/test/compile-fail/unsafe-alias.rs +++ b/src/test/compile-fail/unsafe-alias.rs @@ -1,10 +1,14 @@ -// error-pattern:can not create alias +// error-pattern:may alias with argument -fn foo(&int x) { +fn foo(&int x, fn() f) { log x; } +fn whoknows(@mutable int x) { + *x = 10; +} + fn main() { auto box = @mutable 1; - foo(*box); + foo(*box, bind whoknows(box)); } diff --git a/src/test/compile-fail/unsafe-alt.rs b/src/test/compile-fail/unsafe-alt.rs index a0342d87c867a..4144e3751db0b 100644 --- a/src/test/compile-fail/unsafe-alt.rs +++ b/src/test/compile-fail/unsafe-alt.rs @@ -1,4 +1,4 @@ -// error-pattern:x is being aliased +// error-pattern:invalidate alias i tag foo { left(int); @@ -10,6 +10,7 @@ fn main() { alt (x) { case (left(?i)) { x = right(false); + log i; } case (_) {} } From b33fb684b6d5a7708c9724dd7684ec52ecd0930f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 9 Jun 2011 14:19:13 +0200 Subject: [PATCH 64/64] Properly handle lifetime of aliases in nested blocks There was a bug that would cause the alias analyser to allow you to invalidate an alias that was no longer directly referred to, even if another alias was rooted in it. It now properly tracks dependencies between live aliases. Required another case of copying values in map.rs. --- src/comp/middle/alias.rs | 59 ++++++++++++++++++++++++++++------------ src/lib/map.rs | 3 +- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index fa978ef53c03b..bad328e028c0e 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -20,6 +20,7 @@ type restrict = @rec(vec[def_num] root_vars, def_num block_defnum, vec[def_num] bindings, vec[ty::t] tys, + vec[uint] depends_on, mutable valid ok); type scope = vec[restrict]; @@ -182,6 +183,7 @@ fn check_alt(&ctx cx, &@ast::expr input, &vec[ast::arm] arms, block_defnum=dnums.(0), bindings=dnums, tys=forbidden_tp, + depends_on=deps(sc, roots), mutable ok=valid)); } visit::visit_arm(a, new_sc, v); @@ -221,6 +223,7 @@ fn check_for_each(&ctx cx, &@ast::decl decl, &@ast::expr call, block_defnum=defnum, bindings=[defnum], tys=data.unsafe_ts, + depends_on=deps(sc, data.root_vars), mutable ok=valid); visit::visit_block(block, sc + [new_sc], v); } @@ -256,6 +259,7 @@ fn check_for(&ctx cx, &@ast::decl decl, &@ast::expr seq, block_defnum=defnum, bindings=[defnum], tys=unsafe, + depends_on=deps(sc, root_def), mutable ok=valid); visit::visit_block(block, sc + [new_sc], v); } @@ -274,24 +278,8 @@ fn check_var(&ctx cx, &@ast::expr ex, &ast::path p, ast::ann ann, bool assign, r.ok = val_taken(ex.span, p); } } - } else if (r.ok != valid && vec::member(my_defnum, r.bindings)) { - fail_alias(cx, r.ok, p); - } - } -} - -fn fail_alias(&ctx cx, valid issue, &ast::path pt) { - auto base = " will invalidate alias " + ast::path_name(pt) + - ", which is still used"; - alt (issue) { - case (overwritten(?sp, ?wpt)) { - cx.tcx.sess.span_err - (sp, "overwriting " + ast::path_name(wpt) + base); - } - case (val_taken(?sp, ?vpt)) { - cx.tcx.sess.span_err - (sp, "taking the value of " + ast::path_name(vpt) + - base); + } else if (vec::member(my_defnum, r.bindings)) { + test_scope(cx, sc, r, p); } } } @@ -316,6 +304,41 @@ fn check_assign(&@ctx cx, &@ast::expr dest, &@ast::expr src, } } +fn test_scope(&ctx cx, &scope sc, &restrict r, &ast::path p) { + auto prob = r.ok; + for (uint dep in r.depends_on) { + if (prob != valid) { break; } + prob = sc.(dep).ok; + } + if (prob != valid) { + auto msg = alt (prob) { + case (overwritten(?sp, ?wpt)) { + tup(sp, "overwriting " + ast::path_name(wpt)) + } + case (val_taken(?sp, ?vpt)) { + tup(sp, "taking the value of " + ast::path_name(vpt)) + } + }; + cx.tcx.sess.span_err + (msg._0, msg._1 + " will invalidate alias " + + ast::path_name(p) + ", which is still used"); + } +} + +fn deps(&scope sc, vec[def_num] roots) -> vec[uint] { + auto i = 0u; + auto result = []; + for (restrict r in sc) { + for (def_num dn in roots) { + if (vec::member(dn, r.bindings)) { + vec::push(result, i); + } + } + i += 1u; + } + ret result; +} + fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) -> rec(@ast::expr ex, option::t[ty::t] inner_mut, bool mut_in_box) { let option::t[ty::t] mut = none; diff --git a/src/lib/map.rs b/src/lib/map.rs index 396835bc1d693..854ab74df9a81 100644 --- a/src/lib/map.rs +++ b/src/lib/map.rs @@ -131,7 +131,8 @@ fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] { { for (bucket[K, V] b in oldbkts) { alt (b) { - case (some(?k, ?v)) { + case (some(?k_, ?v_)) { + auto k = k_; auto v = v_; insert_common[K, V](hasher, eqer, newbkts, nnewbkts, k, v); }