Disallow rebinding / matching against consts in alts
As per Issue #1193. Closes #1193. I had to rename a few variables ("info" and "epsilon") to avoid clashing with in-scope constants, which is responsible for all the changes other than resolve and issue-1193.rs.
This commit is contained in:
parent
1e51196f33
commit
b0074c5a92
7 changed files with 65 additions and 48 deletions
|
@ -51,10 +51,10 @@ fn to_str_common(num: float, digits: uint, exact: bool) -> str {
|
||||||
if (frac < epsilon && !exact) || digits == 0u { ret accum; }
|
if (frac < epsilon && !exact) || digits == 0u { ret accum; }
|
||||||
accum += ".";
|
accum += ".";
|
||||||
let mut i = digits;
|
let mut i = digits;
|
||||||
let mut epsilon = 1. / pow_with_uint(10u, i);
|
let mut epsilon_prime = 1. / pow_with_uint(10u, i);
|
||||||
while i > 0u && (frac >= epsilon || exact) {
|
while i > 0u && (frac >= epsilon_prime || exact) {
|
||||||
frac *= 10.0;
|
frac *= 10.0;
|
||||||
epsilon *= 10.0;
|
epsilon_prime *= 10.0;
|
||||||
let digit = frac as uint;
|
let digit = frac as uint;
|
||||||
accum += uint::str(digit);
|
accum += uint::str(digit);
|
||||||
frac -= digit as float;
|
frac -= digit as float;
|
||||||
|
|
|
@ -34,9 +34,8 @@ fn expand_expr(exts: hashmap<str, syntax_extension>, cx: ext_ctxt,
|
||||||
some(normal({expander: exp, span: exp_sp})) {
|
some(normal({expander: exp, span: exp_sp})) {
|
||||||
let expanded = exp(cx, pth.span, args, body);
|
let expanded = exp(cx, pth.span, args, body);
|
||||||
|
|
||||||
let info = {call_site: s,
|
cx.bt_push(expanded_from({call_site: s,
|
||||||
callie: {name: extname, span: exp_sp}};
|
callie: {name: extname, span: exp_sp}}));
|
||||||
cx.bt_push(expanded_from(info));
|
|
||||||
//keep going, outside-in
|
//keep going, outside-in
|
||||||
let fully_expanded = fld.fold_expr(expanded).node;
|
let fully_expanded = fld.fold_expr(expanded).node;
|
||||||
cx.bt_pop();
|
cx.bt_pop();
|
||||||
|
|
|
@ -500,19 +500,23 @@ fn resolve_names(e: @env, c: @ast::crate) {
|
||||||
}
|
}
|
||||||
_ {
|
_ {
|
||||||
e.sess.span_err(p.span,
|
e.sess.span_err(p.span,
|
||||||
"not a enum variant: " +
|
"not an enum variant: " +
|
||||||
ast_util::path_name(p));
|
ast_util::path_name(p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Here we determine whether a given pat_ident binds a new
|
/* Here we determine whether a given pat_ident binds a new
|
||||||
variable a refers to a nullary enum. */
|
variable or refers to a nullary enum. */
|
||||||
ast::pat_ident(p, none) {
|
ast::pat_ident(p, none) {
|
||||||
alt lookup_in_scope(*e, sc, p.span, path_to_ident(p),
|
alt lookup_in_scope(*e, sc, p.span, path_to_ident(p),
|
||||||
ns_val, false) {
|
ns_val, false) {
|
||||||
some(fnd@ast::def_variant(_,_)) {
|
some(fnd@ast::def_variant(_,_)) {
|
||||||
e.def_map.insert(pat.id, fnd);
|
e.def_map.insert(pat.id, fnd);
|
||||||
}
|
}
|
||||||
|
some(fnd@ast::def_const(_)) {
|
||||||
|
e.sess.span_err(p.span, "Sorry, rebinding or matching \
|
||||||
|
against symbolic constants is not allowed.");
|
||||||
|
}
|
||||||
// Binds a var -- nothing needs to be done
|
// Binds a var -- nothing needs to be done
|
||||||
_ {}
|
_ {}
|
||||||
}
|
}
|
||||||
|
@ -1446,16 +1450,16 @@ fn list_search<T: copy, U: copy>(ls: list<T>, f: fn(T) -> option<U>)
|
||||||
|
|
||||||
fn lookup_in_local_mod(e: env, node_id: node_id, sp: span, id: ident,
|
fn lookup_in_local_mod(e: env, node_id: node_id, sp: span, id: ident,
|
||||||
ns: namespace, dr: dir) -> option<def> {
|
ns: namespace, dr: dir) -> option<def> {
|
||||||
let info = alt e.mod_map.find(node_id) {
|
let inf = alt e.mod_map.find(node_id) {
|
||||||
some(x) { x }
|
some(x) { x }
|
||||||
none { e.sess.span_bug(sp, #fmt("lookup_in_local_mod: \
|
none { e.sess.span_bug(sp, #fmt("lookup_in_local_mod: \
|
||||||
module %d not in mod_map", node_id)); }
|
module %d not in mod_map", node_id)); }
|
||||||
};
|
};
|
||||||
if dr == outside && !is_exported(e, id, info) {
|
if dr == outside && !is_exported(e, id, inf) {
|
||||||
// if we're in a native mod, then dr==inside, so info.m is some _mod
|
// if we're in a native mod, then dr==inside, so inf.m is some _mod
|
||||||
ret none; // name is not visible
|
ret none; // name is not visible
|
||||||
}
|
}
|
||||||
alt info.index.find(id) {
|
alt inf.index.find(id) {
|
||||||
none { }
|
none { }
|
||||||
some(lst) {
|
some(lst) {
|
||||||
let found = list_search(lst, bind lookup_in_mie(e, _, ns));
|
let found = list_search(lst, bind lookup_in_mie(e, _, ns));
|
||||||
|
@ -1465,7 +1469,7 @@ fn lookup_in_local_mod(e: env, node_id: node_id, sp: span, id: ident,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// not local or explicitly imported; try globs:
|
// not local or explicitly imported; try globs:
|
||||||
ret lookup_glob_in_mod(e, info, sp, id, ns, outside);
|
ret lookup_glob_in_mod(e, inf, sp, id, ns, outside);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_in_globs(e: env, globs: [glob_imp_def], sp: span, id: ident,
|
fn lookup_in_globs(e: env, globs: [glob_imp_def], sp: span, id: ident,
|
||||||
|
|
|
@ -371,19 +371,19 @@ fn get_tydesc(ccx: @crate_ctxt, t: ty::t,
|
||||||
&static_ti: option<@tydesc_info>) -> ValueRef {
|
&static_ti: option<@tydesc_info>) -> ValueRef {
|
||||||
assert !ty::type_has_params(t);
|
assert !ty::type_has_params(t);
|
||||||
// Otherwise, generate a tydesc if necessary, and return it.
|
// Otherwise, generate a tydesc if necessary, and return it.
|
||||||
let info = get_static_tydesc(ccx, t);
|
let inf = get_static_tydesc(ccx, t);
|
||||||
static_ti = some(info);
|
static_ti = some(inf);
|
||||||
info.tydesc
|
inf.tydesc
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_static_tydesc(ccx: @crate_ctxt, t: ty::t) -> @tydesc_info {
|
fn get_static_tydesc(ccx: @crate_ctxt, t: ty::t) -> @tydesc_info {
|
||||||
alt ccx.tydescs.find(t) {
|
alt ccx.tydescs.find(t) {
|
||||||
some(info) { ret info; }
|
some(inf) { ret inf; }
|
||||||
none {
|
none {
|
||||||
ccx.stats.n_static_tydescs += 1u;
|
ccx.stats.n_static_tydescs += 1u;
|
||||||
let info = declare_tydesc(ccx, t);
|
let inf = declare_tydesc(ccx, t);
|
||||||
ccx.tydescs.insert(t, info);
|
ccx.tydescs.insert(t, inf);
|
||||||
ret info;
|
ret inf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -455,7 +455,7 @@ fn declare_tydesc(ccx: @crate_ctxt, t: ty::t) -> @tydesc_info {
|
||||||
let gvar = str::as_c_str(name, {|buf|
|
let gvar = str::as_c_str(name, {|buf|
|
||||||
llvm::LLVMAddGlobal(ccx.llmod, ccx.tydesc_type, buf)
|
llvm::LLVMAddGlobal(ccx.llmod, ccx.tydesc_type, buf)
|
||||||
});
|
});
|
||||||
let info =
|
let inf =
|
||||||
@{ty: t,
|
@{ty: t,
|
||||||
tydesc: gvar,
|
tydesc: gvar,
|
||||||
size: llsize,
|
size: llsize,
|
||||||
|
@ -464,7 +464,7 @@ fn declare_tydesc(ccx: @crate_ctxt, t: ty::t) -> @tydesc_info {
|
||||||
mut drop_glue: none,
|
mut drop_glue: none,
|
||||||
mut free_glue: none};
|
mut free_glue: none};
|
||||||
log(debug, "--- declare_tydesc " + ty_to_str(ccx.tcx, t));
|
log(debug, "--- declare_tydesc " + ty_to_str(ccx.tcx, t));
|
||||||
ret info;
|
ret inf;
|
||||||
}
|
}
|
||||||
|
|
||||||
type glue_helper = fn@(block, ValueRef, ty::t);
|
type glue_helper = fn@(block, ValueRef, ty::t);
|
||||||
|
@ -2870,8 +2870,8 @@ fn need_invoke(bcx: block) -> bool {
|
||||||
let mut cur = bcx;
|
let mut cur = bcx;
|
||||||
loop {
|
loop {
|
||||||
alt cur.kind {
|
alt cur.kind {
|
||||||
block_scope(info) {
|
block_scope(inf) {
|
||||||
for info.cleanups.each {|cleanup|
|
for inf.cleanups.each {|cleanup|
|
||||||
alt cleanup {
|
alt cleanup {
|
||||||
clean(_, cleanup_type) | clean_temp(_, _, cleanup_type) {
|
clean(_, cleanup_type) | clean_temp(_, _, cleanup_type) {
|
||||||
if cleanup_type == normal_exit_and_unwind {
|
if cleanup_type == normal_exit_and_unwind {
|
||||||
|
@ -2892,8 +2892,8 @@ fn need_invoke(bcx: block) -> bool {
|
||||||
|
|
||||||
fn have_cached_lpad(bcx: block) -> bool {
|
fn have_cached_lpad(bcx: block) -> bool {
|
||||||
let mut res = false;
|
let mut res = false;
|
||||||
in_lpad_scope_cx(bcx) {|info|
|
in_lpad_scope_cx(bcx) {|inf|
|
||||||
alt info.landing_pad {
|
alt inf.landing_pad {
|
||||||
some(_) { res = true; }
|
some(_) { res = true; }
|
||||||
none { res = false; }
|
none { res = false; }
|
||||||
}
|
}
|
||||||
|
@ -2905,9 +2905,9 @@ fn in_lpad_scope_cx(bcx: block, f: fn(scope_info)) {
|
||||||
let mut bcx = bcx;
|
let mut bcx = bcx;
|
||||||
loop {
|
loop {
|
||||||
alt bcx.kind {
|
alt bcx.kind {
|
||||||
block_scope(info) {
|
block_scope(inf) {
|
||||||
if info.cleanups.len() > 0u || bcx.parent == parent_none {
|
if inf.cleanups.len() > 0u || bcx.parent == parent_none {
|
||||||
f(info); ret;
|
f(inf); ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ {}
|
_ {}
|
||||||
|
@ -2920,13 +2920,13 @@ fn get_landing_pad(bcx: block) -> BasicBlockRef {
|
||||||
let _icx = bcx.insn_ctxt("get_landing_pad");
|
let _icx = bcx.insn_ctxt("get_landing_pad");
|
||||||
|
|
||||||
let mut cached = none, pad_bcx = bcx; // Guaranteed to be set below
|
let mut cached = none, pad_bcx = bcx; // Guaranteed to be set below
|
||||||
in_lpad_scope_cx(bcx) {|info|
|
in_lpad_scope_cx(bcx) {|inf|
|
||||||
// If there is a valid landing pad still around, use it
|
// If there is a valid landing pad still around, use it
|
||||||
alt info.landing_pad {
|
alt inf.landing_pad {
|
||||||
some(target) { cached = some(target); }
|
some(target) { cached = some(target); }
|
||||||
none {
|
none {
|
||||||
pad_bcx = sub_block(bcx, "unwind");
|
pad_bcx = sub_block(bcx, "unwind");
|
||||||
info.landing_pad = some(pad_bcx.llbb);
|
inf.landing_pad = some(pad_bcx.llbb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3792,8 +3792,8 @@ fn cleanup_and_leave(bcx: block, upto: option<BasicBlockRef>,
|
||||||
let mut done = false;
|
let mut done = false;
|
||||||
loop {
|
loop {
|
||||||
alt cur.kind {
|
alt cur.kind {
|
||||||
block_scope(info) if info.cleanups.len() > 0u {
|
block_scope(inf) if inf.cleanups.len() > 0u {
|
||||||
option::iter(vec::find(info.cleanup_paths,
|
option::iter(vec::find(inf.cleanup_paths,
|
||||||
{|cp| cp.target == leave})) {|cp|
|
{|cp| cp.target == leave})) {|cp|
|
||||||
Br(bcx, cp.dest);
|
Br(bcx, cp.dest);
|
||||||
done = true;
|
done = true;
|
||||||
|
@ -3801,7 +3801,7 @@ fn cleanup_and_leave(bcx: block, upto: option<BasicBlockRef>,
|
||||||
if done { ret; }
|
if done { ret; }
|
||||||
let sub_cx = sub_block(bcx, "cleanup");
|
let sub_cx = sub_block(bcx, "cleanup");
|
||||||
Br(bcx, sub_cx.llbb);
|
Br(bcx, sub_cx.llbb);
|
||||||
info.cleanup_paths += [{target: leave, dest: sub_cx.llbb}];
|
inf.cleanup_paths += [{target: leave, dest: sub_cx.llbb}];
|
||||||
bcx = trans_block_cleanups_(sub_cx, cur, is_lpad);
|
bcx = trans_block_cleanups_(sub_cx, cur, is_lpad);
|
||||||
}
|
}
|
||||||
_ {}
|
_ {}
|
||||||
|
|
|
@ -381,7 +381,7 @@ fn in_scope_cx(cx: block, f: fn(scope_info)) {
|
||||||
let mut cur = cx;
|
let mut cur = cx;
|
||||||
loop {
|
loop {
|
||||||
alt cur.kind {
|
alt cur.kind {
|
||||||
block_scope(info) { f(info); ret; }
|
block_scope(inf) { f(inf); ret; }
|
||||||
_ {}
|
_ {}
|
||||||
}
|
}
|
||||||
cur = block_parent(cur);
|
cur = block_parent(cur);
|
||||||
|
|
|
@ -514,16 +514,16 @@ fn gen_enum_shapes(ccx: @crate_ctxt) -> ValueRef {
|
||||||
// to each variant shape). As we do so, build up the header.
|
// to each variant shape). As we do so, build up the header.
|
||||||
|
|
||||||
let mut header = [];
|
let mut header = [];
|
||||||
let mut info = [];
|
let mut inf = [];
|
||||||
let header_sz = 2u16 * ccx.shape_cx.next_tag_id;
|
let header_sz = 2u16 * ccx.shape_cx.next_tag_id;
|
||||||
let data_sz = vec::len(data) as u16;
|
let data_sz = vec::len(data) as u16;
|
||||||
|
|
||||||
let mut info_sz = 0u16;
|
let mut inf_sz = 0u16;
|
||||||
for ccx.shape_cx.tag_order.each {|did_|
|
for ccx.shape_cx.tag_order.each {|did_|
|
||||||
let did = did_; // Satisfy alias checker.
|
let did = did_; // Satisfy alias checker.
|
||||||
let num_variants = vec::len(*ty::enum_variants(ccx.tcx, did)) as u16;
|
let num_variants = vec::len(*ty::enum_variants(ccx.tcx, did)) as u16;
|
||||||
add_u16(header, header_sz + info_sz);
|
add_u16(header, header_sz + inf_sz);
|
||||||
info_sz += 2u16 * (num_variants + 2u16) + 3u16;
|
inf_sz += 2u16 * (num_variants + 2u16) + 3u16;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct the info tables, which contain offsets to the shape of each
|
// Construct the info tables, which contain offsets to the shape of each
|
||||||
|
@ -535,11 +535,11 @@ fn gen_enum_shapes(ccx: @crate_ctxt) -> ValueRef {
|
||||||
for ccx.shape_cx.tag_order.each {|did_|
|
for ccx.shape_cx.tag_order.each {|did_|
|
||||||
let did = did_; // Satisfy alias checker.
|
let did = did_; // Satisfy alias checker.
|
||||||
let variants = ty::enum_variants(ccx.tcx, did);
|
let variants = ty::enum_variants(ccx.tcx, did);
|
||||||
add_u16(info, vec::len(*variants) as u16);
|
add_u16(inf, vec::len(*variants) as u16);
|
||||||
|
|
||||||
// Construct the largest-variants table.
|
// Construct the largest-variants table.
|
||||||
add_u16(info,
|
add_u16(inf,
|
||||||
header_sz + info_sz + data_sz + (vec::len(lv_table) as u16));
|
header_sz + inf_sz + data_sz + (vec::len(lv_table) as u16));
|
||||||
|
|
||||||
let lv = largest_variants(ccx, did);
|
let lv = largest_variants(ccx, did);
|
||||||
add_u16(lv_table, vec::len(lv) as u16);
|
add_u16(lv_table, vec::len(lv) as u16);
|
||||||
|
@ -555,22 +555,22 @@ fn gen_enum_shapes(ccx: @crate_ctxt) -> ValueRef {
|
||||||
let size_align = if dynamic { {size: 0u16, align: 0u8} }
|
let size_align = if dynamic { {size: 0u16, align: 0u8} }
|
||||||
else { compute_static_enum_size(ccx, lv, did) };
|
else { compute_static_enum_size(ccx, lv, did) };
|
||||||
// Write in the static size and alignment of the enum.
|
// Write in the static size and alignment of the enum.
|
||||||
add_u16(info, size_align.size);
|
add_u16(inf, size_align.size);
|
||||||
info += [size_align.align];
|
inf += [size_align.align];
|
||||||
|
|
||||||
// Now write in the offset of each variant.
|
// Now write in the offset of each variant.
|
||||||
for vec::each(*variants) {|_v|
|
for vec::each(*variants) {|_v|
|
||||||
add_u16(info, header_sz + info_sz + offsets[i]);
|
add_u16(inf, header_sz + inf_sz + offsets[i]);
|
||||||
i += 1u;
|
i += 1u;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert (i == vec::len(offsets));
|
assert (i == vec::len(offsets));
|
||||||
assert (header_sz == vec::len(header) as u16);
|
assert (header_sz == vec::len(header) as u16);
|
||||||
assert (info_sz == vec::len(info) as u16);
|
assert (inf_sz == vec::len(inf) as u16);
|
||||||
assert (data_sz == vec::len(data) as u16);
|
assert (data_sz == vec::len(data) as u16);
|
||||||
|
|
||||||
header += info;
|
header += inf;
|
||||||
header += data;
|
header += data;
|
||||||
header += lv_table;
|
header += lv_table;
|
||||||
|
|
||||||
|
|
14
src/test/compile-fail/issue-1193.rs
Normal file
14
src/test/compile-fail/issue-1193.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// error-pattern: Sorry, rebinding or matching against symbolic
|
||||||
|
mod foo {
|
||||||
|
type t = u8;
|
||||||
|
|
||||||
|
const a : t = 0u8;
|
||||||
|
const b : t = 1u8;
|
||||||
|
|
||||||
|
fn bar(v: t) -> bool {
|
||||||
|
alt v {
|
||||||
|
a { ret true; }
|
||||||
|
b { ret false; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue