trans: overhaul match bindings. No more phi, one code path for guards.

Fixes #3256.
Fixes #3291.
This commit is contained in:
Niko Matsakis 2012-09-12 17:06:36 -07:00
parent ff54ac8e59
commit 34bf0b9e97
8 changed files with 723 additions and 400 deletions

View File

@ -38,7 +38,7 @@ type config =
uint_type: uint_ty,
float_type: float_ty};
const ppregions: uint = 1 << 0;
const verbose: uint = 1 << 0;
const time_passes: uint = 1 << 1;
const count_llvm_insns: uint = 1 << 2;
const time_llvm_passes: uint = 1 << 3;
@ -60,8 +60,7 @@ const meta_stats: uint = 1 << 16;
const no_opt: uint = 1 << 17;
fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
~[(~"ppregions", ~"prettyprint regions with \
internal repr details", ppregions),
~[(~"verbose", ~"in general, enable more debug printouts", verbose),
(~"time-passes", ~"measure time of each rustc pass", time_passes),
(~"count-llvm-insns", ~"count where LLVM \
instrs originate", count_llvm_insns),
@ -219,7 +218,7 @@ impl session {
fn impossible_case(sp: span, msg: &str) -> ! {
self.span_bug(sp, #fmt("Impossible case reached: %s", msg));
}
fn ppregions() -> bool { self.debugging_opt(ppregions) }
fn verbose() -> bool { self.debugging_opt(verbose) }
fn time_passes() -> bool { self.debugging_opt(time_passes) }
fn count_llvm_insns() -> bool { self.debugging_opt(count_llvm_insns) }
fn count_type_sizes() -> bool { self.debugging_opt(count_type_sizes) }

View File

@ -6,14 +6,14 @@ use syntax::fold::*;
use syntax::codemap::span;
use std::map::HashMap;
export pat_binding_ids, pat_bindings, pat_id_map;
export pat_is_variant;
export pat_binding_ids, pat_bindings, pat_id_map, PatIdMap;
export pat_is_variant, pat_is_binding_or_wild;
type pat_id_map = std::map::HashMap<ident, node_id>;
type PatIdMap = std::map::HashMap<ident, node_id>;
// This is used because same-named variables in alternative patterns need to
// use the node_id of their namesake in the first pattern.
fn pat_id_map(dm: resolve::DefMap, pat: @pat) -> pat_id_map {
fn pat_id_map(dm: resolve::DefMap, pat: @pat) -> PatIdMap {
let map = std::map::uint_hash();
do pat_bindings(dm, pat) |_bm, p_id, _s, n| {
map.insert(path_to_ident(n), p_id);
@ -32,6 +32,14 @@ fn pat_is_variant(dm: resolve::DefMap, pat: @pat) -> bool {
}
}
fn pat_is_binding_or_wild(dm: resolve::DefMap, pat: @pat) -> bool {
match pat.node {
pat_ident(*) => !pat_is_variant(dm, pat),
pat_wild => true,
_ => false
}
}
fn pat_bindings(dm: resolve::DefMap, pat: @pat,
it: fn(binding_mode, node_id, span, @path)) {
do walk_pat(pat) |p| {

File diff suppressed because it is too large Load Diff

View File

@ -49,7 +49,7 @@ use metadata::csearch;
use driver::session::session;
use util::common::may_break;
use syntax::codemap::span;
use pat_util::{pat_is_variant, pat_id_map};
use pat_util::{pat_is_variant, pat_id_map, PatIdMap};
use middle::ty;
use middle::ty::{arg, field, node_type_table, mk_nil, ty_param_bounds_and_ty};
use middle::ty::{vstore_uniq};

View File

@ -111,7 +111,7 @@ fn check_legality_of_move_bindings(fcx: @fn_ctxt,
type pat_ctxt = {
fcx: @fn_ctxt,
map: pat_id_map,
map: PatIdMap,
alt_region: ty::region, // Region for the alt as a whole
block_region: ty::region, // Region for the block of the arm
};

View File

@ -112,17 +112,17 @@ fn explain_region_and_span(cx: ctxt, region: ty::region)
fn bound_region_to_str(cx: ctxt, br: bound_region) -> ~str {
match br {
br_named(id) => fmt!("&%s", cx.sess.str_of(id)),
br_self if cx.sess.ppregions() => ~"&<self>",
br_self if cx.sess.verbose() => ~"&<self>",
br_self => ~"&self",
br_anon(idx) => {
if cx.sess.ppregions() {fmt!("&%u", idx)} else {~"&"}
if cx.sess.verbose() {fmt!("&%u", idx)} else {~"&"}
}
// FIXME(#3011) -- even if this arm is removed, exhaustiveness checking
// does not fail
br_cap_avoid(id, br) => {
if cx.sess.ppregions() {
if cx.sess.verbose() {
fmt!("br_cap_avoid(%?, %s)", id, bound_region_to_str(cx, *br))
} else {
bound_region_to_str(cx, *br)
@ -175,7 +175,7 @@ fn re_scope_id_to_str(cx: ctxt, node_id: ast::node_id) -> ~str {
// you should use `explain_region()` or, better yet,
// `note_and_explain_region()`
fn region_to_str(cx: ctxt, region: region) -> ~str {
if cx.sess.ppregions() {
if cx.sess.verbose() {
return fmt!("&%?", region);
}

View File

@ -0,0 +1,9 @@
fn main() {
let x = Some(unsafe::exclusive(true));
match move x {
Some(ref z) if z.with(|b| *b) => {
do z.with |b| { assert *b; }
},
_ => fail
}
}

View File

@ -0,0 +1,14 @@
fn foo(x: Option<~int>, b: bool) -> int {
match x {
None => { 1 }
Some(copy x) if b => { *x }
Some(_) => { 0 }
}
}
fn main() {
foo(Some(~22), true);
foo(Some(~22), false);
foo(None, true);
foo(None, false);
}