From 3e5de06135fa9a857931191101d61a4abe149c96 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 29 Aug 2013 12:10:02 -0700 Subject: [PATCH 01/16] librustc: Change fold to use traits instead of `@fn`. --- src/librustc/front/assign_node_ids.rs | 17 +- src/librustc/front/config.rs | 62 +- src/librustc/front/std_inject.rs | 169 +-- src/librustc/front/test.rs | 175 ++- src/librustc/middle/astencode.rs | 77 +- src/librustpkg/util.rs | 35 +- src/libsyntax/ast_util.rs | 16 - src/libsyntax/ext/build.rs | 30 + src/libsyntax/ext/expand.rs | 463 ++++--- src/libsyntax/fold.rs | 1540 +++++++++++------------- src/test/compile-fail/dead-code-ret.rs | 5 + src/test/compile-fail/issue-897-2.rs | 4 + 12 files changed, 1335 insertions(+), 1258 deletions(-) diff --git a/src/librustc/front/assign_node_ids.rs b/src/librustc/front/assign_node_ids.rs index 446db5c35e9..fc1b034de97 100644 --- a/src/librustc/front/assign_node_ids.rs +++ b/src/librustc/front/assign_node_ids.rs @@ -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) } diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs index 2c0068729a7..fc1794fb935 100644 --- a/src/librustc/front/config.rs +++ b/src/librustc/front/config.rs @@ -10,6 +10,7 @@ use std::option; +use syntax::fold::ast_fold; use syntax::{ast, fold, attr}; type in_cfg_pred = @fn(attrs: &[ast::Attribute]) -> bool; @@ -26,21 +27,34 @@ pub fn strip_unconfigured_items(crate: @ast::Crate) -> @ast::Crate { } } -pub fn strip_items(crate: &ast::Crate, in_cfg: in_cfg_pred) - -> @ast::Crate { +struct ItemRemover { + ctxt: @Context, +} - let ctxt = @Context { in_cfg: in_cfg }; +impl fold::ast_fold for ItemRemover { + fn fold_mod(&self, module: &ast::_mod) -> ast::_mod { + fold_mod(self.ctxt, module, self) + } + fn fold_block(&self, block: &ast::Block) -> ast::Block { + fold_block(self.ctxt, block, self) + } + fn fold_foreign_mod(&self, foreign_module: &ast::foreign_mod) + -> ast::foreign_mod { + fold_foreign_mod(self.ctxt, foreign_module, self) + } + fn fold_item_underscore(&self, item: &ast::item_) -> ast::item_ { + fold_item_underscore(self.ctxt, item, self) + } +} - 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() +pub fn strip_items(crate: &ast::Crate, in_cfg: in_cfg_pred) -> @ast::Crate { + let ctxt = @Context { + in_cfg: in_cfg, }; - - let fold = fold::make_fold(precursor); - @fold.fold_crate(crate) + let precursor = ItemRemover { + ctxt: ctxt, + }; + @precursor.fold_crate(crate) } fn filter_item(cx: @Context, item: @ast::item) -> @@ -56,7 +70,7 @@ fn filter_view_item<'r>(cx: @Context, view_item: &'r ast::view_item)-> Option<&' } } -fn fold_mod(cx: @Context, m: &ast::_mod, fld: @fold::ast_fold) -> ast::_mod { +fn fold_mod(cx: @Context, m: &ast::_mod, fld: &ItemRemover) -> ast::_mod { let filtered_items = do m.items.iter().filter_map |a| { filter_item(cx, *a).and_then(|x| fld.fold_item(x)) }.collect(); @@ -78,12 +92,12 @@ fn filter_foreign_item(cx: @Context, item: @ast::foreign_item) -> } else { option::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, fld: &ItemRemover) + -> 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) @@ -97,8 +111,8 @@ 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_, fld: &ItemRemover) + -> 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)) @@ -133,11 +147,7 @@ fn filter_stmt(cx: @Context, stmt: @ast::Stmt) -> } } -fn fold_block( - cx: @Context, - b: &ast::Block, - fld: @fold::ast_fold -) -> ast::Block { +fn fold_block(cx: @Context, b: &ast::Block, fld: &ItemRemover) -> ast::Block { let resulting_stmts = do b.stmts.iter().filter_map |a| { filter_stmt(cx, *a).and_then(|stmt| fld.fold_stmt(stmt)) }.collect(); diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs index 79e554090f3..ab407806bcc 100644 --- a/src/librustc/front/std_inject.rs +++ b/src/librustc/front/std_inject.rs @@ -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(x: T) -> codemap::Spanned { - codemap::Spanned { node: x, span: dummy_sp() } +fn spanned(x: T) -> codemap::Spanned { + 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) } diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index f0d7f6c892b..d2baee6c961 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -21,6 +21,7 @@ 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; @@ -61,9 +62,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 +162,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 +179,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"); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index bcc333afeec..6521b4bb3cc 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -287,26 +287,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 +316,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 +350,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) => diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 906bed2f234..02524b65020 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -18,6 +18,8 @@ use syntax::codemap::{dummy_sp, Spanned}; use syntax::ext::base::ExtCtxt; use syntax::{ast, attr, codemap, diagnostic, fold}; use syntax::attr::AttrMetaMethods; +use syntax::fold::ast_fold; +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}; @@ -70,9 +72,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 +95,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 +134,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 +157,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) } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index f0f86911f50..2e47050ad6a 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -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 diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 889c2a5976e..aa4238ae908 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -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) + } +} diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 82d452bc734..0aefbe31338 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -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, @@ -101,12 +100,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 +131,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 +228,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 +251,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 +281,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 +307,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 +332,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") @@ -382,15 +438,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, Span)) - -> (Option, 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 +451,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,11 +481,16 @@ 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}, + 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(), _ => cx.span_fatal( pth.span, @@ -438,12 +498,15 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv, }; 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 +514,7 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv, } }; - (fully_expanded, sp) + fully_expanded } _ => { @@ -460,24 +523,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, Span)) - -> (Option,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 +582,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 +700,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 +752,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. +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 +1135,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(), cfg.clone(), @@ -1038,48 +1166,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 +1305,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(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(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. diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 5472c61a155..18ddee34171 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -14,227 +14,434 @@ use codemap::{Span, Spanned}; use parse::token; use opt_vec::OptVec; -// this file defines an ast_fold trait for objects that can perform -// a "fold" on Rust ASTs. It also contains a structure that implements -// that trait, and a "default_fold" whose fields contain closures -// that perform "default traversals", visiting all of the sub-elements -// and re-assembling the result. The "fun_to_ident_folder" in the -// test module provides a simple example of creating a very simple -// fold that only looks at identifiers. - +// We may eventually want to be able to fold over type parameters, too. pub trait ast_fold { - fn fold_crate(@self, &Crate) -> Crate; - fn fold_view_item(@self, &view_item) -> view_item; - fn fold_foreign_item(@self, @foreign_item) -> @foreign_item; - fn fold_item(@self, @item) -> Option<@item>; - fn fold_struct_field(@self, @struct_field) -> @struct_field; - fn fold_item_underscore(@self, &item_) -> item_; - fn fold_type_method(@self, m: &TypeMethod) -> TypeMethod; - fn fold_method(@self, @method) -> @method; - fn fold_block(@self, &Block) -> Block; - fn fold_stmt(@self, &Stmt) -> Option<@Stmt>; - fn fold_arm(@self, &Arm) -> Arm; - fn fold_pat(@self, @Pat) -> @Pat; - fn fold_decl(@self, @Decl) -> Option<@Decl>; - fn fold_expr(@self, @Expr) -> @Expr; - fn fold_ty(@self, &Ty) -> Ty; - fn fold_mod(@self, &_mod) -> _mod; - fn fold_foreign_mod(@self, &foreign_mod) -> foreign_mod; - fn fold_variant(@self, &variant) -> variant; - fn fold_ident(@self, Ident) -> Ident; - fn fold_path(@self, &Path) -> Path; - fn fold_local(@self, @Local) -> @Local; - fn fold_mac(@self, &mac) -> mac; - fn map_exprs(@self, @fn(@Expr) -> @Expr, &[@Expr]) -> ~[@Expr]; - fn new_id(@self, NodeId) -> NodeId; - fn new_span(@self, Span) -> Span; + fn fold_crate(&self, c: &Crate) -> Crate { + noop_fold_crate(c, self) + } - // New style, using default methods: + fn fold_meta_items(&self, meta_items: &[@MetaItem]) -> ~[@MetaItem] { + meta_items.map(|x| fold_meta_item_(*x, self)) + } - fn fold_variant_arg(@self, va: &variant_arg) -> variant_arg { - variant_arg { - ty: self.fold_ty(&va.ty), - id: self.new_id(va.id) + fn fold_view_paths(&self, view_paths: &[@view_path]) -> ~[@view_path] { + view_paths.map(|view_path| { + let inner_view_path = match view_path.node { + view_path_simple(ref ident, ref path, node_id) => { + view_path_simple(ident.clone(), + self.fold_path(path), + self.new_id(node_id)) + } + view_path_glob(ref path, node_id) => { + view_path_glob(self.fold_path(path), self.new_id(node_id)) + } + view_path_list(ref path, ref path_list_idents, node_id) => { + view_path_list(self.fold_path(path), + path_list_idents.map(|path_list_ident| { + let id = self.new_id(path_list_ident.node + .id); + Spanned { + node: path_list_ident_ { + name: path_list_ident.node + .name + .clone(), + id: id, + }, + span: self.new_span( + path_list_ident.span) + } + }), + self.new_id(node_id)) + } + }; + @Spanned { + node: inner_view_path, + span: self.new_span(view_path.span), + } + }) + } + + fn fold_view_item(&self, vi: &view_item) -> view_item { + let inner_view_item = match vi.node { + view_item_extern_mod(ref ident, + string, + ref meta_items, + node_id) => { + view_item_extern_mod(ident.clone(), + string, + self.fold_meta_items(*meta_items), + self.new_id(node_id)) + } + view_item_use(ref view_paths) => { + view_item_use(self.fold_view_paths(*view_paths)) + } + }; + view_item { + node: inner_view_item, + attrs: vi.attrs.map(|a| fold_attribute_(*a, self)), + vis: vi.vis, + span: self.new_span(vi.span), } } - fn fold_spanned(@self, s: &Spanned, f: &fn(&T) -> T) -> Spanned { + fn fold_foreign_item(&self, ni: @foreign_item) -> @foreign_item { + let fold_attribute = |x| fold_attribute_(x, self); + + @ast::foreign_item { + ident: self.fold_ident(ni.ident), + attrs: ni.attrs.map(|x| fold_attribute(*x)), + node: + match ni.node { + foreign_item_fn(ref fdec, ref generics) => { + foreign_item_fn( + ast::fn_decl { + inputs: fdec.inputs.map(|a| fold_arg_(a, + self)), + output: self.fold_ty(&fdec.output), + cf: fdec.cf, + }, + fold_generics(generics, self)) + } + foreign_item_static(ref t, m) => { + foreign_item_static(self.fold_ty(t), m) + } + }, + id: self.new_id(ni.id), + span: self.new_span(ni.span), + vis: ni.vis, + } + } + + fn fold_item(&self, i: @item) -> Option<@item> { + noop_fold_item(i, self) + } + + fn fold_struct_field(&self, sf: @struct_field) -> @struct_field { + let fold_attribute = |x| fold_attribute_(x, self); + + @Spanned { + node: ast::struct_field_ { + kind: sf.node.kind, + id: self.new_id(sf.node.id), + ty: self.fold_ty(&sf.node.ty), + attrs: sf.node.attrs.map(|e| fold_attribute(*e)) + }, + span: self.new_span(sf.span) + } + } + + fn fold_item_underscore(&self, i: &item_) -> item_ { + noop_fold_item_underscore(i, self) + } + + fn fold_type_method(&self, m: &TypeMethod) -> TypeMethod { + noop_fold_type_method(m, self) + } + + fn fold_method(&self, m: @method) -> @method { + @ast::method { + ident: self.fold_ident(m.ident), + attrs: m.attrs.map(|a| fold_attribute_(*a, self)), + generics: fold_generics(&m.generics, self), + explicit_self: m.explicit_self, + purity: m.purity, + decl: fold_fn_decl(&m.decl, self), + body: self.fold_block(&m.body), + id: self.new_id(m.id), + span: self.new_span(m.span), + self_id: self.new_id(m.self_id), + vis: m.vis, + } + } + + fn fold_block(&self, b: &Block) -> Block { + noop_fold_block(b, self) + } + + fn fold_stmt(&self, s: &Stmt) -> Option<@Stmt> { + noop_fold_stmt(s, self) + } + + fn fold_arm(&self, a: &Arm) -> Arm { + Arm { + pats: a.pats.map(|x| self.fold_pat(*x)), + guard: a.guard.map_move(|x| self.fold_expr(x)), + body: self.fold_block(&a.body), + } + } + + fn fold_pat(&self, p: @Pat) -> @Pat { + let node = match p.node { + PatWild => PatWild, + PatIdent(binding_mode, ref pth, ref sub) => { + PatIdent(binding_mode, + self.fold_path(pth), + sub.map_move(|x| self.fold_pat(x))) + } + PatLit(e) => PatLit(self.fold_expr(e)), + PatEnum(ref pth, ref pats) => { + PatEnum(self.fold_path(pth), + pats.map(|pats| pats.map(|x| self.fold_pat(*x)))) + } + PatStruct(ref pth, ref fields, etc) => { + let pth_ = self.fold_path(pth); + let fs = do fields.map |f| { + ast::FieldPat { + ident: f.ident, + pat: self.fold_pat(f.pat) + } + }; + PatStruct(pth_, fs, etc) + } + PatTup(ref elts) => PatTup(elts.map(|x| self.fold_pat(*x))), + PatBox(inner) => PatBox(self.fold_pat(inner)), + PatUniq(inner) => PatUniq(self.fold_pat(inner)), + PatRegion(inner) => PatRegion(self.fold_pat(inner)), + PatRange(e1, e2) => { + PatRange(self.fold_expr(e1), self.fold_expr(e2)) + }, + PatVec(ref before, ref slice, ref after) => { + PatVec(before.map(|x| self.fold_pat(*x)), + slice.map_move(|x| self.fold_pat(x)), + after.map(|x| self.fold_pat(*x))) + } + }; + + @Pat { + id: self.new_id(p.id), + span: self.new_span(p.span), + node: node, + } + } + + fn fold_decl(&self, d: @Decl) -> Option<@Decl> { + let node = match d.node { + DeclLocal(ref l) => Some(DeclLocal(self.fold_local(*l))), + DeclItem(it) => { + match self.fold_item(it) { + Some(it_folded) => Some(DeclItem(it_folded)), + None => None, + } + } + }; + + node.map_move(|node| { + @Spanned { + node: node, + span: d.span, + } + }) + } + + fn fold_expr(&self, e: @Expr) -> @Expr { + noop_fold_expr(e, self) + } + + fn fold_ty(&self, t: &Ty) -> Ty { + let node = match t.node { + ty_nil | ty_bot | ty_infer => t.node.clone(), + ty_box(ref mt) => ty_box(fold_mt(mt, self)), + ty_uniq(ref mt) => ty_uniq(fold_mt(mt, self)), + ty_vec(ref mt) => ty_vec(fold_mt(mt, self)), + ty_ptr(ref mt) => ty_ptr(fold_mt(mt, self)), + ty_rptr(region, ref mt) => ty_rptr(region, fold_mt(mt, self)), + ty_closure(ref f) => { + ty_closure(@TyClosure { + sigil: f.sigil, + purity: f.purity, + region: f.region, + onceness: f.onceness, + bounds: fold_opt_bounds(&f.bounds, self), + decl: fold_fn_decl(&f.decl, self), + lifetimes: f.lifetimes.map(|l| fold_lifetime(l, self)), + }) + } + ty_bare_fn(ref f) => { + ty_bare_fn(@TyBareFn { + lifetimes: f.lifetimes.map(|l| fold_lifetime(l, self)), + purity: f.purity, + abis: f.abis, + decl: fold_fn_decl(&f.decl, self) + }) + } + ty_tup(ref tys) => ty_tup(tys.map(|ty| self.fold_ty(ty))), + ty_path(ref path, ref bounds, id) => { + ty_path(self.fold_path(path), + fold_opt_bounds(bounds, self), + self.new_id(id)) + } + ty_fixed_length_vec(ref mt, e) => { + ty_fixed_length_vec(fold_mt(mt, self), self.fold_expr(e)) + } + ty_mac(ref mac) => ty_mac(self.fold_mac(mac)), + ty_typeof(expr) => ty_typeof(self.fold_expr(expr)), + }; + Ty { + id: self.new_id(t.id), + span: self.new_span(t.span), + node: node, + } + } + + fn fold_mod(&self, m: &_mod) -> _mod { + noop_fold_mod(m, self) + } + + fn fold_foreign_mod(&self, nm: &foreign_mod) -> foreign_mod { + ast::foreign_mod { + sort: nm.sort, + abis: nm.abis, + view_items: nm.view_items + .iter() + .map(|x| self.fold_view_item(x)) + .collect(), + items: nm.items + .iter() + .map(|x| self.fold_foreign_item(*x)) + .collect(), + } + } + + fn fold_variant(&self, v: &variant) -> variant { + let kind; + match v.node.kind { + tuple_variant_kind(ref variant_args) => { + kind = tuple_variant_kind(variant_args.map(|x| + fold_variant_arg_(x, self))) + } + struct_variant_kind(ref struct_def) => { + kind = struct_variant_kind(@ast::struct_def { + fields: struct_def.fields.iter() + .map(|f| self.fold_struct_field(*f)).collect(), + ctor_id: struct_def.ctor_id.map(|c| self.new_id(*c)) + }) + } + } + + let fold_attribute = |x| fold_attribute_(x, self); + let attrs = v.node.attrs.map(|x| fold_attribute(*x)); + + let de = match v.node.disr_expr { + Some(e) => Some(self.fold_expr(e)), + None => None + }; + let node = ast::variant_ { + name: v.node.name, + attrs: attrs, + kind: kind, + id: self.new_id(v.node.id), + disr_expr: de, + vis: v.node.vis, + }; Spanned { - node: f(&s.node), - span: self.new_span(s.span) + node: node, + span: self.new_span(v.span), } } - fn fold_view_path(@self, vp: &view_path) -> view_path { - self.fold_spanned(vp, |v| self.fold_view_path_(v)) + fn fold_ident(&self, i: Ident) -> Ident { + i } - fn fold_view_paths(@self, vps: &[@view_path]) -> ~[@view_path] { - vps.map(|vp| @self.fold_view_path(*vp)) - } - - fn fold_view_path_(@self, vp: &view_path_) -> view_path_ { - match *vp { - view_path_simple(ident, ref path, node_id) => { - view_path_simple(self.fold_ident(ident), - self.fold_path(path), - self.new_id(node_id)) - } - view_path_glob(ref path, node_id) => { - view_path_glob(self.fold_path(path), - self.new_id(node_id)) - } - view_path_list(ref path, ref idents, node_id) => { - view_path_list(self.fold_path(path), - self.fold_path_list_idents(*idents), - self.new_id(node_id)) - } + fn fold_path(&self, p: &Path) -> Path { + ast::Path { + span: self.new_span(p.span), + global: p.global, + segments: p.segments.map(|segment| ast::PathSegment { + identifier: self.fold_ident(segment.identifier), + lifetime: segment.lifetime, + types: segment.types.map(|typ| self.fold_ty(typ)), + }) } } - fn fold_path_list_idents(@self, idents: &[path_list_ident]) -> ~[path_list_ident] { - idents.map(|i| self.fold_path_list_ident(i)) - } - - fn fold_path_list_ident(@self, ident: &path_list_ident) -> path_list_ident { - self.fold_spanned(ident, |i| self.fold_path_list_ident_(i)) - } - - fn fold_path_list_ident_(@self, ident: &path_list_ident_) -> path_list_ident_ { - path_list_ident_ { - name: self.fold_ident(ident.name), - id: self.new_id(ident.id) - } - } - - fn fold_arg(@self, a: &arg) -> arg { - arg { - is_mutbl: a.is_mutbl, - ty: self.fold_ty(&a.ty), - pat: self.fold_pat(a.pat), - id: self.new_id(a.id), - } - } - - fn fold_trait_ref(@self, p: &trait_ref) -> trait_ref { - trait_ref { - path: self.fold_path(&p.path), - ref_id: self.new_id(p.ref_id), - } - } - - fn fold_ty_param_bound(@self, tpb: &TyParamBound) -> TyParamBound { - match *tpb { - TraitTyParamBound(ref ty) => { - TraitTyParamBound(self.fold_trait_ref(ty)) - } - RegionTyParamBound => { - RegionTyParamBound - } - } - } - - fn fold_ty_param(@self, tp: &TyParam) -> TyParam { - TyParam { - ident: self.fold_ident(tp.ident), - id: self.new_id(tp.id), - bounds: tp.bounds.map(|x| self.fold_ty_param_bound(x)) - } - } - - fn fold_ty_params(@self, tps: &OptVec) -> OptVec { - tps.map(|tp| self.fold_ty_param(tp)) - } - - fn fold_lifetime(@self, l: &Lifetime) -> Lifetime { - Lifetime { + fn fold_local(&self, l: @Local) -> @Local { + @Local { + is_mutbl: l.is_mutbl, + ty: self.fold_ty(&l.ty), + pat: self.fold_pat(l.pat), + init: l.init.map_move(|e| self.fold_expr(e)), id: self.new_id(l.id), span: self.new_span(l.span), - ident: l.ident, // Folding this ident causes hygiene errors - ndm } } - fn fold_lifetimes(@self, lts: &OptVec) -> OptVec { - lts.map(|l| self.fold_lifetime(l)) - } - - - fn fold_meta_item(@self, mi: &MetaItem) -> @MetaItem { - @self.fold_spanned(mi, |n| match *n { - MetaWord(id) => { - MetaWord(id) - } - MetaList(id, ref mis) => { - MetaList(id, self.fold_meta_items(*mis)) - } - MetaNameValue(id, s) => { - MetaNameValue(id, s) - } - }) - } - - fn fold_meta_items(@self, mis: &[@MetaItem]) -> ~[@MetaItem] { - mis.map(|&mi| self.fold_meta_item(mi)) - } - - fn fold_attribute(@self, at: &Attribute) -> Attribute { + fn fold_mac(&self, macro: &mac) -> mac { Spanned { - span: self.new_span(at.span), - node: Attribute_ { - style: at.node.style, - value: self.fold_meta_item(at.node.value), - is_sugared_doc: at.node.is_sugared_doc - } + node: match macro.node { + mac_invoc_tt(ref p, ref tts, ctxt) => { + mac_invoc_tt(self.fold_path(p), + fold_tts(*tts, self), + ctxt) + } + }, + span: self.new_span(macro.span) } } - fn fold_attributes(@self, attrs: &[Attribute]) -> ~[Attribute] { - attrs.map(|x| self.fold_attribute(x)) + fn map_exprs(&self, f: &fn(@Expr) -> @Expr, es: &[@Expr]) -> ~[@Expr] { + es.map(|x| f(*x)) + } + + fn new_id(&self, i: NodeId) -> NodeId { + i + } + + fn new_span(&self, sp: Span) -> Span { + sp } } -// We may eventually want to be able to fold over type parameters, too - -pub struct AstFoldFns { - //unlike the others, item_ is non-trivial - fold_crate: @fn(&Crate, @ast_fold) -> Crate, - fold_view_item: @fn(&view_item_, @ast_fold) -> view_item_, - fold_foreign_item: @fn(@foreign_item, @ast_fold) -> @foreign_item, - fold_item: @fn(@item, @ast_fold) -> Option<@item>, - fold_struct_field: @fn(@struct_field, @ast_fold) -> @struct_field, - fold_item_underscore: @fn(&item_, @ast_fold) -> item_, - fold_type_method: @fn(&TypeMethod, @ast_fold) -> TypeMethod, - fold_method: @fn(@method, @ast_fold) -> @method, - fold_block: @fn(&Block, @ast_fold) -> Block, - fold_stmt: @fn(&Stmt_, Span, @ast_fold) -> (Option, Span), - fold_arm: @fn(&Arm, @ast_fold) -> Arm, - fold_pat: @fn(&Pat_, Span, @ast_fold) -> (Pat_, Span), - fold_decl: @fn(&Decl_, Span, @ast_fold) -> (Option, Span), - fold_expr: @fn(&Expr_, Span, @ast_fold) -> (Expr_, Span), - fold_ty: @fn(&ty_, Span, @ast_fold) -> (ty_, Span), - fold_mod: @fn(&_mod, @ast_fold) -> _mod, - fold_foreign_mod: @fn(&foreign_mod, @ast_fold) -> foreign_mod, - fold_variant: @fn(&variant_, Span, @ast_fold) -> (variant_, Span), - fold_ident: @fn(Ident, @ast_fold) -> Ident, - fold_path: @fn(&Path, @ast_fold) -> Path, - fold_local: @fn(@Local, @ast_fold) -> @Local, - fold_mac: @fn(&mac_, Span, @ast_fold) -> (mac_, Span), - map_exprs: @fn(@fn(@Expr) -> @Expr, &[@Expr]) -> ~[@Expr], - new_id: @fn(NodeId) -> NodeId, - new_span: @fn(Span) -> Span -} - -pub type ast_fold_fns = @AstFoldFns; - /* some little folds that probably aren't useful to have in ast_fold itself*/ -pub fn fold_tts(tts : &[token_tree], fld: @ast_fold) -> ~[token_tree] { +//used in noop_fold_item and noop_fold_crate and noop_fold_crate_directive +fn fold_meta_item_(mi: @MetaItem, fld: &T) -> @MetaItem { + @Spanned { + node: + match mi.node { + MetaWord(id) => MetaWord(id), + MetaList(id, ref mis) => { + let fold_meta_item = |x| fold_meta_item_(x, fld); + MetaList( + id, + mis.map(|e| fold_meta_item(*e)) + ) + } + MetaNameValue(id, s) => MetaNameValue(id, s) + }, + span: fld.new_span(mi.span) } +} + +//used in noop_fold_item and noop_fold_crate +fn fold_attribute_(at: Attribute, fld: &T) -> Attribute { + Spanned { + span: fld.new_span(at.span), + node: ast::Attribute_ { + style: at.node.style, + value: fold_meta_item_(at.node.value, fld), + is_sugared_doc: at.node.is_sugared_doc + } + } +} + +//used in noop_fold_foreign_item and noop_fold_fn_decl +fn fold_arg_(a: &arg, fld: &T) -> arg { + ast::arg { + is_mutbl: a.is_mutbl, + ty: fld.fold_ty(&a.ty), + pat: fld.fold_pat(a.pat), + id: fld.new_id(a.id), + } +} + +// build a new vector of tts by appling the ast_fold's fold_ident to +// all of the identifiers in the token trees. +pub fn fold_tts(tts: &[token_tree], fld: &T) -> ~[token_tree] { do tts.map |tt| { match *tt { tt_tok(span, ref tok) => tt_tok(span,maybe_fold_ident(tok,fld)), - tt_delim(ref tts) => - tt_delim(@mut fold_tts(**tts, fld)), + tt_delim(ref tts) => tt_delim(@mut fold_tts(**tts, fld)), tt_seq(span, ref pattern, ref sep, is_optional) => tt_seq(span, @mut fold_tts(**pattern, fld), @@ -247,33 +454,68 @@ pub fn fold_tts(tts : &[token_tree], fld: @ast_fold) -> ~[token_tree] { } // apply ident folder if it's an ident, otherwise leave it alone -fn maybe_fold_ident(t : &token::Token, f: @ast_fold) -> token::Token { +fn maybe_fold_ident(t: &token::Token, fld: &T) -> token::Token { match *t { - token::IDENT(id,followed_by_colons) => - token::IDENT(f.fold_ident(id),followed_by_colons), + token::IDENT(id, followed_by_colons) => { + token::IDENT(fld.fold_ident(id), followed_by_colons) + } _ => (*t).clone() } } -pub fn fold_fn_decl(decl: &ast::fn_decl, fld: @ast_fold) -> ast::fn_decl { +pub fn fold_fn_decl(decl: &ast::fn_decl, fld: &T) + -> ast::fn_decl { ast::fn_decl { - inputs: decl.inputs.map(|x| fld.fold_arg(x)), + inputs: decl.inputs.map(|x| fold_arg_(x, fld)), // bad copy output: fld.fold_ty(&decl.output), cf: decl.cf, } } -pub fn fold_generics(generics: &Generics, fld: @ast_fold) -> Generics { - Generics {ty_params: fld.fold_ty_params(&generics.ty_params), - lifetimes: fld.fold_lifetimes(&generics.lifetimes)} +fn fold_ty_param_bound(tpb: &TyParamBound, fld: &T) + -> TyParamBound { + match *tpb { + TraitTyParamBound(ref ty) => TraitTyParamBound(fold_trait_ref(ty, fld)), + RegionTyParamBound => RegionTyParamBound + } } -pub fn noop_fold_crate(c: &Crate, fld: @ast_fold) -> Crate { - Crate { - module: fld.fold_mod(&c.module), - attrs: fld.fold_attributes(c.attrs), - config: fld.fold_meta_items(c.config), - span: fld.new_span(c.span), +pub fn fold_ty_param(tp: &TyParam, fld: &T) -> TyParam { + TyParam { + ident: tp.ident, + id: fld.new_id(tp.id), + bounds: tp.bounds.map(|x| fold_ty_param_bound(x, fld)), + } +} + +pub fn fold_ty_params(tps: &OptVec, fld: &T) + -> OptVec { + tps.map(|tp| fold_ty_param(tp, fld)) +} + +pub fn fold_lifetime(l: &Lifetime, fld: &T) -> Lifetime { + Lifetime { + id: fld.new_id(l.id), + span: fld.new_span(l.span), + ident: l.ident + } +} + +pub fn fold_lifetimes(lts: &OptVec, fld: &T) + -> OptVec { + lts.map(|l| fold_lifetime(l, fld)) +} + +pub fn fold_generics(generics: &Generics, fld: &T) -> Generics { + Generics {ty_params: fold_ty_params(&generics.ty_params, fld), + lifetimes: fold_lifetimes(&generics.lifetimes, fld)} +} + +fn fold_struct_def(struct_def: @ast::struct_def, fld: &T) + -> @ast::struct_def { + @ast::struct_def { + fields: struct_def.fields.map(|f| fold_struct_field(*f, fld)), + ctor_id: struct_def.ctor_id.map(|cid| fld.new_id(*cid)), } } @@ -291,172 +533,70 @@ fn noop_fold_view_item(vi: &view_item_, fld: @ast_fold) -> view_item_ { } } -fn noop_fold_foreign_item(ni: @foreign_item, fld: @ast_fold) - -> @foreign_item { - @ast::foreign_item { - ident: fld.fold_ident(ni.ident), - attrs: fld.fold_attributes(ni.attrs), - node: - match ni.node { - foreign_item_fn(ref fdec, ref generics) => { - foreign_item_fn( - ast::fn_decl { - inputs: fdec.inputs.map(|a| fld.fold_arg(a)), - output: fld.fold_ty(&fdec.output), - cf: fdec.cf, - }, - fold_generics(generics, fld)) - } - foreign_item_static(ref t, m) => { - foreign_item_static(fld.fold_ty(t), m) - } - }, - id: fld.new_id(ni.id), - span: fld.new_span(ni.span), - vis: ni.vis, +fn fold_trait_ref(p: &trait_ref, fld: &T) -> trait_ref { + ast::trait_ref { + path: fld.fold_path(&p.path), + ref_id: fld.new_id(p.ref_id), } } -pub fn noop_fold_item(i: @item, fld: @ast_fold) -> Option<@item> { - Some(@ast::item { ident: fld.fold_ident(i.ident), - attrs: fld.fold_attributes(i.attrs), - id: fld.new_id(i.id), - node: fld.fold_item_underscore(&i.node), - vis: i.vis, - span: fld.new_span(i.span) }) -} - -fn noop_fold_struct_field(sf: @struct_field, fld: @ast_fold) - -> @struct_field { - @Spanned { - node: ast::struct_field_ { - kind: sf.node.kind, - id: fld.new_id(sf.node.id), - ty: fld.fold_ty(&sf.node.ty), - attrs: fld.fold_attributes(sf.node.attrs), - }, - span: sf.span - } -} - -pub fn noop_fold_type_method(m: &TypeMethod, fld: @ast_fold) -> TypeMethod { - TypeMethod { - ident: fld.fold_ident(m.ident), - attrs: fld.fold_attributes(m.attrs), - purity: m.purity, - decl: fold_fn_decl(&m.decl, fld), - generics: fold_generics(&m.generics, fld), - explicit_self: m.explicit_self, - id: fld.new_id(m.id), - span: fld.new_span(m.span), - } -} - -pub fn noop_fold_item_underscore(i: &item_, fld: @ast_fold) -> item_ { - match *i { - item_static(ref t, m, e) => { - item_static(fld.fold_ty(t), m, fld.fold_expr(e)) - } - item_fn(ref decl, purity, abi, ref generics, ref body) => { - item_fn( - fold_fn_decl(decl, fld), - purity, - abi, - fold_generics(generics, fld), - fld.fold_block(body) - ) - } - item_mod(ref m) => { - item_mod(fld.fold_mod(m)) - } - item_foreign_mod(ref nm) => { - item_foreign_mod(fld.fold_foreign_mod(nm)) - } - item_ty(ref t, ref generics) => { - item_ty(fld.fold_ty(t), fold_generics(generics, fld)) - } - item_enum(ref enum_definition, ref generics) => { - item_enum( - ast::enum_def { - variants: do enum_definition.variants.map |x| { - fld.fold_variant(x) - }, - }, - fold_generics(generics, fld)) - } - item_struct(ref struct_def, ref generics) => { - let struct_def = fold_struct_def(*struct_def, fld); - item_struct(struct_def, fold_generics(generics, fld)) - } - item_impl(ref generics, ref ifce, ref ty, ref methods) => { - item_impl( - fold_generics(generics, fld), - ifce.map(|p| fld.fold_trait_ref(p)), - fld.fold_ty(ty), - methods.map(|x| fld.fold_method(*x)) - ) - } - item_trait(ref generics, ref traits, ref methods) => { - let methods = do methods.map |method| { - match *method { - required(ref m) => required(fld.fold_type_method(m)), - provided(method) => provided(fld.fold_method(method)) - } - }; - item_trait( - fold_generics(generics, fld), - traits.map(|p| fld.fold_trait_ref(p)), - methods - ) - } - item_mac(ref m) => { - item_mac(fld.fold_mac(m)) - } - } -} - -fn fold_struct_def(struct_def: @ast::struct_def, fld: @ast_fold) - -> @ast::struct_def { - @ast::struct_def { - fields: struct_def.fields.map(|f| fold_struct_field(*f, fld)), - ctor_id: struct_def.ctor_id.map(|cid| fld.new_id(*cid)), - } -} - -fn fold_struct_field(f: @struct_field, fld: @ast_fold) -> @struct_field { +fn fold_struct_field(f: @struct_field, fld: &T) -> @struct_field { @Spanned { node: ast::struct_field_ { kind: f.node.kind, id: fld.new_id(f.node.id), ty: fld.fold_ty(&f.node.ty), - attrs: fld.fold_attributes(f.node.attrs), + attrs: f.node.attrs.map(|a| fold_attribute_(*a, fld)), }, span: fld.new_span(f.span), } } -fn noop_fold_method(m: @method, fld: @ast_fold) -> @method { - @ast::method { - ident: fld.fold_ident(m.ident), - attrs: fld.fold_attributes(m.attrs), - generics: fold_generics(&m.generics, fld), - explicit_self: m.explicit_self, - purity: m.purity, - decl: fold_fn_decl(&m.decl, fld), - body: fld.fold_block(&m.body), - id: fld.new_id(m.id), - span: fld.new_span(m.span), - self_id: fld.new_id(m.self_id), - vis: m.vis, +fn fold_field_(field: Field, folder: &T) -> Field { + ast::Field { + ident: folder.fold_ident(field.ident), + expr: folder.fold_expr(field.expr), + span: folder.new_span(field.span), } } +fn fold_mt(mt: &mt, folder: &T) -> mt { + mt { + ty: ~folder.fold_ty(mt.ty), + mutbl: mt.mutbl, + } +} -pub fn noop_fold_block(b: &Block, fld: @ast_fold) -> Block { - let view_items = b.view_items.map(|x| fld.fold_view_item(x)); +fn fold_field(f: TypeField, folder: &T) -> TypeField { + ast::TypeField { + ident: folder.fold_ident(f.ident), + mt: fold_mt(&f.mt, folder), + span: folder.new_span(f.span), + } +} + +fn fold_opt_bounds(b: &Option>, folder: &T) + -> Option> { + do b.map |bounds| { + do bounds.map |bound| { + fold_ty_param_bound(bound, folder) + } + } +} + +fn fold_variant_arg_(va: &variant_arg, folder: &T) + -> variant_arg { + ast::variant_arg { + ty: folder.fold_ty(&va.ty), + id: folder.new_id(va.id) + } +} + +pub fn noop_fold_block(b: &Block, folder: &T) -> Block { + let view_items = b.view_items.map(|x| folder.fold_view_item(x)); let mut stmts = ~[]; for stmt in b.stmts.iter() { - match fld.fold_stmt(*stmt) { + match folder.fold_stmt(*stmt) { None => {} Some(stmt) => stmts.push(stmt) } @@ -464,580 +604,262 @@ pub fn noop_fold_block(b: &Block, fld: @ast_fold) -> Block { ast::Block { view_items: view_items, stmts: stmts, - expr: b.expr.map(|x| fld.fold_expr(*x)), - id: fld.new_id(b.id), + expr: b.expr.map(|x| folder.fold_expr(*x)), + id: folder.new_id(b.id), rules: b.rules, - span: b.span, + span: folder.new_span(b.span), } } -fn noop_fold_stmt(s: &Stmt_, fld: @ast_fold) -> Option { - match *s { - StmtDecl(d, nid) => { - match fld.fold_decl(d) { - Some(d) => Some(StmtDecl(d, fld.new_id(nid))), - None => None, - } +pub fn noop_fold_item_underscore(i: &item_, folder: &T) -> item_ { + match *i { + item_static(ref t, m, e) => { + item_static(folder.fold_ty(t), m, folder.fold_expr(e)) } - StmtExpr(e, nid) => { - Some(StmtExpr(fld.fold_expr(e), fld.new_id(nid))) - } - StmtSemi(e, nid) => { - Some(StmtSemi(fld.fold_expr(e), fld.new_id(nid))) - } - StmtMac(ref mac, semi) => Some(StmtMac(fld.fold_mac(mac), semi)) - } -} - -fn noop_fold_arm(a: &Arm, fld: @ast_fold) -> Arm { - Arm { - pats: a.pats.map(|x| fld.fold_pat(*x)), - guard: a.guard.map_move(|x| fld.fold_expr(x)), - body: fld.fold_block(&a.body), - } -} - -pub fn noop_fold_pat(p: &Pat_, fld: @ast_fold) -> Pat_ { - match *p { - PatWild => PatWild, - PatIdent(binding_mode, ref pth, ref sub) => { - PatIdent( - binding_mode, - fld.fold_path(pth), - sub.map_move(|x| fld.fold_pat(x)) + item_fn(ref decl, purity, abi, ref generics, ref body) => { + item_fn( + fold_fn_decl(decl, folder), + purity, + abi, + fold_generics(generics, folder), + folder.fold_block(body) ) } - PatLit(e) => PatLit(fld.fold_expr(e)), - PatEnum(ref pth, ref pats) => { - PatEnum( - fld.fold_path(pth), - pats.map(|pats| pats.map(|x| fld.fold_pat(*x))) + item_mod(ref m) => item_mod(folder.fold_mod(m)), + item_foreign_mod(ref nm) => { + item_foreign_mod(folder.fold_foreign_mod(nm)) + } + item_ty(ref t, ref generics) => { + item_ty(folder.fold_ty(t), + fold_generics(generics, folder)) + } + item_enum(ref enum_definition, ref generics) => { + item_enum( + ast::enum_def { + variants: do enum_definition.variants.map |x| { + folder.fold_variant(x) + }, + }, + fold_generics(generics, folder)) + } + item_struct(ref struct_def, ref generics) => { + let struct_def = fold_struct_def(*struct_def, folder); + item_struct(struct_def, fold_generics(generics, folder)) + } + item_impl(ref generics, ref ifce, ref ty, ref methods) => { + item_impl(fold_generics(generics, folder), + ifce.map(|p| fold_trait_ref(p, folder)), + folder.fold_ty(ty), + methods.map(|x| folder.fold_method(*x)) ) } - PatStruct(ref pth, ref fields, etc) => { - let pth_ = fld.fold_path(pth); - let fs = do fields.map |f| { - ast::FieldPat { - ident: f.ident, - pat: fld.fold_pat(f.pat) + item_trait(ref generics, ref traits, ref methods) => { + let methods = do methods.map |method| { + match *method { + required(ref m) => required(folder.fold_type_method(m)), + provided(method) => provided(folder.fold_method(method)) } }; - PatStruct(pth_, fs, etc) - } - PatTup(ref elts) => PatTup(elts.map(|x| fld.fold_pat(*x))), - PatBox(inner) => PatBox(fld.fold_pat(inner)), - PatUniq(inner) => PatUniq(fld.fold_pat(inner)), - PatRegion(inner) => PatRegion(fld.fold_pat(inner)), - PatRange(e1, e2) => { - PatRange(fld.fold_expr(e1), fld.fold_expr(e2)) - }, - PatVec(ref before, ref slice, ref after) => { - PatVec( - before.map(|x| fld.fold_pat(*x)), - slice.map_move(|x| fld.fold_pat(x)), - after.map(|x| fld.fold_pat(*x)) - ) + item_trait(fold_generics(generics, folder), + traits.map(|p| fold_trait_ref(p, folder)), + methods) } + item_mac(ref m) => item_mac(folder.fold_mac(m)), } } -fn noop_fold_decl(d: &Decl_, fld: @ast_fold) -> Option { - match *d { - DeclLocal(ref l) => Some(DeclLocal(fld.fold_local(*l))), - DeclItem(it) => { - match fld.fold_item(it) { - Some(it_folded) => Some(DeclItem(it_folded)), - None => None, - } - } +pub fn noop_fold_type_method(m: &TypeMethod, fld: &T) + -> TypeMethod { + TypeMethod { + ident: fld.fold_ident(m.ident), + attrs: m.attrs.map(|a| fold_attribute_(*a, fld)), + purity: m.purity, + decl: fold_fn_decl(&m.decl, fld), + generics: fold_generics(&m.generics, fld), + explicit_self: m.explicit_self, + id: fld.new_id(m.id), + span: fld.new_span(m.span), } } -// lift a function in ast-thingy X fold -> ast-thingy to a function -// in (ast-thingy X span X fold) -> (ast-thingy X span). Basically, -// carries the span around. -// It seems strange to me that the call to new_fold doesn't happen -// here but instead in the impl down below.... probably just an -// accident? -pub fn wrap(f: @fn(&T, @ast_fold) -> T) - -> @fn(&T, Span, @ast_fold) -> (T, Span) { - let result: @fn(&T, Span, @ast_fold) -> (T, Span) = |x, s, fld| { - (f(x, fld), s) - }; - result +pub fn noop_fold_mod(m: &_mod, folder: &T) -> _mod { + ast::_mod { + view_items: m.view_items + .iter() + .map(|x| folder.fold_view_item(x)).collect(), + items: m.items.iter().filter_map(|x| folder.fold_item(*x)).collect(), + } } -pub fn noop_fold_expr(e: &Expr_, fld: @ast_fold) -> Expr_ { - fn fold_field_(field: Field, fld: @ast_fold) -> Field { - ast::Field { - ident: fld.fold_ident(field.ident), - expr: fld.fold_expr(field.expr), - span: fld.new_span(field.span), - } - } - let fold_field = |x| fold_field_(x, fld); +pub fn noop_fold_crate(c: &Crate, folder: &T) -> Crate { + let fold_meta_item = |x| fold_meta_item_(x, folder); + let fold_attribute = |x| fold_attribute_(x, folder); - match *e { + Crate { + module: folder.fold_mod(&c.module), + attrs: c.attrs.map(|x| fold_attribute(*x)), + config: c.config.map(|x| fold_meta_item(*x)), + span: folder.new_span(c.span), + } +} + +pub fn noop_fold_item(i: @ast::item, folder: &T) + -> Option<@ast::item> { + let fold_attribute = |x| fold_attribute_(x, folder); + + Some(@ast::item { + ident: folder.fold_ident(i.ident), + attrs: i.attrs.map(|e| fold_attribute(*e)), + id: folder.new_id(i.id), + node: folder.fold_item_underscore(&i.node), + vis: i.vis, + span: folder.new_span(i.span) + }) +} + +pub fn noop_fold_expr(e: @ast::Expr, folder: &T) -> @ast::Expr { + let fold_field = |x| fold_field_(x, folder); + + let node = match e.node { ExprVstore(e, v) => { - ExprVstore(fld.fold_expr(e), v) + ExprVstore(folder.fold_expr(e), v) } ExprVec(ref exprs, mutt) => { - ExprVec(fld.map_exprs(|x| fld.fold_expr(x), *exprs), mutt) + ExprVec(folder.map_exprs(|x| folder.fold_expr(x), *exprs), mutt) } ExprRepeat(expr, count, mutt) => { - ExprRepeat(fld.fold_expr(expr), fld.fold_expr(count), mutt) + ExprRepeat(folder.fold_expr(expr), folder.fold_expr(count), mutt) } - ExprTup(ref elts) => ExprTup(elts.map(|x| fld.fold_expr(*x))), + ExprTup(ref elts) => ExprTup(elts.map(|x| folder.fold_expr(*x))), ExprCall(f, ref args, blk) => { - ExprCall( - fld.fold_expr(f), - fld.map_exprs(|x| fld.fold_expr(x), *args), - blk - ) + ExprCall(folder.fold_expr(f), + folder.map_exprs(|x| folder.fold_expr(x), *args), + blk) } ExprMethodCall(callee_id, f, i, ref tps, ref args, blk) => { ExprMethodCall( - fld.new_id(callee_id), - fld.fold_expr(f), - fld.fold_ident(i), - tps.map(|x| fld.fold_ty(x)), - fld.map_exprs(|x| fld.fold_expr(x), *args), + folder.new_id(callee_id), + folder.fold_expr(f), + folder.fold_ident(i), + tps.map(|x| folder.fold_ty(x)), + folder.map_exprs(|x| folder.fold_expr(x), *args), blk ) } ExprBinary(callee_id, binop, lhs, rhs) => { - ExprBinary( - fld.new_id(callee_id), - binop, - fld.fold_expr(lhs), - fld.fold_expr(rhs) - ) + ExprBinary(folder.new_id(callee_id), + binop, + folder.fold_expr(lhs), + folder.fold_expr(rhs)) } ExprUnary(callee_id, binop, ohs) => { - ExprUnary( - fld.new_id(callee_id), - binop, - fld.fold_expr(ohs) - ) + ExprUnary(folder.new_id(callee_id), binop, folder.fold_expr(ohs)) } - ExprDoBody(f) => ExprDoBody(fld.fold_expr(f)), - ExprLit(_) => (*e).clone(), + ExprDoBody(f) => ExprDoBody(folder.fold_expr(f)), + ExprLit(_) => e.node.clone(), ExprCast(expr, ref ty) => { - ExprCast(fld.fold_expr(expr), fld.fold_ty(ty)) + ExprCast(folder.fold_expr(expr), folder.fold_ty(ty)) } - ExprAddrOf(m, ohs) => ExprAddrOf(m, fld.fold_expr(ohs)), + ExprAddrOf(m, ohs) => ExprAddrOf(m, folder.fold_expr(ohs)), ExprIf(cond, ref tr, fl) => { - ExprIf( - fld.fold_expr(cond), - fld.fold_block(tr), - fl.map_move(|x| fld.fold_expr(x)) - ) + ExprIf(folder.fold_expr(cond), + folder.fold_block(tr), + fl.map_move(|x| folder.fold_expr(x))) } ExprWhile(cond, ref body) => { - ExprWhile(fld.fold_expr(cond), fld.fold_block(body)) + ExprWhile(folder.fold_expr(cond), folder.fold_block(body)) } - ExprForLoop(pat, iter, ref body, opt_ident) => { - ExprForLoop(fld.fold_pat(pat), - fld.fold_expr(iter), - fld.fold_block(body), - opt_ident.map_move(|x| fld.fold_ident(x))) + ExprForLoop(pat, iter, ref body, ref maybe_ident) => { + ExprForLoop(folder.fold_pat(pat), + folder.fold_expr(iter), + folder.fold_block(body), + maybe_ident.map_move(|i| folder.fold_ident(i))) } ExprLoop(ref body, opt_ident) => { - ExprLoop( - fld.fold_block(body), - opt_ident.map_move(|x| fld.fold_ident(x)) - ) + ExprLoop(folder.fold_block(body), + opt_ident.map_move(|x| folder.fold_ident(x))) } ExprMatch(expr, ref arms) => { - ExprMatch( - fld.fold_expr(expr), - arms.map(|x| fld.fold_arm(x)) - ) + ExprMatch(folder.fold_expr(expr), + arms.map(|x| folder.fold_arm(x))) } ExprFnBlock(ref decl, ref body) => { ExprFnBlock( - fold_fn_decl(decl, fld), - fld.fold_block(body) + fold_fn_decl(decl, folder), + folder.fold_block(body) ) } - ExprBlock(ref blk) => ExprBlock(fld.fold_block(blk)), + ExprBlock(ref blk) => ExprBlock(folder.fold_block(blk)), ExprAssign(el, er) => { - ExprAssign(fld.fold_expr(el), fld.fold_expr(er)) + ExprAssign(folder.fold_expr(el), folder.fold_expr(er)) } ExprAssignOp(callee_id, op, el, er) => { - ExprAssignOp( - fld.new_id(callee_id), - op, - fld.fold_expr(el), - fld.fold_expr(er) - ) + ExprAssignOp(folder.new_id(callee_id), + op, + folder.fold_expr(el), + folder.fold_expr(er)) } ExprField(el, id, ref tys) => { - ExprField( - fld.fold_expr(el), fld.fold_ident(id), - tys.map(|x| fld.fold_ty(x)) - ) + ExprField(folder.fold_expr(el), folder.fold_ident(id), + tys.map(|x| folder.fold_ty(x))) } ExprIndex(callee_id, el, er) => { - ExprIndex( - fld.new_id(callee_id), - fld.fold_expr(el), - fld.fold_expr(er) - ) + ExprIndex(folder.new_id(callee_id), + folder.fold_expr(el), + folder.fold_expr(er)) } - ExprPath(ref pth) => ExprPath(fld.fold_path(pth)), + ExprPath(ref pth) => ExprPath(folder.fold_path(pth)), ExprSelf => ExprSelf, - ExprBreak(ref opt_ident) => { - // FIXME #6993: add fold_name to fold.... then cut out the - // bogus Name->Ident->Name conversion. - ExprBreak(opt_ident.map_move(|x| { - // FIXME #9129: Assigning the new ident to a temporary to work around codegen bug - let newx = Ident::new(x); - fld.fold_ident(newx).name - })) - } - ExprAgain(ref opt_ident) => { - // FIXME #6993: add fold_name to fold.... - ExprAgain(opt_ident.map_move(|x| { - // FIXME #9129: Assigning the new ident to a temporary to work around codegen bug - let newx = Ident::new(x); - fld.fold_ident(newx).name - })) - } - ExprRet(ref e) => { - ExprRet(e.map_move(|x| fld.fold_expr(x))) - } ExprLogLevel => ExprLogLevel, + ExprBreak(opt_ident) => ExprBreak(opt_ident), + ExprAgain(opt_ident) => ExprAgain(opt_ident), + ExprRet(ref e) => { + ExprRet(e.map_move(|x| folder.fold_expr(x))) + } ExprInlineAsm(ref a) => { ExprInlineAsm(inline_asm { - inputs: a.inputs.map(|&(c, input)| (c, fld.fold_expr(input))), - outputs: a.outputs.map(|&(c, out)| (c, fld.fold_expr(out))), + inputs: a.inputs.map(|&(c, input)| (c, folder.fold_expr(input))), + outputs: a.outputs.map(|&(c, out)| (c, folder.fold_expr(out))), .. (*a).clone() }) } - ExprMac(ref mac) => ExprMac(fld.fold_mac(mac)), + ExprMac(ref mac) => ExprMac(folder.fold_mac(mac)), ExprStruct(ref path, ref fields, maybe_expr) => { - ExprStruct( - fld.fold_path(path), - fields.map(|x| fold_field(*x)), - maybe_expr.map_move(|x| fld.fold_expr(x)) - ) + ExprStruct(folder.fold_path(path), + fields.map(|x| fold_field(*x)), + maybe_expr.map_move(|x| folder.fold_expr(x))) }, - ExprParen(ex) => ExprParen(fld.fold_expr(ex)) - } -} - -pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ { - fn fold_mt(mt: &mt, fld: @ast_fold) -> mt { - mt { - ty: ~fld.fold_ty(mt.ty), - mutbl: mt.mutbl, - } - } - fn fold_field(f: TypeField, fld: @ast_fold) -> TypeField { - ast::TypeField { - ident: fld.fold_ident(f.ident), - mt: fold_mt(&f.mt, fld), - span: fld.new_span(f.span), - } - } - fn fold_opt_bounds(b: &Option>, fld: @ast_fold) - -> Option> { - do b.map |bounds| { - do bounds.map |bound| { fld.fold_ty_param_bound(bound) } - } - } - match *t { - ty_nil | ty_bot | ty_infer => (*t).clone(), - ty_box(ref mt) => ty_box(fold_mt(mt, fld)), - ty_uniq(ref mt) => ty_uniq(fold_mt(mt, fld)), - ty_vec(ref mt) => ty_vec(fold_mt(mt, fld)), - ty_ptr(ref mt) => ty_ptr(fold_mt(mt, fld)), - ty_rptr(region, ref mt) => ty_rptr(region, fold_mt(mt, fld)), - ty_closure(ref f) => { - ty_closure(@TyClosure { - sigil: f.sigil, - purity: f.purity, - region: f.region, - onceness: f.onceness, - bounds: fold_opt_bounds(&f.bounds, fld), - decl: fold_fn_decl(&f.decl, fld), - lifetimes: fld.fold_lifetimes(&f.lifetimes) - }) - } - ty_bare_fn(ref f) => { - ty_bare_fn(@TyBareFn { - lifetimes: fld.fold_lifetimes(&f.lifetimes), - purity: f.purity, - abis: f.abis, - decl: fold_fn_decl(&f.decl, fld) - }) - } - ty_tup(ref tys) => ty_tup(tys.map(|ty| fld.fold_ty(ty))), - ty_path(ref path, ref bounds, id) => - ty_path(fld.fold_path(path), fold_opt_bounds(bounds, fld), fld.new_id(id)), - ty_fixed_length_vec(ref mt, e) => { - ty_fixed_length_vec( - fold_mt(mt, fld), - fld.fold_expr(e) - ) - } - ty_typeof(e) => ty_typeof(fld.fold_expr(e)), - ty_mac(ref mac) => ty_mac(fld.fold_mac(mac)) - } -} - -// ...nor do modules -pub fn noop_fold_mod(m: &_mod, fld: @ast_fold) -> _mod { - ast::_mod { - view_items: m.view_items.iter().map(|x| fld.fold_view_item(x)).collect(), - items: m.items.iter().filter_map(|x| fld.fold_item(*x)).collect(), - } -} - -fn noop_fold_foreign_mod(nm: &foreign_mod, fld: @ast_fold) -> foreign_mod { - ast::foreign_mod { - sort: nm.sort, - abis: nm.abis, - view_items: nm.view_items.iter().map(|x| fld.fold_view_item(x)).collect(), - items: nm.items.iter().map(|x| fld.fold_foreign_item(*x)).collect(), - } -} - -fn noop_fold_variant(v: &variant_, fld: @ast_fold) -> variant_ { - let kind = match v.kind { - tuple_variant_kind(ref variant_args) => { - tuple_variant_kind(variant_args.map(|x| fld.fold_variant_arg(x))) - } - struct_variant_kind(ref struct_def) => { - struct_variant_kind(@ast::struct_def { - fields: struct_def.fields.iter() - .map(|f| fld.fold_struct_field(*f)).collect(), - ctor_id: struct_def.ctor_id.map(|c| fld.new_id(*c)) - }) - } + ExprParen(ex) => ExprParen(folder.fold_expr(ex)) }; - let attrs = fld.fold_attributes(v.attrs); + @Expr { + id: folder.new_id(e.id), + node: node, + span: folder.new_span(e.span), + } +} - let de = match v.disr_expr { - Some(e) => Some(fld.fold_expr(e)), - None => None +pub fn noop_fold_stmt(s: &Stmt, folder: &T) -> Option<@Stmt> { + let node = match s.node { + StmtDecl(d, nid) => { + match folder.fold_decl(d) { + Some(d) => Some(StmtDecl(d, folder.new_id(nid))), + None => None, + } + } + StmtExpr(e, nid) => { + Some(StmtExpr(folder.fold_expr(e), folder.new_id(nid))) + } + StmtSemi(e, nid) => { + Some(StmtSemi(folder.fold_expr(e), folder.new_id(nid))) + } + StmtMac(ref mac, semi) => Some(StmtMac(folder.fold_mac(mac), semi)) }; - ast::variant_ { - name: v.name, - attrs: attrs, - kind: kind, - id: fld.new_id(v.id), - disr_expr: de, - vis: v.vis, - } -} -fn noop_fold_ident(i: Ident, _fld: @ast_fold) -> Ident { - i -} - -fn noop_fold_path(p: &Path, fld: @ast_fold) -> Path { - ast::Path { - span: fld.new_span(p.span), - global: p.global, - segments: p.segments.map(|segment| ast::PathSegment { - identifier: fld.fold_ident(segment.identifier), - lifetime: segment.lifetime, - types: segment.types.map(|typ| fld.fold_ty(typ)), - }) - } -} - -fn noop_fold_local(l: @Local, fld: @ast_fold) -> @Local { - @Local { - is_mutbl: l.is_mutbl, - ty: fld.fold_ty(&l.ty), - pat: fld.fold_pat(l.pat), - init: l.init.map_move(|e| fld.fold_expr(e)), - id: fld.new_id(l.id), - span: fld.new_span(l.span), - } -} - -// the default macro traversal. visit the path -// using fold_path, and the tts using fold_tts, -// and the span using new_span -fn noop_fold_mac(m: &mac_, fld: @ast_fold) -> mac_ { - match *m { - mac_invoc_tt(ref p,ref tts,ctxt) => - mac_invoc_tt(fld.fold_path(p), - fold_tts(*tts,fld), - ctxt) - } -} - - -/* temporarily eta-expand because of a compiler bug with using `fn` as a - value */ -fn noop_map_exprs(f: @fn(@Expr) -> @Expr, es: &[@Expr]) -> ~[@Expr] { - es.map(|x| f(*x)) -} - -fn noop_id(i: NodeId) -> NodeId { return i; } - -fn noop_span(sp: Span) -> Span { return sp; } - -pub fn default_ast_fold() -> ast_fold_fns { - @AstFoldFns { - fold_crate: noop_fold_crate, - fold_view_item: noop_fold_view_item, - fold_foreign_item: noop_fold_foreign_item, - fold_item: noop_fold_item, - fold_struct_field: noop_fold_struct_field, - fold_item_underscore: noop_fold_item_underscore, - fold_type_method: noop_fold_type_method, - fold_method: noop_fold_method, - fold_block: noop_fold_block, - fold_stmt: |x, s, fld| (noop_fold_stmt(x, fld), s), - fold_arm: noop_fold_arm, - fold_pat: wrap(noop_fold_pat), - fold_decl: |x, s, fld| (noop_fold_decl(x, fld), s), - fold_expr: wrap(noop_fold_expr), - fold_ty: wrap(noop_fold_ty), - fold_mod: noop_fold_mod, - fold_foreign_mod: noop_fold_foreign_mod, - fold_variant: wrap(noop_fold_variant), - fold_ident: noop_fold_ident, - fold_path: noop_fold_path, - fold_local: noop_fold_local, - fold_mac: wrap(noop_fold_mac), - map_exprs: noop_map_exprs, - new_id: noop_id, - new_span: noop_span, - } -} - -impl ast_fold for AstFoldFns { - /* naturally, a macro to write these would be nice */ - fn fold_crate(@self, c: &Crate) -> Crate { - (self.fold_crate)(c, self as @ast_fold) - } - fn fold_view_item(@self, x: &view_item) -> view_item { - ast::view_item { - node: (self.fold_view_item)(&x.node, self as @ast_fold), - attrs: self.fold_attributes(x.attrs), - vis: x.vis, - span: (self.new_span)(x.span), - } - } - fn fold_foreign_item(@self, x: @foreign_item) -> @foreign_item { - (self.fold_foreign_item)(x, self as @ast_fold) - } - fn fold_item(@self, i: @item) -> Option<@item> { - (self.fold_item)(i, self as @ast_fold) - } - fn fold_struct_field(@self, sf: @struct_field) -> @struct_field { - @Spanned { - node: ast::struct_field_ { - kind: sf.node.kind, - id: (self.new_id)(sf.node.id), - ty: self.fold_ty(&sf.node.ty), - attrs: self.fold_attributes(sf.node.attrs), - }, - span: (self.new_span)(sf.span), - } - } - fn fold_item_underscore(@self, i: &item_) -> item_ { - (self.fold_item_underscore)(i, self as @ast_fold) - } - fn fold_type_method(@self, m: &TypeMethod) -> TypeMethod { - (self.fold_type_method)(m, self as @ast_fold) - } - fn fold_method(@self, x: @method) -> @method { - (self.fold_method)(x, self as @ast_fold) - } - fn fold_block(@self, x: &Block) -> Block { - (self.fold_block)(x, self as @ast_fold) - } - fn fold_stmt(@self, x: &Stmt) -> Option<@Stmt> { - let (n_opt, s) = (self.fold_stmt)(&x.node, x.span, self as @ast_fold); - match n_opt { - Some(n) => Some(@Spanned { node: n, span: (self.new_span)(s) }), - None => None, - } - } - fn fold_arm(@self, x: &Arm) -> Arm { - (self.fold_arm)(x, self as @ast_fold) - } - fn fold_pat(@self, x: @Pat) -> @Pat { - let (n, s) = (self.fold_pat)(&x.node, x.span, self as @ast_fold); - @Pat { - id: (self.new_id)(x.id), - node: n, - span: (self.new_span)(s), - } - } - fn fold_decl(@self, x: @Decl) -> Option<@Decl> { - let (n_opt, s) = (self.fold_decl)(&x.node, x.span, self as @ast_fold); - match n_opt { - Some(n) => Some(@Spanned { node: n, span: (self.new_span)(s) }), - None => None, - } - } - fn fold_expr(@self, x: @Expr) -> @Expr { - let (n, s) = (self.fold_expr)(&x.node, x.span, self as @ast_fold); - @Expr { - id: (self.new_id)(x.id), - node: n, - span: (self.new_span)(s), - } - } - fn fold_ty(@self, x: &Ty) -> Ty { - let (n, s) = (self.fold_ty)(&x.node, x.span, self as @ast_fold); - Ty { - id: (self.new_id)(x.id), - node: n, - span: (self.new_span)(s), - } - } - fn fold_mod(@self, x: &_mod) -> _mod { - (self.fold_mod)(x, self as @ast_fold) - } - fn fold_foreign_mod(@self, x: &foreign_mod) -> foreign_mod { - (self.fold_foreign_mod)(x, self as @ast_fold) - } - fn fold_variant(@self, x: &variant) -> variant { - let (n, s) = (self.fold_variant)(&x.node, x.span, self as @ast_fold); - Spanned { node: n, span: (self.new_span)(s) } - } - fn fold_ident(@self, x: Ident) -> Ident { - (self.fold_ident)(x, self as @ast_fold) - } - fn fold_path(@self, x: &Path) -> Path { - (self.fold_path)(x, self as @ast_fold) - } - fn fold_local(@self, x: @Local) -> @Local { - (self.fold_local)(x, self as @ast_fold) - } - fn fold_mac(@self, x: &mac) -> mac { - let (n, s) = (self.fold_mac)(&x.node, x.span, self as @ast_fold); - Spanned { node: n, span: (self.new_span)(s) } - } - fn map_exprs(@self, - f: @fn(@Expr) -> @Expr, - e: &[@Expr]) - -> ~[@Expr] { - (self.map_exprs)(f, e) - } - fn new_id(@self, node_id: ast::NodeId) -> NodeId { - (self.new_id)(node_id) - } - fn new_span(@self, span: Span) -> Span { - (self.new_span)(span) - } -} - -// brson agrees with me that this function's existence is probably -// not a good or useful thing. -pub fn make_fold(afp: ast_fold_fns) -> @ast_fold { - afp as @ast_fold + node.map_move(|node| @Spanned { + node: node, + span: folder.new_span(s.span), + }) } #[cfg(test)] @@ -1048,16 +870,23 @@ mod test { use print::pprust; use super::*; + struct IdentFolder { + f: @fn(ast::ident)->ast::ident, + } + + impl ast_fold for IdentFolder { + fn fold_ident(@self, i: ident) -> ident { + (self.f)(i) + } + } + // taken from expand // given a function from idents to idents, produce // an ast_fold that applies that function: - pub fn fun_to_ident_folder(f: @fn(ast::Ident)->ast::Ident) -> @ast_fold{ - let afp = default_ast_fold(); - let f_pre = @AstFoldFns{ - fold_ident : |id, _| f(id), - .. *afp - }; - make_fold(f_pre) + pub fn fun_to_ident_folder(f: @fn(ast::ident)->ast::ident) -> @ast_fold { + @IdentFolder { + f: f, + } as @ast_fold } // this version doesn't care about getting comments or docstrings in. @@ -1120,3 +949,4 @@ mod test { ~"fn zz(){let zz=13 as zz;}"); } } + diff --git a/src/test/compile-fail/dead-code-ret.rs b/src/test/compile-fail/dead-code-ret.rs index 2e4ae7f8544..b6976b2c355 100644 --- a/src/test/compile-fail/dead-code-ret.rs +++ b/src/test/compile-fail/dead-code-ret.rs @@ -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 diff --git a/src/test/compile-fail/issue-897-2.rs b/src/test/compile-fail/issue-897-2.rs index eb60e34df8f..c39c258c701 100644 --- a/src/test/compile-fail/issue-897-2.rs +++ b/src/test/compile-fail/issue-897-2.rs @@ -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. From 33993535efb490ddb0e3afb6e08e4f945ec28a04 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 29 Aug 2013 15:04:09 -0700 Subject: [PATCH 02/16] librustc: Remove garbage collected functions from front/{config,test} and metadata/{tydecode,tyencode} --- src/librustc/front/config.rs | 120 +++++++++++++++--------------- src/librustc/front/test.rs | 2 - src/librustc/metadata/tydecode.rs | 3 +- src/librustc/metadata/tyencode.rs | 2 +- 4 files changed, 62 insertions(+), 65 deletions(-) diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs index fc1794fb935..efaebcca011 100644 --- a/src/librustc/front/config.rs +++ b/src/librustc/front/config.rs @@ -9,14 +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 @@ -27,56 +24,55 @@ pub fn strip_unconfigured_items(crate: @ast::Crate) -> @ast::Crate { } } -struct ItemRemover { - ctxt: @Context, -} - -impl fold::ast_fold for ItemRemover { +impl<'self> fold::ast_fold for Context<'self> { fn fold_mod(&self, module: &ast::_mod) -> ast::_mod { - fold_mod(self.ctxt, module, self) + fold_mod(self, module) } fn fold_block(&self, block: &ast::Block) -> ast::Block { - fold_block(self.ctxt, block, self) + fold_block(self, block) } fn fold_foreign_mod(&self, foreign_module: &ast::foreign_mod) -> ast::foreign_mod { - fold_foreign_mod(self.ctxt, foreign_module, self) + fold_foreign_mod(self, foreign_module) } fn fold_item_underscore(&self, item: &ast::item_) -> ast::item_ { - fold_item_underscore(self.ctxt, item, self) + fold_item_underscore(self, item) } } -pub fn strip_items(crate: &ast::Crate, in_cfg: in_cfg_pred) -> @ast::Crate { - let ctxt = @Context { +pub fn strip_items(crate: &ast::Crate, + in_cfg: &fn(attrs: &[ast::Attribute]) -> bool) + -> @ast::Crate { + let ctxt = Context { in_cfg: in_cfg, }; - let precursor = ItemRemover { - ctxt: ctxt, - }; - @precursor.fold_crate(crate) + @ctxt.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) +fn filter_item(cx: &Context, item: @ast::item) -> Option<@ast::item> { + if item_in_cfg(cx, item) { + Some(item) } else { - option::None + None } } -fn fold_mod(cx: @Context, m: &ast::_mod, fld: &ItemRemover) -> ast::_mod { - let filtered_items = do m.items.iter().filter_map |a| { - filter_item(cx, *a).and_then(|x| fld.fold_item(x)) +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 { @@ -85,22 +81,23 @@ fn fold_mod(cx: @Context, m: &ast::_mod, fld: &ItemRemover) -> 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: &ItemRemover) - -> ast::foreign_mod { +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 { @@ -111,8 +108,7 @@ fn fold_foreign_mod(cx: @Context, nm: &ast::foreign_mod, fld: &ItemRemover) } } -fn fold_item_underscore(cx: @Context, item: &ast::item_, fld: &ItemRemover) - -> 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)) @@ -120,67 +116,70 @@ fn fold_item_underscore(cx: @Context, item: &ast::item_, fld: &ItemRemover) 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: &ItemRemover) -> 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) @@ -192,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)) } + diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index d2baee6c961..18998015e95 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -27,8 +27,6 @@ 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], diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 6e4b6180fd2..b94a43e07a1 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -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); } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index e81da60ed17..417a6dae7be 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -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 From 15ce791ff5b5756b1455c65708782bc8028de56f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 29 Aug 2013 15:24:33 -0700 Subject: [PATCH 03/16] librustc: Port the pretty printer annotation infrastructure to use traits instead of garbage collected functions. --- src/librustc/driver/driver.rs | 115 +++++++++++++++++++++----------- src/librustc/middle/dataflow.rs | 79 +++++++++++----------- src/libsyntax/print/pprust.rs | 47 ++++++++----- 3 files changed, 143 insertions(+), 98 deletions(-) diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index bd0462119bd..a1d8f4c2639 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -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); } } diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 992d4ea2119..1af39f02d82 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -87,6 +87,42 @@ struct LoopScope<'self> { break_bits: ~[uint] } +impl pprust::pp_ann for DataFlowContext { + 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 DataFlowContext { pub fn new(tcx: ty::ctxt, method_map: typeck::method_map, @@ -319,46 +355,9 @@ impl DataFlowContext { } 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); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index b5868cbc63d..6cdd6d2517b 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -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 { From 16e87cb5279cd85ac11eb31de8a0087b08d831eb Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 29 Aug 2013 15:50:53 -0700 Subject: [PATCH 04/16] librustc: Make the fall-through case in match not use garbage collected functions --- src/librustc/middle/trans/_match.rs | 102 +++++++++++++++++++++------- 1 file changed, 76 insertions(+), 26 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index c9a113aeb96..464bcfee48e 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -533,7 +533,7 @@ fn enter_default<'r>(bcx: @mut Block, m: &[Match<'r>], col: uint, val: ValueRef, - chk: Option) + 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, +} + +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) + 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) { + 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, + 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::(|| 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 { - 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 ;` or `let = `. From 7796d519f95305fca9cec9d92d361e3df0dd999c Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 29 Aug 2013 17:46:33 -0700 Subject: [PATCH 05/16] librustc: Don't use garbage-collected closures to store cleanups. --- src/librustc/middle/trans/_match.rs | 2 +- src/librustc/middle/trans/base.rs | 2 +- src/librustc/middle/trans/common.rs | 141 +++++++++++++++++++++++----- 3 files changed, 121 insertions(+), 24 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 464bcfee48e..0de01bced1f 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -1191,7 +1191,7 @@ trait CustomFailureHandler { struct DynamicFailureHandler { bcx: @mut Block, - sp: span, + sp: Span, msg: @str, finished: @mut Option, } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 441cc1bfae2..67aee43bc46 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -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); } } } diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index b659a93f5f0..377144b38e7 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -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 { - 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); } } From 1676e77db279772551cf804bafbad5214096b9a9 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 29 Aug 2013 18:04:17 -0700 Subject: [PATCH 06/16] librustc: Remove garbage-collected functions from util/common. --- src/librustc/util/common.rs | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 46620319a82..8337354724a 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -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; } From 37c32e249505f103f9bcad0bdd83f49f0efec9ef Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 29 Aug 2013 18:34:09 -0700 Subject: [PATCH 07/16] librustc: Remove the remaining direct uses of `@fn` from librustc. --- src/librustc/driver/driver.rs | 24 ++++++------ src/librustc/rustc.rs | 42 +++++++++++++------- src/libsyntax/diagnostic.rs | 74 ++++++++++++++++++++--------------- src/libsyntax/parse/mod.rs | 2 +- 4 files changed, 84 insertions(+), 58 deletions(-) diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index a1d8f4c2639..ae1133e1880 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -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) @@ -589,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") @@ -638,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") { @@ -812,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)); @@ -824,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); @@ -1035,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!(); } diff --git a/src/librustc/rustc.rs b/src/librustc/rustc.rs index a90ab11535e..9fadaf82a98 100644 --- a/src/librustc/rustc.rs +++ b/src/librustc/rustc.rs @@ -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 +} + +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, @@ -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 diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 5e9714ca5b2..6f066218b7c 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -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) -> @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)] @@ -237,24 +243,30 @@ pub fn collect(messages: @mut ~[~str]) f } -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); - } +pub struct DefaultEmitter; + +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; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 9645dab4e8b..91ef55c78f6 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -45,7 +45,7 @@ pub struct ParseSess { included_mod_stack: ~[Path], } -pub fn new_parse_sess(demitter: Option) -> @mut ParseSess { +pub fn new_parse_sess(demitter: Option<@Emitter>) -> @mut ParseSess { let cm = @CodeMap::new(); @mut ParseSess { cm: cm, From 6ecbd75843a2187027d09649c9046189d1d4a446 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 29 Aug 2013 19:01:19 -0700 Subject: [PATCH 08/16] librustc: Change the ID visitor to use traits instead of garbage-collected functions. --- src/librustc/middle/astencode.rs | 47 ++++++++++++------- src/librustc/middle/lint.rs | 22 ++++++--- src/librustc/rustc.rs | 2 +- src/libsyntax/ast_util.rs | 77 +++++++++++++++++++------------- 4 files changed, 94 insertions(+), 54 deletions(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 6521b4bb3cc..683fbba09cc 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -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; @@ -849,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, @@ -856,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(); } diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index da181ff2eb6..c29a5159e81 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -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 } diff --git a/src/librustc/rustc.rs b/src/librustc/rustc.rs index 9fadaf82a98..f1f7a7bf2d6 100644 --- a/src/librustc/rustc.rs +++ b/src/librustc/rustc.rs @@ -299,7 +299,7 @@ struct RustcEmitter { impl diagnostic::Emitter for RustcEmitter { fn emit(&self, - cmsp: Option<(@codemap::CodeMap, codemap::span)>, + cmsp: Option<(@codemap::CodeMap, codemap::Span)>, msg: &str, lvl: diagnostic::level) { if lvl == diagnostic::fatal { diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 2e47050ad6a..ac88fc835d5 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -397,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, } @@ -416,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) } } } @@ -430,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) } } } @@ -460,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) } @@ -473,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) } } _ => {} @@ -489,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) } @@ -513,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) @@ -549,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, @@ -583,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 } From d126be068b0daab3b5abd9b1f365a4c98f2121b7 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 30 Aug 2013 10:55:24 -0700 Subject: [PATCH 09/16] librustpkg: Fix diagnostic invocation syntax in librustdoc, librusti, and librustpkg. --- src/librustdoc/core.rs | 13 +++++++---- src/librusti/rusti.rs | 48 +++++++++++++++++++++++++++------------ src/librustpkg/rustpkg.rs | 4 +++- src/librustpkg/util.rs | 9 ++++++-- 4 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 9fb5e8c04c1..8a7bb1f9346 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -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"))); diff --git a/src/librusti/rusti.rs b/src/librusti/rusti.rs index 368596b3f44..0d024812c21 100644 --- a/src/librusti/rusti.rs +++ b/src/librusti/rusti.rs @@ -76,8 +76,9 @@ 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 +108,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 +147,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 +257,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 +321,9 @@ fn compile_crate(src_filename: ~str, binary: ~str) -> Option { .. (*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( diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs index 077d1cf02f8..25d0802b9ad 100644 --- a/src/librustpkg/rustpkg.rs +++ b/src/librustpkg/rustpkg.rs @@ -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); diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 02524b65020..8c6268e7d23 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -232,7 +232,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; @@ -247,7 +250,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. From 6a8169db0a201b9fc2fbf581f507e143f0482aae Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 30 Aug 2013 12:21:45 -0700 Subject: [PATCH 10/16] libsyntax: Remove some more `@fn` uses --- src/librustpkg/util.rs | 91 +++++++++++++++++++++++++------------ src/libsyntax/diagnostic.rs | 7 --- 2 files changed, 61 insertions(+), 37 deletions(-) diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 8c6268e7d23..ac11744f16a 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -16,9 +16,10 @@ 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}; @@ -28,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}; @@ -395,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: @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 @@ -428,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 @@ -437,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); @@ -480,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 { diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 6f066218b7c..aa06e1bee41 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -236,13 +236,6 @@ 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; impl Emitter for DefaultEmitter { From e95996399fe6d306a206082eb1a49189c5afe878 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 30 Aug 2013 14:40:05 -0700 Subject: [PATCH 11/16] libsyntax: Remove some more `@fn`s from the macro expander --- src/libsyntax/ext/base.rs | 226 +++++++++++++++++++--------- src/libsyntax/ext/expand.rs | 30 ++-- src/libsyntax/ext/tt/macro_rules.rs | 141 +++++++++++++++-- 3 files changed, 294 insertions(+), 103 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 2bcfafc3bb4..63816072c29 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -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 +} -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 +} +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), + NormalTT(@SyntaxExpanderTTTrait, Option), // 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), + IdentTT(@SyntaxExpanderTTItemTrait, Option), } @@ -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,17 @@ 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 +234,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) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 0aefbe31338..60aa7cc5f92 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -83,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, @@ -370,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 { @@ -388,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)) @@ -402,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 @@ -481,17 +483,17 @@ 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) { + 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(_,_,stmt_mkr) => stmt_mkr(), + MRAny(any_macro) => any_macro.make_stmt(), _ => cx.span_fatal( pth.span, fmt!("non-stmt macro in stmt pos: %s", extnamestr)) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 74de8eaa09e..3fd394b3652 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -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)) }); From 9a4de3f3058ddb2cd43863c7c2723cec3d0fc30a Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 30 Aug 2013 18:00:38 -0700 Subject: [PATCH 12/16] libsyntax: Introduce routines and remove all `@fn`s from libsyntax save the old visitor --- src/libextra/c_vec.rs | 50 ++++++++++++++++++++++------------- src/libstd/routine.rs | 28 ++++++++++++++++++++ src/libstd/std.rs | 2 +- src/libstd/unstable/extfmt.rs | 22 +++++++++------ src/libsyntax/ext/fmt.rs | 2 +- src/libsyntax/fold.rs | 36 +++++++------------------ 6 files changed, 85 insertions(+), 55 deletions(-) create mode 100644 src/libstd/routine.rs diff --git a/src/libextra/c_vec.rs b/src/libextra/c_vec.rs index 30bce3a8170..be7acc7bd9c 100644 --- a/src/libextra/c_vec.rs +++ b/src/libextra/c_vec.rs @@ -36,22 +36,22 @@ * still held if needed. */ - -use std::option; +use std::cast; use std::ptr; +use std::routine::Runnable; +use std::util; /** * The type representing a foreign chunk of memory - * */ pub struct CVec { priv base: *mut T, priv len: uint, - priv rsrc: @DtorRes + priv rsrc: @DtorRes, } struct DtorRes { - dtor: Option<@fn()>, + dtor: Option<~Runnable>, } #[unsafe_destructor] @@ -64,9 +64,11 @@ impl Drop for DtorRes { } } -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(base: *mut T, len: uint) -> CVec { - return CVec{ + return CVec { base: base, len: len, - rsrc: @DtorRes(option::None) + rsrc: @DtorRes::new(None) }; } @@ -101,12 +103,12 @@ pub unsafe fn CVec(base: *mut T, len: uint) -> CVec { * * dtor - A function to run when the value is destructed, useful * for freeing the buffer, etc. */ -pub unsafe fn c_vec_with_dtor(base: *mut T, len: uint, dtor: @fn()) - -> CVec { +pub unsafe fn c_vec_with_dtor(base: *mut T, len: uint, dtor: ~Runnable) + -> CVec { return CVec{ base: base, len: len, - rsrc: @DtorRes(option::Some(dtor)) + rsrc: @DtorRes::new(Some(dtor)) }; } @@ -153,6 +155,17 @@ mod tests { use std::libc::*; use std::libc; + use std::routine::Runnable; + + struct LibcFree { + mem: *c_void, + } + + impl Runnable for LibcFree { + fn run(~self) { + libc::free(self.mem) + } + } fn malloc(n: size_t) -> CVec { #[fixed_stack_segment]; @@ -163,12 +176,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); } } diff --git a/src/libstd/routine.rs b/src/libstd/routine.rs new file mode 100644 index 00000000000..e8a91b49c8e --- /dev/null +++ b/src/libstd/routine.rs @@ -0,0 +1,28 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + * 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); +} + +/// A convenience routine that does nothing. +pub struct NoOpRunnable; + +impl Runnable for NoOpRunnable { + fn run(~self) {} +} + diff --git a/src/libstd/std.rs b/src/libstd/std.rs index f7b55e977e0..5c1bac7418e 100644 --- a/src/libstd/std.rs +++ b/src/libstd/std.rs @@ -189,7 +189,7 @@ pub mod reflect; pub mod condition; pub mod logging; pub mod util; - +pub mod routine; /* Unsupported interfaces */ diff --git a/src/libstd/unstable/extfmt.rs b/src/libstd/unstable/extfmt.rs index f2cfd114349..4d53dd7d7bf 100644 --- a/src/libstd/unstable/extfmt.rs +++ b/src/libstd/unstable/extfmt.rs @@ -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 { + pub fn parse_conversion<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>) + -> Parsed { 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 { + pub fn parse_type<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>) + -> Parsed { if i >= lim { err("missing type in conversion"); } // FIXME (#2249): Do we really want two signed types here? diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs index 9adb02ecc98..d48fa03c0ef 100644 --- a/src/libsyntax/ext/fmt.rs +++ b/src/libsyntax/ext/fmt.rs @@ -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)) } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 18ddee34171..66fe125aef4 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -869,35 +869,19 @@ mod test { use parse::token; use print::pprust; use super::*; - - struct IdentFolder { - f: @fn(ast::ident)->ast::ident, - } - - impl ast_fold for IdentFolder { - fn fold_ident(@self, i: ident) -> ident { - (self.f)(i) - } - } - - // taken from expand - // given a function from idents to idents, produce - // an ast_fold that applies that function: - pub fn fun_to_ident_folder(f: @fn(ast::ident)->ast::ident) -> @ast_fold { - @IdentFolder { - f: f, - } as @ast_fold - } - + // this version doesn't care about getting comments or docstrings in. fn fake_print_crate(s: @pprust::ps, crate: &ast::Crate) { pprust::print_mod(s, &crate.module, crate.attrs); } // change every identifier to "zz" - pub fn to_zz() -> @fn(ast::Ident)->ast::Ident { - let zz_id = token::str_to_ident("zz"); - |_id| {zz_id} + struct ToZzIdentFolder; + + impl ast_fold for ToZzIdentFolder { + fn fold_ident(&self, _: ident) -> ident { + token::str_to_ident("zz") + } } // maybe add to expand.rs... @@ -917,7 +901,7 @@ mod test { // make sure idents get transformed everywhere #[test] fn ident_transformation () { - let zz_fold = fun_to_ident_folder(to_zz()); + let zz_fold = ToZzIdentFolder; let ast = string_to_crate(@"#[a] mod b {fn c (d : e, f : g) {h!(i,j,k);l;m}}"); assert_pred!(matches_codepattern, "matches_codepattern", @@ -928,7 +912,7 @@ mod test { // even inside macro defs.... #[test] fn ident_transformation_in_defs () { - let zz_fold = fun_to_ident_folder(to_zz()); + let zz_fold = ToZzIdentFolder; let ast = string_to_crate(@"macro_rules! a {(b $c:expr $(d $e:token)f+ => (g $(d $d $e)+))} "); assert_pred!(matches_codepattern, @@ -940,7 +924,7 @@ mod test { // and in cast expressions... this appears to be an existing bug. #[test] fn ident_transformation_in_types () { - let zz_fold = fun_to_ident_folder(to_zz()); + let zz_fold = ToZzIdentFolder; let ast = string_to_crate(@"fn a() {let z = 13 as int;}"); assert_pred!(matches_codepattern, "matches_codepattern", From 68ea9aed96b6b8147b6c37b844c85cb7ae2867f4 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 10 Sep 2013 18:57:24 -0700 Subject: [PATCH 13/16] librustc: Remove `@fn` managed closures from the language. --- src/libextra/c_vec.rs | 8 ++--- src/libextra/rl.rs | 41 +++++++++++------------ src/libextra/test.rs | 5 --- src/librustc/middle/kind.rs | 21 +++++++++--- src/librustc/middle/mem_categorization.rs | 6 ++-- src/librustc/middle/stack_check.rs | 3 +- src/librustc/middle/trans/closure.rs | 40 ++++------------------ src/librustc/middle/trans/glue.rs | 10 ++---- src/librustc/middle/ty.rs | 7 +--- src/librustc/middle/typeck/astconv.rs | 5 +++ src/librustpkg/util.rs | 4 +-- src/libstd/io.rs | 32 +++++++++++++----- src/libstd/reflect.rs | 8 +++-- src/libstd/unstable/finally.rs | 1 - src/libsyntax/print/pprust.rs | 11 ------ 15 files changed, 90 insertions(+), 112 deletions(-) diff --git a/src/libextra/c_vec.rs b/src/libextra/c_vec.rs index be7acc7bd9c..99bb67ad89c 100644 --- a/src/libextra/c_vec.rs +++ b/src/libextra/c_vec.rs @@ -36,7 +36,6 @@ * still held if needed. */ -use std::cast; use std::ptr; use std::routine::Runnable; use std::util; @@ -57,9 +56,10 @@ struct DtorRes { #[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() } } } diff --git a/src/libextra/rl.rs b/src/libextra/rl.rs index 9476bcb8926..7c7b6de9a3a 100644 --- a/src/libextra/rl.rs +++ b/src/libextra/rl.rs @@ -30,13 +30,11 @@ 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; - rustrt::rust_drop_linenoise_lock(); - x - } + // FIXME #9105: can't use a static mutex in pure Rust yet. + rustrt::rust_take_linenoise_lock(); + let x = $expr; + rustrt::rust_drop_linenoise_lock(); + x } } @@ -88,9 +86,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 +100,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); } } } diff --git a/src/libextra/test.rs b/src/libextra/test.rs index cc80da1506a..7400973c28a 100644 --- a/src/libextra/test.rs +++ b/src/libextra/test.rs @@ -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) { diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 6ca8086efc2..1b3224a2217 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -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(_) => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 0e3c10ef214..9cc95b873d2 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -187,8 +187,7 @@ pub fn opt_deref_kind(t: ty::t) -> Option { 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 { diff --git a/src/librustc/middle/stack_check.rs b/src/librustc/middle/stack_check.rs index 7ab6cfcdf7b..5388e64348c 100644 --- a/src/librustc/middle/stack_check.rs +++ b/src/librustc/middle/stack_check.rs @@ -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 } _ => { diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index 605032dc20c..b5b181e22a6 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -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 } } diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 1958d3c9adb..a760801d73a 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -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); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9abee133290..bcf4de08073 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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, diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 36405136e63..024010e40df 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -400,6 +400,11 @@ pub fn ast_ty_to_ty( 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. diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index ac11744f16a..5d5e895a5ad 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -403,7 +403,7 @@ struct ViewItemVisitor<'self> { sess: session::Session, exec: &'self mut workcache::Exec, c: &'self ast::Crate, - save: @fn(Path), + save: &'self fn(Path), } impl<'self> Visitor<()> for ViewItemVisitor<'self> { @@ -508,7 +508,7 @@ pub fn find_and_install_dependencies(context: &BuildContext, sess: session::Session, exec: &mut workcache::Exec, c: &ast::Crate, - save: @fn(Path)) { + save: &fn(Path)) { debug!("In find_and_install_dependencies..."); let mut visitor = ViewItemVisitor { context: context, diff --git a/src/libstd/io.rs b/src/libstd/io.rs index 890a53690d9..ab8af22e116 100644 --- a/src/libstd/io.rs +++ b/src/libstd/io.rs @@ -1846,31 +1846,38 @@ pub mod fsync { pub struct Arg { val: t, opt_level: Option, - 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, + pub fn FILE_res_sync(file: &FILERes, + opt_level: Option, 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, blk: &fn(v: Res)) { 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, 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)] diff --git a/src/libstd/reflect.rs b/src/libstd/reflect.rs index 91e3719e3d0..833a9f5ed82 100644 --- a/src/libstd/reflect.rs +++ b/src/libstd/reflect.rs @@ -485,9 +485,11 @@ impl TyVisitor for MovePtrAdaptor { } 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 } } diff --git a/src/libstd/unstable/finally.rs b/src/libstd/unstable/finally.rs index 6833ca6d7cf..d98c13083de 100644 --- a/src/libstd/unstable/finally.rs +++ b/src/libstd/unstable/finally.rs @@ -55,7 +55,6 @@ impl<'self,T> Finally for &'self fn() -> T { } finally_fn!(~fn() -> T) -finally_fn!(@fn() -> T) finally_fn!(extern "Rust" fn() -> T) struct Finallyalizer<'self> { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 6cdd6d2517b..867e4fe416b 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2265,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) -> &'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", From a170183ba39c32b9f85c50a379dc4f9b8bd6e0fa Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 11 Sep 2013 16:26:06 -0700 Subject: [PATCH 14/16] librusti: Eliminate `@fn`. --- src/librusti/rusti.rs | 23 ++++++++++++++++------- src/librusti/utils.rs | 8 ++++---- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/librusti/rusti.rs b/src/librusti/rusti.rs index 0d024812c21..462c0a29236 100644 --- a/src/librusti/rusti.rs +++ b/src/librusti/rusti.rs @@ -72,6 +72,7 @@ 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}; @@ -520,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)]; @@ -543,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) } } diff --git a/src/librusti/utils.rs b/src/librusti/utils.rs index 400399253a5..904594fdfb8 100644 --- a/src/librusti/utils.rs +++ b/src/librusti/utils.rs @@ -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 }; From 90d3da971148a471c5766b544dc4ba50a15e5b96 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 16 Sep 2013 23:37:54 -0700 Subject: [PATCH 15/16] test: Fix rustdoc and tests. --- doc/tutorial.md | 28 ------- src/libextra/c_vec.rs | 5 +- src/librustc/driver/driver.rs | 16 +++- src/libstd/unstable/finally.rs | 11 --- src/libsyntax/ext/base.rs | 3 +- src/libsyntax/ext/expand.rs | 4 +- src/libsyntax/fold.rs | 15 +--- src/test/auxiliary/cci_nested_lib.rs | 2 +- src/test/auxiliary/issue4516_ty_param_lib.rs | 14 ---- src/test/bench/task-perf-alloc-unwind.rs | 5 -- .../compile-fail/borrowck-addr-of-upvar.rs | 27 ------- .../compile-fail/borrowck-move-by-capture.rs | 4 +- ...bounds-cant-promote-superkind-in-struct.rs | 4 +- src/test/compile-fail/do2.rs | 2 +- src/test/compile-fail/fn-variance-2.rs | 30 -------- src/test/compile-fail/fn-variance-3.rs | 32 -------- src/test/compile-fail/issue-1451.rs | 8 +- src/test/compile-fail/issue-1896-1.rs | 26 ------- src/test/compile-fail/issue-2074.rs | 4 +- src/test/compile-fail/issue-897.rs | 2 + src/test/compile-fail/kindck-owned.rs | 28 ------- src/test/compile-fail/lambda-mutate-nested.rs | 25 ------ src/test/compile-fail/lambda-mutate.rs | 22 ------ .../liveness-init-in-called-fn-expr.rs | 2 +- .../compile-fail/liveness-init-in-fn-expr.rs | 2 +- src/test/compile-fail/regions-fn-subtyping.rs | 16 +--- src/test/compile-fail/regions-fns.rs | 2 +- .../regions-infer-at-fn-not-param.rs | 4 +- ...regions-infer-contravariance-due-to-ret.rs | 2 +- .../regions-infer-covariance-due-to-arg.rs | 2 +- ...ns-infer-invariance-due-to-mutability-3.rs | 2 +- ...ns-infer-invariance-due-to-mutability-4.rs | 2 +- .../compile-fail/regions-infer-not-param.rs | 4 +- .../compile-fail/sendfn-is-not-a-lambda.rs | 18 ----- .../lexical-scope-in-managed-closure.rs | 77 ------------------- .../var-captured-in-managed-closure.rs | 56 -------------- src/test/pretty/block-arg-disambig.rs | 12 --- src/test/pretty/do1.rs | 2 +- src/test/pretty/fn-types.rs | 1 - src/test/run-fail/unwind-box-fn.rs | 24 ------ src/test/run-fail/unwind-closure.rs | 21 ----- src/test/run-fail/unwind-lambda.rs | 2 +- src/test/run-pass/alignment-gep-tup-like-1.rs | 25 +++++- src/test/run-pass/alignment-gep-tup-like-2.rs | 25 +++++- src/test/run-pass/block-arg-call-as.rs | 6 -- src/test/run-pass/block-arg-used-as-lambda.rs | 24 ------ .../run-pass/borrowck-move-by-capture-ok.rs | 2 +- .../call-closure-from-overloaded-op.rs | 2 +- src/test/run-pass/cap-clause-move.rs | 10 --- .../close-over-big-then-small-data.rs | 25 +++++- src/test/run-pass/cycle-collection2.rs | 28 ++++++- src/test/run-pass/cycle-collection4.rs | 20 ----- src/test/run-pass/cycle-collection5.rs | 22 ------ src/test/run-pass/do-no-args.rs | 4 +- src/test/run-pass/do1.rs | 2 +- src/test/run-pass/do2.rs | 2 +- src/test/run-pass/do3.rs | 2 +- src/test/run-pass/expr-block-fn.rs | 2 +- src/test/run-pass/expr-block-generic-box1.rs | 2 +- src/test/run-pass/expr-block-generic-box2.rs | 2 +- .../run-pass/expr-block-generic-unique1.rs | 2 +- .../run-pass/expr-block-generic-unique2.rs | 2 +- src/test/run-pass/expr-block-generic.rs | 2 +- src/test/run-pass/expr-if-generic-box1.rs | 2 +- src/test/run-pass/expr-if-generic-box2.rs | 2 +- src/test/run-pass/expr-if-generic.rs | 2 +- src/test/run-pass/expr-match-generic-box1.rs | 2 +- src/test/run-pass/expr-match-generic-box2.rs | 2 +- .../run-pass/expr-match-generic-unique1.rs | 2 +- .../run-pass/expr-match-generic-unique2.rs | 2 +- src/test/run-pass/expr-match-generic.rs | 2 +- src/test/run-pass/fixed-point-bind-box.rs | 30 -------- src/test/run-pass/fixed-point-bind-unique.rs | 30 -------- .../run-pass/fn-assign-managed-to-bare-1.rs | 20 ----- .../run-pass/fn-assign-managed-to-bare-2.rs | 28 ------- src/test/run-pass/fn-bare-coerce-to-shared.rs | 17 ---- src/test/run-pass/fn-coerce-field.rs | 4 +- src/test/run-pass/fn-type-infer.rs | 2 +- src/test/run-pass/fun-call-variants.rs | 2 +- src/test/run-pass/hashmap-memory.rs | 2 +- src/test/run-pass/infer-with-expected.rs | 25 ------ src/test/run-pass/issue-1516.rs | 2 +- src/test/run-pass/issue-2185.rs | 16 ++-- src/test/run-pass/issue-2633.rs | 8 +- src/test/run-pass/issue-3052.rs | 2 +- src/test/run-pass/issue-3429.rs | 2 +- src/test/run-pass/issue-4929.rs | 12 --- src/test/run-pass/issue-5783.rs | 19 ----- src/test/run-pass/issue4516_ty_param.rs | 25 ------ src/test/run-pass/lambda-infer-unresolved.rs | 4 +- src/test/run-pass/lambda-no-leak.rs | 17 ---- src/test/run-pass/last-use-in-cap-clause.rs | 4 +- src/test/run-pass/last-use-is-capture.rs | 2 +- .../run-pass/monomorphize-trait-in-fn-at.rs | 30 -------- src/test/run-pass/move-nullary-fn.rs | 4 +- src/test/run-pass/newlambdas-ret-infer.rs | 2 - src/test/run-pass/newlambdas-ret-infer2.rs | 2 - src/test/run-pass/newlambdas.rs | 7 -- .../propagate-expected-type-through-block.rs | 12 --- src/test/run-pass/reflect-visit-data.rs | 4 +- src/test/run-pass/regions-fn-subtyping.rs | 8 +- src/test/run-pass/unused-move-capture.rs | 2 +- 102 files changed, 196 insertions(+), 943 deletions(-) delete mode 100644 src/test/auxiliary/issue4516_ty_param_lib.rs delete mode 100644 src/test/compile-fail/borrowck-addr-of-upvar.rs delete mode 100644 src/test/compile-fail/fn-variance-2.rs delete mode 100644 src/test/compile-fail/fn-variance-3.rs delete mode 100644 src/test/compile-fail/issue-1896-1.rs delete mode 100644 src/test/compile-fail/kindck-owned.rs delete mode 100644 src/test/compile-fail/lambda-mutate-nested.rs delete mode 100644 src/test/compile-fail/lambda-mutate.rs delete mode 100644 src/test/compile-fail/sendfn-is-not-a-lambda.rs delete mode 100644 src/test/debug-info/lexical-scope-in-managed-closure.rs delete mode 100644 src/test/debug-info/var-captured-in-managed-closure.rs delete mode 100644 src/test/pretty/block-arg-disambig.rs delete mode 100644 src/test/run-fail/unwind-box-fn.rs delete mode 100644 src/test/run-fail/unwind-closure.rs delete mode 100644 src/test/run-pass/block-arg-used-as-lambda.rs delete mode 100644 src/test/run-pass/cycle-collection4.rs delete mode 100644 src/test/run-pass/cycle-collection5.rs delete mode 100644 src/test/run-pass/fixed-point-bind-box.rs delete mode 100644 src/test/run-pass/fixed-point-bind-unique.rs delete mode 100644 src/test/run-pass/fn-assign-managed-to-bare-1.rs delete mode 100644 src/test/run-pass/fn-assign-managed-to-bare-2.rs delete mode 100644 src/test/run-pass/fn-bare-coerce-to-shared.rs delete mode 100644 src/test/run-pass/infer-with-expected.rs delete mode 100644 src/test/run-pass/issue-4929.rs delete mode 100644 src/test/run-pass/issue-5783.rs delete mode 100644 src/test/run-pass/issue4516_ty_param.rs delete mode 100644 src/test/run-pass/lambda-no-leak.rs delete mode 100644 src/test/run-pass/monomorphize-trait-in-fn-at.rs delete mode 100644 src/test/run-pass/propagate-expected-type-through-block.rs diff --git a/doc/tutorial.md b/doc/tutorial.md index dd552f45f4e..a8d384226a3 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -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, diff --git a/src/libextra/c_vec.rs b/src/libextra/c_vec.rs index 99bb67ad89c..bd3ce20742e 100644 --- a/src/libextra/c_vec.rs +++ b/src/libextra/c_vec.rs @@ -162,8 +162,11 @@ mod tests { } impl Runnable for LibcFree { + #[fixed_stack_segment] fn run(~self) { - libc::free(self.mem) + unsafe { + libc::free(self.mem) + } } } diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index ae1133e1880..c9a5ca2c61c 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -1065,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"))); } @@ -1083,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()); diff --git a/src/libstd/unstable/finally.rs b/src/libstd/unstable/finally.rs index d98c13083de..ba5986aa4ab 100644 --- a/src/libstd/unstable/finally.rs +++ b/src/libstd/unstable/finally.rs @@ -118,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); -} diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 63816072c29..48eb9a350f1 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -217,7 +217,8 @@ pub fn syntax_expander_table() -> SyntaxEnv { })); syntax_expanders.insert(intern(&"macro_rules"), @SE(IdentTT(@SyntaxExpanderTTItem { - expander: SyntaxExpanderTTItemExpanderWithContext(ext::tt::macro_rules::add_new_extension), + expander: SyntaxExpanderTTItemExpanderWithContext( + ext::tt::macro_rules::add_new_extension), span: None, } as @SyntaxExpanderTTItemTrait, None))); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 60aa7cc5f92..004a889fb4d 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -772,7 +772,7 @@ impl ast_fold for IdentRenamer { // given a mutable list of renames, return a tree-folder that applies those // renames. -fn renames_to_fold(renames: @mut ~[(ast::Ident,ast::Name)]) -> @ast_fold { +pub fn renames_to_fold(renames: @mut ~[(ast::Ident,ast::Name)]) -> @ast_fold { @IdentRenamer { renames: renames, } as @ast_fold @@ -1524,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] { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 66fe125aef4..a25f267c458 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -869,7 +869,7 @@ mod test { use parse::token; use print::pprust; use super::*; - + // this version doesn't care about getting comments or docstrings in. fn fake_print_crate(s: @pprust::ps, crate: &ast::Crate) { pprust::print_mod(s, &crate.module, crate.attrs); @@ -879,7 +879,7 @@ mod test { struct ToZzIdentFolder; impl ast_fold for ToZzIdentFolder { - fn fold_ident(&self, _: ident) -> ident { + fn fold_ident(&self, _: ast::Ident) -> ast::Ident { token::str_to_ident("zz") } } @@ -921,16 +921,5 @@ mod test { token::get_ident_interner()), ~"zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)))"); } - - // and in cast expressions... this appears to be an existing bug. - #[test] fn ident_transformation_in_types () { - let zz_fold = ToZzIdentFolder; - let ast = string_to_crate(@"fn a() {let z = 13 as int;}"); - assert_pred!(matches_codepattern, - "matches_codepattern", - pprust::to_str(&zz_fold.fold_crate(ast),fake_print_crate, - token::get_ident_interner()), - ~"fn zz(){let zz=13 as zz;}"); - } } diff --git a/src/test/auxiliary/cci_nested_lib.rs b/src/test/auxiliary/cci_nested_lib.rs index c9809438d94..350bd09826f 100644 --- a/src/test/auxiliary/cci_nested_lib.rs +++ b/src/test/auxiliary/cci_nested_lib.rs @@ -14,7 +14,7 @@ pub struct Entry { } pub struct alist { - eq_fn: @fn(A,A) -> bool, + eq_fn: extern "Rust" fn(A,A) -> bool, data: @mut ~[Entry] } diff --git a/src/test/auxiliary/issue4516_ty_param_lib.rs b/src/test/auxiliary/issue4516_ty_param_lib.rs deleted file mode 100644 index cd90c9b06c4..00000000000 --- a/src/test/auxiliary/issue4516_ty_param_lib.rs +++ /dev/null @@ -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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub fn to_closure(x: A) -> @fn() -> A { - let result: @fn() -> A = || x.clone(); - result -} diff --git a/src/test/bench/task-perf-alloc-unwind.rs b/src/test/bench/task-perf-alloc-unwind.rs index f383f7a101f..991c102e9f0 100644 --- a/src/test/bench/task-perf-alloc-unwind.rs +++ b/src/test/bench/task-perf-alloc-unwind.rs @@ -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 { 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())], diff --git a/src/test/compile-fail/borrowck-addr-of-upvar.rs b/src/test/compile-fail/borrowck-addr-of-upvar.rs deleted file mode 100644 index 83baedc7892..00000000000 --- a/src/test/compile-fail/borrowck-addr-of-upvar.rs +++ /dev/null @@ -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 or the MIT license -// , 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() { -} diff --git a/src/test/compile-fail/borrowck-move-by-capture.rs b/src/test/compile-fail/borrowck-move-by-capture.rs index ecb18993d93..5994b9e85d5 100644 --- a/src/test/compile-fail/borrowck-move-by-capture.rs +++ b/src/test/compile-fail/borrowck-move-by-capture.rs @@ -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 }; } diff --git a/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs b/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs index b38cb895488..525f8f4a932 100644 --- a/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs +++ b/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs @@ -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 } diff --git a/src/test/compile-fail/do2.rs b/src/test/compile-fail/do2.rs index 4466c07518f..1bffdaa682c 100644 --- a/src/test/compile-fail/do2.rs +++ b/src/test/compile-fail/do2.rs @@ -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); diff --git a/src/test/compile-fail/fn-variance-2.rs b/src/test/compile-fail/fn-variance-2.rs deleted file mode 100644 index ab559190034..00000000000 --- a/src/test/compile-fail/fn-variance-2.rs +++ /dev/null @@ -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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn reproduce(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) -} diff --git a/src/test/compile-fail/fn-variance-3.rs b/src/test/compile-fail/fn-variance-3.rs deleted file mode 100644 index e42c6b658e4..00000000000 --- a/src/test/compile-fail/fn-variance-3.rs +++ /dev/null @@ -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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn mk_identity() -> @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; -} diff --git a/src/test/compile-fail/issue-1451.rs b/src/test/compile-fail/issue-1451.rs index a295e8eb7ed..0d8acaa4464 100644 --- a/src/test/compile-fail/issue-1451.rs +++ b/src/test/compile-fail/issue-1451.rs @@ -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}); } diff --git a/src/test/compile-fail/issue-1896-1.rs b/src/test/compile-fail/issue-1896-1.rs deleted file mode 100644 index 4750f68d59b..00000000000 --- a/src/test/compile-fail/issue-1896-1.rs +++ /dev/null @@ -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 or the MIT license -// , 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); -} diff --git a/src/test/compile-fail/issue-2074.rs b/src/test/compile-fail/issue-2074.rs index 40c2772f234..7815fca16c6 100644 --- a/src/test/compile-fail/issue-2074.rs +++ b/src/test/compile-fail/issue-2074.rs @@ -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 }; diff --git a/src/test/compile-fail/issue-897.rs b/src/test/compile-fail/issue-897.rs index 103156175a3..8df73aef610 100644 --- a/src/test/compile-fail/issue-897.rs +++ b/src/test/compile-fail/issue-897.rs @@ -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. diff --git a/src/test/compile-fail/kindck-owned.rs b/src/test/compile-fail/kindck-owned.rs deleted file mode 100644 index 2dfdb2629f7..00000000000 --- a/src/test/compile-fail/kindck-owned.rs +++ /dev/null @@ -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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn copy1(t: T) -> @fn() -> T { - let result: @fn() -> T = || t.clone(); //~ ERROR does not fulfill `'static` - result -} - -fn copy2(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` -} diff --git a/src/test/compile-fail/lambda-mutate-nested.rs b/src/test/compile-fail/lambda-mutate-nested.rs deleted file mode 100644 index bfd1e12f3a6..00000000000 --- a/src/test/compile-fail/lambda-mutate-nested.rs +++ /dev/null @@ -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 or the MIT license -// , 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); -} diff --git a/src/test/compile-fail/lambda-mutate.rs b/src/test/compile-fail/lambda-mutate.rs deleted file mode 100644 index a848d8698a3..00000000000 --- a/src/test/compile-fail/lambda-mutate.rs +++ /dev/null @@ -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 or the MIT license -// , 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); -} diff --git a/src/test/compile-fail/liveness-init-in-called-fn-expr.rs b/src/test/compile-fail/liveness-init-in-called-fn-expr.rs index 1fddea80966..7054cb0d901 100644 --- a/src/test/compile-fail/liveness-init-in-called-fn-expr.rs +++ b/src/test/compile-fail/liveness-init-in-called-fn-expr.rs @@ -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` }; diff --git a/src/test/compile-fail/liveness-init-in-fn-expr.rs b/src/test/compile-fail/liveness-init-in-fn-expr.rs index b7a715d2958..b6c7895235b 100644 --- a/src/test/compile-fail/liveness-init-in-fn-expr.rs +++ b/src/test/compile-fail/liveness-init-in-fn-expr.rs @@ -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` }; diff --git a/src/test/compile-fail/regions-fn-subtyping.rs b/src/test/compile-fail/regions-fn-subtyping.rs index face9c74214..5928d31a668 100644 --- a/src/test/compile-fail/regions-fn-subtyping.rs +++ b/src/test/compile-fail/regions-fn-subtyping.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn of() -> @fn(T) { fail!(); } -fn subtype(x: @fn(T)) { fail!(); } +fn of() -> &fn(T) { fail!(); } +fn subtype(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() {} diff --git a/src/test/compile-fail/regions-fns.rs b/src/test/compile-fail/regions-fns.rs index 4f6cbdfdd65..715261d816a 100644 --- a/src/test/compile-fail/regions-fns.rs +++ b/src/test/compile-fail/regions-fns.rs @@ -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); } diff --git a/src/test/compile-fail/regions-infer-at-fn-not-param.rs b/src/test/compile-fail/regions-infer-at-fn-not-param.rs index 488d1f3940d..3ddae976ce3 100644 --- a/src/test/compile-fail/regions-infer-at-fn-not-param.rs +++ b/src/test/compile-fail/regions-infer-at-fn-not-param.rs @@ -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 } diff --git a/src/test/compile-fail/regions-infer-contravariance-due-to-ret.rs b/src/test/compile-fail/regions-infer-contravariance-due-to-ret.rs index 15f40a91735..3fcc5184b4a 100644 --- a/src/test/compile-fail/regions-infer-contravariance-due-to-ret.rs +++ b/src/test/compile-fail/regions-infer-contravariance-due-to-ret.rs @@ -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>) { diff --git a/src/test/compile-fail/regions-infer-covariance-due-to-arg.rs b/src/test/compile-fail/regions-infer-covariance-due-to-arg.rs index c33ca2dab2e..4b26e6b6021 100644 --- a/src/test/compile-fail/regions-infer-covariance-due-to-arg.rs +++ b/src/test/compile-fail/regions-infer-covariance-due-to-arg.rs @@ -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>) { diff --git a/src/test/compile-fail/regions-infer-invariance-due-to-mutability-3.rs b/src/test/compile-fail/regions-infer-invariance-due-to-mutability-3.rs index 92447c1ef8d..6e322b170e8 100644 --- a/src/test/compile-fail/regions-infer-invariance-due-to-mutability-3.rs +++ b/src/test/compile-fail/regions-infer-invariance-due-to-mutability-3.rs @@ -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>) { diff --git a/src/test/compile-fail/regions-infer-invariance-due-to-mutability-4.rs b/src/test/compile-fail/regions-infer-invariance-due-to-mutability-4.rs index 61adba3aec1..380e9b27ff9 100644 --- a/src/test/compile-fail/regions-infer-invariance-due-to-mutability-4.rs +++ b/src/test/compile-fail/regions-infer-invariance-due-to-mutability-4.rs @@ -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>) { diff --git a/src/test/compile-fail/regions-infer-not-param.rs b/src/test/compile-fail/regions-infer-not-param.rs index fa853b82d9e..47c1f7a5757 100644 --- a/src/test/compile-fail/regions-infer-not-param.rs +++ b/src/test/compile-fail/regions-infer-not-param.rs @@ -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 diff --git a/src/test/compile-fail/sendfn-is-not-a-lambda.rs b/src/test/compile-fail/sendfn-is-not-a-lambda.rs deleted file mode 100644 index 609439d7b8e..00000000000 --- a/src/test/compile-fail/sendfn-is-not-a-lambda.rs +++ /dev/null @@ -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 or the MIT license -// , 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 -} diff --git a/src/test/debug-info/lexical-scope-in-managed-closure.rs b/src/test/debug-info/lexical-scope-in-managed-closure.rs deleted file mode 100644 index 96da78a9192..00000000000 --- a/src/test/debug-info/lexical-scope-in-managed-closure.rs +++ /dev/null @@ -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 or the MIT license -// , 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() {()} diff --git a/src/test/debug-info/var-captured-in-managed-closure.rs b/src/test/debug-info/var-captured-in-managed-closure.rs deleted file mode 100644 index b20f40378d3..00000000000 --- a/src/test/debug-info/var-captured-in-managed-closure.rs +++ /dev/null @@ -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 or the MIT license -// , 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() {()} diff --git a/src/test/pretty/block-arg-disambig.rs b/src/test/pretty/block-arg-disambig.rs deleted file mode 100644 index c0f173a1a0d..00000000000 --- a/src/test/pretty/block-arg-disambig.rs +++ /dev/null @@ -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 or the MIT license -// , 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"); })(); } diff --git a/src/test/pretty/do1.rs b/src/test/pretty/do1.rs index 6f9aa28f11a..751aedb39a3 100644 --- a/src/test/pretty/do1.rs +++ b/src/test/pretty/do1.rs @@ -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) } } diff --git a/src/test/pretty/fn-types.rs b/src/test/pretty/fn-types.rs index 0545e9ed166..b000c9f9137 100644 --- a/src/test/pretty/fn-types.rs +++ b/src/test/pretty/fn-types.rs @@ -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() { } diff --git a/src/test/run-fail/unwind-box-fn.rs b/src/test/run-fail/unwind-box-fn.rs deleted file mode 100644 index a94f904c492..00000000000 --- a/src/test/run-fail/unwind-box-fn.rs +++ /dev/null @@ -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 or the MIT license -// , 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); -} diff --git a/src/test/run-fail/unwind-closure.rs b/src/test/run-fail/unwind-closure.rs deleted file mode 100644 index 5ea71c94e14..00000000000 --- a/src/test/run-fail/unwind-closure.rs +++ /dev/null @@ -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 or the MIT license -// , 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(); -} diff --git a/src/test/run-fail/unwind-lambda.rs b/src/test/run-fail/unwind-lambda.rs index 74d6ab00802..65d9fce5ff5 100644 --- a/src/test/run-fail/unwind-lambda.rs +++ b/src/test/run-fail/unwind-lambda.rs @@ -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| { diff --git a/src/test/run-pass/alignment-gep-tup-like-1.rs b/src/test/run-pass/alignment-gep-tup-like-1.rs index a821e4647c1..4352c139b62 100644 --- a/src/test/run-pass/alignment-gep-tup-like-1.rs +++ b/src/test/run-pass/alignment-gep-tup-like-1.rs @@ -12,13 +12,30 @@ struct pair { a: A, b: B } -fn f(a: A, b: u16) -> @fn() -> (A, u16) { - let result: @fn() -> (A, u16) = || (a.clone(), b); - result +trait Invokable { + fn f(&self) -> (A, u16); +} + +struct Invoker { + a: A, + b: u16, +} + +impl Invokable for Invoker { + fn f(&self) -> (A, u16) { + (self.a.clone(), self.b) + } +} + +fn f(a: A, b: u16) -> @Invokable { + @Invoker { + a: a, + b: b, + } as @Invokable } 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); diff --git a/src/test/run-pass/alignment-gep-tup-like-2.rs b/src/test/run-pass/alignment-gep-tup-like-2.rs index e924c31bad6..9bf95968a9a 100644 --- a/src/test/run-pass/alignment-gep-tup-like-2.rs +++ b/src/test/run-pass/alignment-gep-tup-like-2.rs @@ -23,13 +23,30 @@ fn make_cycle(a: A) { g.rec = Some(g); } +struct Invoker { + a: A, + b: B, +} + +trait Invokable { + fn f(&self) -> (A, B); +} + +impl Invokable for Invoker { + fn f(&self) -> (A, B) { + (self.a.clone(), self.b.clone()) + } +} + fn f( a: A, b: B) - -> @fn() -> (A, B) { - let result: @fn() -> (A, B) = || (a.clone(), b.clone()); - result + -> @Invokable { + @Invoker { + a: a, + b: b, + } as @Invokable } 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); diff --git a/src/test/run-pass/block-arg-call-as.rs b/src/test/run-pass/block-arg-call-as.rs index d68b0be632e..6a59278982a 100644 --- a/src/test/run-pass/block-arg-call-as.rs +++ b/src/test/run-pass/block-arg-call-as.rs @@ -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); } diff --git a/src/test/run-pass/block-arg-used-as-lambda.rs b/src/test/run-pass/block-arg-used-as-lambda.rs deleted file mode 100644 index 34fa7e36d97..00000000000 --- a/src/test/run-pass/block-arg-used-as-lambda.rs +++ /dev/null @@ -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 or the MIT license -// , 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); -} diff --git a/src/test/run-pass/borrowck-move-by-capture-ok.rs b/src/test/run-pass/borrowck-move-by-capture-ok.rs index 095e2ba6fea..f6328c8c658 100644 --- a/src/test/run-pass/borrowck-move-by-capture-ok.rs +++ b/src/test/run-pass/borrowck-move-by-capture-ok.rs @@ -1,5 +1,5 @@ pub fn main() { let bar = ~3; - let h: @fn() -> int = || *bar; + let h: ~fn() -> int = || *bar; assert_eq!(h(), 3); } diff --git a/src/test/run-pass/call-closure-from-overloaded-op.rs b/src/test/run-pass/call-closure-from-overloaded-op.rs index cc8d8e96195..16728dffd19 100644 --- a/src/test/run-pass/call-closure-from-overloaded-op.rs +++ b/src/test/run-pass/call-closure-from-overloaded-op.rs @@ -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); } diff --git a/src/test/run-pass/cap-clause-move.rs b/src/test/run-pass/cap-clause-move.rs index aadd6a72494..64be8dab6e7 100644 --- a/src/test/run-pass/cap-clause-move.rs +++ b/src/test/run-pass/cap-clause-move.rs @@ -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; diff --git a/src/test/run-pass/close-over-big-then-small-data.rs b/src/test/run-pass/close-over-big-then-small-data.rs index 01c6442fa00..8b7967ac150 100644 --- a/src/test/run-pass/close-over-big-then-small-data.rs +++ b/src/test/run-pass/close-over-big-then-small-data.rs @@ -16,13 +16,30 @@ struct Pair { a: A, b: B } -fn f(a: A, b: u16) -> @fn() -> (A, u16) { - let result: @fn() -> (A, u16) = || (a.clone(), b); - result +struct Invoker { + a: A, + b: u16, +} + +trait Invokable { + fn f(&self) -> (A, u16); +} + +impl Invokable for Invoker { + fn f(&self) -> (A, u16) { + (self.a.clone(), self.b) + } +} + +fn f(a: A, b: u16) -> @Invokable { + @Invoker { + a: a, + b: b, + } as @Invokable } 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); diff --git a/src/test/run-pass/cycle-collection2.rs b/src/test/run-pass/cycle-collection2.rs index cd148417f4c..46c0c52e0c7 100644 --- a/src/test/run-pass/cycle-collection2.rs +++ b/src/test/run-pass/cycle-collection2.rs @@ -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); } diff --git a/src/test/run-pass/cycle-collection4.rs b/src/test/run-pass/cycle-collection4.rs deleted file mode 100644 index 8b613093944..00000000000 --- a/src/test/run-pass/cycle-collection4.rs +++ /dev/null @@ -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 or the MIT license -// , 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; -} diff --git a/src/test/run-pass/cycle-collection5.rs b/src/test/run-pass/cycle-collection5.rs deleted file mode 100644 index f724a86555c..00000000000 --- a/src/test/run-pass/cycle-collection5.rs +++ /dev/null @@ -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 or the MIT license -// , 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; -} diff --git a/src/test/run-pass/do-no-args.rs b/src/test/run-pass/do-no-args.rs index 6aef1f5f9e5..1f725ffb357 100644 --- a/src/test/run-pass/do-no-args.rs +++ b/src/test/run-pass/do-no-args.rs @@ -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 { } diff --git a/src/test/run-pass/do1.rs b/src/test/run-pass/do1.rs index 735621a19fe..0444b269cb3 100644 --- a/src/test/run-pass/do1.rs +++ b/src/test/run-pass/do1.rs @@ -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) } diff --git a/src/test/run-pass/do2.rs b/src/test/run-pass/do2.rs index 684a2c108eb..9feededc980 100644 --- a/src/test/run-pass/do2.rs +++ b/src/test/run-pass/do2.rs @@ -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); diff --git a/src/test/run-pass/do3.rs b/src/test/run-pass/do3.rs index b0d49fd2bdd..eeb983b4557 100644 --- a/src/test/run-pass/do3.rs +++ b/src/test/run-pass/do3.rs @@ -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); diff --git a/src/test/run-pass/expr-block-fn.rs b/src/test/run-pass/expr-block-fn.rs index dbb1ac1f649..63e5c7688d3 100644 --- a/src/test/run-pass/expr-block-fn.rs +++ b/src/test/run-pass/expr-block-fn.rs @@ -11,7 +11,7 @@ fn test_fn() { - type t = @fn() -> int; + type t = &'static fn() -> int; fn ten() -> int { return 10; } let rs: t = { ten }; assert!((rs() == 10)); diff --git a/src/test/run-pass/expr-block-generic-box1.rs b/src/test/run-pass/expr-block-generic-box1.rs index 2c902181810..12b387b7eae 100644 --- a/src/test/run-pass/expr-block-generic-box1.rs +++ b/src/test/run-pass/expr-block-generic-box1.rs @@ -12,7 +12,7 @@ // -*- rust -*- -type compare = @fn(@T, @T) -> bool; +type compare = &'static fn(@T, @T) -> bool; fn test_generic(expected: @T, eq: compare) { let actual: @T = { expected }; diff --git a/src/test/run-pass/expr-block-generic-box2.rs b/src/test/run-pass/expr-block-generic-box2.rs index 7d849bbff01..cfa59d68635 100644 --- a/src/test/run-pass/expr-block-generic-box2.rs +++ b/src/test/run-pass/expr-block-generic-box2.rs @@ -11,7 +11,7 @@ // xfail-fast -type compare = @fn(T, T) -> bool; +type compare<'self, T> = &'self fn(T, T) -> bool; fn test_generic(expected: T, eq: compare) { let actual: T = { expected.clone() }; diff --git a/src/test/run-pass/expr-block-generic-unique1.rs b/src/test/run-pass/expr-block-generic-unique1.rs index 0249820410c..3f9c101761f 100644 --- a/src/test/run-pass/expr-block-generic-unique1.rs +++ b/src/test/run-pass/expr-block-generic-unique1.rs @@ -11,7 +11,7 @@ // -*- rust -*- -type compare = @fn(~T, ~T) -> bool; +type compare<'self, T> = &'self fn(~T, ~T) -> bool; fn test_generic(expected: ~T, eq: compare) { let actual: ~T = { expected.clone() }; diff --git a/src/test/run-pass/expr-block-generic-unique2.rs b/src/test/run-pass/expr-block-generic-unique2.rs index 389a42ae7af..3484a4f7f5a 100644 --- a/src/test/run-pass/expr-block-generic-unique2.rs +++ b/src/test/run-pass/expr-block-generic-unique2.rs @@ -11,7 +11,7 @@ // xfail-fast // -*- rust -*- -type compare = @fn(T, T) -> bool; +type compare<'self, T> = &'self fn(T, T) -> bool; fn test_generic(expected: T, eq: compare) { let actual: T = { expected.clone() }; diff --git a/src/test/run-pass/expr-block-generic.rs b/src/test/run-pass/expr-block-generic.rs index 7091fceb771..2f379602c6b 100644 --- a/src/test/run-pass/expr-block-generic.rs +++ b/src/test/run-pass/expr-block-generic.rs @@ -13,7 +13,7 @@ // xfail-fast // Tests for standalone blocks as expressions with dynamic type sizes -type compare = @fn(T, T) -> bool; +type compare<'self, T> = &'self fn(T, T) -> bool; fn test_generic(expected: T, eq: compare) { let actual: T = { expected.clone() }; diff --git a/src/test/run-pass/expr-if-generic-box1.rs b/src/test/run-pass/expr-if-generic-box1.rs index def991adea8..8bf6e658408 100644 --- a/src/test/run-pass/expr-if-generic-box1.rs +++ b/src/test/run-pass/expr-if-generic-box1.rs @@ -12,7 +12,7 @@ // -*- rust -*- -type compare = @fn(@T, @T) -> bool; +type compare = &'static fn(@T, @T) -> bool; fn test_generic(expected: @T, not_expected: @T, eq: compare) { let actual: @T = if true { expected } else { not_expected }; diff --git a/src/test/run-pass/expr-if-generic-box2.rs b/src/test/run-pass/expr-if-generic-box2.rs index a2d28a2be04..2c4707a87d5 100644 --- a/src/test/run-pass/expr-if-generic-box2.rs +++ b/src/test/run-pass/expr-if-generic-box2.rs @@ -11,7 +11,7 @@ // xfail-fast // -*- rust -*- -type compare = @fn(T, T) -> bool; +type compare = &'static fn(T, T) -> bool; fn test_generic(expected: T, not_expected: T, eq: compare) { let actual: T = if true { expected.clone() } else { not_expected }; diff --git a/src/test/run-pass/expr-if-generic.rs b/src/test/run-pass/expr-if-generic.rs index f5b2a1a7986..1bbf3a537db 100644 --- a/src/test/run-pass/expr-if-generic.rs +++ b/src/test/run-pass/expr-if-generic.rs @@ -12,7 +12,7 @@ // -*- rust -*- // Tests for if as expressions with dynamic type sizes -type compare = @fn(T, T) -> bool; +type compare = &'static fn(T, T) -> bool; fn test_generic(expected: T, not_expected: T, eq: compare) { let actual: T = if true { expected.clone() } else { not_expected }; diff --git a/src/test/run-pass/expr-match-generic-box1.rs b/src/test/run-pass/expr-match-generic-box1.rs index 4ea2d0fba9b..064e3343620 100644 --- a/src/test/run-pass/expr-match-generic-box1.rs +++ b/src/test/run-pass/expr-match-generic-box1.rs @@ -12,7 +12,7 @@ // -*- rust -*- -type compare = @fn(@T, @T) -> bool; +type compare = &'static fn(@T, @T) -> bool; fn test_generic(expected: @T, eq: compare) { let actual: @T = match true { true => { expected }, _ => fail!() }; diff --git a/src/test/run-pass/expr-match-generic-box2.rs b/src/test/run-pass/expr-match-generic-box2.rs index a2ccf5c0fb9..bca06ebdbb5 100644 --- a/src/test/run-pass/expr-match-generic-box2.rs +++ b/src/test/run-pass/expr-match-generic-box2.rs @@ -11,7 +11,7 @@ // xfail-fast // -*- rust -*- -type compare = @fn(T, T) -> bool; +type compare = &'static fn(T, T) -> bool; fn test_generic(expected: T, eq: compare) { let actual: T = match true { true => { expected.clone() }, _ => fail!("wat") }; diff --git a/src/test/run-pass/expr-match-generic-unique1.rs b/src/test/run-pass/expr-match-generic-unique1.rs index 0f564e6a780..7371f8fd89b 100644 --- a/src/test/run-pass/expr-match-generic-unique1.rs +++ b/src/test/run-pass/expr-match-generic-unique1.rs @@ -11,7 +11,7 @@ // -*- rust -*- -type compare = @fn(~T, ~T) -> bool; +type compare = &'static fn(~T, ~T) -> bool; fn test_generic(expected: ~T, eq: compare) { let actual: ~T = match true { diff --git a/src/test/run-pass/expr-match-generic-unique2.rs b/src/test/run-pass/expr-match-generic-unique2.rs index ae88d48bc44..d07d40e6757 100644 --- a/src/test/run-pass/expr-match-generic-unique2.rs +++ b/src/test/run-pass/expr-match-generic-unique2.rs @@ -11,7 +11,7 @@ // xfail-fast // -*- rust -*- -type compare = @fn(T, T) -> bool; +type compare<'self, T> = &'self fn(T, T) -> bool; fn test_generic(expected: T, eq: compare) { let actual: T = match true { diff --git a/src/test/run-pass/expr-match-generic.rs b/src/test/run-pass/expr-match-generic.rs index 59f1ff14f59..b43085d346f 100644 --- a/src/test/run-pass/expr-match-generic.rs +++ b/src/test/run-pass/expr-match-generic.rs @@ -11,7 +11,7 @@ // xfail-fast // -*- rust -*- -type compare = @fn(T, T) -> bool; +type compare = extern "Rust" fn(T, T) -> bool; fn test_generic(expected: T, eq: compare) { let actual: T = match true { true => { expected.clone() }, _ => fail!("wat") }; diff --git a/src/test/run-pass/fixed-point-bind-box.rs b/src/test/run-pass/fixed-point-bind-box.rs deleted file mode 100644 index 4c28151224c..00000000000 --- a/src/test/run-pass/fixed-point-bind-box.rs +++ /dev/null @@ -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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-fast - -fn fix_help(f: extern fn(@fn(A) -> B, A) -> B, x: A) -> B { - return f( |a| fix_help(f, a), x); -} - -fn fix(f: extern fn(@fn(A) -> B, A) -> B) -> @fn(A) -> B { - return |a| fix_help(f, a); -} - -fn fact_(f: @fn(v: int) -> int, n: int) -> int { - // fun fact 0 = 1 - return if n == 0 { 1 } else { n * f(n - 1) }; -} - -pub fn main() { - let fact = fix(fact_); - assert_eq!(fact(5), 120); - assert_eq!(fact(2), 2); -} diff --git a/src/test/run-pass/fixed-point-bind-unique.rs b/src/test/run-pass/fixed-point-bind-unique.rs deleted file mode 100644 index c7b64fde3fd..00000000000 --- a/src/test/run-pass/fixed-point-bind-unique.rs +++ /dev/null @@ -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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-fast - -fn fix_help(f: extern fn(@fn(A) -> B, A) -> B, x: A) -> B { - return f(|a| fix_help(f, a), x); -} - -fn fix(f: extern fn(@fn(A) -> B, A) -> B) -> @fn(A) -> B { - return |a| fix_help(f, a); -} - -fn fact_(f: @fn(v: int) -> int, n: int) -> int { - // fun fact 0 = 1 - return if n == 0 { 1 } else { n * f(n - 1) }; -} - -pub fn main() { - let fact = fix(fact_); - assert_eq!(fact(5), 120); - assert_eq!(fact(2), 2); -} diff --git a/src/test/run-pass/fn-assign-managed-to-bare-1.rs b/src/test/run-pass/fn-assign-managed-to-bare-1.rs deleted file mode 100644 index dece77595bc..00000000000 --- a/src/test/run-pass/fn-assign-managed-to-bare-1.rs +++ /dev/null @@ -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 or the MIT license -// , at your -// 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 -} - -pub fn main() { - assert_eq!(add(3)(4), 7); - let add3 : &fn(int)->int = add(3); - assert_eq!(add3(4), 7); -} diff --git a/src/test/run-pass/fn-assign-managed-to-bare-2.rs b/src/test/run-pass/fn-assign-managed-to-bare-2.rs deleted file mode 100644 index f8daacfa233..00000000000 --- a/src/test/run-pass/fn-assign-managed-to-bare-2.rs +++ /dev/null @@ -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 or the MIT license -// , at your -// 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 -} - -pub fn main() -{ - assert_eq!(add(3)(4), 7); - - 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); -} diff --git a/src/test/run-pass/fn-bare-coerce-to-shared.rs b/src/test/run-pass/fn-bare-coerce-to-shared.rs deleted file mode 100644 index 853b44ed76c..00000000000 --- a/src/test/run-pass/fn-bare-coerce-to-shared.rs +++ /dev/null @@ -1,17 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn bare() {} - -fn likes_shared(f: @fn()) { f() } - -pub fn main() { - likes_shared(bare); -} diff --git a/src/test/run-pass/fn-coerce-field.rs b/src/test/run-pass/fn-coerce-field.rs index 22aab1aa661..ae2e353f913 100644 --- a/src/test/run-pass/fn-coerce-field.rs +++ b/src/test/run-pass/fn-coerce-field.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct r { - field: @fn() +struct r<'self> { + field: &'self fn() } pub fn main() { diff --git a/src/test/run-pass/fn-type-infer.rs b/src/test/run-pass/fn-type-infer.rs index bb9254589f7..09e7ababa6c 100644 --- a/src/test/run-pass/fn-type-infer.rs +++ b/src/test/run-pass/fn-type-infer.rs @@ -11,7 +11,7 @@ #[allow(unused_variable)]; pub fn main() { - // We should be able to type infer inside of @fns. + // We should be able to type infer inside of &fns. let _f = || { let i = 10; }; diff --git a/src/test/run-pass/fun-call-variants.rs b/src/test/run-pass/fun-call-variants.rs index 52e6a4649a8..5011998f929 100644 --- a/src/test/run-pass/fun-call-variants.rs +++ b/src/test/run-pass/fun-call-variants.rs @@ -9,7 +9,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn ho(f: @fn(int) -> int) -> int { let n: int = f(3); return n; } +fn ho(f: &fn(int) -> int) -> int { let n: int = f(3); return n; } fn direct(x: int) -> int { return x + 1; } diff --git a/src/test/run-pass/hashmap-memory.rs b/src/test/run-pass/hashmap-memory.rs index 7cd26dd84c4..15286a85c01 100644 --- a/src/test/run-pass/hashmap-memory.rs +++ b/src/test/run-pass/hashmap-memory.rs @@ -24,7 +24,7 @@ mod map_reduce { use std::str; use std::task; - pub type putter = @fn(~str, ~str); + pub type putter<'self> = &'self fn(~str, ~str); pub type mapper = extern fn(~str, putter); diff --git a/src/test/run-pass/infer-with-expected.rs b/src/test/run-pass/infer-with-expected.rs deleted file mode 100644 index 6f2fd54bc9c..00000000000 --- a/src/test/run-pass/infer-with-expected.rs +++ /dev/null @@ -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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Tests the passing down of expected types through boxing and -// wrapping in a record or tuple. (The a.x would complain about 'this -// type must be known in this context' if the passing down doesn't -// happen.) - -fn eat_tup(_r: ~@(int, @fn(Pair) -> int)) {} -fn eat_rec(_r: ~Rec) {} - -struct Rec<'self> { a: int, b: &'self fn(Pair) -> int } -struct Pair { x: int, y: int } - -pub fn main() { - eat_tup(~@(10, |a| a.x )); - eat_rec(~Rec{a: 10, b: |a| a.x }); -} diff --git a/src/test/run-pass/issue-1516.rs b/src/test/run-pass/issue-1516.rs index 2767ac6d69f..4b73d83595e 100644 --- a/src/test/run-pass/issue-1516.rs +++ b/src/test/run-pass/issue-1516.rs @@ -9,5 +9,5 @@ // except according to those terms. pub fn main() { - let early_error: @fn(&str) -> ! = |_msg| { fail!() }; + let early_error: &'static fn(&str) -> ! = |_msg| { fail!() }; } diff --git a/src/test/run-pass/issue-2185.rs b/src/test/run-pass/issue-2185.rs index c84386c722d..a1ea1b90809 100644 --- a/src/test/run-pass/issue-2185.rs +++ b/src/test/run-pass/issue-2185.rs @@ -18,11 +18,11 @@ // // Running /usr/local/bin/rustc: // issue-2185.rs:24:0: 26:1 error: conflicting implementations for a trait -// issue-2185.rs:24 impl iterable for @fn(&fn(uint)) { +// issue-2185.rs:24 impl iterable for &'static fn(&fn(uint)) { // issue-2185.rs:25 fn iter(&self, blk: &fn(v: uint)) { self( |i| blk(i) ) } // issue-2185.rs:26 } // issue-2185.rs:20:0: 22:1 note: note conflicting implementation here -// issue-2185.rs:20 impl iterable for @fn(&fn(A)) { +// issue-2185.rs:20 impl iterable for &'static fn(&fn(A)) { // issue-2185.rs:21 fn iter(&self, blk: &fn(A)) { self(blk); } // issue-2185.rs:22 } // @@ -42,15 +42,17 @@ trait iterable { fn iter(&self, blk: &fn(A)); } -impl iterable for @fn(&fn(A)) { +impl iterable for &'static fn(&fn(A)) { fn iter(&self, blk: &fn(A)) { self(blk); } } -impl iterable for @fn(&fn(uint)) { +impl iterable for &'static fn(&fn(uint)) { fn iter(&self, blk: &fn(v: uint)) { self( |i| blk(i) ) } } -fn filter>(self: IA, prd: @fn(A) -> bool, blk: &fn(A)) { +fn filter>(self: IA, + prd: &'static fn(A) -> bool, + blk: &fn(A)) { do self.iter |a| { if prd(a) { blk(a) } } @@ -73,8 +75,8 @@ fn range(lo: uint, hi: uint, it: &fn(uint)) { } pub fn main() { - let range: @fn(&fn(uint)) = |a| range(0u, 1000u, a); - let filt: @fn(&fn(v: uint)) = |a| filter( + let range: &'static fn(&fn(uint)) = |a| range(0u, 1000u, a); + let filt: &'static fn(&fn(v: uint)) = |a| filter( range, |&&n: uint| n % 3u != 0u && n % 5u != 0u, a); diff --git a/src/test/run-pass/issue-2633.rs b/src/test/run-pass/issue-2633.rs index e7da1286137..bde18d77b9a 100644 --- a/src/test/run-pass/issue-2633.rs +++ b/src/test/run-pass/issue-2633.rs @@ -9,12 +9,16 @@ // except according to those terms. struct cat { - meow: @fn(), + meow: extern "Rust" fn(), +} + +fn meow() { + error!("meow") } fn cat() -> cat { cat { - meow: || error!("meow") + meow: meow, } } diff --git a/src/test/run-pass/issue-3052.rs b/src/test/run-pass/issue-3052.rs index 852c6d995c6..cb1ffc38908 100644 --- a/src/test/run-pass/issue-3052.rs +++ b/src/test/run-pass/issue-3052.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -type Connection = @fn(~[u8]); +type Connection = &'static fn(~[u8]); fn f() -> Option { let mock_connection: Connection = |_| {}; diff --git a/src/test/run-pass/issue-3429.rs b/src/test/run-pass/issue-3429.rs index abea01cefd3..fc493485b79 100644 --- a/src/test/run-pass/issue-3429.rs +++ b/src/test/run-pass/issue-3429.rs @@ -10,6 +10,6 @@ pub fn main() { let x = 1; - let y: @fn() -> int = || x; + let y: &fn() -> int = || x; let _z = y(); } diff --git a/src/test/run-pass/issue-4929.rs b/src/test/run-pass/issue-4929.rs deleted file mode 100644 index 5803c3da6cc..00000000000 --- a/src/test/run-pass/issue-4929.rs +++ /dev/null @@ -1,12 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn make_adder(x: int) -> @fn(int) -> int { |y| x + y } -pub fn main() { } diff --git a/src/test/run-pass/issue-5783.rs b/src/test/run-pass/issue-5783.rs deleted file mode 100644 index 7f988dc6489..00000000000 --- a/src/test/run-pass/issue-5783.rs +++ /dev/null @@ -1,19 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Issue #5783 -// Nondeterministic behavior when referencing a closure more than once - -fn main() { - let a: &fn(int) -> @fn(int) -> int = |x:int| |y:int| -> int x + y; - let b = a(2); - assert!(a(2)(3) == 5); - assert!(b(6) == 8); -} diff --git a/src/test/run-pass/issue4516_ty_param.rs b/src/test/run-pass/issue4516_ty_param.rs deleted file mode 100644 index 35df47df036..00000000000 --- a/src/test/run-pass/issue4516_ty_param.rs +++ /dev/null @@ -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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-fast - check-fast doesn't understand aux-build -// aux-build:issue4516_ty_param_lib.rs - -// Trigger a bug concerning inlining of generic functions. -// The def-ids in type parameters were not being correctly -// resolved and hence when we checked the type of the closure -// variable (see the library mod) to determine if the value -// should be moved into the closure, trans failed to find -// the relevant kind bounds. - -extern mod issue4516_ty_param_lib; -use issue4516_ty_param_lib::to_closure; -pub fn main() { - to_closure(22)(); -} diff --git a/src/test/run-pass/lambda-infer-unresolved.rs b/src/test/run-pass/lambda-infer-unresolved.rs index 9eecc788a69..d55150e448e 100644 --- a/src/test/run-pass/lambda-infer-unresolved.rs +++ b/src/test/run-pass/lambda-infer-unresolved.rs @@ -9,13 +9,13 @@ // except according to those terms. // This should typecheck even though the type of e is not fully -// resolved when we finish typechecking the @fn. +// resolved when we finish typechecking the &fn. struct Refs { refs: ~[int], n: int } pub fn main() { let e = @mut Refs{refs: ~[], n: 0}; - let _f: @fn() = || error!(e.n); + let _f: &fn() = || error!(e.n); e.refs.push(1); } diff --git a/src/test/run-pass/lambda-no-leak.rs b/src/test/run-pass/lambda-no-leak.rs deleted file mode 100644 index e19503240f0..00000000000 --- a/src/test/run-pass/lambda-no-leak.rs +++ /dev/null @@ -1,17 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Make sure we don't leak @fns in silly ways. -fn force(f: @fn()) { f() } -pub fn main() { - let x = 7; - let _f: @fn() = || error!(x); - force(|| error!(x)); -} diff --git a/src/test/run-pass/last-use-in-cap-clause.rs b/src/test/run-pass/last-use-in-cap-clause.rs index 75c3008af8e..d014a3cf1a1 100644 --- a/src/test/run-pass/last-use-in-cap-clause.rs +++ b/src/test/run-pass/last-use-in-cap-clause.rs @@ -12,10 +12,10 @@ struct A { a: ~int } -fn foo() -> @fn() -> int { +fn foo() -> &'static fn() -> int { let k = ~22; let _u = A {a: k.clone()}; - let result: @fn() -> int = || 22; + let result: &'static fn() -> int = || 22; result } diff --git a/src/test/run-pass/last-use-is-capture.rs b/src/test/run-pass/last-use-is-capture.rs index 2c62b6894d0..079d2374a29 100644 --- a/src/test/run-pass/last-use-is-capture.rs +++ b/src/test/run-pass/last-use-is-capture.rs @@ -13,7 +13,7 @@ struct A { a: ~int } pub fn main() { - fn invoke(f: @fn()) { f(); } + fn invoke(f: &fn()) { f(); } let k = ~22; let _u = A {a: k.clone()}; invoke(|| error!(k.clone()) ) diff --git a/src/test/run-pass/monomorphize-trait-in-fn-at.rs b/src/test/run-pass/monomorphize-trait-in-fn-at.rs deleted file mode 100644 index 8e36b1138bd..00000000000 --- a/src/test/run-pass/monomorphize-trait-in-fn-at.rs +++ /dev/null @@ -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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// test that invoking functions which require -// dictionaries from inside an @fn works -// (at one point, it didn't) - -fn mk_nil(cx: C) -> uint { - cx.mk() -} - -trait ty_ops { - fn mk(&self) -> uint; -} - -impl ty_ops for () { - fn mk(&self) -> uint { 22u } -} - -pub fn main() { - let fn_env: @fn() -> uint = || mk_nil(()); - assert_eq!(fn_env(), 22u); -} diff --git a/src/test/run-pass/move-nullary-fn.rs b/src/test/run-pass/move-nullary-fn.rs index 464d915b2c4..87281c2fd22 100644 --- a/src/test/run-pass/move-nullary-fn.rs +++ b/src/test/run-pass/move-nullary-fn.rs @@ -9,9 +9,9 @@ // except according to those terms. // Issue #922 -fn f2(_thing: @fn()) { } +fn f2(_thing: &fn()) { } -fn f(thing: @fn()) { +fn f(thing: &fn()) { f2(thing); } diff --git a/src/test/run-pass/newlambdas-ret-infer.rs b/src/test/run-pass/newlambdas-ret-infer.rs index 10ac45922aa..6d6757890ad 100644 --- a/src/test/run-pass/newlambdas-ret-infer.rs +++ b/src/test/run-pass/newlambdas-ret-infer.rs @@ -11,8 +11,6 @@ // Test that the lambda kind is inferred correctly as a return // expression -fn shared() -> @fn() { return || (); } - fn unique() -> ~fn() { return || (); } pub fn main() { diff --git a/src/test/run-pass/newlambdas-ret-infer2.rs b/src/test/run-pass/newlambdas-ret-infer2.rs index 4dfe3575eb5..17ff8ce94d9 100644 --- a/src/test/run-pass/newlambdas-ret-infer2.rs +++ b/src/test/run-pass/newlambdas-ret-infer2.rs @@ -11,8 +11,6 @@ // Test that the lambda kind is inferred correctly as a return // expression -fn shared() -> @fn() { || () } - fn unique() -> ~fn() { || () } pub fn main() { diff --git a/src/test/run-pass/newlambdas.rs b/src/test/run-pass/newlambdas.rs index 9c2a223174c..d9d0daa7138 100644 --- a/src/test/run-pass/newlambdas.rs +++ b/src/test/run-pass/newlambdas.rs @@ -14,16 +14,9 @@ fn f(i: int, f: &fn(int) -> int) -> int { f(i) } fn g(_g: &fn()) { } -fn ff() -> @fn(int) -> int { - return |x| x + 1; -} - pub fn main() { assert_eq!(f(10, |a| a), 10); g(||()); assert_eq!(do f(10) |a| { a }, 10); do g() { } - let _x: @fn() -> int = || 10; - let _y: @fn(int) -> int = |a| a; - assert_eq!(ff()(10), 11); } diff --git a/src/test/run-pass/propagate-expected-type-through-block.rs b/src/test/run-pass/propagate-expected-type-through-block.rs deleted file mode 100644 index f8f824cd596..00000000000 --- a/src/test/run-pass/propagate-expected-type-through-block.rs +++ /dev/null @@ -1,12 +0,0 @@ -// Test that expected type propagates through `{}` expressions. If it -// did not, then the type of `x` would not be known and a compilation -// error would result. - -pub fn main() { - let y = ~3; - let foo: @fn(&int) -> int = { - let y = y.clone(); - |x| *x + *y - }; - assert_eq!(foo(@22), 25); -} diff --git a/src/test/run-pass/reflect-visit-data.rs b/src/test/run-pass/reflect-visit-data.rs index 2d9f4a2ff6f..cf6f12a06e5 100644 --- a/src/test/run-pass/reflect-visit-data.rs +++ b/src/test/run-pass/reflect-visit-data.rs @@ -460,9 +460,9 @@ impl TyVisitor for ptr_visit_adaptor { } fn visit_closure_ptr(&mut self, ck: uint) -> bool { - self.align_to::<@fn()>(); + self.align_to::<(uint,uint)>(); if ! self.inner.visit_closure_ptr(ck) { return false; } - self.bump_past::<@fn()>(); + self.bump_past::<(uint,uint)>(); true } } diff --git a/src/test/run-pass/regions-fn-subtyping.rs b/src/test/run-pass/regions-fn-subtyping.rs index a6b43df1f88..06c8aca4741 100644 --- a/src/test/run-pass/regions-fn-subtyping.rs +++ b/src/test/run-pass/regions-fn-subtyping.rs @@ -14,21 +14,21 @@ #[allow(unused_variable)]; // Should pass region checking. -fn ok(f: @fn(x: &uint)) { +fn ok(f: &fn(x: &uint)) { // Here, g is a function that can accept a uint pointer with // lifetime r, and f is a function that can accept a uint pointer // with any lifetime. The assignment g = f should be OK (i.e., // f's type should be a subtype of g's type), because f can be // used in any context that expects g's type. But this currently // fails. - let mut g: @fn<'r>(y: &'r uint) = |x| { }; + let mut g: &fn<'r>(y: &'r uint) = |x| { }; g = f; } // This version is the same as above, except that here, g's type is // inferred. -fn ok_inferred(f: @fn(x: &uint)) { - let mut g: @fn<'r>(x: &'r uint) = |_| {}; +fn ok_inferred(f: &fn(x: &uint)) { + let mut g: &fn<'r>(x: &'r uint) = |_| {}; g = f; } diff --git a/src/test/run-pass/unused-move-capture.rs b/src/test/run-pass/unused-move-capture.rs index dd70b7daa70..662121a0993 100644 --- a/src/test/run-pass/unused-move-capture.rs +++ b/src/test/run-pass/unused-move-capture.rs @@ -10,6 +10,6 @@ pub fn main() { let _x = ~1; - let lam_move: @fn() = || {}; + let lam_move: &fn() = || {}; lam_move(); } From 3b1d3e5bf8e2f288147fd879b37bc5e6f8c5528f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 18 Sep 2013 18:18:45 -0700 Subject: [PATCH 16/16] librustc: Fix merge fallout. --- src/libextra/rl.rs | 33 +- src/librustc/middle/trans/debuginfo.rs | 330 ++++++++++++-------- src/librustpkg/tests.rs | 7 +- src/libsyntax/ext/build.rs | 2 +- src/test/run-pass/nested-enum-same-names.rs | 16 - src/test/run-pass/rl-human-test.rs | 24 +- 6 files changed, 244 insertions(+), 168 deletions(-) diff --git a/src/libextra/rl.rs b/src/libextra/rl.rs index 7c7b6de9a3a..7662a159ba4 100644 --- a/src/libextra/rl.rs +++ b/src/libextra/rl.rs @@ -30,31 +30,40 @@ pub mod rustrt { macro_rules! locked { ($expr:expr) => { - // FIXME #9105: can't use a static mutex in pure Rust yet. - rustrt::rust_take_linenoise_lock(); - let x = $expr; - rustrt::rust_drop_linenoise_lock(); - x + { + // FIXME #9105: can't use a static mutex in pure Rust yet. + rustrt::rust_take_linenoise_lock(); + let x = $expr; + rustrt::rust_drop_linenoise_lock(); + x + } } } /// 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 + } } } @@ -62,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 { diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 272ce49a377..91f6169b419 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -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, + 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, + 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, - 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 { diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index a0e9e49e507..b8ccc49e904 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -1565,8 +1565,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", diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index aa4238ae908..ba2342d7827 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -869,7 +869,7 @@ struct Duplicator { } impl fold::ast_fold for Duplicator { - fn new_id(&self, _: NodeId) -> NodeId { + fn new_id(&self, _: NodeId) -> NodeId { ast::DUMMY_NODE_ID } } diff --git a/src/test/run-pass/nested-enum-same-names.rs b/src/test/run-pass/nested-enum-same-names.rs index 7d9b744ab0f..919b4b59dca 100644 --- a/src/test/run-pass/nested-enum-same-names.rs +++ b/src/test/run-pass/nested-enum-same-names.rs @@ -30,20 +30,4 @@ impl Foo { } } -/* -#2074 duplicate symbols with enum in boxed closure -*/ - -fn foo() { - let one: @fn() -> uint = || { - enum r { a } - a as uint - }; - let two: @fn() -> uint = || { - enum r { a } - a as uint - }; - one(); two(); -} - fn main() {} diff --git a/src/test/run-pass/rl-human-test.rs b/src/test/run-pass/rl-human-test.rs index 558e0b6820d..6a87a6502d2 100644 --- a/src/test/run-pass/rl-human-test.rs +++ b/src/test/run-pass/rl-human-test.rs @@ -22,6 +22,20 @@ use extra::rl; static HISTORY_FILE: &'static str = "rl-human-test-history.txt"; +struct TestCompleter; + +impl rl::CompletionCb for TestCompleter { + fn complete(&self, line: ~str, suggest: &fn(~str)) { + if line.is_empty() { + suggest(~"empty") + } else { + for c in line.rev_iter().take(3) { + suggest(format!("{0}{1}{1}{1}", line, c)) + } + } + } +} + fn main() { // don't run this in robot mode, but still typecheck it. if !cfg!(robot_mode) { @@ -42,14 +56,8 @@ The bool return values of each step are printed.", println!("restricting history length: {}", rl::set_history_max_len(3)); - do rl::complete |line, suggest| { - if line.is_empty() { - suggest(~"empty") - } else { - for c in line.rev_iter().take(3) { - suggest(format!("{0}{1}{1}{1}", line, c)) - } - } + unsafe { + rl::complete(@TestCompleter as @rl::CompletionCb); } println!("adding 'one': {}", rl::add_history("one"));