Skip to content

Commit

Permalink
rustc: Perform region inference
Browse files Browse the repository at this point in the history
  • Loading branch information
pcwalton committed Mar 10, 2012
1 parent 7f55e7d commit 4ffcb95
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 2 deletions.
5 changes: 4 additions & 1 deletion src/rustc/driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,10 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
let freevars =
time(time_passes, "freevar finding",
bind freevars::annotate_freevars(def_map, crate));
let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars);
let region_map =
time(time_passes, "region resolution",
bind middle::region::resolve_crate(sess, crate));
let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars, region_map);
let (method_map, dict_map) =
time(time_passes, "typechecking",
bind typeck::check_crate(ty_cx, impl_map, crate));
Expand Down
145 changes: 145 additions & 0 deletions src/rustc/middle/region.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* Region resolution. This pass runs before typechecking and resolves region
* names to the appropriate block.
*/

import driver::session::session;
import middle::ty;
import syntax::{ast, visit};
import std::map;
import std::map::hashmap;

type region_map = {
parent_blocks: hashmap<ast::node_id,ast::node_id>,
ast_type_to_region: hashmap<ast::node_id,ty::region>
};

enum parent {
pa_item(ast::node_id),
pa_block(ast::node_id),
pa_crate
}

type ctxt = {
sess: session,
region_map: @region_map,
names_in_scope: hashmap<str,ast::def_id>,
parent: parent
};

fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
alt ty.node {
ast::ty_rptr({id: region_id, node: node}, _) {
let region;
alt node {
ast::re_inferred {
// We infer to the caller region if we're at item scope
// and to the block region if we're at block scope.
alt cx.parent {
pa_item(item_id) {
let def_id = {crate: ast::local_crate,
node: item_id};
region = ty::re_caller(def_id);
}
pa_block(block_id) {
region = ty::re_block(block_id);
}
pa_crate {
cx.sess.span_bug(ty.span,
"region type outside item");
}
}
}

ast::re_named(ident) {
// If at item scope, introduce or reuse a binding. If at
// block scope, require that the binding be introduced.
alt cx.names_in_scope.find(ident) {
some(def_id) { region = ty::re_named(def_id); }
none {
alt cx.parent {
pa_item(_) { /* ok; fall through */ }
pa_block(_) {
cx.sess.span_err(ty.span,
"unknown region `" +
ident + "`");
}
pa_crate {
cx.sess.span_bug(ty.span,
"named region at " +
"crate scope?!");
}
}

let def_id = {crate: ast::local_crate,
node: region_id};
cx.names_in_scope.insert(ident, def_id);
region = ty::re_named(def_id);
}
}
}

ast::re_self {
// For blocks, "self" means "the current block".
alt cx.parent {
pa_item(_) {
cx.sess.span_unimpl(ty.span,
"'self' region for items");
}
pa_block(block_id) {
region = ty::re_block(block_id);
}
pa_crate {
cx.sess.span_bug(ty.span,
"region type outside item");
}
}
}

}

cx.region_map.ast_type_to_region.insert(region_id, region);
}
_ { /* nothing to do */ }
}

visit::visit_ty(ty, cx, visitor);
}

fn resolve_block(blk: ast::blk, cx: ctxt, visitor: visit::vt<ctxt>) {
alt cx.parent {
pa_item(_) { /* no-op */ }
pa_block(parent_block_id) {
cx.region_map.parent_blocks.insert(blk.node.id, parent_block_id);
}
pa_crate { cx.sess.span_bug(blk.span, "block outside item?!"); }
}

let new_cx: ctxt = {parent: pa_block(blk.node.id) with cx};
visit::visit_block(blk, new_cx, visitor);
}

fn resolve_item(item: @ast::item, cx: ctxt, visitor: visit::vt<ctxt>) {
// Items create a new outer block scope as far as we're concerned.
let new_cx: ctxt = {names_in_scope: map::new_str_hash(),
parent: pa_item(item.id)
with cx};
visit::visit_item(item, new_cx, visitor);
}

fn resolve_crate(sess: session, crate: @ast::crate) -> @region_map {
let cx: ctxt = {sess: sess,
region_map: @{parent_blocks: map::new_int_hash(),
ast_type_to_region: map::new_int_hash()},
names_in_scope: map::new_str_hash(),
parent: pa_crate};
let visitor = visit::mk_vt(@{
visit_block: resolve_block,
visit_item: resolve_item,
visit_ty: resolve_ty
with *visit::default_visitor()
});
visit::visit_crate(*crate, cx, visitor);
ret cx.region_map;
}

5 changes: 4 additions & 1 deletion src/rustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ type ctxt =
mutable next_id: uint,
sess: session::session,
def_map: resolve::def_map,
region_map: @middle::region::region_map,
node_types: node_type_table,
node_type_substs: hashmap<node_id, [t]>,
items: ast_map::map,
Expand Down Expand Up @@ -327,7 +328,8 @@ fn new_ty_hash<V: copy>() -> map::hashmap<t, V> {
}

fn mk_ctxt(s: session::session, dm: resolve::def_map, amap: ast_map::map,
freevars: freevars::freevar_map) -> ctxt {
freevars: freevars::freevar_map,
region_map: @middle::region::region_map) -> ctxt {
let interner = map::mk_hashmap({|&&k: intern_key|
hash_type_structure(k.struct) +
option::maybe(0u, k.o_def_id, ast_util::hash_def_id)
Expand All @@ -336,6 +338,7 @@ fn mk_ctxt(s: session::session, dm: resolve::def_map, amap: ast_map::map,
mutable next_id: 0u,
sess: s,
def_map: dm,
region_map: region_map,
node_types: @smallintmap::mk(),
node_type_substs: map::new_int_hash(),
items: amap,
Expand Down
1 change: 1 addition & 0 deletions src/rustc/rustc.rc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ mod middle {
mod freevars;
mod capture;
mod pat_util;
mod region;

mod tstate {
mod ck;
Expand Down

0 comments on commit 4ffcb95

Please sign in to comment.