rustc: Map region names to their functions. Also speed up region checking by 17x.

This commit is contained in:
Patrick Walton
2012-03-12 13:24:37 -07:00
parent db79f3c0a5
commit 864ff4707e
3 changed files with 66 additions and 43 deletions

View File

@@ -6,6 +6,8 @@
import driver::session::session; import driver::session::session;
import middle::ty; import middle::ty;
import syntax::{ast, visit}; import syntax::{ast, visit};
import util::common::new_def_hash;
import std::map; import std::map;
import std::map::hashmap; import std::map::hashmap;
@@ -27,6 +29,8 @@ type region_map = {
ast_type_to_region: hashmap<ast::node_id,ty::region>, ast_type_to_region: hashmap<ast::node_id,ty::region>,
/* Mapping from a local variable to its containing block. */ /* Mapping from a local variable to its containing block. */
local_blocks: hashmap<ast::node_id,ast::node_id>, local_blocks: hashmap<ast::node_id,ast::node_id>,
/* Mapping from a region name to its function. */
region_name_to_fn: hashmap<ast::def_id,ast::node_id>,
}; };
type ctxt = { type ctxt = {
@@ -105,9 +109,15 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
alt cx.names_in_scope.find(ident) { alt cx.names_in_scope.find(ident) {
some(def_id) { region = ty::re_named(def_id); } some(def_id) { region = ty::re_named(def_id); }
none { none {
let def_id = {crate: ast::local_crate,
node: region_id};
cx.names_in_scope.insert(ident, def_id);
region = ty::re_named(def_id);
alt cx.parent { alt cx.parent {
pa_item(_) | pa_nested_fn(_) { pa_item(fn_id) | pa_nested_fn(fn_id) {
/* ok; fall through */ let rf = cx.region_map.region_name_to_fn;
rf.insert(def_id, fn_id);
} }
pa_block(_) { pa_block(_) {
cx.sess.span_err(ty.span, cx.sess.span_err(ty.span,
@@ -120,11 +130,6 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
"level?!"); "level?!");
} }
} }
let def_id = {crate: ast::local_crate,
node: region_id};
cx.names_in_scope.insert(ident, def_id);
region = ty::re_named(def_id);
} }
} }
} }
@@ -256,7 +261,8 @@ fn resolve_crate(sess: session, def_map: resolve::def_map, crate: @ast::crate)
def_map: def_map, def_map: def_map,
region_map: @{parents: map::new_int_hash(), region_map: @{parents: map::new_int_hash(),
ast_type_to_region: map::new_int_hash(), ast_type_to_region: map::new_int_hash(),
local_blocks: map::new_int_hash()}, local_blocks: map::new_int_hash(),
region_name_to_fn: new_def_hash()},
names_in_scope: map::new_str_hash(), names_in_scope: map::new_str_hash(),
mut queued_locals: [], mut queued_locals: [],
parent: pa_crate, parent: pa_crate,

View File

