librustc: De-mode pattern bindings. r=nmatsakis

This commit is contained in:
Patrick Walton 2012-12-07 19:34:57 -08:00
parent 184f5102b3
commit 98fdcb0b9d
16 changed files with 99 additions and 108 deletions

View file

@ -248,12 +248,12 @@ fn compile_upto(sess: Session, cfg: ast::crate_cfg,
time(time_passes, ~"loop checking", || time(time_passes, ~"loop checking", ||
middle::check_loop::check_crate(ty_cx, crate)); middle::check_loop::check_crate(ty_cx, crate));
time(time_passes, ~"alt checking", ||
middle::check_alt::check_crate(ty_cx, method_map, crate));
time(time_passes, ~"mode computation", || time(time_passes, ~"mode computation", ||
middle::mode::compute_modes(ty_cx, method_map, crate)); middle::mode::compute_modes(ty_cx, method_map, crate));
time(time_passes, ~"alt checking", ||
middle::check_alt::check_crate(ty_cx, method_map, crate));
let last_use_map = let last_use_map =
time(time_passes, ~"liveness checking", || time(time_passes, ~"liveness checking", ||
middle::liveness::check_crate(ty_cx, method_map, crate)); middle::liveness::check_crate(ty_cx, method_map, crate));

View file

@ -529,20 +529,9 @@ impl gather_loan_ctxt {
self.guarantee_valid(cmt, mutbl, scope_r); self.guarantee_valid(cmt, mutbl, scope_r);
} }
} }
ast::bind_by_implicit_ref => { ast::bind_infer => {
// Note: there is a discussion of the function of // Nothing to do here; this is either a copy or a move;
// cat_discr in the method preserve(): // thus either way there is nothing to check. Yay!
let cmt1 = self.bccx.cat_discr(cmt, alt_id);
let arm_scope = ty::re_scope(arm_id);
// We used to remember the mutability of the location
// that this binding refers to and use it later when
// categorizing the binding. This hack is being
// removed in favor of ref mode bindings.
//
// self.bccx.binding_map.insert(pat.id, cmt1.mutbl);
self.guarantee_valid(cmt1, m_const, arm_scope);
} }
} }
} }

View file

@ -592,15 +592,25 @@ fn check_legality_of_move_bindings(cx: @AltCheckCtxt,
let mut by_ref_span = None; let mut by_ref_span = None;
let mut any_by_move = false; let mut any_by_move = false;
for pats.each |pat| { for pats.each |pat| {
do pat_bindings(def_map, *pat) |bm, _id, span, _path| { do pat_bindings(def_map, *pat) |bm, id, span, _path| {
match bm { match bm {
bind_by_ref(_) | bind_by_implicit_ref => { bind_by_ref(_) => {
by_ref_span = Some(span); by_ref_span = Some(span);
} }
bind_by_move => { bind_by_move => {
any_by_move = true; any_by_move = true;
} }
_ => { } bind_by_value => {}
bind_infer => {
match cx.tcx.value_modes.find(id) {
Some(MoveValue) => any_by_move = true,
Some(CopyValue) | Some(ReadValue) => {}
None => {
cx.tcx.sess.span_bug(span, ~"no mode for pat \
binding");
}
}
}
} }
} }
} }

View file

@ -767,27 +767,6 @@ fn check_item_non_camel_case_types(cx: ty::ctxt, it: @ast::item) {
} }
} }
fn check_pat(tcx: ty::ctxt, pat: @ast::pat) {
debug!("lint check_pat pat=%s", pat_to_str(pat, tcx.sess.intr()));
do pat_bindings(tcx.def_map, pat) |binding_mode, id, span, path| {
match binding_mode {
ast::bind_by_ref(_) | ast::bind_by_value | ast::bind_by_move => {}
ast::bind_by_implicit_ref => {
let pat_ty = ty::node_id_to_type(tcx, id);
let kind = ty::type_kind(tcx, pat_ty);
if !ty::kind_is_safe_for_default_mode(kind) {
tcx.sess.span_lint(
deprecated_pattern, id, id,
span,
fmt!("binding `%s` should use ref or copy mode",
tcx.sess.str_of(path_to_ident(path))));
}
}
}
}
}
fn check_fn(tcx: ty::ctxt, fk: visit::fn_kind, decl: ast::fn_decl, fn check_fn(tcx: ty::ctxt, fk: visit::fn_kind, decl: ast::fn_decl,
_body: ast::blk, span: span, id: ast::node_id) { _body: ast::blk, span: span, id: ast::node_id) {
debug!("lint check_fn fk=%? id=%?", fk, id); debug!("lint check_fn fk=%? id=%?", fk, id);
@ -904,8 +883,6 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
check_item(it, tcx), check_item(it, tcx),
visit_fn: |fk, decl, body, span, id| visit_fn: |fk, decl, body, span, id|
check_fn(tcx, fk, decl, body, span, id), check_fn(tcx, fk, decl, body, span, id),
visit_pat: |pat|
check_pat(tcx, pat),
.. *visit::default_simple_visitor() .. *visit::default_simple_visitor()
}); });
visit::visit_crate(*crate, (), v); visit::visit_crate(*crate, (), v);

