librustc: De-mode pattern bindings. r=nmatsakis
This commit is contained in:
parent
184f5102b3
commit
98fdcb0b9d
16 changed files with 99 additions and 108 deletions
|
@ -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));
|
||||
|
|
|
@ -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!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue