librustc: Move the "legality of move bindings" check from typechecking to alt checking. rs=refactoring
This commit is contained in:
parent
16506c0250
commit
e23ea24aed
src/librustc/middle
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use syntax::ast::*;
|
||||
use syntax::ast_util::{variant_def_ids, dummy_sp, unguarded_pat};
|
||||
use syntax::ast_util::{variant_def_ids, dummy_sp, unguarded_pat, walk_pat};
|
||||
use const_eval::{eval_const_expr, const_val, const_int, const_bool,
|
||||
compare_const_vals, lookup_const_by_id};
|
||||
use syntax::codemap::span;
|
||||
@ -43,6 +43,15 @@ fn check_expr(cx: @AltCheckCtxt, ex: @expr, &&s: (), v: visit::vt<()>) {
|
||||
visit::visit_expr(ex, s, v);
|
||||
match ex.node {
|
||||
expr_match(scrut, ref arms) => {
|
||||
// First, check legality of move bindings.
|
||||
let is_lvalue = ty::expr_is_lval(cx.tcx, cx.method_map, scrut);
|
||||
for arms.each |arm| {
|
||||
check_legality_of_move_bindings(cx,
|
||||
is_lvalue,
|
||||
arm.guard.is_some(),
|
||||
arm.pats);
|
||||
}
|
||||
|
||||
check_arms(cx, (*arms));
|
||||
/* Check for exhaustiveness */
|
||||
// Check for empty enum, because is_useful only works on inhabited
|
||||
@ -511,6 +520,13 @@ fn check_local(cx: @AltCheckCtxt, loc: @local, &&s: (), v: visit::vt<()>) {
|
||||
cx.tcx.sess.span_err(loc.node.pat.span,
|
||||
~"refutable pattern in local binding");
|
||||
}
|
||||
|
||||
// Check legality of move bindings.
|
||||
let is_lvalue = match loc.node.init {
|
||||
Some(init) => ty::expr_is_lval(cx.tcx, cx.method_map, init),
|
||||
None => true
|
||||
};
|
||||
check_legality_of_move_bindings(cx, is_lvalue, false, [ loc.node.pat ]);
|
||||
}
|
||||
|
||||
fn check_fn(cx: @AltCheckCtxt,
|
||||
@ -565,6 +581,67 @@ fn is_refutable(cx: @AltCheckCtxt, pat: &pat) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Legality of move bindings checking
|
||||
|
||||
fn check_legality_of_move_bindings(cx: @AltCheckCtxt,
|
||||
is_lvalue: bool,
|
||||
has_guard: bool,
|
||||
pats: &[@pat]) {
|
||||
let tcx = cx.tcx;
|
||||
let def_map = tcx.def_map;
|
||||
let mut by_ref_span = None;
|
||||
let mut any_by_move = false;
|
||||
for pats.each |pat| {
|
||||
do pat_bindings(def_map, *pat) |bm, _id, span, _path| {
|
||||
match bm {
|
||||
bind_by_ref(_) | bind_by_implicit_ref => {
|
||||
by_ref_span = Some(span);
|
||||
}
|
||||
bind_by_move => {
|
||||
any_by_move = true;
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !any_by_move { return; } // pointless micro-optimization
|
||||
for pats.each |pat| {
|
||||
do walk_pat(*pat) |p| {
|
||||
if pat_is_binding(def_map, p) {
|
||||
match p.node {
|
||||
pat_ident(bind_by_move, _, sub) => {
|
||||
// check legality of moving out of the enum
|
||||
if sub.is_some() {
|
||||
tcx.sess.span_err(
|
||||
p.span,
|
||||
~"cannot bind by-move with sub-bindings");
|
||||
} else if has_guard {
|
||||
tcx.sess.span_err(
|
||||
p.span,
|
||||
~"cannot bind by-move into a pattern guard");
|
||||
} else if by_ref_span.is_some() {
|
||||
tcx.sess.span_err(
|
||||
p.span,
|
||||
~"cannot bind by-move and by-ref \
|
||||
in the same pattern");
|
||||
tcx.sess.span_note(
|
||||
by_ref_span.get(),
|
||||
~"by-ref binding occurs here");
|
||||
} else if is_lvalue {
|
||||
tcx.sess.span_err(
|
||||
p.span,
|
||||
~"cannot bind by-move when \
|
||||
matching an lvalue");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
|
@ -21,7 +21,6 @@ fn check_alt(fcx: @fn_ctxt,
|
||||
|
||||
let pattern_ty = fcx.infcx().next_ty_var();
|
||||
bot = check_expr_with(fcx, discrim, pattern_ty);
|
||||
let is_lvalue = ty::expr_is_lval(tcx, fcx.ccx.method_map, discrim);
|
||||
|
||||
// Typecheck the patterns first, so that we get types for all the
|
||||
// bindings.
|
||||
@ -34,10 +33,6 @@ fn check_alt(fcx: @fn_ctxt,
|
||||
};
|
||||
|
||||
for arm.pats.each |p| { check_pat(pcx, *p, pattern_ty);}
|
||||
check_legality_of_move_bindings(fcx,
|
||||
is_lvalue,
|
||||
arm.guard.is_some(),
|
||||
arm.pats);
|
||||
}
|
||||
|
||||
// Now typecheck the blocks.
|
||||
@ -58,67 +53,6 @@ fn check_alt(fcx: @fn_ctxt,
|
||||
return bot;
|
||||
}
|
||||
|
||||
fn check_legality_of_move_bindings(fcx: @fn_ctxt,
|
||||
is_lvalue: bool,
|
||||
has_guard: bool,
|
||||
pats: &[@ast::pat])
|
||||
{
|
||||
let tcx = fcx.tcx();
|
||||
let def_map = tcx.def_map;
|
||||
let mut by_ref = None;
|
||||
let mut any_by_move = false;
|
||||
for pats.each |pat| {
|
||||
do pat_util::pat_bindings(def_map, *pat) |bm, _id, span, _path| {
|
||||
match bm {
|
||||
ast::bind_by_ref(_) | ast::bind_by_implicit_ref => {
|
||||
by_ref = Some(span);
|
||||
}
|
||||
ast::bind_by_move => {
|
||||
any_by_move = true;
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !any_by_move { return; } // pointless micro-optimization
|
||||
for pats.each |pat| {
|
||||
do walk_pat(*pat) |p| {
|
||||
if pat_is_binding(def_map, p) {
|
||||
match p.node {
|
||||
ast::pat_ident(ast::bind_by_move, _, sub) => {
|
||||
// check legality of moving out of the enum
|
||||
if sub.is_some() {
|
||||
tcx.sess.span_err(
|
||||
p.span,
|
||||
~"cannot bind by-move with sub-bindings");
|
||||
} else if has_guard {
|
||||
tcx.sess.span_err(
|
||||
p.span,
|
||||
~"cannot bind by-move into a pattern guard");
|
||||
} else if by_ref.is_some() {
|
||||
tcx.sess.span_err(
|
||||
p.span,
|
||||
~"cannot bind by-move and by-ref \
|
||||
in the same pattern");
|
||||
tcx.sess.span_note(
|
||||
by_ref.get(),
|
||||
~"by-ref binding occurs here");
|
||||
} else if is_lvalue {
|
||||
tcx.sess.span_err(
|
||||
p.span,
|
||||
~"cannot bind by-move when \
|
||||
matching an lvalue");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type pat_ctxt = {
|
||||
fcx: @fn_ctxt,
|
||||
map: PatIdMap,
|
||||
|
@ -2399,15 +2399,11 @@ fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool {
|
||||
let t = ty::mk_var(tcx, fcx.inh.locals.get(local.node.id));
|
||||
fcx.write_ty(local.node.id, t);
|
||||
|
||||
let is_lvalue;
|
||||
match local.node.init {
|
||||
Some(init) => {
|
||||
bot = check_decl_initializer(fcx, local.node.id, init);
|
||||
is_lvalue = ty::expr_is_lval(tcx, fcx.ccx.method_map, init);
|
||||
}
|
||||
_ => {
|
||||
is_lvalue = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let region =
|
||||
@ -2419,11 +2415,6 @@ fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool {
|
||||
block_region: region,
|
||||
};
|
||||
alt::check_pat(pcx, local.node.pat, t);
|
||||
let has_guard = false;
|
||||
alt::check_legality_of_move_bindings(fcx,
|
||||
is_lvalue,
|
||||
has_guard,
|
||||
[local.node.pat]);
|
||||
return bot;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user