From 652b312122139501ae513e9c985d9c31030684b3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 20 Aug 2012 16:53:33 -0700 Subject: [PATCH] more sound treatment of fn& regions; change all & to be distinct --- src/libcore/option.rs | 2 +- src/libstd/arc.rs | 2 +- src/libstd/sync.rs | 2 +- src/libsyntax/ast.rs | 5 +- src/libsyntax/ast_util.rs | 8 +- src/rustc/driver/driver.rs | 3 - src/rustc/metadata/tydecode.rs | 6 +- src/rustc/metadata/tyencode.rs | 6 +- src/rustc/middle/astencode.rs | 7 +- src/rustc/middle/block_use.rs | 47 ----------- src/rustc/middle/freevars.rs | 2 +- src/rustc/middle/kind.rs | 4 +- src/rustc/middle/mem_categorization.rs | 2 +- src/rustc/middle/resolve3.rs | 9 ++- src/rustc/middle/trans/base.rs | 2 +- src/rustc/middle/trans/foreign.rs | 3 +- src/rustc/middle/tstate/auxiliary.rs | 2 +- src/rustc/middle/ty.rs | 11 +-- src/rustc/middle/typeck/check.rs | 5 +- src/rustc/middle/typeck/check/regionck.rs | 79 +++++++++++++++++++ src/rustc/middle/typeck/check/regionmanip.rs | 2 +- src/rustc/middle/typeck/check/vtable.rs | 2 +- src/rustc/middle/typeck/rscope.rs | 11 ++- src/rustc/rustc.rc | 1 - src/rustc/util/ppaux.rs | 26 +++--- src/test/bench/shootout-binarytrees.rs | 4 +- src/test/compile-fail/block-copy.rs | 8 -- .../compile-fail/borrowck-confuse-region.rs | 2 +- src/test/compile-fail/issue-1896.rs | 8 -- src/test/compile-fail/regions-freevar.rs | 9 +++ .../compile-fail/regions-glb-free-free.rs | 2 +- .../regions-infer-borrow-scope-too-big.rs | 2 +- .../regions-infer-borrow-scope-within-loop.rs | 2 +- src/test/compile-fail/regions-infer-call-3.rs | 2 +- .../compile-fail/regions-steal-closure.rs | 15 ++++ src/test/run-pass/borrowck-root-while-cond.rs | 2 +- src/test/run-pass/explicit-self.rs | 4 +- src/test/run-pass/issue-2748-b.rs | 2 +- .../region-return-interior-of-option.rs | 2 +- .../regions-addr-of-interior-of-unique-box.rs | 2 +- src/test/run-pass/regions-copy-closure.rs | 15 ++++ src/test/run-pass/regions-creating-enums2.rs | 2 +- .../run-pass/regions-escape-into-other-fn.rs | 2 +- .../regions-infer-borrow-scope-view.rs | 2 +- ...gions-infer-borrow-scope-within-loop-ok.rs | 2 +- .../run-pass/regions-infer-borrow-scope.rs | 2 +- src/test/run-pass/regions-mock-trans-impls.rs | 2 +- src/test/run-pass/regions-nullary-variant.rs | 2 +- src/test/run-pass/regions-params.rs | 2 +- src/test/run-pass/regions-static-closure.rs | 16 ++++ 50 files changed, 229 insertions(+), 133 deletions(-) delete mode 100644 src/rustc/middle/block_use.rs delete mode 100644 src/test/compile-fail/block-copy.rs delete mode 100644 src/test/compile-fail/issue-1896.rs create mode 100644 src/test/compile-fail/regions-freevar.rs create mode 100644 src/test/compile-fail/regions-steal-closure.rs create mode 100644 src/test/run-pass/regions-copy-closure.rs create mode 100644 src/test/run-pass/regions-static-closure.rs diff --git a/src/libcore/option.rs b/src/libcore/option.rs index bae84796b16..b1552f26c67 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -29,7 +29,7 @@ enum option { } } -pure fn get_ref(opt: &option) -> &T { +pure fn get_ref(opt: &r/option) -> &r/T { /*! * Gets an immutable reference to the value inside an option. * diff --git a/src/libstd/arc.rs b/src/libstd/arc.rs index 355567e07e2..811c157498d 100644 --- a/src/libstd/arc.rs +++ b/src/libstd/arc.rs @@ -361,7 +361,7 @@ fn write_downgrade(blk: fn(+rw_write_mode) -> U) -> U { } /// To be called inside of the write_downgrade block. - fn downgrade(+token: rw_write_mode) -> rw_read_mode { + fn downgrade(+token: rw_write_mode/&a) -> rw_read_mode/&a { // 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; diff --git a/src/libstd/sync.rs b/src/libstd/sync.rs index 1438e4ab180..bd0e815d325 100644 --- a/src/libstd/sync.rs +++ b/src/libstd/sync.rs @@ -538,7 +538,7 @@ fn write_downgrade(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!"; } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index cb46f6feabc..c7ff6671e0f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -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), diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 0495ea7cd34..d949c546155 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -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) } @@ -381,9 +381,9 @@ fn accept(e: E, v: visit::vt) { referring to a def_self */ fn is_self(d: ast::def) -> bool { match d { - def_self(_) => true, - def_upvar(_, d, _) => is_self(*d), - _ => false + def_self(_) => true, + def_upvar(_, d, _, _) => is_self(*d), + _ => false } } diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index 46add230d9a..36df337a4d4 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -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)); diff --git a/src/rustc/metadata/tydecode.rs b/src/rustc/metadata/tydecode.rs index cb9a6b0ad13..a61e111cca9 100644 --- a/src/rustc/metadata/tydecode.rs +++ b/src/rustc/metadata/tydecode.rs @@ -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); diff --git a/src/rustc/metadata/tyencode.rs b/src/rustc/metadata/tyencode.rs index 5a24b9af8d9..68fe7fc4d65 100644 --- a/src/rustc/metadata/tyencode.rs +++ b/src/rustc/metadata/tyencode.rs @@ -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); diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs index 342113a17b1..3b1525c03f8 100644 --- a/src/rustc/middle/astencode.rs +++ b/src/rustc/middle/astencode.rs @@ -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) diff --git a/src/rustc/middle/block_use.rs b/src/rustc/middle/block_use.rs deleted file mode 100644 index bb33b8c92a8..00000000000 --- a/src/rustc/middle/block_use.rs +++ /dev/null @@ -1,47 +0,0 @@ -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) { - 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; -} diff --git a/src/rustc/middle/freevars.rs b/src/rustc/middle/freevars.rs index 4c81ec30392..60489085bd9 100644 --- a/src/rustc/middle/freevars.rs +++ b/src/rustc/middle/freevars.rs @@ -55,7 +55,7 @@ fn ignore_item(_i: @ast::item, &&_depth: int, _v: visit::vt) { } 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; diff --git a/src/rustc/middle/kind.rs b/src/rustc/middle/kind.rs index 15882d5e9fa..01d8887f691 100644 --- a/src/rustc/middle/kind.rs +++ b/src/rustc/middle/kind.rs @@ -103,7 +103,7 @@ fn check_for_uniq(cx: ctx, id: node_id, fv: option<@freevar_entry>, // copied in data must be copyable, but moved in data can be anything let is_implicit = fv.is_some(); - if !is_move { check_copy(cx, id, var_t, sp, is_implicit); } + if !is_move { check_copy(cx, id, var_t, sp, is_implicit); } // check that only immutable variables are implicitly copied in for fv.each |fv| { @@ -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*/ } diff --git a/src/rustc/middle/mem_categorization.rs b/src/rustc/middle/mem_categorization.rs index 5ffc36f4160..c98e65f38cf 100644 --- a/src/rustc/middle/mem_categorization.rs +++ b/src/rustc/middle/mem_categorization.rs @@ -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 { diff --git a/src/rustc/middle/resolve3.rs b/src/rustc/middle/resolve3.rs index bfd9f720380..ad63be3b142 100644 --- a/src/rustc/middle/resolve3.rs +++ b/src/rustc/middle/resolve3.rs @@ -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, diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 0e068f68312..cf813d108ea 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -2464,7 +2464,7 @@ fn take_local(table: hashmap, } } 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 }; } diff --git a/src/rustc/middle/trans/foreign.rs b/src/rustc/middle/trans/foreign.rs index fdde26d6718..77afcc6fc93 100644 --- a/src/rustc/middle/trans/foreign.rs +++ b/src/rustc/middle/trans/foreign.rs @@ -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), diff --git a/src/rustc/middle/tstate/auxiliary.rs b/src/rustc/middle/tstate/auxiliary.rs index 209e6fb2440..fc9a84571b7 100644 --- a/src/rustc/middle/tstate/auxiliary.rs +++ b/src/rustc/middle/tstate/auxiliary.rs @@ -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})); } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 1415084c22e..70473f52d69 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -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 { 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) } } diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index a810478788c..e1e8af26546 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -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), diff --git a/src/rustc/middle/typeck/check/regionck.rs b/src/rustc/middle/typeck/check/regionck.rs index fc0112ddc8d..4b115f375c4 100644 --- a/src/rustc/middle/typeck/check/regionck.rs +++ b/src/rustc/middle/typeck/check/regionck.rs @@ -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, diff --git a/src/rustc/middle/typeck/check/regionmanip.rs b/src/rustc/middle/typeck/check/regionmanip.rs index 5b09dd48d37..888e04d5eef 100644 --- a/src/rustc/middle/typeck/check/regionmanip.rs +++ b/src/rustc/middle/typeck/check/regionmanip.rs @@ -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) { diff --git a/src/rustc/middle/typeck/check/vtable.rs b/src/rustc/middle/typeck/check/vtable.rs index fa0acf79dbe..a2daf107dfe 100644 --- a/src/rustc/middle/typeck/check/vtable.rs +++ b/src/rustc/middle/typeck/check/vtable.rs @@ -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, _) => { diff --git a/src/rustc/middle/typeck/rscope.rs b/src/rustc/middle/typeck/rscope.rs index 4d33585d47c..b3c275e415b 100644 --- a/src/rustc/middle/typeck/rscope.rs +++ b/src/rustc/middle/typeck/rscope.rs @@ -52,15 +52,20 @@ fn named_region(span: span, id: ast::ident) -> result { } } -enum binding_rscope = {base: region_scope}; +struct binding_rscope { + base: region_scope; + mut anon_bindings: uint; +} fn in_binding_rscope(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 { - 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 { do self.base.named_region(span, id).chain_err |_e| { diff --git a/src/rustc/rustc.rc b/src/rustc/rustc.rc index a69e2ce88fa..fd6e86c5b8c 100644 --- a/src/rustc/rustc.rc +++ b/src/rustc/rustc.rc @@ -94,7 +94,6 @@ mod middle { } mod mem_categorization; mod liveness; - mod block_use; mod kind; mod freevars; mod capture; diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs index 76c34d9ca25..f3aee60f291 100644 --- a/src/rustc/util/ppaux.rs +++ b/src/rustc/util/ppaux.rs @@ -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() => { ~"&" } - br_self => { ~"&self" } + br_named(str) => fmt!{"&%s", *str}, + br_self if cx.sess.ppregions() => ~"&", + 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 diff --git a/src/test/bench/shootout-binarytrees.rs b/src/test/bench/shootout-binarytrees.rs index c9a984117da..c9f1ca832a3 100644 --- a/src/test/bench/shootout-binarytrees.rs +++ b/src/test/bench/shootout-binarytrees.rs @@ -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), diff --git a/src/test/compile-fail/block-copy.rs b/src/test/compile-fail/block-copy.rs deleted file mode 100644 index 964ea5c7750..00000000000 --- a/src/test/compile-fail/block-copy.rs +++ /dev/null @@ -1,8 +0,0 @@ -// 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(); -} diff --git a/src/test/compile-fail/borrowck-confuse-region.rs b/src/test/compile-fail/borrowck-confuse-region.rs index 5183b4b39e5..0f7323358d7 100644 --- a/src/test/compile-fail/borrowck-confuse-region.rs +++ b/src/test/compile-fail/borrowck-confuse-region.rs @@ -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() {} diff --git a/src/test/compile-fail/issue-1896.rs b/src/test/compile-fail/issue-1896.rs deleted file mode 100644 index f01d5b23f84..00000000000 --- a/src/test/compile-fail/issue-1896.rs +++ /dev/null @@ -1,8 +0,0 @@ -type t = { f: fn() -> T }; - -fn f(_x: t) {} - -fn main() { - let x: t<()> = { f: || () }; //~ ERROR expressions with stack closure - f(x); -} diff --git a/src/test/compile-fail/regions-freevar.rs b/src/test/compile-fail/regions-freevar.rs new file mode 100644 index 00000000000..dc2a43cc7db --- /dev/null +++ b/src/test/compile-fail/regions-freevar.rs @@ -0,0 +1,9 @@ +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 + } +} diff --git a/src/test/compile-fail/regions-glb-free-free.rs b/src/test/compile-fail/regions-glb-free-free.rs index 653b7941bfe..881e975d75f 100644 --- a/src/test/compile-fail/regions-glb-free-free.rs +++ b/src/test/compile-fail/regions-glb-free-free.rs @@ -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 } } diff --git a/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs b/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs index dd2968504ee..e601e6c87fd 100644 --- a/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs +++ b/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs @@ -1,6 +1,6 @@ type point = {x: int, y: int}; -fn x_coord(p: &point) -> &int { +fn x_coord(p: &r/point) -> &r/int { return &p.x; } diff --git a/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs b/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs index 4342fa6e961..57e195a9075 100644 --- a/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs +++ b/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs @@ -1,4 +1,4 @@ -fn borrow(x: &T) -> &T {x} +fn borrow(x: &r/T) -> &r/T {x} fn foo(cond: fn() -> bool, box: fn() -> @int) { let mut y: ∫ diff --git a/src/test/compile-fail/regions-infer-call-3.rs b/src/test/compile-fail/regions-infer-call-3.rs index c95ce2cd343..17c43f7c5d3 100644 --- a/src/test/compile-fail/regions-infer-call-3.rs +++ b/src/test/compile-fail/regions-infer-call-3.rs @@ -1,4 +1,4 @@ -fn select(x: &int, y: &int) -> &int { x } +fn select(x: &r/int, y: &r/int) -> &r/int { x } fn with(f: fn(x: &int) -> T) -> T { f(&20) diff --git a/src/test/compile-fail/regions-steal-closure.rs b/src/test/compile-fail/regions-steal-closure.rs new file mode 100644 index 00000000000..f0c5124630a --- /dev/null +++ b/src/test/compile-fail/regions-steal-closure.rs @@ -0,0 +1,15 @@ +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(); +} diff --git a/src/test/run-pass/borrowck-root-while-cond.rs b/src/test/run-pass/borrowck-root-while-cond.rs index 07016d1bf0d..f8f63a71315 100644 --- a/src/test/run-pass/borrowck-root-while-cond.rs +++ b/src/test/run-pass/borrowck-root-while-cond.rs @@ -1,4 +1,4 @@ -fn borrow(x: &T) -> &T {x} +fn borrow(x: &r/T) -> &r/T {x} fn main() { let rec = @{mut f: @22}; diff --git a/src/test/run-pass/explicit-self.rs b/src/test/run-pass/explicit-self.rs index 7bf490c3da2..cd9f486c9aa 100644 --- a/src/test/run-pass/explicit-self.rs +++ b/src/test/run-pass/explicit-self.rs @@ -19,13 +19,13 @@ fn compute_area(shape: &shape) -> float { impl shape { // self is in the implicit self region fn select(&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( - 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) diff --git a/src/test/run-pass/issue-2748-b.rs b/src/test/run-pass/issue-2748-b.rs index a1bcdc5cd5d..99405b6548e 100644 --- a/src/test/run-pass/issue-2748-b.rs +++ b/src/test/run-pass/issue-2748-b.rs @@ -1,4 +1,4 @@ -fn thing(x: &[int]) -> &[int] { x } +fn thing(x: &r/[int]) -> &r/[int] { x } fn main() { let x = &[1,2,3]; let y = x; diff --git a/src/test/run-pass/region-return-interior-of-option.rs b/src/test/run-pass/region-return-interior-of-option.rs index 948a456183b..c737bc16097 100644 --- a/src/test/run-pass/region-return-interior-of-option.rs +++ b/src/test/run-pass/region-return-interior-of-option.rs @@ -1,4 +1,4 @@ -fn get(opt: &option) -> &T { +fn get(opt: &r/option) -> &r/T { match *opt { some(ref v) => v, none => fail ~"none" diff --git a/src/test/run-pass/regions-addr-of-interior-of-unique-box.rs b/src/test/run-pass/regions-addr-of-interior-of-unique-box.rs index 2fa7db00815..924df9f7067 100644 --- a/src/test/run-pass/regions-addr-of-interior-of-unique-box.rs +++ b/src/test/run-pass/regions-addr-of-interior-of-unique-box.rs @@ -1,7 +1,7 @@ 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 diff --git a/src/test/run-pass/regions-copy-closure.rs b/src/test/run-pass/regions-copy-closure.rs new file mode 100644 index 00000000000..35c7930d729 --- /dev/null +++ b/src/test/run-pass/regions-copy-closure.rs @@ -0,0 +1,15 @@ +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; +} diff --git a/src/test/run-pass/regions-creating-enums2.rs b/src/test/run-pass/regions-creating-enums2.rs index b03205e1596..d77ae1ed4f4 100644 --- a/src/test/run-pass/regions-creating-enums2.rs +++ b/src/test/run-pass/regions-creating-enums2.rs @@ -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) } diff --git a/src/test/run-pass/regions-escape-into-other-fn.rs b/src/test/run-pass/regions-escape-into-other-fn.rs index 8f71d9821fe..c9b8b89e0e8 100644 --- a/src/test/run-pass/regions-escape-into-other-fn.rs +++ b/src/test/run-pass/regions-escape-into-other-fn.rs @@ -1,4 +1,4 @@ -fn foo(x: &uint) -> &uint { x } +fn foo(x: &r/uint) -> &r/uint { x } fn bar(x: &uint) -> uint { *x } fn main() { diff --git a/src/test/run-pass/regions-infer-borrow-scope-view.rs b/src/test/run-pass/regions-infer-borrow-scope-view.rs index 4f3b668269a..257ccee7b1f 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-view.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-view.rs @@ -1,4 +1,4 @@ -fn view(x: &[T]) -> &[T] {x} +fn view(x: &r/[T]) -> &r/[T] {x} fn main() { let v = ~[1, 2, 3]; diff --git a/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs b/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs index bd51c4beca5..982c870522c 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs @@ -1,4 +1,4 @@ -fn borrow(x: &T) -> &T {x} +fn borrow(x: &r/T) -> &r/T {x} fn main() { let x = @3; diff --git a/src/test/run-pass/regions-infer-borrow-scope.rs b/src/test/run-pass/regions-infer-borrow-scope.rs index 2378052b24a..d0f2ef8253b 100644 --- a/src/test/run-pass/regions-infer-borrow-scope.rs +++ b/src/test/run-pass/regions-infer-borrow-scope.rs @@ -1,6 +1,6 @@ type point = {x: int, y: int}; -fn x_coord(p: &point) -> &int { +fn x_coord(p: &r/point) -> &r/int { return &p.x; } diff --git a/src/test/run-pass/regions-mock-trans-impls.rs b/src/test/run-pass/regions-mock-trans-impls.rs index 9cc4e2abca9..3b3ae8a282a 100644 --- a/src/test/run-pass/regions-mock-trans-impls.rs +++ b/src/test/run-pass/regions-mock-trans-impls.rs @@ -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 }); } diff --git a/src/test/run-pass/regions-nullary-variant.rs b/src/test/run-pass/regions-nullary-variant.rs index 6d6d7b65a3f..f4db8a55bfa 100644 --- a/src/test/run-pass/regions-nullary-variant.rs +++ b/src/test/run-pass/regions-nullary-variant.rs @@ -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)} } diff --git a/src/test/run-pass/regions-params.rs b/src/test/run-pass/regions-params.rs index 2a4987f8b45..5f2b2756fb0 100644 --- a/src/test/run-pass/regions-params.rs +++ b/src/test/run-pass/regions-params.rs @@ -1,4 +1,4 @@ -fn region_identity(x: &uint) -> &uint { x } +fn region_identity(x: &r/uint) -> &r/uint { x } fn apply(t: T, f: fn(T) -> T) -> T { f(t) } diff --git a/src/test/run-pass/regions-static-closure.rs b/src/test/run-pass/regions-static-closure.rs new file mode 100644 index 00000000000..e45952f8651 --- /dev/null +++ b/src/test/run-pass/regions-static-closure.rs @@ -0,0 +1,16 @@ +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); +} -- GitLab