rewrite region resolution so it takes place in typeck

This commit is contained in:
Niko Matsakis 2012-04-15 22:06:19 -07:00
parent a532ad2828
commit 35a93e61d4
15 changed files with 1043 additions and 912 deletions

View file

@ -1270,7 +1270,7 @@ are written after the name of the implementation, or if that is not
specified, after the `impl` keyword.
~~~~
# iface seq { }
# iface seq<T> { }
impl <T> of seq<T> for [T] {
/* ... */

View file

@ -1,6 +1,6 @@
#!/usr/bin/perl -w
$ident = 0;
$indent = 0;
while (<>) {
if (/^rust: ">>/) {
$indent += 1;

View file

@ -101,6 +101,15 @@ impl extensions<T:copy> for option<T> {
#[doc = "Performs an operation on the contained value or does nothing"]
fn iter(f: fn(T)) { iter(self, f) }
#[doc = "Converts `none` to a zero-element list and `some` to a \
one-element list."]
fn to_vec() -> [T] {
alt self {
some(t) { [t] }
none { [] }
}
}
#[doc = "Performs an operation on the contained value or does nothing"]
fn each(f: fn(T) -> bool) {
alt self {

View file

@ -451,9 +451,8 @@ type region = {id: node_id, node: region_};
#[auto_serialize]
enum region_ {
re_inferred,
re_anon,
re_named(ident),
re_self,
re_static
}

View file

@ -451,15 +451,13 @@ fn parse_ret_ty(p: parser) -> (ast::ret_style, @ast::ty) {
fn region_from_name(p: parser, s: option<str>) -> ast::region {
let r = alt s {
some (string) {
if string == "self" {
ast::re_self
} else if string == "static" {
if string == "static" {
ast::re_static
} else {
ast::re_named(string)
}
}
none { ast::re_inferred }
none { ast::re_anon }
};
{id: p.get_id(), node: r}

View file

@ -320,9 +320,8 @@ fn print_native_mod(s: ps, nmod: ast::native_mod, attrs: [ast::attribute]) {
fn print_region(s: ps, region: ast::region) {
alt region.node {
ast::re_inferred { /* no-op */ }
ast::re_anon { /* no-op */ }
ast::re_named(name) { word(s.s, name); word(s.s, "."); }
ast::re_self { word(s.s, "self"); word(s.s, "."); }
ast::re_static { word(s.s, "static"); word(s.s, "."); }
}
}
@ -826,8 +825,7 @@ fn print_vstore(s: ps, t: ast::vstore) {
ast::vstore_box { word_space(s, "/@"); }
ast::vstore_slice(r) {
alt r.node {
ast::re_inferred { word_space(s, "/&"); }
ast::re_self { word_space(s, "/&self"); }
ast::re_anon { word_space(s, "/&"); }
ast::re_static { word_space(s, "/&static"); }
ast::re_named(name) {
word(s.s, "/&");

View file

@ -104,10 +104,8 @@ fn enc_bound_region(w: io::writer, br: ty::bound_region) {
alt br {
ty::br_self { w.write_char('s') }
ty::br_anon { w.write_char('a') }
ty::br_param(id, s) {
ty::br_named(s) {
w.write_char('[');
w.write_uint(id);
w.write_char('|');
w.write_str(s);
w.write_char(']')
}
@ -132,9 +130,6 @@ fn enc_region(w: io::writer, r: ty::region) {
w.write_int(nid);
w.write_char('|');
}
ty::re_default {
w.write_char('i');
}
ty::re_var(id) {
w.write_char('v');
w.write_uint(id.to_uint());

View file

@ -592,7 +592,7 @@ impl resolve_methods for infer_ctxt {
self.rb,
{|_t| false },
rid,
{|| err(unresolved_region(rid)) });
{|| ok(ty::re_static) });
}
fn resolve_ty(typ: ty::t) -> fres<ty::t> {
@ -1169,7 +1169,10 @@ impl of combine for sub {
}
fn regions(a: ty::region, b: ty::region) -> cres<ty::region> {
#debug["regions(%s <= %s)", a.to_str(*self), b.to_str(*self)];
#debug["%s.regions(%s, %s)",
self.tag(),
a.to_str(self.infcx()),
b.to_str(self.infcx())];
indent {||
alt (a, b) {
(ty::re_var(a_id), ty::re_var(b_id)) {
@ -1376,8 +1379,7 @@ impl of combine for lub {
{|x, y| self.regions(x, y) })
}
(ty::re_var(v_id), r) |
(r, ty::re_var(v_id)) {
(ty::re_var(v_id), r) | (r, ty::re_var(v_id)) {
lattice_var_t(self, self.infcx().rb,
v_id, r,
{|x, y| self.regions(x, y) })
@ -1415,12 +1417,6 @@ impl of combine for lub {
err(ty::terr_regions_differ(b, a))
}
}
(ty::re_default, _) |
(_, ty::re_default) {
// actually a compiler bug, I think.
err(ty::terr_regions_differ(b, a))
}
}
}
}
@ -1561,10 +1557,10 @@ impl of combine for glb {
{|x, y| self.regions(x, y) })
}
(ty::re_var(v_id), _) | (_, ty::re_var(v_id)) {
lattice_var_t(self, self.infcx().rb,
v_id, b,
{|x, y| self.regions(x, y) })
(ty::re_var(v_id), r) | (r, ty::re_var(v_id)) {
lattice_var_t(self, self.infcx().rb,
v_id, r,
{|x, y| self.regions(x, y) })
}
(f @ ty::re_free(f_id, f_br), ty::re_scope(s_id)) |
@ -1601,12 +1597,6 @@ impl of combine for glb {
err(ty::terr_regions_differ(b, a))
}
}
(ty::re_default, _) |
(_, ty::re_default) {
// actually a compiler bug, I think.
err(ty::terr_regions_differ(b, a))
}
}
}
}
@ -1727,7 +1717,7 @@ fn lattice_vars<V:copy vid, T:copy to_str st, L:lattice_ops combine>(
let {root: a_vid, bounds: a_bounds} = self.infcx().get(vb, a_vid);
let {root: b_vid, bounds: b_bounds} = self.infcx().get(vb, b_vid);
#debug["%s.vars(%s=%s <: %s=%s)",
#debug["%s.lattice_vars(%s=%s <: %s=%s)",
self.tag(),
a_vid.to_str(), a_bounds.to_str(self.infcx()),
b_vid.to_str(), b_bounds.to_str(self.infcx())];
@ -1758,15 +1748,15 @@ fn lattice_vars<V:copy vid, T:copy to_str st, L:lattice_ops combine>(
fn lattice_var_t<V:copy vid, T:copy to_str st, L:lattice_ops combine>(
self: L, vb: vals_and_bindings<V, T>,
a_vid: V, b: T,
a_id: V, b: T,
c_ts: fn(T, T) -> cres<T>) -> cres<T> {
let {root: a_id, bounds: a_bounds} = self.infcx().get(vb, a_vid);
let {root: a_id, bounds: a_bounds} = self.infcx().get(vb, a_id);
// The comments in this function are written for LUB, but they
// apply equally well to GLB if you inverse upper/lower/sub/super/etc.
#debug["%s.var_ty(%s=%s <: %s)",
#debug["%s.lattice_vart(%s=%s <: %s)",
self.tag(),
a_id.to_str(), a_bounds.to_str(self.infcx()),
b.to_str(self.infcx())];

View file

@ -162,12 +162,9 @@ type binding = {node_id: ast::node_id,
type region_map = {
/* Mapping from a block/function expression to its parent. */
parents: hashmap<ast::node_id,ast::node_id>,
/* Mapping from a region type in the AST to its resolved region. */
ast_type_to_region: hashmap<ast::node_id,ty::region>,
/* Mapping from a local variable to its containing block. */
local_blocks: hashmap<ast::node_id,ast::node_id>,
/* Mapping from an AST type node to the region that `&` resolves to. */
ast_type_to_inferred_region: hashmap<ast::node_id,ty::region>,
local_blocks: hashmap<ast::node_id,ast::node_id>
};
type region_scope = @{
@ -198,69 +195,6 @@ impl methods for region_scope {
fn self_subscope(node_id: ast::node_id) -> region_scope {
@{node_id: node_id, kind: rsk_self(self)}
}
fn find(nm: str) -> option<binding> {
alt self.kind {
rsk_root { none }
rsk_body(parent) { parent.find(nm) }
rsk_self(parent) { parent.find(nm) }
rsk_binding(parent, bs) {
alt (*bs).find({|b| b.name == nm }) {
none { parent.find(nm) }
some(b) { some(b) }
}
}
}
}
// fn resolve_anon() -> option<ty::region> {
// alt self.kind {
// rsk_root { none }
// rsk_body(_) { none }
// rsk_self(_) { none }
// rsk_binding(_, _) { ty::re_bound(ty::br_anon) }
// }
// }
fn resolve_self_helper(bound: bool) -> option<ty::region> {
alt self.kind {
rsk_root { none }
rsk_self(_) if bound { some(ty::re_bound(ty::br_self)) }
rsk_self(_) { some(ty::re_free(self.node_id, ty::br_self)) }
rsk_binding(p, _) { p.resolve_self_helper(bound) }
rsk_body(p) { p.resolve_self_helper(false) }
}
}
fn resolve_self() -> option<ty::region> {
self.resolve_self_helper(true)
}
fn resolve_ident(nm: str) -> option<ty::region> {
alt self.find(nm) {
some(b) if b.node_id == self.node_id {
some(ty::re_bound(b.br))
}
some(b) {
some(ty::re_free(b.node_id, b.br))
}
none {
alt self.kind {
rsk_self(_) | rsk_root | rsk_body(_) { none }
rsk_binding(_, bs) {
let idx = (*bs).len();
let br = ty::br_param(idx, nm);
vec::push(*bs, {node_id: self.node_id,
name: nm,
br: br});
some(ty::re_bound(br))
}
}
}
}
}
}
type ctxt = {
@ -351,50 +285,6 @@ fn get_inferred_region(cx: ctxt, sp: syntax::codemap::span) -> ty::region {
}
}
fn resolve_region_binding(cx: ctxt, span: span,
region: ast::region) -> ty::region {
alt region.node {
ast::re_inferred { ty::re_default }
ast::re_static { ty::re_static }
ast::re_named(ident) {
alt cx.scope.resolve_ident(ident) {
some(r) { r }
none {
cx.sess.span_fatal(
span,
#fmt["the region `%s` is not declared", ident]);
}
}
}
ast::re_self {
alt cx.scope.resolve_self() {
some(r) { r }
none {
cx.sess.span_fatal(
span,
"the `self` region is not allowed here");
}
}
}
}
}
fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
let inferred_region = get_inferred_region(cx, ty.span);
cx.region_map.ast_type_to_inferred_region.insert(ty.id, inferred_region);
alt ty.node {
ast::ty_vstore(_, ast::vstore_slice(r)) |
ast::ty_rptr(r, _) {
let region = resolve_region_binding(cx, ty.span, r);
cx.region_map.ast_type_to_region.insert(ty.id, region);
}
_ { /* nothing to do */ }
}
visit::visit_ty(ty, cx, visitor);
}
fn opt_parent_id(cx: ctxt) -> option<ast::node_id> {
alt cx.parent {
pa_fn_item(parent_id) |
@ -531,16 +421,12 @@ fn resolve_crate(sess: session, def_map: resolve::def_map, crate: @ast::crate)
let cx: ctxt = {sess: sess,
def_map: def_map,
region_map: @{parents: map::int_hash(),
ast_type_to_region: map::int_hash(),
local_blocks: map::int_hash(),
ast_type_to_inferred_region:
map::int_hash()},
local_blocks: map::int_hash()},
scope: root_scope(0),
parent: pa_crate};
let visitor = visit::mk_vt(@{
visit_block: resolve_block,
visit_item: resolve_item,
visit_ty: resolve_ty,
visit_arm: resolve_arm,
visit_pat: resolve_pat,
visit_expr: resolve_expr,

View file

@ -15,12 +15,13 @@ fn check_expr(expr: @ast::expr,
visit::visit_expr(expr, tcx, visitor);
let t = ty::expr_ty(tcx, expr);
if !ty::type_has_rptrs(t) { ret; }
if !ty::type_has_regions(t) { ret; }
ty::walk_ty(t) { |t|
alt ty::get(t).struct {
ty::ty_rptr(region, _) {
alt region {
ty::re_bound(_) | ty::re_free(_, _) | ty::re_static {
ty::re_bound(_) | ty::re_free(_, _) | ty::re_static |
ty::re_var(_) {
/* ok */
}
ty::re_scope(id) {
@ -31,9 +32,6 @@ fn check_expr(expr: @ast::expr,
ppaux::re_scope_id_to_str(tcx, id)]);
}
}
ty::re_default | ty::re_var(_) {
tcx.sess.span_bug(expr.span, "unresolved region");
}
}
}
_ { /* no-op */ }

View file

@ -36,7 +36,7 @@ export expr_ty;
export expr_ty_params_and_ty;
export expr_is_lval;
export field_ty;
export fold_ty, fold_sty_to_ty, fold_region, fold_ty_var;
export fold_ty, fold_sty_to_ty, fold_region, fold_regions, fold_ty_var;
export field;
export field_idx;
export get_field;
@ -99,7 +99,7 @@ export ty_uniq, mk_uniq, mk_imm_uniq, type_is_unique_box;
export ty_var, mk_var;
export ty_self, mk_self;
export region, bound_region;
export get, type_has_params, type_has_vars, type_has_rptrs, type_id;
export get, type_has_params, type_has_vars, type_has_regions, type_id;
export ty_var_id;
export ty_to_def_id;
export ty_fn_args;
@ -230,7 +230,7 @@ type t_box = @{struct: sty,
id: uint,
has_params: bool,
has_vars: bool,
has_rptrs: bool,
has_regions: bool,
o_def_id: option<ast::def_id>};
// To reduce refcounting cost, we're representing types as unsafe pointers
@ -250,7 +250,7 @@ pure fn get(t: t) -> t_box unsafe {
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_rptrs(t: t) -> bool { get(t).has_rptrs }
fn type_has_regions(t: t) -> bool { get(t).has_regions }
fn type_def_id(t: t) -> option<ast::def_id> { get(t).o_def_id }
fn type_id(t: t) -> uint { get(t).id }
@ -272,20 +272,13 @@ enum region {
re_free(node_id, bound_region),
re_scope(node_id),
re_var(region_vid),
re_static, // effectively `top` in the region lattice
re_default
re_static // effectively `top` in the region lattice
}
enum bound_region {
// The `self` region for a given class/impl/iface. The defining item may
// appear in another crate.
br_self,
// The anonymous region parameter for a given function.
br_anon,
// A named region parameter.
br_param(uint, str)
br_self, // The self region for classes, impls
br_anon, // The anonymous region parameter for a given function.
br_named(str) // A named region parameter.
}
// NB: If you change this, you'll probably want to change the corresponding
@ -461,21 +454,21 @@ 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); } }
_ {}
}
let mut has_params = false, has_vars = false, has_rptrs = false;
fn derive_flags(&has_params: bool, &has_vars: bool, &has_rptrs: bool,
let mut has_params = false, has_vars = false, has_regions = false;
fn derive_flags(&has_params: bool, &has_vars: bool, &has_regions: bool,
tt: t) {
let t = get(tt);
has_params |= t.has_params;
has_vars |= t.has_vars;
has_rptrs |= t.has_rptrs;
has_regions |= t.has_regions;
}
alt st {
ty_estr(vstore_slice(_)) {
has_rptrs = true;
has_regions = true;
}
ty_evec(mt, vstore_slice(_)) {
has_rptrs = true;
derive_flags(has_params, has_vars, has_rptrs, mt.ty);
has_regions = true;
derive_flags(has_params, has_vars, has_regions, mt.ty);
}
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
ty_str | ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) |
@ -484,49 +477,50 @@ fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option<ast::def_id>) -> t {
ty_var(_) | ty_self(_) { has_vars = true; }
ty_enum(_, tys) | ty_iface(_, tys) | ty_class(_, tys) {
for tys.each {|tt|
derive_flags(has_params, has_vars, has_rptrs, tt);
derive_flags(has_params, has_vars, has_regions, tt);
}
}
ty_box(m) | ty_uniq(m) | ty_vec(m) | ty_evec(m, _) | ty_ptr(m) {
derive_flags(has_params, has_vars, has_rptrs, m.ty);
derive_flags(has_params, has_vars, has_regions, m.ty);
}
ty_rptr(r, m) {
alt r {
ty::re_var(_) { has_vars = true; }
_ { }
}
has_rptrs = true;
derive_flags(has_params, has_vars, has_rptrs, m.ty);
has_regions = true;
derive_flags(has_params, has_vars, has_regions, m.ty);
}
ty_rec(flds) {
for flds.each {|f|
derive_flags(has_params, has_vars, has_rptrs, f.mt.ty);
derive_flags(has_params, has_vars, has_regions, f.mt.ty);
}
}
ty_tup(ts) {
for ts.each {|tt| derive_flags(has_params, has_vars, has_rptrs, tt); }
for ts.each {|tt| derive_flags(has_params, has_vars,
has_regions, tt); }
}
ty_fn(f) {
for f.inputs.each {|a|
derive_flags(has_params, has_vars, has_rptrs, a.ty);
derive_flags(has_params, has_vars, has_regions, a.ty);
}
derive_flags(has_params, has_vars, has_rptrs, f.output);
derive_flags(has_params, has_vars, has_regions, f.output);
}
ty_res(_, tt, tps) {
derive_flags(has_params, has_vars, has_rptrs, tt);
derive_flags(has_params, has_vars, has_regions, tt);
for tps.each {|tt|
derive_flags(has_params, has_vars, has_rptrs, tt);
derive_flags(has_params, has_vars, has_regions, tt);
}
}
ty_constr(tt, _) {
derive_flags(has_params, has_vars, has_rptrs, tt);
derive_flags(has_params, has_vars, has_regions, tt);
}
}
let t = @{struct: st,
id: cx.next_id,
has_params: has_params,
has_vars: has_vars,
has_rptrs: has_rptrs,
has_regions: has_regions,
o_def_id: o_def_id};
cx.interner.insert(key, t);
cx.next_id += 1u;
@ -771,11 +765,53 @@ fn fold_ty_var(cx: ctxt, t0: t, fldop: fn(ty_vid) -> t) -> t {
}
}
// n.b. this function is intended to eventually replace fold_region() below,
// that is why its name is so similar.
fn fold_regions(
cx: ctxt,
ty: t,
fldr: fn(r: region, in_fn: bool) -> region) -> t {
fn do_fold(cx: ctxt, ty: t, in_fn: bool,
fldr: fn(region, bool) -> region) -> t {
let tb = ty::get(ty);
if !tb.has_regions { ret ty; }
alt tb.struct {
ty::ty_rptr(r, mt) {
let m_r = fldr(r, in_fn);
let m_t = do_fold(cx, mt.ty, in_fn, fldr);
ty::mk_rptr(cx, m_r, {ty: m_t, mutbl: mt.mutbl})
}
ty_estr(vstore_slice(r)) {
let m_r = fldr(r, in_fn);
ty::mk_estr(cx, vstore_slice(m_r))
}
ty_evec(mt, vstore_slice(r)) {
let m_r = fldr(r, in_fn);
let m_t = do_fold(cx, mt.ty, in_fn, fldr);
ty::mk_evec(cx, {ty: m_t, mutbl: mt.mutbl}, vstore_slice(m_r))
}
sty @ ty_fn(_) {
fold_sty_to_ty(cx, sty) {|t|
do_fold(cx, t, true, fldr)
}
}
sty {
fold_sty_to_ty(cx, sty) {|t|
do_fold(cx, t, in_fn, fldr)
}
}
}
}
do_fold(cx, ty, false, fldr)
}
fn fold_region(cx: ctxt, t0: t, fldop: fn(region, bool) -> region) -> t {
fn do_fold(cx: ctxt, t0: t, under_r: bool,
fldop: fn(region, bool) -> region) -> t {
let tb = get(t0);
if !tb.has_rptrs { ret t0; }
if !tb.has_regions { ret t0; }
alt tb.struct {
ty_rptr(r, {ty: t1, mutbl: m}) {
let m_r = fldop(r, under_r);
@ -1544,9 +1580,9 @@ fn type_autoderef(cx: ctxt, t: t) -> t {
fn hash_bound_region(br: bound_region) -> uint {
alt br { // no idea if this is any good
br_self { 0u }
br_anon { 1u }
br_param(id, _) { id }
ty::br_self { 0u }
ty::br_anon { 1u }
ty::br_named(str) { str::hash(str) }
}
}
@ -1588,8 +1624,7 @@ fn hash_type_structure(st: sty) -> uint {
(hash_bound_region(br)) << 2u | 1u }
re_scope(id) { ((id as uint) << 2u) | 2u }
re_var(id) { (id.to_uint() << 2u) | 3u }
re_default { 4u }
re_bot { 5u }
re_bot { 4u }
}
}
alt st {

File diff suppressed because it is too large Load diff

View file

@ -13,7 +13,7 @@ import driver::session::session;
fn bound_region_to_str(_cx: ctxt, br: bound_region) -> str {
alt br {
br_anon { "&" }
br_param(_, str) { #fmt["&%s", str] }
br_named(str) { #fmt["&%s", str] }
br_self { "&self" }
}
}
@ -53,7 +53,6 @@ fn region_to_str(cx: ctxt, region: region) -> str {
// These two should not be seen by end-users (very often, anyhow):
re_var(id) { #fmt("&%s", id.to_str()) }
re_default { "&(default)" }
re_static { "&static" }
}
}

View file

@ -0,0 +1,13 @@
use std;
fn main() {
iface seq { }
impl <T> of seq<T> for [T] {
//!^ ERROR wrong number of type arguments for a polymorphic type
/* ... */
}
impl of seq<bool> for u32 {
/* Treat the integer as a sequence of bits */
}
}

View file

@ -1,3 +1,5 @@
// xfail-test
enum int_wrapper {
int_wrapper_ctor(&int)
}