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", ||
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", ||
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 =
time(time_passes, ~"liveness checking", ||
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);
}
}
ast::bind_by_implicit_ref => {
// Note: there is a discussion of the function of
// cat_discr in the method preserve():
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);
ast::bind_infer => {
// Nothing to do here; this is either a copy or a move;
// thus either way there is nothing to check. Yay!
}
}
}

View file

@ -592,15 +592,25 @@ fn check_legality_of_move_bindings(cx: @AltCheckCtxt,
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| {
do pat_bindings(def_map, *pat) |bm, id, span, _path| {
match bm {
bind_by_ref(_) | bind_by_implicit_ref => {
bind_by_ref(_) => {
by_ref_span = Some(span);
}
bind_by_move => {
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,
_body: ast::blk, span: span, id: ast::node_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),
visit_fn: |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::visit_crate(*crate, (), v);

View file

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

View file

@ -636,28 +636,12 @@ impl &mem_categorization_ctxt {
mutbl:m, ty:expr_ty}
}
ast::def_binding(vid, ast::bind_by_value) |
ast::def_binding(vid, ast::bind_by_move) |
ast::def_binding(vid, ast::bind_by_ref(_)) => {
ast::def_binding(vid, _) => {
// by-value/by-ref bindings are local variables
@{id:id, span:span,
cat:cat_local(vid), lp:Some(@lp_local(vid)),
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::{CopyValue, MoveValue, ReadValue, ValueMode, ctxt};
use middle::typeck::{method_map, method_map_entry};
use core::vec;
use std::map::HashMap;
use syntax::ast::{box, by_copy, by_move, by_ref, by_val, crate, deref, expr};
use syntax::ast::{expr_addr_of, expr_assign, expr_assign_op, expr_binary};
use syntax::ast::{expr_call, expr_copy, expr_field, expr_index, expr_match};
use syntax::ast::{expr_method_call, expr_paren, expr_path, expr_swap};
use syntax::ast::{expr_unary, neg, node_id, not, sty_uniq, sty_value, uniq};
use syntax::ast::{bind_infer, box, by_copy, by_move, by_ref, by_val, crate};
use syntax::ast::{deref, expr, expr_addr_of, expr_assign, expr_assign_op};
use syntax::ast::{expr_binary, expr_call, expr_copy, expr_field, expr_index};
use syntax::ast::{expr_match, expr_method_call, expr_paren, expr_path};
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::vt;
@ -166,8 +168,14 @@ fn compute_modes_for_expr(expr: @expr,
record_mode_for_expr(expr, cx);
}
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 =
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 {
// Propagate the current mode flag downward.
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.
let head_cx = VisitContext { mode: ReadValue, ..cx };
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) {
let visitor = visit::mk_vt(@{
visit_expr: compute_modes_for_expr,
visit_pat: compute_modes_for_pat,
.. *visit::default_visitor()
});
let callee_cx = VisitContext {

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use middle::ty::{CopyValue, MoveValue, ReadValue};
use syntax::ast::*;
use syntax::ast_util;
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;
}
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 arm.pats.each |pat| {
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 {
bind_by_move => found = true,
bind_by_implicit_ref |
bind_by_ref(*) |
bind_by_value => {}
bind_infer => {
match tcx.value_modes.find(node_id) {
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; }

View file

@ -17,7 +17,6 @@ use middle::lang_items::LanguageItems;
use middle::lint::{deny, allow, forbid, level, unused_imports, warn};
use middle::pat_util::{pat_bindings};
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::{binding_mode, blk, capture_clause, class_ctor, class_dtor};
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::print::pprust::pat_to_str;
use middle::resolve::DefMap;
use middle::ty::{CopyValue, MoveValue, ReadValue};
use back::abi;
use std::map::HashMap;
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
// from the various alternatives.
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 variable_ty = node_id_type(bcx, p_id);
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));
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));
trmode = TrByImplicitRef;
trmode = TrByValue(is_move, alloca(bcx, llvariable_ty));
}
ast::bind_by_ref(_) => {
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);
}
// otherwise the type of x is the expected type T
ast::bind_by_value => {
demand::eqtype(fcx, pat.span, expected, typ);
}
ast::bind_by_move => {
demand::eqtype(fcx, pat.span, expected, typ);
}
ast::bind_by_implicit_ref => {
ast::bind_by_value | ast::bind_by_move | ast::bind_infer => {
demand::eqtype(fcx, pat.span, expected, typ);
}
}

View file

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

View file

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

View file

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

View file

@ -23,7 +23,7 @@ use obsolete::{
ObsoleteModeInFnType, ObsoleteMoveInit, ObsoleteBinaryMove,
};
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,
by_move, by_ref, by_val, capture_clause,
capture_item, class_immutable, class_mutable,
@ -1925,9 +1925,7 @@ impl Parser {
} else {
subpat = @{
id: self.get_id(),
node: pat_ident(bind_by_implicit_ref,
fieldpath,
None),
node: pat_ident(bind_infer, fieldpath, None),
span: self.last_span
};
}
@ -2054,9 +2052,7 @@ impl Parser {
} else if self.eat_keyword(~"move") {
binding_mode = bind_by_move;
} else if refutable {
// XXX: Should be bind_by_value, but that's not
// backward compatible.
binding_mode = bind_by_implicit_ref;
binding_mode = bind_infer;
} else {
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 => {
word_nbsp(s, ~"copy");
}
ast::bind_by_implicit_ref => {}
ast::bind_infer => {}
}
}
print_path(s, path, true);