From 4ffcb959744194413ca20223274d2c351ad7686c Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 9 Mar 2012 16:39:54 -0800 Subject: [PATCH] rustc: Perform region inference --- src/rustc/driver/driver.rs | 5 +- src/rustc/middle/region.rs | 145 +++++++++++++++++++++++++++++++++++++ src/rustc/middle/ty.rs | 5 +- src/rustc/rustc.rc | 1 + 4 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 src/rustc/middle/region.rs diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index 4f037511418..906da4cdede 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -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)); diff --git a/src/rustc/middle/region.rs b/src/rustc/middle/region.rs new file mode 100644 index 00000000000..1981377a83e --- /dev/null +++ b/src/rustc/middle/region.rs @@ -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_type_to_region: hashmap +}; + +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, + parent: parent +}; + +fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt) { + 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) { + 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) { + // 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; +} + diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index ad641a451c4..dc6053ad73d 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -167,6 +167,7 @@ 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, items: ast_map::map, @@ -327,7 +328,8 @@ fn new_ty_hash() -> map::hashmap { } 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) @@ -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, diff --git a/src/rustc/rustc.rc b/src/rustc/rustc.rc index 837e1675679..4880044c81e 100644 --- a/src/rustc/rustc.rc +++ b/src/rustc/rustc.rc @@ -44,6 +44,7 @@ mod middle { mod freevars; mod capture; mod pat_util; + mod region; mod tstate { mod ck; -- GitLab