diff options
| author | Tim Chevalier <chevalier@alum.wellesley.edu> | 2012-01-30 21:00:57 -0800 |
|---|---|---|
| committer | Tim Chevalier <chevalier@alum.wellesley.edu> | 2012-01-31 10:08:24 -0800 |
| commit | fba35e1a3c87892823d1f4d436b9f00a7864cf16 (patch) | |
| tree | 1fadaaee99ef266bd2f709fb2aa5577184ab611e /src/comp | |
| parent | 813a55d89135efb716dd80e96453a091a7cfc631 (diff) | |
| download | rust-fba35e1a3c87892823d1f4d436b9f00a7864cf16.tar.gz rust-fba35e1a3c87892823d1f4d436b9f00a7864cf16.zip | |
Require alts to be exhaustive
middle::check_alt does the work. Lots of changes to add default cases into alts that were previously inexhaustive.
Diffstat (limited to 'src/comp')
38 files changed, 689 insertions, 344 deletions
diff --git a/src/comp/back/rpath.rs b/src/comp/back/rpath.rs index b848ca94590..a2030e10fab 100644 --- a/src/comp/back/rpath.rs +++ b/src/comp/back/rpath.rs @@ -11,6 +11,13 @@ import util::filesearch; export get_rpath_flags; +pure fn not_win32(os: session::os) -> bool { + alt os { + session::os_win32 { false } + _ { true } + } +} + fn get_rpath_flags(sess: session::session, out_filename: str) -> [str] { let os = sess.targ_cfg.os; @@ -99,12 +106,13 @@ fn get_rpaths_relative_to_output(os: session::os, fn get_rpath_relative_to_output(os: session::os, cwd: fs::path, output: fs::path, - &&lib: fs::path) -> str { + &&lib: fs::path) : not_win32(os) -> str { // Mac doesn't appear to support $ORIGIN let prefix = alt os { session::os_linux { "$ORIGIN" + fs::path_sep() } session::os_freebsd { "$ORIGIN" + fs::path_sep() } session::os_macos { "@executable_path" + fs::path_sep() } + session::os_win32 { std::util::unreachable(); } }; prefix + get_relative_to( @@ -309,24 +317,31 @@ mod test { #[test] #[cfg(target_os = "linux")] fn test_rpath_relative() { - let res = get_rpath_relative_to_output(session::os_linux, + let o = session::os_linux; + check not_win32(o); + let res = get_rpath_relative_to_output(o, "/usr", "bin/rustc", "lib/libstd.so"); - assert res == "$ORIGIN/../lib"; + assert res == "$ORIGIN/../lib"; } #[test] #[cfg(target_os = "freebsd")] fn test_rpath_relative() { - let res = get_rpath_relative_to_output(session::os_freebsd, + let o = session::os_freebsd; + check not_win32(o); + let res = get_rpath_relative_to_output(o, "/usr", "bin/rustc", "lib/libstd.so"); - assert res == "$ORIGIN/../lib"; + assert res == "$ORIGIN/../lib"; } #[test] #[cfg(target_os = "macos")] fn test_rpath_relative() { - let res = get_rpath_relative_to_output(session::os_macos, - "/usr", "bin/rustc", "lib/libstd.so"); + // this is why refinements would be nice + let o = session::os_macos; + check not_win32(o); + let res = get_rpath_relative_to_output(o, "/usr", "bin/rustc", + "lib/libstd.so"); assert res == "@executable_path/../lib"; } diff --git a/src/comp/driver/driver.rs b/src/comp/driver/driver.rs index 78ec0330dd9..ac6d785e8b5 100644 --- a/src/comp/driver/driver.rs +++ b/src/comp/driver/driver.rs @@ -608,6 +608,8 @@ mod test { let match = alt getopts::getopts(["--test"], opts()) { ok(m) { m } + err(f) { fail "test_switch_implies_cfg_test: " + + getopts::fail_str(f); } }; let sessopts = build_session_options(match, diagnostic::emit); let sess = build_session(sessopts, "", diagnostic::emit); @@ -622,6 +624,8 @@ mod test { let match = alt getopts::getopts(["--test", "--cfg=test"], opts()) { ok(m) { m } + err(f) { fail "test_switch_implies_cfg_test_unless_cfg_test: " + + getopts::fail_str(f); } }; let sessopts = build_session_options(match, diagnostic::emit); let sess = build_session(sessopts, "", diagnostic::emit); diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs index b570744a665..81f1c76a2c9 100644 --- a/src/comp/driver/session.rs +++ b/src/comp/driver/session.rs @@ -58,7 +58,7 @@ type session = @{targ_cfg: @config, parse_sess: parse_sess, codemap: codemap::codemap, // For a library crate, this is always none - mutable main_fn: option::t<node_id>, + mutable main_fn: option::t<(node_id, codemap::span)>, span_diagnostic: diagnostic::span_handler, filesearch: filesearch::filesearch, mutable building_library: bool, diff --git a/src/comp/metadata/decoder.rs b/src/comp/metadata/decoder.rs index 266167affd4..8fb12aae533 100644 --- a/src/comp/metadata/decoder.rs +++ b/src/comp/metadata/decoder.rs @@ -3,6 +3,7 @@ import std::{ebml, map, io}; import io::writer_util; import syntax::{ast, ast_util}; +import driver::session::session; import front::attr; import middle::ty; import common::*; @@ -302,7 +303,9 @@ fn get_iface_methods(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) let bounds = item_ty_param_bounds(mth, tcx, cdata); let name = item_name(mth); let ty = doc_type(mth, tcx, cdata); - let fty = alt ty::struct(tcx, ty) { ty::ty_fn(f) { f } }; + let fty = alt ty::struct(tcx, ty) { ty::ty_fn(f) { f } + _ { tcx.sess.bug("get_iface_methods: id has non-function type"); + } }; result += [{ident: name, tps: bounds, fty: fty}]; } @result diff --git a/src/comp/metadata/encoder.rs b/src/comp/metadata/encoder.rs index bcd760b5c61..d4cdb7587bf 100644 --- a/src/comp/metadata/encoder.rs +++ b/src/comp/metadata/encoder.rs @@ -10,6 +10,7 @@ import middle::trans::common::crate_ctxt; import middle::ty; import middle::ty::node_id_to_type; import front::attr; +import driver::session::session; export encode_metadata; export encoded_ty; @@ -275,6 +276,8 @@ fn encode_info_for_mod(ecx: @encode_ctxt, ebml_w: ebml::writer, md: _mod, } } } + _ { ecx.ccx.tcx.sess.bug("encode_info_for_mod: \ + undocumented invariant"); } } ebml::end_tag(ebml_w); } diff --git a/src/comp/metadata/tyencode.rs b/src/comp/metadata/tyencode.rs index 5f78f305d8d..f116bb7e17f 100644 --- a/src/comp/metadata/tyencode.rs +++ b/src/comp/metadata/tyencode.rs @@ -5,6 +5,7 @@ import io::writer_util; import std::map::hashmap; import option::{some, none}; import syntax::ast::*; +import driver::session::session; import middle::ty; import syntax::print::pprust::*; @@ -213,6 +214,10 @@ fn enc_ty_fn(w: io::writer, cx: @ctxt, ft: ty::fn_ty) { by_copy { w.write_char('+'); } by_ref { w.write_char('='); } by_val { w.write_char('#'); } + // tediously, this has to be there until there's a way + // to constraint post-typeck types not to contain a mode_infer + mode_infer { cx.tcx.sess.bug("enc_ty_fn: shouldn't see \ + mode_infer"); } } enc_ty(w, cx, arg.ty); } diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index 0d4ecee7dea..98cade0ca26 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -6,10 +6,12 @@ import syntax::visit; import visit::vt; import core::{vec, option}; import std::list; +import std::util::unreachable; import option::{some, none, is_none}; import list::list; import driver::session::session; import pat_util::*; +import util::ppaux::ty_to_str; // This is not an alias-analyser (though it would merit from becoming one, or // getting input from one, to be more precise). It is a pass that checks @@ -575,6 +577,11 @@ fn copy_is_expensive(tcx: ty::ctxt, ty: ty::t) -> bool { for f in fs { sum += score_ty(tcx, f.mt.ty); } sum } + _ { + tcx.sess.warn(#fmt("score_ty: unexpected type %s", + ty_to_str(tcx, ty))); + 1u // ??? + } }; } ret score_ty(tcx, ty) > 8u; @@ -611,6 +618,7 @@ fn pattern_roots(tcx: ty::ctxt, mut: option::t<unsafe_ty>, pat: @ast::pat) let ty = ty::node_id_to_type(tcx, pat.id); let m = alt ty::struct(tcx, ty) { ty::ty_box(mt) { mt.mut != ast::imm } + _ { tcx.sess.span_bug(pat.span, "box pat has non-box type"); } }, c = if m {some(contains(ty)) } else { mut }; walk(tcx, c, p, set); @@ -619,6 +627,7 @@ fn pattern_roots(tcx: ty::ctxt, mut: option::t<unsafe_ty>, pat: @ast::pat) let ty = ty::node_id_to_type(tcx, pat.id); let m = alt ty::struct(tcx, ty) { ty::ty_uniq(mt) { mt.mut != ast::imm } + _ { tcx.sess.span_bug(pat.span, "uniq pat has non-uniq type"); } }, c = if m { some(contains(ty)) } else { mut }; walk(tcx, c, p, set); @@ -672,6 +681,10 @@ fn append_invalid(dest: list<@invalid>, src: list<@invalid>, } cur = *tail; } + list::nil { + fail "append_invalid: stop doesn't appear to be \ + a postfix of src"; + } } } ret dest; @@ -686,6 +699,10 @@ fn filter_invalid(src: list<@invalid>, bs: [binding]) -> list<@invalid> { if !is_none(p) { out = list::cons(head, @out); } cur = *tail; } + list::nil { + // typestate would help... + unreachable(); + } } } ret out; diff --git a/src/comp/middle/ast_map.rs b/src/comp/middle/ast_map.rs index 58c6bfc2914..97881ca17a2 100644 --- a/src/comp/middle/ast_map.rs +++ b/src/comp/middle/ast_map.rs @@ -44,15 +44,15 @@ fn map_fn(cx: ctx, _fk: visit::fn_kind, decl: fn_decl, _body: blk, } fn map_local(cx: ctx, loc: @local) { - pat_util::pat_bindings(loc.node.pat) {|p| - cx.map.insert(p.id, node_local(cx.local_id)); + pat_util::pat_bindings(loc.node.pat) {|p_id, _s, _p| + cx.map.insert(p_id, node_local(cx.local_id)); cx.local_id += 1u; }; } fn map_arm(cx: ctx, arm: arm) { - pat_util::pat_bindings(arm.pats[0]) {|p| - cx.map.insert(p.id, node_local(cx.local_id)); + pat_util::pat_bindings(arm.pats[0]) {|p_id, _s, _p| + cx.map.insert(p_id, node_local(cx.local_id)); cx.local_id += 1u; }; } @@ -79,50 +79,6 @@ fn map_expr(cx: ctx, ex: @expr) { cx.map.insert(ex.id, node_expr(ex)); } -fn node_span(node: ast_node) -> codemap::span { - alt node { - node_item(item) { item.span } - node_native_item(nitem) { nitem.span } - node_expr(expr) { expr.span } - } -} - -#[cfg(test)] -mod test { - import syntax::ast_util; - - #[test] - fn test_node_span_item() { - let expected: codemap::span = ast_util::mk_sp(20u, 30u); - let node = - node_item(@{ident: "test", - attrs: [], - id: 0, - node: item_mod({view_items: [], items: []}), - span: expected}); - assert (node_span(node) == expected); - } - - #[test] - fn test_node_span_native_item() { - let expected: codemap::span = ast_util::mk_sp(20u, 30u); - let node = - node_native_item(@{ident: "test", - attrs: [], - node: native_item_ty, - id: 0, - span: expected}); - assert (node_span(node) == expected); - } - - #[test] - fn test_node_span_expr() { - let expected: codemap::span = ast_util::mk_sp(20u, 30u); - let node = node_expr(@{id: 0, node: expr_break, span: expected}); - assert (node_span(node) == expected); - } -} - // Local Variables: // mode: rust // fill-column: 78; diff --git a/src/comp/middle/check_alt.rs b/src/comp/middle/check_alt.rs index e78b9ddb77f..2577ed03a93 100644 --- a/src/comp/middle/check_alt.rs +++ b/src/comp/middle/check_alt.rs @@ -1,10 +1,14 @@ + import syntax::ast::*; import syntax::ast_util::{variant_def_ids, dummy_sp, compare_lit_exprs, - lit_expr_eq}; + lit_expr_eq, unguarded_pat}; +import syntax::codemap::span; import pat_util::*; import syntax::visit; import option::{some, none}; import driver::session::session; +import middle::ty; +import middle::ty::*; fn check_crate(tcx: ty::ctxt, crate: @crate) { let v = @@ -18,15 +22,20 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) { fn check_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) { visit::visit_expr(ex, s, v); alt ex.node { - expr_alt(_, arms) { - check_arms(tcx, pat_util::normalize_arms(tcx, arms)); + expr_alt(scrut, arms) { + check_arms(tcx, ex.span, scrut, + pat_util::normalize_arms(tcx, arms)); } _ { } } } -fn check_arms(tcx: ty::ctxt, arms: [arm]) { +fn check_arms(tcx: ty::ctxt, sp:span, scrut: @expr, arms: [arm]) { let i = 0; + let scrut_ty = expr_ty(tcx, scrut); + /* (Could both checks be done in a single pass?) */ + + /* Check for unreachable patterns */ for arm: arm in arms { for arm_pat: @pat in arm.pats { let reachable = true; @@ -47,6 +56,97 @@ fn check_arms(tcx: ty::ctxt, arms: [arm]) { } i += 1; } + + /* Check for exhaustiveness */ + + check_exhaustive(tcx, sp, scrut_ty, + vec::concat(vec::filter_map(arms, unguarded_pat))); +} + +// Precondition: patterns have been normalized +// (not checked statically yet) +fn check_exhaustive(tcx: ty::ctxt, sp:span, scrut_ty:ty::t, pats:[@pat]) { + let represented : [def_id] = []; + /* Determine the type of the scrutinee */ + /* If it's not an enum, exit (bailing out on checking non-enum alts + for now) */ + /* Otherwise, get the list of variants and make sure each one is + represented. Then recurse on the columns. */ + + let ty_def_id = alt ty::struct(tcx, scrut_ty) { + ty_enum(id, _) { id } + _ { ret; } }; + + let variants = *enum_variants(tcx, ty_def_id); + for pat in pats { + if !is_refutable(tcx, pat) { + /* automatically makes this alt complete */ ret; + } + alt pat.node { + // want the def_id for the constructor + pat_enum(id,_) { + alt tcx.def_map.find(pat.id) { + some(def_variant(_, variant_def_id)) { + represented += [variant_def_id]; + } + _ { tcx.sess.span_bug(pat.span, "check_exhaustive: + pat_tag not bound to a variant"); } + } + } + _ { tcx.sess.span_bug(pat.span, "check_exhaustive: ill-typed \ + pattern"); // we know this has enum type, + } // so anything else should be impossible + } + } + fn not_represented(v: [def_id], &&vinfo: variant_info) -> bool { + !vec::member(vinfo.id, v) + } + // Could be more efficient (bitvectors?) + alt vec::find(variants, bind not_represented(represented,_)) { + some(bad) { + // complain + // TODO: give examples of cases that aren't covered + tcx.sess.note("Patterns not covered include:"); + tcx.sess.note(bad.name); + tcx.sess.span_err(sp, "Non-exhaustive pattern"); + } + _ {} + } + // Otherwise, check subpatterns + // inefficient + for variant in variants { + // rows consists of the argument list for each pat that's an enum + let rows : [[@pat]] = []; + for pat in pats { + alt pat.node { + pat_enum(id, args) { + alt tcx.def_map.find(pat.id) { + some(def_variant(_,variant_id)) + if variant_id == variant.id { rows += [args]; } + _ { } + } + } + _ {} + } + } + if check vec::is_not_empty(rows) { + let i = 0u; + for it in rows[0] { + let column = [it]; + // Annoying -- see comment in + // tstate::states::find_pre_post_state_loop + check vec::is_not_empty(rows); + for row in vec::tail(rows) { + column += [row[i]]; + } + check_exhaustive(tcx, sp, pat_ty(tcx, it), column); + i += 1u; + } + } + // This shouldn't actually happen, since there were no + // irrefutable patterns if we got here. + else { cont; } + } } fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool { @@ -145,8 +245,8 @@ fn is_refutable(tcx: ty::ctxt, pat: @pat) -> bool { pat_wild | pat_ident(_, none) { false } pat_lit(_) { true } pat_rec(fields, _) { - for field: field_pat in fields { - if is_refutable(tcx, field.pat) { ret true; } + for it: field_pat in fields { + if is_refutable(tcx, it.pat) { ret true; } } false } @@ -156,10 +256,11 @@ fn is_refutable(tcx: ty::ctxt, pat: @pat) -> bool { } pat_enum(_, args) { let vdef = variant_def_ids(tcx.def_map.get(pat.id)); - if vec::len(*ty::enum_variants(tcx, vdef.tg)) != 1u { ret true; } + if vec::len(*ty::enum_variants(tcx, vdef.enm)) != 1u { ret true; } for p: @pat in args { if is_refutable(tcx, p) { ret true; } } false } + pat_range(_, _) { true } } } diff --git a/src/comp/middle/debuginfo.rs b/src/comp/middle/debuginfo.rs index c16dedc1bd4..fe843c6795b 100644 --- a/src/comp/middle/debuginfo.rs +++ b/src/comp/middle/debuginfo.rs @@ -12,6 +12,7 @@ import codemap::span; import ast::ty; import pat_util::*; import util::ppaux::ty_to_str; +import driver::session::session; export create_local_var; export create_function; @@ -249,8 +250,8 @@ fn create_block(cx: @block_ctxt) -> @metadata<block_md> { }*/ let parent = alt cx.parent { - parent_none { create_function(cx.fcx).node } - parent_some(bcx) { create_block(bcx).node } + parent_none { create_function(cx.fcx).node } + parent_some(bcx) { create_block(bcx).node } }; let file_node = create_file(bcx_ccx(cx), fname); let unique_id = alt cache.find(LexicalBlockTag) { @@ -306,6 +307,8 @@ fn create_basic_type(cx: @crate_ctxt, t: ty::t, ty: @ast::ty) ast::ty_f32 {("f32", size_and_align_of::<f32>(), DW_ATE_float)} ast::ty_f64 {("f64", size_and_align_of::<f64>(), DW_ATE_float)} }} + _ { cx.tcx.sess.span_bug(ty.span, + "create_basic_type: unhandled type"); } }; let fname = filename_from_span(cx, ty.span); @@ -481,15 +484,15 @@ fn create_composite_type(type_tag: int, name: str, file: ValueRef, line: int, ret llmdnode(lldata); } -fn create_vec(cx: @crate_ctxt, vec_t: ty::t, elem_t: ty::t, vec_ty: @ast::ty) +fn create_vec(cx: @crate_ctxt, vec_t: ty::t, elem_t: ty::t, + vec_ty_span: codemap::span, elem_ty: @ast::ty) -> @metadata<tydesc_md> { - let fname = filename_from_span(cx, vec_ty.span); + let fname = filename_from_span(cx, vec_ty_span); let file_node = create_file(cx, fname); - let elem_ty = alt vec_ty.node { ast::ty_vec(mt) { mt.ty } }; let elem_ty_md = create_ty(cx, elem_t, elem_ty); let tcx = ccx_tcx(cx); let scx = create_structure(file_node, ty_to_str(tcx, vec_t), 0); - let uint_ty = @{node: ast::ty_uint(ast::ty_u), span: vec_ty.span}; + let uint_ty = @{node: ast::ty_uint(ast::ty_u), span: vec_ty_span}; let size_t_type = create_basic_type(cx, ty::mk_uint(tcx), uint_ty); add_member(scx, "fill", 0, sys::size_of::<ctypes::size_t>() as int, sys::align_of::<ctypes::size_t>() as int, size_t_type.node); @@ -516,12 +519,14 @@ fn member_size_and_align(ty: @ast::ty) -> (int, int) { ast::ty_i8 { size_and_align_of::<i8>() } ast::ty_i16 { size_and_align_of::<i16>() } ast::ty_i32 { size_and_align_of::<i32>() } + ast::ty_i64 { size_and_align_of::<i64>() } }} ast::ty_uint(m) { alt m { ast::ty_u { size_and_align_of::<uint>() } ast::ty_u8 { size_and_align_of::<i8>() } ast::ty_u16 { size_and_align_of::<u16>() } ast::ty_u32 { size_and_align_of::<u32>() } + ast::ty_u64 { size_and_align_of::<u64>() } }} ast::ty_float(m) { alt m { ast::ty_f { size_and_align_of::<float>() } @@ -542,6 +547,7 @@ fn member_size_and_align(ty: @ast::ty) -> (int, int) { ast::ty_vec(_) { size_and_align_of::<ctypes::uintptr_t>() } + _ { fail "member_size_and_align: can't handle this type"; } } } @@ -578,6 +584,9 @@ fn create_ty(cx: @crate_ctxt, t: ty::t, ty: @ast::ty) } ty::ty_vec(mt) { ast::ty_vec({ty: t_to_ty(cx, mt.ty, span), mut: mt.mut}) } + _ { + cx.tcx.sess.span_bug(span, "t_to_ty: Can't handle this type"); + } }; ret @{node: ty, span: span}; } @@ -586,6 +595,7 @@ fn create_ty(cx: @crate_ctxt, t: ty::t, ty: @ast::ty) ast::ty_box(mt) { let inner_t = alt ty::struct(ccx_tcx(cx), t) { ty::ty_box(boxed) { boxed.ty } + _ { cx.tcx.sess.span_bug(ty.span, "t_to_ty was incoherent"); } }; let md = create_ty(cx, inner_t, mt.ty); let box = create_boxed_type(cx, t, inner_t, ty.span, md); @@ -595,6 +605,8 @@ fn create_ty(cx: @crate_ctxt, t: ty::t, ty: @ast::ty) ast::ty_uniq(mt) { let inner_t = alt ty::struct(ccx_tcx(cx), t) { ty::ty_uniq(boxed) { boxed.ty } + // Hoping we'll have a way to eliminate this check soon. + _ { cx.tcx.sess.span_bug(ty.span, "t_to_ty was incoherent"); } }; let md = create_ty(cx, inner_t, mt.ty); ret create_pointer_type(cx, t, ty.span, md); @@ -611,7 +623,8 @@ fn create_ty(cx: @crate_ctxt, t: ty::t, ty: @ast::ty) ast::ty_vec(mt) { let inner_t = ty::sequence_element_type(ccx_tcx(cx), t); - let v = create_vec(cx, t, inner_t, ty); + let inner_ast_t = t_to_ty(cx, inner_t, mt.ty.span); + let v = create_vec(cx, t, inner_t, ty.span, inner_ast_t); ret create_pointer_type(cx, t, ty.span, v); } @@ -650,15 +663,17 @@ fn create_local_var(bcx: @block_ctxt, local: @ast::local) let name = path_to_ident(alt pat_util::normalize_pat(bcx_tcx(bcx), local.node.pat).node { ast::pat_ident(ident, _) { ident /*XXX deal w/ optional node binding*/ } - }); + _ { bcx_tcx(bcx).sess.span_bug(local.span, "create_local_var: \ + weird pattern in local"); } + }); let loc = codemap::lookup_char_pos(cx.sess.codemap, local.span.lo); let ty = base::node_id_type(cx, local.node.id); let tymd = create_ty(cx, ty, local.node.ty); let filemd = create_file(cx, loc.filename); let context = alt bcx.parent { - parent_none { create_function(bcx.fcx).node } - parent_some(_) { create_block(bcx).node } + parent_none { create_function(bcx.fcx).node } + parent_some(_) { create_block(bcx).node } }; let mdnode = create_var(tg, context, name, filemd.node, loc.line as int, tymd.node); @@ -667,9 +682,15 @@ fn create_local_var(bcx: @block_ctxt, local: @ast::local) let llptr = alt bcx.fcx.lllocals.find(local.node.id) { option::some(local_mem(v)) { v } + option::some(_) { + bcx_tcx(bcx).sess.span_bug(local.span, "local is bound to \ + something weird"); + } option::none { alt bcx.fcx.lllocals.get(local.node.pat.id) { local_imm(v) { v } + _ { bcx_tcx(bcx).sess.span_bug(local.span, "local is bound to \ + something weird"); } } } }; @@ -745,15 +766,21 @@ fn create_function(fcx: @fn_ctxt) -> @metadata<subprogram_md> { ast::item_fn(decl, _, _) | ast::item_res(decl, _, _, _, _) { (item.ident, decl.output, item.id) } + _ { fcx_tcx(fcx).sess.span_bug(item.span, "create_function: item \ + bound to non-function"); } } } ast_map::node_method(method) { (method.ident, method.decl.output, method.id) } ast_map::node_res_ctor(item) { - alt item.node { ast::item_res(decl, _, _, _, ctor_id) { - (item.ident, decl.output, ctor_id) - }} + alt item.node { + ast::item_res(decl, _, _, _, ctor_id) { + (item.ident, decl.output, ctor_id) + } + _ { fcx_tcx(fcx).sess.span_bug(item.span, "create_function: \ + expected an item_res here"); } + } } ast_map::node_expr(expr) { alt expr.node { @@ -763,8 +790,12 @@ fn create_function(fcx: @fn_ctxt) -> @metadata<subprogram_md> { ast::expr_fn_block(decl, _) { (dbg_cx.names("fn"), decl.output, expr.id) } + _ { fcx_tcx(fcx).sess.span_bug(expr.span, "create_function: \ + expected an expr_fn or fn_block here"); } } } + _ { fcx_tcx(fcx).sess.bug("create_function: unexpected \ + sort of node"); } }; log(debug, ident); diff --git a/src/comp/middle/gc.rs b/src/comp/middle/gc.rs index 4bcc2a29d38..31b03cc3705 100644 --- a/src/comp/middle/gc.rs +++ b/src/comp/middle/gc.rs @@ -104,7 +104,7 @@ fn type_is_gc_relevant(cx: ty::ctxt, ty: ty::t) -> bool { alt ty::struct(cx, ty) { ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_int(_) | ty::ty_float(_) | ty::ty_uint(_) | ty::ty_str | - ty::ty_type | ty::ty_ptr(_) | ty::ty_native(_) { + ty::ty_type | ty::ty_send_type | ty::ty_ptr(_) | ty::ty_native(_) { ret false; } ty::ty_rec(fields) { @@ -131,9 +131,19 @@ fn type_is_gc_relevant(cx: ty::ctxt, ty: ty::t) -> bool { ty::ty_constr(sub, _) { ret type_is_gc_relevant(cx, sub); } ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_fn(_) | ty::ty_param(_, _) | ty::ty_res(_, _, _) { ret true; } + ty::ty_opaque_closure_ptr(_) { + ret false; // I guess? + } + // A precondition to rule out these cases would be nice ty::ty_var(_) { fail "ty_var in type_is_gc_relevant"; } + ty::ty_iface(_, _) { + fail "ty_iface in type_is_gc_relevant"; + } + ty::ty_named(_,_) { + fail "ty_named in type_is_gc_relevant"; + } } } diff --git a/src/comp/middle/kind.rs b/src/comp/middle/kind.rs index c41b093225c..e06ce29add8 100644 --- a/src/comp/middle/kind.rs +++ b/src/comp/middle/kind.rs @@ -142,7 +142,9 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) { some(ex) { // All noncopyable fields must be overridden let t = ty::expr_ty(cx.tcx, ex); - let ty_fields = alt ty::struct(cx.tcx, t) { ty::ty_rec(f) { f } }; + let ty_fields = alt ty::struct(cx.tcx, t) { ty::ty_rec(f) { f } + _ { cx.tcx.sess.span_bug(ex.span, + "Bad expr type in record"); } }; for tf in ty_fields { if !vec::any(fields, {|f| f.node.ident == tf.ident}) && !ty::kind_can_be_copied(ty::type_kind(cx.tcx, tf.mt.ty)) { diff --git a/src/comp/middle/last_use.rs b/src/comp/middle/last_use.rs index 190e88deae6..24b378b8d38 100644 --- a/src/comp/middle/last_use.rs +++ b/src/comp/middle/last_use.rs @@ -2,6 +2,7 @@ import syntax::{visit, ast_util}; import syntax::ast::*; import syntax::codemap::span; import std::list::{is_not_empty, list, nil, cons, tail}; +import std::util::unreachable; import core::{vec, option}; import std::list; @@ -223,6 +224,11 @@ fn add_block_exit(cx: ctx, tp: block_type) -> bool { } cur = *tail; } + nil { + // typestate can't use the while loop condition -- + // *sigh* + unreachable(); + } } } ret false; diff --git a/src/comp/middle/lint.rs b/src/comp/middle/lint.rs index 838764171f0..f2f5666a346 100644 --- a/src/comp/middle/lint.rs +++ b/src/comp/middle/lint.rs @@ -51,6 +51,7 @@ fn merge_opts(attrs: [ast::attribute], cmd_opts: [(option, bool)]) -> ast::meta_word(name) { str_to_option(name) } + _ { fail "meta_to_option: meta_list contains a non-meta-word"; } }; } diff --git a/src/comp/middle/mut.rs b/src/comp/middle/mut.rs index ef40d4a87b2..736a31851d2 100644 --- a/src/comp/middle/mut.rs +++ b/src/comp/middle/mut.rs @@ -78,6 +78,10 @@ fn expr_root(tcx: ty::ctxt, ex: @expr, autoderef: bool) -> ty::ty_str { ds += [@{mut: false, kind: index, outer_t: auto_unbox.t}]; } + _ { + tcx.sess.span_bug(base.span, "Ill-typed base expression in \ + index"); + } } ds += auto_unbox.ds; ex = base; @@ -92,6 +96,8 @@ fn expr_root(tcx: ty::ctxt, ex: @expr, autoderef: bool) -> ty::ty_res(_, _, _) { } ty::ty_enum(_, _) { } ty::ty_ptr(mt) { is_mut = mt.mut == mut; ptr = true; } + _ { tcx.sess.span_bug(base.span, "Ill-typed base \ + expression in deref"); } } ds += [@{mut: is_mut, kind: unbox(ptr && is_mut), outer_t: base_t}]; diff --git a/src/comp/middle/pat_util.rs b/src/comp/middle/pat_util.rs index 023d49db8a1..8a5c2706bb1 100644 --- a/src/comp/middle/pat_util.rs +++ b/src/comp/middle/pat_util.rs @@ -3,6 +3,7 @@ import syntax::ast_util; import syntax::ast_util::respan; import syntax::fold; import syntax::fold::*; +import syntax::codemap::span; export normalize_arms; export normalize_pat; @@ -80,10 +81,8 @@ type pat_id_map = std::map::hashmap<str, node_id>; // use the node_id of their namesake in the first pattern. fn pat_id_map(tcx: ty::ctxt, pat: @pat) -> pat_id_map { let map = std::map::new_str_hash::<node_id>(); - pat_bindings(normalize_pat(tcx, pat)) {|bound| - let name = path_to_ident(alt bound.node - { pat_ident(n, _) { n } }); - map.insert(name, bound.id); + pat_bindings(normalize_pat(tcx, pat)) {|p_id, _s, n| + map.insert(path_to_ident(n), p_id); }; ret map; } @@ -91,10 +90,11 @@ fn pat_id_map(tcx: ty::ctxt, pat: @pat) -> pat_id_map { // This does *not* normalize. The pattern should be already normalized // if you want to get a normalized pattern out of it. // Could return a constrained type in order to express that (future work) -fn pat_bindings(pat: @pat, it: fn(@pat)) { +fn pat_bindings(pat: @pat, it: fn(node_id, span, @path)) { alt pat.node { - pat_ident(_, option::none) { it(pat); } - pat_ident(_, option::some(sub)) { it(pat); pat_bindings(sub, it); } + pat_ident(pth, option::none) { it(pat.id, pat.span, pth); } + pat_ident(pth, option::some(sub)) { it(pat.id, pat.span, pth); + pat_bindings(sub, it); } pat_enum(_, sub) { for p in sub { pat_bindings(p, it); } } pat_rec(fields, _) { for f in fields { pat_bindings(f.pat, it); } } pat_tup(elts) { for elt in elts { pat_bindings(elt, it); } } @@ -106,7 +106,7 @@ fn pat_bindings(pat: @pat, it: fn(@pat)) { fn pat_binding_ids(pat: @pat) -> [node_id] { let found = []; - pat_bindings(pat) {|b| found += [b.id]; }; + pat_bindings(pat) {|b_id, _sp, _pt| found += [b_id]; }; ret found; } diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index 2d3b9adc9bb..1c04541e764 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -45,15 +45,15 @@ enum scope { type scopes = list<scope>; enum import_state { - todo(ast::node_id, ast::ident, @[ast::ident], codemap::span, scopes), - is_glob(@[ast::ident], scopes, codemap::span), + todo(ast::node_id, ast::ident, @[ast::ident], span, scopes), + is_glob(@[ast::ident], scopes, span), resolving(span), resolved(option::t<def>, /* value */ option::t<def>, /* type */ option::t<def>, /* module */ @[@_impl], /* impls */ /* used for reporting unused import warning */ - ast::ident, codemap::span), + ast::ident, span), } enum glob_import_state { @@ -83,11 +83,13 @@ fn new_ext_hash() -> ext_hash { } enum mod_index_entry { - mie_view_item(@ast::view_item), - mie_import_ident(node_id, codemap::span), + mie_view_item(ident, node_id, span), + mie_import_ident(node_id, span), mie_item(@ast::item), mie_native_item(@ast::native_item), - mie_enum_variant(/* enum item */@ast::item, /* variant index */uint), + mie_enum_variant(/* variant index */uint, + /*parts of enum item*/ [variant], + node_id, span), } type mod_index = hashmap<ident, list<mod_index_entry>>; @@ -278,6 +280,8 @@ fn map_crate(e: @env, c: @ast::crate) { scope_crate { e.mod_map.get(ast::crate_node_id).glob_imports += [glob]; } + _ { e.sess.span_bug(vi.span, "Unexpected scope in a glob \ + import"); } } } } @@ -294,6 +298,7 @@ fn resolve_imports(e: env) { resolve_import(e, local_def(node_id), name, *path, span, scopes); } resolved(_, _, _, _, _, _) | is_glob(_, _, _) { } + _ { e.sess.bug("Shouldn't see a resolving in resolve_imports"); } } }; e.used_imports.track = false; @@ -478,7 +483,7 @@ fn visit_fn_with_scope(e: @env, fk: visit::fn_kind, decl: ast::fn_decl, if is_main_name([nm]) && !e.sess.building_library { // This is a main function -- set it in the session // as the main ID - e.sess.main_fn = some(id); + e.sess.main_fn = some((id, sp)); } } _ { /* fallthrough */ } @@ -665,6 +670,9 @@ fn resolve_import(e: env, defid: ast::def_id, name: ast::ident, lst(id, option::get(e.mod_map.get(ast::crate_node_id).m).view_items) } + _ { + e.sess.bug("find_imports_after: nil or unexpected scope"); + } } } // This function has cleanup code at the end. Do not return without going @@ -904,6 +912,10 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace) ast::native_item_fn(decl, ty_params) { ret lookup_in_fn(e, name, decl, ty_params, ns); } + _ { + e.sess.span_bug(it.span, "lookup_in_scope: \ + scope_native_item doesn't refer to a native item"); + } } } scope_bare_fn(decl, _, ty_params) | @@ -1005,10 +1017,10 @@ fn lookup_in_ty_params(e: env, name: ident, ty_params: [ast::ty_param]) fn lookup_in_pat(e: env, name: ident, pat: @ast::pat) -> option::t<def_id> { let found = none; - pat_util::pat_bindings(normalize_pat_def_map(e.def_map, pat)) {|bound| - let p_name = alt bound.node { ast::pat_ident(n, _) { n } }; - if str::eq(path_to_ident(p_name), name) - { found = some(local_def(bound.id)); } + pat_util::pat_bindings(normalize_pat_def_map(e.def_map, pat)) + {|p_id, _sp, n| + if str::eq(path_to_ident(n), name) + { found = some(local_def(p_id)); } }; ret found; } @@ -1114,6 +1126,7 @@ fn lookup_in_block(e: env, name: ident, sp: span, b: ast::blk_, pos: uint, _ {} } } + _ { e.sess.span_bug(vi.span, "Unexpected view_item in block"); } } } ret none; @@ -1189,16 +1202,16 @@ fn lookup_in_mod(e: env, m: def, sp: span, name: ident, ns: namespace, ast::def_native_mod(defid) { ret lookup_in_local_native_mod(e, defid.node, sp, name, ns); } + _ { + // Precondition + e.sess.span_bug(sp, "lookup_in_mod was passed a non-mod def"); + } } } -fn found_view_item(e: env, vi: @ast::view_item) -> option::t<def> { - alt vi.node { - ast::view_item_use(_, _, id) { - let cnum = cstore::get_use_stmt_cnum(e.cstore, id); - ret some(ast::def_mod({crate: cnum, node: ast::crate_node_id})); - } - } +fn found_view_item(e: env, id: node_id) -> def { + let cnum = cstore::get_use_stmt_cnum(e.cstore, id); + ret ast::def_mod({crate: cnum, node: ast::crate_node_id}); } fn lookup_import(e: env, defid: def_id, ns: namespace) -> option::t<def> { @@ -1220,6 +1233,9 @@ fn lookup_import(e: env, defid: def_id, ns: namespace) -> option::t<def> { ret alt ns { ns_val(_) { val } ns_type { typ } ns_module { md } }; } + is_glob(_,_,_) { + e.sess.bug("lookup_import: can't handle is_glob"); + } } } @@ -1267,6 +1283,9 @@ fn lookup_in_globs(e: env, globs: [glob_imp_def], sp: span, id: ident, ast::view_item_import_glob(_, id) { if vec::member(id, e.ignored_imports) { ret none; } } + _ { + e.sess.span_bug(sp, "lookup_in_globs: not a glob"); + } } alt lookup_in_mod(e, def.def, sp, name, ns, dr) { some(d) { option::some({def: d, item: def.item}) } @@ -1322,24 +1341,20 @@ fn lookup_glob_in_mod(e: env, info: @indexed_mod, sp: span, id: ident, fn lookup_in_mie(e: env, mie: mod_index_entry, ns: namespace) -> option::t<def> { alt mie { - mie_view_item(view_item) { - if ns == ns_module { ret found_view_item(e, view_item); } + mie_view_item(_, id, _) { + if ns == ns_module { ret some(found_view_item(e, id)); } } mie_import_ident(id, _) { ret lookup_import(e, local_def(id), ns); } mie_item(item) { ret found_def_item(item, ns); } - mie_enum_variant(item, variant_idx) { - alt item.node { - ast::item_enum(variants, _) { - alt ns { - ns_val(_) { - let vid = variants[variant_idx].node.id; - ret some(ast::def_variant(local_def(item.id), + mie_enum_variant(variant_idx, variants, parent_id, parent_span) { + alt ns { + ns_val(_) { + let vid = variants[variant_idx].node.id; + ret some(ast::def_variant(local_def(parent_id), local_def(vid))); - } - _ { ret none::<def>; } - } - } - } + } + _ { ret none::<def>; } + } } mie_native_item(native_item) { alt native_item.node { @@ -1374,8 +1389,8 @@ fn index_mod(md: ast::_mod) -> mod_index { let index = new_str_hash::<list<mod_index_entry>>(); for it: @ast::view_item in md.view_items { alt it.node { - ast::view_item_use(ident, _, _) { - add_to_index(index, ident, mie_view_item(it)); + ast::view_item_use(ident, _, id) { + add_to_index(index, ident, mie_view_item(ident, id, it.span)); } ast::view_item_import(ident, _, id) { add_to_index(index, ident, mie_import_ident(id, it.span)); @@ -1405,7 +1420,8 @@ fn index_mod(md: ast::_mod) -> mod_index { let variant_idx: uint = 0u; for v: ast::variant in variants { add_to_index(index, v.node.name, - mie_enum_variant(it, variant_idx)); + mie_enum_variant(variant_idx, variants, + it.id, it.span)); variant_idx += 1u; } } @@ -1418,8 +1434,9 @@ fn index_nmod(md: ast::native_mod) -> mod_index { let index = new_str_hash::<list<mod_index_entry>>(); for it: @ast::view_item in md.view_items { alt it.node { - ast::view_item_use(ident, _, _) { - add_to_index(index, ident, mie_view_item(it)); + ast::view_item_use(ident, _, id) { + add_to_index(index, ident, mie_view_item(ident, id, + it.span)); } ast::view_item_import(ident, _, id) { add_to_index(index, ident, mie_import_ident(id, it.span)); @@ -1431,6 +1448,7 @@ fn index_nmod(md: ast::native_mod) -> mod_index { } } ast::view_item_import_glob(_, _) | ast::view_item_export(_, _) { } + _ { /* tag exports */ } } } for it: @ast::native_item in md.items { @@ -1450,6 +1468,7 @@ fn ns_for_def(d: def) -> namespace { ast::def_mod(_) | ast::def_native_mod(_) { ns_module } ast::def_ty(_) | ast::def_binding(_) | ast::def_use(_) | ast::def_native_ty(_) { ns_type } + ast::def_ty_param(_, _) { ns_type } } } @@ -1529,10 +1548,10 @@ fn check_mod_name(e: env, name: ident, entries: list<mod_index_entry>) { fn mie_span(mie: mod_index_entry) -> span { ret alt mie { - mie_view_item(item) { item.span } + mie_view_item(_, _, span) { span } mie_import_ident(_, span) { span } mie_item(item) { item.span } - mie_enum_variant(item, _) { item.span } + mie_enum_variant(_, _, _, span) { span } mie_native_item(item) { item.span } }; } @@ -1559,9 +1578,8 @@ fn check_item(e: @env, i: @ast::item, &&x: (), v: vt<()>) { } fn check_pat(e: @env, ch: checker, p: @ast::pat) { - pat_util::pat_bindings(normalize_pat_def_map(e.def_map, p)) {|p| - let ident = path_to_ident(alt p.node { pat_ident(n, _) { n } }); - add_name(ch, p.span, ident); + pat_util::pat_bindings(normalize_pat_def_map(e.def_map, p)) {|_i, p_sp, n| + add_name(ch, p_sp, path_to_ident(n)); }; } @@ -1607,14 +1625,13 @@ fn check_block(e: @env, b: ast::blk, &&x: (), v: vt<()>) { ast::decl_local(locs) { let local_values = checker(*e, "value"); for (_, loc) in locs { - pat_util::pat_bindings - (normalize_pat_def_map(e.def_map, loc.node.pat)) - {|p| - let ident = path_to_ident(alt p.node - { pat_ident(n, _) { n } }); - add_name(local_values, p.span, ident); - check_name(values, p.span, ident); - }; + pat_util::pat_bindings + (normalize_pat_def_map(e.def_map, loc.node.pat)) + {|_i, p_sp, n| + let ident = path_to_ident(n); + add_name(local_values, p_sp, ident); + check_name(values, p_sp, ident); + }; } } ast::decl_item(it) { @@ -1807,8 +1824,9 @@ fn check_exports(e: @env) { some(ms) { list::iter(ms) {|m| alt m { - mie_enum_variant(parent_item,_) { - if parent_item.id != parent_id { + mie_enum_variant(_, _, actual_parent_id, + _) { + if actual_parent_id != parent_id { e.sess.span_err(vi.span, #fmt("variant %s \ doesn't belong to enum %s", @@ -1860,6 +1878,10 @@ fn find_impls_in_view_item(e: env, vi: @ast::view_item, scopes); alt e.imports.get(id) { resolved(_, _, _, is, _, _) { act(is); } + _ { + e.sess.bug("Undocumented invariant in \ + lookup_imported_impls"); + } } } _ {} @@ -1899,6 +1921,8 @@ fn find_impls_in_view_item(e: env, vi: @ast::view_item, _ {} } } + _ { e.sess.span_bug(vi.span, "Undocumented invariant in \ + find_impls_in_view_item"); } } } _ {} diff --git a/src/comp/middle/shape.rs b/src/comp/middle/shape.rs index 7612148df45..69c08d68e20 100644 --- a/src/comp/middle/shape.rs +++ b/src/comp/middle/shape.rs @@ -451,6 +451,12 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint]) -> [u8] { ty::ty_opaque_closure_ptr(_) { s += [shape_opaque_closure_ptr]; } + ty::ty_constr(inner_t, _) { + s += shape_of(ccx, inner_t, ty_param_map); + } + ty::ty_named(_, _) { + ccx.tcx.sess.bug("shape_of: shouldn't see a ty_named"); + } } ret s; @@ -699,6 +705,7 @@ fn static_size_of_enum(cx: @crate_ctxt, t: ty::t) cx.enum_sizes.insert(t, max_size); ret max_size; } + _ { cx.tcx.sess.bug("static_size_of_enum called on non-enum"); } } } @@ -779,6 +786,11 @@ fn dynamic_metrics(cx: @block_ctxt, t: ty::t) -> metrics { { bcx: bcx, sz: sz, align: C_int(ccx, 1) } } + _ { + // Precondition? + bcx_tcx(cx).sess.bug("dynamic_metrics: type has static \ + size"); + } } } diff --git a/src/comp/middle/trans/alt.rs b/src/comp/middle/trans/alt.rs index 9cd237828ff..a18a6bb1aa1 100644 --- a/src/comp/middle/trans/alt.rs +++ b/src/comp/middle/trans/alt.rs @@ -21,7 +21,7 @@ import common::*; // range) enum opt { lit(@ast::expr), - var(/* disr val */int, /* variant dids */{tg: def_id, var: def_id}), + var(/* disr val */int, /* variant dids */{enm: def_id, var: def_id}), range(@ast::expr, @ast::expr) } fn opt_eq(a: opt, b: opt) -> bool { @@ -69,7 +69,7 @@ fn trans_opt(bcx: @block_ctxt, o: opt) -> opt_result { // FIXME: invariant -- pat_id is bound in the def_map? fn variant_opt(ccx: @crate_ctxt, pat_id: ast::node_id) -> opt { let vdef = ast_util::variant_def_ids(ccx.tcx.def_map.get(pat_id)); - let variants = ty::enum_variants(ccx.tcx, vdef.tg); + let variants = ty::enum_variants(ccx.tcx, vdef.enm); for v: ty::variant_info in *variants { if vdef.var == v.id { ret var(v.disr_val, vdef); } } @@ -262,24 +262,24 @@ fn get_options(ccx: @crate_ctxt, m: match, col: uint) -> [opt] { } fn extract_variant_args(bcx: @block_ctxt, pat_id: ast::node_id, - vdefs: {tg: def_id, var: def_id}, val: ValueRef) -> + vdefs: {enm: def_id, var: def_id}, val: ValueRef) -> {vals: [ValueRef], bcx: @block_ctxt} { let ccx = bcx.fcx.lcx.ccx, bcx = bcx; // invariant: // pat_id must have the same length ty_param_substs as vdefs? let ty_param_substs = ty::node_id_to_type_params(ccx.tcx, pat_id); let blobptr = val; - let variants = ty::enum_variants(ccx.tcx, vdefs.tg); + let variants = ty::enum_variants(ccx.tcx, vdefs.enm); let args = []; let size = - vec::len(ty::enum_variant_with_id(ccx.tcx, vdefs.tg, vdefs.var).args); + vec::len(ty::enum_variant_with_id(ccx.tcx, vdefs.enm, vdefs.var).args); if size > 0u && vec::len(*variants) != 1u { let enumptr = PointerCast(bcx, val, T_opaque_enum_ptr(ccx)); blobptr = GEPi(bcx, enumptr, [0, 1]); } let i = 0u; - let vdefs_tg = vdefs.tg; + let vdefs_tg = vdefs.enm; let vdefs_var = vdefs.var; while i < size { check (valid_variant_index(i, bcx, vdefs_tg, vdefs_var)); @@ -423,8 +423,7 @@ fn compile_submatch(bcx: @block_ctxt, m: match, vals: [ValueRef], f: mk_fail, // Separate path for extracting and binding record fields if vec::len(rec_fields) > 0u { let rec_ty = ty::node_id_to_type(ccx.tcx, pat_id); - let fields = - alt ty::struct(ccx.tcx, rec_ty) { ty::ty_rec(fields) { fields } }; + let fields = ty::get_fields(ccx.tcx, rec_ty); let rec_vals = []; for field_name: ast::ident in rec_fields { let ix = option::get(ty::field_idx(field_name, fields)); @@ -444,6 +443,10 @@ fn compile_submatch(bcx: @block_ctxt, m: match, vals: [ValueRef], f: mk_fail, let n_tup_elts = alt ty::struct(ccx.tcx, tup_ty) { ty::ty_tup(elts) { vec::len(elts) } + _ { + ccx.sess.bug("Non-tuple type in tuple\ + pattern"); + } }; let tup_vals = [], i = 0u; while i < n_tup_elts { @@ -483,7 +486,7 @@ fn compile_submatch(bcx: @block_ctxt, m: match, vals: [ValueRef], f: mk_fail, if vec::len(opts) > 0u { alt opts[0] { var(_, vdef) { - if vec::len(*ty::enum_variants(ccx.tcx, vdef.tg)) == 1u { + if vec::len(*ty::enum_variants(ccx.tcx, vdef.enm)) == 1u { kind = single; } else { let enumptr = @@ -541,6 +544,8 @@ fn compile_submatch(bcx: @block_ctxt, m: match, vals: [ValueRef], f: mk_fail, llvm::LLVMAddCase(sw, r.val, opt_cx.llbb); bcx = r.bcx; } + _ { bcx_tcx(bcx).sess.bug("Someone forgot to\ + document an invariant in compile_submatch"); } } } compare { @@ -624,8 +629,11 @@ fn make_phi_bindings(bcx: @block_ctxt, map: [exit_node], // Copy references that the alias analysis considered unsafe ids.values {|node_id| if bcx_ccx(bcx).copy_map.contains_key(node_id) { - let local = alt bcx.fcx.lllocals.get(node_id) { - local_mem(x) { x } + let local = alt bcx.fcx.lllocals.find(node_id) { + some(local_mem(x)) { x } + _ { bcx_tcx(bcx).sess.bug("Someone \ + forgot to document an invariant in \ + make_phi_bindings"); } }; let e_ty = ty::node_id_to_type(bcx_tcx(bcx), node_id); let {bcx: abcx, val: alloc} = base::alloc_ty(bcx, e_ty); @@ -745,8 +753,7 @@ fn bind_irrefutable_pat(bcx: @block_ctxt, pat: @ast::pat, val: ValueRef, } ast::pat_rec(fields, _) { let rec_ty = ty::node_id_to_type(ccx.tcx, pat.id); - let rec_fields = - alt ty::struct(ccx.tcx, rec_ty) { ty::ty_rec(fields) { fields } }; + let rec_fields = ty::get_fields(ccx.tcx, rec_ty); for f: ast::field_pat in fields { let ix = option::get(ty::field_idx(f.ident, rec_fields)); // how to get rid of this check? diff --git a/src/comp/middle/trans/base.rs b/src/comp/middle/trans/base.rs index 85c23f4937c..7bff9b25060 100644 --- a/src/comp/middle/trans/base.rs +++ b/src/comp/middle/trans/base.rs @@ -42,6 +42,7 @@ import link::{mangle_internal_name_by_type_only, import metadata::{csearch, cstore}; import util::ppaux::{ty_to_str, ty_to_short_str}; +import shape::static_size_of_enum; import common::*; import build::*; @@ -489,37 +490,6 @@ fn simplify_type(ccx: @crate_ctxt, typ: ty::t) -> ty::t { ret ty::fold_ty(ccx.tcx, ty::fm_general(bind simplifier(ccx, _)), typ); } - -// Computes the size of the data part of a non-dynamically-sized enum. -fn static_size_of_enum(cx: @crate_ctxt, t: ty::t) - : type_has_static_size(cx, t) -> uint { - if cx.enum_sizes.contains_key(t) { ret cx.enum_sizes.get(t); } - alt ty::struct(cx.tcx, t) { - ty::ty_enum(tid, subtys) { - // Compute max(variant sizes). - - let max_size = 0u; - let variants = ty::enum_variants(cx.tcx, tid); - for variant: ty::variant_info in *variants { - let tup_ty = simplify_type(cx, ty::mk_tup(cx.tcx, variant.args)); - // Perform any type parameter substitutions. - - tup_ty = ty::substitute_type_params(cx.tcx, subtys, tup_ty); - // Here we possibly do a recursive call. - - // FIXME: Avoid this check. Since the parent has static - // size, any field must as well. There should be a way to - // express that with constrained types. - check (type_has_static_size(cx, tup_ty)); - let this_size = llsize_of_real(cx, type_of(cx, tup_ty)); - if max_size < this_size { max_size = this_size; } - } - cx.enum_sizes.insert(t, max_size); - ret max_size; - } - } -} - fn dynamic_size_of(cx: @block_ctxt, t: ty::t) -> result { fn align_elements(cx: @block_ctxt, elts: [ty::t]) -> result { // @@ -600,6 +570,9 @@ fn dynamic_size_of(cx: @block_ctxt, t: ty::t) -> result { } else { max_size_val }; ret rslt(bcx, total_size); } + // Precondition? + _ { bcx_tcx(cx).sess.fatal("trans::dynamic_size_of alled on something \ + with static size"); } } } @@ -634,6 +607,8 @@ fn dynamic_align_of(cx: @block_ctxt, t: ty::t) -> result { } ret rslt(bcx, a); } + _ { bcx_tcx(cx).sess.bug("trans::dynamic_align_of called on \ + something with static size"); } } } @@ -1457,16 +1432,16 @@ fn compare_scalar_types(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef, ty::ty_int(_) { ret rslt(cx, f(signed_int)); } ty::ty_uint(_) { ret rslt(cx, f(unsigned_int)); } ty::ty_float(_) { ret rslt(cx, f(floating_point)); } + ty::ty_native(_) { + let cx = trans_fail(cx, none::<span>, + "attempt to compare values of type native"); + ret rslt(cx, C_nil()); + } ty::ty_type { ret rslt(trans_fail(cx, none, "attempt to compare values of type type"), C_nil()); } - ty::ty_native(_) { - let cx = trans_fail(cx, none, - "attempt to compare values of type native"); - ret rslt(cx, C_nil()); - } _ { // Should never get here, because t is scalar. bcx_ccx(cx).sess.bug("non-scalar type passed to \ @@ -1479,6 +1454,11 @@ fn compare_scalar_types(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef, // A helper function to do the actual comparison of scalar values. fn compare_scalar_values(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef, nt: scalar_type, op: ast::binop) -> ValueRef { + fn die_(cx: @block_ctxt) -> ! { + bcx_tcx(cx).sess.bug("compare_scalar_values: must be a\ + comparison operator"); + } + let die = bind die_(cx); alt nt { nil_type { // We don't need to do actual comparisons for nil. @@ -1486,6 +1466,8 @@ fn compare_scalar_values(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef, alt op { ast::eq | ast::le | ast::ge { ret C_bool(true); } ast::ne | ast::lt | ast::gt { ret C_bool(false); } + // refinements would be nice + _ { die(); } } } floating_point { @@ -1496,6 +1478,7 @@ fn compare_scalar_values(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef, ast::le { lib::llvm::LLVMRealOLE } ast::gt { lib::llvm::LLVMRealOGT } ast::ge { lib::llvm::LLVMRealOGE } + _ { die(); } }; ret FCmp(cx, cmp, lhs, rhs); } @@ -1507,6 +1490,7 @@ fn compare_scalar_values(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef, ast::le { lib::llvm::LLVMIntSLE } ast::gt { lib::llvm::LLVMIntSGT } ast::ge { lib::llvm::LLVMIntSGE } + _ { die(); } }; ret ICmp(cx, cmp, lhs, rhs); } @@ -1518,6 +1502,7 @@ fn compare_scalar_values(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef, ast::le { lib::llvm::LLVMIntULE } ast::gt { lib::llvm::LLVMIntUGT } ast::ge { lib::llvm::LLVMIntUGE } + _ { die(); } }; ret ICmp(cx, cmp, lhs, rhs); } @@ -1574,6 +1559,8 @@ fn iter_structural_ty(cx: @block_ctxt, av: ValueRef, t: ty::t, j += 1u; } } + // Precondition? + _ { bcx_tcx(cx).sess.bug("iter_variant: not a function type"); } } ret cx; } @@ -1846,6 +1833,8 @@ fn drop_ty_immediate(bcx: @block_ctxt, v: ValueRef, t: ty::t) -> @block_ctxt { alt ty::struct(bcx_tcx(bcx), t) { ty::ty_uniq(_) | ty::ty_vec(_) | ty::ty_str { free_ty(bcx, v, t) } ty::ty_box(_) | ty::ty_iface(_, _) { decr_refcnt_maybe_free(bcx, v, t) } + // Precondition? + _ { bcx_tcx(bcx).sess.bug("drop_ty_immediate: non-box ty"); } } } @@ -2112,6 +2101,9 @@ fn trans_compare(cx: @block_ctxt, op: ast::binop, lhs: ValueRef, ast::eq | ast::ne { llop = C_u8(abi::cmp_glue_op_eq); } ast::lt | ast::ge { llop = C_u8(abi::cmp_glue_op_lt); } ast::le | ast::gt { llop = C_u8(abi::cmp_glue_op_le); } + // Precondition? + _ { bcx_tcx(cx).sess.bug("trans_compare got\ + non-comparison-op"); } } let rs = call_cmp_glue(cx, lhs, rhs, rhs_t, llop); @@ -2122,6 +2114,8 @@ fn trans_compare(cx: @block_ctxt, op: ast::binop, lhs: ValueRef, ast::ne | ast::ge | ast::gt { ret rslt(rs.bcx, Not(rs.bcx, rs.val)); } + _ { bcx_tcx(cx).sess.bug("trans_compare got\ + non-comparison-op"); } } } @@ -2272,9 +2266,12 @@ fn autoderef(cx: @block_ctxt, v: ValueRef, t: ty::t) -> result_t { ret {bcx: cx, val: v1, ty: t1}; } -fn trans_lazy_binop(bcx: @block_ctxt, op: ast::binop, a: @ast::expr, +// refinement types would obviate the need for this +enum lazy_binop_ty { lazy_and, lazy_or } + +fn trans_lazy_binop(bcx: @block_ctxt, op: lazy_binop_ty, a: @ast::expr, b: @ast::expr, dest: dest) -> @block_ctxt { - let is_and = alt op { ast::and { true } ast::or { false } }; + let is_and = alt op { lazy_and { true } lazy_or { false } }; let lhs_res = trans_temp_expr(bcx, a); if lhs_res.bcx.unreachable { ret lhs_res.bcx; } let rhs_cx = new_scope_block_ctxt(lhs_res.bcx, "rhs"); @@ -2321,8 +2318,11 @@ fn trans_binary(bcx: @block_ctxt, op: ast::binop, lhs: @ast::expr, // First couple cases are lazy: alt op { - ast::and | ast::or { - ret trans_lazy_binop(bcx, op, lhs, rhs, dest); + ast::and { + ret trans_lazy_binop(bcx, lazy_and, lhs, rhs, dest); + } + ast::or { + ret trans_lazy_binop(bcx, lazy_or, lhs, rhs, dest); } _ { // Remaining cases are eager: @@ -2394,7 +2394,11 @@ fn store_in_dest(bcx: @block_ctxt, val: ValueRef, dest: dest) -> @block_ctxt { } fn get_dest_addr(dest: dest) -> ValueRef { - alt dest { save_in(a) { a } } + alt dest { + save_in(a) { a } + // Precondition? + _ { fail "get_dest_addr: not a save_in"; } + } } fn trans_if(cx: @block_ctxt, cond: @ast::expr, thn: ast::blk, @@ -2425,6 +2429,9 @@ fn trans_if(cx: @block_ctxt, cond: @ast::expr, thn: ast::blk, ast::expr_block(blk) { else_cx = trans_block_dps(else_cx, blk, else_dest); } + // would be nice to have a constraint on ifs + _ { bcx_tcx(cx).sess.bug("Strange alternative\ + in if"); } } } _ {} @@ -2691,7 +2698,12 @@ fn trans_rec_field(bcx: @block_ctxt, base: @ast::expr, field: ast::ident) -> lval_result { let {bcx, val} = trans_temp_expr(bcx, base); let {bcx, val, ty} = autoderef(bcx, val, ty::expr_ty(bcx_tcx(bcx), base)); - let fields = alt ty::struct(bcx_tcx(bcx), ty) { ty::ty_rec(fs) { fs } }; + let fields = alt ty::struct(bcx_tcx(bcx), ty) { + ty::ty_rec(fs) { fs } + // Constraint? + _ { bcx_tcx(bcx).sess.span_bug(base.span, "trans_rec_field:\ + base expr has non-record type"); } + }; let ix = option::get(ty::field_idx(field, fields)); // Silly check check type_is_tup_like(bcx, ty); @@ -2763,6 +2775,9 @@ fn trans_callee(bcx: @block_ctxt, e: @ast::expr) -> lval_maybe_callee { some(origin) { // An impl method ret impl::trans_method_callee(bcx, e.id, base, origin); } + // Precondition? + _ { bcx_tcx(bcx).sess.span_bug(e.span, "trans_callee: weird\ + expr"); } } } } @@ -2809,6 +2824,11 @@ fn trans_lval(cx: @block_ctxt, e: @ast::expr) -> lval_result { PointerCast(sub.bcx, sub.val, ellty) } ty::ty_ptr(_) | ty::ty_uniq(_) { sub.val } + // Precondition? + _ { + bcx_tcx(cx).sess.span_bug(e.span, "trans_lval:\ + Weird argument in deref"); + } }; ret lval_owned(sub.bcx, val); } @@ -2949,6 +2969,7 @@ fn trans_cast(cx: @block_ctxt, e: @ast::expr, id: ast::node_id, integral {int_cast(e_res.bcx, ll_t_out, val_ty(lldiscrim_a), lldiscrim_a, true)} float {SIToFP(e_res.bcx, lldiscrim_a, ll_t_out)} + _ { ccx.sess.bug("Translating unsupported cast.") } } } _ { ccx.sess.bug("Translating unsupported cast.") } @@ -2990,7 +3011,7 @@ fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty: TypeRef, if arg.mode == ast::by_val && (lv.kind == owned || !imm) { val = Load(bcx, val); } - } else if arg.mode == ast::by_copy { + } else if arg.mode == ast::by_copy { let {bcx: cx, val: alloc} = alloc_ty(bcx, e_ty); let last_use = ccx.last_uses.contains_key(e.id); bcx = cx; @@ -3341,6 +3362,7 @@ fn trans_tup(bcx: @block_ctxt, elts: [@ast::expr], id: ast::node_id, ret bcx; } save_in(pos) { pos } + _ { bcx_tcx(bcx).sess.bug("trans_tup: weird dest"); } }; let temp_cleanups = [], i = 0; for e in elts { @@ -3368,9 +3390,12 @@ fn trans_rec(bcx: @block_ctxt, fields: [ast::field], ret bcx; } save_in(pos) { pos } + _ { bcx_tcx(bcx).sess.bug("trans_rec: weird dest"); } }; - let ty_fields = alt ty::struct(bcx_tcx(bcx), t) { ty::ty_rec(f) { f } }; + let ty_fields = alt ty::struct(bcx_tcx(bcx), t) { ty::ty_rec(f) { f } + _ { bcx_tcx(bcx).sess.bug("trans_rec: id doesn't\ + have a record type") } }; let temp_cleanups = []; for fld in fields { let ix = option::get(vec::position_pred(ty_fields, {|ft| @@ -3644,6 +3669,9 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt { assert dest == ignore; ret trans_assign_op(bcx, e, op, dst, src); } + _ { bcx_tcx(bcx).sess.span_bug(e.span, "trans_expr reached\ + fall-through case"); } + } } @@ -3914,9 +3942,18 @@ fn init_local(bcx: @block_ctxt, local: @ast::local) -> @block_ctxt { let ty = node_id_type(bcx_ccx(bcx), local.node.id); let llptr = alt bcx.fcx.lllocals.find(local.node.id) { some(local_mem(v)) { v } + some(_) { bcx_tcx(bcx).sess.span_bug(local.span, + "init_local: Someone forgot to document why it's\ + safe to assume local.node.init must be local_mem!"); + } // This is a local that is kept immediate none { - let initexpr = alt local.node.init { some({expr, _}) { expr } }; + let initexpr = alt local.node.init { + some({expr, _}) { expr } + none { bcx_tcx(bcx).sess.span_bug(local.span, + "init_local: Someone forgot to document why it's\ + safe to assume local.node.init isn't none!"); } + }; let {bcx, val, kind} = trans_temp_lval(bcx, initexpr); if kind != temporary { if kind == owned { val = Load(bcx, val); } @@ -3952,6 +3989,8 @@ fn init_ref_local(bcx: @block_ctxt, local: @ast::local) -> @block_ctxt { alt kind { owned_imm { val = do_spill_noroot(bcx, val); } owned {} + _ { bcx_tcx(bcx).sess.span_bug(local.span, + "Someone forgot to document an invariant in init_ref_local!"); } } ret alt::bind_irrefutable_pat(bcx, local.node.pat, val, false); } @@ -4388,9 +4427,15 @@ fn create_llargs_for_fn_args(cx: @fn_ctxt, ty_self: self_arg, fn copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg], arg_tys: [ty::arg]) -> @block_ctxt { let arg_n: uint = 0u, bcx = bcx; + fn epic_fail_(bcx: @block_ctxt) -> ! { + bcx_tcx(bcx).sess.bug("Someone forgot\ + to document an invariant in copy_args_to_allocas!"); + } + let epic_fail = bind epic_fail_(bcx); for arg in arg_tys { let id = args[arg_n].id; - let argval = alt fcx.llargs.get(id) { local_mem(v) { v } }; + let argval = alt fcx.llargs.get(id) { local_mem(v) { v } + _ { epic_fail() } }; alt arg.mode { ast::by_mut_ref { } ast::by_move | ast::by_copy { add_clean(bcx, argval, arg.ty); } @@ -4405,6 +4450,7 @@ fn copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg], } } ast::by_ref {} + _ { epic_fail(); } } if fcx_ccx(fcx).sess.opts.extra_debuginfo { debuginfo::create_arg(bcx, args[arg_n], args[arg_n].ty.span); @@ -4414,9 +4460,13 @@ fn copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg], ret bcx; } +// cries out for a precondition fn arg_tys_of_fn(ccx: @crate_ctxt, id: ast::node_id) -> [ty::arg] { - alt ty::struct(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)) { + let tt = ty::node_id_to_type(ccx.tcx, id); + alt ty::struct(ccx.tcx, tt) { ty::ty_fn({inputs, _}) { inputs } + _ { ccx.sess.bug(#fmt("arg_tys_of_fn called on non-function\ + type %s", ty_to_str(ccx.tcx, tt)));} } } @@ -4438,14 +4488,14 @@ enum self_arg { impl_self(ty::t), no_self, } // trans_closure: Builds an LLVM function out of a source function. // If the function closes over its environment a closure will be // returned. -fn trans_closure(cx: @local_ctxt, sp: span, decl: ast::fn_decl, +fn trans_closure(cx: @local_ctxt, decl: ast::fn_decl, body: ast::blk, llfndecl: ValueRef, ty_self: self_arg, ty_params: [ast::ty_param], id: ast::node_id, maybe_load_env: fn(@fn_ctxt)) { set_uwtable(llfndecl); // Set up arguments to the function. - let fcx = new_fn_ctxt_w_id(cx, llfndecl, id, decl.cf, some(sp)); + let fcx = new_fn_ctxt_w_id(cx, llfndecl, id, decl.cf, some(body.span)); create_llargs_for_fn_args(fcx, ty_self, decl.inputs, ty_params); // Create the first basic block in the function and keep a handle on it to @@ -4480,7 +4530,7 @@ fn trans_closure(cx: @local_ctxt, sp: span, decl: ast::fn_decl, // trans_fn: creates an LLVM function corresponding to a source language // function. -fn trans_fn(cx: @local_ctxt, sp: span, decl: ast::fn_decl, body: ast::blk, +fn trans_fn(cx: @local_ctxt, decl: ast::fn_decl, body: ast::blk, llfndecl: ValueRef, ty_self: self_arg, ty_params: [ast::ty_param], id: ast::node_id) { let do_time = cx.ccx.sess.opts.stats; @@ -4490,7 +4540,7 @@ fn trans_fn(cx: @local_ctxt, sp: span, decl: ast::fn_decl, body: ast::blk, {sec: 0u32, usec: 0u32} }; let fcx = option::none; - trans_closure(cx, sp, decl, body, llfndecl, ty_self, ty_params, id, + trans_closure(cx, decl, body, llfndecl, ty_self, ty_params, id, {|new_fcx| fcx = option::some(new_fcx);}); if cx.ccx.sess.opts.extra_debuginfo { debuginfo::create_function(option::get(fcx)); @@ -4516,6 +4566,8 @@ fn trans_res_ctor(cx: @local_ctxt, dtor: ast::fn_decl, let tup_t = ty::mk_tup(ccx.tcx, [ty::mk_int(ccx.tcx), arg_t]); let arg = alt fcx.llargs.find(dtor.inputs[0].id) { some(local_mem(x)) { x } + _ { ccx.sess.bug("Someone forgot to document an invariant \ + in trans_res_ctor"); } }; let llretptr = fcx.llretptr; if ty::type_has_dynamic_size(ccx.tcx, ret_t) { @@ -4603,7 +4655,9 @@ fn trans_enum_variant(cx: @local_ctxt, enum_id: ast::node_id, // If this argument to this function is a enum, it'll have come in to // this function as an opaque blob due to the way that type_of() // works. So we have to cast to the destination's view of the type. - let llarg = alt fcx.llargs.find(va.id) { some(local_mem(x)) { x } }; + let llarg = alt fcx.llargs.find(va.id) { some(local_mem(x)) { x } + _ { bcx_tcx(bcx).sess.span_fatal(variant.span, "Someone forgot\ + to document an invariant in trans_tag_variant"); } }; let arg_ty = arg_tys[i].ty; if ty::type_contains_params(bcx_tcx(bcx), arg_ty) { lldestptr = PointerCast(bcx, lldestptr, val_ty(llarg)); @@ -4733,6 +4787,10 @@ fn c_stack_tys(ccx: @crate_ctxt, shim_fn_ty: T_fn([T_ptr(bundle_ty)], T_void()) }; } + _ { + // Precondition? + ccx.tcx.sess.bug("c_stack_tys called on non-function type"); + } } } @@ -4889,7 +4947,7 @@ fn trans_item(cx: @local_ctxt, item: ast::item) { let sub_cx = extend_path(cx, item.ident); alt cx.ccx.item_ids.find(item.id) { some(llfndecl) { - trans_fn(sub_cx, item.span, decl, body, llfndecl, no_self, tps, + trans_fn(sub_cx, decl, body, llfndecl, no_self, tps, item.id); } _ { @@ -4907,7 +4965,7 @@ fn trans_item(cx: @local_ctxt, item: ast::item) { // Create a function for the destructor alt cx.ccx.item_ids.find(item.id) { some(lldtor_decl) { - trans_fn(cx, item.span, decl, body, lldtor_decl, no_self, + trans_fn(cx, decl, body, lldtor_decl, no_self, tps, dtor_id); } _ { @@ -4998,8 +5056,10 @@ fn create_main_wrapper(ccx: @crate_ctxt, sp: span, main_llfn: ValueRef, } let main_takes_argv = + // invariant! alt ty::struct(ccx.tcx, main_node_type) { ty::ty_fn({inputs, _}) { vec::len(inputs) != 0u } + _ { ccx.sess.span_fatal(sp, "main has a non-function type"); } }; let llfn = create_main(ccx, main_llfn, main_takes_argv); @@ -5094,7 +5154,10 @@ fn fill_fn_pair(bcx: @block_ctxt, pair: ValueRef, llfn: ValueRef, fn native_fn_ty_param_count(cx: @crate_ctxt, id: ast::node_id) -> uint { let count; let native_item = - alt cx.ast_map.find(id) { some(ast_map::node_native_item(i)) { i } }; + // invariant?! + alt cx.ast_map.find(id) { some(ast_map::node_native_item(i)) { i } + _ { cx.sess.bug("native_fn_ty_param_count\ + given a non-native item"); } }; alt native_item.node { ast::native_item_ty { cx.sess.bug("register_native_fn(): native fn isn't \ @@ -5107,13 +5170,17 @@ fn native_fn_ty_param_count(cx: @crate_ctxt, id: ast::node_id) -> uint { ret count; } -fn native_fn_wrapper_type(cx: @crate_ctxt, + +// TODO: precondition +fn native_fn_wrapper_type(cx: @crate_ctxt, sp: span, param_bounds: [ty::param_bounds], x: ty::t) -> TypeRef { alt ty::struct(cx.tcx, x) { ty::ty_fn({inputs: args, output: out, _}) { ret type_of_fn(cx, args, out, param_bounds); } + _ { cx.sess.span_bug(sp, "native_fn_wrapper_type got ill-typed\ + thing"); } } } diff --git a/src/comp/middle/trans/closure.rs b/src/comp/middle/trans/closure.rs index ed1d5e9158a..4ff6d6fca2b 100644 --- a/src/comp/middle/trans/closure.rs +++ b/src/comp/middle/trans/closure.rs @@ -520,7 +520,7 @@ fn trans_expr_fn(bcx: @block_ctxt, let cap_vars = capture::compute_capture_vars( ccx.tcx, id, proto, cap_clause); let {llbox, cbox_ty, bcx} = build_closure(bcx, cap_vars, ck); - trans_closure(sub_cx, sp, decl, body, llfn, no_self, [], id, {|fcx| + trans_closure(sub_cx, decl, body, llfn, no_self, [], id, {|fcx| load_environment(bcx, fcx, cbox_ty, cap_vars, ck); }); llbox @@ -532,7 +532,7 @@ fn trans_expr_fn(bcx: @block_ctxt, ast::proto_uniq { trans_closure_env(ty::ck_uniq) } ast::proto_bare { let closure = C_null(T_opaque_cbox_ptr(ccx)); - trans_closure(sub_cx, sp, decl, body, llfn, no_self, [], + trans_closure(sub_cx, decl, body, llfn, no_self, [], id, {|_fcx|}); closure } diff --git a/src/comp/middle/trans/common.rs b/src/comp/middle/trans/common.rs index 57c74d1bad3..96cc79a6db2 100644 --- a/src/comp/middle/trans/common.rs +++ b/src/comp/middle/trans/common.rs @@ -414,6 +414,9 @@ fn find_scope_cx(cx: @block_ctxt) -> @block_ctxt { if cx.kind != NON_SCOPE_BLOCK { ret cx; } alt cx.parent { parent_some(b) { ret find_scope_cx(b); } + _ { + bcx_tcx(cx).sess.bug("find_scope_cx: empty scope"); + } } } diff --git a/src/comp/middle/trans/impl.rs b/src/comp/middle/trans/impl.rs index 0798e0236f5..ded05d4bc0c 100644 --- a/src/comp/middle/trans/impl.rs +++ b/src/comp/middle/trans/impl.rs @@ -2,6 +2,7 @@ import core::ctypes::c_uint; import base::*; import common::*; import build::*; +import driver::session::session; import option::{some, none}; import syntax::{ast, ast_util}; import metadata::csearch; @@ -45,10 +46,13 @@ fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method], for m in methods { alt cx.ccx.item_ids.find(m.id) { some(llfn) { - trans_fn(extend_path(sub_cx, m.ident), m.span, m.decl, m.body, + trans_fn(extend_path(sub_cx, m.ident), m.decl, m.body, llfn, impl_self(ty::node_id_to_type(cx.ccx.tcx, id)), tps + m.tps, m.id); } + _ { + cx.ccx.tcx.sess.bug("Unbound id in trans_impl"); + } } } } @@ -148,6 +152,9 @@ fn trans_iface_callee(bcx: @block_ctxt, callee_id: ast::node_id, T_opaque_cbox_ptr(bcx_ccx(bcx))); let iface_id = alt ty::struct(tcx, ty::expr_ty(tcx, base)) { ty::ty_iface(did, _) { did } + // precondition + _ { bcx_tcx(bcx).sess.span_bug(base.span, "base has non-iface type \ + in trans_iface_callee"); } }; trans_vtable_callee(bcx, self, dict, callee_id, iface_id, n_method) } @@ -241,6 +248,10 @@ fn trans_impl_vtable(ccx: @crate_ctxt, pt: [ast::ident], let target = ccx.item_ids.get(m.id); trans_impl_wrapper(ccx, new_pt + [m.ident], extra_tps, target) } + _ { + ccx.tcx.sess.span_bug(it.span, "No matching method \ + in trans_impl_vtable"); + } } }); let s = link::mangle_internal_name_by_path(ccx, new_pt + ["!vtable"]); @@ -340,6 +351,10 @@ fn dict_id(tcx: ty::ctxt, origin: typeck::dict_origin) -> dict_id { d_params += [dict_param_dict(dict_id(tcx, origs[orig]))]; orig += 1u; } + _ { + tcx.sess.bug("Someone forgot to document an invariant in \ + dict_id"); + } } } } @@ -348,6 +363,9 @@ fn dict_id(tcx: ty::ctxt, origin: typeck::dict_origin) -> dict_id { typeck::dict_iface(did) { @{def: did, params: []} } + _ { + tcx.sess.bug("Unexpected dict_param in dict_id"); + } } } @@ -410,6 +428,9 @@ fn get_dict_ptrs(bcx: @block_ctxt, origin: typeck::dict_origin) typeck::dict_iface(did) { {bcx: bcx, ptrs: [get_vtable(ccx, did)]} } + _ { + bcx_tcx(bcx).sess.bug("Unexpected dict_param in get_dict_ptrs"); + } } } diff --git a/src/comp/middle/trans/tvec.rs b/src/comp/middle/trans/tvec.rs index 0b7df351d7a..7b4d0033ec8 100644 --- a/src/comp/middle/trans/tvec.rs +++ b/src/comp/middle/trans/tvec.rs @@ -1,6 +1,7 @@ import vec; import option::none; import syntax::ast; +import driver::session::session; import lib::llvm::llvm::{ValueRef, TypeRef}; import back::abi; import base::{call_memmove, trans_shared_malloc, type_of_or_i8, @@ -159,6 +160,10 @@ fn trans_append(cx: @block_ctxt, vec_ty: ty::t, lhsptr: ValueRef, let strings = alt ty::struct(bcx_tcx(cx), vec_ty) { ty::ty_str { true } ty::ty_vec(_) { false } + _ { + // precondition? + bcx_tcx(cx).sess.bug("Bad argument type in trans_append"); + } }; let {bcx: bcx, val: unit_sz} = size_of(cx, unit_ty); @@ -230,7 +235,7 @@ fn trans_add(bcx: @block_ctxt, vec_ty: ty::t, lhs: ValueRef, let ccx = bcx_ccx(bcx); let strings = alt ty::struct(bcx_tcx(bcx), vec_ty) { ty::ty_str { true } - ty::ty_vec(_) { false } + _ { false } }; let unit_ty = ty::sequence_element_type(bcx_tcx(bcx), vec_ty); let llunitty = type_of_or_i8(bcx, unit_ty); diff --git a/src/comp/middle/trans/uniq.rs b/src/comp/middle/trans/uniq.rs index 8cff8794081..cca7e8a7399 100644 --- a/src/comp/middle/trans/uniq.rs +++ b/src/comp/middle/trans/uniq.rs @@ -74,6 +74,7 @@ fn content_ty(bcx: @block_ctxt, t: ty::t) alt ty::struct(bcx_tcx(bcx), t) { ty::ty_uniq({ty: ct, _}) { ct } + _ { std::util::unreachable(); } } } diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs index e1b0ccccad1..2934d4a5b1e 100644 --- a/src/comp/middle/tstate/auxiliary.rs +++ b/src/comp/middle/tstate/auxiliary.rs @@ -582,12 +582,14 @@ fn expr_to_constr_arg(tcx: ty::ctxt, e: @expr) -> @constr_arg_use { ret @respan(p.span, carg_ident({ident: p.node.idents[0], node: id.node})); } - some(_) { - tcx.sess.bug("exprs_to_constr_args: non-local variable " + - "as pred arg"); + some(what) { + tcx.sess.span_bug(e.span, + #fmt("exprs_to_constr_args: non-local variable %? \ + as pred arg", what)); } none { - tcx.sess.bug("exprs_to_constr_args: NONE " + "as pred arg"); + tcx.sess.span_bug(e.span, + "exprs_to_constr_args: unbound id as pred arg"); } } @@ -1055,10 +1057,8 @@ type binding = {lhs: [inst], rhs: option::t<initializer>}; fn local_to_bindings(tcx: ty::ctxt, loc: @local) -> binding { let lhs = []; - pat_bindings(pat_util::normalize_pat(tcx, loc.node.pat)) {|p| - let ident = alt p.node - { pat_ident(name, _) { path_to_ident(name) } }; - lhs += [{ident: ident, node: p.id}]; + pat_bindings(pat_util::normalize_pat(tcx, loc.node.pat)) {|p_id, _s, name| + lhs += [{ident: path_to_ident(name), node: p_id}]; }; {lhs: lhs, rhs: loc.node.init} } @@ -1070,7 +1070,7 @@ fn locals_to_bindings(tcx: ty::ctxt, ret rslt; } -fn callee_modes(fcx: fn_ctxt, callee: node_id) -> [ty::mode] { +fn callee_modes(fcx: fn_ctxt, callee: node_id) -> [mode] { let ty = ty::type_autoderef(fcx.ccx.tcx, ty::node_id_to_type(fcx.ccx.tcx, callee)); @@ -1089,7 +1089,7 @@ fn callee_modes(fcx: fn_ctxt, callee: node_id) -> [ty::mode] { } fn callee_arg_init_ops(fcx: fn_ctxt, callee: node_id) -> [init_op] { - fn mode_to_op(m: ty::mode) -> init_op { + fn mode_to_op(m: mode) -> init_op { alt m { by_move { init_move } _ { init_assign } } } vec::map(callee_modes(fcx, callee), mode_to_op) diff --git a/src/comp/middle/tstate/collect_locals.rs b/src/comp/middle/tstate/collect_locals.rs index 30a93e4db36..1abc9903d5c 100644 --- a/src/comp/middle/tstate/collect_locals.rs +++ b/src/comp/middle/tstate/collect_locals.rs @@ -12,11 +12,9 @@ import aux::*; type ctxt = {cs: @mutable [sp_constr], tcx: ty::ctxt}; fn collect_local(loc: @local, cx: ctxt, v: visit::vt<ctxt>) { - pat_bindings(pat_util::normalize_pat(cx.tcx, loc.node.pat)) {|p| - let ident = alt p.node - { pat_ident(id, _) { path_to_ident(id) } }; - log(debug, "collect_local: pushing " + ident);; - *cx.cs += [respan(loc.span, ninit(p.id, ident))]; + pat_bindings(pat_util::normalize_pat(cx.tcx, loc.node.pat)) + {|p_id, _s, id| + *cx.cs += [respan(loc.span, ninit(p_id, path_to_ident(id)))]; }; visit::visit_local(loc, cx, v); } @@ -26,10 +24,6 @@ fn collect_pred(e: @expr, cx: ctxt, v: visit::vt<ctxt>) { expr_check(_, ch) { *cx.cs += [expr_to_constr(cx.tcx, ch)]; } expr_if_check(ex, _, _) { *cx.cs += [expr_to_constr(cx.tcx, ex)]; } - - - - // If it's a call, generate appropriate instances of the // call's constraints. expr_call(operator, operands, _) { diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index 987bbb4d81d..9977b20cddb 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -18,7 +18,6 @@ import util::common::{new_def_hash, log_expr, field_exprs, import syntax::codemap::span; import driver::session::session; - fn find_pre_post_mod(_m: _mod) -> _mod { #debug("implement find_pre_post_mod!"); fail; @@ -106,14 +105,12 @@ fn find_pre_post_loop(fcx: fn_ctxt, l: @local, index: @expr, body: blk, id: node_id) { find_pre_post_expr(fcx, index); find_pre_post_block(fcx, body); - pat_bindings(normalize_pat(fcx.ccx.tcx, l.node.pat)) {|p| - let ident = alt p.node - { pat_ident(id, _) { path_to_ident(id) } }; - let v_init = ninit(p.id, ident); + pat_bindings(normalize_pat(fcx.ccx.tcx, l.node.pat)) {|p_id, _s, n| + let v_init = ninit(p_id, path_to_ident(n)); relax_precond_block(fcx, bit_num(fcx, v_init) as node_id, body); // Hack: for-loop index variables are frequently ignored, // so we pretend they're used - use_var(fcx, p.id); + use_var(fcx, p_id); }; let loop_precond = @@ -289,10 +286,10 @@ fn handle_var_def(fcx: fn_ctxt, rslt: pre_and_post, def: def, name: ident) { } } -fn forget_args_moved_in(fcx: fn_ctxt, parent: @expr, modes: [ty::mode], +fn forget_args_moved_in(fcx: fn_ctxt, parent: @expr, modes: [mode], operands: [@expr]) { let i = 0u; - for mode: ty::mode in modes { + for mode: mode in modes { if mode == by_move { forget_in_postcond(fcx, parent.id, operands[i].id); } @@ -571,8 +568,8 @@ fn find_pre_post_stmt(fcx: fn_ctxt, s: stmt) { /* LHS always becomes initialized, whether or not this is a move */ find_pre_post_expr(fcx, an_init.expr); - pat_bindings(alocal.node.pat) {|p| - copy_pre_post(fcx.ccx, p.id, an_init.expr); + pat_bindings(alocal.node.pat) {|p_id, _s, _n| + copy_pre_post(fcx.ccx, p_id, an_init.expr); }; /* Inherit ann from initializer, and add var being initialized to the postcondition */ @@ -585,16 +582,12 @@ fn find_pre_post_stmt(fcx: fn_ctxt, s: stmt) { } pat_bindings(normalize_pat(fcx.ccx.tcx, alocal.node.pat)) - {|pat| - /* FIXME: This won't be necessary when typestate - works well enough for pat_bindings to return a - refinement-typed thing. */ - let ident = alt pat.node - { pat_ident(n, _) { path_to_ident(n) } }; + {|p_id, _s, n| + let ident = path_to_ident(n); alt p { some(p) { copy_in_postcond(fcx, id, - {ident: ident, node: pat.id}, + {ident: ident, node: p_id}, {ident: path_to_ident(p), node: an_init.expr.id}, @@ -602,7 +595,7 @@ fn find_pre_post_stmt(fcx: fn_ctxt, s: stmt) { } none { } } - gen(fcx, id, ninit(pat.id, ident)); + gen(fcx, id, ninit(p_id, ident)); }; if an_init.op == init_move && is_path(an_init.expr) { @@ -617,22 +610,16 @@ fn find_pre_post_stmt(fcx: fn_ctxt, s: stmt) { /* Include the LHSs too, since those aren't in the postconds of the RHSs themselves */ pat_bindings(normalize_pat(fcx.ccx.tcx, alocal.node.pat)) - {|pat| - // FIXME - // Generalize this pattern? map_if_ident... - alt pat.node { - pat_ident(n, _) { + {|pat_id, _s, n| set_in_postcond(bit_num(fcx, - ninit(pat.id, path_to_ident(n))), prev_pp); - } - } - }; + ninit(pat_id, path_to_ident(n))), prev_pp); + }; copy_pre_post_(fcx.ccx, id, prev_pp.precondition, prev_pp.postcondition); } none { - pat_bindings(alocal.node.pat) {|p| - clear_pp(node_id_to_ts_ann(fcx.ccx, p.id).conditions); + pat_bindings(alocal.node.pat) {|p_id, _s, _n| + clear_pp(node_id_to_ts_ann(fcx.ccx, p_id).conditions); }; clear_pp(node_id_to_ts_ann(fcx.ccx, id).conditions); } diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index a125c00d63b..9a4bfc26ddf 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -215,6 +215,8 @@ fn find_pre_post_state_exprs(fcx: fn_ctxt, pres: prestate, id: node_id, fn find_pre_post_state_loop(fcx: fn_ctxt, pres: prestate, l: @local, index: @expr, body: blk, id: node_id) -> bool { + // I'm confused about this -- how does the poststate for the body + // ever grow larger? It seems like it can't? let loop_pres = intersect_states(pres, block_poststate(fcx.ccx, body)); let changed = @@ -224,10 +226,9 @@ fn find_pre_post_state_loop(fcx: fn_ctxt, pres: prestate, l: @local, // Make sure the index vars are considered initialized // in the body let index_post = tritv_clone(expr_poststate(fcx.ccx, index)); - pat_bindings(pat_util::normalize_pat(fcx.ccx.tcx, l.node.pat)) {|p| - let ident = alt p.node - { pat_ident(name, _) { path_to_ident(name) } }; - set_in_poststate_ident(fcx, p.id, ident, index_post); + pat_bindings(pat_util::normalize_pat(fcx.ccx.tcx, l.node.pat)) + {|p_id, _s, n| + set_in_poststate_ident(fcx, p_id, path_to_ident(n), index_post); }; changed |= find_pre_post_state_block(fcx, index_post, body); diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 57031e7c6da..597fd548f04 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -42,6 +42,7 @@ export fold_ty; export field; export field_idx; export get_field; +export get_fields; export fm_general; export get_element_type; export idx_nil; @@ -84,7 +85,6 @@ export mk_var; export mk_opaque_closure_ptr; export mk_named; export gen_ty; -export mode; export mt; export node_type_table; export pat_ty; @@ -125,7 +125,6 @@ export ty_ptr; export ty_rec; export ty_enum; export ty_tup; -export ty_type; export ty_send_type; export ty_uint; export ty_uniq; @@ -177,7 +176,6 @@ export variant_info; export walk_ty; export occurs_check_fails; export closure_kind; -export ck_any; export ck_block; export ck_box; export ck_uniq; @@ -186,7 +184,10 @@ export param_bounds_to_kind; // Data types -type arg = {mode: mode, ty: t}; +// TODO: really should be a separate type, or a refinement, +// so that we don't have to handle the mode_infer case after +// typeck. but that's too hard right now. +type arg = {mode: ast::mode, ty: t}; type field = {ident: ast::ident, mt: mt}; @@ -232,7 +233,6 @@ type raw_t = {struct: sty, type t = uint; enum closure_kind { - ck_any, ck_block, ck_box, ck_uniq, @@ -458,7 +458,7 @@ fn mk_raw_ty(cx: ctxt, st: sty) -> @raw_t { } alt st { ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | - ty_str | ty_send_type | ty_type | ty_native(_) | + ty_str | ty_type | ty_send_type | ty_native(_) | ty_opaque_closure_ptr(_) { /* no-op */ } @@ -629,7 +629,7 @@ pure fn struct_raw(cx: ctxt, typ: t) -> sty { interner::get(*cx.ts, typ).struct } -// Returns struact(cx, typ) but replaces all occurences of platform +// Returns struct(cx, typ) but replaces all occurences of platform // dependent primitive types with their machine type equivalent pure fn mach_struct(cx: ctxt, cfg: @session::config, typ: t) -> sty { alt interner::get(*cx.ts, typ).struct { @@ -678,6 +678,9 @@ fn walk_ty(cx: ctxt, ty: t, f: fn(t)) { } ty_constr(sub, _) { walk_ty(cx, sub, f); } ty_uniq(tm) { walk_ty(cx, tm.ty, f); } + // precondition? + ty_named(_,_) { cx.sess.bug("walk_ty: should not see a ty_named \ + here"); } } f(ty); } @@ -699,7 +702,7 @@ fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t { } alt interner::get(*cx.ts, ty).struct { ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_str | ty_send_type | ty_type | ty_native(_) | + ty_str | ty_type | ty_send_type | ty_native(_) | ty_opaque_closure_ptr(_) { /* no-op */ } @@ -1033,6 +1036,7 @@ fn type_kind(cx: ctxt, ty: t) -> kind { param_bounds_to_kind(cx.ty_param_bounds.get(did.node)) } ty_constr(t, _) { type_kind(cx, t) } + _ { cx.sess.bug("Bad type in type_kind"); } }; cx.kind_cache.insert(ty, result); @@ -1192,9 +1196,14 @@ fn type_is_pod(cx: ctxt, ty: t) -> bool { } ty_constr(subt, _) { result = type_is_pod(cx, subt); } ty_var(_) { - fail "ty_var in type_is_pod"; + cx.sess.bug("ty_var in type_is_pod"); } ty_param(_, _) { result = false; } + ty_opaque_closure_ptr(_) { result = true; } + ty_named(_,_) { + cx.sess.bug("ty_named in type_is_pod"); + } + } ret result; @@ -1577,12 +1586,17 @@ fn field_idx(id: ast::ident, fields: [field]) -> option::t<uint> { } fn get_field(tcx: ctxt, rec_ty: t, id: ast::ident) -> field { + alt vec::find(get_fields(tcx, rec_ty), {|f| str::eq(f.ident, id) }) { + some(f) { ret f; } + _ { tcx.sess.bug(#fmt("get_field: bad field id %s", id)); } + } +} + +// TODO: could have a precondition instead of failing +fn get_fields(tcx:ctxt, rec_ty:t) -> [field] { alt struct(tcx, rec_ty) { - ty_rec(fields) { - alt vec::find(fields, {|f| str::eq(f.ident, id) }) { - some(f) { ret f; } - } - } + ty::ty_rec(fields) { fields } + _ { tcx.sess.bug("get_fields called on non-record type"); } } } @@ -1669,6 +1683,8 @@ mod unify { variance: variance) -> union_result { let vb = alt cx.st { in_bindings(vb) { vb } + _ { cx.tcx.sess.bug("Someone forgot to document an invariant \ + in union"); } }; ufind::grow(vb.sets, math::max(set_a, set_b) + 1u); let root_a = ufind::find(vb.sets, set_a); @@ -1719,7 +1735,10 @@ mod unify { fn record_var_binding( cx: @ctxt, key: int, typ: t, variance: variance) -> result { - let vb = alt cx.st { in_bindings(vb) { vb } }; + let vb = alt cx.st { in_bindings(vb) { vb } + _ { cx.tcx.sess.bug("Someone forgot to document an invariant \ + in record_var_binding"); } + }; ufind::grow(vb.sets, (key as uint) + 1u); let root = ufind::find(vb.sets, key as uint); let result_type = typ; @@ -2060,7 +2079,7 @@ mod unify { ret ures_ok(actual); } ty::ty_bool | ty::ty_int(_) | ty_uint(_) | ty_float(_) | - ty::ty_str | ty::ty_type | ty::ty_send_type { + ty::ty_str | ty::ty_send_type { ret struct_cmp(cx, expected, actual); } ty::ty_native(ex_id) { @@ -2333,6 +2352,7 @@ mod unify { } } } + _ { cx.tcx.sess.bug("unify: unexpected type"); } } } fn unify(expected: t, actual: t, st: unify_style, @@ -2497,6 +2517,7 @@ fn def_has_ty_params(def: ast::def) -> bool { ast::def_ty_param(_, _) | ast::def_binding(_) | ast::def_use(_) | ast::def_native_ty(_) | ast::def_self(_) | ast::def_ty(_) { false } ast::def_fn(_, _) | ast::def_variant(_, _) { true } + _ { false } // ???? } } @@ -2552,6 +2573,7 @@ fn enum_variants(cx: ctxt, id: ast::def_id) -> @[variant_info] { // FIXME: issue #1417 disr_val = alt syntax::ast_util::eval_const_expr(ex) { ast_util::const_int(val) {val as int} + _ { cx.sess.bug("tag_variants: bad disr expr"); } } } _ {disr_val += 1;} @@ -2564,6 +2586,7 @@ fn enum_variants(cx: ctxt, id: ast::def_id) -> @[variant_info] { } }) } + _ { cx.sess.bug("tag_variants: id not bound to an enum"); } } }; cx.enum_var_cache.insert(id, result); diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index de467009750..da951150c7f 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -107,6 +107,9 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) -> some(self_impl(impl_t)) { ret {bounds: @[], ty: impl_t}; } + none { + fcx.ccx.tcx.sess.span_bug(sp, "def_self with no self_info"); + } } } ast::def_fn(id, _) | ast::def_const(id) | @@ -248,16 +251,14 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { some(ast_map::node_native_item(native_item)) { ty_of_native_item(tcx, mode, native_item) } + _ { + tcx.sess.bug("Unexpected sort of item in ast_ty_to_ty"); + } } } } } } - fn ast_arg_to_arg(tcx: ty::ctxt, mode: mode, arg: ast::arg) - -> {mode: ty::mode, ty: ty::t} { - let ty = ast_ty_to_ty(tcx, mode, arg.ty); - ret {mode: default_arg_mode_for_ty(tcx, arg.mode, ty), ty: ty}; - } alt tcx.ast_ty_to_ty_cache.find(ast_ty) { some(some(ty)) { ret ty; } some(none) { @@ -364,6 +365,10 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { "found `ty_infer` in unexpected place"); } } } + ast::ty_mac(_) { + tcx.sess.span_bug(ast_ty.span, + "found `ty_mac` in unexpected place"); + } } tcx.ast_ty_to_ty_cache.insert(ast_ty, some(typ)); ret typ; @@ -587,7 +592,13 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method, tcx.sess.span_err(sp, "method `" + if_m.ident + "` has an incompatible set of type parameters"); } else { - let impl_fty = ty::mk_fn(tcx, impl_m.fty); + let auto_modes = vec::map2(impl_m.fty.inputs, if_m.fty.inputs, {|i, f| + alt ty::struct(tcx, f.ty) { + ty::ty_param(0u, _) { {mode: ast::by_ref with i} } + _ { i } + } + }); + let impl_fty = ty::mk_fn(tcx, {inputs: auto_modes with impl_m.fty}); // Add dummy substs for the parameters of the impl method let substs = substs + vec::init_fn(vec::len(*if_m.tps), {|i| ty::mk_param(tcx, i + impl_tps, {crate: 0, node: 0}) @@ -1209,7 +1220,7 @@ fn check_pat(fcx: @fn_ctxt, map: pat_util::pat_id_map, pat: @ast::pat, // Typecheck the path. let v_def = lookup_def(fcx, path.span, pat.id); let v_def_ids = ast_util::variant_def_ids(v_def); - let ctor_tpt = ty::lookup_item_type(tcx, v_def_ids.tg); + let ctor_tpt = ty::lookup_item_type(tcx, v_def_ids.enm); instantiate_path(fcx, path, ctor_tpt, pat.span, pat.id); // Take the enum type params out of `expected`. @@ -1422,6 +1433,9 @@ fn impl_self_ty(tcx: ty::ctxt, did: ast::def_id) -> {n_tps: uint, ty: ty::t} { _}) { {n_tps: vec::len(ts), ty: ast_ty_to_ty(tcx, m_check, st)} } + an_item { + tcx.sess.bug("Undocumented invariant in impl_self_ty"); + } } } else { let tpt = csearch::get_type(tcx, did); @@ -1444,6 +1458,10 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes, ty::bound_iface(t) { let (iid, tps) = alt ty::struct(tcx, t) { ty::ty_iface(i, tps) { (i, tps) } + _ { + tcx.sess.span_bug(sp, "Undocument invariant in \ + lookup_method"); + } }; let ifce_methods = ty::iface_methods(tcx, iid); alt vec::position_pred(*ifce_methods, {|m| m.ident == name}) { @@ -1485,6 +1503,9 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes, let mt = ty_of_method(tcx, m_check, m); ty::mk_fn(tcx, mt.fty) } + _ { + tcx.sess.bug("Undocumented invariant in ty_from_did"); + } } } else { csearch::get_type(tcx, did).ty } } @@ -1793,7 +1814,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, let rhs_bot = check_expr_with(fcx, rhs, lhs_t); if !ast_util::lazy_binop(binop) { bot |= rhs_bot; } - let result = check_binop(fcx, expr, lhs_t, binop, rhs); write_ty(tcx, id, result); } @@ -2335,6 +2355,8 @@ fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool { let id_map = pat_util::pat_id_map(fcx.ccx.tcx, local.node.pat); check_pat(fcx, id_map, local.node.pat, t); } + _ { fcx.ccx.tcx.sess.span_bug(local.span, "Undocumented invariant \ + in check_decl_local"); } } ret bot; } @@ -2697,7 +2719,7 @@ fn arg_is_argv_ty(tcx: ty::ctxt, a: ty::arg) -> bool { } } -fn check_main_fn_ty(tcx: ty::ctxt, main_id: ast::node_id) { +fn check_main_fn_ty(tcx: ty::ctxt, main_id: ast::node_id, main_span: span) { let main_t = ty::node_id_to_type(tcx, main_id); alt ty::struct(tcx, main_t) { ty::ty_fn({proto: ast::proto_bare, inputs, output, @@ -2708,15 +2730,13 @@ fn check_main_fn_ty(tcx: ty::ctxt, main_id: ast::node_id) { ok &= num_args == 0u || num_args == 1u && arg_is_argv_ty(tcx, inputs[0]); if !ok { - let span = ast_map::node_span(tcx.items.get(main_id)); - tcx.sess.span_err(span, + tcx.sess.span_err(main_span, "wrong type in main function: found `" + ty_to_str(tcx, main_t) + "`"); } } _ { - let span = ast_map::node_span(tcx.items.get(main_id)); - tcx.sess.span_bug(span, + tcx.sess.span_bug(main_span, "main has a non-function type: found `" + ty_to_str(tcx, main_t) + "`"); } @@ -2726,7 +2746,7 @@ fn check_main_fn_ty(tcx: ty::ctxt, main_id: ast::node_id) { fn check_for_main_fn(tcx: ty::ctxt, crate: @ast::crate) { if !tcx.sess.building_library { alt tcx.sess.main_fn { - some(id) { check_main_fn_ty(tcx, id); } + some((id, sp)) { check_main_fn_ty(tcx, id, sp); } none { tcx.sess.span_err(crate.span, "main function not found"); } } } @@ -2765,6 +2785,8 @@ mod dict { let tcx = fcx.ccx.tcx; let (iface_id, iface_tps) = alt ty::struct(tcx, iface_ty) { ty::ty_iface(did, tps) { (did, tps) } + _ { tcx.sess.span_bug(sp, "Undocumented invariant in lookup\ + _dict"); } }; let ty = fixup_ty(fcx, sp, ty); alt ty::struct(tcx, ty) { @@ -2777,6 +2799,8 @@ mod dict { ty::ty_iface(idid, _) { if iface_id == idid { ret dict_param(n, n_bound); } } + _ { tcx.sess.span_bug(sp, "Undocumented invariant in \ + lookup_dict"); } } n_bound += 1u; } @@ -2796,6 +2820,9 @@ mod dict { some(ity) { alt ty::struct(tcx, ity) { ty::ty_iface(id, _) { id == iface_id } + // Bleah, abstract this + _ { tcx.sess.span_bug(sp, "Undocumented invariant \ + in lookup_dict"); } } } _ { false } @@ -2862,6 +2889,10 @@ mod dict { vec::iter2(tps, iface_tys, {|a, b| demand::simple(fcx, sp, a, b);}); } + _ { + tcx.sess.span_bug(sp, "Undocumented invariant in \ + connect_iface_tps"); + } } } diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index 1436f9b08f4..f52afc0875c 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -328,14 +328,10 @@ enum ty_ { ty_uniq(mt), ty_vec(mt), ty_ptr(mt), - ty_task, - ty_port(@ty), - ty_chan(@ty), ty_rec([ty_field]), ty_fn(proto, fn_decl), ty_tup([@ty]), ty_path(@path, node_id), - ty_type, ty_constr(@ty, [@ty_constr]), ty_mac(mac), // ty_infer means the type should be inferred instead of it having been diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs index 68b157cecb8..baaa3022eb3 100644 --- a/src/comp/syntax/ast_util.rs +++ b/src/comp/syntax/ast_util.rs @@ -19,8 +19,10 @@ fn path_name_i(idents: [ident]) -> str { str::connect(idents, "::") } fn local_def(id: node_id) -> def_id { ret {crate: local_crate, node: id}; } -fn variant_def_ids(d: def) -> {tg: def_id, var: def_id} { - alt d { def_variant(enum_id, var_id) { ret {tg: enum_id, var: var_id}; } } +fn variant_def_ids(d: def) -> {enm: def_id, var: def_id} { + alt d { def_variant(enum_id, var_id) { + ret {enm: enum_id, var: var_id}; } + _ { fail "non-variant in variant_def_ids"; } } } fn def_id_of_def(d: def) -> def_id { @@ -77,6 +79,7 @@ fn is_path(e: @expr) -> bool { fn int_ty_to_str(t: int_ty) -> str { alt t { + ty_char { "u8" } // ??? ty_i { "" } ty_i8 { "i8" } ty_i16 { "i16" } ty_i32 { "i32" } ty_i64 { "i64" } } @@ -86,7 +89,7 @@ fn int_ty_max(t: int_ty) -> u64 { alt t { ty_i8 { 0x80u64 } ty_i16 { 0x800u64 } - ty_char | ty_i32 { 0x80000000u64 } + ty_i | ty_char | ty_i32 { 0x80000000u64 } // actually ni about ty_i ty_i64 { 0x8000000000000000u64 } } } @@ -102,7 +105,7 @@ fn uint_ty_max(t: uint_ty) -> u64 { alt t { ty_u8 { 0xffu64 } ty_u16 { 0xffffu64 } - ty_u32 { 0xffffffffu64 } + ty_u | ty_u32 { 0xffffffffu64 } // actually ni about ty_u ty_u64 { 0xffffffffffffffffu64 } } } @@ -223,12 +226,14 @@ fn eval_const_expr(e: @expr) -> const_val { const_float(f) { const_float(-f) } const_int(i) { const_int(-i) } const_uint(i) { const_uint(-i) } + _ { fail "eval_const_expr: bad neg argument"; } } } expr_unary(not, inner) { alt eval_const_expr(inner) { const_int(i) { const_int(!i) } const_uint(i) { const_uint(!i) } + _ { fail "eval_const_expr: bad not argument"; } } } expr_binary(op, a, b) { @@ -240,6 +245,7 @@ fn eval_const_expr(e: @expr) -> const_val { rem { const_float(a % b) } eq { fromb(a == b) } lt { fromb(a < b) } le { fromb(a <= b) } ne { fromb(a != b) } ge { fromb(a >= b) } gt { fromb(a > b) } + _ { fail "eval_const_expr: can't apply this binop to floats"; } } } (const_int(a), const_int(b)) { @@ -253,6 +259,7 @@ fn eval_const_expr(e: @expr) -> const_val { eq { fromb(a == b) } lt { fromb(a < b) } le { fromb(a <= b) } ne { fromb(a != b) } ge { fromb(a >= b) } gt { fromb(a > b) } + _ { fail "eval_const_expr: can't apply this binop to ints"; } } } (const_uint(a), const_uint(b)) { @@ -267,11 +274,17 @@ fn eval_const_expr(e: @expr) -> const_val { eq { fromb(a == b) } lt { fromb(a < b) } le { fromb(a <= b) } ne { fromb(a != b) } ge { fromb(a >= b) } gt { fromb(a > b) } + _ { fail "eval_const_expr: can't apply this binop to uints"; } } } + _ { fail "eval_constr_expr: bad binary arguments"; } } } expr_lit(lit) { lit_to_const(lit) } + // Precondition? + _ { + fail "eval_const_expr: non-constant expression"; + } } } @@ -324,6 +337,9 @@ fn compare_const_vals(a: const_val, b: const_val) -> int { 1 } } + _ { + fail "compare_const_vals: ill-typed comparison"; + } } } @@ -341,6 +357,17 @@ fn ident_to_path(s: span, i: ident) -> @path { @respan(s, {global: false, idents: [i], types: []}) } +pure fn is_unguarded(&&a: arm) -> bool { + alt a.guard { + none { true } + _ { false } + } +} + +pure fn unguarded_pat(a: arm) -> option::t<[@pat]> { + if is_unguarded(a) { some(a.pats) } else { none } +} + // Provides an extra node_id to hang callee information on, in case the // operator is deferred to a user-supplied method. The parser is responsible // for reserving this id. diff --git a/src/comp/syntax/ext/simplext.rs b/src/comp/syntax/ext/simplext.rs index 5477c495883..b7fdfc46908 100644 --- a/src/comp/syntax/ext/simplext.rs +++ b/src/comp/syntax/ext/simplext.rs @@ -4,6 +4,7 @@ import codemap::span; import core::{vec, option}; import std::map::{hashmap, new_str_hash}; import option::{some, none}; +import driver::session::session; import base::{ext_ctxt, normal}; @@ -460,11 +461,6 @@ fn p_t_s_rec(cx: ext_ctxt, m: matchable, s: selector, b: binders) { } } } - - - - - /* TODO: handle embedded types and blocks, at least */ expr_mac(mac) { p_t_s_r_mac(cx, mac, s, b); @@ -483,6 +479,9 @@ fn p_t_s_rec(cx: ext_ctxt, m: matchable, s: selector, b: binders) { } } } + _ { + cx.session().bug("undocumented invariant in p_t_s_rec"); + } } } @@ -718,6 +717,10 @@ fn add_new_extension(cx: ext_ctxt, sp: span, arg: @expr, // FIXME: check duplicates (or just simplify // the macro arg situation) } + _ { + cx.span_bug(mac.span, "undocumented invariant in \ + add_extension"); + } } } _ { diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 1c81eda7df5..95c37b9b8e9 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -258,7 +258,7 @@ fn check_bad_word(p: parser) { } } -fn parse_ty_fn(proto: ast::proto, p: parser) -> ast::ty_ { +fn parse_ty_fn(p: parser) -> ast::fn_decl { fn parse_fn_input_ty(p: parser) -> ast::arg { let mode = parse_arg_mode(p); let name = if is_plain_ident(p) && p.look_ahead(1u) == token::COLON { @@ -275,9 +275,9 @@ fn parse_ty_fn(proto: ast::proto, p: parser) -> ast::ty_ { // auto constrs = parse_constrs(~[], p); let constrs: [@ast::constr] = []; let (ret_style, ret_ty) = parse_ret_ty(p); - ret ast::ty_fn(proto, {inputs: inputs.node, output: ret_ty, + ret {inputs: inputs.node, output: ret_ty, purity: ast::impure_fn, cf: ret_style, - constraints: constrs}); + constraints: constrs}; } fn parse_ty_methods(p: parser) -> [ast::ty_method] { @@ -287,15 +287,10 @@ fn parse_ty_methods(p: parser) -> [ast::ty_method] { expect_word(p, "fn"); let ident = parse_method_name(p); let tps = parse_ty_params(p); - let f = parse_ty_fn(ast::proto_bare, p), fhi = p.last_span.hi; + let d = parse_ty_fn(p), fhi = p.last_span.hi; expect(p, token::SEMI); - alt f { - ast::ty_fn(_, d) { {ident: ident, attrs: attrs, decl: d, tps: tps, - span: ast_util::mk_sp(flo, fhi)} - } - } - }, p).node + span: ast_util::mk_sp(flo, fhi)}}, p).node } fn parse_mt(p: parser) -> ast::mt { @@ -506,10 +501,10 @@ fn parse_ty(p: parser, colons_before_params: bool) -> @ast::ty { ast::proto_bare { p.warn("fn is deprecated, use native fn"); } _ { /* fallthrough */ } } - t = parse_ty_fn(proto, p); + t = ast::ty_fn(proto, parse_ty_fn(p)); } else if eat_word(p, "native") { expect_word(p, "fn"); - t = parse_ty_fn(ast::proto_bare, p); + t = ast::ty_fn(ast::proto_bare, parse_ty_fn(p)); } else if p.token == token::MOD_SEP || is_ident(p.token) { let path = parse_path(p); t = ast::ty_path(path, p.get_id()); diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index c361beb21ce..fbfa5f4f433 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -336,17 +336,6 @@ fn print_type(s: ps, &&ty: @ast::ty) { word(s.s, "]"); } ast::ty_ptr(mt) { word(s.s, "*"); print_mt(s, mt); } - ast::ty_task { word(s.s, "task"); } - ast::ty_port(t) { - word(s.s, "port<"); - print_type(s, t); - word(s.s, ">"); - } - ast::ty_chan(t) { - word(s.s, "chan<"); - print_type(s, t); - word(s.s, ">"); - } ast::ty_rec(fields) { word(s.s, "{"); fn print_field(s: ps, f: ast::ty_field) { @@ -370,12 +359,18 @@ fn print_type(s: ps, &&ty: @ast::ty) { print_ty_fn(s, some(proto), d, none, none); } ast::ty_path(path, _) { print_path(s, path, false); } - ast::ty_type { word(s.s, "type"); } ast::ty_constr(t, cs) { print_type(s, t); space(s.s); word(s.s, ast_ty_constrs_str(cs)); } + ast::ty_mac(_) { + fail "print_type doesn't know how to print a ty_mac"; + } + ast::ty_infer { + fail "print_type shouldn't see a ty_infer"; + } + } end(s); } @@ -703,11 +698,6 @@ fn print_if(s: ps, test: @ast::expr, blk: ast::blk, alt els { some(_else) { alt _else.node { - - - - - // "another else-if" ast::expr_if(i, t, e) { cbox(s, indent_unit - 1u); @@ -718,11 +708,6 @@ fn print_if(s: ps, test: @ast::expr, blk: ast::blk, print_block(s, t); do_else(s, e); } - - - - - // "final else" ast::expr_block(b) { cbox(s, indent_unit - 1u); @@ -730,6 +715,10 @@ fn print_if(s: ps, test: @ast::expr, blk: ast::blk, word(s.s, " else "); print_block(s, b); } + // BLEAH, constraints would be great here + _ { + fail "print_if saw if with weird alternative"; + } } } _ {/* fall through */ } diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs index 1fb6991256e..2ba0567c213 100644 --- a/src/comp/syntax/visit.rs +++ b/src/comp/syntax/visit.rs @@ -165,7 +165,6 @@ fn visit_ty<E>(t: @ty, e: E, v: vt<E>) { v.visit_ty(decl.output, e, v); } ty_path(p, _) { visit_path(p, e, v); } - ty_type {/* no-op */ } ty_constr(t, cs) { v.visit_ty(t, e, v); for tc: @spanned<constr_general_<@path, node_id>> in cs { diff --git a/src/comp/util/ppaux.rs b/src/comp/util/ppaux.rs index dd563048293..9b0be29ca26 100644 --- a/src/comp/util/ppaux.rs +++ b/src/comp/util/ppaux.rs @@ -8,7 +8,7 @@ import syntax::print::pprust::{path_to_str, constr_args_to_str, proto_to_str}; import syntax::{ast, ast_util}; import middle::ast_map; -fn mode_str(m: ty::mode) -> str { +fn mode_str(m: ast::mode) -> str { alt m { ast::by_ref { "&&" } ast::by_val { "++" } @@ -20,7 +20,7 @@ fn mode_str(m: ty::mode) -> str { } fn ty_to_str(cx: ctxt, typ: t) -> str { - fn fn_input_to_str(cx: ctxt, input: {mode: middle::ty::mode, ty: t}) -> + fn fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) -> str { let modestr = alt input.mode { ast::by_ref { |