View file

@ -390,9 +390,7 @@ impl IrMaps {
Arg(id, _, by_copy) | Arg(id, _, by_copy) |
Local(LocalInfo {id: id, kind: FromLetNoInitializer, _}) | Local(LocalInfo {id: id, kind: FromLetNoInitializer, _}) |
Local(LocalInfo {id: id, kind: FromLetWithInitializer, _}) | Local(LocalInfo {id: id, kind: FromLetWithInitializer, _}) |
Local(LocalInfo {id: id, kind: FromMatch(bind_by_value), _}) | Local(LocalInfo {id: id, kind: FromMatch(_), _}) => {
Local(LocalInfo {id: id, kind: FromMatch(bind_by_ref(_)), _}) |
Local(LocalInfo {id: id, kind: FromMatch(bind_by_move), _}) => {
let v = match self.last_use_map.find(expr_id) { let v = match self.last_use_map.find(expr_id) {
Some(v) => v, Some(v) => v,
None => { None => {
@ -405,8 +403,7 @@ impl IrMaps {
(*v).push(id); (*v).push(id);
} }
Arg(_, _, by_ref) | Arg(_, _, by_ref) |
Arg(_, _, by_val) | Self | ImplicitRet | Arg(_, _, by_val) | Self | ImplicitRet => {
Local(LocalInfo {kind: FromMatch(bind_by_implicit_ref), _}) => {
debug!("--but it is not owned"); debug!("--but it is not owned");
} }
} }

View file

@ -636,28 +636,12 @@ impl &mem_categorization_ctxt {
mutbl:m, ty:expr_ty} mutbl:m, ty:expr_ty}
} }
ast::def_binding(vid, ast::bind_by_value) | ast::def_binding(vid, _) => {
ast::def_binding(vid, ast::bind_by_move) |
ast::def_binding(vid, ast::bind_by_ref(_)) => {
// by-value/by-ref bindings are local variables // by-value/by-ref bindings are local variables
@{id:id, span:span, @{id:id, span:span,
cat:cat_local(vid), lp:Some(@lp_local(vid)), cat:cat_local(vid), lp:Some(@lp_local(vid)),
mutbl:m_imm, ty:expr_ty} mutbl:m_imm, ty:expr_ty}
} }
ast::def_binding(pid, ast::bind_by_implicit_ref) => {
// implicit-by-ref bindings are "special" since they are
// implicit pointers.
// Technically, the mutability is not always imm, but we
// (choose to be) unsound for the moment since these
// implicit refs are going away and it reduces external
// dependencies.
@{id:id, span:span,
cat:cat_binding(pid), lp:None,
mutbl:m_imm, ty:expr_ty}
}
} }
} }

