Require alts to be exhaustive

middle::check_alt does the work. Lots of changes to add default cases
into alts that were previously inexhaustive.
This commit is contained in:
Tim Chevalier 2012-01-30 21:00:57 -08:00
parent 813a55d891
commit fba35e1a3c
50 changed files with 766 additions and 367 deletions

View file

@ -93,6 +93,7 @@ fn load_link(mis: [@ast::meta_item]) -> (option::t<str>,
_ { }
}
}
_ { fail "load_link: meta items must be name-values"; }
}
}
(name, vers, uuid)
@ -135,6 +136,7 @@ fn load_pkg(filename: str) -> option::t<pkg> {
uuid = u;
}
}
_ { fail "load_pkg: pkg attributes may not contain meta_words"; }
}
}

View file

@ -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";
}

View file

@ -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);

View file

@ -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,

View file

@ -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

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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;

View file

@ -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 }
}
}

View file

@ -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);

View file

@ -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";
}
}
}

View file

@ -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)) {

View file

@ -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;

View file

@ -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"; }
};
}

View file

@ -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}];

View file

@ -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;
}

View file

@ -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"); }
}
}
_ {}

View file

@ -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");
}
}
}

View file

@ -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?

View file

@ -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"); }
}
}

View file

@ -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
}

View file

@ -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");
}
}
}

View file

@ -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");
}
}
}

View file

@ -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);

View file

@ -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(); }
}
}

View file

@ -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)

View file

@ -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, _) {

View file

@ -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);
}

View file

@ -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);

View file

@ -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);

View file

@ -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");
}
}
}

View file

@ -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

View file

@ -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.

View file

@ -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");
}
}
}
_ {

View file

@ -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());

View file

@ -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 */ }

View file

@ -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 {

View file

@ -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 {

View file

@ -87,12 +87,17 @@ Visit all pairs in the map in order.
fn traverse<K, V: copy>(m: treemap<K, V>, f: fn(K, V)) {
alt *m {
empty { }
node(@k, @v, _, _) {
/*
Previously, this had what looked like redundant
matches to me, so I changed it. but that may be a
de-optimization -- tjc
*/
node(@k, @v, left, right) {
// copy v to make aliases work out
let v1 = v;
alt *m { node(_, _, left, _) { traverse(left, f); } }
traverse(left, f);
f(k, v1);
alt *m { node(_, _, _, right) { traverse(right, f); } }
traverse(right, f);
}
}
}

View file

@ -398,7 +398,8 @@ mod tests {
fn first_free_arg_should_be_a_filter() {
let args = ["progname", "filter"];
check (vec::is_not_empty(args));
let opts = alt parse_opts(args) { either::left(o) { o } };
let opts = alt parse_opts(args) { either::left(o) { o }
_ { fail "Malformed arg in first_free_arg_should_be_a_filter"; } };
assert (str::eq("filter", option::get(opts.filter)));
}
@ -406,7 +407,8 @@ mod tests {
fn parse_ignored_flag() {
let args = ["progname", "filter", "--ignored"];
check (vec::is_not_empty(args));
let opts = alt parse_opts(args) { either::left(o) { o } };
let opts = alt parse_opts(args) { either::left(o) { o }
_ { fail "Malformed arg in parse_ignored_flag"; } };
assert (opts.run_ignored);
}

View file

@ -66,14 +66,13 @@ Find a value based on the key
fn find<K: copy, V: copy>(m: treemap<K, V>, k: K) -> option<V> {
alt *m {
empty { none }
node(@kk, @v, _, _) {
// TODO: was that an optimization?
node(@kk, @v, left, right) {
if k == kk {
some(v)
} else if k < kk {
// Again, ugliness to unpack left and right individually.
alt *m { node(_, _, left, _) { find(left, k) } }
} else { alt *m { node(_, _, _, right) { find(right, k) } } }
find(left, k)
} else { find(right, k) }
}
}
}
@ -86,11 +85,16 @@ Visit all pairs in the map in order.
fn traverse<K, V>(m: treemap<K, V>, f: fn(K, V)) {
alt *m {
empty { }
node(k, v, _, _) {
/*
Previously, this had what looked like redundant
matches to me, so I changed it. but that may be a
de-optimization -- tjc
*/
node(k, v, left, right) {
let k1 = k, v1 = v;
alt *m { node(_, _, left, _) { traverse(left, f); } }
traverse(left, f);
f(*k1, *v1);
alt *m { node(_, _, _, right) { traverse(right, f); } }
traverse(right, f);
}
}
}

View file

@ -120,6 +120,7 @@ fn test_connect() {
connected(cd) {
close_connection(thread, 0u32);
}
_ { fail "test_connect: port isn't connected"; }
}
join_thread(thread);
delete_thread(thread);
@ -156,12 +157,15 @@ fn test_http() {
}
delete_buf(buf);
}
_ { fail "test_http: protocol error"; }
}
}
close_connection(thread, 0u32);
}
_ { fail "test_http: expected `wrote`"; }
}
}
_ { fail "test_http: port not connected"; }
}
join_thread(thread);
delete_thread(thread);

View file

