提交 652b3121 编写于 作者: N Niko Matsakis

more sound treatment of fn& regions; change all & to be distinct

上级 8ee79c79
......@@ -29,7 +29,7 @@ enum option<T> {
}
}
pure fn get_ref<T>(opt: &option<T>) -> &T {
pure fn get_ref<T>(opt: &r/option<T>) -> &r/T {
/*!
* Gets an immutable reference to the value inside an option.
*
......
......@@ -361,7 +361,7 @@ fn write_downgrade<U>(blk: fn(+rw_write_mode<T>) -> U) -> U {
}
/// To be called inside of the write_downgrade block.
fn downgrade(+token: rw_write_mode<T>) -> rw_read_mode<T> {
fn downgrade(+token: rw_write_mode/&a<T>) -> rw_read_mode/&a<T> {
// The rwlock should assert that the token belongs to us for us.
let state = unsafe { get_shared_immutable_state(&self.x) };
let rw_write_mode((data, t, _poison)) = token;
......
......@@ -538,7 +538,7 @@ fn write_downgrade<U>(blk: fn(+rwlock_write_mode) -> U) -> U {
}
/// To be called inside of the write_downgrade block.
fn downgrade(+token: rwlock_write_mode) -> rwlock_read_mode {
fn downgrade(+token: rwlock_write_mode/&a) -> rwlock_read_mode/&a {
if !ptr::ref_eq(self, token.lock) {
fail ~"Can't downgrade() with a different rwlock's write_mode!";
}
......
......@@ -84,9 +84,10 @@ enum def {
def_ty_param(def_id, uint),
def_binding(node_id, binding_mode),
def_use(def_id),
def_upvar(node_id /* local id of closed over var */,
def_upvar(node_id /* id of closed over var */,
@def /* closed over def */,
node_id /* expr node that creates the closure */),
node_id /* expr node that creates the closure */,
node_id /* id for the block/body of the closure expr */),
def_class(def_id, bool /* has constructor */),
def_typaram_binder(node_id), /* class, impl or trait that has ty params */
def_region(node_id),
......
......@@ -60,7 +60,7 @@ fn variant_def_ids(d: def) -> {enm: def_id, var: def_id} {
id
}
def_arg(id, _) | def_local(id, _) | def_self(id) |
def_upvar(id, _, _) | def_binding(id, _) | def_region(id)
def_upvar(id, _, _, _) | def_binding(id, _) | def_region(id)
| def_typaram_binder(id) | def_label(id) => {
local_def(id)
}
......@@ -382,7 +382,7 @@ fn accept<E>(e: E, v: visit::vt<E>) {
fn is_self(d: ast::def) -> bool {
match d {
def_self(_) => true,
def_upvar(_, d, _) => is_self(*d),
def_upvar(_, d, _, _) => is_self(*d),
_ => false
}
}
......
......@@ -207,9 +207,6 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
if upto == cu_typeck { return {crate: crate, tcx: some(ty_cx)}; }
time(time_passes, ~"block-use checking", ||
middle::block_use::check_crate(ty_cx, crate));
time(time_passes, ~"loop checking", ||
middle::check_loop::check_crate(ty_cx, crate));
......
......@@ -128,7 +128,11 @@ fn parse_substs(st: @pstate, conv: conv_did) -> ty::substs {
fn parse_bound_region(st: @pstate) -> ty::bound_region {
match check next(st) {
's' => ty::br_self,
'a' => ty::br_anon,
'a' => {
let id = parse_int(st) as uint;
assert next(st) == '|';
ty::br_anon(id)
}
'[' => ty::br_named(@parse_str(st, ']')),
'c' => {
let id = parse_int(st);
......
......@@ -154,7 +154,11 @@ fn enc_region(w: io::Writer, cx: @ctxt, r: ty::region) {
fn enc_bound_region(w: io::Writer, br: ty::bound_region) {
match br {
ty::br_self => w.write_char('s'),
ty::br_anon => w.write_char('a'),
ty::br_anon(idx) => {
w.write_char('a');
w.write_uint(idx);
w.write_char('|');
}
ty::br_named(s) => {
w.write_char('[');
w.write_str(*s);
......
......@@ -363,8 +363,11 @@ fn tr(xcx: extended_decode_ctxt) -> ast::def {
ast::def_ty_param(did, v) => ast::def_ty_param(did.tr(xcx), v),
ast::def_binding(nid, bm) => ast::def_binding(xcx.tr_id(nid), bm),
ast::def_use(did) => ast::def_use(did.tr(xcx)),
ast::def_upvar(nid1, def, nid2) => {
ast::def_upvar(xcx.tr_id(nid1), @(*def).tr(xcx), xcx.tr_id(nid2))
ast::def_upvar(nid1, def, nid2, nid3) => {
ast::def_upvar(xcx.tr_id(nid1),
@(*def).tr(xcx),
xcx.tr_id(nid2),
xcx.tr_id(nid3))
}
ast::def_class(did, has_constructor) => {
ast::def_class(did.tr(xcx), has_constructor)
......
import syntax::visit;
import syntax::ast::*;
import driver::session::session;
type ctx = {tcx: ty::ctxt, mut allow_block: bool};
fn check_crate(tcx: ty::ctxt, crate: @crate) {
let cx = {tcx: tcx, mut allow_block: false};
let v = visit::mk_vt(@{visit_expr: visit_expr
with *visit::default_visitor()});
visit::visit_crate(*crate, cx, v);
}
fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
if !cx.allow_block {
match ty::get(ty::expr_ty(cx.tcx, ex)).struct {
ty::ty_fn({proto: p, _}) if ty::is_blockish(p) => {
cx.tcx.sess.span_err(ex.span,
~"expressions with stack closure type \
can only appear in callee or (by-ref) argument position");
}
_ => {}
}
}
let outer = cx.allow_block;
match ex.node {
expr_call(f, args, _) => {
cx.allow_block = true;
v.visit_expr(f, cx, v);
let mut i = 0u;
for ty::ty_fn_args(ty::expr_ty(cx.tcx, f)).each |arg_t| {
cx.allow_block = (ty::arg_mode(cx.tcx, arg_t) == by_ref);
v.visit_expr(args[i], cx, v);
i += 1u;
}
}
expr_loop_body(body) | expr_do_body(body) => {
cx.allow_block = true;
v.visit_expr(body, cx, v);
}
_ => {
cx.allow_block = false;
visit::visit_expr(ex, cx, v);
}
}
cx.allow_block = outer;
}
......@@ -55,7 +55,7 @@ fn ignore_item(_i: @ast::item, &&_depth: int, _v: visit::vt<int>) { }
let mut def = df;
while i < depth {
match copy def {
ast::def_upvar(_, inner, _) => { def = *inner; }
ast::def_upvar(_, inner, _, _) => { def = *inner; }
_ => break
}
i += 1;
......
......@@ -426,7 +426,7 @@ fn check_imm_free_var(cx: ctx, def: def, sp: span) {
}
}
}
def_upvar(_, def1, _) => {
def_upvar(_, def1, _, _) => {
check_imm_free_var(cx, *def1, sp);
}
def_binding(*) | def_self(*) => { /*ok*/ }
......
......@@ -378,7 +378,7 @@ fn cat_def(id: ast::node_id,
mutbl:m_imm, ty:expr_ty}
}
ast::def_upvar(upvid, inner, fn_node_id) => {
ast::def_upvar(upvid, inner, fn_node_id, _) => {
let ty = ty::node_id_to_type(self.tcx, fn_node_id);
let proto = ty::ty_fn_proto(ty);
match proto {
......
......@@ -199,7 +199,7 @@ enum RibKind {
// We passed through a function scope at the given node ID. Translate
// upvars as appropriate.
FunctionRibKind(node_id),
FunctionRibKind(node_id /* func id */, node_id /* body id */),
// We passed through a class, impl, or trait and are now in one of its
// methods. Allow references to ty params that that class, impl or trait
......@@ -2752,11 +2752,12 @@ fn upvarify(ribs: @DVec<@Rib>, rib_index: uint, def_like: def_like,
NormalRibKind => {
// Nothing to do. Continue.
}
FunctionRibKind(function_id) => {
FunctionRibKind(function_id, body_id) => {
if !is_ty_param {
def = def_upvar(def_id_of_def(def).node,
@def,
function_id);
function_id,
body_id);
}
}
MethodRibKind(item_id, method_id) => {
......@@ -4164,7 +4165,7 @@ fn resolve_expr(expr: @expr, visitor: ResolveVisitor) {
expr_fn(_, fn_decl, block, capture_clause) |
expr_fn_block(fn_decl, block, capture_clause) => {
self.resolve_function(FunctionRibKind(expr.id),
self.resolve_function(FunctionRibKind(expr.id, block.node.id),
some(@fn_decl),
NoTypeParameters,
block,
......
......@@ -2464,7 +2464,7 @@ fn take_local(table: hashmap<ast::node_id, local_val>,
}
}
match def {
ast::def_upvar(nid, _, _) => {
ast::def_upvar(nid, _, _, _) => {
assert (cx.fcx.llupvars.contains_key(nid));
return { val: cx.fcx.llupvars.get(nid), kind: lv_owned };
}
......
......@@ -961,7 +961,8 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
let fty = ty::mk_fn(bcx.tcx(), {
purity: ast::impure_fn,
proto:
ty::proto_vstore(ty::vstore_slice(ty::re_bound(ty::br_anon))),
ty::proto_vstore(ty::vstore_slice(
ty::re_bound(ty::br_anon(0)))),
bounds: @~[],
inputs: ~[{
mode: ast::expl(ast::by_val),
......
......@@ -525,7 +525,7 @@ fn expr_to_constr_arg(tcx: ty::ctxt, e: @expr) -> @constr_arg_use {
expr_path(p) {
match tcx.def_map.find(e.id) {
some(def_local(nid, _)) | some(def_arg(nid, _)) |
some(def_binding(nid, _)) | some(def_upvar(nid, _, _)) {
some(def_binding(nid, _)) | some(def_upvar(nid, _, _, _)) {
return @respan(p.span,
carg_ident({ident: p.idents[0], node: nid}));
}
......
......@@ -377,8 +377,8 @@ enum bound_region {
/// The self region for classes, impls (&T in a type defn or &self/T)
br_self,
/// Anonymous region parameter for a given fn (&T)
br_anon,
/// An anonymous region parameter for a given fn (&T)
br_anon(uint),
/// Named region parameters for functions (a in &a/T)
br_named(ast::ident),
......@@ -2192,9 +2192,10 @@ fn index_sty(cx: ctxt, sty: &sty) -> option<mt> {
pure fn hash_bound_region(br: &bound_region) -> uint {
match *br { // no idea if this is any good
ty::br_self => 0u,
ty::br_anon => 1u,
ty::br_named(str) => str::hash(str),
ty::br_cap_avoid(id, br) => id as uint | hash_bound_region(br)
ty::br_anon(idx) => 1u | (idx << 2),
ty::br_named(str) => 2u | (str::hash(str) << 2),
ty::br_cap_avoid(id, br) =>
3u | (id as uint << 2) | hash_bound_region(br)
}
}
......
......@@ -2304,7 +2304,7 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
ast::def_ty(_) | ast::def_prim_ty(_) => {
fcx.ccx.tcx.sess.span_fatal(sp, ~"expected value but found type");
}
ast::def_upvar(_, inner, _) => {
ast::def_upvar(_, inner, _, _) => {
return ty_param_bounds_and_ty_for_def(fcx, sp, *inner);
}
ast::def_ty_param(did, n) => {
......@@ -2513,7 +2513,8 @@ fn arg(m: ast::rmode, ty: ty::t) -> ty::arg {
let fty = ty::mk_fn(ccx.tcx, {
purity: ast::impure_fn,
proto:
ty::proto_vstore(ty::vstore_slice(ty::re_bound(ty::br_anon))),
ty::proto_vstore(ty::vstore_slice(
ty::re_bound(ty::br_anon(0)))),
bounds: @~[],
inputs: ~[{
mode: ast::expl(ast::by_val),
......
......@@ -21,12 +21,42 @@
import ppaux::{note_and_explain_region, ty_to_str};
import syntax::print::pprust;
import infer::{resolve_and_force_all_but_regions, fres};
import syntax::ast::{def_arg, def_binding, def_local, def_self, def_upvar};
import middle::freevars::get_freevars;
import middle::kind::check_owned;
import middle::pat_util::pat_bindings;
import middle::ty::{encl_region, proto_bare, proto_vstore, re_scope};
import middle::ty::{ty_fn_proto, vstore_box, vstore_fixed, vstore_slice};
import middle::ty::{vstore_uniq};
enum rcx { rcx_({fcx: @fn_ctxt, mut errors_reported: uint}) }
type rvt = visit::vt<@rcx>;
fn encl_region_of_def(fcx: @fn_ctxt, def: ast::def) -> ty::region {
let tcx = fcx.tcx();
match def {
def_local(node_id, _) | def_arg(node_id, _) | def_self(node_id) |
def_binding(node_id, _) =>
return encl_region(tcx, node_id),
def_upvar(local_id, subdef, closure_id, body_id) => {
match ty_fn_proto(fcx.node_ty(closure_id)) {
proto_bare =>
tcx.sess.bug(~"proto_bare in encl_region_of_def?!"),
proto_vstore(vstore_fixed(_)) =>
tcx.sess.bug(~"vstore_fixed in encl_region_of_def?!"),
proto_vstore(vstore_slice(_)) =>
encl_region_of_def(fcx, *subdef),
proto_vstore(vstore_uniq) | proto_vstore(vstore_box) =>
re_scope(body_id)
}
}
_ => {
tcx.sess.bug(fmt!("unexpected def in encl_region_of_def: %?",
def))
}
}
}
impl @rcx {
/// Try to resolve the type for the given node.
///
......@@ -180,6 +210,22 @@ fn visit_expr(e: @ast::expr, &&rcx: @rcx, v: rvt) {
// See #3148 for more details.
}
ast::expr_fn(*) | ast::expr_fn_block(*) => {
match rcx.resolve_node_type(e.id) {
result::err(_) => return, // Typechecking will fail anyhow.
result::ok(function_type) => {
match ty::get(function_type).struct {
ty::ty_fn({
proto: proto_vstore(vstore_slice(region)), _
}) => {
constrain_free_variables(rcx, region, e);
}
_ => ()
}
}
}
}
_ => ()
}
......@@ -217,6 +263,39 @@ fn visit_node(id: ast::node_id, span: span, rcx: @rcx) -> bool {
return constrain_regions_in_type(rcx, encl_region, span, ty);
}
fn constrain_free_variables(
rcx: @rcx,
region: ty::region,
expr: @ast::expr)
{
// Make sure that all regions referenced by the free
// variables inside the closure outlive the closure
// itself.
let tcx = rcx.fcx.ccx.tcx;
for get_freevars(tcx, expr.id).each |freevar| {
debug!("freevar def is %?", freevar.def);
let def = freevar.def;
let en_region = encl_region_of_def(rcx.fcx, def);
match rcx.fcx.mk_subr(true, freevar.span,
region, en_region) {
result::ok(()) => {}
result::err(_) => {
tcx.sess.span_err(
freevar.span,
~"captured variable does not outlive the enclosing closure");
note_and_explain_region(
tcx,
~"captured variable is valid for",
en_region);
note_and_explain_region(
tcx,
~"closure is valid for",
region);
}
}
}
}
fn constrain_regions_in_type(
rcx: @rcx,
encl_region: ty::region,
......
......@@ -148,7 +148,7 @@ fn replace_bound_regions(
// As long as we are not within a fn() type, `&T` is
// mapped to the free region anon_r. But within a fn
// type, it remains bound.
ty::re_bound(ty::br_anon) if in_fn => r,
ty::re_bound(ty::br_anon(_)) if in_fn => r,
ty::re_bound(br) => {
match isr.find(br) {
......
......@@ -321,7 +321,7 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
if !is_early { cx.vtable_map.insert(callee_id, vtbls); }
}
}
_ => ()
none => ()
}
}
ast::expr_cast(src, _) => {
......
......@@ -52,15 +52,20 @@ fn named_region(span: span, id: ast::ident) -> result<ty::region, ~str> {
}
}
enum binding_rscope = {base: region_scope};
struct binding_rscope {
base: region_scope;
mut anon_bindings: uint;
}
fn in_binding_rscope<RS: region_scope copy owned>(self: RS)
-> @binding_rscope {
let base = self as region_scope;
@binding_rscope({base: base})
@binding_rscope { base: base, anon_bindings: 0 }
}
impl @binding_rscope: region_scope {
fn anon_region(_span: span) -> result<ty::region, ~str> {
result::ok(ty::re_bound(ty::br_anon))
let idx = self.anon_bindings;
self.anon_bindings += 1;
result::ok(ty::re_bound(ty::br_anon(idx)))
}
fn named_region(span: span, id: ast::ident) -> result<ty::region, ~str> {
do self.base.named_region(span, id).chain_err |_e| {
......
......@@ -94,7 +94,6 @@ mod middle {
}
mod mem_categorization;
mod liveness;
mod block_use;
mod kind;
mod freevars;
mod capture;
......
......@@ -68,18 +68,21 @@ fn explain_region_and_span(cx: ctxt, region: ty::region)
}
re_free(id, br) => {
let prefix = match br {
br_anon(idx) => fmt!("the anonymous lifetime #%u defined on",
idx + 1),
_ => fmt!("the lifetime %s as defined on",
bound_region_to_str(cx, br))
};
match cx.items.find(id) {
some(ast_map::node_block(blk)) => {
let (msg, opt_span) = explain_span(cx, ~"block", blk.span);
(fmt!("the lifetime %s as defined on %s",
bound_region_to_str(cx, br), msg),
opt_span)
(fmt!("%s %s", prefix, msg), opt_span)
}
some(_) | none => {
// this really should not happen
(fmt!("the lifetime %s as defined on node %d",
bound_region_to_str(cx, br), id),
none)
(fmt!("%s node %d", prefix, id), none)
}
}
}
......@@ -103,10 +106,13 @@ fn explain_span(cx: ctxt, heading: ~str, span: span)
fn bound_region_to_str(cx: ctxt, br: bound_region) -> ~str {
match br {
br_anon => { ~"&" }
br_named(str) => { fmt!{"&%s", *str} }
br_self if cx.sess.ppregions() => { ~"&<self>" }
br_self => { ~"&self" }
br_named(str) => fmt!{"&%s", *str},
br_self if cx.sess.ppregions() => ~"&<self>",
br_self => ~"&self",
br_anon(idx) => {
if cx.sess.ppregions() {fmt!("&%u", idx)} else {~"&"}
}
// FIXME(#3011) -- even if this arm is removed, exhaustiveness checking
// does not fail
......
......@@ -13,7 +13,9 @@ fn item_check(t: &tree) -> int {
}
}
fn bottom_up_tree(arena: &arena::arena, item: int, depth: int) -> &tree {
fn bottom_up_tree(arena: &r/arena::arena,
item: int,
depth: int) -> &r/tree {
if depth > 0 {
return arena.alloc(
|| node(bottom_up_tree(arena, 2 * item - 1, depth - 1),
......
// error-pattern: stack closure type can only appear
fn lol(f: fn()) -> fn() { return f; }
fn main() {
let i = 8;
let f = lol(fn&() { log(error, i); });
f();
}
......@@ -8,7 +8,7 @@
fn get() -> &int {
let x = 3;
return &x;
//~^ ERROR illegal borrow: borrowed pointer must be valid for the lifetime & as defined on the block at 8:17, but the borrowed value is only valid for the block at 8:17
//~^ ERROR illegal borrow: borrowed pointer must be valid for the anonymous lifetime #1 defined on the block at 8:17, but the borrowed value is only valid for the block at 8:17
}
fn main() {}
type t<T> = { f: fn() -> T };
fn f<T>(_x: t<T>) {}
fn main() {
let x: t<()> = { f: || () }; //~ ERROR expressions with stack closure
f(x);
}
fn wants_static_fn(_x: &static/fn()) {}
fn main() {
let i = 3;
do wants_static_fn {
#debug("i=%d", i);
//~^ ERROR captured variable does not outlive the enclosing closure
}
}
......@@ -11,7 +11,7 @@ struct Flag {
mut value: uint;
}
fn flag(name: &str, desc: &str) -> Flag {
fn flag(name: &r/str, desc: &r/str) -> Flag/&r {
Flag { name: name, desc: desc, max_count: 1, value: 0 }
}
......
type point = {x: int, y: int};
fn x_coord(p: &point) -> &int {
fn x_coord(p: &r/point) -> &r/int {
return &p.x;
}
......
fn borrow<T>(x: &T) -> &T {x}
fn borrow<T>(x: &r/T) -> &r/T {x}
fn foo(cond: fn() -> bool, box: fn() -> @int) {
let mut y: &int;
......
fn select(x: &int, y: &int) -> &int { x }
fn select(x: &r/int, y: &r/int) -> &r/int { x }
fn with<T>(f: fn(x: &int) -> T) -> T {
f(&20)
......
struct closure_box {
cl: &fn();
}
fn box_it(x: &r/fn()) -> closure_box/&r {
closure_box {cl: x}
}
fn main() {
let cl_box = {
let mut i = 3;
box_it(|| i += 1) //~ ERROR cannot infer an appropriate lifetime
};
cl_box.cl();
}
fn borrow<T>(x: &T) -> &T {x}
fn borrow<T>(x: &r/T) -> &r/T {x}
fn main() {
let rec = @{mut f: @22};
......
......@@ -19,13 +19,13 @@ fn compute_area(shape: &shape) -> float {
impl shape {
// self is in the implicit self region
fn select<T>(&self, threshold: float,
a: &T, b: &T) -> &T {
a: &r/T, b: &r/T) -> &r/T {
if compute_area(self) > threshold {a} else {b}
}
}
fn select_based_on_unit_circle<T>(
threshold: float, a: &T, b: &T) -> &T {
threshold: float, a: &r/T, b: &r/T) -> &r/T {
let shape = &circle({x: 0.0, y: 0.0}, 1.0);
shape.select(threshold, a, b)
......
fn thing(x: &[int]) -> &[int] { x }
fn thing(x: &r/[int]) -> &r/[int] { x }
fn main() {
let x = &[1,2,3];
let y = x;
......
fn get<T>(opt: &option<T>) -> &T {
fn get<T>(opt: &r/option<T>) -> &r/T {
match *opt {
some(ref v) => v,
none => fail ~"none"
......
type point = { x: int, y: int };
type character = { pos: ~point };
fn get_x(x: &character) -> &int {
fn get_x(x: &r/character) -> &r/int {
// interesting case because the scope of this
// borrow of the unique pointer is in fact
// larger than the fn itself
......
struct closure_box {
cl: &fn();
}
fn box_it(x: &r/fn()) -> closure_box/&r {
closure_box {cl: x}
}
fn main() {
let mut i = 3;
let cl_box = box_it(|| i += 1);
assert i == 3;
cl_box.cl();
assert i == 4;
}
......@@ -3,7 +3,7 @@ enum ast {
add(&ast, &ast)
}
fn mk_add_ok(x: &ast, y: &ast) -> ast {
fn mk_add_ok(x: &r/ast, y: &r/ast) -> ast/&r {
add(x, y)
}
......
fn foo(x: &uint) -> &uint { x }
fn foo(x: &r/uint) -> &r/uint { x }
fn bar(x: &uint) -> uint { *x }
fn main() {
......
fn view<T>(x: &[T]) -> &[T] {x}
fn view<T>(x: &r/[T]) -> &r/[T] {x}
fn main() {
let v = ~[1, 2, 3];
......
fn borrow<T>(x: &T) -> &T {x}
fn borrow<T>(x: &r/T) -> &r/T {x}
fn main() {
let x = @3;
......
type point = {x: int, y: int};
fn x_coord(p: &point) -> &int {
fn x_coord(p: &r/point) -> &r/int {
return &p.x;
}
......
......@@ -15,7 +15,7 @@
x: int
};
fn h(bcx : &bcx) -> &bcx {
fn h(bcx : &r/bcx) -> &r/bcx {
return bcx.fcx.arena.alloc(|| { fcx: bcx.fcx });
}
......
......@@ -2,7 +2,7 @@ enum roption {
a, b(&uint)
}
fn mk(cond: bool, ptr: &uint) -> roption {
fn mk(cond: bool, ptr: &r/uint) -> roption/&r {
if cond {a} else {b(ptr)}
}
......
fn region_identity(x: &uint) -> &uint { x }
fn region_identity(x: &r/uint) -> &r/uint { x }
fn apply<T>(t: T, f: fn(T) -> T) -> T { f(t) }
......
struct closure_box {
cl: &fn();
}
fn box_it(x: &r/fn()) -> closure_box/&r {
closure_box {cl: x}
}
fn call_static_closure(cl: closure_box/&static) {
cl.cl();
}
fn main() {
let cl_box = box_it(|| debug!("Hello, world!"));
call_static_closure(cl_box);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册