View file

@ -1,14 +1,16 @@
use middle::pat_util;
use middle::ty; use middle::ty;
use middle::ty::{CopyValue, MoveValue, ReadValue, ValueMode, ctxt}; use middle::ty::{CopyValue, MoveValue, ReadValue, ValueMode, ctxt};
use middle::typeck::{method_map, method_map_entry}; use middle::typeck::{method_map, method_map_entry};
use core::vec; use core::vec;
use std::map::HashMap; use std::map::HashMap;
use syntax::ast::{box, by_copy, by_move, by_ref, by_val, crate, deref, expr}; use syntax::ast::{bind_infer, box, by_copy, by_move, by_ref, by_val, crate};
use syntax::ast::{expr_addr_of, expr_assign, expr_assign_op, expr_binary}; use syntax::ast::{deref, expr, expr_addr_of, expr_assign, expr_assign_op};
use syntax::ast::{expr_call, expr_copy, expr_field, expr_index, expr_match}; use syntax::ast::{expr_binary, expr_call, expr_copy, expr_field, expr_index};
use syntax::ast::{expr_method_call, expr_paren, expr_path, expr_swap}; use syntax::ast::{expr_match, expr_method_call, expr_paren, expr_path};
use syntax::ast::{expr_unary, neg, node_id, not, sty_uniq, sty_value, uniq}; use syntax::ast::{expr_swap, expr_unary, neg, node_id, not, pat, pat_ident};
use syntax::ast::{sty_uniq, sty_value, uniq};
use syntax::visit; use syntax::visit;
use syntax::visit::vt; use syntax::visit::vt;
@ -166,8 +168,14 @@ fn compute_modes_for_expr(expr: @expr,
record_mode_for_expr(expr, cx); record_mode_for_expr(expr, cx);
} }
expr_match(head, ref arms) => { expr_match(head, ref arms) => {
// We must do this first so that `arms_have_by_move_bindings`
// below knows which bindings are moves.
for arms.each |arm| {
(v.visit_arm)(*arm, cx, v);
}
let by_move_bindings_present = let by_move_bindings_present =
pat_util::arms_have_by_move_bindings(cx.tcx.def_map, *arms); pat_util::arms_have_by_move_bindings(cx.tcx, *arms);
if by_move_bindings_present { if by_move_bindings_present {
// Propagate the current mode flag downward. // Propagate the current mode flag downward.
visit::visit_expr(expr, cx, v); visit::visit_expr(expr, cx, v);
@ -175,9 +183,6 @@ fn compute_modes_for_expr(expr: @expr,
// We aren't moving into any pattern, so this is just a read. // We aren't moving into any pattern, so this is just a read.
let head_cx = VisitContext { mode: ReadValue, ..cx }; let head_cx = VisitContext { mode: ReadValue, ..cx };
compute_modes_for_expr(head, head_cx, v); compute_modes_for_expr(head, head_cx, v);
for arms.each |arm| {
(v.visit_arm)(*arm, cx, v);
}
} }
} }
_ => { _ => {
@ -188,9 +193,28 @@ fn compute_modes_for_expr(expr: @expr,
} }
} }
fn compute_modes_for_pat(pat: @pat,
&&cx: VisitContext,
v: vt<VisitContext>) {
match pat.node {
pat_ident(bind_infer, _, _)
if pat_util::pat_is_binding(cx.tcx.def_map, pat) => {
if ty::type_implicitly_moves(cx.tcx, ty::pat_ty(cx.tcx, pat)) {
cx.tcx.value_modes.insert(pat.id, MoveValue);
} else {
cx.tcx.value_modes.insert(pat.id, CopyValue);
}
}
_ => {}
}
visit::visit_pat(pat, cx, v);
}
pub fn compute_modes(tcx: ctxt, method_map: method_map, crate: @crate) { pub fn compute_modes(tcx: ctxt, method_map: method_map, crate: @crate) {
let visitor = visit::mk_vt(@{ let visitor = visit::mk_vt(@{
visit_expr: compute_modes_for_expr, visit_expr: compute_modes_for_expr,
visit_pat: compute_modes_for_pat,
.. *visit::default_visitor() .. *visit::default_visitor()
}); });
let callee_cx = VisitContext { let callee_cx = VisitContext {

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use middle::ty::{CopyValue, MoveValue, ReadValue};
use syntax::ast::*; use syntax::ast::*;
use syntax::ast_util; use syntax::ast_util;
use syntax::ast_util::{path_to_ident, respan, walk_pat}; use syntax::ast_util::{path_to_ident, respan, walk_pat};
@ -93,16 +95,25 @@ fn pat_binding_ids(dm: resolve::DefMap, pat: @pat) -> ~[node_id] {
return found; return found;
} }
fn arms_have_by_move_bindings(dm: resolve::DefMap, +arms: &[arm]) -> bool { fn arms_have_by_move_bindings(tcx: ty::ctxt, +arms: &[arm]) -> bool {
for arms.each |arm| { for arms.each |arm| {
for arm.pats.each |pat| { for arm.pats.each |pat| {
let mut found = false; let mut found = false;
do pat_bindings(dm, *pat) |binding_mode, _node_id, _span, _path| { do pat_bindings(tcx.def_map, *pat)
|binding_mode, node_id, span, _path| {
match binding_mode { match binding_mode {
bind_by_move => found = true, bind_by_move => found = true,
bind_by_implicit_ref | bind_infer => {
bind_by_ref(*) | match tcx.value_modes.find(node_id) {
bind_by_value => {} Some(MoveValue) => found = true,
Some(CopyValue) | Some(ReadValue) => {}
None => {
tcx.sess.span_bug(span, ~"pat binding not in \
value mode map");
}
}
}
bind_by_ref(*) | bind_by_value => {}
} }
} }
if found { return true; } if found { return true; }

View file

@ -17,7 +17,6 @@ use middle::lang_items::LanguageItems;
use middle::lint::{deny, allow, forbid, level, unused_imports, warn}; use middle::lint::{deny, allow, forbid, level, unused_imports, warn};
use middle::pat_util::{pat_bindings}; use middle::pat_util::{pat_bindings};
use syntax::ast::{_mod, add, arm}; use syntax::ast::{_mod, add, arm};
use syntax::ast::{bind_by_ref, bind_by_implicit_ref, bind_by_value};
use syntax::ast::{bitand, bitor, bitxor}; use syntax::ast::{bitand, bitor, bitxor};
use syntax::ast::{binding_mode, blk, capture_clause, class_ctor, class_dtor}; use syntax::ast::{binding_mode, blk, capture_clause, class_ctor, class_dtor};
use syntax::ast::{crate, crate_num, decl_item}; use syntax::ast::{crate, crate_num, decl_item};

View file

@ -154,6 +154,7 @@ use syntax::ast::def_id;
use syntax::codemap::span; use syntax::codemap::span;
use syntax::print::pprust::pat_to_str; use syntax::print::pprust::pat_to_str;
use middle::resolve::DefMap; use middle::resolve::DefMap;
use middle::ty::{CopyValue, MoveValue, ReadValue};
use back::abi; use back::abi;
use std::map::HashMap; use std::map::HashMap;
use dvec::DVec; use dvec::DVec;
@ -1394,7 +1395,7 @@ fn trans_alt_inner(scope_cx: block,
// Note that we use the names because each binding will have many ids // Note that we use the names because each binding will have many ids
// from the various alternatives. // from the various alternatives.
let bindings_map = std::map::HashMap(); let bindings_map = std::map::HashMap();
do pat_bindings(tcx.def_map, arm.pats[0]) |bm, p_id, _s, path| { do pat_bindings(tcx.def_map, arm.pats[0]) |bm, p_id, s, path| {
let ident = path_to_ident(path); let ident = path_to_ident(path);
let variable_ty = node_id_type(bcx, p_id); let variable_ty = node_id_type(bcx, p_id);
let llvariable_ty = type_of::type_of(bcx.ccx(), variable_ty); let llvariable_ty = type_of::type_of(bcx.ccx(), variable_ty);
@ -1408,9 +1409,18 @@ fn trans_alt_inner(scope_cx: block,
llmatch = alloca(bcx, T_ptr(llvariable_ty)); llmatch = alloca(bcx, T_ptr(llvariable_ty));
trmode = TrByValue(is_move, alloca(bcx, llvariable_ty)); trmode = TrByValue(is_move, alloca(bcx, llvariable_ty));
} }
ast::bind_by_implicit_ref => { ast::bind_infer => {
// in this case also, the type of the variable will be T,
// but we need to store a *T
let is_move = match tcx.value_modes.find(p_id) {
None => {
tcx.sess.span_bug(s, ~"no value mode");
}
Some(MoveValue) => true,
Some(CopyValue) | Some(ReadValue) => false
};
llmatch = alloca(bcx, T_ptr(llvariable_ty)); llmatch = alloca(bcx, T_ptr(llvariable_ty));
trmode = TrByImplicitRef; trmode = TrByValue(is_move, alloca(bcx, llvariable_ty));
} }
ast::bind_by_ref(_) => { ast::bind_by_ref(_) => {
llmatch = alloca(bcx, llvariable_ty); llmatch = alloca(bcx, llvariable_ty);

View file

@ -358,13 +358,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
demand::eqtype(fcx, pat.span, region_ty, typ); demand::eqtype(fcx, pat.span, region_ty, typ);
} }
// otherwise the type of x is the expected type T // otherwise the type of x is the expected type T
ast::bind_by_value => { ast::bind_by_value | ast::bind_by_move | ast::bind_infer => {
demand::eqtype(fcx, pat.span, expected, typ);
}
ast::bind_by_move => {
demand::eqtype(fcx, pat.span, expected, typ);
}
ast::bind_by_implicit_ref => {
demand::eqtype(fcx, pat.span, expected, typ); demand::eqtype(fcx, pat.span, expected, typ);
} }
} }

View file

@ -291,7 +291,7 @@ pub impl<
Number(v) => v.serialize(s), Number(v) => v.serialize(s),
String(ref v) => v.serialize(s), String(ref v) => v.serialize(s),
Boolean(v) => v.serialize(s), Boolean(v) => v.serialize(s),
List(v) => v.serialize(s), List(ref v) => v.serialize(s),
Object(ref v) => { Object(ref v) => {
do s.emit_rec || { do s.emit_rec || {
let mut idx = 0; let mut idx = 0;
@ -927,8 +927,8 @@ impl Json : Eq {
match *other { Boolean(b1) => b0 == b1, _ => false }, match *other { Boolean(b1) => b0 == b1, _ => false },
Null => Null =>
match *other { Null => true, _ => false }, match *other { Null => true, _ => false },
List(v0) => List(ref v0) =>
match *other { List(v1) => v0 == v1, _ => false }, match *other { List(ref v1) => v0 == v1, _ => false },
Object(ref d0) => { Object(ref d0) => {
match *other { match *other {
Object(ref d1) => { Object(ref d1) => {
@ -981,10 +981,10 @@ impl Json : Ord {
} }
} }
List(l0) => { List(ref l0) => {
match *other { match *other {
Number(_) | String(_) | Boolean(_) => false, Number(_) | String(_) | Boolean(_) => false,
List(l1) => l0 < l1, List(ref l1) => (*l0) < (*l1),
Object(_) | Null => true Object(_) | Null => true
} }
} }

View file

@ -309,7 +309,7 @@ enum binding_mode {
bind_by_value, bind_by_value,
bind_by_move, bind_by_move,
bind_by_ref(ast::mutability), bind_by_ref(ast::mutability),
bind_by_implicit_ref bind_infer
} }
impl binding_mode : to_bytes::IterBytes { impl binding_mode : to_bytes::IterBytes {
@ -322,7 +322,7 @@ impl binding_mode : to_bytes::IterBytes {
bind_by_ref(ref m) => bind_by_ref(ref m) =>
to_bytes::iter_bytes_2(&2u8, m, lsb0, f), to_bytes::iter_bytes_2(&2u8, m, lsb0, f),
bind_by_implicit_ref => bind_infer =>
3u8.iter_bytes(lsb0, f), 3u8.iter_bytes(lsb0, f),
} }
} }
@ -349,9 +349,9 @@ impl binding_mode : cmp::Eq {
_ => false _ => false
} }
} }
bind_by_implicit_ref => { bind_infer => {
match (*other) { match (*other) {
bind_by_implicit_ref => true, bind_infer => true,
_ => false _ => false
} }
} }

View file

@ -134,7 +134,7 @@ impl ext_ctxt: ext_ctxt_ast_builder {
@{node: {is_mutbl: false, @{node: {is_mutbl: false,
ty: self.ty_infer(), ty: self.ty_infer(),
pat: @{id: self.next_id(), pat: @{id: self.next_id(),
node: ast::pat_ident(ast::bind_by_implicit_ref, node: ast::pat_ident(ast::bind_infer,
path(~[ident], path(~[ident],
dummy_sp()), dummy_sp()),
None), None),

View file

@ -23,7 +23,7 @@ use obsolete::{
ObsoleteModeInFnType, ObsoleteMoveInit, ObsoleteBinaryMove, ObsoleteModeInFnType, ObsoleteMoveInit, ObsoleteBinaryMove,
}; };
use ast::{_mod, add, arg, arm, attribute, use ast::{_mod, add, arg, arm, attribute,
bind_by_ref, bind_by_implicit_ref, bind_by_value, bind_by_move, bind_by_ref, bind_infer, bind_by_value, bind_by_move,
bitand, bitor, bitxor, blk, blk_check_mode, box, by_copy, bitand, bitor, bitxor, blk, blk_check_mode, box, by_copy,
by_move, by_ref, by_val, capture_clause, by_move, by_ref, by_val, capture_clause,
capture_item, class_immutable, class_mutable, capture_item, class_immutable, class_mutable,
@ -1925,9 +1925,7 @@ impl Parser {
} else { } else {
subpat = @{ subpat = @{
id: self.get_id(), id: self.get_id(),
node: pat_ident(bind_by_implicit_ref, node: pat_ident(bind_infer, fieldpath, None),
fieldpath,
None),
span: self.last_span span: self.last_span
}; };
} }
@ -2054,9 +2052,7 @@ impl Parser {
} else if self.eat_keyword(~"move") { } else if self.eat_keyword(~"move") {
binding_mode = bind_by_move; binding_mode = bind_by_move;
} else if refutable { } else if refutable {
// XXX: Should be bind_by_value, but that's not binding_mode = bind_infer;
// backward compatible.
binding_mode = bind_by_implicit_ref;
} else { } else {
binding_mode = bind_by_value; binding_mode = bind_by_value;
} }

View file

@ -1573,7 +1573,7 @@ fn print_pat(s: ps, &&pat: @ast::pat, refutable: bool) {
ast::bind_by_value => { ast::bind_by_value => {
word_nbsp(s, ~"copy"); word_nbsp(s, ~"copy");
} }
ast::bind_by_implicit_ref => {} ast::bind_infer => {}
} }
} }
print_path(s, path, true); print_path(s, path, true);