Skip to content

librustc: Implement moves based on type #4109

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/libcore/option.rs
Original file line number Diff line number Diff line change
@@ -140,8 +140,8 @@ pub pure fn or<T>(opta: Option<T>, optb: Option<T>) -> Option<T> {
/*!
* Returns the leftmost some() value, or none if both are none.
*/
match opta {
Some(_) => move opta,
match move opta {
Some(move opta) => Some(move opta),
_ => move optb
}
}
6 changes: 3 additions & 3 deletions src/libcore/pipes.rs
Original file line number Diff line number Diff line change
@@ -1019,9 +1019,9 @@ impl<T: Send> Port<T>: Recv<T> {
pure fn peek() -> bool unsafe {
let mut endp = None;
endp <-> self.endp;
let peek = match endp {
Some(ref endp) => pipes::peek(endp),
None => fail ~"peeking empty stream"
let peek = match &endp {
&Some(ref endp) => pipes::peek(endp),
&None => fail ~"peeking empty stream"
};
self.endp <-> endp;
peek
3 changes: 3 additions & 0 deletions src/librustc/driver/driver.rs
Original file line number Diff line number Diff line change
@@ -241,6 +241,9 @@ fn compile_upto(sess: Session, cfg: ast::crate_cfg,
time(time_passes, ~"alt checking", ||
middle::check_alt::check_crate(ty_cx, crate));

time(time_passes, ~"mode computation", ||
middle::mode::compute_modes(ty_cx, method_map, crate));

let last_use_map =
time(time_passes, ~"liveness checking", ||
middle::liveness::check_crate(ty_cx, method_map, crate));
3 changes: 2 additions & 1 deletion src/librustc/metadata/common.rs
Original file line number Diff line number Diff line change
@@ -121,7 +121,8 @@ enum astencode_tag { // Reserves 0x50 -- 0x6f
tag_table_method_map = 0x60,
tag_table_vtable_map = 0x61,
tag_table_adjustments = 0x62,
tag_table_legacy_boxed_trait = 0x63
tag_table_legacy_boxed_trait = 0x63,
tag_table_value_mode = 0x64
}

const tag_item_trait_method_sort: uint = 0x70;
6 changes: 3 additions & 3 deletions src/librustc/metadata/tyencode.rs
Original file line number Diff line number Diff line change
@@ -108,9 +108,9 @@ fn enc_mt(w: io::Writer, cx: @ctxt, mt: ty::mt) {
}

fn enc_opt<T>(w: io::Writer, t: Option<T>, enc_f: fn(T)) {
match t {
None => w.write_char('n'),
Some(v) => {
match &t {
&None => w.write_char('n'),
&Some(v) => {
w.write_char('s');
enc_f(v);
}
12 changes: 12 additions & 0 deletions src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
@@ -846,6 +846,15 @@ fn encode_side_tables_for_id(ecx: @e::encode_ctxt,
ebml_w.id(id);
}
}

do option::iter(&tcx.value_modes.find(id)) |vm| {
do ebml_w.tag(c::tag_table_value_mode) {
ebml_w.id(id);
do ebml_w.tag(c::tag_table_val) {
(*vm).serialize(&ebml_w)
}
}
}
}

trait doc_decoder_helpers {
@@ -980,6 +989,9 @@ fn decode_side_tables(xcx: extended_decode_ctxt,
let adj: @ty::AutoAdjustment = @deserialize(val_dsr);
adj.tr(xcx);
dcx.tcx.adjustments.insert(id, adj);
} else if tag == (c::tag_table_value_mode as uint) {
let vm: ty::ValueMode = deserialize(val_dsr);
dcx.tcx.value_modes.insert(id, vm);
} else {
xcx.dcx.tcx.sess.bug(
fmt!("unknown tag found in side tables: %x", tag));
13 changes: 11 additions & 2 deletions src/librustc/middle/kind.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ use syntax::{visit, ast_util};
use syntax::ast::*;
use syntax::codemap::span;
use middle::ty::{Kind, kind_copyable, kind_noncopyable, kind_const};
use middle::ty::{CopyValue, MoveValue, ReadValue};
use std::map::HashMap;
use util::ppaux::{ty_to_str, tys_to_str};
use syntax::print::pprust::expr_to_str;
@@ -470,8 +471,16 @@ fn check_copy_ex(cx: ctx, ex: @expr, implicit_copy: bool,
// borrowed unique value isn't really a copy
!is_autorefd(cx, ex)
{
let ty = ty::expr_ty(cx.tcx, ex);
check_copy(cx, ex.id, ty, ex.span, implicit_copy, why);
match cx.tcx.value_modes.find(ex.id) {
None => cx.tcx.sess.span_bug(ex.span, ~"no value mode for lval"),
Some(MoveValue) | Some(ReadValue) => {} // Won't be a copy.
Some(CopyValue) => {
debug!("(kind checking) is a copy value: `%s`",
expr_to_str(ex, cx.tcx.sess.intr()));
let ty = ty::expr_ty(cx.tcx, ex);
check_copy(cx, ex.id, ty, ex.span, implicit_copy, why);
}
}
}

fn is_autorefd(cx: ctx, ex: @expr) -> bool {
17 changes: 17 additions & 0 deletions src/librustc/middle/liveness.rs
Original file line number Diff line number Diff line change
@@ -101,6 +101,7 @@ use syntax::codemap::span;
use syntax::ast::*;
use io::WriterUtil;
use capture::{cap_move, cap_drop, cap_copy, cap_ref};
use middle::ty::MoveValue;

export check_crate;
export last_use_map;
@@ -1523,6 +1524,22 @@ fn check_expr(expr: @expr, &&self: @Liveness, vt: vt<@Liveness>) {
for self.variable_from_def_map(expr.id, expr.span).each |var| {
let ln = self.live_node(expr.id, expr.span);
self.consider_last_use(expr, ln, *var);

match self.tcx.value_modes.find(expr.id) {
Some(MoveValue) => {
debug!("(checking expr) is a move: `%s`",
expr_to_str(expr, self.tcx.sess.intr()));
self.check_move_from_var(expr.span, ln, *var);
}
Some(v) => {
debug!("(checking expr) not a move (%?): `%s`",
v,
expr_to_str(expr, self.tcx.sess.intr()));
}
None => {
fail ~"no mode for lval";
}
}
}

visit::visit_expr(expr, self, vt);
181 changes: 181 additions & 0 deletions src/librustc/middle/mode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
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::{by_copy, by_move, by_ref, by_val, crate, expr, expr_assign};
use syntax::ast::{expr_addr_of, expr_assign_op, expr_binary, expr_call};
use syntax::ast::{expr_copy, expr_field, expr_index, expr_method_call};
use syntax::ast::{expr_path, expr_swap, expr_unary, node_id, sty_uniq};
use syntax::ast::{sty_value};
use syntax::ast::{box, uniq, deref, not, neg, expr_paren};
use syntax::visit;
use syntax::visit::vt;

struct VisitContext {
tcx: ctxt,
method_map: HashMap<node_id,method_map_entry>,
mode: ValueMode,
}

fn compute_modes_for_fn_args(callee_id: node_id,
args: &[@expr],
&&cx: VisitContext,
v: vt<VisitContext>) {
let arg_tys = ty::ty_fn_args(ty::node_id_to_type(cx.tcx, callee_id));
for vec::each2(args, arg_tys) |arg, arg_ty| {
match ty::resolved_mode(cx.tcx, arg_ty.mode) {
by_ref => {
let arg_cx = VisitContext { mode: ReadValue, ..cx };
compute_modes_for_expr(*arg, arg_cx, v);
}
by_val | by_move | by_copy => compute_modes_for_expr(*arg, cx, v)
}
}
}

fn record_mode_for_expr(expr: @expr, &&cx: VisitContext) {
match cx.mode {
ReadValue | CopyValue => {
cx.tcx.value_modes.insert(expr.id, cx.mode);
}
MoveValue => {
// This is, contextually, a move, but if this expression
// is implicitly copyable it's cheaper to copy.
let e_ty = ty::expr_ty(cx.tcx, expr);
if ty::type_implicitly_moves(cx.tcx, e_ty) {
cx.tcx.value_modes.insert(expr.id, MoveValue);
} else {
cx.tcx.value_modes.insert(expr.id, CopyValue);
}
}
}
}

fn compute_modes_for_expr(expr: @expr,
&&cx: VisitContext,
v: vt<VisitContext>) {
// Adjust the mode if there was an implicit reference here.
let cx = match cx.tcx.adjustments.find(expr.id) {
None => cx,
Some(adjustment) => {
if adjustment.autoref.is_some() {
VisitContext { mode: ReadValue, ..cx }
} else {
cx
}
}
};

match expr.node {
expr_call(callee, args, _) => {
let callee_cx = VisitContext { mode: ReadValue, ..cx };
compute_modes_for_expr(callee, callee_cx, v);
compute_modes_for_fn_args(callee.id, args, cx, v);
}
expr_path(*) => {
record_mode_for_expr(expr, cx);
}
expr_copy(expr) => {
let callee_cx = VisitContext { mode: CopyValue, ..cx };
compute_modes_for_expr(expr, callee_cx, v);
}
expr_method_call(callee, _, _, args, _) => {
// The LHS of the dot may or may not result in a move, depending
// on the method map entry.
let callee_mode;
match cx.method_map.find(expr.id) {
Some(method_map_entry) => {
match method_map_entry.explicit_self {
sty_uniq(_) | sty_value => callee_mode = MoveValue,
_ => callee_mode = ReadValue
}
}
None => {
cx.tcx.sess.span_bug(expr.span, ~"no method map entry");
}
}

let callee_cx = VisitContext { mode: callee_mode, ..cx };
compute_modes_for_expr(callee, callee_cx, v);

compute_modes_for_fn_args(expr.callee_id, args, cx, v);
}
expr_binary(_, lhs, rhs) | expr_assign_op(_, lhs, rhs) => {
// The signatures of these take their arguments by-ref, so they
// don't copy or move.
let arg_cx = VisitContext { mode: ReadValue, ..cx };
compute_modes_for_expr(lhs, arg_cx, v);
compute_modes_for_expr(rhs, arg_cx, v);
}
expr_addr_of(_, arg) => {
// Takes its argument by-ref, so it doesn't copy or move.
let arg_cx = VisitContext { mode: ReadValue, ..cx };
compute_modes_for_expr(arg, arg_cx, v);
}
expr_unary(unop, arg) => {
// Ditto.
let arg_cx = VisitContext { mode: ReadValue, ..cx };
compute_modes_for_expr(arg, arg_cx, v);

match unop {
deref => {
// This is an lvalue, so it needs a value mode recorded
// for it.
record_mode_for_expr(expr, cx);
}
box(_) | uniq(_) | not | neg => {}
}
}
expr_field(arg, _, _) => {
let arg_cx = VisitContext { mode: ReadValue, ..cx };
compute_modes_for_expr(arg, arg_cx, v);

record_mode_for_expr(expr, cx);
}
expr_assign(lhs, rhs) => {
// The signatures of these take their arguments by-ref, so they
// don't copy or move.
let arg_cx = VisitContext { mode: ReadValue, ..cx };
compute_modes_for_expr(lhs, arg_cx, v);
compute_modes_for_expr(rhs, cx, v);
}
expr_swap(lhs, rhs) => {
let arg_cx = VisitContext { mode: ReadValue, ..cx };
compute_modes_for_expr(lhs, arg_cx, v);
compute_modes_for_expr(rhs, arg_cx, v);
}
expr_index(lhs, rhs) => {
let lhs_cx = VisitContext { mode: ReadValue, ..cx };
compute_modes_for_expr(lhs, lhs_cx, v);
let rhs_cx = VisitContext { mode: MoveValue, ..cx };
compute_modes_for_expr(rhs, rhs_cx, v);

record_mode_for_expr(expr, cx);
}
expr_paren(arg) => {
compute_modes_for_expr(arg, cx, v);
record_mode_for_expr(expr, cx);
}
_ => {
// XXX: Spell out every expression above so when we add them we
// don't forget to update this file.
visit::visit_expr(expr, 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::default_visitor()
});
let callee_cx = VisitContext {
tcx: tcx,
method_map: method_map,
mode: MoveValue
};
visit::visit_crate(*crate, callee_cx, visitor);
}

2 changes: 1 addition & 1 deletion src/librustc/middle/trans/closure.rs
Original file line number Diff line number Diff line change
@@ -260,7 +260,7 @@ fn build_closure(bcx0: block,
let mut env_vals = ~[];
for vec::each(cap_vars) |cap_var| {
debug!("Building closure: captured variable %?", *cap_var);
let datum = expr::trans_local_var(bcx, cap_var.def);
let datum = expr::trans_local_var(bcx, cap_var.def, None);
match cap_var.mode {
capture::cap_ref => {
assert proto == ast::ProtoBorrowed;
8 changes: 6 additions & 2 deletions src/librustc/middle/trans/datum.rs
Original file line number Diff line number Diff line change
@@ -499,13 +499,17 @@ impl Datum {
}
}

fn GEPi(bcx: block, ixs: &[uint], ty: ty::t) -> Datum {
fn GEPi(bcx: block,
ixs: &[uint],
ty: ty::t,
source: DatumSource)
-> Datum {
let base_val = self.to_ref_llval(bcx);
Datum {
val: GEPi(bcx, base_val, ixs),
mode: ByRef,
ty: ty,
source: FromLvalue
source: source
}
}

Loading