auto merge of #9453 : pnkfelix/rust/fsk-further-syntax-visit-refactors, r=alexcrichton

r? anyone.

Part of #7081.

More refactorings of the syntax::visit::Visitor implementations, folding so-called "environments" into the visitor impl when the latter was previously a trivial unit struct.

As usual, this refactoring only applies when the environments are not actually carrying state that is meant to be pushed and popped as we traverse the expression.  (For an example where the environment *isn't* just passed through, see the `visit_fn` in `liveness.rs`.)

Got rid of a bit of @-allocation in borrowck.

Both cases should be pure-refactorings.
This commit is contained in:
bors 2013-09-24 02:26:06 -07:00
commit c7e672602e
8 changed files with 123 additions and 144 deletions

View File

@ -33,7 +33,7 @@ use util::ppaux::Repr;
#[deriving(Clone)]
struct CheckLoanCtxt<'self> {
bccx: @BorrowckCtxt,
bccx: &'self BorrowckCtxt,
dfcx_loans: &'self LoanDataFlow,
move_data: @move_data::FlowedMoveData,
all_loans: &'self [Loan],
@ -60,7 +60,7 @@ impl<'self> Visitor<()> for CheckLoanCtxt<'self> {
}
}
pub fn check_loans(bccx: @BorrowckCtxt,
pub fn check_loans(bccx: &BorrowckCtxt,
dfcx_loans: &LoanDataFlow,
move_data: move_data::FlowedMoveData,
all_loans: &[Loan],

View File

@ -22,7 +22,7 @@ use syntax::ast_util;
use syntax::codemap::Span;
use util::ppaux::{UserString};
pub fn gather_decl(bccx: @BorrowckCtxt,
pub fn gather_decl(bccx: &BorrowckCtxt,
move_data: &mut MoveData,
decl_id: ast::NodeId,
_decl_span: Span,
@ -31,7 +31,7 @@ pub fn gather_decl(bccx: @BorrowckCtxt,
move_data.add_move(bccx.tcx, loan_path, decl_id, Declared);
}
pub fn gather_move_from_expr(bccx: @BorrowckCtxt,
pub fn gather_move_from_expr(bccx: &BorrowckCtxt,
move_data: &mut MoveData,
move_expr: @ast::Expr,
cmt: mc::cmt) {
@ -39,7 +39,7 @@ pub fn gather_move_from_expr(bccx: @BorrowckCtxt,
MoveExpr(move_expr), cmt);
}
pub fn gather_move_from_pat(bccx: @BorrowckCtxt,
pub fn gather_move_from_pat(bccx: &BorrowckCtxt,
move_data: &mut MoveData,
move_pat: @ast::Pat,
cmt: mc::cmt) {
@ -47,7 +47,7 @@ pub fn gather_move_from_pat(bccx: @BorrowckCtxt,
MovePat(move_pat), cmt);
}
fn gather_move_from_expr_or_pat(bccx: @BorrowckCtxt,
fn gather_move_from_expr_or_pat(bccx: &BorrowckCtxt,
move_data: &mut MoveData,
move_id: ast::NodeId,
move_kind: MoveKind,
@ -66,7 +66,7 @@ fn gather_move_from_expr_or_pat(bccx: @BorrowckCtxt,
}
}
pub fn gather_captures(bccx: @BorrowckCtxt,
pub fn gather_captures(bccx: &BorrowckCtxt,
move_data: &mut MoveData,
closure_expr: @ast::Expr) {
let captured_vars = bccx.capture_map.get(&closure_expr.id);
@ -83,7 +83,7 @@ pub fn gather_captures(bccx: @BorrowckCtxt,
}
}
pub fn gather_assignment(bccx: @BorrowckCtxt,
pub fn gather_assignment(bccx: &BorrowckCtxt,
move_data: &mut MoveData,
assignment_id: ast::NodeId,
assignment_span: Span,
@ -96,7 +96,7 @@ pub fn gather_assignment(bccx: @BorrowckCtxt,
assignee_id);
}
fn check_is_legal_to_move_from(bccx: @BorrowckCtxt,
fn check_is_legal_to_move_from(bccx: &BorrowckCtxt,
cmt0: mc::cmt,
cmt: mc::cmt) -> bool {
match cmt.cat {

View File

@ -20,7 +20,7 @@ use syntax::ast;
use syntax::codemap::Span;
use util::ppaux::{note_and_explain_region};
pub fn guarantee_lifetime(bccx: @BorrowckCtxt,
pub fn guarantee_lifetime(bccx: &BorrowckCtxt,
item_scope_id: ast::NodeId,
root_scope_id: ast::NodeId,
span: Span,
@ -42,8 +42,8 @@ pub fn guarantee_lifetime(bccx: @BorrowckCtxt,
///////////////////////////////////////////////////////////////////////////
// Private
struct GuaranteeLifetimeContext {
bccx: @BorrowckCtxt,
struct GuaranteeLifetimeContext<'self> {
bccx: &'self BorrowckCtxt,
// the node id of the function body for the enclosing item
item_scope_id: ast::NodeId,
@ -58,7 +58,7 @@ struct GuaranteeLifetimeContext {
cmt_original: mc::cmt
}
impl GuaranteeLifetimeContext {
impl<'self> GuaranteeLifetimeContext<'self> {
fn tcx(&self) -> ty::ctxt {
self.bccx.tcx
}

View File

@ -64,8 +64,8 @@ mod gather_moves;
/// No good. Instead what will happen is that `root_ub` will be set to the
/// body of the while loop and we will refuse to root the pointer `&*x`
/// because it would have to be rooted for a region greater than `root_ub`.
struct GatherLoanCtxt {
bccx: @BorrowckCtxt,
struct GatherLoanCtxt<'self> {
bccx: &'self BorrowckCtxt,
id_range: id_range,
move_data: @mut move_data::MoveData,
all_loans: @mut ~[Loan],
@ -73,7 +73,7 @@ struct GatherLoanCtxt {
repeating_ids: ~[ast::NodeId]
}
impl visit::Visitor<()> for GatherLoanCtxt {
impl<'self> visit::Visitor<()> for GatherLoanCtxt<'self> {
fn visit_expr(&mut self, ex:@Expr, _:()) {
gather_loans_in_expr(self, ex);
}
@ -100,7 +100,7 @@ impl visit::Visitor<()> for GatherLoanCtxt {
fn visit_item(&mut self, _:@ast::item, _:()) { }
}
pub fn gather_loans(bccx: @BorrowckCtxt,
pub fn gather_loans(bccx: &BorrowckCtxt,
decl: &ast::fn_decl,
body: &ast::Block)
-> (id_range, @mut ~[Loan], @mut move_data::MoveData) {
@ -315,7 +315,7 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
}
}
impl GatherLoanCtxt {
impl<'self> GatherLoanCtxt<'self> {
pub fn tcx(&self) -> ty::ctxt { self.bccx.tcx }
pub fn push_repeating_id(&mut self, id: ast::NodeId) {
@ -532,7 +532,7 @@ impl GatherLoanCtxt {
// }
// }
fn check_mutability(bccx: @BorrowckCtxt,
fn check_mutability(bccx: &BorrowckCtxt,
borrow_span: Span,
cmt: mc::cmt,
req_mutbl: LoanMutability) {

View File

@ -23,7 +23,7 @@ pub enum RestrictionResult {
SafeIf(@LoanPath, ~[Restriction])
}
pub fn compute_restrictions(bccx: @BorrowckCtxt,
pub fn compute_restrictions(bccx: &BorrowckCtxt,
span: Span,
cmt: mc::cmt,
restr: RestrictionSet) -> RestrictionResult {
@ -39,13 +39,13 @@ pub fn compute_restrictions(bccx: @BorrowckCtxt,
///////////////////////////////////////////////////////////////////////////
// Private
struct RestrictionsContext {
bccx: @BorrowckCtxt,
struct RestrictionsContext<'self> {
bccx: &'self BorrowckCtxt,
span: Span,
cmt_original: mc::cmt
}
impl RestrictionsContext {
impl<'self> RestrictionsContext<'self> {
fn tcx(&self) -> ty::ctxt {
self.bccx.tcx
}

View File

@ -61,12 +61,10 @@ impl Clone for LoanDataFlowOperator {
pub type LoanDataFlow = DataFlowContext<LoanDataFlowOperator>;
struct BorrowckVisitor;
impl Visitor<@BorrowckCtxt> for BorrowckVisitor {
impl Visitor<()> for BorrowckCtxt {
fn visit_fn(&mut self, fk:&fn_kind, fd:&fn_decl,
b:&Block, s:Span, n:NodeId, e:@BorrowckCtxt) {
borrowck_fn(self, fk, fd, b, s, n, e);
b:&Block, s:Span, n:NodeId, _:()) {
borrowck_fn(self, fk, fd, b, s, n);
}
}
@ -78,7 +76,7 @@ pub fn check_crate(
capture_map: moves::CaptureMap,
crate: &ast::Crate) -> (root_map, write_guard_map)
{
let bccx = @BorrowckCtxt {
let mut bccx = BorrowckCtxt {
tcx: tcx,
method_map: method_map,
moves_map: moves_map,
@ -96,9 +94,9 @@ pub fn check_crate(
guaranteed_paths: 0,
}
};
let bccx = &mut bccx;
let mut v = BorrowckVisitor;
visit::walk_crate(&mut v, crate, bccx);
visit::walk_crate(bccx, crate, ());
if tcx.sess.borrowck_stats() {
io::println("--- borrowck stats ---");
@ -116,20 +114,19 @@ pub fn check_crate(
return (bccx.root_map, bccx.write_guard_map);
fn make_stat(bccx: &BorrowckCtxt, stat: uint) -> ~str {
fn make_stat(bccx: &mut BorrowckCtxt, stat: uint) -> ~str {
let stat_f = stat as float;
let total = bccx.stats.guaranteed_paths as float;
fmt!("%u (%.0f%%)", stat , stat_f * 100f / total)
}
}
fn borrowck_fn(v: &mut BorrowckVisitor,
fn borrowck_fn(this: &mut BorrowckCtxt,
fk: &visit::fn_kind,
decl: &ast::fn_decl,
body: &ast::Block,
sp: Span,
id: ast::NodeId,
this: @BorrowckCtxt) {
id: ast::NodeId) {
match fk {
&visit::fk_anon(*) |
&visit::fk_fn_block(*) => {
@ -166,7 +163,7 @@ fn borrowck_fn(v: &mut BorrowckVisitor,
}
}
visit::walk_fn(v, fk, decl, body, sp, id, this);
visit::walk_fn(this, fk, decl, body, sp, id, ());
}
// ----------------------------------------------------------------------

View File

@ -375,8 +375,6 @@ enum AnyVisitor {
NewVisitor(@mut visit::Visitor<()>),
}
type VCObj = @mut Visitor<@mut Context>;
struct Context {
// All known lint modes (string versions)
dict: @LintDict,

View File

@ -191,18 +191,16 @@ enum UseMode {
Read // Read no matter what the type.
}
struct ComputeModesVisitor;
impl visit::Visitor<VisitContext> for ComputeModesVisitor {
impl visit::Visitor<()> for VisitContext {
fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&fn_decl,
b:&Block, s:Span, n:NodeId, e:VisitContext) {
compute_modes_for_fn(*self, fk, fd, b, s, n, e);
b:&Block, s:Span, n:NodeId, _:()) {
compute_modes_for_fn(self, fk, fd, b, s, n);
}
fn visit_expr(&mut self, ex:@Expr, e:VisitContext) {
compute_modes_for_expr(*self, ex, e);
fn visit_expr(&mut self, ex:@Expr, _:()) {
compute_modes_for_expr(self, ex);
}
fn visit_local(&mut self, l:@Local, e:VisitContext) {
compute_modes_for_local(*self, l, e);
fn visit_local(&mut self, l:@Local, _:()) {
compute_modes_for_local(self, l);
}
}
@ -210,8 +208,7 @@ pub fn compute_moves(tcx: ty::ctxt,
method_map: method_map,
crate: &Crate) -> MoveMaps
{
let mut visitor = ComputeModesVisitor;
let visit_cx = VisitContext {
let mut visit_cx = VisitContext {
tcx: tcx,
method_map: method_map,
move_maps: MoveMaps {
@ -220,7 +217,8 @@ pub fn compute_moves(tcx: ty::ctxt,
moved_variables_set: @mut HashSet::new()
}
};
visit::walk_crate(&mut visitor, crate, visit_cx);
let visit_cx = &mut visit_cx;
visit::walk_crate(visit_cx, crate, ());
return visit_cx.move_maps;
}
@ -238,44 +236,40 @@ pub fn moved_variable_node_id_from_def(def: Def) -> Option<NodeId> {
///////////////////////////////////////////////////////////////////////////
// Expressions
fn compute_modes_for_local<'a>(v: ComputeModesVisitor,
local: @Local,
cx: VisitContext) {
fn compute_modes_for_local<'a>(cx: &mut VisitContext,
local: @Local) {
cx.use_pat(local.pat);
for &init in local.init.iter() {
cx.use_expr(init, Read, v);
cx.use_expr(init, Read);
}
}
fn compute_modes_for_fn(v: ComputeModesVisitor,
fn compute_modes_for_fn(cx: &mut VisitContext,
fk: &visit::fn_kind,
decl: &fn_decl,
body: &Block,
span: Span,
id: NodeId,
cx: VisitContext) {
let mut v = v;
id: NodeId) {
for a in decl.inputs.iter() {
cx.use_pat(a.pat);
}
visit::walk_fn(&mut v, fk, decl, body, span, id, cx);
visit::walk_fn(cx, fk, decl, body, span, id, ());
}
fn compute_modes_for_expr(v: ComputeModesVisitor,
expr: @Expr,
cx: VisitContext)
fn compute_modes_for_expr(cx: &mut VisitContext,
expr: @Expr)
{
cx.consume_expr(expr, v);
cx.consume_expr(expr);
}
impl VisitContext {
pub fn consume_exprs(&self, exprs: &[@Expr], visitor: ComputeModesVisitor) {
pub fn consume_exprs(&mut self, exprs: &[@Expr]) {
for expr in exprs.iter() {
self.consume_expr(*expr, visitor);
self.consume_expr(*expr);
}
}
pub fn consume_expr(&self, expr: @Expr, visitor: ComputeModesVisitor) {
pub fn consume_expr(&mut self, expr: @Expr) {
/*!
* Indicates that the value of `expr` will be consumed,
* meaning either copied or moved depending on its type.
@ -287,13 +281,13 @@ impl VisitContext {
let expr_ty = ty::expr_ty_adjusted(self.tcx, expr);
if ty::type_moves_by_default(self.tcx, expr_ty) {
self.move_maps.moves_map.insert(expr.id);
self.use_expr(expr, Move, visitor);
self.use_expr(expr, Move);
} else {
self.use_expr(expr, Read, visitor);
self.use_expr(expr, Read);
};
}
pub fn consume_block(&self, blk: &Block, visitor: ComputeModesVisitor) {
pub fn consume_block(&mut self, blk: &Block) {
/*!
* Indicates that the value of `blk` will be consumed,
* meaning either copied or moved depending on its type.
@ -302,19 +296,17 @@ impl VisitContext {
debug!("consume_block(blk.id=%?)", blk.id);
for stmt in blk.stmts.iter() {
let mut v = visitor;
v.visit_stmt(*stmt, *self);
self.visit_stmt(*stmt, ());
}
for tail_expr in blk.expr.iter() {
self.consume_expr(*tail_expr, visitor);
self.consume_expr(*tail_expr);
}
}
pub fn use_expr(&self,
pub fn use_expr(&mut self,
expr: @Expr,
expr_mode: UseMode,
visitor: ComputeModesVisitor) {
expr_mode: UseMode) {
/*!
* Indicates that `expr` is used with a given mode. This will
* in turn trigger calls to the subcomponents of `expr`.
@ -351,25 +343,23 @@ impl VisitContext {
}
ExprUnary(_, UnDeref, base) => { // *base
if !self.use_overloaded_operator(
expr, base, [], visitor)
if !self.use_overloaded_operator(expr, base, [])
{
// Moving out of *base moves out of base.
self.use_expr(base, comp_mode, visitor);
self.use_expr(base, comp_mode);
}
}
ExprField(base, _, _) => { // base.f
// Moving out of base.f moves out of base.
self.use_expr(base, comp_mode, visitor);
self.use_expr(base, comp_mode);
}
ExprIndex(_, lhs, rhs) => { // lhs[rhs]
if !self.use_overloaded_operator(
expr, lhs, [rhs], visitor)
if !self.use_overloaded_operator(expr, lhs, [rhs])
{
self.use_expr(lhs, comp_mode, visitor);
self.consume_expr(rhs, visitor);
self.use_expr(lhs, comp_mode);
self.consume_expr(rhs);
}
}
@ -394,20 +384,20 @@ impl VisitContext {
if mode == Move {
self.move_maps.moves_map.insert(callee.id);
}
self.use_expr(callee, mode, visitor);
self.use_fn_args(callee.id, *args, visitor);
self.use_expr(callee, mode);
self.use_fn_args(callee.id, *args);
}
ExprMethodCall(callee_id, rcvr, _, _, ref args, _) => { // callee.m(args)
// Implicit self is equivalent to & mode, but every
// other kind should be + mode.
self.use_receiver(rcvr, visitor);
self.use_fn_args(callee_id, *args, visitor);
self.use_receiver(rcvr);
self.use_fn_args(callee_id, *args);
}
ExprStruct(_, ref fields, opt_with) => {
for field in fields.iter() {
self.consume_expr(field.expr, visitor);
self.consume_expr(field.expr);
}
for with_expr in opt_with.iter() {
@ -449,22 +439,22 @@ impl VisitContext {
which defines the `Drop` trait",
with_ty.user_string(self.tcx)));
}
self.consume_expr(*with_expr, visitor);
self.consume_expr(*with_expr);
} else {
self.use_expr(*with_expr, Read, visitor);
self.use_expr(*with_expr, Read);
}
}
}
ExprTup(ref exprs) => {
self.consume_exprs(*exprs, visitor);
self.consume_exprs(*exprs);
}
ExprIf(cond_expr, ref then_blk, opt_else_expr) => {
self.consume_expr(cond_expr, visitor);
self.consume_block(then_blk, visitor);
self.consume_expr(cond_expr);
self.consume_block(then_blk);
for else_expr in opt_else_expr.iter() {
self.consume_expr(*else_expr, visitor);
self.consume_expr(*else_expr);
}
}
@ -472,27 +462,27 @@ impl VisitContext {
// We must do this first so that `arms_have_by_move_bindings`
// below knows which bindings are moves.
for arm in arms.iter() {
self.consume_arm(arm, visitor);
self.consume_arm(arm);
}
// The discriminant may, in fact, be partially moved
// if there are by-move bindings, but borrowck deals
// with that itself.
self.use_expr(discr, Read, visitor);
self.use_expr(discr, Read);
}
ExprParen(base) => {
// Note: base is not considered a *component* here, so
// use `expr_mode` not `comp_mode`.
self.use_expr(base, expr_mode, visitor);
self.use_expr(base, expr_mode);
}
ExprVec(ref exprs, _) => {
self.consume_exprs(*exprs, visitor);
self.consume_exprs(*exprs);
}
ExprAddrOf(_, base) => { // &base
self.use_expr(base, Read, visitor);
self.use_expr(base, Read);
}
ExprLogLevel |
@ -502,70 +492,67 @@ impl VisitContext {
ExprLit(*) => {}
ExprLoop(ref blk, _) => {
self.consume_block(blk, visitor);
self.consume_block(blk);
}
ExprWhile(cond_expr, ref blk) => {
self.consume_expr(cond_expr, visitor);
self.consume_block(blk, visitor);
self.consume_expr(cond_expr);
self.consume_block(blk);
}
ExprForLoop(*) => fail!("non-desugared expr_for_loop"),
ExprUnary(_, _, lhs) => {
if !self.use_overloaded_operator(
expr, lhs, [], visitor)
if !self.use_overloaded_operator(expr, lhs, [])
{
self.consume_expr(lhs, visitor);
self.consume_expr(lhs);
}
}
ExprBinary(_, _, lhs, rhs) => {
if !self.use_overloaded_operator(
expr, lhs, [rhs], visitor)
if !self.use_overloaded_operator(expr, lhs, [rhs])
{
self.consume_expr(lhs, visitor);
self.consume_expr(rhs, visitor);
self.consume_expr(lhs);
self.consume_expr(rhs);
}
}
ExprBlock(ref blk) => {
self.consume_block(blk, visitor);
self.consume_block(blk);
}
ExprRet(ref opt_expr) => {
for expr in opt_expr.iter() {
self.consume_expr(*expr, visitor);
self.consume_expr(*expr);
}
}
ExprAssign(lhs, rhs) => {
self.use_expr(lhs, Read, visitor);
self.consume_expr(rhs, visitor);
self.use_expr(lhs, Read);
self.consume_expr(rhs);
}
ExprCast(base, _) => {
self.consume_expr(base, visitor);
self.consume_expr(base);
}
ExprAssignOp(_, _, lhs, rhs) => {
// FIXME(#4712) --- Overloaded operators?
//
// if !self.use_overloaded_operator(
// expr, DoDerefArgs, lhs, [rhs], visitor)
// if !self.use_overloaded_operator(expr, DoDerefArgs, lhs, [rhs])
// {
self.consume_expr(lhs, visitor);
self.consume_expr(rhs, visitor);
self.consume_expr(lhs);
self.consume_expr(rhs);
// }
}
ExprRepeat(base, count, _) => {
self.consume_expr(base, visitor);
self.consume_expr(count, visitor);
self.consume_expr(base);
self.consume_expr(count);
}
ExprDoBody(base) => {
self.use_expr(base, comp_mode, visitor);
self.use_expr(base, comp_mode);
}
ExprFnBlock(ref decl, ref body) => {
@ -574,11 +561,11 @@ impl VisitContext {
}
let cap_vars = self.compute_captures(expr.id);
self.move_maps.capture_map.insert(expr.id, cap_vars);
self.consume_block(body, visitor);
self.consume_block(body);
}
ExprVstore(base, _) => {
self.use_expr(base, comp_mode, visitor);
self.use_expr(base, comp_mode);
}
ExprMac(*) => {
@ -589,40 +576,39 @@ impl VisitContext {
}
}
pub fn use_overloaded_operator(&self,
pub fn use_overloaded_operator(&mut self,
expr: &Expr,
receiver_expr: @Expr,
arg_exprs: &[@Expr],
visitor: ComputeModesVisitor)
arg_exprs: &[@Expr])
-> bool {
if !self.method_map.contains_key(&expr.id) {
return false;
}
self.use_receiver(receiver_expr, visitor);
self.use_receiver(receiver_expr);
// for overloaded operatrs, we are always passing in a
// borrowed pointer, so it's always read mode:
for arg_expr in arg_exprs.iter() {
self.use_expr(*arg_expr, Read, visitor);
self.use_expr(*arg_expr, Read);
}
return true;
}
pub fn consume_arm(&self, arm: &Arm, visitor: ComputeModesVisitor) {
pub fn consume_arm(&mut self, arm: &Arm) {
for pat in arm.pats.iter() {
self.use_pat(*pat);
}
for guard in arm.guard.iter() {
self.consume_expr(*guard, visitor);
self.consume_expr(*guard);
}
self.consume_block(&arm.body, visitor);
self.consume_block(&arm.body);
}
pub fn use_pat(&self, pat: @Pat) {
pub fn use_pat(&mut self, pat: @Pat) {
/*!
*
* Decides whether each binding in a pattern moves the value
@ -651,28 +637,26 @@ impl VisitContext {
}
}
pub fn use_receiver(&self,
receiver_expr: @Expr,
visitor: ComputeModesVisitor) {
self.use_fn_arg(receiver_expr, visitor);
pub fn use_receiver(&mut self,
receiver_expr: @Expr) {
self.use_fn_arg(receiver_expr);
}
pub fn use_fn_args(&self,
pub fn use_fn_args(&mut self,
_: NodeId,
arg_exprs: &[@Expr],
visitor: ComputeModesVisitor) {
arg_exprs: &[@Expr]) {
//! Uses the argument expressions.
for arg_expr in arg_exprs.iter() {
self.use_fn_arg(*arg_expr, visitor);
self.use_fn_arg(*arg_expr);
}
}
pub fn use_fn_arg(&self, arg_expr: @Expr, visitor: ComputeModesVisitor) {
pub fn use_fn_arg(&mut self, arg_expr: @Expr) {
//! Uses the argument.
self.consume_expr(arg_expr, visitor)
self.consume_expr(arg_expr)
}
pub fn arms_have_by_move_bindings(&self,
pub fn arms_have_by_move_bindings(&mut self,
moves_map: MovesMap,
arms: &[Arm])
-> Option<@Pat> {
@ -693,7 +677,7 @@ impl VisitContext {
ret
}
pub fn compute_captures(&self, fn_expr_id: NodeId) -> @[CaptureVar] {
pub fn compute_captures(&mut self, fn_expr_id: NodeId) -> @[CaptureVar] {
debug!("compute_capture_vars(fn_expr_id=%?)", fn_expr_id);
let _indenter = indenter();