auto merge of #9310 : pcwalton/rust/at-fn, r=pcwalton

r? @brson
This commit is contained in:
bors 2013-09-23 19:20:58 -07:00
commit d062de8aa4
147 changed files with 2900 additions and 2975 deletions

View File

@ -1469,34 +1469,6 @@ cannot be stored in data structures or returned from
functions. Despite these limitations, stack closures are used
pervasively in Rust code.
## Managed closures
When you need to store a closure in a data structure, a stack closure
will not do, since the compiler will refuse to let you store it. For
this purpose, Rust provides a type of closure that has an arbitrary
lifetime, written `@fn` (boxed closure, analogous to the `@` pointer
type described earlier). This type of closure *is* first-class.
A managed closure does not directly access its environment, but merely
copies out the values that it closes over into a private data
structure. This means that it can not assign to these variables, and
cannot observe updates to them.
This code creates a closure that adds a given string to its argument,
returns it from a function, and then calls it:
~~~~
fn mk_appender(suffix: ~str) -> @fn(~str) -> ~str {
// The compiler knows that we intend this closure to be of type @fn
return |s| s + suffix;
}
fn main() {
let shout = mk_appender(~"!");
println(shout(~"hey ho, let's go"));
}
~~~~
## Owned closures
Owned closures, written `~fn` in analogy to the `~` pointer type,

View File