@@ -22,33 +22,37 @@ type ctxt = {
}; };
fn check_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) { fn check_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
ty::walk_ty(cx.tcx, ty::expr_ty(cx.tcx, expr)) { |t| let t = ty::expr_ty(cx.tcx, expr);
alt ty::get(t).struct { if ty::type_has_rptrs(t) {
ty::ty_rptr(region, _) { ty::walk_ty(cx.tcx, t) { |t|
alt region { alt ty::get(t).struct {
ty::re_named(_) | ty::re_caller(_) { /* ok */ } ty::ty_rptr(region, _) {
ty::re_block(rbi) { alt region {
let referent_block_id = rbi; ty::re_named(_) | ty::re_caller(_) { /* ok */ }
let enclosing_block_id = alt cx.enclosing_block { ty::re_block(rbi) {
none { let referent_block_id = rbi;
cx.tcx.sess.span_bug(expr.span, "block " + let enclosing_block_id = alt cx.enclosing_block {
"region type outside " + none {
"a block?!"); cx.tcx.sess.span_bug(expr.span,
"block region " +
"type outside a " +
"block?!");
}
some(eb) { eb }
};
if !region::scope_contains(cx.tcx.region_map,
referent_block_id,
enclosing_block_id) {
cx.tcx.sess.span_err(expr.span, "reference " +
"escapes its block");
} }
some(eb) { eb }
};
if !region::scope_contains(cx.tcx.region_map,
referent_block_id,
enclosing_block_id) {
cx.tcx.sess.span_err(expr.span, "reference " +
"escapes its block");
} }
} }
} }
_ { /* no-op */ }
} }
_ { /* no-op */ }
} }
} }

View File

@@ -89,7 +89,7 @@ export ty_uniq, mk_uniq, mk_imm_uniq, type_is_unique_box;
export ty_var, mk_var; export ty_var, mk_var;
export ty_self, mk_self; export ty_self, mk_self;
export region, re_named, re_caller, re_block; export region, re_named, re_caller, re_block;
export get, type_has_params, type_has_vars, type_id; export get, type_has_params, type_has_vars, type_has_rptrs, type_id;
export same_type; export same_type;
export ty_var_id; export ty_var_id;
export ty_fn_args; export ty_fn_args;
@@ -187,6 +187,7 @@ type t_box = @{struct: sty,
id: uint, id: uint,
has_params: bool, has_params: bool,
has_vars: bool, has_vars: bool,
has_rptrs: bool,
o_def_id: option<ast::def_id>}; o_def_id: option<ast::def_id>};
// To reduce refcounting cost, we're representing types as unsafe pointers // To reduce refcounting cost, we're representing types as unsafe pointers
@@ -206,6 +207,7 @@ pure fn get(t: t) -> t_box unsafe {
fn type_has_params(t: t) -> bool { get(t).has_params } fn type_has_params(t: t) -> bool { get(t).has_params }
fn type_has_vars(t: t) -> bool { get(t).has_vars } fn type_has_vars(t: t) -> bool { get(t).has_vars }
fn type_has_rptrs(t: t) -> bool { get(t).has_rptrs }
fn type_def_id(t: t) -> option<ast::def_id> { get(t).o_def_id } fn type_def_id(t: t) -> option<ast::def_id> { get(t).o_def_id }
fn type_id(t: t) -> uint { get(t).id } fn type_id(t: t) -> uint { get(t).id }
@@ -368,11 +370,13 @@ fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option<ast::def_id>) -> t {
some(t) { unsafe { ret unsafe::reinterpret_cast(t); } } some(t) { unsafe { ret unsafe::reinterpret_cast(t); } }
_ {} _ {}
} }
let has_params = false, has_vars = false; let has_params = false, has_vars = false, has_rptrs = false;
fn derive_flags(&has_params: bool, &has_vars: bool, tt: t) { fn derive_flags(&has_params: bool, &has_vars: bool, &has_rptrs: bool,
tt: t) {
let t = get(tt); let t = get(tt);
has_params |= t.has_params; has_params |= t.has_params;
has_vars |= t.has_vars; has_vars |= t.has_vars;
has_rptrs |= t.has_rptrs;
} }
alt st { alt st {
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
@@ -381,33 +385,42 @@ fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option<ast::def_id>) -> t {
ty_param(_, _) { has_params = true; } ty_param(_, _) { has_params = true; }
ty_var(_) | ty_self(_) { has_vars = true; } ty_var(_) | ty_self(_) { has_vars = true; }
ty_enum(_, tys) | ty_iface(_, tys) | ty_class(_, tys) { ty_enum(_, tys) | ty_iface(_, tys) | ty_class(_, tys) {
for tt in tys { derive_flags(has_params, has_vars, tt); } for tt in tys { derive_flags(has_params, has_vars, has_rptrs, tt); }
} }
ty_box(m) | ty_uniq(m) | ty_vec(m) | ty_ptr(m) | ty_rptr(_, m) { ty_box(m) | ty_uniq(m) | ty_vec(m) | ty_ptr(m) {
derive_flags(has_params, has_vars, m.ty); derive_flags(has_params, has_vars, has_rptrs, m.ty);
}
ty_rptr(_, m) {
has_rptrs = true;
derive_flags(has_params, has_vars, has_rptrs, m.ty);
} }
ty_rec(flds) { ty_rec(flds) {
for f in flds { derive_flags(has_params, has_vars, f.mt.ty); } for f in flds {
derive_flags(has_params, has_vars, has_rptrs, f.mt.ty);
}
} }
ty_tup(ts) { ty_tup(ts) {
for tt in ts { derive_flags(has_params, has_vars, tt); } for tt in ts { derive_flags(has_params, has_vars, has_rptrs, tt); }
} }
ty_fn(f) { ty_fn(f) {
for a in f.inputs { derive_flags(has_params, has_vars, a.ty); } for a in f.inputs {
derive_flags(has_params, has_vars, f.output); derive_flags(has_params, has_vars, has_rptrs, a.ty);
}
derive_flags(has_params, has_vars, has_rptrs, f.output);
} }
ty_res(_, tt, tps) { ty_res(_, tt, tps) {
derive_flags(has_params, has_vars, tt); derive_flags(has_params, has_vars, has_rptrs, tt);
for tt in tps { derive_flags(has_params, has_vars, tt); } for tt in tps { derive_flags(has_params, has_vars, has_rptrs, tt); }
} }
ty_constr(tt, _) { ty_constr(tt, _) {
derive_flags(has_params, has_vars, tt); derive_flags(has_params, has_vars, has_rptrs, tt);
} }
} }
let t = @{struct: st, let t = @{struct: st,
id: cx.next_id, id: cx.next_id,
has_params: has_params, has_params: has_params,
has_vars: has_vars, has_vars: has_vars,
has_rptrs: has_rptrs,
o_def_id: o_def_id}; o_def_id: o_def_id};
cx.interner.insert(key, t); cx.interner.insert(key, t);
cx.next_id += 1u; cx.next_id += 1u;