diff --git a/src/doc/rust.md b/src/doc/rust.md
index 58819a3cf48ee..11e635a5af697 100644
--- a/src/doc/rust.md
+++ b/src/doc/rust.md
@@ -2155,8 +2155,6 @@ These are functions:
* `str_eq`
: Compare two strings (`&str`) for equality.
-* `uniq_str_eq`
- : Compare two owned strings (`String`) for equality.
* `strdup_uniq`
: Return a new unique string
containing a copy of the contents of a unique string.
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 1400e207ab1a8..cde83693f0b41 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -74,12 +74,12 @@ impl fmt::Show for Matrix {
}
}
-struct MatchCheckCtxt<'a> {
- tcx: &'a ty::ctxt
+pub struct MatchCheckCtxt<'a> {
+ pub tcx: &'a ty::ctxt
}
#[deriving(Clone, PartialEq)]
-enum Constructor {
+pub enum Constructor {
/// The constructor of all patterns that don't vary by constructor,
/// e.g. struct patterns and fixed-length arrays.
Single,
@@ -492,9 +492,9 @@ fn is_useful_specialized(cx: &MatchCheckCtxt, &Matrix(ref m): &Matrix, v: &[Gc
Usefulness {
let arity = constructor_arity(cx, &ctor, lty);
let matrix = Matrix(m.iter().filter_map(|r| {
- specialize(cx, r.as_slice(), &ctor, arity)
+ specialize(cx, r.as_slice(), &ctor, 0u, arity)
}).collect());
- match specialize(cx, v, &ctor, arity) {
+ match specialize(cx, v, &ctor, 0u, arity) {
Some(v) => is_useful(cx, &matrix, v.as_slice(), witness),
None => NotUseful
}
@@ -580,7 +580,7 @@ fn is_wild(cx: &MatchCheckCtxt, p: Gc) -> bool {
///
/// For instance, a tuple pattern (_, 42u, Some([])) has the arity of 3.
/// A struct pattern's arity is the number of fields it contains, etc.
-fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: ty::t) -> uint {
+pub fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: ty::t) -> uint {
match ty::get(ty).sty {
ty::ty_tup(ref fs) => fs.len(),
ty::ty_box(_) | ty::ty_uniq(_) => 1u,
@@ -628,11 +628,11 @@ fn range_covered_by_constructor(ctor: &Constructor,
/// different patterns.
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
/// fields filled with wild patterns.
-fn specialize(cx: &MatchCheckCtxt, r: &[Gc],
- constructor: &Constructor, arity: uint) -> Option>> {
+pub fn specialize(cx: &MatchCheckCtxt, r: &[Gc],
+ constructor: &Constructor, col: uint, arity: uint) -> Option>> {
let &Pat {
id: pat_id, node: ref node, span: pat_span
- } = &(*raw_pat(r[0]));
+ } = &(*raw_pat(r[col]));
let head: Option>> = match node {
&PatWild =>
Some(Vec::from_elem(arity, wild())),
@@ -776,7 +776,7 @@ fn specialize(cx: &MatchCheckCtxt, r: &[Gc],
None
}
};
- head.map(|head| head.append(r.tail()))
+ head.map(|head| head.append(r.slice_to(col)).append(r.slice_from(col + 1)))
}
fn default(cx: &MatchCheckCtxt, r: &[Gc]) -> Option>> {
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 20e4188a8f6c5..186a737a56ba3 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -248,7 +248,6 @@ lets_do_this! {
OrdTraitLangItem, "ord", ord_trait;
StrEqFnLangItem, "str_eq", str_eq_fn;
- UniqStrEqFnLangItem, "uniq_str_eq", uniq_str_eq_fn;
// A number of failure-related lang items. The `fail_` item corresponds to
// divide-by-zero and various failure cases with `match`. The
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs
index 5fae1635bee8e..595203fdefb2d 100644
--- a/src/librustc/middle/trans/_match.rs
+++ b/src/librustc/middle/trans/_match.rs
@@ -199,7 +199,8 @@ use driver::config::FullDebugInfo;
use lib::llvm::{llvm, ValueRef, BasicBlockRef};
use middle::const_eval;
use middle::def;
-use middle::lang_items::{UniqStrEqFnLangItem, StrEqFnLangItem};
+use middle::check_match;
+use middle::lang_items::StrEqFnLangItem;
use middle::pat_util::*;
use middle::resolve::DefMap;
use middle::trans::adt;
@@ -223,15 +224,16 @@ use middle::ty;
use util::common::indenter;
use util::ppaux::{Repr, vec_map_to_str};
+use std;
use std::collections::HashMap;
use std::cell::Cell;
use std::rc::Rc;
-use std::gc::{Gc, GC};
+use std::gc::{Gc};
use syntax::ast;
use syntax::ast::Ident;
use syntax::ast_util::path_to_ident;
use syntax::ast_util;
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax::codemap::Span;
use syntax::parse::token::InternedString;
// An option identifying a literal: either a unit-like struct or an
@@ -252,7 +254,7 @@ pub enum VecLenOpt {
// range)
enum Opt {
lit(Lit),
- var(ty::Disr, Rc),
+ var(ty::Disr, Rc, ast::DefId),
range(Gc, Gc),
vec_len(/* length */ uint, VecLenOpt, /*range of matches*/(uint, uint))
}
@@ -284,7 +286,7 @@ fn opt_eq(tcx: &ty::ctxt, a: &Opt, b: &Opt) -> bool {
_ => fail!("compare_list_exprs: type mismatch"),
}
}
- (&var(a, _), &var(b, _)) => a == b,
+ (&var(a, _, _), &var(b, _, _)) => a == b,
(&vec_len(a1, a2, _), &vec_len(b1, b2, _)) =>
a1 == b1 && a2 == b2,
_ => false
@@ -320,7 +322,7 @@ fn trans_opt<'a>(bcx: &'a Block<'a>, o: &Opt) -> opt_result<'a> {
let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
return single_result(Result::new(bcx, lit_datum.val));
}
- var(disr_val, ref repr) => {
+ var(disr_val, ref repr, _) => {
return adt::trans_case(bcx, &**repr, disr_val);
}
range(ref l1, ref l2) => {
@@ -342,18 +344,11 @@ fn variant_opt(bcx: &Block, pat_id: ast::NodeId) -> Opt {
let def = ccx.tcx.def_map.borrow().get_copy(&pat_id);
match def {
def::DefVariant(enum_id, var_id, _) => {
- let variants = ty::enum_variants(ccx.tcx(), enum_id);
- for v in (*variants).iter() {
- if var_id == v.id {
- return var(v.disr_val,
- adt::represent_node(bcx, pat_id))
- }
- }
- unreachable!();
+ let variant = ty::enum_variant_with_id(ccx.tcx(), enum_id, var_id);
+ var(variant.disr_val, adt::represent_node(bcx, pat_id), var_id)
}
- def::DefFn(..) |
- def::DefStruct(_) => {
- return lit(UnitLikeStructLit(pat_id));
+ def::DefFn(..) | def::DefStruct(_) => {
+ lit(UnitLikeStructLit(pat_id))
}
_ => {
ccx.sess().bug("non-variant or struct in variant_opt()");
@@ -462,16 +457,7 @@ fn expand_nested_bindings<'a, 'b>(
}).collect()
}
-fn assert_is_binding_or_wild(bcx: &Block, p: Gc) {
- if !pat_is_binding_or_wild(&bcx.tcx().def_map, &*p) {
- bcx.sess().span_bug(
- p.span,
- format!("expected an identifier pattern but found p: {}",
- p.repr(bcx.tcx())).as_slice());
- }
-}
-
-type enter_pat<'a> = |Gc|: 'a -> Option>>;
+type enter_pats<'a> = |&[Gc]|: 'a -> Option>>;
fn enter_match<'a, 'b>(
bcx: &'b Block<'b>,
@@ -479,7 +465,7 @@ fn enter_match<'a, 'b>(
m: &'a [Match<'a, 'b>],
col: uint,
val: ValueRef,
- e: enter_pat)
+ e: enter_pats)
-> Vec> {
debug!("enter_match(bcx={}, m={}, col={}, val={})",
bcx.to_str(),
@@ -489,10 +475,7 @@ fn enter_match<'a, 'b>(
let _indenter = indenter();
m.iter().filter_map(|br| {
- e(*br.pats.get(col)).map(|sub| {
- let pats = sub.append(br.pats.slice(0u, col))
- .append(br.pats.slice(col + 1u, br.pats.len()));
-
+ e(br.pats.as_slice()).map(|pats| {
let this = *br.pats.get(col);
let mut bound_ptrs = br.bound_ptrs.clone();
match this.node {
@@ -528,11 +511,11 @@ fn enter_default<'a, 'b>(
let _indenter = indenter();
// Collect all of the matches that can match against anything.
- enter_match(bcx, dm, m, col, val, |p| {
- match p.node {
- ast::PatWild | ast::PatWildMulti => Some(Vec::new()),
- ast::PatIdent(_, _, None) if pat_is_binding(dm, &*p) => Some(Vec::new()),
- _ => None
+ enter_match(bcx, dm, m, col, val, |pats| {
+ if pat_is_binding_or_wild(dm, pats[col]) {
+ Some(Vec::from_slice(pats.slice_to(col)).append(pats.slice_from(col + 1)))
+ } else {
+ None
}
})
}
@@ -561,8 +544,14 @@ fn enter_default<'a, 'b>(
// so all patterns must either be records (resp. tuples) or
// wildcards
+/// The above is now outdated in that enter_match() now takes a function that
+/// takes the complete row of patterns rather than just the first one.
+/// Also, most of the enter_() family functions have been unified with
+/// the check_match specialization step.
fn enter_opt<'a, 'b>(
bcx: &'b Block<'b>,
+ _: ast::NodeId,
+ dm: &DefMap,
m: &'a [Match<'a, 'b>],
opt: &Opt,
col: uint,
@@ -577,88 +566,32 @@ fn enter_opt<'a, 'b>(
bcx.val_to_str(val));
let _indenter = indenter();
- let tcx = bcx.tcx();
- let dummy = box(GC) ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
- let mut i = 0;
- enter_match(bcx, &tcx.def_map, m, col, val, |p| {
- let answer = match p.node {
- ast::PatEnum(..) |
- ast::PatIdent(_, _, None) if pat_is_const(&tcx.def_map, &*p) => {
- let const_def = tcx.def_map.borrow().get_copy(&p.id);
- let const_def_id = const_def.def_id();
- if opt_eq(tcx, &lit(ConstLit(const_def_id)), opt) {
- Some(Vec::new())
- } else {
- None
- }
- }
- ast::PatEnum(_, ref subpats) => {
- if opt_eq(tcx, &variant_opt(bcx, p.id), opt) {
- // FIXME: Must we clone?
- match *subpats {
- None => Some(Vec::from_elem(variant_size, dummy)),
- Some(ref subpats) => {
- Some((*subpats).iter().map(|x| *x).collect())
- }
- }
- } else {
- None
- }
- }
- ast::PatIdent(_, _, None)
- if pat_is_variant_or_struct(&tcx.def_map, &*p) => {
- if opt_eq(tcx, &variant_opt(bcx, p.id), opt) {
- Some(Vec::new())
- } else {
- None
- }
- }
- ast::PatLit(l) => {
- if opt_eq(tcx, &lit(ExprLit(l)), opt) { Some(Vec::new()) }
- else { None }
- }
- ast::PatRange(l1, l2) => {
- if opt_eq(tcx, &range(l1, l2), opt) { Some(Vec::new()) }
- else { None }
- }
- ast::PatStruct(_, ref field_pats, _) => {
- if opt_eq(tcx, &variant_opt(bcx, p.id), opt) {
- // Look up the struct variant ID.
- let struct_id;
- match tcx.def_map.borrow().get_copy(&p.id) {
- def::DefVariant(_, found_struct_id, _) => {
- struct_id = found_struct_id;
- }
- _ => {
- tcx.sess.span_bug(p.span, "expected enum variant def");
- }
- }
+ let ctor = match opt {
+ &lit(UnitLikeStructLit(_)) => check_match::Single,
+ &lit(x) => check_match::ConstantValue(const_eval::eval_const_expr(
+ bcx.tcx(), lit_to_expr(bcx.tcx(), &x))),
+ &range(ref lo, ref hi) => check_match::ConstantRange(
+ const_eval::eval_const_expr(bcx.tcx(), &**lo),
+ const_eval::eval_const_expr(bcx.tcx(), &**hi)
+ ),
+ &vec_len(len, _, _) => check_match::Slice(len),
+ &var(_, _, def_id) => check_match::Variant(def_id)
+ };
- // Reorder the patterns into the same order they were
- // specified in the struct definition. Also fill in
- // unspecified fields with dummy.
- let mut reordered_patterns = Vec::new();
- let r = ty::lookup_struct_fields(tcx, struct_id);
- for field in r.iter() {
- match field_pats.iter().find(|p| p.ident.name
- == field.name) {
- None => reordered_patterns.push(dummy),
- Some(fp) => reordered_patterns.push(fp.pat)
- }
- }
- Some(reordered_patterns)
- } else {
- None
- }
- }
+ let mut i = 0;
+ let tcx = bcx.tcx();
+ let mcx = check_match::MatchCheckCtxt { tcx: bcx.tcx() };
+ enter_match(bcx, dm, m, col, val, |pats| {
+ let span = pats[col].span;
+ let specialized = match pats[col].node {
ast::PatVec(ref before, slice, ref after) => {
let (lo, hi) = match *opt {
vec_len(_, _, (lo, hi)) => (lo, hi),
- _ => tcx.sess.span_bug(p.span,
+ _ => tcx.sess.span_bug(span,
"vec pattern but not vec opt")
};
- match slice {
+ let elems = match slice {
Some(slice) if i >= lo && i <= hi => {
let n = before.len() + after.len();
let this_opt = vec_len(n, vec_len_ge(before.len()),
@@ -690,172 +623,15 @@ fn enter_opt<'a, 'b>(
}
}
_ => None
- }
+ };
+ elems.map(|head| head.append(pats.slice_to(col)).append(pats.slice_from(col + 1)))
}
_ => {
- assert_is_binding_or_wild(bcx, p);
- Some(Vec::from_elem(variant_size, dummy))
+ check_match::specialize(&mcx, pats.as_slice(), &ctor, col, variant_size)
}
};
i += 1;
- answer
- })
-}
-
-fn enter_rec_or_struct<'a, 'b>(
- bcx: &'b Block<'b>,
- dm: &DefMap,
- m: &'a [Match<'a, 'b>],
- col: uint,
- fields: &[ast::Ident],
- val: ValueRef)
- -> Vec> {
- debug!("enter_rec_or_struct(bcx={}, m={}, col={}, val={})",
- bcx.to_str(),
- m.repr(bcx.tcx()),
- col,
- bcx.val_to_str(val));
- let _indenter = indenter();
-
- let dummy = box(GC) ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
- enter_match(bcx, dm, m, col, val, |p| {
- match p.node {
- ast::PatStruct(_, ref fpats, _) => {
- let mut pats = Vec::new();
- for fname in fields.iter() {
- match fpats.iter().find(|p| p.ident.name == fname.name) {
- None => pats.push(dummy),
- Some(pat) => pats.push(pat.pat)
- }
- }
- Some(pats)
- }
- _ => {
- assert_is_binding_or_wild(bcx, p);
- Some(Vec::from_elem(fields.len(), dummy))
- }
- }
- })
-}
-
-fn enter_tup<'a, 'b>(
- bcx: &'b Block<'b>,
- dm: &DefMap,
- m: &'a [Match<'a, 'b>],
- col: uint,
- val: ValueRef,
- n_elts: uint)
- -> Vec> {
- debug!("enter_tup(bcx={}, m={}, col={}, val={})",
- bcx.to_str(),
- m.repr(bcx.tcx()),
- col,
- bcx.val_to_str(val));
- let _indenter = indenter();
-
- let dummy = box(GC) ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
- enter_match(bcx, dm, m, col, val, |p| {
- match p.node {
- ast::PatTup(ref elts) => {
- let mut new_elts = Vec::new();
- for elt in elts.iter() {
- new_elts.push((*elt).clone())
- }
- Some(new_elts)
- }
- _ => {
- assert_is_binding_or_wild(bcx, p);
- Some(Vec::from_elem(n_elts, dummy))
- }
- }
- })
-}
-
-fn enter_tuple_struct<'a, 'b>(
- bcx: &'b Block<'b>,
- dm: &DefMap,
- m: &'a [Match<'a, 'b>],
- col: uint,
- val: ValueRef,
- n_elts: uint)
- -> Vec> {
- debug!("enter_tuple_struct(bcx={}, m={}, col={}, val={})",
- bcx.to_str(),
- m.repr(bcx.tcx()),
- col,
- bcx.val_to_str(val));
- let _indenter = indenter();
-
- let dummy = box(GC) ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
- enter_match(bcx, dm, m, col, val, |p| {
- match p.node {
- ast::PatEnum(_, Some(ref elts)) => {
- Some(elts.iter().map(|x| (*x)).collect())
- }
- ast::PatEnum(_, None) => {
- Some(Vec::from_elem(n_elts, dummy))
- }
- _ => {
- assert_is_binding_or_wild(bcx, p);
- Some(Vec::from_elem(n_elts, dummy))
- }
- }
- })
-}
-
-fn enter_uniq<'a, 'b>(
- bcx: &'b Block<'b>,
- dm: &DefMap,
- m: &'a [Match<'a, 'b>],
- col: uint,
- val: ValueRef)
- -> Vec> {
- debug!("enter_uniq(bcx={}, m={}, col={}, val={})",
- bcx.to_str(),
- m.repr(bcx.tcx()),
- col,
- bcx.val_to_str(val));
- let _indenter = indenter();
-
- let dummy = box(GC) ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
- enter_match(bcx, dm, m, col, val, |p| {
- match p.node {
- ast::PatBox(sub) => {
- Some(vec!(sub))
- }
- _ => {
- assert_is_binding_or_wild(bcx, p);
- Some(vec!(dummy))
- }
- }
- })
-}
-
-fn enter_region<'a, 'b>(
- bcx: &'b Block<'b>,
- dm: &DefMap,
- m: &'a [Match<'a, 'b>],
- col: uint,
- val: ValueRef)
- -> Vec> {
- debug!("enter_region(bcx={}, m={}, col={}, val={})",
- bcx.to_str(),
- m.repr(bcx.tcx()),
- col,
- bcx.val_to_str(val));
- let _indenter = indenter();
-
- let dummy = box(GC) ast::Pat { id: 0, node: ast::PatWild, span: DUMMY_SP };
- enter_match(bcx, dm, m, col, val, |p| {
- match p.node {
- ast::PatRegion(sub) => {
- Some(vec!(sub))
- }
- _ => {
- assert_is_binding_or_wild(bcx, p);
- Some(vec!(dummy))
- }
- }
+ specialized
})
}
@@ -900,14 +676,10 @@ fn get_options(bcx: &Block, m: &[Match], col: uint) -> Vec {
// variable binding.
let opt_def = ccx.tcx.def_map.borrow().find_copy(&cur.id);
match opt_def {
- Some(def::DefVariant(..)) => {
+ Some(def::DefVariant(..)) | Some(def::DefStruct(..)) => {
add_to_set(ccx.tcx(), &mut found,
variant_opt(bcx, cur.id));
}
- Some(def::DefStruct(..)) => {
- add_to_set(ccx.tcx(), &mut found,
- lit(UnitLikeStructLit(cur.id)));
- }
Some(def::DefStatic(const_did, false)) => {
add_to_set(ccx.tcx(), &mut found,
lit(ConstLit(const_did)));
@@ -1027,49 +799,6 @@ fn extract_vec_elems<'a>(
ExtractedBlock { vals: elems, bcx: bcx }
}
-/// Checks every pattern in `m` at `col` column.
-/// If there are a struct pattern among them function
-/// returns list of all fields that are matched in these patterns.
-/// Function returns None if there is no struct pattern.
-/// Function doesn't collect fields from struct-like enum variants.
-/// Function can return empty list if there is only wildcard struct pattern.
-fn collect_record_or_struct_fields<'a>(
- bcx: &'a Block<'a>,
- m: &[Match],
- col: uint)
- -> Option > {
- let mut fields: Vec = Vec::new();
- let mut found = false;
- for br in m.iter() {
- match br.pats.get(col).node {
- ast::PatStruct(_, ref fs, _) => {
- match ty::get(node_id_type(bcx, br.pats.get(col).id)).sty {
- ty::ty_struct(..) => {
- extend(&mut fields, fs.as_slice());
- found = true;
- }
- _ => ()
- }
- }
- _ => ()
- }
- }
- if found {
- return Some(fields);
- } else {
- return None;
- }
-
- fn extend(idents: &mut Vec , field_pats: &[ast::FieldPat]) {
- for field_pat in field_pats.iter() {
- let field_ident = field_pat.ident;
- if !idents.iter().any(|x| x.name == field_ident.name) {
- idents.push(field_ident);
- }
- }
- }
-}
-
// Macro for deciding whether any of the remaining matches fit a given kind of
// pattern. Note that, because the macro is well-typed, either ALL of the
// matches should fit that sort of pattern or NONE (however, some of the
@@ -1093,21 +822,17 @@ fn any_region_pat(m: &[Match], col: uint) -> bool {
any_pat!(m, ast::PatRegion(_))
}
-fn any_tup_pat(m: &[Match], col: uint) -> bool {
- any_pat!(m, ast::PatTup(_))
-}
-
-fn any_tuple_struct_pat(bcx: &Block, m: &[Match], col: uint) -> bool {
+fn any_irrefutable_adt_pat(bcx: &Block, m: &[Match], col: uint) -> bool {
m.iter().any(|br| {
let pat = *br.pats.get(col);
match pat.node {
- ast::PatEnum(_, _) => {
+ ast::PatTup(_) => true,
+ ast::PatStruct(_, _, _) | ast::PatEnum(_, _) =>
match bcx.tcx().def_map.borrow().find(&pat.id) {
Some(&def::DefFn(..)) |
Some(&def::DefStruct(..)) => true,
_ => false
- }
- }
+ },
_ => false
}
})
@@ -1197,7 +922,7 @@ fn pick_col(m: &[Match]) -> uint {
}
#[deriving(PartialEq)]
-pub enum branch_kind { no_branch, single, switch, compare, compare_vec_len, }
+pub enum branch_kind { no_branch, single, switch, compare, compare_vec_len }
// Compiles a comparison between two things.
fn compare_values<'a>(
@@ -1226,21 +951,6 @@ fn compare_values<'a>(
}
match ty::get(rhs_t).sty {
- ty::ty_uniq(t) => match ty::get(t).sty {
- ty::ty_str => {
- let scratch_lhs = alloca(cx, val_ty(lhs), "__lhs");
- Store(cx, lhs, scratch_lhs);
- let scratch_rhs = alloca(cx, val_ty(rhs), "__rhs");
- Store(cx, rhs, scratch_rhs);
- let did = langcall(cx,
- None,
- format!("comparison of `{}`",
- cx.ty_to_str(rhs_t)).as_slice(),
- UniqStrEqFnLangItem);
- callee::trans_lang_call(cx, did, [scratch_lhs, scratch_rhs], None)
- }
- _ => cx.sess().bug("only strings supported in compare_values"),
- },
ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty {
ty::ty_str => compare_str(cx, lhs, rhs, rhs_t),
ty::ty_vec(mt, _) => match ty::get(mt.ty).sty {
@@ -1254,7 +964,7 @@ fn compare_values<'a>(
},
_ => cx.sess().bug("only byte strings supported in compare_values"),
},
- _ => cx.sess().bug("on string and byte strings supported in compare_values"),
+ _ => cx.sess().bug("only string and byte strings supported in compare_values"),
},
_ => cx.sess().bug("only scalars, byte strings, and strings supported in compare_values"),
}
@@ -1475,103 +1185,41 @@ fn compile_submatch_continue<'a, 'b>(
let vals_left = Vec::from_slice(vals.slice(0u, col)).append(vals.slice(col + 1u, vals.len()));
let ccx = bcx.fcx.ccx;
- let mut pat_id = 0;
- for br in m.iter() {
- // Find a real id (we're adding placeholder wildcard patterns, but
- // each column is guaranteed to have at least one real pattern)
- if pat_id == 0 {
- pat_id = br.pats.get(col).id;
- }
- }
-
- match collect_record_or_struct_fields(bcx, m, col) {
- Some(ref rec_fields) => {
- let pat_ty = node_id_type(bcx, pat_id);
- let pat_repr = adt::represent_type(bcx.ccx(), pat_ty);
- expr::with_field_tys(tcx, pat_ty, Some(pat_id), |discr, field_tys| {
- let rec_vals = rec_fields.iter().map(|field_name| {
- let ix = ty::field_idx_strict(tcx, field_name.name, field_tys);
- adt::trans_field_ptr(bcx, &*pat_repr, val, discr, ix)
- }).collect::>();
- compile_submatch(
- bcx,
- enter_rec_or_struct(bcx,
- dm,
- m,
- col,
- rec_fields.as_slice(),
- val).as_slice(),
- rec_vals.append(vals_left.as_slice()).as_slice(),
- chk, has_genuine_default);
- });
- return;
- }
- None => {}
- }
- if any_tup_pat(m, col) {
- let tup_ty = node_id_type(bcx, pat_id);
- let tup_repr = adt::represent_type(bcx.ccx(), tup_ty);
- let n_tup_elts = match ty::get(tup_ty).sty {
- ty::ty_tup(ref elts) => elts.len(),
- _ => ccx.sess().bug("non-tuple type in tuple pattern")
- };
- let tup_vals = Vec::from_fn(n_tup_elts, |i| {
- adt::trans_field_ptr(bcx, &*tup_repr, val, 0, i)
- });
- compile_submatch(bcx,
- enter_tup(bcx,
- dm,
- m,
- col,
- val,
- n_tup_elts).as_slice(),
- tup_vals.append(vals_left.as_slice()).as_slice(),
- chk, has_genuine_default);
- return;
- }
+ // Find a real id (we're adding placeholder wildcard patterns, but
+ // each column is guaranteed to have at least one real pattern)
+ let pat_id = m.iter().map(|br| br.pats.get(col).id).find(|&id| id != 0).unwrap_or(0);
- if any_tuple_struct_pat(bcx, m, col) {
- let struct_ty = node_id_type(bcx, pat_id);
- let struct_element_count;
- match ty::get(struct_ty).sty {
- ty::ty_struct(struct_id, _) => {
- struct_element_count =
- ty::lookup_struct_fields(tcx, struct_id).len();
- }
- _ => {
- ccx.sess().bug("non-struct type in tuple struct pattern");
- }
- }
-
- let struct_repr = adt::represent_type(bcx.ccx(), struct_ty);
- let llstructvals = Vec::from_fn(struct_element_count, |i| {
- adt::trans_field_ptr(bcx, &*struct_repr, val, 0, i)
- });
- compile_submatch(bcx,
- enter_tuple_struct(bcx, dm, m, col, val,
- struct_element_count).as_slice(),
- llstructvals.append(vals_left.as_slice()).as_slice(),
- chk, has_genuine_default);
- return;
- }
+ let left_ty = if pat_id == 0 {
+ ty::mk_nil()
+ } else {
+ node_id_type(bcx, pat_id)
+ };
- if any_uniq_pat(m, col) {
- let llbox = Load(bcx, val);
- compile_submatch(bcx,
- enter_uniq(bcx, dm, m, col, val).as_slice(),
- (vec!(llbox)).append(vals_left.as_slice()).as_slice(),
- chk, has_genuine_default);
- return;
- }
+ let mcx = check_match::MatchCheckCtxt { tcx: bcx.tcx() };
+ let adt_vals = if any_irrefutable_adt_pat(bcx, m, col) {
+ let repr = adt::represent_type(bcx.ccx(), left_ty);
+ let arg_count = adt::num_args(&*repr, 0);
+ let field_vals: Vec = std::iter::range(0, arg_count).map(|ix|
+ adt::trans_field_ptr(bcx, &*repr, val, 0, ix)
+ ).collect();
+ Some(field_vals)
+ } else if any_uniq_pat(m, col) || any_region_pat(m, col) {
+ Some(vec!(Load(bcx, val)))
+ } else {
+ None
+ };
- if any_region_pat(m, col) {
- let loaded_val = Load(bcx, val);
- compile_submatch(bcx,
- enter_region(bcx, dm, m, col, val).as_slice(),
- (vec!(loaded_val)).append(vals_left.as_slice()).as_slice(),
- chk, has_genuine_default);
- return;
+ match adt_vals {
+ Some(field_vals) => {
+ let pats = enter_match(bcx, dm, m, col, val, |pats|
+ check_match::specialize(&mcx, pats, &check_match::Single, col, field_vals.len())
+ );
+ let vals = field_vals.append(vals_left.as_slice());
+ compile_submatch(bcx, pats.as_slice(), vals.as_slice(), chk, has_genuine_default);
+ return;
+ }
+ _ => ()
}
// Decide what kind of branch we need
@@ -1582,15 +1230,14 @@ fn compile_submatch_continue<'a, 'b>(
debug!("test_val={}", bcx.val_to_str(test_val));
if opts.len() > 0u {
match *opts.get(0) {
- var(_, ref repr) => {
+ var(_, ref repr, _) => {
let (the_kind, val_opt) = adt::trans_switch(bcx, &**repr, val);
kind = the_kind;
for &tval in val_opt.iter() { test_val = tval; }
}
lit(_) => {
- let pty = node_id_type(bcx, pat_id);
- test_val = load_if_immediate(bcx, val, pty);
- kind = if ty::type_is_integral(pty) { switch }
+ test_val = load_if_immediate(bcx, val, left_ty);
+ kind = if ty::type_is_integral(left_ty) { switch }
else { compare };
}
range(_, _) => {
@@ -1598,8 +1245,7 @@ fn compile_submatch_continue<'a, 'b>(
kind = compare;
},
vec_len(..) => {
- let vec_ty = node_id_type(bcx, pat_id);
- let (_, len) = tvec::get_base_and_len(bcx, val, vec_ty);
+ let (_, len) = tvec::get_base_and_len(bcx, val, left_ty);
test_val = len;
kind = compare_vec_len;
}
@@ -1652,17 +1298,19 @@ fn compile_submatch_continue<'a, 'b>(
}
}
}
- compare => {
- let t = node_id_type(bcx, pat_id);
+ compare | compare_vec_len => {
+ let t = if kind == compare {
+ left_ty
+ } else {
+ ty::mk_uint() // vector length
+ };
let Result {bcx: after_cx, val: matches} = {
match trans_opt(bcx, opt) {
single_result(Result {bcx, val}) => {
compare_values(bcx, test_val, val, t)
}
lower_bound(Result {bcx, val}) => {
- compare_scalar_types(
- bcx, test_val, val,
- t, ast::BiGe)
+ compare_scalar_types(bcx, test_val, val, t, ast::BiGe)
}
range_result(Result {val: vbegin, ..},
Result {bcx, val: vend}) => {
@@ -1686,48 +1334,7 @@ fn compile_submatch_continue<'a, 'b>(
// the default.
let guarded = m[i].data.arm.guard.is_some();
let multi_pats = m[i].pats.len() > 1;
- if i+1 < len && (guarded || multi_pats) {
- branch_chk = Some(JumpToBasicBlock(bcx.llbb));
- }
- CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb);
- }
- compare_vec_len => {
- let Result {bcx: after_cx, val: matches} = {
- match trans_opt(bcx, opt) {
- single_result(
- Result {bcx, val}) => {
- let value = compare_scalar_values(
- bcx, test_val, val,
- signed_int, ast::BiEq);
- Result::new(bcx, value)
- }
- lower_bound(
- Result {bcx, val: val}) => {
- let value = compare_scalar_values(
- bcx, test_val, val,
- signed_int, ast::BiGe);
- Result::new(bcx, value)
- }
- range_result(
- Result {val: vbegin, ..},
- Result {bcx, val: vend}) => {
- let llge =
- compare_scalar_values(
- bcx, test_val,
- vbegin, signed_int, ast::BiGe);
- let llle =
- compare_scalar_values(
- bcx, test_val, vend,
- signed_int, ast::BiLe);
- Result::new(bcx, And(bcx, llge, llle))
- }
- }
- };
- bcx = fcx.new_temp_block("compare_vec_len_next");
-
- // If none of these subcases match, move on to the
- // next condition if there is any.
- if i+1 < len {
+ if i + 1 < len && (guarded || multi_pats || kind == compare_vec_len) {
branch_chk = Some(JumpToBasicBlock(bcx.llbb));
}
CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb);
@@ -1741,7 +1348,7 @@ fn compile_submatch_continue<'a, 'b>(
let mut size = 0u;
let mut unpacked = Vec::new();
match *opt {
- var(disr_val, ref repr) => {
+ var(disr_val, ref repr, _) => {
let ExtractedBlock {vals: argvals, bcx: new_bcx} =
extract_variant_args(opt_cx, &**repr, disr_val, val);
size = argvals.len();
@@ -1761,7 +1368,7 @@ fn compile_submatch_continue<'a, 'b>(
}
lit(_) | range(_, _) => ()
}
- let opt_ms = enter_opt(opt_cx, m, opt, col, size, val);
+ let opt_ms = enter_opt(opt_cx, pat_id, dm, m, opt, col, size, val);
let opt_vals = unpacked.append(vals_left.as_slice());
match branch_chk {