@ -36,37 +36,39 @@
* still held if needed.
*/
use std::option;
use std::ptr;
use std::routine::Runnable;
use std::util;
/**
* The type representing a foreign chunk of memory
*
*/
pub struct CVec<T> {
priv base: *mut T,
priv len: uint,
priv rsrc: @DtorRes
priv rsrc: @DtorRes,
}
struct DtorRes {
dtor: Option<@fn()>,
dtor: Option<~Runnable>,
}
#[unsafe_destructor]
impl Drop for DtorRes {
fn drop(&mut self) {
match self.dtor {
option::None => (),
option::Some(f) => f()
let dtor = util::replace(&mut self.dtor, None);
match dtor {
None => (),
Some(f) => f.run()
}
}
}
fn DtorRes(dtor: Option<@fn()>) -> DtorRes {
DtorRes {
dtor: dtor
impl DtorRes {
fn new(dtor: Option<~Runnable>) -> DtorRes {
DtorRes {
dtor: dtor,
}
}
}
@ -83,10 +85,10 @@ fn DtorRes(dtor: Option<@fn()>) -> DtorRes {
* * len - The number of elements in the buffer
*/
pub unsafe fn CVec<T>(base: *mut T, len: uint) -> CVec<T> {
return CVec{
return CVec {
base: base,
len: len,
rsrc: @DtorRes(option::None)
rsrc: @DtorRes::new(None)
};
}
@ -101,12 +103,12 @@ pub unsafe fn CVec<T>(base: *mut T, len: uint) -> CVec<T> {
* * dtor - A function to run when the value is destructed, useful
* for freeing the buffer, etc.
*/
pub unsafe fn c_vec_with_dtor<T>(base: *mut T, len: uint, dtor: @fn())
-> CVec<T> {
pub unsafe fn c_vec_with_dtor<T>(base: *mut T, len: uint, dtor: ~Runnable)
-> CVec<T> {
return CVec{
base: base,
len: len,
rsrc: @DtorRes(option::Some(dtor))
rsrc: @DtorRes::new(Some(dtor))
};
}
@ -153,6 +155,20 @@ mod tests {
use std::libc::*;
use std::libc;
use std::routine::Runnable;
struct LibcFree {
mem: *c_void,
}
impl Runnable for LibcFree {
#[fixed_stack_segment]
fn run(~self) {
unsafe {
libc::free(self.mem)
}
}
}
fn malloc(n: size_t) -> CVec<u8> {
#[fixed_stack_segment];
@ -163,12 +179,11 @@ mod tests {
assert!(mem as int != 0);
return c_vec_with_dtor(mem as *mut u8, n as uint, || f(mem));
}
fn f(mem: *c_void) {
#[fixed_stack_segment]; #[inline(never)];
unsafe { libc::free(mem) }
return c_vec_with_dtor(mem as *mut u8,
n as uint,
~LibcFree {
mem: mem,
} as ~Runnable);
}
}

View File

@ -30,7 +30,7 @@ pub mod rustrt {
macro_rules! locked {
($expr:expr) => {
unsafe {
{
// FIXME #9105: can't use a static mutex in pure Rust yet.
rustrt::rust_take_linenoise_lock();
let x = $expr;
@ -43,20 +43,27 @@ macro_rules! locked {
/// Add a line to history
pub fn add_history(line: &str) -> bool {
do line.with_c_str |buf| {
(locked!(rustrt::linenoiseHistoryAdd(buf))) == 1 as c_int
unsafe {
(locked!(rustrt::linenoiseHistoryAdd(buf))) == 1 as c_int
}
}
}
/// Set the maximum amount of lines stored
pub fn set_history_max_len(len: int) -> bool {
(locked!(rustrt::linenoiseHistorySetMaxLen(len as c_int))) == 1 as c_int
unsafe {
(locked!(rustrt::linenoiseHistorySetMaxLen(len as c_int))) == 1
as c_int
}
}
/// Save line history to a file
pub fn save_history(file: &str) -> bool {
do file.with_c_str |buf| {
// 0 on success, -1 on failure
(locked!(rustrt::linenoiseHistorySave(buf))) == 0 as c_int
unsafe {
(locked!(rustrt::linenoiseHistorySave(buf))) == 0 as c_int
}
}
}
@ -64,14 +71,18 @@ pub fn save_history(file: &str) -> bool {
pub fn load_history(file: &str) -> bool {
do file.with_c_str |buf| {
// 0 on success, -1 on failure
(locked!(rustrt::linenoiseHistoryLoad(buf))) == 0 as c_int
unsafe {
(locked!(rustrt::linenoiseHistoryLoad(buf))) == 0 as c_int
}
}
}
/// Print out a prompt and then wait for input and return it
pub fn read(prompt: &str) -> Option<~str> {
do prompt.with_c_str |buf| {
let line = locked!(rustrt::linenoise(buf));
let line = unsafe {
locked!(rustrt::linenoise(buf))
};
if line.is_null() { None }
else {
@ -88,9 +99,13 @@ pub fn read(prompt: &str) -> Option<~str> {
}
}
pub type CompletionCb = @fn(~str, @fn(~str));
/// The callback used to perform completions.
pub trait CompletionCb {
/// Performs a completion.
fn complete(&self, line: ~str, suggestion: &fn(~str));
}
local_data_key!(complete_key: CompletionCb)
local_data_key!(complete_key: @CompletionCb)
/// Bind to the main completion callback in the current task.
///
@ -98,25 +113,22 @@ local_data_key!(complete_key: CompletionCb)
/// other than the closure that it receives as its second
/// argument. Calling such a function will deadlock on the mutex used
/// to ensure that the calls are thread-safe.
pub fn complete(cb: CompletionCb) {
pub unsafe fn complete(cb: @CompletionCb) {
local_data::set(complete_key, cb);
extern fn callback(c_line: *c_char, completions: *()) {
extern fn callback(line: *c_char, completions: *()) {
do local_data::get(complete_key) |opt_cb| {
// only fetch completions if a completion handler has been
// registered in the current task.
match opt_cb {
None => {},
None => {}
Some(cb) => {
let line = unsafe { str::raw::from_c_str(c_line) };
do (*cb)(line) |suggestion| {
do suggestion.with_c_str |buf| {
// This isn't locked, because `callback` gets
// called inside `rustrt::linenoise`, which
// *is* already inside the mutex, so
// re-locking would be a deadlock.
unsafe {
rustrt::linenoiseAddCompletion(completions, buf);
unsafe {
do cb.complete(str::raw::from_c_str(line))
|suggestion| {
do suggestion.with_c_str |buf| {
rustrt::linenoiseAddCompletion(completions,
buf);
}
}
}

View File

@ -807,11 +807,6 @@ pub fn filter_tests(
}
}
struct TestFuture {
test: TestDesc,
wait: @fn() -> TestResult,
}
pub fn run_test(force_ignore: bool,
test: TestDescAndFn,
monitor_ch: SharedChan<MonitorMsg>) {

View File

@ -113,8 +113,8 @@ pub fn build_configuration(sess: Session) ->
}
// Convert strings provided as --cfg [cfgspec] into a crate_cfg
fn parse_cfgspecs(cfgspecs: ~[~str],
demitter: diagnostic::Emitter) -> ast::CrateConfig {
fn parse_cfgspecs(cfgspecs: ~[~str], demitter: @diagnostic::Emitter)
-> ast::CrateConfig {
do cfgspecs.move_iter().map |s| {
let sess = parse::new_parse_sess(Some(demitter));
parse::parse_meta_from_source_str(@"cfgspec", s.to_managed(), ~[], sess)
@ -439,15 +439,70 @@ pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
phase_6_link_output(sess, &trans, outputs);
}
pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, input: &input,
ppm: PpMode) {
struct IdentifiedAnnotation {
contents: (),
}
fn ann_paren_for_expr(node: pprust::ann_node) {
impl pprust::pp_ann for IdentifiedAnnotation {
fn pre(&self, node: pprust::ann_node) {
match node {
pprust::node_expr(s, _) => pprust::popen(s),
_ => ()
pprust::node_expr(s, _) => pprust::popen(s),
_ => ()
}
}
fn post(&self, node: pprust::ann_node) {
match node {
pprust::node_item(s, item) => {
pp::space(s.s);
pprust::synth_comment(s, item.id.to_str());
}
pprust::node_block(s, ref blk) => {
pp::space(s.s);
pprust::synth_comment(s, ~"block " + blk.id.to_str());
}
pprust::node_expr(s, expr) => {
pp::space(s.s);
pprust::synth_comment(s, expr.id.to_str());
pprust::pclose(s);
}
pprust::node_pat(s, pat) => {
pp::space(s.s);
pprust::synth_comment(s, ~"pat " + pat.id.to_str());
}
}
}
}
struct TypedAnnotation {
analysis: CrateAnalysis,
}
impl pprust::pp_ann for TypedAnnotation {
fn pre(&self, node: pprust::ann_node) {
match node {
pprust::node_expr(s, _) => pprust::popen(s),
_ => ()
}
}
fn post(&self, node: pprust::ann_node) {
let tcx = self.analysis.ty_cx;
match node {
pprust::node_expr(s, expr) => {
pp::space(s.s);
pp::word(s.s, "as");
pp::space(s.s);
pp::word(s.s, ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr)));
pprust::pclose(s);
}
_ => ()
}
}
}
pub fn pretty_print_input(sess: Session,
cfg: ast::CrateConfig,
input: &input,
ppm: PpMode) {
fn ann_typed_post(tcx: ty::ctxt, node: pprust::ann_node) {
match node {
pprust::node_expr(s, expr) => {
@ -460,28 +515,6 @@ pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, input: &input,
_ => ()
}
}
fn ann_identified_post(node: pprust::ann_node) {
match node {
pprust::node_item(s, item) => {
pp::space(s.s);
pprust::synth_comment(s, item.id.to_str());
}
pprust::node_block(s, ref blk) => {
pp::space(s.s);
pprust::synth_comment(
s, ~"block " + blk.id.to_str());
}
pprust::node_expr(s, expr) => {
pp::space(s.s);
pprust::synth_comment(s, expr.id.to_str());
pprust::pclose(s);
}
pprust::node_pat(s, pat) => {
pp::space(s.s);
pprust::synth_comment(s, ~"pat " + pat.id.to_str());
}
}
}
let crate = phase_1_parse_input(sess, cfg.clone(), input);
@ -494,28 +527,30 @@ pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, input: &input,
let annotation = match ppm {
PpmIdentified | PpmExpandedIdentified => {
pprust::pp_ann {
pre: ann_paren_for_expr,
post: ann_identified_post
}
@IdentifiedAnnotation {
contents: (),
} as @pprust::pp_ann
}
PpmTyped => {
let analysis = phase_3_run_analysis_passes(sess, crate);
pprust::pp_ann {
pre: ann_paren_for_expr,
post: |a| ann_typed_post(analysis.ty_cx, a)
}
@TypedAnnotation {
analysis: analysis
} as @pprust::pp_ann
}
_ => pprust::no_ann()
_ => @pprust::no_ann::new() as @pprust::pp_ann,
};
let src = sess.codemap.get_filemap(source_name(input)).src;
do io::with_str_reader(src) |rdr| {
pprust::print_crate(sess.codemap, token::get_ident_interner(),
sess.span_diagnostic, crate,
pprust::print_crate(sess.codemap,
token::get_ident_interner(),
sess.span_diagnostic,
crate,
source_name(input),
rdr, io::stdout(),
annotation, is_expanded);
rdr,
io::stdout(),
annotation,
is_expanded);
}
}
@ -554,8 +589,8 @@ static architecture_abis : &'static [(&'static str, abi::Architecture)] = &'stat
("mips", abi::Mips)];
pub fn build_target_config(sopts: @session::options,
demitter: diagnostic::Emitter)
-> @session::config {
demitter: @diagnostic::Emitter)
-> @session::config {
let os = match get_os(sopts.target_triple) {
Some(os) => os,
None => early_error(demitter, ~"unknown operating system")
@ -603,8 +638,8 @@ pub fn host_triple() -> ~str {
pub fn build_session_options(binary: @str,
matches: &getopts::Matches,
demitter: diagnostic::Emitter)
-> @session::options {
demitter: @diagnostic::Emitter)
-> @session::options {
let crate_type = if matches.opt_present("lib") {
session::lib_crate
} else if matches.opt_present("bin") {
@ -777,8 +812,8 @@ pub fn build_session_options(binary: @str,
return sopts;
}
pub fn build_session(sopts: @session::options,
demitter: diagnostic::Emitter) -> Session {
pub fn build_session(sopts: @session::options, demitter: @diagnostic::Emitter)
-> Session {
let codemap = @codemap::CodeMap::new();
let diagnostic_handler =
diagnostic::mk_handler(Some(demitter));
@ -789,9 +824,9 @@ pub fn build_session(sopts: @session::options,
pub fn build_session_(sopts: @session::options,
cm: @codemap::CodeMap,
demitter: diagnostic::Emitter,
demitter: @diagnostic::Emitter,
span_diagnostic_handler: @mut diagnostic::span_handler)
-> Session {
-> Session {
let target_cfg = build_target_config(sopts, demitter);
let p_s = parse::new_parse_sess_special_handler(span_diagnostic_handler,
cm);
@ -1000,8 +1035,8 @@ pub fn build_output_filenames(input: &input,
}
}
pub fn early_error(emitter: diagnostic::Emitter, msg: ~str) -> ! {
emitter(None, msg, diagnostic::fatal);
pub fn early_error(emitter: @diagnostic::Emitter, msg: ~str) -> ! {
emitter.emit(None, msg, diagnostic::fatal);
fail!();
}
@ -1030,8 +1065,12 @@ mod test {
Err(f) => fail!("test_switch_implies_cfg_test: %s", f.to_err_msg())
};
let sessopts = build_session_options(
@"rustc", matches, diagnostic::emit);
let sess = build_session(sessopts, diagnostic::emit);
@"rustc",
matches,
@diagnostic::DefaultEmitter as @diagnostic::Emitter);
let sess = build_session(sessopts,
@diagnostic::DefaultEmitter as
@diagnostic::Emitter);
let cfg = build_configuration(sess);
assert!((attr::contains_name(cfg, "test")));
}
@ -1048,8 +1087,12 @@ mod test {
}
};
let sessopts = build_session_options(
@"rustc", matches, diagnostic::emit);
let sess = build_session(sessopts, diagnostic::emit);
@"rustc",
matches,
@diagnostic::DefaultEmitter as @diagnostic::Emitter);
let sess = build_session(sessopts,
@diagnostic::DefaultEmitter as
@diagnostic::Emitter);
let cfg = build_configuration(sess);
let mut test_items = cfg.iter().filter(|m| "test" == m.name());
assert!(test_items.next().is_some());

View File

@ -11,9 +11,22 @@
use driver::session::Session;
use syntax::ast;
use syntax::ast_util;
use syntax::fold::ast_fold;
struct NodeIdAssigner {
sess: Session,
}
impl ast_fold for NodeIdAssigner {
fn new_id(&self, old_id: ast::NodeId) -> ast::NodeId {
assert_eq!(old_id, ast::DUMMY_NODE_ID);
self.sess.next_node_id()
}
}
pub fn assign_node_ids(sess: Session, crate: @ast::Crate) -> @ast::Crate {
let fold = ast_util::node_id_assigner(|| sess.next_node_id());
let fold = NodeIdAssigner {
sess: sess,
};
@fold.fold_crate(crate)
}

View File

@ -9,13 +9,11 @@
// except according to those terms.
use std::option;
use syntax::fold::ast_fold;
use syntax::{ast, fold, attr};
type in_cfg_pred = @fn(attrs: &[ast::Attribute]) -> bool;
struct Context {
in_cfg: in_cfg_pred
struct Context<'self> {
in_cfg: &'self fn(attrs: &[ast::Attribute]) -> bool,
}
// Support conditional compilation by transforming the AST, stripping out
@ -26,43 +24,55 @@ pub fn strip_unconfigured_items(crate: @ast::Crate) -> @ast::Crate {
}
}
pub fn strip_items(crate: &ast::Crate, in_cfg: in_cfg_pred)
-> @ast::Crate {
let ctxt = @Context { in_cfg: in_cfg };
let precursor = @fold::AstFoldFns {
fold_mod: |a,b| fold_mod(ctxt, a, b),
fold_block: |a,b| fold_block(ctxt, a, b),
fold_foreign_mod: |a,b| fold_foreign_mod(ctxt, a, b),
fold_item_underscore: |a,b| fold_item_underscore(ctxt, a, b),
.. *fold::default_ast_fold()
};
let fold = fold::make_fold(precursor);
@fold.fold_crate(crate)
}
fn filter_item(cx: @Context, item: @ast::item) ->
Option<@ast::item> {
if item_in_cfg(cx, item) { option::Some(item) } else { option::None }
}
fn filter_view_item<'r>(cx: @Context, view_item: &'r ast::view_item)-> Option<&'r ast::view_item> {
if view_item_in_cfg(cx, view_item) {
option::Some(view_item)
} else {
option::None
impl<'self> fold::ast_fold for Context<'self> {
fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
fold_mod(self, module)
}
fn fold_block(&self, block: &ast::Block) -> ast::Block {
fold_block(self, block)
}
fn fold_foreign_mod(&self, foreign_module: &ast::foreign_mod)
-> ast::foreign_mod {
fold_foreign_mod(self, foreign_module)
}
fn fold_item_underscore(&self, item: &ast::item_) -> ast::item_ {
fold_item_underscore(self, item)
}
}
fn fold_mod(cx: @Context, m: &ast::_mod, fld: @fold::ast_fold) -> ast::_mod {
let filtered_items = do m.items.iter().filter_map |a| {
filter_item(cx, *a).and_then(|x| fld.fold_item(x))
pub fn strip_items(crate: &ast::Crate,
in_cfg: &fn(attrs: &[ast::Attribute]) -> bool)
-> @ast::Crate {
let ctxt = Context {
in_cfg: in_cfg,
};
@ctxt.fold_crate(crate)
}
fn filter_item(cx: &Context, item: @ast::item) -> Option<@ast::item> {
if item_in_cfg(cx, item) {
Some(item)
} else {
None
}
}
fn filter_view_item<'r>(cx: &Context, view_item: &'r ast::view_item)
-> Option<&'r ast::view_item> {
if view_item_in_cfg(cx, view_item) {
Some(view_item)
} else {
None
}
}
fn fold_mod(cx: &Context, m: &ast::_mod) -> ast::_mod {
let filtered_items = do m.items.iter().filter_map |a| {
filter_item(cx, *a).and_then(|x| cx.fold_item(x))
}.collect();
let filtered_view_items = do m.view_items.iter().filter_map |a| {
do filter_view_item(cx, a).map_move |x| {
fld.fold_view_item(x)
cx.fold_view_item(x)
}
}.collect();
ast::_mod {
@ -71,22 +81,23 @@ fn fold_mod(cx: @Context, m: &ast::_mod, fld: @fold::ast_fold) -> ast::_mod {
}
}
fn filter_foreign_item(cx: @Context, item: @ast::foreign_item) ->
Option<@ast::foreign_item> {
fn filter_foreign_item(cx: &Context, item: @ast::foreign_item)
-> Option<@ast::foreign_item> {
if foreign_item_in_cfg(cx, item) {
option::Some(item)
} else { option::None }
Some(item)
} else {
None
}
}
fn fold_foreign_mod(
cx: @Context,
nm: &ast::foreign_mod,
fld: @fold::ast_fold
) -> ast::foreign_mod {
let filtered_items = nm.items.iter().filter_map(|a| filter_foreign_item(cx, *a)).collect();
fn fold_foreign_mod(cx: &Context, nm: &ast::foreign_mod) -> ast::foreign_mod {
let filtered_items = nm.items
.iter()
.filter_map(|a| filter_foreign_item(cx, *a))
.collect();
let filtered_view_items = do nm.view_items.iter().filter_map |a| {
do filter_view_item(cx, a).map_move |x| {
fld.fold_view_item(x)
cx.fold_view_item(x)
}
}.collect();
ast::foreign_mod {
@ -97,8 +108,7 @@ fn fold_foreign_mod(
}
}
fn fold_item_underscore(cx: @Context, item: &ast::item_,
fld: @fold::ast_fold) -> ast::item_ {
fn fold_item_underscore(cx: &Context, item: &ast::item_) -> ast::item_ {
let item = match *item {
ast::item_impl(ref a, ref b, ref c, ref methods) => {
let methods = methods.iter().filter(|m| method_in_cfg(cx, **m))
@ -106,71 +116,70 @@ fn fold_item_underscore(cx: @Context, item: &ast::item_,
ast::item_impl((*a).clone(), (*b).clone(), (*c).clone(), methods)
}
ast::item_trait(ref a, ref b, ref methods) => {
let methods = methods.iter().filter(|m| trait_method_in_cfg(cx, *m) )
.map(|x| (*x).clone()).collect();
let methods = methods.iter()
.filter(|m| trait_method_in_cfg(cx, *m) )
.map(|x| (*x).clone())
.collect();
ast::item_trait((*a).clone(), (*b).clone(), methods)
}
ref item => (*item).clone(),
};
fold::noop_fold_item_underscore(&item, fld)
fold::noop_fold_item_underscore(&item, cx)
}
fn filter_stmt(cx: @Context, stmt: @ast::Stmt) ->
Option<@ast::Stmt> {
fn filter_stmt(cx: &Context, stmt: @ast::Stmt) -> Option<@ast::Stmt> {
match stmt.node {
ast::StmtDecl(decl, _) => {
match decl.node {
ast::DeclItem(item) => {
if item_in_cfg(cx, item) {
option::Some(stmt)
} else { option::None }
Some(stmt)
} else {
None
}
}
_ => option::Some(stmt)
_ => Some(stmt)
}
}
_ => option::Some(stmt)
_ => Some(stmt),
}
}
fn fold_block(
cx: @Context,
b: &ast::Block,
fld: @fold::ast_fold
) -> ast::Block {
fn fold_block(cx: &Context, b: &ast::Block) -> ast::Block {
let resulting_stmts = do b.stmts.iter().filter_map |a| {
filter_stmt(cx, *a).and_then(|stmt| fld.fold_stmt(stmt))
filter_stmt(cx, *a).and_then(|stmt| cx.fold_stmt(stmt))
}.collect();
let filtered_view_items = do b.view_items.iter().filter_map |a| {
filter_view_item(cx, a).map(|x| fld.fold_view_item(*x))
filter_view_item(cx, a).map(|x| cx.fold_view_item(*x))
}.collect();
ast::Block {
view_items: filtered_view_items,
stmts: resulting_stmts,
expr: b.expr.map(|x| fld.fold_expr(*x)),
expr: b.expr.map(|x| cx.fold_expr(*x)),
id: b.id,
rules: b.rules,
span: b.span,
}
}
fn item_in_cfg(cx: @Context, item: @ast::item) -> bool {
fn item_in_cfg(cx: &Context, item: @ast::item) -> bool {
return (cx.in_cfg)(item.attrs);
}
fn foreign_item_in_cfg(cx: @Context, item: @ast::foreign_item) -> bool {
fn foreign_item_in_cfg(cx: &Context, item: @ast::foreign_item) -> bool {
return (cx.in_cfg)(item.attrs);
}
fn view_item_in_cfg(cx: @Context, item: &ast::view_item) -> bool {
fn view_item_in_cfg(cx: &Context, item: &ast::view_item) -> bool {
return (cx.in_cfg)(item.attrs);
}
fn method_in_cfg(cx: @Context, meth: @ast::method) -> bool {
fn method_in_cfg(cx: &Context, meth: @ast::method) -> bool {
return (cx.in_cfg)(meth.attrs);
}
fn trait_method_in_cfg(cx: @Context, meth: &ast::trait_method) -> bool {
fn trait_method_in_cfg(cx: &Context, meth: &ast::trait_method) -> bool {
match *meth {
ast::required(ref meth) => (cx.in_cfg)(meth.attrs),
ast::provided(@ref meth) => (cx.in_cfg)(meth.attrs)
@ -182,3 +191,4 @@ fn trait_method_in_cfg(cx: @Context, meth: &ast::trait_method) -> bool {
fn in_cfg(cfg: &[@ast::MetaItem], attrs: &[ast::Attribute]) -> bool {
attr::test_cfg(cfg, attrs.iter().map(|x| *x))
}

View File

@ -16,6 +16,7 @@ use syntax::ast;
use syntax::attr;
use syntax::codemap::dummy_sp;
use syntax::codemap;
use syntax::fold::ast_fold;
use syntax::fold;
use syntax::opt_vec;
@ -38,91 +39,103 @@ fn no_prelude(attrs: &[ast::Attribute]) -> bool {
attr::contains_name(attrs, "no_implicit_prelude")
}
fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
fn spanned<T>(x: T) -> codemap::Spanned<T> {
codemap::Spanned { node: x, span: dummy_sp() }
fn spanned<T>(x: T) -> codemap::Spanned<T> {
codemap::Spanned {
node: x,
span: dummy_sp(),
}
}
struct StandardLibraryInjector {
sess: Session,
}
impl fold::ast_fold for StandardLibraryInjector {
fn fold_crate(&self, crate: &ast::Crate) -> ast::Crate {
let version = STD_VERSION.to_managed();
let vi1 = ast::view_item {
node: ast::view_item_extern_mod(self.sess.ident_of("std"),
None,
~[],
ast::DUMMY_NODE_ID),
attrs: ~[
attr::mk_attr(attr::mk_name_value_item_str(@"vers", version))
],
vis: ast::private,
span: dummy_sp()
};
let vis = vec::append(~[vi1], crate.module.view_items);
let mut new_module = ast::_mod {
view_items: vis,
..crate.module.clone()
};
if !no_prelude(crate.attrs) {
// only add `use std::prelude::*;` if there wasn't a
// `#[no_implicit_prelude];` at the crate level.
new_module = self.fold_mod(&new_module);
}
// FIXME #2543: Bad copy.
ast::Crate {
module: new_module,
..(*crate).clone()
}
}
let precursor = @fold::AstFoldFns {
fold_crate: |crate, fld| {
let n1 = ast::DUMMY_NODE_ID;
let vi1 = ast::view_item {
node: ast::view_item_extern_mod(
sess.ident_of("std"), None, ~[], n1),
attrs: ~[
attr::mk_attr(
attr::mk_name_value_item_str(@"vers", STD_VERSION.to_managed()))
],
vis: ast::private,
span: dummy_sp()
};
fn fold_item(&self, item: @ast::item) -> Option<@ast::item> {
if !no_prelude(item.attrs) {
// only recur if there wasn't `#[no_implicit_prelude];`
// on this item, i.e. this means that the prelude is not
// implicitly imported though the whole subtree
fold::noop_fold_item(item, self)
} else {
Some(item)
}
}
let vis = vec::append(~[vi1], crate.module.view_items);
let mut new_module = ast::_mod {
view_items: vis,
..crate.module.clone()
};
fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
let prelude_path = ast::Path {
span: dummy_sp(),
global: false,
segments: ~[
ast::PathSegment {
identifier: self.sess.ident_of("std"),
lifetime: None,
types: opt_vec::Empty,
},
ast::PathSegment {
identifier: self.sess.ident_of("prelude"),
lifetime: None,
types: opt_vec::Empty,
},
],
};
if !no_prelude(crate.attrs) {
// only add `use std::prelude::*;` if there wasn't a
// `#[no_implicit_prelude];` at the crate level.
new_module = fld.fold_mod(&new_module);
}
let vp = @spanned(ast::view_path_glob(prelude_path,
ast::DUMMY_NODE_ID));
let vi2 = ast::view_item {
node: ast::view_item_use(~[vp]),
attrs: ~[],
vis: ast::private,
span: dummy_sp(),
};
// FIXME #2543: Bad copy.
ast::Crate {
module: new_module,
..(*crate).clone()
}
},
fold_item: |item, fld| {
if !no_prelude(item.attrs) {
// only recur if there wasn't `#[no_implicit_prelude];`
// on this item, i.e. this means that the prelude is not
// implicitly imported though the whole subtree
fold::noop_fold_item(item, fld)
} else {
Some(item)
}
},
fold_mod: |module, fld| {
let n2 = ast::DUMMY_NODE_ID;
let vis = vec::append(~[vi2], module.view_items);
let prelude_path = ast::Path {
span: dummy_sp(),
global: false,
segments: ~[
ast::PathSegment {
identifier: sess.ident_of("std"),
lifetime: None,
types: opt_vec::Empty,
},
ast::PathSegment {
identifier: sess.ident_of("prelude"),
lifetime: None,
types: opt_vec::Empty,
},
],
};
// FIXME #2543: Bad copy.
let new_module = ast::_mod {
view_items: vis,
..(*module).clone()
};
fold::noop_fold_mod(&new_module, self)
}
}
let vp = @spanned(ast::view_path_glob(prelude_path, n2));
let vi2 = ast::view_item { node: ast::view_item_use(~[vp]),
attrs: ~[],
vis: ast::private,
span: dummy_sp() };
let vis = vec::append(~[vi2], module.view_items);
// FIXME #2543: Bad copy.
let new_module = ast::_mod {
view_items: vis,
..(*module).clone()
};
fold::noop_fold_mod(&new_module, fld)
},
..*fold::default_ast_fold()
fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
let fold = StandardLibraryInjector {
sess: sess,
};
let fold = fold::make_fold(precursor);
@fold.fold_crate(crate)
}

View File

@ -21,13 +21,12 @@ use syntax::attr;
use syntax::codemap::{dummy_sp, Span, ExpnInfo, NameAndSpan};
use syntax::codemap;
use syntax::ext::base::ExtCtxt;
use syntax::fold::ast_fold;
use syntax::fold;
use syntax::opt_vec;
use syntax::print::pprust;
use syntax::{ast, ast_util};
type node_id_gen = @fn() -> ast::NodeId;
struct Test {
span: Span,
path: ~[ast::Ident],
@ -61,9 +60,89 @@ pub fn modify_for_testing(sess: session::Session,
}
}
fn generate_test_harness(sess: session::Session,
crate: @ast::Crate)
-> @ast::Crate {
struct TestHarnessGenerator {
cx: @mut TestCtxt,
}
impl fold::ast_fold for TestHarnessGenerator {
fn fold_crate(&self, c: &ast::Crate) -> ast::Crate {
let folded = fold::noop_fold_crate(c, self);
// Add a special __test module to the crate that will contain code
// generated for the test harness
ast::Crate {
module: add_test_module(self.cx, &folded.module),
.. folded
}
}
fn fold_item(&self, i: @ast::item) -> Option<@ast::item> {
self.cx.path.push(i.ident);
debug!("current path: %s",
ast_util::path_name_i(self.cx.path.clone()));
if is_test_fn(self.cx, i) || is_bench_fn(i) {
match i.node {
ast::item_fn(_, purity, _, _, _)
if purity == ast::unsafe_fn => {
let sess = self.cx.sess;
sess.span_fatal(i.span,
"unsafe functions cannot be used for \
tests");
}
_ => {
debug!("this is a test function");
let test = Test {
span: i.span,
path: self.cx.path.clone(),
bench: is_bench_fn(i),
ignore: is_ignored(self.cx, i),
should_fail: should_fail(i)
};
self.cx.testfns.push(test);
// debug!("have %u test/bench functions",
// cx.testfns.len());
}
}
}
let res = fold::noop_fold_item(i, self);
self.cx.path.pop();
return res;
}
fn fold_mod(&self, m: &ast::_mod) -> ast::_mod {
// Remove any #[main] from the AST so it doesn't clash with
// the one we're going to add. Only if compiling an executable.
fn nomain(cx: @mut TestCtxt, item: @ast::item) -> @ast::item {
if !*cx.sess.building_library {
@ast::item {
attrs: do item.attrs.iter().filter_map |attr| {
if "main" != attr.name() {
Some(*attr)
} else {
None
}
}.collect(),
.. (*item).clone()
}
} else {
item
}
}
let mod_nomain = ast::_mod {
view_items: m.view_items.clone(),
items: m.items.iter().map(|i| nomain(self.cx, *i)).collect(),
};
fold::noop_fold_mod(&mod_nomain, self)
}
}
fn generate_test_harness(sess: session::Session, crate: @ast::Crate)
-> @ast::Crate {
let cx: @mut TestCtxt = @mut TestCtxt {
sess: sess,
crate: crate,
@ -81,12 +160,9 @@ fn generate_test_harness(sess: session::Session,
}
});
let precursor = @fold::AstFoldFns {
fold_crate: |a,b| fold_crate(cx, a, b),
fold_item: |a,b| fold_item(cx, a, b),
fold_mod: |a,b| fold_mod(cx, a, b),.. *fold::default_ast_fold()};
let fold = fold::make_fold(precursor);
let fold = TestHarnessGenerator {
cx: cx
};
let res = @fold.fold_crate(&*crate);
ext_cx.bt_pop();
return res;
@ -101,85 +177,6 @@ fn strip_test_functions(crate: &ast::Crate) -> @ast::Crate {
}
}
fn fold_mod(cx: @mut TestCtxt,
m: &ast::_mod,
fld: @fold::ast_fold)
-> ast::_mod {
// Remove any #[main] from the AST so it doesn't clash with
// the one we're going to add. Only if compiling an executable.
fn nomain(cx: @mut TestCtxt, item: @ast::item) -> @ast::item {
if !*cx.sess.building_library {
@ast::item {
attrs: do item.attrs.iter().filter_map |attr| {
if "main" != attr.name() {
Some(*attr)
} else {
None
}
}.collect(),
.. (*item).clone()
}
} else {
item
}
}
let mod_nomain = ast::_mod {
view_items: m.view_items.clone(),
items: m.items.iter().map(|i| nomain(cx, *i)).collect(),
};
fold::noop_fold_mod(&mod_nomain, fld)
}
fn fold_crate(cx: @mut TestCtxt, c: &ast::Crate, fld: @fold::ast_fold)
-> ast::Crate {
let folded = fold::noop_fold_crate(c, fld);
// Add a special __test module to the crate that will contain code
// generated for the test harness
ast::Crate {
module: add_test_module(cx, &folded.module),
.. folded
}
}
fn fold_item(cx: @mut TestCtxt, i: @ast::item, fld: @fold::ast_fold)
-> Option<@ast::item> {
cx.path.push(i.ident);
debug!("current path: %s",
ast_util::path_name_i(cx.path.clone()));
if is_test_fn(cx, i) || is_bench_fn(i) {
match i.node {
ast::item_fn(_, purity, _, _, _) if purity == ast::unsafe_fn => {
let sess = cx.sess;
sess.span_fatal(
i.span,
"unsafe functions cannot be used for tests");
}
_ => {
debug!("this is a test function");
let test = Test {
span: i.span,
path: cx.path.clone(),
bench: is_bench_fn(i),
ignore: is_ignored(cx, i),
should_fail: should_fail(i)
};
cx.testfns.push(test);
// debug!("have %u test/bench functions", cx.testfns.len());
}
}
}
let res = fold::noop_fold_item(i, fld);
cx.path.pop();
return res;
}
fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool {
let has_test_attr = attr::contains_name(i.attrs, "test");

View File

@ -95,8 +95,7 @@ pub fn parse_ident(st: &mut PState, last: char) -> ast::Ident {
return parse_ident_(st, |a| is_last(last, a) );
}
fn parse_ident_(st: &mut PState, is_last: @fn(char) -> bool) ->
ast::Ident {
fn parse_ident_(st: &mut PState, is_last: &fn(char) -> bool) -> ast::Ident {
let rslt = scan(st, is_last, str::from_utf8);
return st.tcx.sess.ident_of(rslt);
}

View File

@ -26,7 +26,7 @@ use syntax::print::pprust::*;
pub struct ctxt {
diag: @mut span_handler,
// Def -> str Callback:
ds: @fn(DefId) -> ~str,
ds: extern "Rust" fn(DefId) -> ~str,
// The type context.
tcx: ty::ctxt,
abbrevs: abbrev_ctxt

View File

@ -24,6 +24,7 @@ use middle;
use util::ppaux::ty_to_str;
use std::at_vec;
use std::libc;
use extra::ebml::reader;
use extra::ebml;
use extra::serialize;
@ -287,26 +288,24 @@ fn encode_ast(ebml_w: &mut writer::Encoder, item: ast::inlined_item) {
ebml_w.end_tag();
}
// Produces a simplified copy of the AST which does not include things
// that we do not need to or do not want to export. For example, we
// do not include any nested items: if these nested items are to be
// inlined, their AST will be exported separately (this only makes
// sense because, in Rust, nested items are independent except for
// their visibility).
//
// As it happens, trans relies on the fact that we do not export
// nested items, as otherwise it would get confused when translating
// inlined items.
fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
fn drop_nested_items(blk: &ast::Block, fld: @fold::ast_fold) -> ast::Block {
struct NestedItemsDropper {
contents: (),
}
impl fold::ast_fold for NestedItemsDropper {
fn fold_block(&self, blk: &ast::Block) -> ast::Block {
let stmts_sans_items = do blk.stmts.iter().filter_map |stmt| {
match stmt.node {
ast::StmtExpr(_, _) | ast::StmtSemi(_, _) |
ast::StmtDecl(@codemap::Spanned { node: ast::DeclLocal(_), span: _}, _)
=> Some(*stmt),
ast::StmtDecl(@codemap::Spanned { node: ast::DeclItem(_), span: _}, _)
=> None,
ast::StmtMac(*) => fail!("unexpanded macro in astencode")
ast::StmtExpr(_, _) | ast::StmtSemi(_, _) |
ast::StmtDecl(@codemap::Spanned {
node: ast::DeclLocal(_),
span: _
}, _) => Some(*stmt),
ast::StmtDecl(@codemap::Spanned {
node: ast::DeclItem(_),
span: _
}, _) => None,
ast::StmtMac(*) => fail!("unexpanded macro in astencode")
}
}.collect();
let blk_sans_items = ast::Block {
@ -318,13 +317,24 @@ fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
rules: blk.rules,
span: blk.span,
};
fold::noop_fold_block(&blk_sans_items, fld)
fold::noop_fold_block(&blk_sans_items, self)
}
}
let fld = fold::make_fold(@fold::AstFoldFns {
fold_block: drop_nested_items,
.. *fold::default_ast_fold()
});
// Produces a simplified copy of the AST which does not include things
// that we do not need to or do not want to export. For example, we
// do not include any nested items: if these nested items are to be
// inlined, their AST will be exported separately (this only makes
// sense because, in Rust, nested items are independent except for
// their visibility).
//
// As it happens, trans relies on the fact that we do not export
// nested items, as otherwise it would get confused when translating
// inlined items.
fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
let fld = NestedItemsDropper {
contents: (),
};
match *ii {
//hack: we're not dropping items
@ -341,14 +351,24 @@ fn decode_ast(par_doc: ebml::Doc) -> ast::inlined_item {
Decodable::decode(&mut d)
}
struct AstRenumberer {
xcx: @ExtendedDecodeContext,
}
impl fold::ast_fold for AstRenumberer {
fn new_id(&self, id: ast::NodeId) -> ast::NodeId {
self.xcx.tr_id(id)
}
fn new_span(&self, span: Span) -> Span {
self.xcx.tr_span(span)
}
}
fn renumber_ast(xcx: @ExtendedDecodeContext, ii: ast::inlined_item)
-> ast::inlined_item {
let fld = fold::make_fold(@fold::AstFoldFns{
new_id: |a| xcx.tr_id(a),
new_span: |a| xcx.tr_span(a),
.. *fold::default_ast_fold()
});
let fld = AstRenumberer {
xcx: xcx,
};
match ii {
ast::ii_item(i) => ast::ii_item(fld.fold_item(i).unwrap()),
ast::ii_method(d, is_provided, m) =>
@ -830,6 +850,26 @@ impl write_tag_and_id for writer::Encoder {
}
}
struct SideTableEncodingIdVisitor {
ecx_ptr: *libc::c_void,
new_ebml_w: writer::Encoder,
maps: Maps,
}
impl ast_util::IdVisitingOperation for SideTableEncodingIdVisitor {
fn visit_id(&self, id: ast::NodeId) {
// Note: this will cause a copy of ebml_w, which is bad as
// it is mutable. But I believe it's harmless since we generate
// balanced EBML.
let mut new_ebml_w = self.new_ebml_w.clone();
// See above
let ecx: &e::EncodeContext = unsafe {
cast::transmute(self.ecx_ptr)
};
encode_side_tables_for_id(ecx, self.maps, &mut new_ebml_w, id)
}
}
fn encode_side_tables_for_ii(ecx: &e::EncodeContext,
maps: Maps,
ebml_w: &mut writer::Encoder,
@ -837,22 +877,16 @@ fn encode_side_tables_for_ii(ecx: &e::EncodeContext,
ebml_w.start_tag(c::tag_table as uint);
let new_ebml_w = (*ebml_w).clone();
// Because the ast visitor uses @fn, I can't pass in
// ecx directly, but /I/ know that it'll be fine since
// the lifetime is tied to the CrateContext that
// lives this entire section.
let ecx_ptr : *() = unsafe { cast::transmute(ecx) };
ast_util::visit_ids_for_inlined_item(
ii,
|id: ast::NodeId| {
// Note: this will cause a copy of ebml_w, which is bad as
// it is mutable. But I believe it's harmless since we generate
// balanced EBML.
let mut new_ebml_w = new_ebml_w.clone();
// See above
let ecx : &e::EncodeContext = unsafe { cast::transmute(ecx_ptr) };
encode_side_tables_for_id(ecx, maps, &mut new_ebml_w, id)
});
// Because the ast visitor uses @IdVisitingOperation, I can't pass in
// ecx directly, but /I/ know that it'll be fine since the lifetime is
// tied to the CrateContext that lives throughout this entire section.
ast_util::visit_ids_for_inlined_item(ii, @SideTableEncodingIdVisitor {
ecx_ptr: unsafe {
cast::transmute(ecx)
},
new_ebml_w: new_ebml_w,
maps: maps,
} as @ast_util::IdVisitingOperation);
ebml_w.end_tag();
}

View File

@ -87,6 +87,42 @@ struct LoopScope<'self> {
break_bits: ~[uint]
}
impl<O:DataFlowOperator> pprust::pp_ann for DataFlowContext<O> {
fn pre(&self, node: pprust::ann_node) {
let (ps, id) = match node {
pprust::node_expr(ps, expr) => (ps, expr.id),
pprust::node_block(ps, blk) => (ps, blk.id),
pprust::node_item(ps, _) => (ps, 0),
pprust::node_pat(ps, pat) => (ps, pat.id)
};
if self.nodeid_to_bitset.contains_key(&id) {
let (start, end) = self.compute_id_range_frozen(id);
let on_entry = self.on_entry.slice(start, end);
let entry_str = bits_to_str(on_entry);
let gens = self.gens.slice(start, end);
let gens_str = if gens.iter().any(|&u| u != 0) {
fmt!(" gen: %s", bits_to_str(gens))
} else {
~""
};
let kills = self.kills.slice(start, end);
let kills_str = if kills.iter().any(|&u| u != 0) {
fmt!(" kill: %s", bits_to_str(kills))
} else {
~""
};
let comment_str = fmt!("id %d: %s%s%s",
id, entry_str, gens_str, kills_str);
pprust::synth_comment(ps, comment_str);
pp::space(ps.s);
}
}
}
impl<O:DataFlowOperator> DataFlowContext<O> {
pub fn new(tcx: ty::ctxt,
method_map: typeck::method_map,
@ -319,46 +355,9 @@ impl<O:DataFlowOperator+Clone+'static> DataFlowContext<O> {
}
fn pretty_print_to(@self, wr: @io::Writer, blk: &ast::Block) {
let pre: @fn(pprust::ann_node) = |node| {
let (ps, id) = match node {
pprust::node_expr(ps, expr) => (ps, expr.id),
pprust::node_block(ps, blk) => (ps, blk.id),
pprust::node_item(ps, _) => (ps, 0),
pprust::node_pat(ps, pat) => (ps, pat.id)
};
if self.nodeid_to_bitset.contains_key(&id) {
let (start, end) = self.compute_id_range_frozen(id);
let on_entry = self.on_entry.slice(start, end);
let entry_str = bits_to_str(on_entry);
let gens = self.gens.slice(start, end);
let gens_str = if gens.iter().any(|&u| u != 0) {
fmt!(" gen: %s", bits_to_str(gens))
} else {
~""
};
let kills = self.kills.slice(start, end);
let kills_str = if kills.iter().any(|&u| u != 0) {
fmt!(" kill: %s", bits_to_str(kills))
} else {
~""
};
let comment_str = fmt!("id %d: %s%s%s",
id, entry_str, gens_str, kills_str);
pprust::synth_comment(ps, comment_str);
pp::space(ps.s);
}
};
let post: @fn(pprust::ann_node) = |_| {
};
let ps = pprust::rust_printer_annotated(
wr, self.tcx.sess.intr(),
pprust::pp_ann {pre:pre, post:post});
let ps = pprust::rust_printer_annotated(wr,
self.tcx.sess.intr(),
self as @pprust::pp_ann);
pprust::cbox(ps, pprust::indent_unit);
pprust::ibox(ps, 0u);
pprust::print_block(ps, blk);

View File

@ -218,14 +218,25 @@ fn with_appropriate_checker(cx: Context, id: NodeId,
let fty = ty::node_id_to_type(cx.tcx, id);
match ty::get(fty).sty {
ty::ty_closure(ty::ClosureTy {sigil: OwnedSigil, bounds: bounds, _}) => {
ty::ty_closure(ty::ClosureTy {
sigil: OwnedSigil,
bounds: bounds,
_
}) => {
b(|cx, fv| check_for_uniq(cx, fv, bounds))
}
ty::ty_closure(ty::ClosureTy {sigil: ManagedSigil, bounds: bounds, _}) => {
b(|cx, fv| check_for_box(cx, fv, bounds))
ty::ty_closure(ty::ClosureTy {
sigil: ManagedSigil,
_
}) => {
// can't happen
}
ty::ty_closure(ty::ClosureTy {sigil: BorrowedSigil, bounds: bounds,
region: region, _}) => {
ty::ty_closure(ty::ClosureTy {
sigil: BorrowedSigil,
bounds: bounds,
region: region,
_
}) => {
b(|cx, fv| check_for_block(cx, fv, bounds, region))
}
ty::ty_bare_fn(_) => {

View File

@ -1228,17 +1228,27 @@ fn lint_unused_mut() -> @mut OuterLint {
@mut UnusedMutLintVisitor{ stopping_on_items: false } as @mut OuterLint
}
fn lint_session(cx: @mut Context) -> @mut visit::Visitor<()> {
ast_util::id_visitor(|id| {
match cx.tcx.sess.lints.pop(&id) {
None => {},
struct LintReportingIdVisitor {
cx: @mut Context,
}
impl ast_util::IdVisitingOperation for LintReportingIdVisitor {
fn visit_id(&self, id: ast::NodeId) {
match self.cx.tcx.sess.lints.pop(&id) {
None => {}
Some(l) => {
for (lint, span, msg) in l.move_iter() {
cx.span_lint(lint, span, msg)
self.cx.span_lint(lint, span, msg)
}
}
}
}, false)
}
}
fn lint_session(cx: @mut Context) -> @mut visit::Visitor<()> {
ast_util::id_visitor(@LintReportingIdVisitor {
cx: cx,
} as @ast_util::IdVisitingOperation, false)
}
struct UnnecessaryAllocationLintVisitor { stopping_on_items: bool }

View File

@ -187,8 +187,7 @@ pub fn opt_deref_kind(t: ty::t) -> Option<deref_kind> {
Some(deref_ptr(gc_ptr(m)))
}
ty::ty_estr(ty::vstore_box) |
ty::ty_closure(ty::ClosureTy {sigil: ast::ManagedSigil, _}) => {
ty::ty_estr(ty::vstore_box) => {
Some(deref_ptr(gc_ptr(ast::MutImmutable)))
}
@ -515,7 +514,8 @@ impl mem_categorization_ctxt {
(ast::BorrowedSigil, ast::Once) => true,
// Heap closures always capture by copy/move, and can
// move out iff they are once.
(ast::OwnedSigil, _) | (ast::ManagedSigil, _) => false,
(ast::OwnedSigil, _) |
(ast::ManagedSigil, _) => false,
};
if var_is_refd {

View File

@ -116,8 +116,7 @@ fn stack_check_fn<'a>(v: StackCheckVisitor,
visit::fk_anon(*) | visit::fk_fn_block => {
match ty::get(ty::node_id_to_type(in_cx.tcx, id)).sty {
ty::ty_bare_fn(*) |
ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) |
ty::ty_closure(ty::ClosureTy {sigil: ast::ManagedSigil, _}) => {
ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
false
}
_ => {

View File

@ -533,7 +533,7 @@ fn enter_default<'r>(bcx: @mut Block,
m: &[Match<'r>],
col: uint,
val: ValueRef,
chk: Option<mk_fail>)
chk: FailureHandler)
-> ~[Match<'r>] {
debug!("enter_default(bcx=%s, m=%s, col=%u, val=%s)",
bcx.to_str(),
@ -567,7 +567,7 @@ fn enter_default<'r>(bcx: @mut Block,
// we don't need any default cases. If the check *isn't* nonexhaustive
// (because chk is Some), then we need the defaults anyways.
let is_exhaustive = match matches.last_opt() {
Some(m) if m.data.arm.guard.is_some() && chk.is_none() => true,
Some(m) if m.data.arm.guard.is_some() && chk.is_infallible() => true,
_ => false
};
@ -1185,7 +1185,62 @@ fn any_tuple_struct_pat(bcx: @mut Block, m: &[Match], col: uint) -> bool {
}
}
type mk_fail = @fn() -> BasicBlockRef;
trait CustomFailureHandler {
fn handle_fail(&self) -> BasicBlockRef;
}
struct DynamicFailureHandler {
bcx: @mut Block,
sp: Span,
msg: @str,
finished: @mut Option<BasicBlockRef>,
}
impl CustomFailureHandler for DynamicFailureHandler {
fn handle_fail(&self) -> BasicBlockRef {
match *self.finished {
Some(bb) => return bb,
_ => (),
}
let fail_cx = sub_block(self.bcx, "case_fallthrough");
controlflow::trans_fail(fail_cx, Some(self.sp), self.msg);
*self.finished = Some(fail_cx.llbb);
fail_cx.llbb
}
}
/// What to do when the pattern match fails.
enum FailureHandler {
Infallible,
JumpToBasicBlock(BasicBlockRef),
CustomFailureHandlerClass(@CustomFailureHandler),
}
impl FailureHandler {
fn is_infallible(&self) -> bool {
match *self {
Infallible => true,
_ => false,
}
}
fn is_fallible(&self) -> bool {
!self.is_infallible()
}
fn handle_fail(&self) -> BasicBlockRef {
match *self {
Infallible => {
fail!("attempted to fail in infallible failure handler!")
}
JumpToBasicBlock(basic_block) => basic_block,
CustomFailureHandlerClass(custom_failure_handler) => {
custom_failure_handler.handle_fail()
}
}
}
}
fn pick_col(m: &[Match]) -> uint {
fn score(p: &ast::Pat) -> uint {
@ -1347,7 +1402,7 @@ fn compile_guard(bcx: @mut Block,
data: &ArmData,
m: &[Match],
vals: &[ValueRef],
chk: Option<mk_fail>)
chk: FailureHandler)
-> @mut Block {
debug!("compile_guard(bcx=%s, guard_expr=%s, m=%s, vals=%s)",
bcx.to_str(),
@ -1400,9 +1455,9 @@ fn compile_guard(bcx: @mut Block,
}
fn compile_submatch(bcx: @mut Block,
m: &[Match],
vals: &[ValueRef],
chk: Option<mk_fail>) {
m: &[Match],
vals: &[ValueRef],
chk: FailureHandler) {
debug!("compile_submatch(bcx=%s, m=%s, vals=%s)",
bcx.to_str(),
m.repr(bcx.tcx()),
@ -1412,11 +1467,11 @@ fn compile_submatch(bcx: @mut Block,
/*
For an empty match, a fall-through case must exist
*/
assert!((m.len() > 0u || chk.is_some()));
assert!((m.len() > 0u || chk.is_fallible()));
let _icx = push_ctxt("match::compile_submatch");
let mut bcx = bcx;
if m.len() == 0u {
Br(bcx, chk.unwrap()());
Br(bcx, chk.handle_fail());
return;
}
if m[0].pats.len() == 0u {
@ -1454,7 +1509,7 @@ fn compile_submatch(bcx: @mut Block,
fn compile_submatch_continue(mut bcx: @mut Block,
m: &[Match],
vals: &[ValueRef],
chk: Option<mk_fail>,
chk: FailureHandler,
col: uint,
val: ValueRef) {
let tcx = bcx.tcx();
@ -1617,7 +1672,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
};
let defaults = enter_default(else_cx, dm, m, col, val, chk);
let exhaustive = chk.is_none() && defaults.len() == 0u;
let exhaustive = chk.is_infallible() && defaults.len() == 0u;
let len = opts.len();
// Compile subtrees for each option
@ -1721,7 +1776,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
// If none of these subcases match, move on to the
// next condition.
branch_chk = Some::<mk_fail>(|| bcx.llbb);
branch_chk = JumpToBasicBlock(bcx.llbb);
CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb);
}
_ => ()
@ -1860,11 +1915,15 @@ fn trans_match_inner(scope_cx: @mut Block,
if ty::type_is_empty(tcx, t) {
// Special case for empty types
let fail_cx = @mut None;
let f: mk_fail = || mk_fail(scope_cx, discr_expr.span,
@"scrutinizing value that can't exist", fail_cx);
Some(f)
let fail_handler = @DynamicFailureHandler {
bcx: scope_cx,
sp: discr_expr.span,
msg: @"scrutinizing value that can't exist",
finished: fail_cx,
} as @CustomFailureHandler;
CustomFailureHandlerClass(fail_handler)
} else {
None
Infallible
}
};
let lldiscr = discr_datum.to_zeroable_ref_llval(bcx);
@ -1892,15 +1951,6 @@ fn trans_match_inner(scope_cx: @mut Block,
bcx = controlflow::join_blocks(scope_cx, arm_cxs);
return bcx;
fn mk_fail(bcx: @mut Block, sp: Span, msg: @str,
finished: @mut Option<BasicBlockRef>) -> BasicBlockRef {
match *finished { Some(bb) => return bb, _ => () }
let fail_cx = sub_block(bcx, "case_fallthrough");
controlflow::trans_fail(fail_cx, Some(sp), msg);
*finished = Some(fail_cx.llbb);
return fail_cx.llbb;
}
}
enum IrrefutablePatternBindingMode {
@ -1913,7 +1963,7 @@ enum IrrefutablePatternBindingMode {
pub fn store_local(bcx: @mut Block,
pat: @ast::Pat,
opt_init_expr: Option<@ast::Expr>)
-> @mut Block {
-> @mut Block {
/*!
* Generates code for a local variable declaration like
* `let <pat>;` or `let <pat> = <opt_init_expr>`.

View File

@ -1320,7 +1320,7 @@ pub fn trans_block_cleanups_(bcx: @mut Block,
// Some types don't need to be cleaned up during
// landing pads because they can be freed en mass later
if cleanup_type == normal_exit_and_unwind || !is_lpad {
bcx = cfn(bcx);
bcx = cfn.clean(bcx);
}
}
}

View File

@ -172,7 +172,7 @@ pub fn allocate_cbox(bcx: @mut Block, sigil: ast::Sigil, cdata_ty: ty::t)
// Allocate and initialize the box:
match sigil {
ast::ManagedSigil => {
malloc_raw(bcx, cdata_ty, heap_managed)
tcx.sess.bug("trying to trans allocation of @fn")
}
ast::OwnedSigil => {
malloc_raw(bcx, cdata_ty, heap_for_unique_closure(bcx, cdata_ty))
@ -197,7 +197,8 @@ pub struct ClosureResult {
// Otherwise, it is stack allocated and copies pointers to the upvars.
pub fn store_environment(bcx: @mut Block,
bound_values: ~[EnvValue],
sigil: ast::Sigil) -> ClosureResult {
sigil: ast::Sigil)
-> ClosureResult {
let _icx = push_ctxt("closure::store_environment");
let ccx = bcx.ccx();
let tcx = ccx.tcx;
@ -444,27 +445,6 @@ pub fn make_closure_glue(
}
}
pub fn make_opaque_cbox_take_glue(
bcx: @mut Block,
sigil: ast::Sigil,
cboxptr: ValueRef) // ptr to ptr to the opaque closure
-> @mut Block {
// Easy cases:
let _icx = push_ctxt("closure::make_opaque_cbox_take_glue");
match sigil {
ast::BorrowedSigil => {
return bcx;
}
ast::ManagedSigil => {
glue::incr_refcnt_of_boxed(bcx, Load(bcx, cboxptr));
return bcx;
}
ast::OwnedSigil => {
fail!("unique closures are not copyable")
}
}
}
pub fn make_opaque_cbox_drop_glue(
bcx: @mut Block,
sigil: ast::Sigil,
@ -474,9 +454,7 @@ pub fn make_opaque_cbox_drop_glue(
match sigil {
ast::BorrowedSigil => bcx,
ast::ManagedSigil => {
glue::decr_refcnt_maybe_free(
bcx, Load(bcx, cboxptr), Some(cboxptr),
ty::mk_opaque_closure_ptr(bcx.tcx(), sigil))
bcx.tcx().sess.bug("trying to trans drop glue of @fn")
}
ast::OwnedSigil => {
glue::free_ty(
@ -516,12 +494,8 @@ pub fn make_opaque_cbox_free_glue(
abi::tydesc_field_drop_glue, None);
// Free the ty descr (if necc) and the box itself
match sigil {
ast::ManagedSigil => glue::trans_free(bcx, cbox),
ast::OwnedSigil => glue::trans_exchange_free(bcx, cbox),
ast::BorrowedSigil => {
bcx.sess().bug("impossible")
}
}
glue::trans_exchange_free(bcx, cbox);
bcx
}
}

View File

@ -294,9 +294,85 @@ pub enum cleantype {
normal_exit_and_unwind
}
// Cleanup functions
/// A cleanup function: a built-in destructor.
pub trait CleanupFunction {
fn clean(&self, block: @mut Block) -> @mut Block;
}
/// A cleanup function that calls the "drop glue" (destructor function) on
/// a typed value.
pub struct TypeDroppingCleanupFunction {
val: ValueRef,
t: ty::t,
}
impl CleanupFunction for TypeDroppingCleanupFunction {
fn clean(&self, block: @mut Block) -> @mut Block {
glue::drop_ty(block, self.val, self.t)
}
}
/// A cleanup function that calls the "drop glue" (destructor function) on
/// an immediate typed value.
pub struct ImmediateTypeDroppingCleanupFunction {
val: ValueRef,
t: ty::t,
}
impl CleanupFunction for ImmediateTypeDroppingCleanupFunction {
fn clean(&self, block: @mut Block) -> @mut Block {
glue::drop_ty_immediate(block, self.val, self.t)
}
}
/// A cleanup function that releases a write guard, returning a value to
/// mutable status.
pub struct WriteGuardReleasingCleanupFunction {
root_key: root_map_key,
frozen_val_ref: ValueRef,
bits_val_ref: ValueRef,
filename_val: ValueRef,
line_val: ValueRef,
}
impl CleanupFunction for WriteGuardReleasingCleanupFunction {
fn clean(&self, bcx: @mut Block) -> @mut Block {
write_guard::return_to_mut(bcx,
self.root_key,
self.frozen_val_ref,
self.bits_val_ref,
self.filename_val,
self.line_val)
}
}
/// A cleanup function that frees some memory in the garbage-collected heap.
pub struct GCHeapFreeingCleanupFunction {
ptr: ValueRef,
}
impl CleanupFunction for GCHeapFreeingCleanupFunction {
fn clean(&self, bcx: @mut Block) -> @mut Block {
glue::trans_free(bcx, self.ptr)
}
}
/// A cleanup function that frees some memory in the exchange heap.
pub struct ExchangeHeapFreeingCleanupFunction {
ptr: ValueRef,
}
impl CleanupFunction for ExchangeHeapFreeingCleanupFunction {
fn clean(&self, bcx: @mut Block) -> @mut Block {
glue::trans_exchange_free(bcx, self.ptr)
}
}
pub enum cleanup {
clean(@fn(@mut Block) -> @mut Block, cleantype),
clean_temp(ValueRef, @fn(@mut Block) -> @mut Block, cleantype),
clean(@CleanupFunction, cleantype),
clean_temp(ValueRef, @CleanupFunction, cleantype),
}
// Can't use deriving(Clone) because of the managed closure.
@ -337,13 +413,19 @@ pub fn cleanup_type(cx: ty::ctxt, ty: ty::t) -> cleantype {
}
pub fn add_clean(bcx: @mut Block, val: ValueRef, t: ty::t) {
if !ty::type_needs_drop(bcx.tcx(), t) { return; }
if !ty::type_needs_drop(bcx.tcx(), t) {
return
}
debug!("add_clean(%s, %s, %s)", bcx.to_str(), bcx.val_to_str(val), t.repr(bcx.tcx()));
let cleanup_type = cleanup_type(bcx.tcx(), t);
do in_scope_cx(bcx, None) |scope_info| {
scope_info.cleanups.push(clean(|a| glue::drop_ty(a, val, t), cleanup_type));
scope_info.cleanups.push(clean(@TypeDroppingCleanupFunction {
val: val,
t: t,
} as @CleanupFunction,
cleanup_type));
grow_scope_clean(scope_info);
}
}
@ -355,9 +437,12 @@ pub fn add_clean_temp_immediate(cx: @mut Block, val: ValueRef, ty: ty::t) {
ty.repr(cx.tcx()));
let cleanup_type = cleanup_type(cx.tcx(), ty);
do in_scope_cx(cx, None) |scope_info| {
scope_info.cleanups.push(
clean_temp(val, |a| glue::drop_ty_immediate(a, val, ty),
cleanup_type));
scope_info.cleanups.push(clean_temp(val,
@ImmediateTypeDroppingCleanupFunction {
val: val,
t: ty,
} as @CleanupFunction,
cleanup_type));
grow_scope_clean(scope_info);
}
}
@ -381,7 +466,12 @@ pub fn add_clean_temp_mem_in_scope_(bcx: @mut Block, scope_id: Option<ast::NodeI
t.repr(bcx.tcx()));
let cleanup_type = cleanup_type(bcx.tcx(), t);
do in_scope_cx(bcx, scope_id) |scope_info| {
scope_info.cleanups.push(clean_temp(val, |a| glue::drop_ty(a, val, t), cleanup_type));
scope_info.cleanups.push(clean_temp(val,
@TypeDroppingCleanupFunction {
val: val,
t: t,
} as @CleanupFunction,
cleanup_type));
grow_scope_clean(scope_info);
}
}
@ -405,29 +495,36 @@ pub fn add_clean_return_to_mut(bcx: @mut Block,
bcx.val_to_str(frozen_val_ref),
bcx.val_to_str(bits_val_ref));
do in_scope_cx(bcx, Some(scope_id)) |scope_info| {
scope_info.cleanups.push(
clean_temp(
scope_info.cleanups.push(clean_temp(
frozen_val_ref,
|bcx| write_guard::return_to_mut(bcx, root_key, frozen_val_ref, bits_val_ref,
filename_val, line_val),
@WriteGuardReleasingCleanupFunction {
root_key: root_key,
frozen_val_ref: frozen_val_ref,
bits_val_ref: bits_val_ref,
filename_val: filename_val,
line_val: line_val,
} as @CleanupFunction,
normal_exit_only));
grow_scope_clean(scope_info);
}
}
pub fn add_clean_free(cx: @mut Block, ptr: ValueRef, heap: heap) {
let free_fn = match heap {
heap_managed | heap_managed_unique => {
let f: @fn(@mut Block) -> @mut Block = |a| glue::trans_free(a, ptr);
f
}
heap_exchange | heap_exchange_closure => {
let f: @fn(@mut Block) -> @mut Block = |a| glue::trans_exchange_free(a, ptr);
f
}
heap_managed | heap_managed_unique => {
@GCHeapFreeingCleanupFunction {
ptr: ptr,
} as @CleanupFunction
}
heap_exchange | heap_exchange_closure => {
@ExchangeHeapFreeingCleanupFunction {
ptr: ptr,
} as @CleanupFunction
}
};
do in_scope_cx(cx, None) |scope_info| {
scope_info.cleanups.push(clean_temp(ptr, free_fn,
normal_exit_and_unwind));
scope_info.cleanups.push(clean_temp(ptr,
free_fn,
normal_exit_and_unwind));
grow_scope_clean(scope_info);
}
}

View File

@ -1086,6 +1086,36 @@ fn pointer_type_metadata(cx: &mut CrateContext,
return ptr_metadata;
}
trait MemberDescriptionFactory {
fn create_member_descriptions(&self, cx: &mut CrateContext)
-> ~[MemberDescription];
}
struct StructMemberDescriptionFactory {
fields: ~[ty::field],
span: Span,
}
impl MemberDescriptionFactory for StructMemberDescriptionFactory {
fn create_member_descriptions(&self, cx: &mut CrateContext)
-> ~[MemberDescription] {
do self.fields.map |field| {
let name = if field.ident.name == special_idents::unnamed_field.name {
@""
} else {
token::ident_to_str(&field.ident)
};
MemberDescription {
name: name,
llvm_type: type_of::type_of(cx, field.mt.ty),
type_metadata: type_metadata(cx, field.mt.ty, self.span),
offset: ComputedMemberOffset,
}
}
}
}
fn prepare_struct_metadata(cx: &mut CrateContext,
struct_type: ty::t,
def_id: ast::DefId,
@ -1114,22 +1144,10 @@ fn prepare_struct_metadata(cx: &mut CrateContext,
metadata_stub: struct_metadata_stub,
llvm_type: struct_llvm_type,
file_metadata: file_metadata,
member_description_factory: |cx| {
do fields.map |field| {
let name = if field.ident.name == special_idents::unnamed_field.name {
@""
} else {
token::ident_to_str(&field.ident)
};
MemberDescription {
name: name,
llvm_type: type_of::type_of(cx, field.mt.ty),
type_metadata: type_metadata(cx, field.mt.ty, span),
offset: ComputedMemberOffset,
}
}
}
member_description_factory: @StructMemberDescriptionFactory {
fields: fields,
span: span,
} as @MemberDescriptionFactory,
}
}
@ -1139,7 +1157,7 @@ enum RecursiveTypeDescription {
metadata_stub: DICompositeType,
llvm_type: Type,
file_metadata: DIFile,
member_description_factory: @fn(cx: &mut CrateContext) -> ~[MemberDescription],
member_description_factory: @MemberDescriptionFactory,
},
FinalMetadata(DICompositeType)
}
@ -1167,7 +1185,8 @@ impl RecursiveTypeDescription {
debug_context(cx).created_types.insert(cache_id, metadata_stub);
// ... then create the member descriptions ...
let member_descriptions = member_description_factory(cx);
let member_descriptions = member_description_factory.
create_member_descriptions(cx);
// ... and attach them to the stub to complete it.
set_members_of_composite_type(cx,
@ -1182,6 +1201,25 @@ impl RecursiveTypeDescription {
}
}
struct TupleMemberDescriptionFactory {
component_types: ~[ty::t],
span: Span,
}
impl MemberDescriptionFactory for TupleMemberDescriptionFactory {
fn create_member_descriptions(&self, cx: &mut CrateContext)
-> ~[MemberDescription] {
do self.component_types.map |&component_type| {
MemberDescription {
name: @"",
llvm_type: type_of::type_of(cx, component_type),
type_metadata: type_metadata(cx, component_type, self.span),
offset: ComputedMemberOffset,
}
}
}
}
fn prepare_tuple_metadata(cx: &mut CrateContext,
tuple_type: ty::t,
component_types: &[ty::t],
@ -1192,8 +1230,6 @@ fn prepare_tuple_metadata(cx: &mut CrateContext,
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, loc.file.name);
// Needs to be copied for closure below :(
let component_types = component_types.to_owned();
UnfinishedMetadata {
cache_id: cache_id_for_type(tuple_type),
@ -1205,17 +1241,147 @@ fn prepare_tuple_metadata(cx: &mut CrateContext,
span),
llvm_type: tuple_llvm_type,
file_metadata: file_metadata,
member_description_factory: |cx| {
do component_types.map |&component_type| {
member_description_factory: @TupleMemberDescriptionFactory {
component_types: component_types.to_owned(),
span: span,
} as @MemberDescriptionFactory
}
}
struct GeneralMemberDescriptionFactory {
type_rep: @adt::Repr,
variants: @~[@ty::VariantInfo],
discriminant_type_metadata: ValueRef,
containing_scope: DIScope,
file_metadata: DIFile,
span: Span,
}
impl MemberDescriptionFactory for GeneralMemberDescriptionFactory {
fn create_member_descriptions(&self, cx: &mut CrateContext)
-> ~[MemberDescription] {
// Capture type_rep, so we don't have to copy the struct_defs array
let struct_defs = match *self.type_rep {
adt::General(ref struct_defs) => struct_defs,
_ => cx.sess.bug("unreachable")
};
do struct_defs
.iter()
.enumerate()
.map |(i, struct_def)| {
let (variant_type_metadata, variant_llvm_type, member_desc_factory) =
describe_variant(cx,
struct_def,
self.variants[i],
Some(self.discriminant_type_metadata),
self.containing_scope,
self.file_metadata,
self.span);
let member_descriptions =
member_desc_factory.create_member_descriptions(cx);
set_members_of_composite_type(cx,
variant_type_metadata,
variant_llvm_type,
member_descriptions,
self.file_metadata,
codemap::dummy_sp());
MemberDescription {
name: @"",
llvm_type: type_of::type_of(cx, component_type),
type_metadata: type_metadata(cx, component_type, span),
offset: ComputedMemberOffset,
llvm_type: variant_llvm_type,
type_metadata: variant_type_metadata,
offset: FixedMemberOffset { bytes: 0 },
}
}.collect()
}
}
struct EnumVariantMemberDescriptionFactory {
args: ~[(@str, ty::t)],
discriminant_type_metadata: Option<DIType>,
span: Span,
}
impl MemberDescriptionFactory for EnumVariantMemberDescriptionFactory {
fn create_member_descriptions(&self, cx: &mut CrateContext)
-> ~[MemberDescription] {
do self.args.iter().enumerate().map |(i, &(name, ty))| {
MemberDescription {
name: name,
llvm_type: type_of::type_of(cx, ty),
type_metadata: match self.discriminant_type_metadata {
Some(metadata) if i == 0 => metadata,
_ => type_metadata(cx, ty, self.span)
},
offset: ComputedMemberOffset,
}
}.collect()
}
}
fn describe_variant(cx: &mut CrateContext,
struct_def: &adt::Struct,
variant_info: &ty::VariantInfo,
discriminant_type_metadata: Option<DIType>,
containing_scope: DIScope,
file_metadata: DIFile,
span: Span)
-> (DICompositeType, Type, @MemberDescriptionFactory) {
let variant_name = token::ident_to_str(&variant_info.name);
let variant_llvm_type = Type::struct_(struct_def.fields.map(|&t| type_of::type_of(cx, t)),
struct_def.packed);
// Could some consistency checks here: size, align, field count, discr type
// Find the source code location of the variant's definition
let variant_definition_span = if variant_info.id.crate == ast::LOCAL_CRATE {
match cx.tcx.items.find(&variant_info.id.node) {
Some(&ast_map::node_variant(ref variant, _, _)) => variant.span,
ref node => {
cx.sess.span_warn(span,
fmt!("debuginfo::enum_metadata()::adt_struct_metadata() - Unexpected node \
type: %?. This is a bug.", node));
codemap::dummy_sp()
}
}
} else {
// For definitions from other crates we have no location information available.
codemap::dummy_sp()
};
let metadata_stub = create_struct_stub(cx,
variant_llvm_type,
variant_name,
containing_scope,
file_metadata,
variant_definition_span);
// Get the argument names from the enum variant info
let mut arg_names = match variant_info.arg_names {
Some(ref names) => do names.map |ident| { token::ident_to_str(ident) },
None => do variant_info.args.map |_| { @"" }
};
// If this is not a univariant enum, there is also the (unnamed) discriminant field
if discriminant_type_metadata.is_some() {
arg_names.insert(0, @"");
}
// Build an array of (field name, field type) pairs to be captured in the factory closure.
let args: ~[(@str, ty::t)] = arg_names.iter()
.zip(struct_def.fields.iter())
.map(|(&s, &t)| (s, t))
.collect();
let member_description_factory =
@EnumVariantMemberDescriptionFactory {
args: args,
discriminant_type_metadata: discriminant_type_metadata,
span: span,
} as @MemberDescriptionFactory;
(metadata_stub, variant_llvm_type, member_description_factory)
}
fn prepare_enum_metadata(cx: &mut CrateContext,
@ -1336,42 +1502,14 @@ fn prepare_enum_metadata(cx: &mut CrateContext,
metadata_stub: enum_metadata,
llvm_type: enum_llvm_type,
file_metadata: file_metadata,
member_description_factory: |cx| {
// Capture type_rep, so we don't have to copy the struct_defs array
let struct_defs = match *type_rep {
adt::General(ref struct_defs) => struct_defs,
_ => cx.sess.bug("unreachable")
};
do struct_defs
.iter()
.enumerate()
.map |(i, struct_def)| {
let (variant_type_metadata, variant_llvm_type, member_desc_factory) =
describe_variant(cx,
struct_def,
variants[i],
Some(discriminant_type_metadata),
containing_scope,
file_metadata,
span);
let member_descriptions = member_desc_factory(cx);
set_members_of_composite_type(cx,
variant_type_metadata,
variant_llvm_type,
member_descriptions,
file_metadata,
codemap::dummy_sp());
MemberDescription {
name: @"",
llvm_type: variant_llvm_type,
type_metadata: variant_type_metadata,
offset: FixedMemberOffset { bytes: 0 },
}
}.collect()
}
member_description_factory: @GeneralMemberDescriptionFactory {
type_rep: type_rep,
variants: variants,
discriminant_type_metadata: discriminant_type_metadata,
containing_scope: containing_scope,
file_metadata: file_metadata,
span: span,
} as @MemberDescriptionFactory,
}
}
adt::NullablePointer { nonnull: ref struct_def, nndiscr, _ } => {
@ -1393,76 +1531,6 @@ fn prepare_enum_metadata(cx: &mut CrateContext,
}
}
};
fn describe_variant(cx: &mut CrateContext,
struct_def: &adt::Struct,
variant_info: &ty::VariantInfo,
discriminant_type_metadata: Option<DIType>,
containing_scope: DIScope,
file_metadata: DIFile,
span: Span)
-> (DICompositeType, Type, @fn(&mut CrateContext) -> ~[MemberDescription]) {
let variant_name = token::ident_to_str(&variant_info.name);
let variant_llvm_type = Type::struct_(struct_def.fields.map(|&t| type_of::type_of(cx, t)),
struct_def.packed);
// Could some consistency checks here: size, align, field count, discr type
// Find the source code location of the variant's definition
let variant_definition_span = if variant_info.id.crate == ast::LOCAL_CRATE {
match cx.tcx.items.find(&variant_info.id.node) {
Some(&ast_map::node_variant(ref variant, _, _)) => variant.span,
ref node => {
cx.sess.span_warn(span,
fmt!("debuginfo::enum_metadata()::adt_struct_metadata() - Unexpected node \
type: %?. This is a bug.", node));
codemap::dummy_sp()
}
}
} else {
// For definitions from other crates we have no location information available.
codemap::dummy_sp()
};
let metadata_stub = create_struct_stub(cx,
variant_llvm_type,
variant_name,
containing_scope,
file_metadata,
variant_definition_span);
// Get the argument names from the enum variant info
let mut arg_names = match variant_info.arg_names {
Some(ref names) => do names.map |ident| { token::ident_to_str(ident) },
None => do variant_info.args.map |_| { @"" }
};
// If this is not a univariant enum, there is also the (unnamed) discriminant field
if discriminant_type_metadata.is_some() {
arg_names.insert(0, @"");
}
// Build an array of (field name, field type) pairs to be captured in the factory closure.
let args: ~[(@str, ty::t)] = arg_names.iter()
.zip(struct_def.fields.iter())
.map(|(&s, &t)| (s, t))
.collect();
let member_description_factory: @fn(cx: &mut CrateContext) -> ~[MemberDescription] = |cx| {
do args.iter().enumerate().map |(i, &(name, ty))| {
MemberDescription {
name: name,
llvm_type: type_of::type_of(cx, ty),
type_metadata: match discriminant_type_metadata {
Some(metadata) if i == 0 => metadata,
_ => type_metadata(cx, ty, span)
},
offset: ComputedMemberOffset,
}
}.collect()
};
(metadata_stub, variant_llvm_type, member_description_factory)
}
}
enum MemberOffset {

View File

@ -581,11 +581,7 @@ pub fn make_take_glue(bcx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
| ty::ty_estr(ty::vstore_slice(_)) => {
bcx
}
ty::ty_closure(ty::ClosureTy { sigil: ast::BorrowedSigil, _ }) |
ty::ty_closure(ty::ClosureTy { sigil: ast::ManagedSigil, _ }) => {
closure::make_closure_glue(bcx, v, t, take_ty)
}
ty::ty_closure(ty::ClosureTy { sigil: ast::OwnedSigil, _ }) => bcx,
ty::ty_closure(_) => bcx,
ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
let llbox = Load(bcx, GEPi(bcx, v, [0u, abi::trt_field_box]));
incr_refcnt_of_boxed(bcx, llbox);
@ -606,9 +602,7 @@ pub fn make_take_glue(bcx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
None);
bcx
}
ty::ty_opaque_closure_ptr(ck) => {
closure::make_opaque_cbox_take_glue(bcx, ck, v)
}
ty::ty_opaque_closure_ptr(_) => bcx,
ty::ty_struct(did, _) => {
let tcx = bcx.tcx();
let bcx = iter_structural_ty(bcx, v, t, take_ty);

View File

@ -2308,12 +2308,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
ast::Many => TC_NONE
};
// Prevent noncopyable types captured in the environment from being copied.
let ct = if cty.sigil == ast::ManagedSigil {
TC_NONE
} else {
TC_NONCOPY_TRAIT
};
st + rt + ot + ct
st + rt + ot + TC_NONCOPY_TRAIT
}
fn trait_contents(store: TraitStore, mutbl: ast::Mutability,

View File

@ -400,6 +400,11 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope + Clone + 'static>(
bf.abis, &bf.lifetimes, &bf.decl))
}
ast::ty_closure(ref f) => {
if f.sigil == ast::ManagedSigil {
tcx.sess.span_err(ast_ty.span,
"managed closures are not supported");
}
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, match f.sigil {
// Use corresponding trait store to figure out default bounds
// if none were specified.

View File

@ -33,6 +33,7 @@ use driver::driver::{compile_input};
use driver::session;
use middle::lint;
use std::comm;
use std::io;
use std::num;
use std::os;
@ -43,6 +44,7 @@ use std::vec;
use extra::getopts::groups;
use extra::getopts;
use syntax::codemap;
use syntax::diagnostic::Emitter;
use syntax::diagnostic;
pub mod middle {
@ -191,7 +193,7 @@ pub fn describe_debug_flags() {
}
}
pub fn run_compiler(args: &[~str], demitter: diagnostic::Emitter) {
pub fn run_compiler(args: &[~str], demitter: @diagnostic::Emitter) {
// Don't display log spew by default. Can override with RUST_LOG.
::std::logging::console_off();
@ -291,6 +293,23 @@ pub enum monitor_msg {
done,
}
struct RustcEmitter {
ch_capture: comm::SharedChan<monitor_msg>
}
impl diagnostic::Emitter for RustcEmitter {
fn emit(&self,
cmsp: Option<(@codemap::CodeMap, codemap::Span)>,
msg: &str,
lvl: diagnostic::level) {
if lvl == diagnostic::fatal {
self.ch_capture.send(fatal)
}
diagnostic::DefaultEmitter.emit(cmsp, msg, lvl)
}
}
/*
This is a sanity check that any failure of the compiler is performed
through the diagnostic module and reported properly - we shouldn't be calling
@ -303,7 +322,7 @@ diagnostic emitter which records when we hit a fatal error. If the task
fails without recording a fatal error then we've encountered a compiler
bug and need to present an error.
*/
pub fn monitor(f: ~fn(diagnostic::Emitter)) {
pub fn monitor(f: ~fn(@diagnostic::Emitter)) {
use std::comm::*;
// XXX: This is a hack for newsched since it doesn't support split stacks.
@ -324,18 +343,11 @@ pub fn monitor(f: ~fn(diagnostic::Emitter)) {
match do task_builder.try {
let ch = ch_capture.clone();
let ch_capture = ch.clone();
// The 'diagnostics emitter'. Every error, warning, etc. should
// go through this function.
let demitter: @fn(Option<(@codemap::CodeMap, codemap::Span)>,
&str,
diagnostic::level) =
|cmsp, msg, lvl| {
if lvl == diagnostic::fatal {
ch_capture.send(fatal);
}
diagnostic::emit(cmsp, msg, lvl);
};
let demitter = @RustcEmitter {
ch_capture: ch.clone(),
} as @diagnostic::Emitter;
struct finally {
ch: SharedChan<monitor_msg>,
@ -357,7 +369,7 @@ pub fn monitor(f: ~fn(diagnostic::Emitter)) {
result::Err(_) => {
// Task failed without emitting a fatal diagnostic
if p.recv() == done {
diagnostic::emit(
diagnostic::DefaultEmitter.emit(
None,
diagnostic::ice_msg("unexpected failure"),
diagnostic::error);
@ -370,7 +382,9 @@ pub fn monitor(f: ~fn(diagnostic::Emitter)) {
to github.com/mozilla/rust/issues"
];
for note in xs.iter() {
diagnostic::emit(None, *note, diagnostic::note)
diagnostic::DefaultEmitter.emit(None,
*note,
diagnostic::note)
}
}
// Fail so the process returns a failure code

View File

@ -60,12 +60,12 @@ pub fn field_exprs(fields: ~[ast::Field]) -> ~[@ast::Expr] {
fields.map(|f| f.expr)
}
struct LoopQueryVisitor {
p: @fn(&ast::Expr_) -> bool
struct LoopQueryVisitor<'self> {
p: &'self fn(&ast::Expr_) -> bool
}
impl Visitor<@mut bool> for LoopQueryVisitor {
fn visit_expr(&mut self, e:@ast::Expr, flag:@mut bool) {
impl<'self> Visitor<@mut bool> for LoopQueryVisitor<'self> {
fn visit_expr(&mut self, e: @ast::Expr, flag: @mut bool) {
*flag |= (self.p)(&e.node);
match e.node {
// Skip inner loops, since a break in the inner loop isn't a
@ -78,19 +78,21 @@ impl Visitor<@mut bool> for LoopQueryVisitor {
// Takes a predicate p, returns true iff p is true for any subexpressions
// of b -- skipping any inner loops (loop, while, loop_body)
pub fn loop_query(b: &ast::Block, p: @fn(&ast::Expr_) -> bool) -> bool {
pub fn loop_query(b: &ast::Block, p: &fn(&ast::Expr_) -> bool) -> bool {
let rs = @mut false;
let mut v = LoopQueryVisitor { p: p };
let mut v = LoopQueryVisitor {
p: p,
};
visit::walk_block(&mut v, b, rs);
return *rs;
}
struct BlockQueryVisitor {
p: @fn(@ast::Expr) -> bool
struct BlockQueryVisitor<'self> {
p: &'self fn(@ast::Expr) -> bool
}
impl Visitor<@mut bool> for BlockQueryVisitor {
fn visit_expr(&mut self, e:@ast::Expr, flag:@mut bool) {
impl<'self> Visitor<@mut bool> for BlockQueryVisitor<'self> {
fn visit_expr(&mut self, e: @ast::Expr, flag: @mut bool) {
*flag |= (self.p)(e);
visit::walk_expr(self, e, flag)
}
@ -98,9 +100,11 @@ impl Visitor<@mut bool> for BlockQueryVisitor {
// Takes a predicate p, returns true iff p is true for any subexpressions
// of b -- skipping any inner loops (loop, while, loop_body)
pub fn block_query(b: &ast::Block, p: @fn(@ast::Expr) -> bool) -> bool {
pub fn block_query(b: &ast::Block, p: &fn(@ast::Expr) -> bool) -> bool {
let rs = @mut false;
let mut v = BlockQueryVisitor { p: p };
let mut v = BlockQueryVisitor {
p: p,
};
visit::walk_block(&mut v, b, rs);
return *rs;
}

View File

@ -11,9 +11,10 @@
use rustc;
use rustc::{driver, middle};
use syntax;
use syntax::parse;
use syntax::ast;
use syntax::diagnostic;
use syntax::parse;
use syntax;
use std::os;
use std::local_data;
@ -48,9 +49,11 @@ fn get_ast_and_resolve(cpath: &Path, libs: ~[Path]) -> DocContext {
let span_diagnostic_handler =
syntax::diagnostic::mk_span_handler(diagnostic_handler, parsesess.cm);
let sess = driver::driver::build_session_(sessopts, parsesess.cm,
syntax::diagnostic::emit,
span_diagnostic_handler);
let sess = driver::driver::build_session_(sessopts,
parsesess.cm,
@diagnostic::DefaultEmitter as
@diagnostic::Emitter,
span_diagnostic_handler);
let mut cfg = build_configuration(sess);
cfg.push(@dummy_spanned(ast::MetaWord(@"stage2")));

View File

@ -72,12 +72,14 @@ extern mod syntax;
use std::{libc, io, os, task};
use std::cell::Cell;
use extra::rl::CompletionCb;
use extra::rl;
use rustc::driver::{driver, session};
use rustc::back::link::jit;
use syntax::{ast, diagnostic};
use syntax::{ast, codemap, diagnostic};
use syntax::ast_util::*;
use syntax::diagnostic::Emitter;
use syntax::parse::token;
use syntax::print::pprust;
@ -107,6 +109,28 @@ enum CmdAction {
action_run_line(~str),
}
struct EncodableWarningEmitter;
impl diagnostic::Emitter for EncodableWarningEmitter {
fn emit(&self,
cm: Option<(@codemap::CodeMap, codemap::Span)>,
msg: &str,
lvl: diagnostic::level) {
diagnostic::DefaultEmitter.emit(cm, msg, lvl);
if msg.contains("failed to find an implementation of trait") &&
msg.contains("extra::serialize::Encodable") {
diagnostic::DefaultEmitter.emit(cm,
"Currrently rusti serializes \
bound locals between different \
lines of input. This means that \
all values of local variables \
need to be encodable, and this \
type isn't encodable",
diagnostic::note);
}
}
}
/// Run an input string in a Repl, returning the new Repl.
fn run(mut program: ~Program, binary: ~str, lib_search_paths: ~[~str],
input: ~str) -> (~Program, Option<~jit::Engine>)
@ -124,18 +148,9 @@ fn run(mut program: ~Program, binary: ~str, lib_search_paths: ~[~str],
// extra helpful information if the error crops up. Otherwise people are
// bound to be very confused when they find out code is running that they
// never typed in...
let sess = driver::build_session(options, |cm, msg, lvl| {
diagnostic::emit(cm, msg, lvl);
if msg.contains("failed to find an implementation of trait") &&
msg.contains("extra::serialize::Encodable") {
diagnostic::emit(cm,
"Currrently rusti serializes bound locals between \
different lines of input. This means that all \
values of local variables need to be encodable, \
and this type isn't encodable",
diagnostic::note);
}
});
let sess = driver::build_session(options,
@EncodableWarningEmitter as
@diagnostic::Emitter);
let intr = token::get_ident_interner();
//
@ -243,7 +258,9 @@ fn run(mut program: ~Program, binary: ~str, lib_search_paths: ~[~str],
let input = driver::str_input(code.to_managed());
let cfg = driver::build_configuration(sess);
let outputs = driver::build_output_filenames(&input, &None, &None, [], sess);
let sess = driver::build_session(options, diagnostic::emit);
let sess = driver::build_session(options,
@diagnostic::DefaultEmitter as
@diagnostic::Emitter);
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
let expanded_crate = driver::phase_2_configure_and_expand(sess, cfg, crate);
@ -305,7 +322,9 @@ fn compile_crate(src_filename: ~str, binary: ~str) -> Option<bool> {
.. (*session::basic_options()).clone()
};
let input = driver::file_input(src_path.clone());
let sess = driver::build_session(options, diagnostic::emit);
let sess = driver::build_session(options,
@diagnostic::DefaultEmitter as
@diagnostic::Emitter);
*sess.building_library = true;
let cfg = driver::build_configuration(sess);
let outputs = driver::build_output_filenames(
@ -502,6 +521,19 @@ pub fn main() {
main_args(args);
}
struct Completer;
impl CompletionCb for Completer {
fn complete(&self, line: ~str, suggest: &fn(~str)) {
if line.starts_with(":") {
suggest(~":clear");
suggest(~":exit");
suggest(~":help");
suggest(~":load");
}
}
}
pub fn main_args(args: &[~str]) {
#[fixed_stack_segment]; #[inline(never)];
@ -525,13 +557,8 @@ pub fn main_args(args: &[~str]) {
println("unstable. If you encounter problems, please use the");
println("compiler instead. Type :help for help.");
do rl::complete |line, suggest| {
if line.starts_with(":") {
suggest(~":clear");
suggest(~":exit");
suggest(~":help");
suggest(~":load");
}
unsafe {
rl::complete(@Completer as @CompletionCb)
}
}

View File

@ -15,11 +15,11 @@ use syntax::print::pprust;
use syntax::parse::token;
use syntax::visit;
struct EachBindingVisitor {
f: @fn(&ast::Path, ast::NodeId)
struct EachBindingVisitor<'self> {
f: &'self fn(&ast::Path, ast::NodeId)
}
impl visit::Visitor<()> for EachBindingVisitor {
impl<'self> visit::Visitor<()> for EachBindingVisitor<'self> {
fn visit_pat(&mut self, pat:@ast::Pat, _:()) {
match pat.node {
ast::PatIdent(_, ref path, _) => {
@ -32,7 +32,7 @@ impl visit::Visitor<()> for EachBindingVisitor {
}
}
pub fn each_binding(l: @ast::Local, f: @fn(&ast::Path, ast::NodeId)) {
pub fn each_binding(l: @ast::Local, f: &fn(&ast::Path, ast::NodeId)) {
use syntax::visit::Visitor;
let mut vt = EachBindingVisitor{ f: f };

View File

@ -110,7 +110,9 @@ impl<'self> PkgScript<'self> {
.. (*session::basic_options()).clone()
};
let input = driver::file_input(script.clone());
let sess = driver::build_session(options, diagnostic::emit);
let sess = driver::build_session(options,
@diagnostic::DefaultEmitter as
@diagnostic::Emitter);
let cfg = driver::build_configuration(sess);
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
let crate = driver::phase_2_configure_and_expand(sess, cfg.clone(), crate);

View File

@ -1567,8 +1567,11 @@ fn test_linker_build() {
let matches = getopts([], optgroups());
let options = build_session_options(@"rustpkg",
matches.get_ref(),
diagnostic::emit);
let sess = build_session(options, diagnostic::emit);
@diagnostic::DefaultEmitter as
@diagnostic::Emitter);
let sess = build_session(options,
@diagnostic::DefaultEmitter as
@diagnostic::Emitter);
command_line_test([test_sysroot().to_str(),
~"install",
~"--linker",

View File

@ -16,8 +16,11 @@ use extra::getopts::groups::getopts;
use syntax::ast_util::*;
use syntax::codemap::{dummy_sp, Spanned};
use syntax::ext::base::ExtCtxt;
use syntax::{ast, attr, codemap, diagnostic, fold};
use syntax::{ast, attr, codemap, diagnostic, fold, visit};
use syntax::attr::AttrMetaMethods;
use syntax::fold::ast_fold;
use syntax::visit::Visitor;
use rustc::back::link::output_type_exe;
use rustc::back::link;
use rustc::driver::session::{lib_crate, bin_crate};
use context::{in_target, StopBefore, Link, Assemble, BuildContext};
@ -26,6 +29,7 @@ use package_source::PkgSrc;
use workspace::pkg_parent_workspaces;
use path_util::{installed_library_in_workspace, U_RWX, rust_path, system_library, target_build_dir};
use messages::error;
use conditions::nonexistent_package::cond;
pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
use workcache_support::{digest_file_with_date, digest_only_date};
@ -70,9 +74,8 @@ struct ReadyCtx {
fns: ~[ListenerFn]
}
fn fold_mod(_ctx: @mut ReadyCtx,
m: &ast::_mod,
fold: @fold::ast_fold) -> ast::_mod {
fn fold_mod(_ctx: @mut ReadyCtx, m: &ast::_mod, fold: &CrateSetup)
-> ast::_mod {
fn strip_main(item: @ast::item) -> @ast::item {
@ast::item {
attrs: do item.attrs.iter().filter_map |attr| {
@ -94,9 +97,8 @@ fn fold_mod(_ctx: @mut ReadyCtx,
}, fold)
}
fn fold_item(ctx: @mut ReadyCtx,
item: @ast::item,
fold: @fold::ast_fold) -> Option<@ast::item> {
fn fold_item(ctx: @mut ReadyCtx, item: @ast::item, fold: &CrateSetup)
-> Option<@ast::item> {
ctx.path.push(item.ident);
let mut cmds = ~[];
@ -134,6 +136,19 @@ fn fold_item(ctx: @mut ReadyCtx,
res
}
struct CrateSetup {
ctx: @mut ReadyCtx,
}
impl fold::ast_fold for CrateSetup {
fn fold_item(&self, item: @ast::item) -> Option<@ast::item> {
fold_item(self.ctx, item, self)
}
fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
fold_mod(self.ctx, module, self)
}
}
/// Generate/filter main function, add the list of commands, etc.
pub fn ready_crate(sess: session::Session,
crate: @ast::Crate) -> @ast::Crate {
@ -144,15 +159,9 @@ pub fn ready_crate(sess: session::Session,
path: ~[],
fns: ~[]
};
let precursor = @fold::AstFoldFns {
// fold_crate: fold::wrap(|a, b| fold_crate(ctx, a, b)),
fold_item: |a, b| fold_item(ctx, a, b),
fold_mod: |a, b| fold_mod(ctx, a, b),
.. *fold::default_ast_fold()
let fold = CrateSetup {
ctx: ctx,
};
let fold = fold::make_fold(precursor);
@fold.fold_crate(crate)
}
@ -225,7 +234,10 @@ pub fn compile_input(context: &BuildContext,
maybe_sysroot: Some(sysroot_to_use),
addl_lib_search_paths: @mut (~[]),
output_type: output_type,
.. (*driver::build_session_options(binary, &matches, diagnostic::emit)).clone()
.. (*driver::build_session_options(binary,
&matches,
@diagnostic::DefaultEmitter as
@diagnostic::Emitter)).clone()
};
let addl_lib_search_paths = @mut options.addl_lib_search_paths;
@ -240,7 +252,9 @@ pub fn compile_input(context: &BuildContext,
}
}
let sess = driver::build_session(options, diagnostic::emit);
let sess = driver::build_session(options,
@diagnostic::DefaultEmitter as
@diagnostic::Emitter);
// Infer dependencies that rustpkg needs to build, by scanning for
// `extern mod` directives.
@ -383,31 +397,28 @@ pub fn compile_crate(ctxt: &BuildContext,
compile_input(ctxt, exec, pkg_id, crate, workspace, flags, cfgs, opt, what)
}
struct ViewItemVisitor<'self> {
context: &'self BuildContext,
parent: &'self PkgId,
sess: session::Session,
exec: &'self mut workcache::Exec,
c: &'self ast::Crate,
save: &'self fn(Path),
}
/// Collect all `extern mod` directives in `c`, then
/// try to install their targets, failing if any target
/// can't be found.
pub fn find_and_install_dependencies(context: &BuildContext,
parent: &PkgId,
sess: session::Session,
exec: &mut workcache::Exec,
c: &ast::Crate,
save: @fn(Path)
) {
use conditions::nonexistent_package::cond;
do c.each_view_item() |vi: &ast::view_item| {
impl<'self> Visitor<()> for ViewItemVisitor<'self> {
fn visit_view_item(&mut self, vi: &ast::view_item, env: ()) {
debug!("A view item!");
match vi.node {
// ignore metadata, I guess
ast::view_item_extern_mod(lib_ident, path_opt, _, _) => {
let lib_name = match path_opt {
Some(p) => p,
None => sess.str_of(lib_ident)
None => self.sess.str_of(lib_ident)
};
debug!("Finding and installing... %s", lib_name);
// Check standard Rust library path first
match system_library(&context.sysroot(), lib_name) {
match system_library(&self.context.sysroot(), lib_name) {
Some(ref installed_path) => {
debug!("It exists: %s", installed_path.to_str());
// Say that [path for c] has a discovered dependency on
@ -416,8 +427,9 @@ pub fn find_and_install_dependencies(context: &BuildContext,
// I'm not sure what the right thing is.
// Now we know that this crate has a discovered dependency on
// installed_path
exec.discover_input("binary", installed_path.to_str(),
digest_only_date(installed_path));
self.exec.discover_input("binary",
installed_path.to_str(),
digest_only_date(installed_path));
}
None => {
// FIXME #8711: need to parse version out of path_opt
@ -425,35 +437,44 @@ pub fn find_and_install_dependencies(context: &BuildContext,
lib_name.to_str());
// Try to install it
let pkg_id = PkgId::new(lib_name);
let workspaces = pkg_parent_workspaces(&context.context, &pkg_id);
let workspaces = pkg_parent_workspaces(&self.context.context,
&pkg_id);
let dep_workspace = if workspaces.is_empty() {
error(fmt!("Couldn't find package %s, which is needed by %s, \
in any of the workspaces in the RUST_PATH (%?)",
lib_name, parent.to_str(), rust_path()));
lib_name,
self.parent.to_str(),
rust_path()));
cond.raise((pkg_id.clone(), ~"Dependency not found"))
}
else {
workspaces[0]
};
let (outputs_disc, inputs_disc) =
context.install(PkgSrc::new(dep_workspace.clone(),
false, pkg_id), &JustOne(Path(lib_crate_filename)));
self.context.install(PkgSrc::new(dep_workspace.clone(),
false,
pkg_id),
&JustOne(Path(
lib_crate_filename)));
debug!("Installed %s, returned %? dependencies and \
%? transitive dependencies",
lib_name, outputs_disc.len(), inputs_disc.len());
for dep in outputs_disc.iter() {
debug!("Discovering a binary input: %s", dep.to_str());
exec.discover_input("binary", dep.to_str(),
digest_only_date(dep));
self.exec.discover_input("binary",
dep.to_str(),
digest_only_date(dep));
}
for &(ref what, ref dep) in inputs_disc.iter() {
if *what == ~"file" {
exec.discover_input(*what, *dep,
digest_file_with_date(&Path(*dep)));
self.exec.discover_input(*what,
*dep,
digest_file_with_date(&Path(*dep)));
}
else if *what == ~"binary" {
exec.discover_input(*what, *dep,
digest_only_date(&Path(*dep)));
self.exec.discover_input(*what,
*dep,
digest_only_date(&Path(*dep)));
}
else {
fail!("Bad kind: %s", *what);
@ -468,14 +489,36 @@ pub fn find_and_install_dependencies(context: &BuildContext,
let install_dir = installed_library.pop();
debug!("Installed %s into %s [%?]", lib_name, install_dir.to_str(),
datestamp(&installed_library));
save(install_dir);
(self.save)(install_dir);
}
}}
// Ignore `use`s
_ => ()
}
true
visit::walk_view_item(self, vi, env)
}
}
/// Collect all `extern mod` directives in `c`, then
/// try to install their targets, failing if any target
/// can't be found.
pub fn find_and_install_dependencies(context: &BuildContext,
parent: &PkgId,
sess: session::Session,
exec: &mut workcache::Exec,
c: &ast::Crate,
save: &fn(Path)) {
debug!("In find_and_install_dependencies...");
let mut visitor = ViewItemVisitor {
context: context,
parent: parent,
sess: sess,
exec: exec,
c: c,
save: save,
};
visit::walk_crate(&mut visitor, c, ())
}
pub fn mk_string_lit(s: @str) -> ast::lit {

View File

@ -1846,31 +1846,38 @@ pub mod fsync {
pub struct Arg<t> {
val: t,
opt_level: Option<Level>,
fsync_fn: @fn(f: &t, Level) -> int,
fsync_fn: extern "Rust" fn(f: &t, Level) -> int,
}
// fsync file after executing blk
// FIXME (#2004) find better way to create resources within lifetime of
// outer res
pub fn FILE_res_sync(file: &FILERes, opt_level: Option<Level>,
pub fn FILE_res_sync(file: &FILERes,
opt_level: Option<Level>,
blk: &fn(v: Res<*libc::FILE>)) {
blk(Res::new(Arg {
val: file.f, opt_level: opt_level,
fsync_fn: |file, l| fsync_fd(fileno(*file), l)
val: file.f,
opt_level: opt_level,
fsync_fn: fsync_FILE,
}));
fn fileno(stream: *libc::FILE) -> libc::c_int {
#[fixed_stack_segment]; #[inline(never)];
unsafe { libc::fileno(stream) }
}
fn fsync_FILE(stream: &*libc::FILE, level: Level) -> int {
fsync_fd(fileno(*stream), level)
}
}
// fsync fd after executing blk
pub fn fd_res_sync(fd: &FdRes, opt_level: Option<Level>,
blk: &fn(v: Res<fd_t>)) {
blk(Res::new(Arg {
val: fd.fd, opt_level: opt_level,
fsync_fn: |fd, l| fsync_fd(*fd, l)
val: fd.fd,
opt_level: opt_level,
fsync_fn: fsync_fd_helper,
}));
}
@ -1880,6 +1887,10 @@ pub mod fsync {
os::fsync_fd(fd, level) as int
}
fn fsync_fd_helper(fd_ptr: &libc::c_int, level: Level) -> int {
fsync_fd(*fd_ptr, level)
}
// Type of objects that may want to fsync
pub trait FSyncable { fn fsync(&self, l: Level) -> int; }
@ -1887,10 +1898,15 @@ pub mod fsync {
pub fn obj_sync(o: @FSyncable, opt_level: Option<Level>,
blk: &fn(v: Res<@FSyncable>)) {
blk(Res::new(Arg {
val: o, opt_level: opt_level,
fsync_fn: |o, l| (*o).fsync(l)
val: o,
opt_level: opt_level,
fsync_fn: obj_fsync_fn,
}));
}
fn obj_fsync_fn(o: &@FSyncable, level: Level) -> int {
(*o).fsync(level)
}
}
#[cfg(test)]

View File

@ -485,9 +485,11 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
}
fn visit_closure_ptr(&mut self, ck: uint) -> bool {
self.align_to::<@fn()>();
if ! self.inner.visit_closure_ptr(ck) { return false; }
self.bump_past::<@fn()>();
self.align_to::<~fn()>();
if ! self.inner.visit_closure_ptr(ck) {
return false
}
self.bump_past::<~fn()>();
true
}
}

View File

@ -8,21 +8,21 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn add(n: int) -> @fn(int) -> int {
let result: @fn(int) -> int = |m| m + n;
result
/*!
* Routines are like closures except that they own their arguments and can
* only run once.
*/
/// A routine that takes no arguments and returns nothing.
pub trait Runnable {
/// The entry point for the routine.
fn run(~self);
}
pub fn main()
{
assert_eq!(add(3)(4), 7);
/// A convenience routine that does nothing.
pub struct NoOpRunnable;
let add1 : @fn(int)->int = add(1);
assert_eq!(add1(6), 7);
let add2 : &(@fn(int)->int) = &add(2);
assert_eq!((*add2)(5), 7);
let add3 : &fn(int)->int = add(3);
assert_eq!(add3(4), 7);
impl Runnable for NoOpRunnable {
fn run(~self) {}
}

View File

@ -189,7 +189,7 @@ pub mod reflect;
pub mod condition;
pub mod logging;
pub mod util;
pub mod routine;
/* Unsupported interfaces */

View File

@ -158,11 +158,14 @@ pub mod ct {
// A fragment of the output sequence
#[deriving(Eq)]
pub enum Piece { PieceString(~str), PieceConv(Conv), }
pub enum Piece {
PieceString(~str),
PieceConv(Conv),
}
pub type ErrorFn = @fn(&str) -> !;
pub type ErrorFn<'self> = &'self fn(&str) -> !;
pub fn parse_fmt_string(s: &str, err: ErrorFn) -> ~[Piece] {
pub fn parse_fmt_string<'a>(s: &str, err: ErrorFn<'a>) -> ~[Piece] {
fn push_slice(ps: &mut ~[Piece], s: &str, from: uint, to: uint) {
if to > from {
ps.push(PieceString(s.slice(from, to).to_owned()));
@ -185,7 +188,10 @@ pub mod ct {
i += 1;
} else {
push_slice(&mut pieces, s, h, i - 1);
let Parsed {val, next} = parse_conversion(s, i, lim, err);
let Parsed {
val,
next
} = parse_conversion(s, i, lim, |s| err(s));
pieces.push(val);
i = next;
}
@ -224,8 +230,8 @@ pub mod ct {
}
}
pub fn parse_conversion(s: &str, i: uint, lim: uint, err: ErrorFn) ->
Parsed<Piece> {
pub fn parse_conversion<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>)
-> Parsed<Piece> {
let param = parse_parameter(s, i, lim);
// avoid copying ~[Flag] by destructuring
let Parsed {val: flags_val, next: flags_next} = parse_flags(s,
@ -308,8 +314,8 @@ pub mod ct {
}
}
pub fn parse_type(s: &str, i: uint, lim: uint, err: ErrorFn) ->
Parsed<Ty> {
pub fn parse_type<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>)
-> Parsed<Ty> {
if i >= lim { err("missing type in conversion"); }
// FIXME (#2249): Do we really want two signed types here?

View File

@ -55,7 +55,6 @@ impl<'self,T> Finally<T> for &'self fn() -> T {
}
finally_fn!(~fn() -> T)
finally_fn!(@fn() -> T)
finally_fn!(extern "Rust" fn() -> T)
struct Finallyalizer<'self> {
@ -119,14 +118,3 @@ fn test_owned() {
spawn_with_finalizer(owned);
}
#[test]
fn test_managed() {
let i = @mut 10;
let managed: @fn() -> int = || {
let r = *i;
*i += 10;
r
};
assert_eq!(do managed.finally {}, 10);
assert_eq!(*i, 20);
}

View File

@ -12,7 +12,6 @@ use ast::*;
use ast;
use ast_util;
use codemap::{Span, dummy_sp};
use fold;
use opt_vec;
use parse::token;
use visit::Visitor;
@ -371,21 +370,6 @@ pub fn empty_generics() -> Generics {
ty_params: opt_vec::Empty}
}
///////////////////////////////////////////////////////////////////////////
// Assigning node ids
fn node_id_assigner(next_id: @fn() -> ast::NodeId) -> @fold::ast_fold {
let precursor = @fold::AstFoldFns {
new_id: |old_id| {
assert_eq!(old_id, ast::DUMMY_NODE_ID);
next_id()
},
..*fold::default_ast_fold()
};
fold::make_fold(precursor)
}
// ______________________________________________________________________
// Enumerating the IDs which appear in an AST
@ -413,18 +397,22 @@ impl id_range {
}
}
pub fn id_visitor(vfn: @fn(NodeId), pass_through_items: bool)
pub fn id_visitor(operation: @IdVisitingOperation, pass_through_items: bool)
-> @mut Visitor<()> {
let visitor = @mut IdVisitor {
visit_callback: vfn,
operation: operation,
pass_through_items: pass_through_items,
visited_outermost: false,
};
visitor as @mut Visitor<()>
}
pub trait IdVisitingOperation {
fn visit_id(&self, node_id: NodeId);
}
pub struct IdVisitor {
visit_callback: @fn(NodeId),
operation: @IdVisitingOperation,
pass_through_items: bool,
visited_outermost: bool,
}
@ -432,10 +420,10 @@ pub struct IdVisitor {
impl IdVisitor {
fn visit_generics_helper(&self, generics: &Generics) {
for type_parameter in generics.ty_params.iter() {
(self.visit_callback)(type_parameter.id)
self.operation.visit_id(type_parameter.id)
}
for lifetime in generics.lifetimes.iter() {
(self.visit_callback)(lifetime.id)
self.operation.visit_id(lifetime.id)
}
}
}
@ -446,26 +434,26 @@ impl Visitor<()> for IdVisitor {
_: Span,
node_id: NodeId,
env: ()) {
(self.visit_callback)(node_id);
self.operation.visit_id(node_id);
visit::walk_mod(self, module, env)
}
fn visit_view_item(&mut self, view_item: &view_item, env: ()) {
match view_item.node {
view_item_extern_mod(_, _, _, node_id) => {
(self.visit_callback)(node_id)
self.operation.visit_id(node_id)
}
view_item_use(ref view_paths) => {
for view_path in view_paths.iter() {
match view_path.node {
view_path_simple(_, _, node_id) |
view_path_glob(_, node_id) => {
(self.visit_callback)(node_id)
self.operation.visit_id(node_id)
}
view_path_list(_, ref paths, node_id) => {
(self.visit_callback)(node_id);
self.operation.visit_id(node_id);
for path in paths.iter() {
(self.visit_callback)(path.node.id)
self.operation.visit_id(path.node.id)
}
}
}
@ -476,7 +464,7 @@ impl Visitor<()> for IdVisitor {
}
fn visit_foreign_item(&mut self, foreign_item: @foreign_item, env: ()) {
(self.visit_callback)(foreign_item.id);
self.operation.visit_id(foreign_item.id);
visit::walk_foreign_item(self, foreign_item, env)
}
@ -489,11 +477,11 @@ impl Visitor<()> for IdVisitor {
}
}
(self.visit_callback)(item.id);
self.operation.visit_id(item.id);
match item.node {
item_enum(ref enum_definition, _) => {
for variant in enum_definition.variants.iter() {
(self.visit_callback)(variant.node.id)
self.operation.visit_id(variant.node.id)
}
}
_ => {}
@ -505,22 +493,22 @@ impl Visitor<()> for IdVisitor {
}
fn visit_local(&mut self, local: @Local, env: ()) {
(self.visit_callback)(local.id);
self.operation.visit_id(local.id);
visit::walk_local(self, local, env)
}
fn visit_block(&mut self, block: &Block, env: ()) {
(self.visit_callback)(block.id);
self.operation.visit_id(block.id);
visit::walk_block(self, block, env)
}
fn visit_stmt(&mut self, statement: @Stmt, env: ()) {
(self.visit_callback)(ast_util::stmt_id(statement));
self.operation.visit_id(ast_util::stmt_id(statement));
visit::walk_stmt(self, statement, env)
}
fn visit_pat(&mut self, pattern: @Pat, env: ()) {
(self.visit_callback)(pattern.id);
self.operation.visit_id(pattern.id);
visit::walk_pat(self, pattern, env)
}
@ -529,17 +517,17 @@ impl Visitor<()> for IdVisitor {
{
let optional_callee_id = expression.get_callee_id();
for callee_id in optional_callee_id.iter() {
(self.visit_callback)(*callee_id)
self.operation.visit_id(*callee_id)
}
}
(self.visit_callback)(expression.id);
self.operation.visit_id(expression.id);
visit::walk_expr(self, expression, env)
}
fn visit_ty(&mut self, typ: &Ty, env: ()) {
(self.visit_callback)(typ.id);
self.operation.visit_id(typ.id);
match typ.node {
ty_path(_, _, id) => (self.visit_callback)(id),
ty_path(_, _, id) => self.operation.visit_id(id),
_ => {}
}
visit::walk_ty(self, typ, env)
@ -565,21 +553,21 @@ impl Visitor<()> for IdVisitor {
}
}
(self.visit_callback)(node_id);
self.operation.visit_id(node_id);
match *function_kind {
visit::fk_item_fn(_, generics, _, _) => {
self.visit_generics_helper(generics)
}
visit::fk_method(_, generics, method) => {
(self.visit_callback)(method.self_id);
self.operation.visit_id(method.self_id);
self.visit_generics_helper(generics)
}
visit::fk_anon(_) | visit::fk_fn_block => {}
}
for argument in function_declaration.inputs.iter() {
(self.visit_callback)(argument.id)
self.operation.visit_id(argument.id)
}
visit::walk_fn(self,
@ -599,25 +587,36 @@ impl Visitor<()> for IdVisitor {
}
fn visit_struct_field(&mut self, struct_field: @struct_field, env: ()) {
(self.visit_callback)(struct_field.node.id);
self.operation.visit_id(struct_field.node.id);
visit::walk_struct_field(self, struct_field, env)
}
}
pub fn visit_ids_for_inlined_item(item: &inlined_item, vfn: @fn(NodeId)) {
pub fn visit_ids_for_inlined_item(item: &inlined_item,
operation: @IdVisitingOperation) {
let mut id_visitor = IdVisitor {
visit_callback: vfn,
operation: operation,
pass_through_items: true,
visited_outermost: false,
};
item.accept((), &mut id_visitor);
}
pub fn compute_id_range(visit_ids_fn: &fn(@fn(NodeId))) -> id_range {
let result = @mut id_range::max();
do visit_ids_fn |id| {
result.add(id);
struct IdRangeComputingVisitor {
result: @mut id_range,
}
impl IdVisitingOperation for IdRangeComputingVisitor {
fn visit_id(&self, id: NodeId) {
self.result.add(id)
}
}
pub fn compute_id_range(visit_ids_fn: &fn(@IdVisitingOperation)) -> id_range {
let result = @mut id_range::max();
visit_ids_fn(@IdRangeComputingVisitor {
result: result,
} as @IdVisitingOperation);
*result
}

View File

@ -15,9 +15,12 @@ use std::io;
use std::local_data;
use extra::term;
pub type Emitter = @fn(cmsp: Option<(@codemap::CodeMap, Span)>,
msg: &str,
lvl: level);
pub trait Emitter {
fn emit(&self,
cmsp: Option<(@codemap::CodeMap, Span)>,
msg: &str,
lvl: level);
}
// a handler deals with errors; certain errors
// (fatal, bug, unimpl) may cause immediate exit,
@ -55,7 +58,7 @@ pub trait span_handler {
struct HandlerT {
err_count: uint,
emit: Emitter,
emit: @Emitter,
}
struct CodemapT {
@ -91,11 +94,11 @@ impl span_handler for CodemapT {
impl handler for HandlerT {
fn fatal(@mut self, msg: &str) -> ! {
(self.emit)(None, msg, fatal);
self.emit.emit(None, msg, fatal);
fail!();
}
fn err(@mut self, msg: &str) {
(self.emit)(None, msg, error);
self.emit.emit(None, msg, error);
self.bump_err_count();
}
fn bump_err_count(@mut self) {
@ -120,10 +123,10 @@ impl handler for HandlerT {
self.fatal(s);
}
fn warn(@mut self, msg: &str) {
(self.emit)(None, msg, warning);
self.emit.emit(None, msg, warning);
}
fn note(@mut self, msg: &str) {
(self.emit)(None, msg, note);
self.emit.emit(None, msg, note);
}
fn bug(@mut self, msg: &str) -> ! {
self.fatal(ice_msg(msg));
@ -135,7 +138,7 @@ impl handler for HandlerT {
cmsp: Option<(@codemap::CodeMap, Span)>,
msg: &str,
lvl: level) {
(self.emit)(cmsp, msg, lvl);
self.emit.emit(cmsp, msg, lvl);
}
}
@ -145,19 +148,22 @@ pub fn ice_msg(msg: &str) -> ~str {
pub fn mk_span_handler(handler: @mut handler, cm: @codemap::CodeMap)
-> @mut span_handler {
@mut CodemapT { handler: handler, cm: cm } as @mut span_handler
@mut CodemapT {
handler: handler,
cm: cm,
} as @mut span_handler
}
pub fn mk_handler(emitter: Option<Emitter>) -> @mut handler {
let emit: Emitter = match emitter {
pub fn mk_handler(emitter: Option<@Emitter>) -> @mut handler {
let emit: @Emitter = match emitter {
Some(e) => e,
None => {
let emit: Emitter = |cmsp, msg, t| emit(cmsp, msg, t);
emit
}
None => @DefaultEmitter as @Emitter
};
@mut HandlerT { err_count: 0, emit: emit } as @mut handler
@mut HandlerT {
err_count: 0,
emit: emit,
} as @mut handler
}
#[deriving(Eq)]
@ -230,31 +236,30 @@ fn print_diagnostic(topic: &str, lvl: level, msg: &str) {
print_maybe_styled(fmt!("%s\n", msg), term::attr::Bold);
}
pub fn collect(messages: @mut ~[~str])
-> @fn(Option<(@codemap::CodeMap, Span)>, &str, level) {
let f: @fn(Option<(@codemap::CodeMap, Span)>, &str, level) =
|_o, msg: &str, _l| { messages.push(msg.to_str()); };
f
}
pub struct DefaultEmitter;
pub fn emit(cmsp: Option<(@codemap::CodeMap, Span)>, msg: &str, lvl: level) {
match cmsp {
Some((cm, sp)) => {
let sp = cm.adjust_span(sp);
let ss = cm.span_to_str(sp);
let lines = cm.span_to_lines(sp);
print_diagnostic(ss, lvl, msg);
highlight_lines(cm, sp, lvl, lines);
print_macro_backtrace(cm, sp);
}
None => {
print_diagnostic("", lvl, msg);
}
impl Emitter for DefaultEmitter {
fn emit(&self,
cmsp: Option<(@codemap::CodeMap, Span)>,
msg: &str,
lvl: level) {
match cmsp {
Some((cm, sp)) => {
let sp = cm.adjust_span(sp);
let ss = cm.span_to_str(sp);
let lines = cm.span_to_lines(sp);
print_diagnostic(ss, lvl, msg);
highlight_lines(cm, sp, lvl, lines);
print_macro_backtrace(cm, sp);
}
None => print_diagnostic("", lvl, msg),
}
}
}
fn highlight_lines(cm: @codemap::CodeMap,
sp: Span, lvl: level,
sp: Span,
lvl: level,
lines: @codemap::FileLines) {
let fm = lines.file;

View File

@ -33,62 +33,120 @@ pub struct MacroDef {
ext: SyntaxExtension
}
// No context arg for an Item Decorator macro, simply because
// adding it would require adding a ctxt field to all items.
// we could do this if it turns out to be useful.
pub type ItemDecorator = extern "Rust" fn(@ExtCtxt,
Span,
@ast::MetaItem,
~[@ast::item])
-> ~[@ast::item];
pub type ItemDecoratorFun = @fn(@ExtCtxt,
Span,
@ast::MetaItem,
~[@ast::item])
-> ~[@ast::item];
pub struct SyntaxExpanderTT {
expander: SyntaxExpanderTTExpander,
span: Option<Span>
}
pub type SyntaxExpanderTTFun = @fn(@ExtCtxt,
Span,
&[ast::token_tree],
ast::SyntaxContext)
-> MacResult;
pub trait SyntaxExpanderTTTrait {
fn expand(&self,
ecx: @ExtCtxt,
span: Span,
token_tree: &[ast::token_tree],
context: ast::SyntaxContext)
-> MacResult;
}
pub type SyntaxExpanderTTItemFun = @fn(@ExtCtxt,
Span,
ast::Ident,
~[ast::token_tree],
ast::SyntaxContext)
-> MacResult;
pub type SyntaxExpanderTTFunNoCtxt =
extern "Rust" fn(ecx: @ExtCtxt,
span: codemap::Span,
token_tree: &[ast::token_tree])
-> MacResult;
// oog... in order to make the presentation of builtin_normal_tt_no_ctxt
// and builtin_ident_tt_no_ctxt palatable, we need one-off types for
// functions that don't consume a ctxt:
enum SyntaxExpanderTTExpander {
SyntaxExpanderTTExpanderWithoutContext(SyntaxExpanderTTFunNoCtxt),
}
pub type SyntaxExpanderTTFunNoCtxt = @fn(@ExtCtxt,
Span,
&[ast::token_tree])
-> MacResult;
impl SyntaxExpanderTTTrait for SyntaxExpanderTT {
fn expand(&self,
ecx: @ExtCtxt,
span: Span,
token_tree: &[ast::token_tree],
_: ast::SyntaxContext)
-> MacResult {
match self.expander {
SyntaxExpanderTTExpanderWithoutContext(f) => {
f(ecx, span, token_tree)
}
}
}
}
pub type SyntaxExpanderTTItemFunNoCtxt = @fn(@ExtCtxt,
Span,
ast::Ident,
~[ast::token_tree])
-> MacResult;
enum SyntaxExpanderTTItemExpander {
SyntaxExpanderTTItemExpanderWithContext(SyntaxExpanderTTItemFun),
SyntaxExpanderTTItemExpanderWithoutContext(SyntaxExpanderTTItemFunNoCtxt),
}
pub struct SyntaxExpanderTTItem {
expander: SyntaxExpanderTTItemExpander,
span: Option<Span>
}
pub trait SyntaxExpanderTTItemTrait {
fn expand(&self,
cx: @ExtCtxt,
sp: Span,
ident: ast::Ident,
token_tree: ~[ast::token_tree],
context: ast::SyntaxContext)
-> MacResult;
}
impl SyntaxExpanderTTItemTrait for SyntaxExpanderTTItem {
fn expand(&self,
cx: @ExtCtxt,
sp: Span,
ident: ast::Ident,
token_tree: ~[ast::token_tree],
context: ast::SyntaxContext)
-> MacResult {
match self.expander {
SyntaxExpanderTTItemExpanderWithContext(fun) => {
fun(cx, sp, ident, token_tree, context)
}
SyntaxExpanderTTItemExpanderWithoutContext(fun) => {
fun(cx, sp, ident, token_tree)
}
}
}
}
pub type SyntaxExpanderTTItemFun = extern "Rust" fn(@ExtCtxt,
Span,
ast::Ident,
~[ast::token_tree],
ast::SyntaxContext)
-> MacResult;
pub type SyntaxExpanderTTItemFunNoCtxt =
extern "Rust" fn(@ExtCtxt, Span, ast::Ident, ~[ast::token_tree])
-> MacResult;
pub trait AnyMacro {
fn make_expr(&self) -> @ast::Expr;
fn make_item(&self) -> Option<@ast::item>;
fn make_stmt(&self) -> @ast::Stmt;
}
pub enum MacResult {
MRExpr(@ast::Expr),
MRItem(@ast::item),
MRAny(@fn() -> @ast::Expr,
@fn() -> Option<@ast::item>,
@fn() -> @ast::Stmt),
MRDef(MacroDef)
MRAny(@AnyMacro),
MRDef(MacroDef),
}
pub enum SyntaxExtension {
// #[auto_encode] and such
ItemDecorator(ItemDecoratorFun),
ItemDecorator(ItemDecorator),
// Token-tree expanders
NormalTT(SyntaxExpanderTTFun, Option<Span>),
NormalTT(@SyntaxExpanderTTTrait, Option<Span>),
// An IdentTT is a macro that has an
// identifier in between the name of the
@ -98,7 +156,7 @@ pub enum SyntaxExtension {
// perhaps macro_rules! will lose its odd special identifier argument,
// and this can go away also
IdentTT(SyntaxExpanderTTItemFun, Option<Span>),
IdentTT(@SyntaxExpanderTTItemTrait, Option<Span>),
}
@ -133,16 +191,22 @@ type RenameList = ~[(ast::Ident,Name)];
// AST nodes into full ASTs
pub fn syntax_expander_table() -> SyntaxEnv {
// utility function to simplify creating NormalTT syntax extensions
// that ignore their contexts
fn builtin_normal_tt_no_ctxt(f: SyntaxExpanderTTFunNoCtxt) -> @Transformer {
let wrapped_expander : SyntaxExpanderTTFun = |a,b,c,_d|{f(a,b,c)};
@SE(NormalTT(wrapped_expander, None))
fn builtin_normal_tt_no_ctxt(f: SyntaxExpanderTTFunNoCtxt)
-> @Transformer {
@SE(NormalTT(@SyntaxExpanderTT{
expander: SyntaxExpanderTTExpanderWithoutContext(f),
span: None,
} as @SyntaxExpanderTTTrait,
None))
}
// utility function to simplify creating IdentTT syntax extensions
// that ignore their contexts
fn builtin_item_tt_no_ctxt(f: SyntaxExpanderTTItemFunNoCtxt) -> @Transformer {
let wrapped_expander : SyntaxExpanderTTItemFun = |a,b,c,d,_e|{f(a,b,c,d)};
@SE(IdentTT(wrapped_expander, None))
@SE(IdentTT(@SyntaxExpanderTTItem {
expander: SyntaxExpanderTTItemExpanderWithoutContext(f),
span: None,
} as @SyntaxExpanderTTItemTrait,
None))
}
let mut syntax_expanders = HashMap::new();
// NB identifier starts with space, and can't conflict with legal idents
@ -152,11 +216,18 @@ pub fn syntax_expander_table() -> SyntaxEnv {
pending_renames : @mut ~[]
}));
syntax_expanders.insert(intern(&"macro_rules"),
@SE(IdentTT(ext::tt::macro_rules::add_new_extension, None)));
@SE(IdentTT(@SyntaxExpanderTTItem {
expander: SyntaxExpanderTTItemExpanderWithContext(
ext::tt::macro_rules::add_new_extension),
span: None,
} as @SyntaxExpanderTTItemTrait,
None)));
syntax_expanders.insert(intern(&"fmt"),
builtin_normal_tt_no_ctxt(ext::fmt::expand_syntax_ext));
builtin_normal_tt_no_ctxt(
ext::fmt::expand_syntax_ext));
syntax_expanders.insert(intern(&"format_args"),
builtin_normal_tt_no_ctxt(ext::format::expand_args));
builtin_normal_tt_no_ctxt(
ext::format::expand_args));
syntax_expanders.insert(
intern(&"auto_encode"),
@SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
@ -164,67 +235,77 @@ pub fn syntax_expander_table() -> SyntaxEnv {
intern(&"auto_decode"),
@SE(ItemDecorator(ext::auto_encode::expand_auto_decode)));
syntax_expanders.insert(intern(&"env"),
builtin_normal_tt_no_ctxt(ext::env::expand_env));
builtin_normal_tt_no_ctxt(
ext::env::expand_env));
syntax_expanders.insert(intern(&"option_env"),
builtin_normal_tt_no_ctxt(ext::env::expand_option_env));
builtin_normal_tt_no_ctxt(
ext::env::expand_option_env));
syntax_expanders.insert(intern("bytes"),
builtin_normal_tt_no_ctxt(ext::bytes::expand_syntax_ext));
builtin_normal_tt_no_ctxt(
ext::bytes::expand_syntax_ext));
syntax_expanders.insert(intern("concat_idents"),
builtin_normal_tt_no_ctxt(
ext::concat_idents::expand_syntax_ext));
ext::concat_idents::expand_syntax_ext));
syntax_expanders.insert(intern(&"log_syntax"),
builtin_normal_tt_no_ctxt(
ext::log_syntax::expand_syntax_ext));
ext::log_syntax::expand_syntax_ext));
syntax_expanders.insert(intern(&"deriving"),
@SE(ItemDecorator(
ext::deriving::expand_meta_deriving)));
// Quasi-quoting expanders
syntax_expanders.insert(intern(&"quote_tokens"),
builtin_normal_tt_no_ctxt(
ext::quote::expand_quote_tokens));
builtin_normal_tt_no_ctxt(
ext::quote::expand_quote_tokens));
syntax_expanders.insert(intern(&"quote_expr"),
builtin_normal_tt_no_ctxt(ext::quote::expand_quote_expr));
builtin_normal_tt_no_ctxt(
ext::quote::expand_quote_expr));
syntax_expanders.insert(intern(&"quote_ty"),
builtin_normal_tt_no_ctxt(ext::quote::expand_quote_ty));
builtin_normal_tt_no_ctxt(
ext::quote::expand_quote_ty));
syntax_expanders.insert(intern(&"quote_item"),
builtin_normal_tt_no_ctxt(ext::quote::expand_quote_item));
builtin_normal_tt_no_ctxt(
ext::quote::expand_quote_item));
syntax_expanders.insert(intern(&"quote_pat"),
builtin_normal_tt_no_ctxt(ext::quote::expand_quote_pat));
builtin_normal_tt_no_ctxt(
ext::quote::expand_quote_pat));
syntax_expanders.insert(intern(&"quote_stmt"),
builtin_normal_tt_no_ctxt(ext::quote::expand_quote_stmt));
builtin_normal_tt_no_ctxt(
ext::quote::expand_quote_stmt));
syntax_expanders.insert(intern(&"line"),
builtin_normal_tt_no_ctxt(
ext::source_util::expand_line));
ext::source_util::expand_line));
syntax_expanders.insert(intern(&"col"),
builtin_normal_tt_no_ctxt(
ext::source_util::expand_col));
ext::source_util::expand_col));
syntax_expanders.insert(intern(&"file"),
builtin_normal_tt_no_ctxt(
ext::source_util::expand_file));
ext::source_util::expand_file));
syntax_expanders.insert(intern(&"stringify"),
builtin_normal_tt_no_ctxt(
ext::source_util::expand_stringify));
ext::source_util::expand_stringify));
syntax_expanders.insert(intern(&"include"),
builtin_normal_tt_no_ctxt(
ext::source_util::expand_include));
ext::source_util::expand_include));
syntax_expanders.insert(intern(&"include_str"),
builtin_normal_tt_no_ctxt(
ext::source_util::expand_include_str));
ext::source_util::expand_include_str));
syntax_expanders.insert(intern(&"include_bin"),
builtin_normal_tt_no_ctxt(
ext::source_util::expand_include_bin));
ext::source_util::expand_include_bin));
syntax_expanders.insert(intern(&"module_path"),
builtin_normal_tt_no_ctxt(
ext::source_util::expand_mod));
ext::source_util::expand_mod));
syntax_expanders.insert(intern(&"asm"),
builtin_normal_tt_no_ctxt(ext::asm::expand_asm));
builtin_normal_tt_no_ctxt(
ext::asm::expand_asm));
syntax_expanders.insert(intern(&"cfg"),
builtin_normal_tt_no_ctxt(ext::cfg::expand_cfg));
syntax_expanders.insert(
intern(&"trace_macros"),
builtin_normal_tt_no_ctxt(ext::trace_macros::expand_trace_macros));
builtin_normal_tt_no_ctxt(
ext::cfg::expand_cfg));
syntax_expanders.insert(intern(&"trace_macros"),
builtin_normal_tt_no_ctxt(
ext::trace_macros::expand_trace_macros));
MapChain::new(~syntax_expanders)
}

View File

@ -15,6 +15,7 @@ use ast_util;
use codemap::{Span, respan, dummy_sp};
use ext::base::ExtCtxt;
use ext::quote::rt::*;
use fold;
use opt_vec;
use opt_vec::OptVec;
@ -862,3 +863,32 @@ impl AstBuilder for @ExtCtxt {
ast::view_path_glob(self.path(sp, path), ast::DUMMY_NODE_ID))])
}
}
struct Duplicator {
cx: @ExtCtxt,
}
impl fold::ast_fold for Duplicator {
fn new_id(&self, _: NodeId) -> NodeId {
ast::DUMMY_NODE_ID
}
}
pub trait Duplicate {
//
// Duplication functions
//
// These functions just duplicate AST nodes.
//
fn duplicate(&self, cx: @ExtCtxt) -> Self;
}
impl Duplicate for @ast::Expr {
fn duplicate(&self, cx: @ExtCtxt) -> @ast::Expr {
let folder = @Duplicator {
cx: cx,
} as @fold::ast_fold;
folder.fold_expr(*self)
}
}

View File

@ -10,7 +10,7 @@
use ast::{Block, Crate, DeclLocal, Expr_, ExprMac, SyntaxContext};
use ast::{Local, Ident, mac_invoc_tt};
use ast::{item_mac, Mrk, Stmt_, StmtDecl, StmtMac, StmtExpr, StmtSemi};
use ast::{item_mac, Mrk, Stmt, StmtDecl, StmtMac, StmtExpr, StmtSemi};
use ast::{token_tree};
use ast;
use ast_util::{mtwt_outer_mark, new_rename, new_mark};
@ -21,6 +21,7 @@ use codemap;
use codemap::{Span, Spanned, ExpnInfo, NameAndSpan};
use ext::base::*;
use fold::*;
use opt_vec;
use parse;
use parse::{parse_item_from_source_str};
use parse::token;
@ -32,12 +33,10 @@ use std::vec;
pub fn expand_expr(extsbox: @mut SyntaxEnv,
cx: @ExtCtxt,
e: &Expr_,
span: Span,
fld: @ast_fold,
orig: @fn(&Expr_, Span, @ast_fold) -> (Expr_, Span))
-> (Expr_, Span) {
match *e {
e: @ast::Expr,
fld: &MacroExpander)
-> @ast::Expr {
match e.node {
// expr_mac should really be expr_ext or something; it's the
// entry-point for all syntax extensions.
ExprMac(ref mac) => {
@ -66,7 +65,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
}
Some(@SE(NormalTT(expandfun, exp_span))) => {
cx.bt_push(ExpnInfo {
call_site: span,
call_site: e.span,
callee: NameAndSpan {
name: extnamestr,
span: exp_span,
@ -84,10 +83,12 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
let mac_span = original_span(cx);
let expanded =
match expandfun(cx, mac_span.call_site,
marked_before, marked_ctxt) {
match expandfun.expand(cx,
mac_span.call_site,
marked_before,
marked_ctxt) {
MRExpr(e) => e,
MRAny(expr_maker,_,_) => expr_maker(),
MRAny(any_macro) => any_macro.make_expr(),
_ => {
cx.span_fatal(
pth.span,
@ -101,12 +102,19 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
// mark after:
let marked_after = mark_expr(expanded,fm);
//keep going, outside-in
// Keep going, outside-in.
//
// XXX(pcwalton): Is it necessary to clone the
// node here?
let fully_expanded =
fld.fold_expr(marked_after).node.clone();
cx.bt_pop();
(fully_expanded, span)
@ast::Expr {
id: ast::DUMMY_NODE_ID,
node: fully_expanded,
span: e.span,
}
}
_ => {
cx.span_fatal(
@ -125,8 +133,48 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
ast::ExprForLoop(src_pat, src_expr, ref src_loop_block, opt_ident) => {
// Expand any interior macros etc.
// NB: we don't fold pats yet. Curious.
let src_expr = fld.fold_expr(src_expr);
let src_loop_block = fld.fold_block(src_loop_block);
let src_expr = fld.fold_expr(src_expr).clone();
let src_loop_block = fld.fold_block(src_loop_block).clone();
let span = e.span;
pub fn mk_expr(_: @ExtCtxt, span: Span, node: Expr_)
-> @ast::Expr {
@ast::Expr {
id: ast::DUMMY_NODE_ID,
node: node,
span: span,
}
}
fn mk_block(_: @ExtCtxt,
stmts: &[@ast::Stmt],
expr: Option<@ast::Expr>,
span: Span)
-> ast::Block {
ast::Block {
view_items: ~[],
stmts: stmts.to_owned(),
expr: expr,
id: ast::DUMMY_NODE_ID,
rules: ast::DefaultBlock,
span: span,
}
}
fn mk_simple_path(ident: ast::Ident, span: Span) -> ast::Path {
ast::Path {
span: span,
global: false,
segments: ~[
ast::PathSegment {
identifier: ident,
lifetime: None,
types: opt_vec::Empty,
}
],
}
}
// to:
//
@ -182,10 +230,14 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
~[iter_decl_stmt],
Some(loop_expr));
(ast::ExprBlock(block), span)
@ast::Expr {
id: ast::DUMMY_NODE_ID,
node: ast::ExprBlock(block),
span: span,
}
}
_ => orig(e, span, fld)
_ => noop_fold_expr(e, fld)
}
}
@ -201,12 +253,10 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
pub fn expand_mod_items(extsbox: @mut SyntaxEnv,
cx: @ExtCtxt,
module_: &ast::_mod,
fld: @ast_fold,
orig: @fn(&ast::_mod, @ast_fold) -> ast::_mod)
-> ast::_mod {
fld: &MacroExpander)
-> ast::_mod {
// Fold the contents first:
let module_ = orig(module_, fld);
let module_ = noop_fold_mod(module_, fld);
// For each item, look through the attributes. If any of them are
// decorated with "item decorators", then use that function to transform
@ -233,7 +283,10 @@ pub fn expand_mod_items(extsbox: @mut SyntaxEnv,
}
};
ast::_mod { items: new_items, ..module_ }
ast::_mod {
items: new_items,
..module_
}
}
// eval $e with a new exts frame:
@ -256,19 +309,20 @@ static special_block_name : &'static str = " block";
pub fn expand_item(extsbox: @mut SyntaxEnv,
cx: @ExtCtxt,
it: @ast::item,
fld: @ast_fold,
orig: @fn(@ast::item, @ast_fold) -> Option<@ast::item>)
-> Option<@ast::item> {
fld: &MacroExpander)
-> Option<@ast::item> {
match it.node {
ast::item_mac(*) => expand_item_mac(extsbox, cx, it, fld),
ast::item_mod(_) | ast::item_foreign_mod(_) => {
cx.mod_push(it.ident);
let macro_escape = contains_macro_escape(it.attrs);
let result = with_exts_frame!(extsbox,macro_escape,orig(it,fld));
let result = with_exts_frame!(extsbox,
macro_escape,
noop_fold_item(it, fld));
cx.mod_pop();
result
},
_ => orig(it,fld)
_ => noop_fold_item(it, fld)
}
}
@ -280,11 +334,15 @@ pub fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool {
// Support for item-position macro invocations, exactly the same
// logic as for expression-position macro invocations.
pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
cx: @ExtCtxt, it: @ast::item,
fld: @ast_fold)
-> Option<@ast::item> {
cx: @ExtCtxt,
it: @ast::item,
fld: &MacroExpander)
-> Option<@ast::item> {
let (pth, tts, ctxt) = match it.node {
item_mac(codemap::Spanned { node: mac_invoc_tt(ref pth, ref tts, ctxt), _}) => {
item_mac(codemap::Spanned {
node: mac_invoc_tt(ref pth, ref tts, ctxt),
_
}) => {
(pth, (*tts).clone(), ctxt)
}
_ => cx.span_bug(it.span, "invalid item macro invocation")
@ -314,7 +372,7 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
// mark before expansion:
let marked_before = mark_tts(tts,fm);
let marked_ctxt = new_mark(fm,ctxt);
expander(cx, it.span, marked_before, marked_ctxt)
expander.expand(cx, it.span, marked_before, marked_ctxt)
}
Some(@SE(IdentTT(expander, span))) => {
if it.ident.name == parse::token::special_idents::invalid.name {
@ -332,7 +390,7 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
// mark before expansion:
let marked_tts = mark_tts(tts,fm);
let marked_ctxt = new_mark(fm,ctxt);
expander(cx, it.span, it.ident, marked_tts, marked_ctxt)
expander.expand(cx, it.span, it.ident, marked_tts, marked_ctxt)
}
_ => cx.span_fatal(
it.span, fmt!("%s! is not legal in item position", extnamestr))
@ -346,10 +404,10 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
MRExpr(_) => {
cx.span_fatal(pth.span, fmt!("expr macro in item position: %s", extnamestr))
}
MRAny(_, item_maker, _) => {
item_maker()
.and_then(|i| mark_item(i,fm))
.and_then(|i| fld.fold_item(i))
MRAny(any_macro) => {
any_macro.make_item()
.and_then(|i| mark_item(i,fm))
.and_then(|i| fld.fold_item(i))
}
MRDef(ref mdef) => {
// yikes... no idea how to apply the mark to this. I'm afraid
@ -382,15 +440,12 @@ fn insert_macro(exts: SyntaxEnv, name: ast::Name, transformer: @Transformer) {
// expand a stmt
pub fn expand_stmt(extsbox: @mut SyntaxEnv,
cx: @ExtCtxt,
s: &Stmt_,
sp: Span,
fld: @ast_fold,
orig: @fn(&Stmt_, Span, @ast_fold)
-> (Option<Stmt_>, Span))
-> (Option<Stmt_>, Span) {
s: &Stmt,
fld: &MacroExpander)
-> Option<@Stmt> {
// why the copying here and not in expand_expr?
// looks like classic changed-in-only-one-place
let (pth, tts, semi, ctxt) = match *s {
let (pth, tts, semi, ctxt) = match s.node {
StmtMac(ref mac, semi) => {
match mac.node {
mac_invoc_tt(ref pth, ref tts, ctxt) => {
@ -398,24 +453,26 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
}
}
}
_ => return expand_non_macro_stmt(*extsbox,s,sp,fld,orig)
_ => return expand_non_macro_stmt(*extsbox, s, fld)
};
if (pth.segments.len() > 1u) {
cx.span_fatal(
pth.span,
fmt!("expected macro name without module \
separators"));
cx.span_fatal(pth.span,
"expected macro name without module separators");
}
let extname = &pth.segments[0].identifier;
let extnamestr = ident_to_str(extname);
let (fully_expanded, sp) = match (*extsbox).find(&extname.name) {
None =>
cx.span_fatal(pth.span, fmt!("macro undefined: '%s'", extnamestr)),
let fully_expanded: @ast::Stmt = match (*extsbox).find(&extname.name) {
None => {
cx.span_fatal(pth.span, fmt!("macro undefined: '%s'", extnamestr))
}
Some(@SE(NormalTT(expandfun, exp_span))) => {
cx.bt_push(ExpnInfo {
call_site: sp,
callee: NameAndSpan { name: extnamestr, span: exp_span }
call_site: s.span,
callee: NameAndSpan {
name: extnamestr,
span: exp_span,
}
});
let fm = fresh_mark();
// mark before expansion:
@ -426,24 +483,32 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
// not the current mac.span.
let mac_span = original_span(cx);
let expanded = match expandfun(cx, mac_span.call_site,
marked_tts, marked_ctxt) {
MRExpr(e) =>
@codemap::Spanned { node: StmtExpr(e, ast::DUMMY_NODE_ID),
span: e.span},
MRAny(_,_,stmt_mkr) => stmt_mkr(),
let expanded = match expandfun.expand(cx,
mac_span.call_site,
marked_tts,
marked_ctxt) {
MRExpr(e) => {
@codemap::Spanned {
node: StmtExpr(e, ast::DUMMY_NODE_ID),
span: e.span,
}
}
MRAny(any_macro) => any_macro.make_stmt(),
_ => cx.span_fatal(
pth.span,
fmt!("non-stmt macro in stmt pos: %s", extnamestr))
};
let marked_after = mark_stmt(expanded,fm);
//keep going, outside-in
// Keep going, outside-in.
let fully_expanded = match fld.fold_stmt(marked_after) {
Some(stmt) => {
let fully_expanded = &stmt.node;
cx.bt_pop();
(*fully_expanded).clone()
@Spanned {
span: stmt.span,
node: (*fully_expanded).clone(),
}
}
None => {
cx.span_fatal(pth.span,
@ -451,7 +516,7 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
}
};
(fully_expanded, sp)
fully_expanded
}
_ => {
@ -460,24 +525,28 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
}
};
(match fully_expanded {
StmtExpr(e, stmt_id) if semi => Some(StmtSemi(e, stmt_id)),
_ => { Some(fully_expanded) } /* might already have a semi */
}, sp)
match fully_expanded.node {
StmtExpr(e, stmt_id) if semi => {
Some(@Spanned {
span: fully_expanded.span,
node: StmtSemi(e, stmt_id),
})
}
_ => Some(fully_expanded), /* might already have a semi */
}
}
// expand a non-macro stmt. this is essentially the fallthrough for
// expand_stmt, above.
fn expand_non_macro_stmt (exts: SyntaxEnv,
s: &Stmt_,
sp: Span,
fld: @ast_fold,
orig: @fn(&Stmt_, Span, @ast_fold) -> (Option<Stmt_>, Span))
-> (Option<Stmt_>,Span) {
fn expand_non_macro_stmt(exts: SyntaxEnv, s: &Stmt, fld: &MacroExpander)
-> Option<@Stmt> {
// is it a let?
match *s {
StmtDecl(@Spanned{node: DeclLocal(ref local), span: stmt_span}, node_id) => {
match s.node {
StmtDecl(@Spanned {
node: DeclLocal(ref local),
span: stmt_span
},
node_id) => {
let block_info = get_block_info(exts);
let pending_renames = block_info.pending_renames;
@ -515,19 +584,24 @@ fn expand_non_macro_stmt (exts: SyntaxEnv,
// also, don't forget to expand the init:
let new_init_opt = init.map(|e| fld.fold_expr(*e));
let rewritten_local =
@Local{is_mutbl:is_mutbl,
ty:ty,
pat:rewritten_pat,
init:new_init_opt,
id:id,
span:span};
(Some(StmtDecl(@Spanned{node:DeclLocal(rewritten_local),
span: stmt_span},node_id)),
sp)
@Local {
is_mutbl: is_mutbl,
ty: ty,
pat: rewritten_pat,
init: new_init_opt,
id: id,
span: span,
};
Some(@Spanned {
node: StmtDecl(@Spanned {
node: DeclLocal(rewritten_local),
span: stmt_span
},
node_id),
span: span
})
},
_ => {
orig(s, sp, fld)
}
_ => noop_fold_stmt(s, fld),
}
}
@ -628,18 +702,18 @@ pub fn new_path_finder(paths: @mut ~[ast::Path]) -> @mut Visitor<()> {
// expand a block. pushes a new exts_frame, then calls expand_block_elts
pub fn expand_block(extsbox: @mut SyntaxEnv,
_cx: @ExtCtxt,
_: @ExtCtxt,
blk: &Block,
fld: @ast_fold,
_orig: @fn(&Block, @ast_fold) -> Block)
-> Block {
fld: &MacroExpander)
-> Block {
// see note below about treatment of exts table
with_exts_frame!(extsbox,false,
expand_block_elts(*extsbox, blk, fld))
}
// expand the elements of a block.
pub fn expand_block_elts(exts: SyntaxEnv, b: &Block, fld: @ast_fold) -> Block {
pub fn expand_block_elts(exts: SyntaxEnv, b: &Block, fld: &MacroExpander)
-> Block {
let block_info = get_block_info(exts);
let pending_renames = block_info.pending_renames;
let rename_fld = renames_to_fold(pending_renames);
@ -680,9 +754,47 @@ fn get_block_info(exts : SyntaxEnv) -> BlockInfo {
}
}
struct IdentRenamer {
renames: @mut ~[(ast::Ident,ast::Name)],
}
impl ast_fold for IdentRenamer {
fn fold_ident(&self, id: ast::Ident) -> ast::Ident {
let new_ctxt = self.renames.iter().fold(id.ctxt, |ctxt, &(from, to)| {
new_rename(from, to, ctxt)
});
ast::Ident {
name: id.name,
ctxt: new_ctxt,
}
}
}
// given a mutable list of renames, return a tree-folder that applies those
// renames.
pub fn renames_to_fold(renames: @mut ~[(ast::Ident,ast::Name)]) -> @ast_fold {
@IdentRenamer {
renames: renames,
} as @ast_fold
}
// perform a bunch of renames
fn apply_pending_renames(folder : @ast_fold, stmt : ast::Stmt) -> @ast::Stmt {
match folder.fold_stmt(&stmt) {
Some(s) => s,
None => fail!(fmt!("renaming of stmt produced None"))
}
}
pub fn new_span(cx: @ExtCtxt, sp: Span) -> Span {
/* this discards information in the case of macro-defining macros */
return Span {lo: sp.lo, hi: sp.hi, expn_info: cx.backtrace()};
Span {
lo: sp.lo,
hi: sp.hi,
expn_info: cx.backtrace(),
}
}
// FIXME (#2247): this is a moderately bad kludge to inject some macros into
@ -1025,10 +1137,28 @@ pub fn std_macros() -> @str {
}";
}
struct Injector {
sm: @ast::item,
}
impl ast_fold for Injector {
fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
// Just inject the standard macros at the start of the first module
// in the crate: that is, at the start of the crate file itself.
let items = vec::append(~[ self.sm ], module.items);
ast::_mod {
items: items,
..(*module).clone() // FIXME #2543: Bad copy.
}
}
}
// add a bunch of macros as though they were placed at the head of the
// program (ick). This should run before cfg stripping.
pub fn inject_std_macros(parse_sess: @mut parse::ParseSess,
cfg: ast::CrateConfig, c: &Crate) -> @Crate {
cfg: ast::CrateConfig,
c: @Crate)
-> @Crate {
let sm = match parse_item_from_source_str(@"<std-macros>",
std_macros(),
cfg.clone(),
@ -1038,48 +1168,80 @@ pub fn inject_std_macros(parse_sess: @mut parse::ParseSess,
None => fail!("expected core macros to parse correctly")
};
let injecter = @AstFoldFns {
fold_mod: |modd, _| {
// just inject the std macros at the start of the first
// module in the crate (i.e the crate file itself.)
let items = vec::append(~[sm], modd.items);
ast::_mod {
items: items,
// FIXME #2543: Bad copy.
.. (*modd).clone()
}
},
.. *default_ast_fold()
};
@make_fold(injecter).fold_crate(c)
let injector = @Injector {
sm: sm,
} as @ast_fold;
@injector.fold_crate(c)
}
struct NoOpFolder {
contents: (),
}
impl ast_fold for NoOpFolder {}
struct MacroExpander {
extsbox: @mut SyntaxEnv,
cx: @ExtCtxt,
}
impl ast_fold for MacroExpander {
fn fold_expr(&self, expr: @ast::Expr) -> @ast::Expr {
expand_expr(self.extsbox,
self.cx,
expr,
self)
}
fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
expand_mod_items(self.extsbox,
self.cx,
module,
self)
}
fn fold_item(&self, item: @ast::item) -> Option<@ast::item> {
expand_item(self.extsbox,
self.cx,
item,
self)
}
fn fold_stmt(&self, stmt: &ast::Stmt) -> Option<@ast::Stmt> {
expand_stmt(self.extsbox,
self.cx,
stmt,
self)
}
fn fold_block(&self, block: &ast::Block) -> ast::Block {
expand_block(self.extsbox,
self.cx,
block,
self)
}
fn new_span(&self, span: Span) -> Span {
new_span(self.cx, span)
}
}
pub fn expand_crate(parse_sess: @mut parse::ParseSess,
cfg: ast::CrateConfig, c: &Crate) -> @Crate {
cfg: ast::CrateConfig,
c: &Crate) -> @Crate {
// adding *another* layer of indirection here so that the block
// visitor can swap out one exts table for another for the duration
// of the block. The cleaner alternative would be to thread the
// exts table through the fold, but that would require updating
// every method/element of AstFoldFns in fold.rs.
let extsbox = @mut syntax_expander_table();
let afp = default_ast_fold();
let extsbox = syntax_expander_table();
let cx = ExtCtxt::new(parse_sess, cfg.clone());
let f_pre = @AstFoldFns {
fold_expr: |expr,span,recur|
expand_expr(extsbox, cx, expr, span, recur, afp.fold_expr),
fold_mod: |modd,recur|
expand_mod_items(extsbox, cx, modd, recur, afp.fold_mod),
fold_item: |item,recur|
expand_item(extsbox, cx, item, recur, afp.fold_item),
fold_stmt: |stmt,span,recur|
expand_stmt(extsbox, cx, stmt, span, recur, afp.fold_stmt),
fold_block: |blk,recur|
expand_block(extsbox, cx, blk, recur, afp.fold_block),
new_span: |a| new_span(cx, a),
.. *afp};
let f = make_fold(f_pre);
let expander = @MacroExpander {
extsbox: @mut extsbox,
cx: cx,
} as @ast_fold;
let ret = @f.fold_crate(c);
let ret = @expander.fold_crate(c);
parse_sess.span_diagnostic.handler().abort_if_errors();
return ret;
}
@ -1145,53 +1307,56 @@ impl CtxtFn for Repainter {
}
}
// given a function from ctxts to ctxts, produce
// an ast_fold that applies that function to all ctxts:
pub fn fun_to_ctxt_folder<T : 'static + CtxtFn>(cf: @T) -> @AstFoldFns {
let afp = default_ast_fold();
let fi : @fn(ast::Ident, @ast_fold) -> ast::Ident =
|ast::Ident{name, ctxt}, _| {
ast::Ident{name:name,ctxt:cf.f(ctxt)}
};
let fm : @fn(&ast::mac_, Span, @ast_fold) -> (ast::mac_,Span) =
|m, sp, fld| {
match *m {
mac_invoc_tt(ref path, ref tts, ctxt) =>
(mac_invoc_tt(fld.fold_path(path),
fold_tts(*tts,fld),
cf.f(ctxt)),
sp)
}
pub struct ContextWrapper {
context_function: @CtxtFn,
}
};
@AstFoldFns{
fold_ident : fi,
fold_mac : fm,
.. *afp
impl ast_fold for ContextWrapper {
fn fold_ident(&self, id: ast::Ident) -> ast::Ident {
let ast::Ident {
name,
ctxt
} = id;
ast::Ident {
name: name,
ctxt: self.context_function.f(ctxt),
}
}
fn fold_mac(&self, m: &ast::mac) -> ast::mac {
let macro = match m.node {
mac_invoc_tt(ref path, ref tts, ctxt) => {
mac_invoc_tt(self.fold_path(path),
fold_tts(*tts, self),
self.context_function.f(ctxt))
}
};
Spanned {
node: macro,
span: m.span,
}
}
}
// given a mutable list of renames, return a tree-folder that applies those
// renames.
// FIXME #4536: currently pub to allow testing
pub fn renames_to_fold(renames : @mut ~[(ast::Ident,ast::Name)]) -> @AstFoldFns {
fun_to_ctxt_folder(@MultiRenamer{renames : renames})
// given a function from ctxts to ctxts, produce
// an ast_fold that applies that function to all ctxts:
pub fn fun_to_ctxt_folder<T : 'static + CtxtFn>(cf: @T) -> @ContextWrapper {
@ContextWrapper {
context_function: cf as @CtxtFn,
}
}
// just a convenience:
pub fn new_mark_folder(m : Mrk) -> @AstFoldFns {
pub fn new_mark_folder(m: Mrk) -> @ContextWrapper {
fun_to_ctxt_folder(@Marker{mark:m})
}
pub fn new_rename_folder(from : ast::Ident, to : ast::Name) -> @AstFoldFns {
pub fn new_rename_folder(from: ast::Ident, to: ast::Name) -> @ContextWrapper {
fun_to_ctxt_folder(@Renamer{from:from,to:to})
}
// apply a given mark to the given token trees. Used prior to expansion of a macro.
fn mark_tts(tts : &[token_tree], m : Mrk) -> ~[token_tree] {
fold_tts(tts,new_mark_folder(m) as @ast_fold)
fold_tts(tts,new_mark_folder(m))
}
// apply a given mark to the given expr. Used following the expansion of a macro.
@ -1359,7 +1524,7 @@ mod test {
let ident_str = @"x";
let tts = string_to_tts(ident_str);
let fm = fresh_mark();
let marked_once = fold::fold_tts(tts,new_mark_folder(fm) as @fold::ast_fold);
let marked_once = fold::fold_tts(tts,new_mark_folder(fm));
assert_eq!(marked_once.len(),1);
let marked_once_ctxt =
match marked_once[0] {

View File

@ -38,7 +38,7 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree])
fn parse_fmt_err_(cx: @ExtCtxt, sp: Span, msg: &str) -> ! {
cx.span_fatal(sp, msg);
}
let parse_fmt_err: @fn(&str) -> ! = |s| parse_fmt_err_(cx, fmtspan, s);
let parse_fmt_err: &fn(&str) -> ! = |s| parse_fmt_err_(cx, fmtspan, s);
let pieces = parse_fmt_string(fmt, parse_fmt_err);
MRExpr(pieces_to_expr(cx, sp, pieces, args))
}

View File

@ -12,9 +12,9 @@ use ast::{Ident, matcher_, matcher, match_tok, match_nonterminal, match_seq};
use ast::{tt_delim};
use ast;
use codemap::{Span, Spanned, dummy_sp};
use ext::base::{ExtCtxt, MacResult, MRAny, MRDef, MacroDef, NormalTT};
use ext::base::{AnyMacro, ExtCtxt, MacResult, MRAny, MRDef, MacroDef};
use ext::base::{NormalTT, SyntaxExpanderTTTrait};
use ext::base;
use ext::expand;
use ext::tt::macro_parser::{error};
use ext::tt::macro_parser::{named_match, matched_seq, matched_nonterminal};
use ext::tt::macro_parser::{parse, parse_or_else, success, failure};
@ -24,6 +24,112 @@ use parse::token::{get_ident_interner, special_idents, gensym_ident, ident_to_st
use parse::token::{FAT_ARROW, SEMI, nt_matchers, nt_tt};
use print;
struct ParserAnyMacro {
parser: @Parser,
}
impl AnyMacro for ParserAnyMacro {
fn make_expr(&self) -> @ast::Expr {
self.parser.parse_expr()
}
fn make_item(&self) -> Option<@ast::item> {
self.parser.parse_item(~[]) // no attrs
}
fn make_stmt(&self) -> @ast::Stmt {
self.parser.parse_stmt(~[]) // no attrs
}
}
struct MacroRulesSyntaxExpanderTTFun {
name: Ident,
lhses: @~[@named_match],
rhses: @~[@named_match],
}
impl SyntaxExpanderTTTrait for MacroRulesSyntaxExpanderTTFun {
fn expand(&self,
cx: @ExtCtxt,
sp: Span,
arg: &[ast::token_tree],
_: ast::SyntaxContext)
-> MacResult {
generic_extension(cx, sp, self.name, arg, *self.lhses, *self.rhses)
}
}
// Given `lhses` and `rhses`, this is the new macro we create
fn generic_extension(cx: @ExtCtxt,
sp: Span,
name: Ident,
arg: &[ast::token_tree],
lhses: &[@named_match],
rhses: &[@named_match])
-> MacResult {
if cx.trace_macros() {
printfln!("%s! { %s }",
cx.str_of(name),
print::pprust::tt_to_str(
&ast::tt_delim(@mut arg.to_owned()),
get_ident_interner()));
}
// Which arm's failure should we report? (the one furthest along)
let mut best_fail_spot = dummy_sp();
let mut best_fail_msg = ~"internal error: ran no matchers";
let s_d = cx.parse_sess().span_diagnostic;
for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers
match *lhs {
@matched_nonterminal(nt_matchers(ref mtcs)) => {
// `none` is because we're not interpolating
let arg_rdr = new_tt_reader(
s_d,
None,
arg.to_owned()
) as @mut reader;
match parse(cx.parse_sess(), cx.cfg(), arg_rdr, *mtcs) {
success(named_matches) => {
let rhs = match rhses[i] {
// okay, what's your transcriber?
@matched_nonterminal(nt_tt(@ref tt)) => {
match (*tt) {
// cut off delimiters; don't parse 'em
tt_delim(ref tts) => {
(*tts).slice(1u,(*tts).len()-1u).to_owned()
}
_ => cx.span_fatal(
sp, "macro rhs must be delimited")
}
},
_ => cx.span_bug(sp, "bad thing in rhs")
};
// rhs has holes ( `$id` and `$(...)` that need filled)
let trncbr = new_tt_reader(s_d, Some(named_matches),
rhs);
let p = @Parser(cx.parse_sess(),
cx.cfg(),
trncbr as @mut reader);
// Let the context choose how to interpret the result.
// Weird, but useful for X-macros.
return MRAny(@ParserAnyMacro {
parser: p,
} as @AnyMacro)
}
failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo {
best_fail_spot = sp;
best_fail_msg = (*msg).clone();
},
error(sp, ref msg) => cx.span_fatal(sp, (*msg))
}
}
_ => cx.bug("non-matcher found in parsed lhses")
}
}
cx.span_fatal(best_fail_spot, best_fail_msg);
}
// this procedure performs the expansion of the
// macro_rules! macro. It parses the RHS and adds
// an extension to the current context.
@ -31,10 +137,8 @@ pub fn add_new_extension(cx: @ExtCtxt,
sp: Span,
name: Ident,
arg: ~[ast::token_tree],
stx_ctxt: ast::SyntaxContext)
-> base::MacResult {
let arg = expand::mtwt_cancel_outer_mark(arg,stx_ctxt);
// Wrap a matcher_ in a spanned to produce a matcher.
_: ast::SyntaxContext)
-> base::MacResult {
// these spans won't matter, anyways
fn ms(m: matcher_) -> matcher {
Spanned {
@ -82,11 +186,13 @@ pub fn add_new_extension(cx: @ExtCtxt,
};
// Given `lhses` and `rhses`, this is the new macro we create
fn generic_extension(cx: @ExtCtxt, sp: Span, name: Ident,
fn generic_extension(cx: @ExtCtxt,
sp: Span,
name: Ident,
arg: &[ast::token_tree],
lhses: &[@named_match], rhses: &[@named_match])
-> MacResult {
lhses: &[@named_match],
rhses: &[@named_match])
-> MacResult {
if cx.trace_macros() {
printfln!("%s! { %s }",
cx.str_of(name),
@ -135,9 +241,9 @@ pub fn add_new_extension(cx: @ExtCtxt,
// Let the context choose how to interpret the result.
// Weird, but useful for X-macros.
return MRAny(|| p.parse_expr(),
|| p.parse_item(~[/* no attrs*/]),
|| p.parse_stmt(~[/* no attrs*/]));
return MRAny(@ParserAnyMacro {
parser: p
} as @AnyMacro);
}
failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo {
best_fail_spot = sp;
@ -152,10 +258,13 @@ pub fn add_new_extension(cx: @ExtCtxt,
cx.span_fatal(best_fail_spot, best_fail_msg);
}
let exp: @fn(@ExtCtxt, Span, &[ast::token_tree], ctxt: ast::SyntaxContext) -> MacResult =
|cx, sp, arg, _ctxt| generic_extension(cx, sp, name, arg, *lhses, *rhses);
let exp = @MacroRulesSyntaxExpanderTTFun {
name: name,
lhses: lhses,
rhses: rhses,
} as @SyntaxExpanderTTTrait;
return MRDef(MacroDef{
return MRDef(MacroDef {
name: ident_to_str(&name),
ext: NormalTT(exp, Some(sp))
});

File diff suppressed because it is too large Load Diff

View File

@ -45,7 +45,7 @@ pub struct ParseSess {
included_mod_stack: ~[Path],
}
pub fn new_parse_sess(demitter: Option<Emitter>) -> @mut ParseSess {
pub fn new_parse_sess(demitter: Option<@Emitter>) -> @mut ParseSess {
let cm = @CodeMap::new();
@mut ParseSess {
cm: cm,

View File

@ -37,16 +37,26 @@ pub enum ann_node<'self> {
node_expr(@ps, &'self ast::Expr),
node_pat(@ps, &'self ast::Pat),
}
pub struct pp_ann {
pre: @fn(ann_node),
post: @fn(ann_node)
pub trait pp_ann {
fn pre(&self, _node: ann_node) {}
fn post(&self, _node: ann_node) {}
}
pub fn no_ann() -> pp_ann {
fn ignore(_node: ann_node) { }
return pp_ann {pre: ignore, post: ignore};
pub struct no_ann {
contents: (),
}
impl no_ann {
pub fn new() -> no_ann {
no_ann {
contents: (),
}
}
}
impl pp_ann for no_ann {}
pub struct CurrentCommentAndLiteral {
cur_cmnt: uint,
cur_lit: uint,
@ -60,7 +70,7 @@ pub struct ps {
literals: Option<~[comments::lit]>,
cur_cmnt_and_lit: @mut CurrentCommentAndLiteral,
boxes: @mut ~[pp::breaks],
ann: pp_ann
ann: @pp_ann
}
pub fn ibox(s: @ps, u: uint) {
@ -74,12 +84,13 @@ pub fn end(s: @ps) {
}
pub fn rust_printer(writer: @io::Writer, intr: @ident_interner) -> @ps {
return rust_printer_annotated(writer, intr, no_ann());
return rust_printer_annotated(writer, intr, @no_ann::new() as @pp_ann);
}
pub fn rust_printer_annotated(writer: @io::Writer,
intr: @ident_interner,
ann: pp_ann) -> @ps {
ann: @pp_ann)
-> @ps {
return @ps {
s: pp::mk_printer(writer, default_columns),
cm: None::<@CodeMap>,
@ -109,7 +120,7 @@ pub fn print_crate(cm: @CodeMap,
filename: @str,
input: @io::Reader,
out: @io::Writer,
ann: pp_ann,
ann: @pp_ann,
is_expanded: bool) {
let (cmnts, lits) = comments::gather_comments_and_literals(
span_diagnostic,
@ -484,7 +495,7 @@ pub fn print_item(s: @ps, item: &ast::item) {
maybe_print_comment(s, item.span.lo);
print_outer_attributes(s, item.attrs);
let ann_node = node_item(s, item);
(s.ann.pre)(ann_node);
s.ann.pre(ann_node);
match item.node {
ast::item_static(ref ty, m, expr) => {
head(s, visibility_qualified(item.vis, "static"));
@ -635,7 +646,7 @@ pub fn print_item(s: @ps, item: &ast::item) {
end(s);
}
}
(s.ann.post)(ann_node);
s.ann.post(ann_node);
}
fn print_trait_ref(s: @ps, t: &ast::trait_ref) {
@ -958,7 +969,7 @@ pub fn print_possibly_embedded_block_(s: @ps,
}
maybe_print_comment(s, blk.span.lo);
let ann_node = node_block(s, blk);
(s.ann.pre)(ann_node);
s.ann.pre(ann_node);
match embedded {
block_block_fn => end(s),
block_normal => bopen(s)
@ -979,7 +990,7 @@ pub fn print_possibly_embedded_block_(s: @ps,
_ => ()
}
bclose_maybe_open(s, blk.span, indented, close_box);
(s.ann.post)(ann_node);
s.ann.post(ann_node);
}
pub fn print_if(s: @ps, test: &ast::Expr, blk: &ast::Block,
@ -1121,7 +1132,7 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
maybe_print_comment(s, expr.span.lo);
ibox(s, indent_unit);
let ann_node = node_expr(s, expr);
(s.ann.pre)(ann_node);
s.ann.pre(ann_node);
match expr.node {
ast::ExprVstore(e, v) => {
print_expr_vstore(s, v);
@ -1456,7 +1467,7 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
pclose(s);
}
}
(s.ann.post)(ann_node);
s.ann.post(ann_node);
end(s);
}
@ -1578,7 +1589,7 @@ pub fn print_bounded_path(s: @ps, path: &ast::Path,
pub fn print_pat(s: @ps, pat: &ast::Pat) {
maybe_print_comment(s, pat.span.lo);
let ann_node = node_pat(s, pat);
(s.ann.pre)(ann_node);
s.ann.pre(ann_node);
/* Pat isn't normalized, but the beauty of it
is that it doesn't matter */
match pat.node {
@ -1678,7 +1689,7 @@ pub fn print_pat(s: @ps, pat: &ast::Pat) {
word(s.s, "]");
}
}
(s.ann.post)(ann_node);
s.ann.post(ann_node);
}
pub fn explicit_self_to_str(explicit_self: &ast::explicit_self_, intr: @ident_interner) -> ~str {
@ -2254,17 +2265,6 @@ pub fn print_fn_header_info(s: @ps,
print_opt_sigil(s, opt_sigil);
}
pub fn opt_sigil_to_str(opt_p: Option<ast::Sigil>) -> &'static str {
match opt_p {
None => "fn",
Some(p) => match p {
ast::BorrowedSigil => "fn&",
ast::OwnedSigil => "fn~",
ast::ManagedSigil => "fn@"
}
}
}
pub fn purity_to_str(p: ast::purity) -> &'static str {
match p {
ast::impure_fn => "impure",

View File

@ -14,7 +14,7 @@ pub struct Entry<A,B> {
}
pub struct alist<A,B> {
eq_fn: @fn(A,A) -> bool,
eq_fn: extern "Rust" fn(A,A) -> bool,
data: @mut ~[Entry<A,B>]
}

View File

@ -1,14 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub fn to_closure<A:'static + Clone>(x: A) -> @fn() -> A {
let result: @fn() -> A = || x.clone();
result
}

View File

@ -46,7 +46,6 @@ type nillist = List<()>;
struct State {
box: @nillist,
unique: ~nillist,
fn_box: @fn() -> @nillist,
tuple: (@nillist, ~nillist),
vec: ~[@nillist],
res: r
@ -79,19 +78,15 @@ fn recurse_or_fail(depth: int, st: Option<State>) {
State {
box: @Nil,
unique: ~Nil,
fn_box: || @Nil::<()>,
tuple: (@Nil, ~Nil),
vec: ~[@Nil],
res: r(@Nil)
}
}
Some(st) => {
let fn_box = st.fn_box;
State {
box: @Cons((), st.box),
unique: ~Cons((), @*st.unique),
fn_box: || @Cons((), fn_box()),
tuple: (@Cons((), st.tuple.first()),
~Cons((), @*st.tuple.second())),
vec: st.vec + &[@Cons((), *st.vec.last())],

View File

@ -1,27 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn foo(x: @int) -> @fn() -> &'static int {
let result: @fn() -> &'static int = || &*x; //~ ERROR cannot root
result
}
fn bar(x: @int) -> @fn() -> &int {
let result: @fn() -> &int = || &*x; //~ ERROR cannot root
result
}
fn zed(x: @int) -> @fn() -> int {
let result: @fn() -> int = || *&*x;
result
}
fn main() {
}

View File

@ -1,13 +1,13 @@
pub fn main() {
let foo = ~3;
let _pfoo = &foo;
let _f: @fn() -> int = || *foo + 5;
let _f: ~fn() -> int = || *foo + 5;
//~^ ERROR cannot move `foo`
// FIXME(#2202) - Due to the way that borrowck treats closures,
// you get two error reports here.
let bar = ~3;
let _g = || { //~ ERROR capture of moved value
let _h: @fn() -> int = || *bar; //~ ERROR capture of moved value
let _h: ~fn() -> int = || *bar; //~ ERROR capture of moved value
};
}

View File

@ -9,10 +9,10 @@
// except according to those terms.
struct X {
field: @fn:Send(),
field: ~fn:Send(),
}
fn foo(blk: @fn:()) -> X {
fn foo(blk: ~fn:()) -> X {
return X { field: blk }; //~ ERROR expected bounds `Send` but found no bounds
}

View File

@ -1,3 +1,8 @@
// xfail-test
// xfail'd because the lint pass doesn't know to ignore standard library
// stuff.
// -*- rust -*-
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn f(f: @fn(int) -> bool) -> bool { f(10i) }
fn f(f: &fn(int) -> bool) -> bool { f(10i) }
fn main() {
assert!(do f() |i| { i == 10i } == 10i);

View File

@ -1,30 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn reproduce<T>(t: T) -> @fn() -> T {
let result: @fn() -> T = || t;
result
}
fn main() {
// type of x is the variable X,
// with the lower bound @mut int
let x = @mut 3;
// type of r is @fn() -> X
let r = reproduce(x);
// Requires that X be a subtype of
// @mut int.
let f: @mut int = r();
// Bad.
let h: @int = r(); //~ ERROR (values differ in mutability)
}

View File

@ -1,32 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn mk_identity<T>() -> @fn(T) -> T {
let result: @fn(t: T) -> T = |t| t;
result
}
fn main() {
// type of r is @fn(X) -> X
// for some fresh X
let r = mk_identity();
// @mut int <: X
r(@mut 3);
// @int <: X
//
// Here the type check fails because @const is gone and there is no
// supertype.
r(@3); //~ ERROR mismatched types
// Here the type check succeeds.
*r(@mut 3) = 4;
}

View File

@ -9,8 +9,8 @@
// except according to those terms.
// xfail-test
struct T { f: @fn() };
struct S { f: @fn() };
struct T { f: extern "Rust" fn() };
struct S { f: extern "Rust" fn() };
fn fooS(t: S) {
}
@ -22,11 +22,11 @@ fn bar() {
}
fn main() {
let x: @fn() = bar;
let x: extern "Rust" fn() = bar;
fooS(S {f: x});
fooS(S {f: bar});
let x: @fn() = bar;
let x: extern "Rust" fn() = bar;
fooT(T {f: x});
fooT(T {f: bar});
}

View File

@ -1,26 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that we require managed closures to be rooted when borrowed.
struct boxedFn<'self> { theFn: &'self fn() -> uint }
fn createClosure (closedUint: uint) -> boxedFn {
let theFn: @fn() -> uint = || closedUint;
boxedFn {theFn: theFn} //~ ERROR cannot root
}
fn main () {
let aFn: boxedFn = createClosure(10);
let myInt: uint = (aFn.theFn)();
assert_eq!(myInt, 10);
}

View File

@ -10,11 +10,11 @@
// xfail-test
fn main() {
let one: @fn() -> uint = || {
let one: &fn() -> uint = || {
enum r { a };
a as uint
};
let two = @fn() -> uint = || {
let two = &fn() -> uint = || {
enum r { a };
a as uint
};

View File

@ -1,3 +1,7 @@
// xfail-test
// xfail'd because the lint pass doesn't know to ignore standard library
// stuff.
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.

View File

@ -1,3 +1,5 @@
// xfail-test
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.

View File

@ -1,28 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn copy1<T:Clone>(t: T) -> @fn() -> T {
let result: @fn() -> T = || t.clone(); //~ ERROR does not fulfill `'static`
result
}
fn copy2<T:Clone + 'static>(t: T) -> @fn() -> T {
let result: @fn() -> T = || t.clone();
result
}
fn main() {
let x = &3;
copy2(&x); //~ ERROR does not fulfill `'static`
copy2(@3);
copy2(@&x); //~ ERROR value may contain borrowed pointers
//~^ ERROR does not fulfill `'static`
}

View File

@ -1,25 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Make sure that nesting a block within a @fn doesn't let us
// mutate upvars from a @fn.
fn f2(x: &fn()) { x(); }
fn main() {
let i = 0;
let ctr: @fn() -> int = || { f2(|| i = i + 1 ); i };
//~^ ERROR cannot assign
error!(ctr());
error!(ctr());
error!(ctr());
error!(ctr());
error!(ctr());
error!(i);
}

View File

@ -1,22 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Make sure we can't write to upvars from @fns
fn main() {
let i = 0;
let ctr: @fn() -> int = || { i = i + 1; i };
//~^ ERROR cannot assign
error!(ctr());
error!(ctr());
error!(ctr());
error!(ctr());
error!(ctr());
error!(i);
}

View File

@ -9,7 +9,7 @@
// except according to those terms.
fn main() {
let j: @fn() -> int = || {
let j: &fn() -> int = || {
let i: int;
i //~ ERROR use of possibly uninitialized variable: `i`
};

View File

@ -9,7 +9,7 @@
// except according to those terms.
fn main() {
let f: @fn() -> int = || {
let f: &fn() -> int = || {
let i: int;
i //~ ERROR use of possibly uninitialized variable: `i`
};

View File

@ -8,8 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn of<T>() -> @fn(T) { fail!(); }
fn subtype<T>(x: @fn(T)) { fail!(); }
fn of<T>() -> &fn(T) { fail!(); }
fn subtype<T>(x: &fn(T)) { fail!(); }
fn test_fn<'x,'y,'z,T>(_x: &'x T, _y: &'y T, _z: &'z T) {
// Here, x, y, and z are free. Other letters
@ -40,18 +40,6 @@ fn test_fn<'x,'y,'z,T>(_x: &'x T, _y: &'y T, _z: &'z T) {
subtype::<&fn<'x,'y>(&'x T, &'y T)>(
of::<&fn<'a,'b>(&'a T, &'b T)>()); //~ ERROR mismatched types
subtype::<&fn<'x,'a>(&'x T) -> @fn(&'a T)>(
of::<&fn<'x,'a>(&'x T) -> @fn(&'a T)>());
subtype::<&fn<'a>(&'a T) -> @fn(&'a T)>(
of::<&fn<'a,'b>(&'a T) -> @fn(&'b T)>()); //~ ERROR mismatched types
subtype::<&fn<'a>(&'a T) -> @fn(&'a T)>(
of::<&fn<'x,'b>(&'x T) -> @fn(&'b T)>()); //~ ERROR mismatched types
subtype::<&fn<'a,'b>(&'a T) -> @fn(&'b T)>(
of::<&fn<'a>(&'a T) -> @fn(&'a T)>());
}
fn main() {}

View File

@ -12,7 +12,7 @@
// we reported errors in this case:
fn not_ok<'b>(a: &uint, b: &'b uint) {
let mut g: @fn(x: &uint) = |x: &'b uint| {};
let mut g: &fn(x: &uint) = |x: &'b uint| {};
//~^ ERROR mismatched types
g(a);
}

View File

@ -13,11 +13,11 @@ struct parameterized1<'self> {
}
struct not_parameterized1 {
g: @fn()
g: &'static fn()
}
struct not_parameterized2 {
g: @fn()
g: &'static fn()
}
fn take1(p: parameterized1) -> parameterized1 { p }

View File

@ -14,7 +14,7 @@
// the normal case.
struct contravariant<'self> {
f: @fn() -> &'self int
f: &'static fn() -> &'self int
}
fn to_same_lifetime<'r>(bi: contravariant<'r>) {

View File

@ -13,7 +13,7 @@
// You can upcast to a *larger region* but not a smaller one.
struct covariant<'self> {
f: @fn(x: &'self int) -> int
f: &'static fn(x: &'self int) -> int
}
fn to_same_lifetime<'r>(bi: covariant<'r>) {

View File

@ -9,7 +9,7 @@
// except according to those terms.
struct invariant<'self> {
f: @fn(x: @mut &'self int)
f: &'static fn(x: @mut &'self int)
}
fn to_same_lifetime<'r>(bi: invariant<'r>) {

View File

@ -9,7 +9,7 @@
// except according to those terms.
struct invariant<'self> {
f: @fn() -> @mut &'self int
f: &'static fn() -> @mut &'self int
}
fn to_same_lifetime<'r>(bi: invariant<'r>) {

View File

@ -14,12 +14,12 @@ struct direct<'self> {
struct indirect1 {
// Here the lifetime parameter of direct is bound by the fn()
g: @fn(direct)
g: &'static fn(direct)
}
struct indirect2<'self> {
// But here it is set to 'self
g: @fn(direct<'self>)
g: &'static fn(direct<'self>)
}
fn take_direct(p: direct) -> direct { p } //~ ERROR mismatched types

View File

@ -1,18 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn test(f: @fn(uint) -> uint) -> uint {
return f(22u);
}
fn main() {
let f: ~fn(x: uint) -> uint = |x| 4u;
info!(test(f)); //~ ERROR expected @ closure, found ~ closure
}

View File

@ -1,77 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags:-Z extra-debug-info
// debugger:rbreak zzz
// debugger:run
// debugger:finish
// debugger:print x
// check:$1 = false
// debugger:continue
// debugger:finish
// debugger:print x
// check:$2 = false
// debugger:continue
// debugger:finish
// debugger:print x
// check:$3 = 1000
// debugger:continue
// debugger:finish
// debugger:print x
// check:$4 = 2.5
// debugger:continue
// debugger:finish
// debugger:print x
// check:$5 = true
// debugger:continue
// debugger:finish
// debugger:print x
// check:$6 = false
// debugger:continue
fn main() {
let x = false;
zzz();
sentinel();
let managed_closure: @fn(int) = |x| {
zzz();
sentinel();
let x = 2.5;
zzz();
sentinel();
let x = true;
zzz();
sentinel();
};
zzz();
sentinel();
managed_closure(1000);
zzz();
sentinel();
}
fn zzz() {()}
fn sentinel() {()}

View File

@ -1,56 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags:-Z extra-debug-info
// debugger:rbreak zzz
// debugger:run
// debugger:finish
// debugger:print constant
// check:$1 = 1
// debugger:print a_struct
// check:$2 = {a = -2, b = 3.5, c = 4}
// debugger:print *owned
// check:$3 = 5
// debugger:print managed->val
// check:$4 = 6
#[allow(unused_variable)];
struct Struct {
a: int,
b: float,
c: uint
}
fn main() {
let constant = 1;
let a_struct = Struct {
a: -2,
b: 3.5,
c: 4
};
let owned = ~5;
let managed = @6;
let closure: @fn() = || {
zzz();
do_something(&constant, &a_struct.a, owned, managed);
};
closure();
}
fn do_something(_: &int, _:&int, _:&int, _:&int) {
}
fn zzz() {()}

View File

@ -1,12 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn blk1(_b: &fn()) -> @fn() { return || { }; }
fn test1() { (do blk1 { info!("hi"); })(); }

View File

@ -10,6 +10,6 @@
// pp-exact
fn f(f: @fn(int)) { f(10) }
fn f(f: &fn(int)) { f(10) }
fn main() { do f |i| { assert!(i == 10) } }

View File

@ -12,6 +12,5 @@
fn from_foreign_fn(_x: extern "Rust" fn()) { }
fn from_stack_closure(_x: &fn()) { }
fn from_box_closure(_x: @fn()) { }
fn from_unique_closure(_x: ~fn()) { }
fn main() { }

View File

@ -1,24 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern:fail
fn failfn() {
fail!();
}
fn main() {
let y = ~0;
let x: @@fn() = @|| {
error!(y.clone());
};
failfn();
error!(x);
}

View File

@ -1,21 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern:fail
fn f(_a: @int) {
fail!();
}
fn main() {
let b = @0;
let g: @fn() = || f(b);
g();
}

View File

@ -14,7 +14,7 @@ fn main() {
let cheese = ~"roquefort";
let carrots = @~"crunchy";
let result: @fn(@~str, &fn(~str)) = (|tasties, macerate| {
let result: &'static fn(@~str, &fn(~str)) = (|tasties, macerate| {
macerate((*tasties).clone());
});
result(carrots, |food| {

View File

@ -12,13 +12,30 @@ struct pair<A,B> {
a: A, b: B
}
fn f<A:Clone + 'static>(a: A, b: u16) -> @fn() -> (A, u16) {
let result: @fn() -> (A, u16) = || (a.clone(), b);
result
trait Invokable<A> {
fn f(&self) -> (A, u16);
}
struct Invoker<A> {
a: A,
b: u16,
}
impl<A:Clone> Invokable<A> for Invoker<A> {
fn f(&self) -> (A, u16) {
(self.a.clone(), self.b)
}
}
fn f<A:Clone + 'static>(a: A, b: u16) -> @Invokable<A> {
@Invoker {
a: a,
b: b,
} as @Invokable<A>
}
pub fn main() {
let (a, b) = f(22_u64, 44u16)();
let (a, b) = f(22_u64, 44u16).f();
info!("a=%? b=%?", a, b);
assert_eq!(a, 22u64);
assert_eq!(b, 44u16);

View File

@ -23,13 +23,30 @@ fn make_cycle<A:'static>(a: A) {
g.rec = Some(g);
}
struct Invoker<A,B> {
a: A,
b: B,
}
trait Invokable<A,B> {
fn f(&self) -> (A, B);
}
impl<A:Clone,B:Clone> Invokable<A,B> for Invoker<A,B> {
fn f(&self) -> (A, B) {
(self.a.clone(), self.b.clone())
}
}
fn f<A:Send + Clone + 'static,
B:Send + Clone + 'static>(
a: A,
b: B)
-> @fn() -> (A, B) {
let result: @fn() -> (A, B) = || (a.clone(), b.clone());
result
-> @Invokable<A,B> {
@Invoker {
a: a,
b: b,
} as @Invokable<A,B>
}
pub fn main() {
@ -37,7 +54,7 @@ pub fn main() {
let y = 44_u64;
let z = f(~x, y);
make_cycle(z);
let (a, b) = z();
let (a, b) = z.f();
info!("a=%u b=%u", *a as uint, b as uint);
assert_eq!(*a, x);
assert_eq!(b, y);

View File

@ -14,10 +14,6 @@ fn asSendfn( f : ~fn()->uint ) -> uint {
return f();
}
fn asLambda( f : @fn()->uint ) -> uint {
return f();
}
fn asBlock( f : &fn()->uint ) -> uint {
return f();
}
@ -25,8 +21,6 @@ fn asBlock( f : &fn()->uint ) -> uint {
pub fn main() {
let x = asSendfn(|| 22u);
assert_eq!(x, 22u);
let x = asLambda(|| 22u);
assert_eq!(x, 22u);
let x = asBlock(|| 22u);
assert_eq!(x, 22u);
}

View File

@ -1,24 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn to_lambda(f: @fn(uint) -> uint) -> @fn(uint) -> uint {
return f;
}
pub fn main() {
let x: @fn(uint) -> uint = to_lambda(|x| x * 2u );
let y = to_lambda(x);
let x_r = x(22u);
let y_r = y(x_r);
assert_eq!(x_r, 44u);
assert_eq!(y_r, 88u);
}

View File

@ -1,5 +1,5 @@
pub fn main() {
let bar = ~3;
let h: @fn() -> int = || *bar;
let h: ~fn() -> int = || *bar;
assert_eq!(h(), 3);
}

View File

@ -11,7 +11,7 @@
fn foo() -> int { 22 }
pub fn main() {
let mut x: ~[@fn() -> int] = ~[];
let mut x: ~[extern "Rust" fn() -> int] = ~[];
x.push(foo);
assert_eq!((x[0])(), 22);
}

View File

@ -11,16 +11,6 @@
use std::ptr;
pub fn main() {
let x = ~1;
let y = ptr::to_unsafe_ptr(&(*x)) as uint;
let lam_move: @fn() -> uint = || ptr::to_unsafe_ptr(&(*x)) as uint;
assert_eq!(lam_move(), y);
let x = ~2;
let y = ptr::to_unsafe_ptr(&(*x)) as uint;
let lam_move: @fn() -> uint = || ptr::to_unsafe_ptr(&(*x)) as uint;
assert_eq!(lam_move(), y);
let x = ~3;
let y = ptr::to_unsafe_ptr(&(*x)) as uint;
let snd_move: ~fn() -> uint = || ptr::to_unsafe_ptr(&(*x)) as uint;

View File

@ -16,13 +16,30 @@ struct Pair<A,B> {
a: A, b: B
}
fn f<A:Clone + 'static>(a: A, b: u16) -> @fn() -> (A, u16) {
let result: @fn() -> (A, u16) = || (a.clone(), b);
result
struct Invoker<A> {
a: A,
b: u16,
}
trait Invokable<A> {
fn f(&self) -> (A, u16);
}
impl<A:Clone> Invokable<A> for Invoker<A> {
fn f(&self) -> (A, u16) {
(self.a.clone(), self.b)
}
}
fn f<A:Clone + 'static>(a: A, b: u16) -> @Invokable<A> {
@Invoker {
a: a,
b: b,
} as @Invokable<A>
}
pub fn main() {
let (a, b) = f(22_u64, 44u16)();
let (a, b) = f(22_u64, 44u16).f();
info!("a=%? b=%?", a, b);
assert_eq!(a, 22u64);
assert_eq!(b, 44u16);

View File

@ -8,13 +8,33 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
struct foo { z: @fn() }
struct foo {
z: Option<@Invokable>,
}
struct Thing {
w: @mut foo,
}
trait Invokable {
fn f(&self);
}
impl Invokable for Thing {
fn f(&self) {
nop_foo(self.w);
}
}
fn nop() { }
fn nop_foo(_x : @mut foo) { }
pub fn main() {
let w = @mut foo{ z: || nop() };
let x: @fn() = || nop_foo(w);
w.z = x;
let w = @mut foo {
z: None,
};
let x = @Thing {
w: w,
} as @Invokable;
w.z = Some(x);
}

View File

@ -1,20 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
struct foo { z : @fn() }
fn nop() { }
fn nop_foo(_y: ~[int], _x : @mut foo) { }
pub fn main() {
let w = @mut foo{ z: || nop() };
let x : @fn() = || nop_foo(~[], w);
w.z = x;
}

View File

@ -1,22 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
struct foo { z: @fn() }
fn nop() { }
fn nop_foo(_y: @int, _x: @mut foo) { }
fn o() -> @int { @10 }
pub fn main() {
let w = @mut foo { z: || nop() };
let x : @fn() = || nop_foo(o(), w);
w.z = x;
}

View File

@ -10,9 +10,9 @@
// Testing that we can drop the || in do exprs
fn f(_f: @fn() -> bool) -> bool { true }
fn f(_f: &fn() -> bool) -> bool { true }
fn d(_f: @fn()) { }
fn d(_f: &fn()) { }
pub fn main() {
do d { }

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn f(f: @fn(int)) { f(10) }
fn f(f: &fn(int)) { f(10) }
pub fn main() {
do f() |i| { assert!(i == 10) }

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn f(f: @fn(int) -> int) -> int { f(10) }
fn f(f: &fn(int) -> int) -> int { f(10) }
pub fn main() {
assert_eq!(do f() |i| { i }, 10);

Some files were not shown because too many files have changed in this diff Show More