提交 96dfed2b 编写于 作者: N Niko Matsakis

Pre-step towards issue #12624 and others: Introduce ExprUseVisitor, remove the

moves computation. ExprUseVisitor is a visitor that walks the AST for a
function and calls a delegate to inform it where borrows, copies, and moves
occur.

In this patch, I rewrite the gather_loans visitor to use ExprUseVisitor, but in
future patches, I think we could rewrite regionck, check_loans, and possibly
other passes to use it as well. This would refactor the repeated code between
those places that tries to determine where copies/moves/etc occur.
上级 77a975df
......@@ -23,7 +23,7 @@
use metadata::cstore::CStore;
use metadata::creader::Loader;
use metadata;
use middle::{trans, freevars, kind, ty, typeck, lint, astencode, reachable};
use middle::{trans, freevars, kind, ty, typeck, lint, reachable};
use middle;
use util::common::time;
use util::ppaux;
......@@ -35,7 +35,6 @@
use std::io;
use std::io::fs;
use std::io::MemReader;
use std::mem::drop;
use std::os;
use getopts::{optopt, optmulti, optflag, optflagopt};
use getopts;
......@@ -270,7 +269,6 @@ pub struct CrateAnalysis {
pub exported_items: middle::privacy::ExportedItems,
pub public_items: middle::privacy::PublicItems,
pub ty_cx: ty::ctxt,
pub maps: astencode::Maps,
pub reachable: NodeSet,
}
......@@ -346,21 +344,14 @@ pub fn phase_3_run_analysis_passes(sess: Session,
time(time_passes, "effect checking", (), |_|
middle::effect::check_crate(&ty_cx, krate));
let middle::moves::MoveMaps {moves_map, capture_map} =
time(time_passes, "compute moves", (), |_|
middle::moves::compute_moves(&ty_cx, krate));
time(time_passes, "match checking", (), |_|
middle::check_match::check_crate(&ty_cx, &moves_map, krate));
middle::check_match::check_crate(&ty_cx, krate));
time(time_passes, "liveness checking", (), |_|
middle::liveness::check_crate(&ty_cx, &capture_map, krate));
middle::liveness::check_crate(&ty_cx, krate));
time(time_passes, "borrow checking", (), |_|
middle::borrowck::check_crate(&ty_cx, &moves_map,
&capture_map, krate));
drop(moves_map);
middle::borrowck::check_crate(&ty_cx, krate));
time(time_passes, "kind checking", (), |_|
kind::check_crate(&ty_cx, krate));
......@@ -384,9 +375,6 @@ pub fn phase_3_run_analysis_passes(sess: Session,
ty_cx: ty_cx,
exported_items: exported_items,
public_items: public_items,
maps: astencode::Maps {
capture_map: RefCell::new(capture_map)
},
reachable: reachable_map
}
}
......
......@@ -86,13 +86,13 @@ pub mod middle {
pub mod astencode;
pub mod lang_items;
pub mod privacy;
pub mod moves;
pub mod entry;
pub mod effect;
pub mod reachable;
pub mod graph;
pub mod cfg;
pub mod dead;
pub mod expr_use_visitor;
}
pub mod front {
......
......@@ -24,8 +24,7 @@
RegionParameter};
use metadata::tyencode;
use middle::typeck::{MethodCall, MethodCallee, MethodOrigin};
use middle::{ty, typeck, moves};
use middle;
use middle::{ty, typeck};
use util::ppaux::ty_to_str;
use syntax::{ast, ast_map, ast_util, codemap, fold};
......@@ -36,7 +35,6 @@
use libc;
use std::cast;
use std::cell::RefCell;
use std::io::Seek;
use std::io::MemWriter;
use std::rc::Rc;
......@@ -52,15 +50,9 @@
#[cfg(test)] use syntax::parse;
#[cfg(test)] use syntax::print::pprust;
// Auxiliary maps of things to be encoded
pub struct Maps {
pub capture_map: RefCell<middle::moves::CaptureMap>,
}
struct DecodeContext<'a> {
cdata: &'a cstore::crate_metadata,
tcx: &'a ty::ctxt,
maps: &'a Maps
}
struct ExtendedDecodeContext<'a> {
......@@ -84,8 +76,7 @@ trait tr_intern {
pub fn encode_inlined_item(ecx: &e::EncodeContext,
ebml_w: &mut Encoder,
ii: e::InlinedItemRef,
maps: &Maps) {
ii: e::InlinedItemRef) {
let id = match ii {
e::IIItemRef(i) => i.id,
e::IIForeignRef(i) => i.id,
......@@ -101,7 +92,7 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext,
ebml_w.start_tag(c::tag_ast as uint);
id_range.encode(ebml_w);
encode_ast(ebml_w, ii);
encode_side_tables_for_ii(ecx, maps, ebml_w, &ii);
encode_side_tables_for_ii(ecx, ebml_w, &ii);
ebml_w.end_tag();
debug!("< Encoded inlined fn: {} ({})",
......@@ -111,14 +102,12 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext,
pub fn decode_inlined_item(cdata: &cstore::crate_metadata,
tcx: &ty::ctxt,
maps: &Maps,
path: Vec<ast_map::PathElem>,
par_doc: ebml::Doc)
-> Result<ast::InlinedItem, Vec<ast_map::PathElem>> {
let dcx = &DecodeContext {
cdata: cdata,
tcx: tcx,
maps: maps
};
match par_doc.opt_child(c::tag_ast) {
None => Err(path),
......@@ -551,32 +540,6 @@ fn tr(&self, xcx: &ExtendedDecodeContext) -> freevar_entry {
}
}
// ______________________________________________________________________
// Encoding and decoding of CaptureVar information
trait capture_var_helper {
fn read_capture_var(&mut self, xcx: &ExtendedDecodeContext)
-> moves::CaptureVar;
}
impl<'a> capture_var_helper for reader::Decoder<'a> {
fn read_capture_var(&mut self, xcx: &ExtendedDecodeContext)
-> moves::CaptureVar {
let cvar: moves::CaptureVar = Decodable::decode(self).unwrap();
cvar.tr(xcx)
}
}
impl tr for moves::CaptureVar {
fn tr(&self, xcx: &ExtendedDecodeContext) -> moves::CaptureVar {
moves::CaptureVar {
def: self.def.tr(xcx),
span: self.span.tr(xcx),
mode: self.mode
}
}
}
// ______________________________________________________________________
// Encoding and decoding of MethodCallee
......@@ -935,7 +898,6 @@ fn id(&mut self, id: ast::NodeId) {
struct SideTableEncodingIdVisitor<'a,'b> {
ecx_ptr: *libc::c_void,
new_ebml_w: &'a mut Encoder<'b>,
maps: &'a Maps,
}
impl<'a,'b> ast_util::IdVisitingOperation for
......@@ -953,12 +915,11 @@ fn visit_id(&self, id: ast::NodeId) {
let ecx: &e::EncodeContext = unsafe {
cast::transmute(self.ecx_ptr)
};
encode_side_tables_for_id(ecx, self.maps, &mut new_ebml_w, id)
encode_side_tables_for_id(ecx, &mut new_ebml_w, id)
}
}
fn encode_side_tables_for_ii(ecx: &e::EncodeContext,
maps: &Maps,
ebml_w: &mut Encoder,
ii: &ast::InlinedItem) {
ebml_w.start_tag(c::tag_table as uint);
......@@ -974,13 +935,11 @@ fn encode_side_tables_for_ii(ecx: &e::EncodeContext,
cast::transmute(ecx)
},
new_ebml_w: &mut new_ebml_w,
maps: maps,
});
ebml_w.end_tag();
}
fn encode_side_tables_for_id(ecx: &e::EncodeContext,
maps: &Maps,
ebml_w: &mut Encoder,
id: ast::NodeId) {
let tcx = ecx.tcx;
......@@ -1096,17 +1055,6 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
})
})
}
for &cap_vars in maps.capture_map.borrow().find(&id).iter() {
ebml_w.tag(c::tag_table_capture_map, |ebml_w| {
ebml_w.id(id);
ebml_w.tag(c::tag_table_val, |ebml_w| {
ebml_w.emit_from_vec(cap_vars.as_slice(), |ebml_w, cap_var| {
cap_var.encode(ebml_w)
});
})
})
}
}
trait doc_decoder_helpers {
......@@ -1405,15 +1353,6 @@ fn decode_side_tables(xcx: &ExtendedDecodeContext,
let adj: ty::AutoAdjustment = val_dsr.read_auto_adjustment(xcx);
dcx.tcx.adjustments.borrow_mut().insert(id, adj);
}
c::tag_table_capture_map => {
let cvars =
val_dsr.read_to_vec(
|val_dsr| Ok(val_dsr.read_capture_var(xcx)))
.unwrap()
.move_iter()
.collect();
dcx.maps.capture_map.borrow_mut().insert(id, Rc::new(cvars));
}
_ => {
xcx.dcx.tcx.sess.bug(
format!("unknown tag found in side tables: {:x}", tag));
......
......@@ -18,9 +18,10 @@
// 4. moves do not affect things loaned out in any way
use mc = middle::mem_categorization;
use middle::borrowck::*;
use middle::moves;
use euv = middle::expr_use_visitor;
use middle::freevars;
use mc = middle::mem_categorization;
use middle::ty;
use middle::typeck::MethodCall;
use syntax::ast;
......@@ -288,7 +289,7 @@ pub fn report_error_if_loan_conflicts_with_restriction(&self,
}
match new_loan.cause {
ClosureCapture(span) => {
euv::ClosureCapture(span) => {
self.bccx.span_note(
span,
format!("borrow occurs due to use of `{}` in closure",
......@@ -321,13 +322,17 @@ pub fn report_error_if_loan_conflicts_with_restriction(&self,
};
let borrow_summary = match old_loan.cause {
ClosureCapture(_) => {
euv::ClosureCapture(_) => {
format!("previous borrow of `{}` occurs here due to \
use in closure",
self.bccx.loan_path_to_str(&*old_loan.loan_path))
}
AddrOf | AutoRef | RefBinding | ClosureInvocation => {
euv::OverloadedOperator(..) |
euv::AddrOf(..) |
euv::AutoRef(..) |
euv::ClosureInvocation(..) |
euv::RefBinding(..) => {
format!("previous borrow of `{}` occurs here",
self.bccx.loan_path_to_str(&*old_loan.loan_path))
}
......@@ -711,29 +716,33 @@ fn check_move_out_from_id(&self, id: ast::NodeId, span: Span) {
fn check_captured_variables(&self,
closure_id: ast::NodeId,
span: Span) {
for cap_var in self.bccx.capture_map.get(&closure_id).iter() {
let var_id = ast_util::def_id_of_def(cap_var.def).node;
self.check_if_path_is_moved(closure_id, span,
MovedInCapture, &Rc::new(LpVar(var_id)));
match cap_var.mode {
moves::CapRef | moves::CapCopy => {}
moves::CapMove => {
check_by_move_capture(self, closure_id, cap_var, &LpVar(var_id));
let freevar_mode = freevars::get_capture_mode(self.tcx(), closure_id);
freevars::with_freevars(self.tcx(), closure_id, |freevars| {
for freevar in freevars.iter() {
let var_id = ast_util::def_id_of_def(freevar.def).node;
let var_path = Rc::new(LpVar(var_id));
self.check_if_path_is_moved(closure_id, span,
MovedInCapture, &var_path);
match freevar_mode {
freevars::CaptureByRef => { }
freevars::CaptureByValue => {
check_by_move_capture(self, closure_id, freevar, &*var_path);
}
}
}
}
});
return;
fn check_by_move_capture(this: &CheckLoanCtxt,
closure_id: ast::NodeId,
cap_var: &moves::CaptureVar,
freevar: &freevars::freevar_entry,
move_path: &LoanPath) {
let move_err = this.analyze_move_out_from(closure_id, move_path);
match move_err {
MoveOk => {}
MoveWhileBorrowed(loan_path, loan_span) => {
this.bccx.span_err(
cap_var.span,
freevar.span,
format!("cannot move `{}` into closure \
because it is borrowed",
this.bccx.loan_path_to_str(move_path)));
......
......@@ -17,7 +17,7 @@
use middle::borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector};
use middle::borrowck::gather_loans::move_error::MoveSpanAndPath;
use middle::borrowck::move_data::*;
use middle::moves;
use euv = middle::expr_use_visitor;
use middle::ty;
use syntax::ast;
use syntax::codemap::Span;
......@@ -44,10 +44,10 @@ pub fn gather_decl(bccx: &BorrowckCtxt,
pub fn gather_move_from_expr(bccx: &BorrowckCtxt,
move_data: &MoveData,
move_error_collector: &MoveErrorCollector,
move_expr: &ast::Expr,
move_expr_id: ast::NodeId,
cmt: mc::cmt) {
let move_info = GatherMoveInfo {
id: move_expr.id,
id: move_expr_id,
kind: MoveExpr,
cmt: cmt,
span_path_opt: None,
......@@ -76,29 +76,6 @@ pub fn gather_move_from_pat(bccx: &BorrowckCtxt,
gather_move(bccx, move_data, move_error_collector, move_info);
}
pub fn gather_captures(bccx: &BorrowckCtxt,
move_data: &MoveData,
move_error_collector: &MoveErrorCollector,
closure_expr: &ast::Expr) {
for captured_var in bccx.capture_map.get(&closure_expr.id).iter() {
match captured_var.mode {
moves::CapMove => {
let cmt = bccx.cat_captured_var(closure_expr.id,
closure_expr.span,
captured_var);
let move_info = GatherMoveInfo {
id: closure_expr.id,
kind: Captured,
cmt: cmt,
span_path_opt: None
};
gather_move(bccx, move_data, move_error_collector, move_info);
}
moves::CapCopy | moves::CapRef => {}
}
}
}
fn gather_move(bccx: &BorrowckCtxt,
move_data: &MoveData,
move_error_collector: &MoveErrorCollector,
......@@ -110,6 +87,7 @@ fn gather_move(bccx: &BorrowckCtxt,
check_and_get_illegal_move_origin(bccx, &move_info.cmt);
match potentially_illegal_move {
Some(illegal_move_origin) => {
debug!("illegal_move_origin={}", illegal_move_origin.repr(bccx.tcx));
let error = MoveError::with_move_info(illegal_move_origin,
move_info.span_path_opt);
move_error_collector.add_error(error);
......@@ -134,27 +112,14 @@ pub fn gather_assignment(bccx: &BorrowckCtxt,
assignment_id: ast::NodeId,
assignment_span: Span,
assignee_loan_path: Rc<LoanPath>,
assignee_id: ast::NodeId) {
move_data.add_assignment(bccx.tcx,
assignee_loan_path,
assignment_id,
assignment_span,
assignee_id,
false);
}
pub fn gather_move_and_assignment(bccx: &BorrowckCtxt,
move_data: &MoveData,
assignment_id: ast::NodeId,
assignment_span: Span,
assignee_loan_path: Rc<LoanPath>,
assignee_id: ast::NodeId) {
assignee_id: ast::NodeId,
mode: euv::MutateMode) {
move_data.add_assignment(bccx.tcx,
assignee_loan_path,
assignment_id,
assignment_span,
assignee_id,
true);
mode);
}
fn check_and_get_illegal_move_origin(bccx: &BorrowckCtxt,
......
......@@ -14,6 +14,7 @@
*/
use middle::borrowck::*;
use euv = middle::expr_use_visitor;
use mc = middle::mem_categorization;
use middle::ty;
use util::ppaux::Repr;
......@@ -24,9 +25,8 @@
pub fn guarantee_lifetime(bccx: &BorrowckCtxt,
item_scope_id: ast::NodeId,
root_scope_id: ast::NodeId,
span: Span,
cause: LoanCause,
cause: euv::LoanCause,
cmt: mc::cmt,
loan_region: ty::Region,
loan_kind: ty::BorrowKind)
......@@ -39,8 +39,7 @@ pub fn guarantee_lifetime(bccx: &BorrowckCtxt,
cause: cause,
loan_region: loan_region,
loan_kind: loan_kind,
cmt_original: cmt.clone(),
root_scope_id: root_scope_id};
cmt_original: cmt.clone()};
ctxt.check(&cmt, None)
}
......@@ -53,12 +52,8 @@ struct GuaranteeLifetimeContext<'a> {
// the node id of the function body for the enclosing item
item_scope_id: ast::NodeId,
// the node id of the innermost loop / function body; this is the
// longest scope for which we can root managed boxes
root_scope_id: ast::NodeId,
span: Span,
cause: LoanCause,
cause: euv::LoanCause,
loan_region: ty::Region,
loan_kind: ty::BorrowKind,
cmt_original: mc::cmt
......
......@@ -100,6 +100,7 @@ fn group_errors_with_same_origin(errors: &Vec<MoveError>)
fn append_to_grouped_errors(grouped_errors: &mut Vec<GroupedMoveErrors>,
error: &MoveError) {
let move_from_id = error.move_from.id;
debug!("append_to_grouped_errors(move_from_id={})", move_from_id);
let move_to = if error.move_to.is_some() {
vec!(error.move_to.clone().unwrap())
} else {
......@@ -107,10 +108,12 @@ fn append_to_grouped_errors(grouped_errors: &mut Vec<GroupedMoveErrors>,
};
for ge in grouped_errors.mut_iter() {
if move_from_id == ge.move_from.id && error.move_to.is_some() {
debug!("appending move_to to list");
ge.move_to_places.push_all_move(move_to);
return
}
}
debug!("found a new move from location");
grouped_errors.push(GroupedMoveErrors {
move_from: error.move_from.clone(),
move_to_places: move_to
......
......@@ -13,6 +13,7 @@
*/
use middle::borrowck::*;
use euv = middle::expr_use_visitor;
use mc = middle::mem_categorization;
use middle::ty;
use syntax::codemap::Span;
......@@ -27,7 +28,7 @@ pub enum RestrictionResult {
pub fn compute_restrictions(bccx: &BorrowckCtxt,
span: Span,
cause: LoanCause,
cause: euv::LoanCause,
cmt: mc::cmt,
loan_region: ty::Region,
restr: RestrictionSet) -> RestrictionResult {
......@@ -50,7 +51,7 @@ struct RestrictionsContext<'a> {
span: Span,
cmt_original: mc::cmt,
loan_region: ty::Region,
cause: LoanCause,
cause: euv::LoanCause,
}
impl<'a> RestrictionsContext<'a> {
......
......@@ -12,16 +12,14 @@
#![allow(non_camel_case_types)]
use mc = middle::mem_categorization;
use middle::ty;
use middle::typeck;
use middle::moves;
use middle::dataflow::DataFlowContext;
use middle::dataflow::DataFlowOperator;
use util::nodemap::{NodeMap, NodeSet};
use euv = middle::expr_use_visitor;
use mc = middle::mem_categorization;
use middle::ty;
use util::ppaux::{note_and_explain_region, Repr, UserString};
use std::cell::{Cell, RefCell};
use std::cell::{Cell};
use std::ops::{BitOr, BitAnd};
use std::rc::Rc;
use std::strbuf::StrBuf;
......@@ -75,13 +73,9 @@ fn visit_item(&mut self, item: &ast::Item, _: ()) {
}
pub fn check_crate(tcx: &ty::ctxt,
moves_map: &NodeSet,
capture_map: &moves::CaptureMap,
krate: &ast::Crate) {
let mut bccx = BorrowckCtxt {
tcx: tcx,
moves_map: moves_map,
capture_map: capture_map,
stats: @BorrowStats {
loaned_paths_same: Cell::new(0),
loaned_paths_imm: Cell::new(0),
......@@ -135,7 +129,8 @@ fn borrowck_fn(this: &mut BorrowckCtxt,
debug!("borrowck_fn(id={})", id);
// Check the body of fn items.
let (id_range, all_loans, move_data) =
let id_range = ast_util::compute_id_range_for_fn_body(fk, decl, body, sp, id);
let (all_loans, move_data) =
gather_loans::gather_loans_in_fn(this, decl, body);
let mut loan_dfcx =
DataFlowContext::new(this.tcx,
......@@ -164,8 +159,6 @@ fn borrowck_fn(this: &mut BorrowckCtxt,
pub struct BorrowckCtxt<'a> {
tcx: &'a ty::ctxt,
moves_map: &'a NodeSet,
capture_map: &'a moves::CaptureMap,
// Statistics:
stats: @BorrowStats
......@@ -199,16 +192,7 @@ pub struct Loan {
gen_scope: ast::NodeId,
kill_scope: ast::NodeId,
span: Span,
cause: LoanCause,
}
#[deriving(Eq)]
pub enum LoanCause {
ClosureCapture(Span),
AddrOf,
AutoRef,
RefBinding,
ClosureInvocation,
cause: euv::LoanCause,
}
#[deriving(Eq, TotalEq, Hash)]
......@@ -341,14 +325,14 @@ pub enum bckerr_code {
#[deriving(Eq)]
pub struct BckError {
span: Span,
cause: LoanCause,
cause: euv::LoanCause,
cmt: mc::cmt,
code: bckerr_code
}
pub enum AliasableViolationKind {
MutabilityViolation,
BorrowViolation(LoanCause)
BorrowViolation(euv::LoanCause)
}
pub enum MovedValueUseKind {
......@@ -370,14 +354,8 @@ pub fn is_subscope_of(&self, r_sub: ast::NodeId, r_sup: ast::NodeId)
self.tcx.region_maps.is_subscope_of(r_sub, r_sup)
}
pub fn is_move(&self, id: ast::NodeId) -> bool {
self.moves_map.contains(&id)
}
pub fn mc(&self) -> mc::MemCategorizationContext<&'a ty::ctxt> {
mc::MemCategorizationContext {
typer: self.tcx,
}
pub fn mc(&self) -> mc::MemCategorizationContext<'a,ty::ctxt> {
mc::MemCategorizationContext::new(self.tcx)
}
pub fn cat_expr(&self, expr: &ast::Expr) -> mc::cmt {
......@@ -439,14 +417,15 @@ pub fn cat_def(&self,
}
pub fn cat_captured_var(&self,
id: ast::NodeId,
span: Span,
captured_var: &moves::CaptureVar) -> mc::cmt {
closure_id: ast::NodeId,
closure_span: Span,
upvar_def: ast::Def)
-> mc::cmt {
// Create the cmt for the variable being borrowed, from the
// caller's perspective
let var_id = ast_util::def_id_of_def(captured_var.def).node;
let var_id = ast_util::def_id_of_def(upvar_def).node;
let var_ty = ty::node_id_to_type(self.tcx, var_id);
self.cat_def(id, span, var_ty, captured_var.def)
self.cat_def(closure_id, closure_span, var_ty, upvar_def)
}
pub fn cat_discr(&self, cmt: mc::cmt, match_id: ast::NodeId) -> mc::cmt {
......@@ -604,13 +583,16 @@ pub fn bckerr_to_str(&self, err: &BckError) -> ~str {
};
match err.cause {
ClosureCapture(_) => {
euv::ClosureCapture(_) => {
format!("closure cannot assign to {}", descr)
}
AddrOf | RefBinding | AutoRef => {
euv::OverloadedOperator |
euv::AddrOf |
euv::RefBinding |
euv::AutoRef => {
format!("cannot borrow {} as mutable", descr)
}
ClosureInvocation => {
euv::ClosureInvocation => {
self.tcx.sess.span_bug(err.span,
"err_mutbl with a closure invocation");
}
......@@ -644,7 +626,7 @@ pub fn report_aliasability_violation(&self,
MutabilityViolation => {
"cannot assign to data"
}
BorrowViolation(ClosureCapture(_)) => {
BorrowViolation(euv::ClosureCapture(_)) => {
// I don't think we can get aliasability violations
// with closure captures, so no need to come up with a
// good error message. The reason this cannot happen
......@@ -654,13 +636,14 @@ pub fn report_aliasability_violation(&self,
span,
"aliasability violation with closure");
}
BorrowViolation(AddrOf) |
BorrowViolation(AutoRef) |
BorrowViolation(RefBinding) => {
BorrowViolation(euv::OverloadedOperator) |
BorrowViolation(euv::AddrOf) |
BorrowViolation(euv::AutoRef) |
BorrowViolation(euv::RefBinding) => {
"cannot borrow data mutably"
}
BorrowViolation(ClosureInvocation) => {
BorrowViolation(euv::ClosureInvocation) => {
"closure invocation"
}
};
......@@ -839,34 +822,3 @@ fn repr(&self, tcx: &ty::ctxt) -> ~str {
}
}
///////////////////////////////////////////////////////////////////////////
impl<'a> mc::Typer for &'a ty::ctxt {
fn tcx<'a>(&'a self) -> &'a ty::ctxt {
*self
}
fn node_ty(&self, id: ast::NodeId) -> mc::McResult<ty::t> {
Ok(ty::node_id_to_type(*self, id))
}
fn node_method_ty(&self, method_call: typeck::MethodCall) -> Option<ty::t> {
self.method_map.borrow().find(&method_call).map(|method| method.ty)
}
fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment>> {
&self.adjustments
}
fn is_method_call(&self, id: ast::NodeId) -> bool {
self.method_map.borrow().contains_key(&typeck::MethodCall::expr(id))
}
fn temporary_scope(&self, id: ast::NodeId) -> Option<ast::NodeId> {
self.region_maps.temporary_scope(id)
}
fn upvar_borrow(&self, id: ty::UpvarId) -> ty::UpvarBorrow {
self.upvar_borrow_map.borrow().get_copy(&id)
}
}
......@@ -22,6 +22,7 @@
use middle::borrowck::*;
use middle::dataflow::DataFlowContext;
use middle::dataflow::DataFlowOperator;
use euv = middle::expr_use_visitor;
use middle::ty;
use syntax::ast;
use syntax::ast_util;
......@@ -357,7 +358,7 @@ pub fn add_assignment(&self,
assign_id: ast::NodeId,
span: Span,
assignee_id: ast::NodeId,
is_also_move: bool) {
mode: euv::MutateMode) {
/*!
* Adds a new record for an assignment to `lp` that occurs at
* location `id` with the given `span`.
......@@ -368,8 +369,11 @@ pub fn add_assignment(&self,
let path_index = self.move_path(tcx, lp.clone());
if !is_also_move {
self.assignee_ids.borrow_mut().insert(assignee_id);
match mode {
euv::JustWrite => {
self.assignee_ids.borrow_mut().insert(assignee_id);
}
euv::WriteAndRead => { }
}
let assignment = Assignment {
......
......@@ -15,7 +15,6 @@
use middle::pat_util::*;
use middle::ty::*;
use middle::ty;
use util::nodemap::NodeSet;
use util::ppaux::ty_to_str;
use std::cmp;
......@@ -29,7 +28,6 @@
struct MatchCheckCtxt<'a> {
tcx: &'a ty::ctxt,
moves_map: &'a NodeSet
}
impl<'a> Visitor<()> for MatchCheckCtxt<'a> {
......@@ -45,11 +43,9 @@ fn visit_fn(&mut self, fk: &FnKind, fd: &FnDecl, b: &Block, s: Span, n: NodeId,
}
pub fn check_crate(tcx: &ty::ctxt,
moves_map: &NodeSet,
krate: &Crate) {
let mut cx = MatchCheckCtxt {
tcx: tcx,
moves_map: moves_map
};
visit::walk_crate(&mut cx, krate, ());
......@@ -931,22 +927,18 @@ fn is_refutable(cx: &MatchCheckCtxt, pat: &Pat) -> bool {
// Legality of move bindings checking
fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
has_guard: bool,
pats: &[@Pat]) {
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 pat in pats.iter() {
pat_bindings(def_map, *pat, |bm, id, span, _path| {
pat_bindings(def_map, *pat, |bm, _, span, _path| {
match bm {
BindByRef(_) => {
by_ref_span = Some(span);
}
BindByValue(_) => {
if cx.moves_map.contains(&id) {
any_by_move = true;
}
}
}
})
......@@ -975,16 +967,18 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
}
};
if !any_by_move { return; } // pointless micro-optimization
for pat in pats.iter() {
walk_pat(*pat, |p| {
if pat_is_binding(def_map, p) {
match p.node {
PatIdent(_, _, sub) => {
if cx.moves_map.contains(&p.id) {
PatIdent(BindByValue(_), _, sub) => {
let pat_ty = ty::node_id_to_type(tcx, p.id);
if ty::type_moves_by_default(tcx, pat_ty) {
check_move(p, sub);
}
}
PatIdent(BindByRef(_), _, _) => {
}
_ => {
cx.tcx.sess.span_bug(
p.span,
......
......@@ -15,7 +15,7 @@
use middle::ty;
use middle::typeck::astconv;
use util::nodemap::{DefIdMap, NodeMap};
use util::nodemap::{DefIdMap};
use syntax::ast::*;
use syntax::parse::token::InternedString;
......@@ -23,7 +23,6 @@
use syntax::visit;
use syntax::{ast, ast_map, ast_util};
use std::cell::RefCell;
use std::rc::Rc;
//
......@@ -125,11 +124,8 @@ fn variant_expr(variants: &[ast::P<ast::Variant>], id: ast::NodeId) -> Option<@E
Some(&e) => return e,
None => {}
}
let maps = astencode::Maps {
capture_map: RefCell::new(NodeMap::new())
};
let e = match csearch::maybe_get_item_ast(tcx, enum_def,
|a, b, c, d| astencode::decode_inlined_item(a, b, &maps, c, d)) {
|a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) {
csearch::found(ast::IIItem(item)) => match item.node {
ItemEnum(ast::EnumDef { variants: ref variants }, _) => {
variant_expr(variants.as_slice(), variant_def.node)
......@@ -163,11 +159,8 @@ pub fn lookup_const_by_id(tcx: &ty::ctxt, def_id: ast::DefId)
Some(&e) => return e,
None => {}
}
let maps = astencode::Maps {
capture_map: RefCell::new(NodeMap::new())
};
let e = match csearch::maybe_get_item_ast(tcx, def_id,
|a, b, c, d| astencode::decode_inlined_item(a, b, &maps, c, d)) {
|a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) {
csearch::found(ast::IIItem(item)) => match item.node {
ItemStatic(_, ast::MutImmutable, const_expr) => Some(const_expr),
_ => None
......
此差异已折叠。
......@@ -22,6 +22,15 @@
use syntax::visit;
use syntax::visit::Visitor;
#[deriving(Show)]
pub enum CaptureMode {
/// Copy/move the value from this llvm ValueRef into the environment.
CaptureByValue,
/// Access by reference (used for stack closures).
CaptureByRef
}
// A vector of defs representing the free variables referred to in a function.
// (The def_upvar will already have been stripped).
#[deriving(Encodable, Decodable)]
......@@ -38,7 +47,6 @@ struct CollectFreevarsVisitor<'a> {
}
impl<'a> Visitor<int> for CollectFreevarsVisitor<'a> {
fn visit_item(&mut self, _: &ast::Item, _: int) {
// ignore_item
}
......@@ -133,3 +141,14 @@ pub fn with_freevars<T>(tcx: &ty::ctxt, fid: ast::NodeId, f: |&[freevar_entry]|
Some(d) => f(d.as_slice())
}
}
pub fn get_capture_mode(tcx: &ty::ctxt,
closure_expr_id: ast::NodeId)
-> CaptureMode
{
let fn_ty = ty::node_id_to_type(tcx, closure_expr_id);
match ty::ty_closure_store(fn_ty) {
ty::RegionTraitStore(..) => CaptureByRef,
ty::UniqTraitStore => CaptureByValue
}
}
......@@ -228,11 +228,11 @@ fn check_fn(
// Check kinds on free variables:
with_appropriate_checker(cx, fn_id, |chk| {
freevars::with_freevars(cx.tcx, fn_id, |r| {
for fv in r.iter() {
freevars::with_freevars(cx.tcx, fn_id, |freevars| {
for fv in freevars.iter() {
chk(cx, fv);
}
})
});
});
visit::walk_fn(cx, fk, decl, body, sp, fn_id, ());
......
......@@ -103,10 +103,10 @@
*/
use middle::freevars;
use middle::lint::{UnusedVariable, DeadAssignment};
use middle::pat_util;
use middle::ty;
use middle::moves;
use util::nodemap::NodeMap;
use std::cast::transmute;
......@@ -170,9 +170,8 @@ fn visit_fn(&mut self, fk: &FnKind, fd: &FnDecl, b: &Block, s: Span, n: NodeId,
}
pub fn check_crate(tcx: &ty::ctxt,
capture_map: &moves::CaptureMap,
krate: &Crate) {
visit::walk_crate(&mut IrMaps(tcx, capture_map), krate, ());
visit::walk_crate(&mut IrMaps(tcx), krate, ());
tcx.sess.abort_if_errors();
}
......@@ -245,7 +244,6 @@ enum VarKind {
struct IrMaps<'a> {
tcx: &'a ty::ctxt,
capture_map: &'a moves::CaptureMap,
num_live_nodes: uint,
num_vars: uint,
......@@ -256,12 +254,10 @@ struct IrMaps<'a> {
lnks: Vec<LiveNodeKind>,
}
fn IrMaps<'a>(tcx: &'a ty::ctxt,
capture_map: &'a moves::CaptureMap)
fn IrMaps<'a>(tcx: &'a ty::ctxt)
-> IrMaps<'a> {
IrMaps {
tcx: tcx,
capture_map: capture_map,
num_live_nodes: 0,
num_vars: 0,
live_node_map: NodeMap::new(),
......@@ -361,7 +357,7 @@ fn visit_fn(ir: &mut IrMaps,
let _i = ::util::common::indenter();
// swap in a new set of IR maps for this function body:
let mut fn_maps = IrMaps(ir.tcx, ir.capture_map);
let mut fn_maps = IrMaps(ir.tcx);
unsafe {
debug!("creating fn_maps: {}", transmute::<&IrMaps, *IrMaps>(&fn_maps));
......@@ -446,13 +442,23 @@ fn visit_arm(ir: &mut IrMaps, arm: &Arm) {
visit::walk_arm(ir, arm, ());
}
fn moved_variable_node_id_from_def(def: Def) -> Option<NodeId> {
match def {
DefBinding(nid, _) |
DefArg(nid, _) |
DefLocal(nid, _) => Some(nid),
_ => None
}
}
fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
match expr.node {
// live nodes required for uses or definitions of variables:
ExprPath(_) => {
let def = ir.tcx.def_map.borrow().get_copy(&expr.id);
debug!("expr {}: path that leads to {:?}", expr.id, def);
if moves::moved_variable_node_id_from_def(def).is_some() {
if moved_variable_node_id_from_def(def).is_some() {
ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
}
visit::walk_expr(ir, expr, ());
......@@ -467,24 +473,33 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
// in better error messages than just pointing at the closure
// construction site.
let mut call_caps = Vec::new();
for cv in ir.capture_map.get(&expr.id).iter() {
match moves::moved_variable_node_id_from_def(cv.def) {
Some(rv) => {
let cv_ln = ir.add_live_node(FreeVarNode(cv.span));
let is_move = match cv.mode {
// var must be dead afterwards
moves::CapMove => true,
// var can still be used
moves::CapCopy | moves::CapRef => false
};
call_caps.push(CaptureInfo {ln: cv_ln,
is_move: is_move,
var_nid: rv});
}
None => {}
let fv_mode = freevars::get_capture_mode(ir.tcx, expr.id);
freevars::with_freevars(ir.tcx, expr.id, |freevars| {
for fv in freevars.iter() {
match moved_variable_node_id_from_def(fv.def) {
Some(rv) => {
let fv_ln = ir.add_live_node(FreeVarNode(fv.span));
let fv_id = ast_util::def_id_of_def(fv.def).node;
let fv_ty = ty::node_id_to_type(ir.tcx, fv_id);
let is_move = match fv_mode {
// var must be dead afterwards
freevars::CaptureByValue => {
ty::type_moves_by_default(ir.tcx, fv_ty)
}
// var can still be used
freevars::CaptureByRef => {
false
}
};
call_caps.push(CaptureInfo {ln: fv_ln,
is_move: is_move,
var_nid: rv});
}
None => {}
}
}
}
});
ir.set_captures(expr.id, call_caps);
visit::walk_expr(ir, expr, ());
......@@ -1270,7 +1285,7 @@ fn write_lvalue(&mut self, expr: &Expr, succ: LiveNode, acc: uint)
fn access_path(&mut self, expr: &Expr, succ: LiveNode, acc: uint)
-> LiveNode {
let def = self.ir.tcx.def_map.borrow().get_copy(&expr.id);
match moves::moved_variable_node_id_from_def(def) {
match moved_variable_node_id_from_def(def) {
Some(nid) => {
let ln = self.live_node(expr.id, expr.span);
if acc != 0u {
......@@ -1497,7 +1512,7 @@ fn check_lvalue(&mut self, expr: &Expr) {
self.warn_about_dead_assign(expr.span, expr.id, ln, var);
}
def => {
match moves::moved_variable_node_id_from_def(def) {
match moved_variable_node_id_from_def(def) {
Some(nid) => {
let ln = self.live_node(expr.id, expr.span);
let var = self.variable(nid, expr.span);
......
......@@ -241,8 +241,8 @@ fn id(&self) -> ast::NodeId { self.id }
fn span(&self) -> Span { self.span }
}
pub struct MemCategorizationContext<TYPER> {
pub typer: TYPER
pub struct MemCategorizationContext<'t,TYPER> {
typer: &'t TYPER
}
pub type McResult<T> = Result<T, ()>;
......@@ -349,8 +349,12 @@ pub fn to_user_str(&self) -> &'static str {
)
)
impl<TYPER:Typer> MemCategorizationContext<TYPER> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt {
impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
pub fn new(typer: &'t TYPER) -> MemCategorizationContext<'t,TYPER> {
MemCategorizationContext { typer: typer }
}
fn tcx(&self) -> &'t ty::ctxt {
self.typer.tcx()
}
......@@ -418,7 +422,9 @@ pub fn cat_expr(&self, expr: &ast::Expr) -> McResult<cmt> {
}
}
pub fn cat_expr_autoderefd(&self, expr: &ast::Expr, autoderefs: uint)
pub fn cat_expr_autoderefd(&self,
expr: &ast::Expr,
autoderefs: uint)
-> McResult<cmt> {
let mut cmt = if_ok!(self.cat_expr_unadjusted(expr));
for deref in range(1u, autoderefs + 1) {
......@@ -456,7 +462,9 @@ pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> McResult<cmt> {
self.cat_def(expr.id, expr.span, expr_ty, def)
}
ast::ExprParen(e) => self.cat_expr_unadjusted(e),
ast::ExprParen(e) => {
self.cat_expr(e)
}
ast::ExprAddrOf(..) | ast::ExprCall(..) |
ast::ExprAssign(..) | ast::ExprAssignOp(..) |
......
此差异已折叠。
......@@ -2073,7 +2073,7 @@ pub fn write_metadata(cx: &CrateContext, krate: &ast::Crate) -> Vec<u8> {
}
let encode_inlined_item: encoder::EncodeInlinedItem =
|ecx, ebml_w, ii| astencode::encode_inlined_item(ecx, ebml_w, ii, &cx.maps);
|ecx, ebml_w, ii| astencode::encode_inlined_item(ecx, ebml_w, ii);
let encode_parms = crate_ctxt_to_encode_parms(cx, encode_inlined_item);
let metadata = encoder::encode_metadata(encode_parms, krate);
......@@ -2103,7 +2103,7 @@ pub fn write_metadata(cx: &CrateContext, krate: &ast::Crate) -> Vec<u8> {
pub fn trans_crate(krate: ast::Crate,
analysis: CrateAnalysis,
output: &OutputFilenames) -> (ty::ctxt, CrateTranslation) {
let CrateAnalysis { ty_cx: tcx, exp_map2, maps, reachable, .. } = analysis;
let CrateAnalysis { ty_cx: tcx, exp_map2, reachable, .. } = analysis;
// Before we touch LLVM, make sure that multithreading is enabled.
unsafe {
......@@ -2135,7 +2135,7 @@ pub fn trans_crate(krate: ast::Crate,
// 1. http://llvm.org/bugs/show_bug.cgi?id=11479
let llmod_id = link_meta.crateid.name + ".rs";
let ccx = CrateContext::new(llmod_id, tcx, exp_map2, maps,
let ccx = CrateContext::new(llmod_id, tcx, exp_map2,
Sha256::new(), link_meta, reachable);
{
let _icx = push_ctxt("text");
......
......@@ -13,8 +13,8 @@
use back::link::mangle_internal_name_by_path_and_seq;
use driver::session::FullDebugInfo;
use lib::llvm::ValueRef;
use middle::freevars;
use middle::lang_items::ClosureExchangeMallocFnLangItem;
use middle::moves;
use middle::trans::base::*;
use middle::trans::build::*;
use middle::trans::common::*;
......@@ -98,35 +98,14 @@
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pub enum EnvAction {
/// Copy the value from this llvm ValueRef into the environment.
EnvCopy,
/// Move the value from this llvm ValueRef into the environment.
EnvMove,
/// Access by reference (used for stack closures).
EnvRef
}
pub struct EnvValue {
action: EnvAction,
action: freevars::CaptureMode,
datum: Datum<Lvalue>
}
impl EnvAction {
pub fn to_str(&self) -> ~str {
match *self {
EnvCopy => "EnvCopy".to_owned(),
EnvMove => "EnvMove".to_owned(),
EnvRef => "EnvRef".to_owned()
}
}
}
impl EnvValue {
pub fn to_str(&self, ccx: &CrateContext) -> ~str {
format!("{}({})", self.action.to_str(), self.datum.to_str(ccx))
format!("{}({})", self.action, self.datum.to_str(ccx))
}
}
......@@ -140,8 +119,8 @@ pub fn mk_closure_tys(tcx: &ty::ctxt,
// converted to ptrs.
let bound_tys = bound_values.iter().map(|bv| {
match bv.action {
EnvCopy | EnvMove => bv.datum.ty,
EnvRef => ty::mk_mut_ptr(tcx, bv.datum.ty)
freevars::CaptureByValue => bv.datum.ty,
freevars::CaptureByRef => ty::mk_mut_ptr(tcx, bv.datum.ty)
}
}).collect();
let cdata_ty = ty::mk_tup(tcx, bound_tys);
......@@ -232,10 +211,10 @@ pub fn store_environment<'a>(
let bound_data = GEPi(bcx, llbox, [0u, abi::box_field_body, i]);
match bv.action {
EnvCopy | EnvMove => {
freevars::CaptureByValue => {
bcx = bv.datum.store_to(bcx, bound_data);
}
EnvRef => {
freevars::CaptureByRef => {
Store(bcx, bv.datum.to_llref(), bound_data);
}
}
......@@ -247,9 +226,11 @@ pub fn store_environment<'a>(
// Given a context and a list of upvars, build a closure. This just
// collects the upvars and packages them up for store_environment.
fn build_closure<'a>(bcx0: &'a Block<'a>,
cap_vars: &[moves::CaptureVar],
freevar_mode: freevars::CaptureMode,
freevars: &Vec<freevars::freevar_entry>,
store: ty::TraitStore)
-> ClosureResult<'a> {
-> ClosureResult<'a>
{
let _icx = push_ctxt("closure::build_closure");
// If we need to, package up the iterator body to call
......@@ -257,28 +238,9 @@ fn build_closure<'a>(bcx0: &'a Block<'a>,
// Package up the captured upvars
let mut env_vals = Vec::new();
for cap_var in cap_vars.iter() {
debug!("Building closure: captured variable {:?}", *cap_var);
let datum = expr::trans_local_var(bcx, cap_var.def);
match cap_var.mode {
moves::CapRef => {
let is_region_closure = match store {
ty::RegionTraitStore(..) => true,
ty::UniqTraitStore => false
};
assert!(is_region_closure);
env_vals.push(EnvValue {action: EnvRef,
datum: datum});
}
moves::CapCopy => {
env_vals.push(EnvValue {action: EnvCopy,
datum: datum});
}
moves::CapMove => {
env_vals.push(EnvValue {action: EnvMove,
datum: datum});
}
}
for freevar in freevars.iter() {
let datum = expr::trans_local_var(bcx, freevar.def);
env_vals.push(EnvValue {action: freevar_mode, datum: datum});
}
store_environment(bcx, env_vals, store)
......@@ -287,13 +249,15 @@ fn build_closure<'a>(bcx0: &'a Block<'a>,
// Given an enclosing block context, a new function context, a closure type,
// and a list of upvars, generate code to load and populate the environment
// with the upvars and type descriptors.
fn load_environment<'a>(bcx: &'a Block<'a>, cdata_ty: ty::t,
cap_vars: &[moves::CaptureVar],
store: ty::TraitStore) -> &'a Block<'a> {
fn load_environment<'a>(bcx: &'a Block<'a>,
cdata_ty: ty::t,
freevars: &Vec<freevars::freevar_entry>,
store: ty::TraitStore)
-> &'a Block<'a> {
let _icx = push_ctxt("closure::load_environment");
// Don't bother to create the block if there's nothing to load
if cap_vars.len() == 0 {
if freevars.len() == 0 {
return bcx;
}
......@@ -312,13 +276,13 @@ fn load_environment<'a>(bcx: &'a Block<'a>, cdata_ty: ty::t,
// Populate the upvars from the environment
let mut i = 0u;
for cap_var in cap_vars.iter() {
for freevar in freevars.iter() {
let mut upvarptr = GEPi(bcx, llcdata, [0u, i]);
match store {
ty::RegionTraitStore(..) => { upvarptr = Load(bcx, upvarptr); }
ty::UniqTraitStore => {}
}
let def_id = ast_util::def_id_of_def(cap_var.def);
let def_id = ast_util::def_id_of_def(freevar.def);
bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvarptr);
......@@ -330,7 +294,7 @@ fn load_environment<'a>(bcx: &'a Block<'a>, cdata_ty: ty::t,
env_pointer_alloca,
i,
store,
cap_var.span);
freevar.span);
}
i += 1u;
......@@ -395,15 +359,19 @@ pub fn trans_expr_fn<'a>(
// set an inline hint for all closures
set_inline_hint(llfn);
let cap_vars = ccx.maps.capture_map.borrow().get_copy(&id);
let freevar_mode = freevars::get_capture_mode(tcx, id);
let freevars: Vec<freevars::freevar_entry> =
freevars::with_freevars(
tcx, id,
|fv| fv.iter().map(|&fv| fv).collect());
let ClosureResult {llbox, cdata_ty, bcx} =
build_closure(bcx, cap_vars.as_slice(), store);
build_closure(bcx, freevar_mode, &freevars, store);
trans_closure(ccx, decl, body, llfn,
bcx.fcx.param_substs, id,
[], ty::ty_fn_ret(fty),
|bcx| load_environment(bcx, cdata_ty, cap_vars.as_slice(), store));
|bcx| load_environment(bcx, cdata_ty, &freevars, store));
fill_fn_pair(bcx, dest_addr, llfn, llbox);
bcx
}
......
......@@ -15,7 +15,6 @@
use lib::llvm::{llvm, TargetData, TypeNames};
use lib::llvm::mk_target_data;
use metadata::common::LinkMeta;
use middle::astencode;
use middle::resolve;
use middle::trans::adt;
use middle::trans::base;
......@@ -113,7 +112,6 @@ pub struct CrateContext {
pub type_hashcodes: RefCell<HashMap<ty::t, ~str>>,
pub all_llvm_symbols: RefCell<HashSet<~str>>,
pub tcx: ty::ctxt,
pub maps: astencode::Maps,
pub stats: Stats,
pub int_type: Type,
pub opaque_vec_type: Type,
......@@ -131,7 +129,6 @@ impl CrateContext {
pub fn new(name: &str,
tcx: ty::ctxt,
emap2: resolve::ExportMap2,
maps: astencode::Maps,
symbol_hasher: Sha256,
link_meta: LinkMeta,
reachable: NodeSet)
......@@ -195,7 +192,6 @@ pub fn new(name: &str,
type_hashcodes: RefCell::new(HashMap::new()),
all_llvm_symbols: RefCell::new(HashSet::new()),
tcx: tcx,
maps: maps,
stats: Stats {
n_static_tydescs: Cell::new(0u),
n_glues_created: Cell::new(0u),
......
......@@ -40,7 +40,7 @@ pub fn maybe_instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId)
let csearch_result =
csearch::maybe_get_item_ast(
ccx.tcx(), fn_id,
|a,b,c,d| astencode::decode_inlined_item(a, b, &ccx.maps, c, d));
|a,b,c,d| astencode::decode_inlined_item(a, b, c, d));
return match csearch_result {
csearch::not_found => {
ccx.external.borrow_mut().insert(fn_id, None);
......
......@@ -13,6 +13,7 @@
use back::svh::Svh;
use driver::session::Session;
use metadata::csearch;
use mc = middle::mem_categorization;
use middle::const_eval;
use middle::lang_items::{ExchangeHeapLangItem, OpaqueStructLangItem};
use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem};
......@@ -508,7 +509,7 @@ pub struct UpvarId {
pub closure_expr_id: ast::NodeId,
}
#[deriving(Clone, Eq, TotalEq, Hash)]
#[deriving(Clone, Eq, TotalEq, Hash, Show)]
pub enum BorrowKind {
/// Data must be immutable and is aliasable.
ImmBorrow,
......@@ -4779,3 +4780,33 @@ pub fn to_user_str(&self) -> &'static str {
}
}
}
impl mc::Typer for ty::ctxt {
fn tcx<'a>(&'a self) -> &'a ty::ctxt {
self
}
fn node_ty(&self, id: ast::NodeId) -> mc::McResult<ty::t> {
Ok(ty::node_id_to_type(self, id))
}
fn node_method_ty(&self, method_call: typeck::MethodCall) -> Option<ty::t> {
self.method_map.borrow().find(&method_call).map(|method| method.ty)
}
fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment>> {
&self.adjustments
}
fn is_method_call(&self, id: ast::NodeId) -> bool {
self.method_map.borrow().contains_key(&typeck::MethodCall::expr(id))
}
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<ast::NodeId> {
self.region_maps.temporary_scope(rvalue_id)
}
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow {
self.upvar_borrow_map.borrow().get_copy(&upvar_id)
}
}
......@@ -261,7 +261,7 @@ pub fn resolve_expr_type_adjusted(&mut self, expr: &ast::Expr) -> ty::t {
}
}
impl<'a, 'b> mc::Typer for &'a Rcx<'b> {
impl<'fcx> mc::Typer for Rcx<'fcx> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt {
self.fcx.tcx()
}
......@@ -638,7 +638,7 @@ fn check_expr_fn_block(rcx: &mut Rcx,
ty::ty_closure(~ty::ClosureTy {store: ty::RegionTraitStore(..), ..}) => {
freevars::with_freevars(tcx, expr.id, |freevars| {
propagate_upupvar_borrow_kind(rcx, expr, freevars);
});
})
}
_ => ()
}
......@@ -754,9 +754,9 @@ fn constrain_callee(rcx: &mut Rcx,
ty::RegionTraitStore(r, _) => {
// While we're here, link the closure's region with a unique
// immutable borrow (gathered later in borrowck)
let mc = mc::MemCategorizationContext { typer: &*rcx };
let mc = mc::MemCategorizationContext::new(rcx);
let expr_cmt = ignore_err!(mc.cat_expr(callee_expr));
link_region(mc.typer, callee_expr.span, call_region,
link_region(rcx, callee_expr.span, call_region,
ty::UniqueImmBorrow, expr_cmt);
r
}
......@@ -880,9 +880,9 @@ fn constrain_autoderefs(rcx: &mut Rcx,
method.ty.repr(rcx.tcx())))
};
{
let mc = mc::MemCategorizationContext { typer: &*rcx };
let mc = mc::MemCategorizationContext::new(rcx);
let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
link_region(mc.typer, deref_expr.span, r,
link_region(rcx, deref_expr.span, r,
ty::BorrowKind::from_mutbl(m), self_cmt);
}
......@@ -1038,7 +1038,7 @@ fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
debug!("link_addr_of(base=?)");
let cmt = {
let mc = mc::MemCategorizationContext { typer: &*rcx };
let mc = mc::MemCategorizationContext::new(rcx);
ignore_err!(mc.cat_expr(base))
};
link_region_from_node_type(rcx, expr.span, expr.id, mutability, cmt);
......@@ -1056,9 +1056,9 @@ fn link_local(rcx: &Rcx, local: &ast::Local) {
None => { return; }
Some(expr) => expr,
};
let mc = mc::MemCategorizationContext { typer: rcx };
let mc = mc::MemCategorizationContext::new(rcx);
let discr_cmt = ignore_err!(mc.cat_expr(init_expr));
link_pattern(mc, discr_cmt, local.pat);
link_pattern(rcx, mc, discr_cmt, local.pat);
}
fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) {
......@@ -1069,17 +1069,18 @@ fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) {
*/
debug!("regionck::for_match()");
let mc = mc::MemCategorizationContext { typer: rcx };
let mc = mc::MemCategorizationContext::new(rcx);
let discr_cmt = ignore_err!(mc.cat_expr(discr));
debug!("discr_cmt={}", discr_cmt.repr(mc.typer.tcx()));
debug!("discr_cmt={}", discr_cmt.repr(rcx.tcx()));
for arm in arms.iter() {
for &root_pat in arm.pats.iter() {
link_pattern(mc, discr_cmt.clone(), root_pat);
link_pattern(rcx, mc, discr_cmt.clone(), root_pat);
}
}
}
fn link_pattern(mc: mc::MemCategorizationContext<&Rcx>,
fn link_pattern(rcx: &Rcx,
mc: mc::MemCategorizationContext<Rcx>,
discr_cmt: mc::cmt,
root_pat: &ast::Pat) {
/*!
......@@ -1092,7 +1093,7 @@ fn link_pattern(mc: mc::MemCategorizationContext<&Rcx>,
// `ref x` pattern
ast::PatIdent(ast::BindByRef(mutbl), _, _) => {
link_region_from_node_type(
mc.typer, sub_pat.span, sub_pat.id,
rcx, sub_pat.span, sub_pat.id,
mutbl, sub_cmt);
}
......@@ -1100,7 +1101,7 @@ fn link_pattern(mc: mc::MemCategorizationContext<&Rcx>,
ast::PatVec(_, Some(slice_pat), _) => {
match mc.cat_slice_pattern(sub_cmt, slice_pat) {
Ok((slice_cmt, slice_mutbl, slice_r)) => {
link_region(mc.typer, sub_pat.span, slice_r,
link_region(rcx, sub_pat.span, slice_r,
ty::BorrowKind::from_mutbl(slice_mutbl),
slice_cmt);
}
......@@ -1122,25 +1123,25 @@ fn link_autoref(rcx: &Rcx,
*/
debug!("link_autoref(autoref={:?})", autoref);
let mc = mc::MemCategorizationContext { typer: rcx };
let mc = mc::MemCategorizationContext::new(rcx);
let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
debug!("expr_cmt={}", expr_cmt.repr(mc.typer.tcx()));
debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx()));
match *autoref {
ty::AutoPtr(r, m) => {
link_region(mc.typer, expr.span, r,
link_region(rcx, expr.span, r,
ty::BorrowKind::from_mutbl(m), expr_cmt);
}
ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => {
let cmt_index = mc.cat_index(expr, expr_cmt, autoderefs+1);
link_region(mc.typer, expr.span, r,
link_region(rcx, expr.span, r,
ty::BorrowKind::from_mutbl(m), cmt_index);
}
ty::AutoBorrowObj(r, m) => {
let cmt_deref = mc.cat_deref_obj(expr, expr_cmt);
link_region(mc.typer, expr.span, r,
link_region(rcx, expr.span, r,
ty::BorrowKind::from_mutbl(m), cmt_deref);
}
......@@ -1160,10 +1161,10 @@ fn link_by_ref(rcx: &Rcx,
let tcx = rcx.tcx();
debug!("link_by_ref(expr={}, callee_scope={})",
expr.repr(tcx), callee_scope);
let mc = mc::MemCategorizationContext { typer: rcx };
let mc = mc::MemCategorizationContext::new(rcx);
let expr_cmt = ignore_err!(mc.cat_expr(expr));
let region_min = ty::ReScope(callee_scope);
link_region(mc.typer, expr.span, region_min, ty::ImmBorrow, expr_cmt);
link_region(rcx, expr.span, region_min, ty::ImmBorrow, expr_cmt);
}
fn link_region_from_node_type(rcx: &Rcx,
......@@ -1306,9 +1307,9 @@ fn adjust_borrow_kind_for_assignment_lhs(rcx: &Rcx,
* expression.
*/
let mc = mc::MemCategorizationContext { typer: rcx };
let mc = mc::MemCategorizationContext::new(rcx);
let cmt = ignore_err!(mc.cat_expr(lhs));
adjust_upvar_borrow_kind_for_mut(mc.typer, cmt);
adjust_upvar_borrow_kind_for_mut(rcx, cmt);
}
fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
......
......@@ -469,7 +469,6 @@ fn visit_pat(&mut self, pattern: &Pat, env: ()) {
visit::walk_pat(self, pattern, env)
}
fn visit_expr(&mut self, expression: &Expr, env: ()) {
self.operation.visit_id(expression.id);
visit::walk_expr(self, expression, env)
......@@ -590,6 +589,30 @@ pub fn compute_id_range_for_inlined_item(item: &InlinedItem) -> IdRange {
visitor.result.get()
}
pub fn compute_id_range_for_fn_body(fk: &visit::FnKind,
decl: &FnDecl,
body: &Block,
sp: Span,
id: NodeId)
-> IdRange
{
/*!
* Computes the id range for a single fn body,
* ignoring nested items.
*/
let visitor = IdRangeComputingVisitor {
result: Cell::new(IdRange::max())
};
let mut id_visitor = IdVisitor {
operation: &visitor,
pass_through_items: false,
visited_outermost: false,
};
id_visitor.visit_fn(fk, decl, body, sp, id, ());
visitor.result.get()
}
pub fn is_item_impl(item: @ast::Item) -> bool {
match item.node {
ItemImpl(..) => true,
......
......@@ -25,13 +25,13 @@ fn test0(f: Foo, g: Noncopyable, h: Noncopyable) {
fn test1(f: Foo, g: Noncopyable, h: Noncopyable) {
// copying move-by-default fields from `f`, so move:
let _b = Foo {noncopyable: g, ..f};
let _c = Foo {noncopyable: h, ..f}; //~ ERROR use of moved value: `f`
let _c = Foo {noncopyable: h, ..f}; //~ ERROR use of partially moved value: `f`
}
fn test2(f: Foo, g: Noncopyable) {
// move non-copyable field
let _b = Foo {copied: 22, moved: ~23, ..f};
let _c = Foo {noncopyable: g, ..f}; //~ ERROR use of moved value: `f`
let _c = Foo {noncopyable: g, ..f}; //~ ERROR use of partially moved value: `f`
}
fn main() {}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册