2013-05-21 04:04:55 -05:00
|
|
|
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 18:48:01 -06:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2013-05-17 17:28:44 -05:00
|
|
|
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::const_eval::{compare_const_vals, lookup_const_by_id};
|
2013-03-26 15:38:07 -05:00
|
|
|
use middle::const_eval::{eval_const_expr, const_val, const_bool};
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::pat_util::*;
|
|
|
|
use middle::ty::*;
|
|
|
|
use middle::ty;
|
|
|
|
use middle::typeck::method_map;
|
2013-01-10 12:59:58 -06:00
|
|
|
use middle::moves;
|
2012-12-13 15:05:22 -06:00
|
|
|
use util::ppaux::ty_to_str;
|
|
|
|
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 11:05:17 -05:00
|
|
|
use std::num;
|
2013-06-28 17:32:26 -05:00
|
|
|
use std::uint;
|
|
|
|
use std::vec;
|
2013-05-18 14:39:17 -05:00
|
|
|
use extra::sort;
|
2012-09-04 13:54:36 -05:00
|
|
|
use syntax::ast::*;
|
2013-03-26 15:38:07 -05:00
|
|
|
use syntax::ast_util::{unguarded_pat, walk_pat};
|
2013-01-30 11:56:33 -06:00
|
|
|
use syntax::codemap::{span, dummy_sp, spanned};
|
2012-09-04 13:54:36 -05:00
|
|
|
use syntax::visit;
|
2011-07-25 06:45:09 -05:00
|
|
|
|
2013-01-30 15:44:24 -06:00
|
|
|
pub struct MatchCheckCtxt {
|
2012-12-05 20:27:04 -06:00
|
|
|
tcx: ty::ctxt,
|
|
|
|
method_map: method_map,
|
2013-01-10 12:59:58 -06:00
|
|
|
moves_map: moves::MovesMap
|
2012-12-05 20:27:04 -06:00
|
|
|
}
|
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
pub fn check_crate(tcx: ty::ctxt,
|
|
|
|
method_map: method_map,
|
|
|
|
moves_map: moves::MovesMap,
|
2013-06-27 08:04:22 -05:00
|
|
|
crate: &crate) {
|
2013-01-10 12:59:58 -06:00
|
|
|
let cx = @MatchCheckCtxt {tcx: tcx,
|
|
|
|
method_map: method_map,
|
|
|
|
moves_map: moves_map};
|
2013-06-11 21:55:16 -05:00
|
|
|
visit::visit_crate(crate, ((), visit::mk_vt(@visit::Visitor {
|
|
|
|
visit_expr: |a,b| check_expr(cx, a, b),
|
|
|
|
visit_local: |a,b| check_local(cx, a, b),
|
|
|
|
visit_fn: |kind, decl, body, sp, id, (e, v)|
|
|
|
|
check_fn(cx, kind, decl, body, sp, id, (e, v)),
|
2012-09-04 15:29:32 -05:00
|
|
|
.. *visit::default_visitor::<()>()
|
2013-06-11 21:55:16 -05:00
|
|
|
})));
|
2011-07-25 06:45:09 -05:00
|
|
|
tcx.sess.abort_if_errors();
|
|
|
|
}
|
|
|
|
|
2013-06-11 21:55:16 -05:00
|
|
|
pub fn check_expr(cx: @MatchCheckCtxt, ex: @expr, (s, v): ((), visit::vt<()>)) {
|
|
|
|
visit::visit_expr(ex, (s, v));
|
2012-08-06 14:34:08 -05:00
|
|
|
match ex.node {
|
2012-12-04 12:50:00 -06:00
|
|
|
expr_match(scrut, ref arms) => {
|
2012-12-05 21:01:14 -06:00
|
|
|
// First, check legality of move bindings.
|
2013-06-21 07:29:53 -05:00
|
|
|
for arms.iter().advance |arm| {
|
2012-12-05 21:01:14 -06:00
|
|
|
check_legality_of_move_bindings(cx,
|
|
|
|
arm.guard.is_some(),
|
|
|
|
arm.pats);
|
|
|
|
}
|
|
|
|
|
2013-03-03 10:50:20 -06:00
|
|
|
check_arms(cx, *arms);
|
2012-02-15 02:35:11 -06:00
|
|
|
/* Check for exhaustiveness */
|
2012-07-27 15:13:03 -05:00
|
|
|
// Check for empty enum, because is_useful only works on inhabited
|
|
|
|
// types.
|
2012-12-05 20:27:04 -06:00
|
|
|
let pat_ty = node_id_to_type(cx.tcx, scrut.id);
|
2012-12-04 12:50:00 -06:00
|
|
|
if (*arms).is_empty() {
|
2012-12-05 20:27:04 -06:00
|
|
|
if !type_is_empty(cx.tcx, pat_ty) {
|
2012-08-15 16:28:52 -05:00
|
|
|
// We know the type is inhabited, so this must be wrong
|
2012-12-05 20:27:04 -06:00
|
|
|
cx.tcx.sess.span_err(ex.span, fmt!("non-exhaustive patterns: \
|
|
|
|
type %s is non-empty",
|
|
|
|
ty_to_str(cx.tcx, pat_ty)));
|
2012-07-27 15:13:03 -05:00
|
|
|
}
|
2012-08-15 16:28:52 -05:00
|
|
|
// If the type *is* empty, it's vacuously exhaustive
|
|
|
|
return;
|
|
|
|
}
|
2012-09-11 18:20:31 -05:00
|
|
|
match ty::get(pat_ty).sty {
|
2012-08-03 21:59:04 -05:00
|
|
|
ty_enum(did, _) => {
|
2012-12-05 20:27:04 -06:00
|
|
|
if (*enum_variants(cx.tcx, did)).is_empty() &&
|
|
|
|
(*arms).is_empty() {
|
2012-07-27 15:13:03 -05:00
|
|
|
|
2012-08-01 19:30:05 -05:00
|
|
|
return;
|
2012-07-27 15:13:03 -05:00
|
|
|
}
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => { /* We assume only enum types can be uninhabited */ }
|
2012-07-27 15:13:03 -05:00
|
|
|
}
|
2013-07-01 21:38:19 -05:00
|
|
|
let arms = arms.iter().filter_map(unguarded_pat).collect::<~[~[@pat]]>().concat_vec();
|
2013-02-26 06:32:36 -06:00
|
|
|
if arms.is_empty() {
|
2013-04-30 11:47:52 -05:00
|
|
|
cx.tcx.sess.span_err(ex.span, "non-exhaustive patterns");
|
2013-02-26 06:32:36 -06:00
|
|
|
} else {
|
|
|
|
check_exhaustive(cx, ex.span, arms);
|
|
|
|
}
|
2012-08-24 23:03:51 -05:00
|
|
|
}
|
|
|
|
_ => ()
|
2012-01-14 18:05:07 -06:00
|
|
|
}
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
|
|
|
|
2012-04-24 04:13:25 -05:00
|
|
|
// Check for unreachable patterns
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn check_arms(cx: &MatchCheckCtxt, arms: &[arm]) {
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut seen = ~[];
|
2013-06-21 07:29:53 -05:00
|
|
|
for arms.iter().advance |arm| {
|
|
|
|
for arm.pats.iter().advance |pat| {
|
2012-09-19 18:55:01 -05:00
|
|
|
let v = ~[*pat];
|
2013-03-03 10:50:20 -06:00
|
|
|
match is_useful(cx, &seen, v) {
|
2012-08-03 21:59:04 -05:00
|
|
|
not_useful => {
|
2013-04-30 11:47:52 -05:00
|
|
|
cx.tcx.sess.span_err(pat.span, "unreachable pattern");
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => ()
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
2012-09-26 19:33:34 -05:00
|
|
|
if arm.guard.is_none() { seen.push(v); }
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
|
|
|
}
|
2012-01-30 23:00:57 -06:00
|
|
|
}
|
|
|
|
|
2013-01-30 15:44:24 -06:00
|
|
|
pub fn raw_pat(p: @pat) -> @pat {
|
2012-08-06 14:34:08 -05:00
|
|
|
match p.node {
|
2012-08-20 14:23:37 -05:00
|
|
|
pat_ident(_, _, Some(s)) => { raw_pat(s) }
|
2012-07-31 21:25:24 -05:00
|
|
|
_ => { p }
|
2012-02-15 02:40:42 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn check_exhaustive(cx: &MatchCheckCtxt, sp: span, pats: ~[@pat]) {
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!((!pats.is_empty()));
|
2013-05-19 00:07:44 -05:00
|
|
|
let ext = match is_useful(cx, &pats.map(|p| ~[*p]), [wild()]) {
|
2013-02-16 12:36:09 -06:00
|
|
|
not_useful => {
|
|
|
|
// This is good, wildcard pattern isn't reachable
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
useful_ => None,
|
|
|
|
useful(ty, ref ctor) => {
|
|
|
|
match ty::get(ty).sty {
|
|
|
|
ty::ty_bool => {
|
|
|
|
match (*ctor) {
|
2013-06-12 12:02:55 -05:00
|
|
|
val(const_bool(true)) => Some(@"true"),
|
|
|
|
val(const_bool(false)) => Some(@"false"),
|
2013-02-16 12:36:09 -06:00
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ty::ty_enum(id, _) => {
|
2013-02-10 18:33:16 -06:00
|
|
|
let vid = match *ctor {
|
2013-02-16 12:36:09 -06:00
|
|
|
variant(id) => id,
|
2013-05-05 17:18:51 -05:00
|
|
|
_ => fail!("check_exhaustive: non-variant ctor"),
|
2013-02-16 12:36:09 -06:00
|
|
|
};
|
|
|
|
let variants = ty::enum_variants(cx.tcx, id);
|
|
|
|
|
2013-06-17 18:43:22 -05:00
|
|
|
match variants.iter().find_(|v| v.id == vid) {
|
2013-02-16 12:36:09 -06:00
|
|
|
Some(v) => Some(cx.tcx.sess.str_of(v.name)),
|
|
|
|
None => {
|
2013-05-05 17:18:51 -05:00
|
|
|
fail!("check_exhaustive: bad variant in ctor")
|
2013-02-16 12:36:09 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
|
2013-02-10 18:33:16 -06:00
|
|
|
match *ctor {
|
2013-06-12 12:02:55 -05:00
|
|
|
vec(n) => Some(fmt!("vectors of length %u", n).to_managed()),
|
2013-03-03 13:44:11 -06:00
|
|
|
_ => None
|
2013-02-16 12:36:09 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => None
|
2012-12-08 14:22:43 -06:00
|
|
|
}
|
2012-02-15 02:40:42 -06:00
|
|
|
}
|
2012-04-24 04:13:25 -05:00
|
|
|
};
|
2012-08-06 14:34:08 -05:00
|
|
|
let msg = ~"non-exhaustive patterns" + match ext {
|
2013-06-12 12:02:55 -05:00
|
|
|
Some(ref s) => fmt!(": %s not covered", *s),
|
2013-02-16 12:36:09 -06:00
|
|
|
None => ~""
|
2012-04-24 04:13:25 -05:00
|
|
|
};
|
2012-12-05 20:27:04 -06:00
|
|
|
cx.tcx.sess.span_err(sp, msg);
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
|
|
|
|
2013-01-30 15:44:24 -06:00
|
|
|
pub type matrix = ~[~[@pat]];
|
2012-04-24 04:13:25 -05:00
|
|
|
|
2013-01-30 15:44:24 -06:00
|
|
|
pub enum useful { useful(ty::t, ctor), useful_, not_useful }
|
2012-04-24 04:13:25 -05:00
|
|
|
|
2013-03-20 10:40:02 -05:00
|
|
|
#[deriving(Eq)]
|
2013-01-30 15:44:24 -06:00
|
|
|
pub enum ctor {
|
2012-04-24 04:13:25 -05:00
|
|
|
single,
|
|
|
|
variant(def_id),
|
|
|
|
val(const_val),
|
|
|
|
range(const_val, const_val),
|
2012-12-15 17:06:48 -06:00
|
|
|
vec(uint)
|
2012-02-15 02:40:42 -06:00
|
|
|
}
|
|
|
|
|
2012-04-24 04:13:25 -05:00
|
|
|
// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
|
|
|
|
//
|
|
|
|
// Whether a vector `v` of patterns is 'useful' in relation to a set of such
|
|
|
|
// vectors `m` is defined as there being a set of inputs that will match `v`
|
|
|
|
// but not any of the sets in `m`.
|
|
|
|
//
|
|
|
|
// This is used both for reachability checking (if a pattern isn't useful in
|
|
|
|
// relation to preceding patterns, it is not reachable) and exhaustiveness
|
|
|
|
// checking (if a wildcard pattern is useful in relation to a matrix, the
|
|
|
|
// matrix isn't exhaustive).
|
|
|
|
|
2012-07-27 15:13:03 -05:00
|
|
|
// Note: is_useful doesn't work on empty types, as the paper notes.
|
|
|
|
// So it assumes that v is non-empty.
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[@pat]) -> useful {
|
2012-08-01 19:30:05 -05:00
|
|
|
if m.len() == 0u { return useful_; }
|
|
|
|
if m[0].len() == 0u { return not_useful; }
|
2013-06-17 18:43:22 -05:00
|
|
|
let real_pat = match m.iter().find_(|r| r[0].id != 0) {
|
2012-08-20 14:23:37 -05:00
|
|
|
Some(r) => r[0], None => v[0]
|
2012-04-24 04:13:25 -05:00
|
|
|
};
|
2013-04-22 22:19:05 -05:00
|
|
|
let left_ty = if real_pat.id == 0 { ty::mk_nil() }
|
2012-12-05 20:27:04 -06:00
|
|
|
else { ty::node_id_to_type(cx.tcx, real_pat.id) };
|
2012-02-15 02:40:42 -06:00
|
|
|
|
2012-12-05 20:27:04 -06:00
|
|
|
match pat_ctor_id(cx, v[0]) {
|
2012-08-20 14:23:37 -05:00
|
|
|
None => {
|
2012-12-05 20:27:04 -06:00
|
|
|
match missing_ctor(cx, m, left_ty) {
|
2012-08-20 14:23:37 -05:00
|
|
|
None => {
|
2012-09-11 18:20:31 -05:00
|
|
|
match ty::get(left_ty).sty {
|
2012-08-03 21:59:04 -05:00
|
|
|
ty::ty_bool => {
|
2012-12-05 20:27:04 -06:00
|
|
|
match is_useful_specialized(cx, m, v,
|
|
|
|
val(const_bool(true)),
|
|
|
|
0u, left_ty){
|
2012-08-03 21:59:04 -05:00
|
|
|
not_useful => {
|
2012-12-05 20:27:04 -06:00
|
|
|
is_useful_specialized(cx, m, v,
|
|
|
|
val(const_bool(false)),
|
2012-04-24 04:13:25 -05:00
|
|
|
0u, left_ty)
|
|
|
|
}
|
2013-06-27 19:41:35 -05:00
|
|
|
ref u => *u,
|
2012-02-15 02:40:42 -06:00
|
|
|
}
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
ty::ty_enum(eid, _) => {
|
2013-06-21 07:29:53 -05:00
|
|
|
for (*ty::enum_variants(cx.tcx, eid)).iter().advance |va| {
|
2012-12-05 20:27:04 -06:00
|
|
|
match is_useful_specialized(cx, m, v, variant(va.id),
|
|
|
|
va.args.len(), left_ty) {
|
2012-08-03 21:59:04 -05:00
|
|
|
not_useful => (),
|
2013-06-27 19:41:35 -05:00
|
|
|
ref u => return *u,
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
not_useful
|
|
|
|
}
|
2012-12-08 14:22:43 -06:00
|
|
|
ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
|
2013-06-08 03:28:08 -05:00
|
|
|
let max_len = do m.rev_iter().fold(0) |max_len, r| {
|
2013-03-20 00:17:42 -05:00
|
|
|
match r[0].node {
|
|
|
|
pat_vec(ref before, _, ref after) => {
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 11:05:17 -05:00
|
|
|
num::max(before.len() + after.len(), max_len)
|
2013-02-26 12:58:46 -06:00
|
|
|
}
|
2012-12-08 14:22:43 -06:00
|
|
|
_ => max_len
|
|
|
|
}
|
|
|
|
};
|
|
|
|
for uint::range(0, max_len + 1) |n| {
|
|
|
|
match is_useful_specialized(cx, m, v, vec(n), n, left_ty) {
|
|
|
|
not_useful => (),
|
2013-06-27 19:41:35 -05:00
|
|
|
ref u => return *u,
|
2012-12-08 14:22:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
not_useful
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => {
|
2013-04-17 11:15:37 -05:00
|
|
|
let arity = ctor_arity(cx, &single, left_ty);
|
2012-12-05 20:27:04 -06:00
|
|
|
is_useful_specialized(cx, m, v, single, arity, left_ty)
|
2012-04-20 02:54:42 -05:00
|
|
|
}
|
2012-01-30 23:00:57 -06:00
|
|
|
}
|
2012-05-03 10:35:12 -05:00
|
|
|
}
|
2012-12-04 12:50:00 -06:00
|
|
|
Some(ref ctor) => {
|
2013-01-31 19:12:29 -06:00
|
|
|
match is_useful(cx,
|
2013-07-01 21:38:19 -05:00
|
|
|
&m.iter().filter_map(|r| default(cx, *r)).collect::<matrix>(),
|
2013-03-03 09:22:40 -06:00
|
|
|
v.tail()) {
|
2013-06-27 19:41:35 -05:00
|
|
|
useful_ => useful(left_ty, *ctor),
|
|
|
|
ref u => *u,
|
2012-05-03 10:35:12 -05:00
|
|
|
}
|
|
|
|
}
|
2012-01-30 23:00:57 -06:00
|
|
|
}
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
2012-12-04 12:50:00 -06:00
|
|
|
Some(ref v0_ctor) => {
|
2013-04-17 11:15:37 -05:00
|
|
|
let arity = ctor_arity(cx, v0_ctor, left_ty);
|
2013-06-27 19:41:35 -05:00
|
|
|
is_useful_specialized(cx, m, v, *v0_ctor, arity, left_ty)
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
2012-01-30 23:00:57 -06:00
|
|
|
}
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
|
|
|
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn is_useful_specialized(cx: &MatchCheckCtxt,
|
2013-03-03 13:44:11 -06:00
|
|
|
m: &matrix,
|
2013-03-03 09:22:40 -06:00
|
|
|
v: &[@pat],
|
2013-04-17 11:15:37 -05:00
|
|
|
ctor: ctor,
|
2013-01-30 15:44:24 -06:00
|
|
|
arity: uint,
|
|
|
|
lty: ty::t)
|
|
|
|
-> useful {
|
2013-07-01 21:38:19 -05:00
|
|
|
let ms = m.iter().filter_map(|r| specialize(cx, *r, &ctor, arity, lty)).collect::<matrix>();
|
2012-08-06 14:34:08 -05:00
|
|
|
let could_be_useful = is_useful(
|
2013-04-17 11:15:37 -05:00
|
|
|
cx, &ms, specialize(cx, v, &ctor, arity, lty).get());
|
2012-08-06 14:34:08 -05:00
|
|
|
match could_be_useful {
|
2012-08-03 21:59:04 -05:00
|
|
|
useful_ => useful(lty, ctor),
|
2013-06-27 19:41:35 -05:00
|
|
|
ref u => *u,
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
|
|
|
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn pat_ctor_id(cx: &MatchCheckCtxt, p: @pat) -> Option<ctor> {
|
2012-04-24 04:13:25 -05:00
|
|
|
let pat = raw_pat(p);
|
2013-03-20 00:17:42 -05:00
|
|
|
match pat.node {
|
2012-08-20 14:23:37 -05:00
|
|
|
pat_wild => { None }
|
2012-07-31 21:25:24 -05:00
|
|
|
pat_ident(_, _, _) | pat_enum(_, _) => {
|
2013-02-05 21:41:45 -06:00
|
|
|
match cx.tcx.def_map.find(&pat.id) {
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&def_variant(_, id)) => Some(variant(id)),
|
2013-06-21 20:46:34 -05:00
|
|
|
Some(&def_static(did, false)) => {
|
2012-12-05 20:27:04 -06:00
|
|
|
let const_expr = lookup_const_by_id(cx.tcx, did).get();
|
|
|
|
Some(val(eval_const_expr(cx.tcx, const_expr)))
|
2012-11-13 00:10:15 -06:00
|
|
|
}
|
2012-08-20 14:23:37 -05:00
|
|
|
_ => None
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
2012-12-05 20:27:04 -06:00
|
|
|
pat_lit(expr) => { Some(val(eval_const_expr(cx.tcx, expr))) }
|
2012-07-31 21:25:24 -05:00
|
|
|
pat_range(lo, hi) => {
|
2012-12-05 20:27:04 -06:00
|
|
|
Some(range(eval_const_expr(cx.tcx, lo), eval_const_expr(cx.tcx, hi)))
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
2012-08-06 19:01:14 -05:00
|
|
|
pat_struct(*) => {
|
2013-02-05 21:41:45 -06:00
|
|
|
match cx.tcx.def_map.find(&pat.id) {
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&def_variant(_, id)) => Some(variant(id)),
|
2012-10-24 20:47:59 -05:00
|
|
|
_ => Some(single)
|
|
|
|
}
|
|
|
|
}
|
2013-03-05 20:38:52 -06:00
|
|
|
pat_box(_) | pat_uniq(_) | pat_tup(_) | pat_region(*) => {
|
2012-08-20 14:23:37 -05:00
|
|
|
Some(single)
|
2012-07-31 21:25:24 -05:00
|
|
|
}
|
2013-03-20 00:17:42 -05:00
|
|
|
pat_vec(ref before, slice, ref after) => {
|
2013-02-26 12:58:46 -06:00
|
|
|
match slice {
|
2012-12-15 17:06:48 -06:00
|
|
|
Some(_) => None,
|
2013-02-26 12:58:46 -06:00
|
|
|
None => Some(vec(before.len() + after.len()))
|
2012-12-08 14:22:43 -06:00
|
|
|
}
|
|
|
|
}
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
2011-07-25 06:45:09 -05:00
|
|
|
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn is_wild(cx: &MatchCheckCtxt, p: @pat) -> bool {
|
2012-04-24 04:13:25 -05:00
|
|
|
let pat = raw_pat(p);
|
2012-08-06 14:34:08 -05:00
|
|
|
match pat.node {
|
2012-07-31 21:25:24 -05:00
|
|
|
pat_wild => { true }
|
|
|
|
pat_ident(_, _, _) => {
|
2013-02-05 21:41:45 -06:00
|
|
|
match cx.tcx.def_map.find(&pat.id) {
|
2013-06-21 20:46:34 -05:00
|
|
|
Some(&def_variant(_, _)) | Some(&def_static(*)) => { false }
|
2012-07-31 21:25:24 -05:00
|
|
|
_ => { true }
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
|
|
|
}
|
2012-07-31 21:25:24 -05:00
|
|
|
_ => { false }
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn missing_ctor(cx: &MatchCheckCtxt,
|
2013-03-03 13:44:11 -06:00
|
|
|
m: &matrix,
|
2013-01-30 15:44:24 -06:00
|
|
|
left_ty: ty::t)
|
|
|
|
-> Option<ctor> {
|
2012-09-11 18:20:31 -05:00
|
|
|
match ty::get(left_ty).sty {
|
2012-09-07 19:07:32 -05:00
|
|
|
ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_rptr(*) | ty::ty_tup(_) |
|
2013-03-05 20:06:53 -06:00
|
|
|
ty::ty_struct(*) => {
|
2013-06-21 07:29:53 -05:00
|
|
|
for m.iter().advance |r| {
|
2012-12-05 20:27:04 -06:00
|
|
|
if !is_wild(cx, r[0]) { return None; }
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
2012-08-20 14:23:37 -05:00
|
|
|
return Some(single);
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
ty::ty_enum(eid, _) => {
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut found = ~[];
|
2013-06-21 07:29:53 -05:00
|
|
|
for m.iter().advance |r| {
|
2013-06-10 16:50:12 -05:00
|
|
|
let r = pat_ctor_id(cx, r[0]);
|
|
|
|
for r.iter().advance |id| {
|
2013-06-28 11:08:32 -05:00
|
|
|
if !found.contains(id) {
|
2013-06-27 19:41:35 -05:00
|
|
|
found.push(*id);
|
2012-09-28 00:20:47 -05:00
|
|
|
}
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
2011-08-15 06:15:19 -05:00
|
|
|
}
|
2012-12-05 20:27:04 -06:00
|
|
|
let variants = ty::enum_variants(cx.tcx, eid);
|
2012-05-03 10:35:12 -05:00
|
|
|
if found.len() != (*variants).len() {
|
2013-06-21 07:29:53 -05:00
|
|
|
for (*variants).iter().advance |v| {
|
2013-07-04 21:13:26 -05:00
|
|
|
if !found.iter().any(|x| x == &(variant(v.id))) {
|
2012-08-20 14:23:37 -05:00
|
|
|
return Some(variant(v.id));
|
2012-05-03 10:35:12 -05:00
|
|
|
}
|
|
|
|
}
|
2013-02-11 21:26:38 -06:00
|
|
|
fail!();
|
2012-08-20 14:23:37 -05:00
|
|
|
} else { None }
|
2011-08-15 06:15:19 -05:00
|
|
|
}
|
2012-08-20 14:23:37 -05:00
|
|
|
ty::ty_nil => None,
|
2012-08-03 21:59:04 -05:00
|
|
|
ty::ty_bool => {
|
2013-06-04 23:43:41 -05:00
|
|
|
let mut true_found = false;
|
|
|
|
let mut false_found = false;
|
2013-06-21 07:29:53 -05:00
|
|
|
for m.iter().advance |r| {
|
2012-12-05 20:27:04 -06:00
|
|
|
match pat_ctor_id(cx, r[0]) {
|
2012-08-20 14:23:37 -05:00
|
|
|
None => (),
|
|
|
|
Some(val(const_bool(true))) => true_found = true,
|
|
|
|
Some(val(const_bool(false))) => false_found = true,
|
2013-05-05 17:18:51 -05:00
|
|
|
_ => fail!("impossible case")
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
2012-08-20 14:23:37 -05:00
|
|
|
if true_found && false_found { None }
|
|
|
|
else if true_found { Some(val(const_bool(false))) }
|
|
|
|
else { Some(val(const_bool(true))) }
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
2012-12-08 14:22:43 -06:00
|
|
|
ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
|
2012-12-15 17:11:58 -06:00
|
|
|
|
2013-02-26 12:58:46 -06:00
|
|
|
// Find the lengths and slices of all vector patterns.
|
2013-07-01 21:38:19 -05:00
|
|
|
let vec_pat_lens = do m.iter().filter_map |r| {
|
2013-01-31 19:12:29 -06:00
|
|
|
match r[0].node {
|
2013-02-26 12:58:46 -06:00
|
|
|
pat_vec(ref before, ref slice, ref after) => {
|
|
|
|
Some((before.len() + after.len(), slice.is_some()))
|
2012-12-15 17:11:58 -06:00
|
|
|
}
|
2012-12-08 14:22:43 -06:00
|
|
|
_ => None
|
|
|
|
}
|
2013-07-01 21:38:19 -05:00
|
|
|
}.collect::<~[(uint, bool)]>();
|
2012-12-15 17:11:58 -06:00
|
|
|
|
|
|
|
// Sort them by length such that for patterns of the same length,
|
2013-02-26 12:58:46 -06:00
|
|
|
// those with a destructured slice come first.
|
2012-12-15 17:11:58 -06:00
|
|
|
let mut sorted_vec_lens = sort::merge_sort(vec_pat_lens,
|
2013-02-26 12:58:46 -06:00
|
|
|
|&(len1, slice1), &(len2, slice2)| {
|
2012-12-15 17:11:58 -06:00
|
|
|
if len1 == len2 {
|
2013-02-26 12:58:46 -06:00
|
|
|
slice1 > slice2
|
2012-12-15 17:11:58 -06:00
|
|
|
} else {
|
|
|
|
len1 <= len2
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
2013-06-28 22:41:09 -05:00
|
|
|
sorted_vec_lens.dedup();
|
2012-12-08 14:22:43 -06:00
|
|
|
|
2013-02-26 12:58:46 -06:00
|
|
|
let mut found_slice = false;
|
2012-12-15 17:11:58 -06:00
|
|
|
let mut next = 0;
|
2012-12-08 14:22:43 -06:00
|
|
|
let mut missing = None;
|
2013-06-21 07:29:53 -05:00
|
|
|
for sorted_vec_lens.iter().advance |&(length, slice)| {
|
2012-12-15 17:11:58 -06:00
|
|
|
if length != next {
|
|
|
|
missing = Some(next);
|
|
|
|
break;
|
|
|
|
}
|
2013-02-26 12:58:46 -06:00
|
|
|
if slice {
|
|
|
|
found_slice = true;
|
2012-12-15 17:11:58 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
next += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We found patterns of all lengths within <0, next), yet there was no
|
2013-02-26 12:58:46 -06:00
|
|
|
// pattern with a slice - therefore, we report vec(next) as missing.
|
|
|
|
if !found_slice {
|
2012-12-15 17:11:58 -06:00
|
|
|
missing = Some(next);
|
2012-12-08 14:22:43 -06:00
|
|
|
}
|
|
|
|
match missing {
|
|
|
|
Some(k) => Some(vec(k)),
|
|
|
|
None => None
|
|
|
|
}
|
|
|
|
}
|
2012-08-20 14:23:37 -05:00
|
|
|
_ => Some(single)
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn ctor_arity(cx: &MatchCheckCtxt, ctor: &ctor, ty: ty::t) -> uint {
|
2013-03-20 00:17:42 -05:00
|
|
|
match ty::get(ty).sty {
|
|
|
|
ty::ty_tup(ref fs) => fs.len(),
|
2012-09-07 19:07:32 -05:00
|
|
|
ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_rptr(*) => 1u,
|
2012-08-03 21:59:04 -05:00
|
|
|
ty::ty_enum(eid, _) => {
|
2013-04-17 11:15:37 -05:00
|
|
|
let id = match *ctor { variant(id) => id,
|
2013-05-05 17:18:51 -05:00
|
|
|
_ => fail!("impossible case") };
|
2013-06-19 17:56:57 -05:00
|
|
|
match ty::enum_variants(cx.tcx, eid).iter().find_(|v| v.id == id ) {
|
2012-08-20 14:23:37 -05:00
|
|
|
Some(v) => v.args.len(),
|
2013-05-05 17:18:51 -05:00
|
|
|
None => fail!("impossible case")
|
2011-09-23 13:15:17 -05:00
|
|
|
}
|
|
|
|
}
|
2012-12-10 15:47:54 -06:00
|
|
|
ty::ty_struct(cid, _) => ty::lookup_struct_fields(cx.tcx, cid).len(),
|
2012-12-08 14:22:43 -06:00
|
|
|
ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
|
2013-04-17 11:15:37 -05:00
|
|
|
match *ctor {
|
2012-12-15 17:06:48 -06:00
|
|
|
vec(n) => n,
|
2012-12-08 14:22:43 -06:00
|
|
|
_ => 0u
|
|
|
|
}
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => 0u
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-30 15:44:24 -06:00
|
|
|
pub fn wild() -> @pat {
|
2013-01-30 11:56:33 -06:00
|
|
|
@pat {id: 0, node: pat_wild, span: dummy_sp()}
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
|
|
|
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn specialize(cx: &MatchCheckCtxt,
|
2013-03-03 09:22:40 -06:00
|
|
|
r: &[@pat],
|
2013-04-17 11:15:37 -05:00
|
|
|
ctor_id: &ctor,
|
2013-01-30 15:44:24 -06:00
|
|
|
arity: uint,
|
|
|
|
left_ty: ty::t)
|
|
|
|
-> Option<~[@pat]> {
|
2013-01-24 22:10:05 -06:00
|
|
|
// Sad, but I can't get rid of this easily
|
2013-07-02 14:47:32 -05:00
|
|
|
let r0 = (*raw_pat(r[0])).clone();
|
2013-01-24 22:10:05 -06:00
|
|
|
match r0 {
|
|
|
|
pat{id: pat_id, node: n, span: pat_span} =>
|
|
|
|
match n {
|
2013-03-03 09:22:40 -06:00
|
|
|
pat_wild => {
|
|
|
|
Some(vec::append(vec::from_elem(arity, wild()), r.tail()))
|
|
|
|
}
|
2013-01-24 22:10:05 -06:00
|
|
|
pat_ident(_, _, _) => {
|
2013-02-05 21:41:45 -06:00
|
|
|
match cx.tcx.def_map.find(&pat_id) {
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&def_variant(_, id)) => {
|
2013-04-17 11:15:37 -05:00
|
|
|
if variant(id) == *ctor_id {
|
2013-07-12 02:53:03 -05:00
|
|
|
Some(r.tail().to_owned())
|
2013-03-03 09:22:40 -06:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2013-01-24 22:10:05 -06:00
|
|
|
}
|
2013-06-21 20:46:34 -05:00
|
|
|
Some(&def_static(did, _)) => {
|
2013-01-24 22:10:05 -06:00
|
|
|
let const_expr =
|
|
|
|
lookup_const_by_id(cx.tcx, did).get();
|
|
|
|
let e_v = eval_const_expr(cx.tcx, const_expr);
|
2013-04-17 11:15:37 -05:00
|
|
|
let match_ = match *ctor_id {
|
2013-05-21 04:04:55 -05:00
|
|
|
val(ref v) => {
|
|
|
|
match compare_const_vals(&e_v, v) {
|
|
|
|
Some(val1) => (val1 == 0),
|
|
|
|
None => {
|
|
|
|
cx.tcx.sess.span_err(pat_span,
|
|
|
|
"mismatched types between arms");
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2013-01-24 22:10:05 -06:00
|
|
|
range(ref c_lo, ref c_hi) => {
|
2013-06-04 23:43:41 -05:00
|
|
|
let m1 = compare_const_vals(c_lo, &e_v);
|
|
|
|
let m2 = compare_const_vals(c_hi, &e_v);
|
2013-05-21 04:04:55 -05:00
|
|
|
match (m1, m2) {
|
2013-06-04 23:43:41 -05:00
|
|
|
(Some(val1), Some(val2)) => {
|
|
|
|
(val1 >= 0 && val2 <= 0)
|
|
|
|
}
|
2013-05-21 04:04:55 -05:00
|
|
|
_ => {
|
|
|
|
cx.tcx.sess.span_err(pat_span,
|
|
|
|
"mismatched types between ranges");
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
2013-01-24 22:10:05 -06:00
|
|
|
}
|
|
|
|
single => true,
|
2013-05-05 17:18:51 -05:00
|
|
|
_ => fail!("type error")
|
2013-01-24 22:10:05 -06:00
|
|
|
};
|
2013-03-03 09:22:40 -06:00
|
|
|
if match_ {
|
2013-07-12 02:53:03 -05:00
|
|
|
Some(r.tail().to_owned())
|
2013-03-03 09:22:40 -06:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
Some(
|
|
|
|
vec::append(
|
|
|
|
vec::from_elem(arity, wild()),
|
|
|
|
r.tail()
|
|
|
|
)
|
|
|
|
)
|
2013-01-24 22:10:05 -06:00
|
|
|
}
|
2012-11-13 00:10:15 -06:00
|
|
|
}
|
2012-11-02 11:56:09 -05:00
|
|
|
}
|
2013-01-24 22:10:05 -06:00
|
|
|
pat_enum(_, args) => {
|
2013-05-05 11:17:59 -05:00
|
|
|
match cx.tcx.def_map.get_copy(&pat_id) {
|
2013-06-21 20:46:34 -05:00
|
|
|
def_static(did, _) => {
|
2013-03-21 02:27:26 -05:00
|
|
|
let const_expr =
|
|
|
|
lookup_const_by_id(cx.tcx, did).get();
|
|
|
|
let e_v = eval_const_expr(cx.tcx, const_expr);
|
2013-04-17 11:15:37 -05:00
|
|
|
let match_ = match *ctor_id {
|
2013-05-21 04:04:55 -05:00
|
|
|
val(ref v) =>
|
|
|
|
match compare_const_vals(&e_v, v) {
|
|
|
|
Some(val1) => (val1 == 0),
|
|
|
|
None => {
|
|
|
|
cx.tcx.sess.span_err(pat_span,
|
|
|
|
"mismatched types between arms");
|
|
|
|
false
|
|
|
|
}
|
|
|
|
},
|
2013-03-21 02:27:26 -05:00
|
|
|
range(ref c_lo, ref c_hi) => {
|
2013-06-04 23:43:41 -05:00
|
|
|
let m1 = compare_const_vals(c_lo, &e_v);
|
|
|
|
let m2 = compare_const_vals(c_hi, &e_v);
|
2013-05-21 04:04:55 -05:00
|
|
|
match (m1, m2) {
|
|
|
|
(Some(val1), Some(val2)) => (val1 >= 0 && val2 <= 0),
|
|
|
|
_ => {
|
|
|
|
cx.tcx.sess.span_err(pat_span,
|
|
|
|
"mismatched types between ranges");
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
2013-03-21 02:27:26 -05:00
|
|
|
}
|
|
|
|
single => true,
|
2013-05-05 17:18:51 -05:00
|
|
|
_ => fail!("type error")
|
2013-03-21 02:27:26 -05:00
|
|
|
};
|
|
|
|
if match_ {
|
2013-07-12 02:53:03 -05:00
|
|
|
Some(r.tail().to_owned())
|
2013-03-21 02:27:26 -05:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2013-04-17 11:15:37 -05:00
|
|
|
def_variant(_, id) if variant(id) == *ctor_id => {
|
2013-01-24 22:10:05 -06:00
|
|
|
let args = match args {
|
|
|
|
Some(args) => args,
|
|
|
|
None => vec::from_elem(arity, wild())
|
|
|
|
};
|
2013-07-12 02:53:03 -05:00
|
|
|
Some(vec::append(args, r.tail()))
|
2013-01-24 22:10:05 -06:00
|
|
|
}
|
|
|
|
def_variant(_, _) => None,
|
2013-04-29 19:21:59 -05:00
|
|
|
|
|
|
|
def_fn(*) |
|
2013-01-24 22:10:05 -06:00
|
|
|
def_struct(*) => {
|
2013-01-31 21:48:43 -06:00
|
|
|
// FIXME #4731: Is this right? --pcw
|
2013-01-24 22:10:05 -06:00
|
|
|
let new_args;
|
|
|
|
match args {
|
|
|
|
Some(args) => new_args = args,
|
|
|
|
None => new_args = vec::from_elem(arity, wild())
|
2012-10-24 20:47:59 -05:00
|
|
|
}
|
2013-07-12 02:53:03 -05:00
|
|
|
Some(vec::append(new_args, r.tail()))
|
2013-01-24 22:10:05 -06:00
|
|
|
}
|
|
|
|
_ => None
|
2012-10-24 20:47:59 -05:00
|
|
|
}
|
2012-08-06 19:01:14 -05:00
|
|
|
}
|
2013-01-24 22:10:05 -06:00
|
|
|
pat_struct(_, ref flds, _) => {
|
|
|
|
// Is this a struct or an enum variant?
|
2013-05-05 11:17:59 -05:00
|
|
|
match cx.tcx.def_map.get_copy(&pat_id) {
|
2013-01-24 22:10:05 -06:00
|
|
|
def_variant(_, variant_id) => {
|
2013-04-17 11:15:37 -05:00
|
|
|
if variant(variant_id) == *ctor_id {
|
2013-01-31 21:48:43 -06:00
|
|
|
// FIXME #4731: Is this right? --pcw
|
2013-01-24 22:10:05 -06:00
|
|
|
let args = flds.map(|ty_field| {
|
2013-06-17 18:43:22 -05:00
|
|
|
match flds.iter().find_(|f|
|
2013-01-24 22:10:05 -06:00
|
|
|
f.ident == ty_field.ident) {
|
|
|
|
Some(f) => f.pat,
|
|
|
|
_ => wild()
|
|
|
|
}
|
|
|
|
});
|
2013-07-12 02:53:03 -05:00
|
|
|
Some(vec::append(args, r.tail()))
|
2013-01-24 22:10:05 -06:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2012-10-24 20:47:59 -05:00
|
|
|
}
|
|
|
|
_ => {
|
2013-01-24 22:10:05 -06:00
|
|
|
// Grab the class data that we care about.
|
2013-06-04 23:43:41 -05:00
|
|
|
let class_fields;
|
|
|
|
let class_id;
|
2013-01-24 22:10:05 -06:00
|
|
|
match ty::get(left_ty).sty {
|
|
|
|
ty::ty_struct(cid, _) => {
|
|
|
|
class_id = cid;
|
|
|
|
class_fields =
|
|
|
|
ty::lookup_struct_fields(cx.tcx,
|
|
|
|
class_id);
|
|
|
|
}
|
|
|
|
_ => {
|
2013-04-02 00:32:37 -05:00
|
|
|
cx.tcx.sess.span_bug(
|
|
|
|
pat_span,
|
|
|
|
fmt!("struct pattern resolved to %s, \
|
|
|
|
not a struct",
|
|
|
|
ty_to_str(cx.tcx, left_ty)));
|
2013-01-24 22:10:05 -06:00
|
|
|
}
|
|
|
|
}
|
2013-06-29 00:05:50 -05:00
|
|
|
let args = class_fields.iter().transform(|class_field| {
|
2013-06-17 18:43:22 -05:00
|
|
|
match flds.iter().find_(|f|
|
2013-01-24 22:10:05 -06:00
|
|
|
f.ident == class_field.ident) {
|
|
|
|
Some(f) => f.pat,
|
|
|
|
_ => wild()
|
|
|
|
}
|
2013-06-29 00:05:50 -05:00
|
|
|
}).collect();
|
2013-07-12 02:53:03 -05:00
|
|
|
Some(vec::append(args, r.tail()))
|
2012-10-24 20:47:59 -05:00
|
|
|
}
|
|
|
|
}
|
2013-01-24 22:10:05 -06:00
|
|
|
}
|
2013-03-03 09:22:40 -06:00
|
|
|
pat_tup(args) => Some(vec::append(args, r.tail())),
|
|
|
|
pat_box(a) | pat_uniq(a) | pat_region(a) => {
|
|
|
|
Some(vec::append(~[a], r.tail()))
|
|
|
|
}
|
2013-01-24 22:10:05 -06:00
|
|
|
pat_lit(expr) => {
|
|
|
|
let e_v = eval_const_expr(cx.tcx, expr);
|
2013-04-17 11:15:37 -05:00
|
|
|
let match_ = match *ctor_id {
|
2013-05-21 04:04:55 -05:00
|
|
|
val(ref v) => {
|
|
|
|
match compare_const_vals(&e_v, v) {
|
|
|
|
Some(val1) => val1 == 0,
|
|
|
|
None => {
|
|
|
|
cx.tcx.sess.span_err(pat_span,
|
|
|
|
"mismatched types between arms");
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2013-01-24 22:10:05 -06:00
|
|
|
range(ref c_lo, ref c_hi) => {
|
2013-06-04 23:43:41 -05:00
|
|
|
let m1 = compare_const_vals(c_lo, &e_v);
|
|
|
|
let m2 = compare_const_vals(c_hi, &e_v);
|
2013-05-21 04:04:55 -05:00
|
|
|
match (m1, m2) {
|
|
|
|
(Some(val1), Some(val2)) => (val1 >= 0 && val2 <= 0),
|
|
|
|
_ => {
|
|
|
|
cx.tcx.sess.span_err(pat_span,
|
|
|
|
"mismatched types between ranges");
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
2012-10-24 20:47:59 -05:00
|
|
|
}
|
2013-01-24 22:10:05 -06:00
|
|
|
single => true,
|
2013-05-05 17:18:51 -05:00
|
|
|
_ => fail!("type error")
|
2013-01-24 22:10:05 -06:00
|
|
|
};
|
2013-07-12 02:53:03 -05:00
|
|
|
if match_ { Some(r.tail().to_owned()) } else { None }
|
2012-08-06 19:01:14 -05:00
|
|
|
}
|
2013-01-24 22:10:05 -06:00
|
|
|
pat_range(lo, hi) => {
|
2013-04-17 11:15:37 -05:00
|
|
|
let (c_lo, c_hi) = match *ctor_id {
|
2013-06-27 19:41:35 -05:00
|
|
|
val(ref v) => (*v, *v),
|
|
|
|
range(ref lo, ref hi) => (*lo, *hi),
|
2013-07-12 02:53:03 -05:00
|
|
|
single => return Some(r.tail().to_owned()),
|
2013-05-05 17:18:51 -05:00
|
|
|
_ => fail!("type error")
|
2013-01-24 22:10:05 -06:00
|
|
|
};
|
2013-06-04 23:43:41 -05:00
|
|
|
let v_lo = eval_const_expr(cx.tcx, lo);
|
|
|
|
let v_hi = eval_const_expr(cx.tcx, hi);
|
2013-05-21 04:04:55 -05:00
|
|
|
|
2013-06-04 23:43:41 -05:00
|
|
|
let m1 = compare_const_vals(&c_lo, &v_lo);
|
|
|
|
let m2 = compare_const_vals(&c_hi, &v_hi);
|
2013-05-21 04:04:55 -05:00
|
|
|
match (m1, m2) {
|
|
|
|
(Some(val1), Some(val2)) if val1 >= 0 && val2 <= 0 => {
|
2013-07-12 02:53:03 -05:00
|
|
|
Some(r.tail().to_owned())
|
2013-05-21 04:04:55 -05:00
|
|
|
},
|
|
|
|
(Some(_), Some(_)) => None,
|
|
|
|
_ => {
|
|
|
|
cx.tcx.sess.span_err(pat_span,
|
|
|
|
"mismatched types between ranges");
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-02-26 12:58:46 -06:00
|
|
|
pat_vec(before, slice, after) => {
|
2013-04-17 11:15:37 -05:00
|
|
|
match *ctor_id {
|
2013-01-24 22:10:05 -06:00
|
|
|
vec(_) => {
|
2013-02-26 12:58:46 -06:00
|
|
|
let num_elements = before.len() + after.len();
|
|
|
|
if num_elements < arity && slice.is_some() {
|
2013-01-24 22:10:05 -06:00
|
|
|
Some(vec::append(
|
2013-02-26 12:58:46 -06:00
|
|
|
vec::concat(&[
|
|
|
|
before,
|
|
|
|
vec::from_elem(
|
|
|
|
arity - num_elements, wild()),
|
|
|
|
after
|
|
|
|
]),
|
|
|
|
r.tail()
|
2013-01-24 22:10:05 -06:00
|
|
|
))
|
|
|
|
} else if num_elements == arity {
|
2013-02-26 12:58:46 -06:00
|
|
|
Some(vec::append(
|
|
|
|
vec::append(before, after),
|
|
|
|
r.tail()
|
|
|
|
))
|
2013-01-24 22:10:05 -06:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => None
|
|
|
|
}
|
2012-12-08 14:22:43 -06:00
|
|
|
}
|
|
|
|
}
|
2011-07-25 06:45:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn default(cx: &MatchCheckCtxt, r: &[@pat]) -> Option<~[@pat]> {
|
2013-07-12 02:53:03 -05:00
|
|
|
if is_wild(cx, r[0]) { Some(r.tail().to_owned()) }
|
2012-08-20 14:23:37 -05:00
|
|
|
else { None }
|
2012-04-24 04:13:25 -05:00
|
|
|
}
|
|
|
|
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn check_local(cx: &MatchCheckCtxt,
|
2013-01-30 15:44:24 -06:00
|
|
|
loc: @local,
|
2013-06-11 21:55:16 -05:00
|
|
|
(s, v): ((),
|
|
|
|
visit::vt<()>)) {
|
|
|
|
visit::visit_local(loc, (s, v));
|
2012-12-05 20:27:04 -06:00
|
|
|
if is_refutable(cx, loc.node.pat) {
|
|
|
|
cx.tcx.sess.span_err(loc.node.pat.span,
|
2013-04-30 11:47:52 -05:00
|
|
|
"refutable pattern in local binding");
|
2011-08-01 08:26:48 -05:00
|
|
|
}
|
2012-12-05 21:01:14 -06:00
|
|
|
|
|
|
|
// Check legality of move bindings.
|
2013-06-20 14:25:52 -05:00
|
|
|
check_legality_of_move_bindings(cx, false, [ loc.node.pat ]);
|
2011-08-01 08:26:48 -05:00
|
|
|
}
|
|
|
|
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn check_fn(cx: &MatchCheckCtxt,
|
2013-02-18 23:25:44 -06:00
|
|
|
kind: &visit::fn_kind,
|
2013-02-18 00:20:36 -06:00
|
|
|
decl: &fn_decl,
|
|
|
|
body: &blk,
|
2013-01-30 15:44:24 -06:00
|
|
|
sp: span,
|
|
|
|
id: node_id,
|
2013-06-11 21:55:16 -05:00
|
|
|
(s, v): ((),
|
|
|
|
visit::vt<()>)) {
|
|
|
|
visit::visit_fn(kind, decl, body, sp, id, (s, v));
|
2013-06-21 07:29:53 -05:00
|
|
|
for decl.inputs.iter().advance |input| {
|
2012-12-05 20:27:04 -06:00
|
|
|
if is_refutable(cx, input.pat) {
|
|
|
|
cx.tcx.sess.span_err(input.pat.span,
|
2013-04-30 11:47:52 -05:00
|
|
|
"refutable pattern in function argument");
|
2012-11-06 20:41:06 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn is_refutable(cx: &MatchCheckCtxt, pat: &pat) -> bool {
|
2013-02-05 21:41:45 -06:00
|
|
|
match cx.tcx.def_map.find(&pat.id) {
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&def_variant(enum_id, _)) => {
|
2013-06-08 20:38:47 -05:00
|
|
|
if ty::enum_variants(cx.tcx, enum_id).len() != 1u {
|
2012-08-06 19:01:14 -05:00
|
|
|
return true;
|
|
|
|
}
|
2012-02-22 09:57:23 -06:00
|
|
|
}
|
2013-06-21 20:46:34 -05:00
|
|
|
Some(&def_static(*)) => return true,
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => ()
|
2012-02-22 09:57:23 -06:00
|
|
|
}
|
|
|
|
|
2013-03-20 00:17:42 -05:00
|
|
|
match pat.node {
|
2012-09-07 19:07:32 -05:00
|
|
|
pat_box(sub) | pat_uniq(sub) | pat_region(sub) |
|
|
|
|
pat_ident(_, _, Some(sub)) => {
|
2012-12-05 20:27:04 -06:00
|
|
|
is_refutable(cx, sub)
|
2011-12-08 04:56:16 -06:00
|
|
|
}
|
2012-08-20 14:23:37 -05:00
|
|
|
pat_wild | pat_ident(_, _, None) => { false }
|
2013-01-15 15:51:43 -06:00
|
|
|
pat_lit(@expr {node: expr_lit(@spanned { node: lit_nil, _}), _}) => {
|
2012-12-27 13:36:00 -06:00
|
|
|
// "()"
|
|
|
|
false
|
|
|
|
}
|
2012-07-31 21:25:24 -05:00
|
|
|
pat_lit(_) | pat_range(_, _) => { true }
|
2013-03-20 00:17:42 -05:00
|
|
|
pat_struct(_, ref fields, _) => {
|
2013-07-04 21:13:26 -05:00
|
|
|
fields.iter().any(|f| is_refutable(cx, f.pat))
|
2012-08-06 19:01:14 -05:00
|
|
|
}
|
2013-03-20 00:17:42 -05:00
|
|
|
pat_tup(ref elts) => {
|
2013-07-04 21:13:26 -05:00
|
|
|
elts.iter().any(|elt| is_refutable(cx, *elt))
|
2011-08-15 06:15:19 -05:00
|
|
|
}
|
2013-03-20 00:17:42 -05:00
|
|
|
pat_enum(_, Some(ref args)) => {
|
2013-07-04 21:13:26 -05:00
|
|
|
args.iter().any(|a| is_refutable(cx, *a))
|
2011-08-01 08:26:48 -05:00
|
|
|
}
|
2012-07-31 21:25:24 -05:00
|
|
|
pat_enum(_,_) => { false }
|
2012-12-08 14:22:43 -06:00
|
|
|
pat_vec(*) => { true }
|
2011-08-01 08:26:48 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-05 21:01:14 -06:00
|
|
|
// Legality of move bindings checking
|
|
|
|
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
|
2013-01-30 15:44:24 -06:00
|
|
|
has_guard: bool,
|
|
|
|
pats: &[@pat]) {
|
2012-12-05 21:01:14 -06:00
|
|
|
let tcx = cx.tcx;
|
|
|
|
let def_map = tcx.def_map;
|
|
|
|
let mut by_ref_span = None;
|
|
|
|
let mut any_by_move = false;
|
2013-06-21 07:29:53 -05:00
|
|
|
for pats.iter().advance |pat| {
|
2012-12-07 21:34:57 -06:00
|
|
|
do pat_bindings(def_map, *pat) |bm, id, span, _path| {
|
2012-12-05 21:01:14 -06:00
|
|
|
match bm {
|
2012-12-07 21:34:57 -06:00
|
|
|
bind_by_ref(_) => {
|
2012-12-05 21:01:14 -06:00
|
|
|
by_ref_span = Some(span);
|
|
|
|
}
|
2012-12-07 21:34:57 -06:00
|
|
|
bind_infer => {
|
2013-03-22 21:26:41 -05:00
|
|
|
if cx.moves_map.contains(&id) {
|
2013-01-10 12:59:58 -06:00
|
|
|
any_by_move = true;
|
2012-12-07 21:34:57 -06:00
|
|
|
}
|
|
|
|
}
|
2012-12-05 21:01:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-14 19:50:48 -06:00
|
|
|
let check_move: &fn(@pat, Option<@pat>) = |p, sub| {
|
|
|
|
// check legality of moving out of the enum
|
|
|
|
if sub.is_some() {
|
|
|
|
tcx.sess.span_err(
|
|
|
|
p.span,
|
2013-04-30 11:47:52 -05:00
|
|
|
"cannot bind by-move with sub-bindings");
|
2012-12-14 19:50:48 -06:00
|
|
|
} else if has_guard {
|
|
|
|
tcx.sess.span_err(
|
|
|
|
p.span,
|
2013-04-30 11:47:52 -05:00
|
|
|
"cannot bind by-move into a pattern guard");
|
2012-12-14 19:50:48 -06:00
|
|
|
} else if by_ref_span.is_some() {
|
|
|
|
tcx.sess.span_err(
|
|
|
|
p.span,
|
2013-04-30 11:47:52 -05:00
|
|
|
"cannot bind by-move and by-ref \
|
|
|
|
in the same pattern");
|
2012-12-14 19:50:48 -06:00
|
|
|
tcx.sess.span_note(
|
|
|
|
by_ref_span.get(),
|
2013-04-30 11:47:52 -05:00
|
|
|
"by-ref binding occurs here");
|
2012-12-14 19:50:48 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-12-05 21:01:14 -06:00
|
|
|
if !any_by_move { return; } // pointless micro-optimization
|
2013-06-21 07:29:53 -05:00
|
|
|
for pats.iter().advance |pat| {
|
2013-05-22 05:54:35 -05:00
|
|
|
for walk_pat(*pat) |p| {
|
2012-12-05 21:01:14 -06:00
|
|
|
if pat_is_binding(def_map, p) {
|
|
|
|
match p.node {
|
2013-01-10 12:59:58 -06:00
|
|
|
pat_ident(_, _, sub) => {
|
2013-03-22 21:26:41 -05:00
|
|
|
if cx.moves_map.contains(&p.id) {
|
2013-01-10 12:59:58 -06:00
|
|
|
check_move(p, sub);
|
2012-12-05 21:01:14 -06:00
|
|
|
}
|
|
|
|
}
|
2013-01-10 12:59:58 -06:00
|
|
|
_ => {
|
|
|
|
cx.tcx.sess.span_bug(
|
|
|
|
p.span,
|
|
|
|
fmt!("Binding pattern %d is \
|
|
|
|
not an identifier: %?",
|
|
|
|
p.id, p.node));
|
|
|
|
}
|
2012-12-05 21:01:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|