@ -70,6 +70,9 @@ fn parse_item_attrs<T>(
astsrv::exec(srv) {|ctxt|
let attrs = alt ctxt.ast_map.get(id) {
ast_map::node_item(item) { item.attrs }
_ {
fail "parse_item_attrs: not an item";
}
};
parse_attrs(attrs)
}
@ -277,6 +280,7 @@ fn fold_enum(
attr_parser::parse_variant(ast_variant.node.attrs)
}
_ { fail "fold_enum: undocumented invariant"; }
}
};
@ -363,7 +367,6 @@ fn fold_res_should_extract_arg_docs() {
assert doc.args[0].desc == some("b");
}
fn fold_iface(
fold: fold::fold<astsrv::srv>,
doc: doc::ifacedoc
@ -395,6 +398,9 @@ fn merge_method_attrs(
(method.ident, attr_parser::parse_method(method.attrs))
}
}
_ {
fail "Undocumented invariant in merge_method_attrs";
}
}
};
@ -441,4 +447,4 @@ fn should_extract_iface_method_docs() {
assert doc.topmod.ifaces()[0].methods[0].args[0].desc == some("a");
assert doc.topmod.ifaces()[0].methods[0].return.desc == some("return");
assert doc.topmod.ifaces()[0].methods[0].failure == some("failure");
}
}

View file

@ -43,4 +43,4 @@ fn from_str_sess(sess: session::session, source: str) -> @ast::crate {
fn cfg(sess: session::session) -> ast::crate_cfg {
driver::default_configuration(sess, "rustdoc", "<anon>")
}
}

View file

@ -111,8 +111,12 @@ fn is_exported_from_mod(
ast::item_mod(m) {
ast_util::is_exported(item_name, m)
}
_ {
fail "is_exported_from_mod: not a mod";
}
}
}
_ { fail "is_exported_from_mod: not an item"; }
}
}
}
@ -243,4 +247,4 @@ fn should_prune_unexported_ifaces_from_top_mod() {
let doc = extract::from_srv(srv, "");
let doc = run(srv, doc);
assert vec::is_empty(doc.topmod.ifaces());
}
}

View file

@ -50,6 +50,9 @@ fn get_fn_sig(srv: astsrv::srv, fn_id: doc::ast_id) -> option<str> {
}) {
some(pprust::fun_to_str(decl, ident, []))
}
_ {
fail "get_fn_sig: undocumented invariant";
}
}
}
}
@ -87,6 +90,7 @@ fn get_ret_ty(srv: astsrv::srv, fn_id: doc::ast_id) -> option<str> {
}) {
ret_ty_to_str(decl)
}
_ { fail "get_ret_ty: undocumented invariant"; }
}
}
}
@ -145,6 +149,9 @@ fn get_arg_tys(srv: astsrv::srv, fn_id: doc::ast_id) -> [(str, str)] {
}) {
decl_arg_tys(decl)
}
_ {
fail "get_arg_tys: undocumented invariant";
}
}
}
}
@ -180,6 +187,9 @@ fn fold_const(
}) {
pprust::ty_to_str(ty)
}
_ {
fail "fold_const: undocumented invariant";
}
}
})
with doc
@ -215,6 +225,7 @@ fn fold_enum(
pprust::variant_to_str(ast_variant)
}
_ { fail "fold_enum: undocumented invariant"; }
}
};
@ -251,6 +262,7 @@ fn fold_res(
}) {
pprust::res_to_str(decl, doc.name, [])
}
_ { fail "fold_res: undocumented invariant"; }
}
})
with doc
@ -336,8 +348,10 @@ fn get_method_ret_ty(
some(method) {
ret_ty_to_str(method.decl)
}
_ { fail "get_method_ret_ty: undocumented invariant"; }
}
}
_ { fail "get_method_ret_ty: undocumented invariant"; }
}
}
}
@ -358,8 +372,10 @@ fn get_method_sig(
some(method) {
some(pprust::fun_to_str(method.decl, method.ident, []))
}
_ { fail "get_method_ret_sig: undocumented invariant"; }
}
}
_ { fail "get_method_ret_sig: undocumented invariant"; }
}
}
}
@ -396,8 +412,10 @@ fn get_method_arg_tys(
some(method) {
decl_arg_tys(method.decl)
}
_ { fail "get_method_arg_tys: undocumented invariant"; }
}
}
_ { fail "get_method_arg_tys: undocumented invariant"; }
}
}
}

View file

@ -0,0 +1,13 @@
// -*- rust -*-
// error-pattern: Non-exhaustive pattern
enum t { a(u), b }
enum u { c, d }
fn main() {
let x = a(c);
alt x {
a(d) { fail "hello"; }
b { fail "goodbye"; }
}
}

View file

@ -1,9 +1,5 @@
// -*- rust -*-
// error-pattern:non-exhaustive match failure
// error-pattern: Non-exhaustive pattern
enum t { a, b, }
fn main() { let x = a; alt x { b { } } }

View file

@ -4,6 +4,6 @@ mod m1 {
enum foo { foo1, foo2, }
}
fn bar(x: m1::foo) { alt x { m1::foo1 { } } }
fn bar(x: m1::foo) { alt x { m1::foo1 { } m1::foo2 { } } }
fn main() { }