Skip to content

Implement moved!(...) to inform stateful when something is moved #2

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 3 commits into from
Closed
Show file tree
Hide file tree
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
9 changes: 3 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@
#![allow(non_shorthand_field_patterns)]

#[generator]
fn gen<'a, T>(items: &'a [T]) -> &'a T {
for item in items.iter() {
yield_!(item);
};
fn gen(item: String) -> String {
yield_!(moved!(item));
}

fn main() {
let items = &[1, 2, 3];
for value in gen(items) {
for value in gen(String::from("wee")) {
println!("{}", value);
}
}
2 changes: 1 addition & 1 deletion src/mar/build/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ impl<'a, 'b: 'a> Builder<'a, 'b> {
extent: CodeExtent,
block: BasicBlock,
ast_block: &ast::Block) -> BasicBlock {
self.in_scope(extent, block, |this| {
self.in_scope(extent, ast_block.span, block, |this| {
// FIXME: handle trailing exprs
this.stmts(extent, block, &ast_block.stmts[..])
})
Expand Down
10 changes: 8 additions & 2 deletions src/mar/build/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ impl CFG {
}

pub fn start_new_block(&mut self,
span: Span,
name: Option<&'static str>,
decls: Vec<(VarDecl, ast::Ident)>) -> BasicBlock {
let node_index = self.basic_blocks.len();
self.basic_blocks.push(BasicBlockData::new(name, decls, None));
self.basic_blocks.push(BasicBlockData::new(span, name, decls, None));
BasicBlock::new(node_index)
}

Expand All @@ -37,11 +38,16 @@ impl CFG {
});
}

pub fn terminate(&mut self, block: BasicBlock, kind: TerminatorKind) {
pub fn terminate(&mut self,
span: Span,
block: BasicBlock,
kind: TerminatorKind) {
assert!(self.block_data(block).terminator.is_none(),
"terminate: block {:?} already has a terminator set", block);

let block_data = self.block_data_mut(block);
block_data.terminator = Some(Terminator {
span: span,
kind: kind,
});
}
Expand Down
66 changes: 44 additions & 22 deletions src/mar/build/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ impl<'a, 'b: 'a> Builder<'a, 'b> {
extent: CodeExtent,
block: BasicBlock,
expr: &P<ast::Expr>) -> BasicBlock {
let expr = self.expand_moved(expr);

// There's no reason for us to transform expressions if they don't contain any transitions.
if !self.contains_transition(expr) {
return self.into(extent, block, expr.clone());
if !self.contains_transition(&expr) {
return self.into(extent, block, expr);
}

match expr.node {
Expand All @@ -38,30 +39,42 @@ impl<'a, 'b: 'a> Builder<'a, 'b> {
}
ExprKind::Ret(None) => {
self.exit_scope(expr.span, extent, block, END_BLOCK);
self.start_new_block(Some("AfterReturn"))
self.start_new_block(expr.span, Some("AfterReturn"))
}
ExprKind::If(ref cond_expr, ref then_expr, ref else_expr) => {
// FIXME: This does not handle the `cond_expr` containing a transition yet.

let mut then_block = self.start_new_block(Some("Then"));
let mut else_block = self.start_new_block(Some("Else"));
let mut then_block = self.start_new_block(expr.span, Some("Then"));
let mut else_block = self.start_new_block(expr.span, Some("Else"));

self.terminate(block, TerminatorKind::If {
self.terminate(expr.span, block, TerminatorKind::If {
cond: cond_expr.clone(),
targets: (then_block, else_block),
});

then_block = self.into(extent, then_block, then_expr);
else_block = self.into(extent, else_block, else_expr);

let join_block = self.start_new_block(Some("IfJoin"));
self.terminate(then_block, TerminatorKind::Goto { target: join_block });
self.terminate(else_block, TerminatorKind::Goto { target: join_block });
let join_block = self.start_new_block(expr.span, Some("IfJoin"));

self.terminate(
then_expr.span,
then_block,
TerminatorKind::Goto { target: join_block });

self.terminate(
match *else_expr {
Some(ref expr) => expr.span,
None => expr.span,
},
else_block,
TerminatorKind::Goto { target: join_block });

join_block
}
ExprKind::Match(ref discriminant, ref arms) => {
self.match_expr(extent, expr.span, block, discriminant.clone(), &arms)

}
ExprKind::Loop(ref body, label) => {
self.expr_loop(extent, block, None, body, label)
Expand All @@ -81,7 +94,7 @@ impl<'a, 'b: 'a> Builder<'a, 'b> {
// }
// }
// }
let builder = AstBuilder::new();
let builder = AstBuilder::new().span(expr.span);

// ::std::iter::IntoIterator::into_iter($expr)
let into_iter = builder.expr().call()
Expand Down Expand Up @@ -161,7 +174,7 @@ impl<'a, 'b: 'a> Builder<'a, 'b> {
// $pat => $then_block,
// _ => $else_block,
// }
let builder = AstBuilder::new();
let builder = AstBuilder::new().span(expr.span);

// $then_pat => $then_block
let then_arm = builder.arm()
Expand Down Expand Up @@ -195,7 +208,7 @@ impl<'a, 'b: 'a> Builder<'a, 'b> {
// _ => break,
// }
// }
let builder = AstBuilder::new();
let builder = AstBuilder::new().span(expr.span);

// $pat => $then_block
let then_arm = builder.arm()
Expand Down Expand Up @@ -257,31 +270,40 @@ impl<'a, 'b: 'a> Builder<'a, 'b> {
// | |
// +--------------------------+

let loop_block = self.start_new_block(Some("Loop"));
let exit_block = self.start_new_block(Some("LoopExit"));
let loop_block = self.start_new_block(body.span, Some("Loop"));
let exit_block = self.start_new_block(body.span, Some("LoopExit"));

// start the loop
self.terminate(block, TerminatorKind::Goto { target: loop_block });
self.terminate(
body.span,
block,
TerminatorKind::Goto { target: loop_block });

self.in_loop_scope(extent, label, loop_block, exit_block, |this| {
// conduct the test, if necessary
let body_block;
if let Some(cond_expr) = condition {
// FIXME: This does not yet handle the expr having a transition.

body_block = this.start_new_block(Some("LoopBody"));
body_block = this.start_new_block(cond_expr.span, Some("LoopBody"));

this.terminate(loop_block, TerminatorKind::If {
cond: cond_expr.clone(),
targets: (body_block, exit_block),
});
this.terminate(
cond_expr.span,
loop_block,
TerminatorKind::If {
cond: cond_expr.clone(),
targets: (body_block, exit_block),
});
} else {
body_block = loop_block;
}

// execute the body, branching back to the test
let body_block_end = this.into(extent, body_block, body);
this.terminate(body_block_end, TerminatorKind::Goto { target: loop_block });
this.terminate(
body.span,
body_block_end,
TerminatorKind::Goto { target: loop_block });

// final point is exit_block
exit_block
Expand All @@ -303,6 +325,6 @@ impl<'a, 'b: 'a> Builder<'a, 'b> {
// Even though we've exited `block`, there could be code following the break/continue. To
// keep rust happy, we'll create a new block that has an edge to `block`, even though
// control will never actually flow into this block.
self.start_new_block(Some("AfterBreakOrContinue"))
self.start_new_block(span, Some("AfterBreakOrContinue"))
}
}
6 changes: 4 additions & 2 deletions src/mar/build/mac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ impl<'a, 'b: 'a> Builder<'a, 'b> {
let (expr, idents) = parse_mac_yield(self.cx, mac);
assert!(idents.is_empty());

let next_block = self.start_new_block(Some("AfterYield"));
let expr = self.expand_moved(&expr);

self.terminate(block, TerminatorKind::Yield {
let next_block = self.start_new_block(mac.span, Some("AfterYield"));

self.terminate(mac.span, block, TerminatorKind::Yield {
expr: expr.clone(),
target: next_block,
});
Expand Down
13 changes: 6 additions & 7 deletions src/mar/build/matches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,25 @@ impl<'a, 'b: 'a> Builder<'a, 'b> {
Arm {
pats: arm.pats.clone(),
guard: arm.guard.clone(),
block: self.start_new_block(Some("Arm")),
block: self.start_new_block(span, Some("Arm")),
}
})
.collect::<Vec<_>>();

let join_block = self.start_new_block(Some("MatchJoin"));
let join_block = self.start_new_block(span, Some("MatchJoin"));

for (arm, target) in arms.iter().zip(targets.iter()) {
let arm_block = self.in_scope(extent, block, |this| {
this.add_decls_from_pats(span,
extent,
let arm_block = self.in_scope(extent, span, block, |this| {
this.add_decls_from_pats(extent,
target.block,
arm.pats.iter());
this.expr(extent, target.block, &arm.body)
});

self.terminate(arm_block, TerminatorKind::Goto { target: join_block });
self.terminate(span, arm_block, TerminatorKind::Goto { target: join_block });
}

self.terminate(block, TerminatorKind::Match {
self.terminate(span, block, TerminatorKind::Match {
discr: discriminant.clone(),
targets: targets,
});
Expand Down
15 changes: 8 additions & 7 deletions src/mar/build/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use mar::repr::*;
use syntax::ast::{self, ItemKind};
use syntax::codemap::Span;
use syntax::ext::base::ExtCtxt;
use syntax::fold;
use syntax::ptr::P;
Expand Down Expand Up @@ -50,16 +51,15 @@ pub fn construct(cx: &ExtCtxt, item: P<ast::Item>) -> Result<Mar, Error> {

let extent = builder.start_new_extent();

assert_eq!(builder.start_new_block(Some("Start")), START_BLOCK);
assert_eq!(builder.start_new_block(Some("End")), END_BLOCK);
assert_eq!(builder.start_new_block(item.span, Some("Start")), START_BLOCK);
assert_eq!(builder.start_new_block(item.span, Some("End")), END_BLOCK);

let mut block = START_BLOCK;

builder.push_scope(extent, block);

// Register the arguments as declarations.
builder.add_decls_from_pats(
item.span,
extent,
block,
fn_decl.inputs.iter().map(|arg| &arg.pat));
Expand All @@ -70,8 +70,8 @@ pub fn construct(cx: &ExtCtxt, item: P<ast::Item>) -> Result<Mar, Error> {

builder.pop_scope(extent, block);

builder.terminate(block, TerminatorKind::Goto { target: END_BLOCK });
builder.terminate(END_BLOCK, TerminatorKind::Return);
builder.terminate(item.span, block, TerminatorKind::Goto { target: END_BLOCK });
builder.terminate(item.span, END_BLOCK, TerminatorKind::Return);

// The drops seem redundant, we are always moving values.
for bb in builder.cfg.basic_blocks.iter_mut() {
Expand Down Expand Up @@ -129,9 +129,9 @@ fn assign_node_ids(item: P<ast::Item>) -> P<ast::Item> {
}

impl<'a, 'b: 'a> Builder<'a, 'b> {
pub fn start_new_block(&mut self, name: Option<&'static str>) -> BasicBlock {
pub fn start_new_block(&mut self, span: Span, name: Option<&'static str>) -> BasicBlock {
let decls = self.find_live_decls();
self.cfg.start_new_block(name, decls)
self.cfg.start_new_block(span, name, decls)
}

pub fn start_new_extent(&mut self) -> CodeExtent {
Expand All @@ -156,6 +156,7 @@ mod expr;
mod into;
mod mac;
mod matches;
mod moved;
mod scope;
mod stmt;
mod transition;
86 changes: 86 additions & 0 deletions src/mar/build/moved.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use aster::AstBuilder;
use mar::build::Builder;
use syntax::ast;
use syntax::ext::base::ExtCtxt;
use syntax::ext::tt::transcribe::new_tt_reader;
use syntax::fold::{self, Folder};
use syntax::parse::parser::Parser;
use syntax::ptr::P;

impl<'a, 'b: 'a> Builder<'a, 'b> {
pub fn expand_moved(&mut self, expr: &P<ast::Expr>) -> P<ast::Expr> {
let mut expander = ExpandMac {
cx: self.cx,
moved_idents: vec![],
};

let expr = expander.fold_expr(expr.clone());

for moved_ident in expander.moved_idents {
if let Some(decl) = self.find_decl(moved_ident) {
self.schedule_move(decl);
} else {
self.cx.span_bug(
expr.span,
&format!("ident {:?} not in scope", moved_ident));
}
}

expr
}
}

struct ExpandMac<'a, 'b: 'a> {
cx: &'a ExtCtxt<'b>,
moved_idents: Vec<ast::Ident>,
}

impl<'a, 'b> ExpandMac<'a, 'b> {
fn parse_mac_moved(&mut self, mac: &ast::Mac) -> P<ast::Expr> {
let rdr = new_tt_reader(
&self.cx.parse_sess().span_diagnostic,
None,
None,
mac.node.tts.clone());

let mut parser = Parser::new(
self.cx.parse_sess(),
self.cx.cfg(),
Box::new(rdr));

let ident = panictry!(parser.parse_ident());
self.moved_idents.push(ident);

let expr = AstBuilder::new().expr()
.span(mac.span)
.id(ident);

expr
}
}

impl<'a, 'b> Folder for ExpandMac<'a, 'b> {
fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
match expr.node {
ast::ExprKind::Mac(ref mac) if is_moved_path(&mac.node.path) => {
return self.parse_mac_moved(&mac);
}
_ => {}
}

expr.map(|expr| fold::noop_fold_expr(expr, self))
}

fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
fold::noop_fold_mac(mac, self)
}
}

fn is_moved_path(path: &ast::Path) -> bool {
let builder = AstBuilder::new();
let yield_ = builder.path()
.id("moved")
.build();

!path.global && path.segments == yield_.segments
}
Loading