rustc: Redo region inference to be a bit less broken

This commit is contained in:
Patrick Walton 2012-03-23 11:37:10 -07:00
parent 84019aa0dc
commit 7931a61ebb
8 changed files with 392 additions and 330 deletions

View file

@ -92,23 +92,23 @@ fn enc_mt(w: io::writer, cx: @ctxt, mt: ty::mt) {
}
enc_ty(w, cx, mt.ty);
}
fn enc_region(w: io::writer, cx: @ctxt, r: ty::region) {
fn enc_region(w: io::writer, r: ty::region) {
alt r {
ty::re_named(did) {
w.write_char('n'); w.write_str(cx.ds(did)); w.write_char('|');
}
ty::re_caller(did) {
w.write_char('c'); w.write_str(cx.ds(did)); w.write_char('|');
}
ty::re_block(nid) {
w.write_char('b'); w.write_int(nid); w.write_char('|');
}
ty::re_self(did) {
w.write_char('s'); w.write_str(cx.ds(did)); w.write_char('|');
ty::re_self {
w.write_char('s');
}
ty::re_inferred {
w.write_char('i');
}
ty::re_param(id) {
w.write_char('p'); w.write_uint(id); w.write_char('|');
}
ty::re_var(id) {
w.write_char('v'); w.write_uint(id); w.write_char('|');
}
}
}
fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
@ -167,7 +167,7 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
ty::ty_ptr(mt) { w.write_char('*'); enc_mt(w, cx, mt); }
ty::ty_rptr(r, mt) {
w.write_char('&');
enc_region(w, cx, r);
enc_region(w, r);
enc_mt(w, cx, mt);
}
ty::ty_vec(mt) { w.write_char('I'); enc_mt(w, cx, mt); }

View file

@ -22,10 +22,10 @@ enum parent {
pa_crate
}
/* Records the binding site of a region name. */
/* Records the parameter ID of a region name. */
type binding = {
name: str,
id: ast::def_id
id: uint
};
type region_map = {
@ -35,12 +35,8 @@ type region_map = {
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 a region name to its function. */
region_name_to_fn: hashmap<ast::def_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>,
/* Mapping from a call site (or `bind` site) to its containing block. */
call_site_to_block: hashmap<ast::node_id,ast::node_id>,
/*
* Mapping from an address-of operator or alt expression to its containing
* block. This is used as the region if the operand is an rvalue.
@ -67,22 +63,12 @@ type ctxt = {
/* True if we're within the pattern part of an alt, false otherwise. */
in_alt: bool,
/*
* Points to the site of the current typeclass implementation, or none if
* we're outside one.
*/
self_binding: option<ast::def_id>
};
/* True if we're within a typeclass implementation, false otherwise. */
in_typeclass: bool,
fn region_to_scope(region_map: @region_map, region: ty::region)
-> ast::node_id {
ret alt region {
ty::re_caller(def_id) | ty::re_self(def_id) { def_id.node }
ty::re_named(def_id) { region_map.region_name_to_fn.get(def_id) }
ty::re_block(node_id) { node_id }
ty::re_param(_) { fail "unresolved region in region_to_scope" }
};
}
/* The next parameter ID. */
mut next_param_id: uint
};
// Returns true if `subscope` is equal to or is lexically nested inside
// `superscope` and false otherwise.
@ -105,8 +91,10 @@ fn get_inferred_region(cx: ctxt, sp: syntax::codemap::span) -> ty::region {
// TODO: What do we do if we're in an alt?
ret alt cx.parent {
pa_fn_item(item_id) | pa_nested_fn(item_id) {
ty::re_caller({crate: ast::local_crate, node: item_id})
pa_fn_item(_) | pa_nested_fn(_) {
let id = cx.next_param_id;
cx.next_param_id += 1u;
ty::re_param(id)
}
pa_block(block_id) { ty::re_block(block_id) }
pa_item(_) { ty::re_param(0u) }
@ -123,17 +111,14 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
alt node {
ast::re_inferred { /* no-op */ }
ast::re_self {
alt cx.self_binding {
some(def_id) {
let region = ty::re_self(def_id);
let rm = cx.region_map;
rm.ast_type_to_region.insert(region_id, region);
}
none {
cx.sess.span_err(ty.span,
"the `self` region is not \
allowed here");
}
if cx.in_typeclass {
let r = ty::re_self;
let rm = cx.region_map;
rm.ast_type_to_region.insert(region_id, r);
} else {
cx.sess.span_err(ty.span,
"the `self` region is not allowed \
here");
}
}
ast::re_named(ident) {
@ -142,18 +127,18 @@ fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
let bindings = cx.bindings;
let mut region;
alt list::find(*bindings, {|b| ident == b.name}) {
some(binding) { region = ty::re_named(binding.id); }
some(binding) { region = ty::re_param(binding.id); }
none {
let def_id = {crate: ast::local_crate,
node: region_id};
let binding = {name: ident, id: def_id};
let id = cx.next_param_id;
let binding = {name: ident, id: id};
cx.next_param_id += 1u;
cx.bindings = @list::cons(binding, cx.bindings);
region = ty::re_named(def_id);
region = ty::re_param(id);
alt cx.parent {
pa_fn_item(fn_id) | pa_nested_fn(fn_id) {
let rf = cx.region_map.region_name_to_fn;
rf.insert(def_id, fn_id);
/* ok */
}
pa_item(_) {
cx.sess.span_err(ty.span,
@ -264,16 +249,6 @@ fn resolve_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
in_alt: false with cx};
visit::visit_expr(expr, new_cx, visitor);
}
ast::expr_call(_, _, _) | ast::expr_bind(_, _) {
// Record the block that this call appears in.
alt cx.parent {
pa_block(blk_id) {
cx.region_map.call_site_to_block.insert(expr.id, blk_id);
}
_ { cx.sess.span_bug(expr.span, "expr outside of block?!"); }
}
visit::visit_expr(expr, cx, visitor);
}
ast::expr_addr_of(_, subexpr) | ast::expr_alt(subexpr, _, _) {
// Record the block that this expression appears in, in case the
// operand is an rvalue.
@ -302,22 +277,29 @@ fn resolve_local(local: @ast::local, cx: ctxt, visitor: visit::vt<ctxt>) {
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 mut parent;
let mut self_binding = cx.self_binding;
let mut in_typeclass;
alt item.node {
ast::item_fn(_, _, _) | ast::item_enum(_, _) {
parent = pa_fn_item(item.id);
in_typeclass = false;
}
ast::item_impl(_, _, _, _) {
self_binding = some({crate: ast::local_crate, node: item.id});
parent = pa_item(item.id);
in_typeclass = true;
}
_ {
parent = pa_item(item.id);
in_typeclass = false;
}
_ { parent = pa_item(item.id); }
};
let new_cx: ctxt = {bindings: @list::nil,
parent: parent,
in_alt: false,
self_binding: self_binding
in_typeclass: in_typeclass,
mut next_param_id: 0u
with cx};
visit::visit_item(item, new_cx, visitor);
}
@ -328,16 +310,15 @@ fn resolve_crate(sess: session, def_map: resolve::def_map, crate: @ast::crate)
region_map: @{parents: map::int_hash(),
ast_type_to_region: map::int_hash(),
local_blocks: map::int_hash(),
region_name_to_fn: new_def_hash(),
ast_type_to_inferred_region:
map::int_hash(),
call_site_to_block: map::int_hash(),
rvalue_to_block: map::int_hash()},
mut bindings: @list::nil,
mut queued_locals: [],
parent: pa_crate,
in_alt: false,
self_binding: none};
in_typeclass: false,
mut next_param_id: 0u};
let visitor = visit::mk_vt(@{
visit_block: resolve_block,
visit_item: resolve_item,

View file

@ -28,7 +28,7 @@ fn check_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
alt ty::get(t).struct {
ty::ty_rptr(region, _) {
alt region {
ty::re_named(_) | ty::re_caller(_) | ty::re_self(_) {
ty::re_self | ty::re_inferred | ty::re_param(_) {
/* ok */
}
ty::re_block(rbi) {
@ -51,7 +51,7 @@ fn check_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
"escapes its block");
}
}
ty::re_param(_) {
ty::re_var(_) {
cx.tcx.sess.span_bug(expr.span,
"unresolved region");
}

View file

@ -2004,6 +2004,7 @@ fn check_exports(e: @env) {
maybe_add_reexport(e, export_id, t);
maybe_add_reexport(e, export_id, m);
}
_ { e.sess.span_bug(vi.span, "unresolved export"); }
}
}
mie_item(@{id, _}) | mie_native_item(@{id, _}) |

View file

@ -91,7 +91,7 @@ export ty_uint, mk_uint, mk_mach_uint;
export ty_uniq, mk_uniq, mk_imm_uniq, type_is_unique_box;
export ty_var, mk_var;
export ty_self, mk_self;
export region, re_named, re_caller, re_block, re_param;
export region, re_block, re_param, re_var;
export get, type_has_params, type_has_vars, type_has_rptrs, type_id;
export same_type;
export ty_var_id;
@ -139,7 +139,7 @@ export default_arg_mode_for_ty;
export item_path;
export item_path_str;
export ast_ty_to_ty_cache_entry;
export atttce_unresolved, atttce_resolved, atttce_has_regions;
export atttce_unresolved, atttce_resolved;
// Data types
@ -174,8 +174,7 @@ type intern_key = {struct: sty, o_def_id: option<ast::def_id>};
enum ast_ty_to_ty_cache_entry {
atttce_unresolved, /* not resolved yet */
atttce_resolved(t), /* resolved to a type, irrespective of region */
atttce_has_regions /* has regions; cannot be cached */
atttce_resolved(t) /* resolved to a type, irrespective of region */
}
type ctxt =
@ -240,14 +239,19 @@ type fn_ty = {proto: ast::proto,
constraints: [@constr]};
enum region {
re_named(def_id),
re_caller(def_id),
re_self(def_id),
// The region of a block.
re_block(node_id),
// The self region. Only valid inside classes and typeclass
// implementations.
re_self,
// The inferred region, which also corresponds to &self in typedefs.
re_inferred,
// A region parameter. Currently used only for typedefs.
// TODO: Use this for caller and named regions as well.
re_param(uint)
// A region parameter.
re_param(uint),
// A region variable.
re_var(uint)
}
// NB: If you change this, you'll probably want to change the corresponding
@ -594,100 +598,123 @@ fn maybe_walk_ty(ty: t, f: fn(t) -> bool) {
enum fold_mode {
fm_var(fn@(int) -> t),
fm_param(fn@(uint, def_id) -> t),
fm_rptr(fn@(region) -> region),
fm_rptr(fn@(region, bool /* under & */) -> region),
fm_general(fn@(t) -> t),
}
fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t {
let mut ty = ty_0;
fn do_fold(cx: ctxt, fld: fold_mode, ty_0: t, under_rptr: bool) -> t {
let mut ty = ty_0;
let tb = get(ty);
alt fld {
fm_var(_) { if !tb.has_vars { ret ty; } }
fm_param(_) { if !tb.has_params { ret ty; } }
fm_rptr(_) { if !tb.has_rptrs { ret ty; } }
fm_general(_) {/* no fast path */ }
}
alt tb.struct {
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
ty_str | ty_type | ty_opaque_closure_ptr(_) |
ty_opaque_box {}
ty_box(tm) {
ty = mk_box(cx, {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl});
}
ty_uniq(tm) {
ty = mk_uniq(cx, {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl});
}
ty_ptr(tm) {
ty = mk_ptr(cx, {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl});
}
ty_vec(tm) {
ty = mk_vec(cx, {ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl});
}
ty_enum(tid, subtys) {
ty = mk_enum(cx, tid, vec::map(subtys, {|t| fold_ty(cx, fld, t) }));
}
ty_iface(did, subtys) {
ty = mk_iface(cx, did, vec::map(subtys, {|t| fold_ty(cx, fld, t) }));
}
ty_self(subtys) {
ty = mk_self(cx, vec::map(subtys, {|t| fold_ty(cx, fld, t) }));
}
ty_rec(fields) {
let mut new_fields: [field] = [];
for fl: field in fields {
let new_ty = fold_ty(cx, fld, fl.mt.ty);
let new_mt = {ty: new_ty, mutbl: fl.mt.mutbl};
new_fields += [{ident: fl.ident, mt: new_mt}];
let tb = get(ty);
alt fld {
fm_var(_) { if !tb.has_vars { ret ty; } }
fm_param(_) { if !tb.has_params { ret ty; } }
fm_rptr(_) { if !tb.has_rptrs { ret ty; } }
fm_general(_) {/* no fast path */ }
}
ty = mk_rec(cx, new_fields);
}
ty_tup(ts) {
let mut new_ts = [];
for tt in ts { new_ts += [fold_ty(cx, fld, tt)]; }
ty = mk_tup(cx, new_ts);
}
ty_fn(f) {
let mut new_args: [arg] = [];
for a: arg in f.inputs {
let new_ty = fold_ty(cx, fld, a.ty);
new_args += [{mode: a.mode, ty: new_ty}];
alt tb.struct {
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
ty_str | ty_type | ty_opaque_closure_ptr(_) |
ty_opaque_box {}
ty_box(tm) {
ty = mk_box(cx, {ty: do_fold(cx, fld, tm.ty, under_rptr),
mutbl: tm.mutbl});
}
ty_uniq(tm) {
ty = mk_uniq(cx, {ty: do_fold(cx, fld, tm.ty, under_rptr),
mutbl: tm.mutbl});
}
ty_ptr(tm) {
ty = mk_ptr(cx, {ty: do_fold(cx, fld, tm.ty, under_rptr),
mutbl: tm.mutbl});
}
ty_vec(tm) {
ty = mk_vec(cx, {ty: do_fold(cx, fld, tm.ty, under_rptr),
mutbl: tm.mutbl});
}
ty_enum(tid, subtys) {
ty = mk_enum(cx, tid,
vec::map(subtys, {|t|
do_fold(cx, fld, t, under_rptr)
}));
}
ty_iface(did, subtys) {
ty = mk_iface(cx, did,
vec::map(subtys, {|t|
do_fold(cx, fld, t, under_rptr)
}));
}
ty_self(subtys) {
ty = mk_self(cx, vec::map(subtys, {|t|
do_fold(cx, fld, t, under_rptr)
}));
}
ty_rec(fields) {
let mut new_fields: [field] = [];
for fl: field in fields {
let new_ty = do_fold(cx, fld, fl.mt.ty, under_rptr);
let new_mt = {ty: new_ty, mutbl: fl.mt.mutbl};
new_fields += [{ident: fl.ident, mt: new_mt}];
}
ty = mk_rec(cx, new_fields);
}
ty_tup(ts) {
let mut new_ts = [];
for tt in ts { new_ts += [do_fold(cx, fld, tt, under_rptr)]; }
ty = mk_tup(cx, new_ts);
}
ty_fn(f) {
let mut new_args: [arg] = [];
for a: arg in f.inputs {
let new_ty = do_fold(cx, fld, a.ty, under_rptr);
new_args += [{mode: a.mode, ty: new_ty}];
}
ty = mk_fn(cx, {inputs: new_args,
output: do_fold(cx, fld, f.output, under_rptr)
with f});
}
ty_res(did, subty, tps) {
let mut new_tps = [];
for tp: t in tps {
new_tps += [do_fold(cx, fld, tp, under_rptr)];
}
ty = mk_res(cx, did, do_fold(cx, fld, subty, under_rptr),
new_tps);
}
ty_var(id) {
alt fld { fm_var(folder) { ty = folder(id); } _ {/* no-op */ } }
}
ty_param(id, did) {
alt fld { fm_param(folder) { ty = folder(id, did); } _ {} }
}
ty_rptr(r, tm) {
let region = alt fld {
fm_rptr(folder) { folder(r, under_rptr) }
_ { r }
};
ty = mk_rptr(cx, region,
{ty: do_fold(cx, fld, tm.ty, true),
mutbl: tm.mutbl});
}
ty_constr(subty, cs) {
ty = mk_constr(cx, do_fold(cx, fld, subty, under_rptr), cs);
}
_ {
cx.sess.bug("unsupported sort of type in fold_ty");
}
}
ty = mk_fn(cx, {inputs: new_args,
output: fold_ty(cx, fld, f.output)
with f});
}
ty_res(did, subty, tps) {
let mut new_tps = [];
for tp: t in tps { new_tps += [fold_ty(cx, fld, tp)]; }
ty = mk_res(cx, did, fold_ty(cx, fld, subty), new_tps);
}
ty_var(id) {
alt fld { fm_var(folder) { ty = folder(id); } _ {/* no-op */ } }
}
ty_param(id, did) {
alt fld { fm_param(folder) { ty = folder(id, did); } _ {} }
}
ty_rptr(r, tm) {
let region = alt fld { fm_rptr(folder) { folder(r) } _ { r } };
ty = mk_rptr(cx, region,
{ty: fold_ty(cx, fld, tm.ty), mutbl: tm.mutbl});
}
ty_constr(subty, cs) {
ty = mk_constr(cx, fold_ty(cx, fld, subty), cs);
}
_ {
cx.sess.bug("unsupported sort of type in fold_ty");
}
}
alt tb.o_def_id {
some(did) { ty = mk_t_with_id(cx, get(ty).struct, some(did)); }
_ {}
alt tb.o_def_id {
some(did) { ty = mk_t_with_id(cx, get(ty).struct, some(did)); }
_ {}
}
// If this is a general type fold, then we need to run it now.
alt fld { fm_general(folder) { ret folder(ty); } _ { ret ty; } }
}
// If this is a general type fold, then we need to run it now.
alt fld { fm_general(folder) { ret folder(ty); } _ { ret ty; } }
ret do_fold(cx, fld, ty_0, false);
}
@ -1168,11 +1195,11 @@ fn hash_type_structure(st: sty) -> uint {
}
fn hash_region(r: region) -> uint {
alt r {
re_named(_) { 1u }
re_caller(_) { 2u }
re_self(_) { 3u }
re_block(_) { 4u }
re_param(_) { 5u }
re_block(_) { 0u }
re_self { 1u }
re_inferred { 2u }
re_param(_) { 3u }
re_var(_) { 4u }
}
}
alt st {
@ -1643,7 +1670,7 @@ mod unify {
fn@(rb: @region_bindings, r: region) {
ufind::union(rb.sets, set_a, set_b);
let root_c: uint = ufind::find(rb.sets, set_a);
smallintmap::insert::<region>(rb.regions, root_c, r);
smallintmap::insert(rb.regions, root_c, r);
}
);
@ -2013,39 +2040,69 @@ mod unify {
cx: @uctxt, e_region: region, a_region: region,
variance: variance,
nxt: fn(region) -> ures<T>) -> ures<T> {
let {sub, super} = alt variance {
covariant { {sub: a_region, super: e_region} }
contravariant { {sub: e_region, super: a_region} }
invariant {
ret if e_region == a_region {
nxt(e_region)
} else {
err(terr_regions_differ(true, e_region, a_region))
};
}
};
let mut sub, super;
alt variance {
covariant | invariant { super = e_region; sub = a_region; }
contravariant { super = a_region; sub = e_region; }
}
// FIXME: This is wrong. We should be keeping a set of region bindings
// around.
alt (sub, super) {
(ty::re_param(_), _) | (_, ty::re_param(_)) {
ret if sub == super {
nxt(super)
} else {
err(terr_regions_differ(true, super, sub))
}
// FIXME: Should have a way of unifying regions that relies on bounds,
// not on unification.
alt (super, sub) {
(ty::re_var(superkey), ty::re_var(subkey)) {
ret union_region_sets(cx, subkey, superkey, variance,
{|| nxt(sub) });
}
(ty::re_var(superkey), _) {
ret record_region_binding(cx, superkey, sub, variance, nxt);
}
(_, ty::re_var(subkey)) {
ret record_region_binding(cx, subkey, super, variance, nxt);
}
_ { /* fall through */ }
}
// Outer regions are subtypes of inner regions. (This is somewhat
// surprising!)
let superscope = region::region_to_scope(cx.tcx.region_map, super);
let subscope = region::region_to_scope(cx.tcx.region_map, sub);
if region::scope_contains(cx.tcx.region_map, subscope, superscope) {
ret nxt(super);
if variance == invariant {
ret if e_region == a_region {
nxt(e_region)
} else {
err(terr_regions_differ(true, e_region, a_region))
};
}
alt (super, sub) {
(ty::re_var(_), _) | (_, ty::re_var(_)) {
fail "should have been handled above";
}
(ty::re_inferred, _) | (_, ty::re_inferred) {
fail "tried to unify inferred regions";
}
(ty::re_param(_), ty::re_param(_)) |
(ty::re_self, ty::re_self) {
ret if super == sub {
nxt(ty::re_self)
} else {
err(terr_regions_differ(false, super, sub))
};
}
(ty::re_param(_), ty::re_block(_)) |
(ty::re_self, ty::re_block(_)) {
ret nxt(super);
}
(ty::re_block(_), ty::re_param(_)) |
(ty::re_block(_), ty::re_self) {
ret err(terr_regions_differ(false, super, sub));
}
(ty::re_block(superblock), ty::re_block(subblock)) {
// Outer regions are subtypes of inner regions. (This is
// somewhat surprising!)
let rm = cx.tcx.region_map;
if region::scope_contains(rm, subblock, superblock) {
ret nxt(super);
}
ret err(terr_regions_differ(false, sub, super));
}
}
ret err(terr_regions_differ(false, sub, super));
}
fn unify_field<T:copy>(
@ -2074,6 +2131,9 @@ mod unify {
// Fast path.
if expected == actual { ret nxt(expected); }
// FIXME: This is terribly wrong. We should be unifying type sets
// using some sort of bound.
alt (get(expected).struct, get(actual).struct) {
(ty_var(e_id), ty_var(a_id)) {
union(cx, e_id as uint, a_id as uint, variance) {||

View file

@ -253,21 +253,10 @@ enum mode { m_collect, m_check, m_check_tyvar(@fn_ctxt), }
// internal notion of a type. `getter` is a function that returns the type
// corresponding to a definition ID:
fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
fn subst_inferred_regions(tcx: ty::ctxt, use_site: ast::node_id,
ty: ty::t) -> ty::t {
ret ty::fold_ty(tcx, ty::fm_rptr({|r|
alt r {
// FIXME: This is probably wrong for params.
ty::re_param(_) | ty::re_self(_) {
tcx.region_map.ast_type_to_inferred_region.get(use_site)
}
_ { r }
}
}), ty);
}
fn getter(tcx: ty::ctxt, use_site: ast::node_id, mode: mode,
id: ast::def_id) -> ty::ty_param_bounds_and_ty {
let tpt = alt mode {
fn getter(tcx: ty::ctxt, mode: mode, id: ast::def_id)
-> ty::ty_param_bounds_and_ty {
alt mode {
m_check | m_check_tyvar(_) { ty::lookup_item_type(tcx, id) }
m_collect {
if id.crate != ast::local_crate { csearch::get_type(tcx, id) }
@ -285,23 +274,14 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
}
}
}
};
if ty::type_has_rptrs(tpt.ty) {
ret {bounds: tpt.bounds,
ty: subst_inferred_regions(tcx, use_site, tpt.ty)};
}
ret tpt;
}
fn ast_mt_to_mt(tcx: ty::ctxt, use_site: ast::node_id, mode: mode,
mt: ast::mt) -> ty::mt {
ret {ty: do_ast_ty_to_ty(tcx, use_site, mode, mt.ty),
mutbl: mt.mutbl};
fn ast_mt_to_mt(tcx: ty::ctxt, mode: mode, mt: ast::mt) -> ty::mt {
ret {ty: do_ast_ty_to_ty(tcx, mode, mt.ty), mutbl: mt.mutbl};
}
fn instantiate(tcx: ty::ctxt, use_site: ast::node_id, sp: span,
mode: mode, id: ast::def_id, path_id: ast::node_id,
args: [@ast::ty]) -> ty::t {
let ty_param_bounds_and_ty = getter(tcx, use_site, mode, id);
fn instantiate(tcx: ty::ctxt, sp: span, mode: mode, id: ast::def_id,
path_id: ast::node_id, args: [@ast::ty]) -> ty::t {
let ty_param_bounds_and_ty = getter(tcx, mode, id);
if vec::len(*ty_param_bounds_and_ty.bounds) == 0u {
ret ty_param_bounds_and_ty.ty;
}
@ -313,7 +293,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
polymorphic type");
}
for ast_ty: @ast::ty in args {
param_bindings += [do_ast_ty_to_ty(tcx, use_site, mode, ast_ty)];
param_bindings += [do_ast_ty_to_ty(tcx, mode, ast_ty)];
}
#debug("substituting(%s into %s)",
str::concat(vec::map(param_bindings, {|t| ty_to_str(tcx, t)})),
@ -324,8 +304,9 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
write_substs(tcx, path_id, param_bindings);
ret typ;
}
fn do_ast_ty_to_ty(tcx: ty::ctxt, use_site: ast::node_id, mode: mode,
&&ast_ty: @ast::ty) -> ty::t {
fn do_ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty)
-> ty::t {
alt tcx.ast_ty_to_ty_cache.find(ast_ty) {
some(ty::atttce_resolved(ty)) { ret ty; }
some(ty::atttce_unresolved) {
@ -333,7 +314,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
insert a enum in the cycle, \
if this is desired)");
}
some(ty::atttce_has_regions) | none { /* go on */ }
none { /* go on */ }
}
tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::atttce_unresolved);
@ -341,46 +322,37 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
ast::ty_nil { ty::mk_nil(tcx) }
ast::ty_bot { ty::mk_bot(tcx) }
ast::ty_box(mt) {
ty::mk_box(tcx, ast_mt_to_mt(tcx, use_site, mode, mt))
ty::mk_box(tcx, ast_mt_to_mt(tcx, mode, mt))
}
ast::ty_uniq(mt) {
ty::mk_uniq(tcx, ast_mt_to_mt(tcx, use_site, mode, mt))
ty::mk_uniq(tcx, ast_mt_to_mt(tcx, mode, mt))
}
ast::ty_vec(mt) {
ty::mk_vec(tcx, ast_mt_to_mt(tcx, use_site, mode, mt))
ty::mk_vec(tcx, ast_mt_to_mt(tcx, mode, mt))
}
ast::ty_ptr(mt) {
ty::mk_ptr(tcx, ast_mt_to_mt(tcx, use_site, mode, mt))
ty::mk_ptr(tcx, ast_mt_to_mt(tcx, mode, mt))
}
ast::ty_rptr(region, mt) {
let region = alt region.node {
ast::re_inferred {
let attir = tcx.region_map.ast_type_to_inferred_region;
alt attir.find(ast_ty.id) {
some(resolved_region) { resolved_region }
none {
// FIXME: Shouldn't be 0u and should instead be
// a fresh variable.
ty::re_param(0u)
}
}
}
ast::re_named(_) | ast::re_self {
ast::re_inferred { ty::re_inferred }
ast::re_self { ty::re_self }
ast::re_named(_) {
tcx.region_map.ast_type_to_region.get(region.id)
}
};
ty::mk_rptr(tcx, region, ast_mt_to_mt(tcx, use_site, mode, mt))
ty::mk_rptr(tcx, region, ast_mt_to_mt(tcx, mode, mt))
}
ast::ty_tup(fields) {
let flds = vec::map(fields,
bind do_ast_ty_to_ty(tcx, use_site, mode, _));
let flds = vec::map(fields, bind do_ast_ty_to_ty(tcx, mode, _));
ty::mk_tup(tcx, flds)
}
ast::ty_rec(fields) {
let flds = vec::map(fields) {|f|
let tm = ast_mt_to_mt(tcx, use_site, mode, f.node.mt);
{ident: f.node.ident, mt: tm}
};
let mut flds: [field] = [];
for f: ast::ty_field in fields {
let tm = ast_mt_to_mt(tcx, mode, f.node.mt);
flds += [{ident: f.node.ident, mt: tm}];
}
ty::mk_rec(tcx, flds)
}
ast::ty_fn(proto, decl) {
@ -393,7 +365,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
some(d) { d }};
alt a_def {
ast::def_ty(did) {
instantiate(tcx, use_site, ast_ty.span, mode, did,
instantiate(tcx, ast_ty.span, mode, did,
id, path.node.types)
}
ast::def_prim_ty(nty) {
@ -421,7 +393,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
self type");
}
ty::mk_self(tcx, vec::map(path.node.types, {|ast_ty|
do_ast_ty_to_ty(tcx, use_site, mode, ast_ty)
do_ast_ty_to_ty(tcx, mode, ast_ty)
}))
}
}
@ -445,7 +417,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
}
}
else {
getter(tcx, use_site, mode, class_id).ty
getter(tcx, mode, class_id).ty
}
}
_ {
@ -455,11 +427,11 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
}
}
ast::ty_constr(t, cs) {
let out_cs = vec::map(cs) {|constr|
ty::ast_constr_to_constr(tcx, constr)
};
ty::mk_constr(tcx, do_ast_ty_to_ty(tcx, use_site, mode, t),
out_cs)
let mut out_cs = [];
for constr: @ast::ty_constr in cs {
out_cs += [ty::ast_constr_to_constr(tcx, constr)];
}
ty::mk_constr(tcx, do_ast_ty_to_ty(tcx, mode, t), out_cs)
}
ast::ty_infer {
alt mode {
@ -474,16 +446,11 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
}
};
if ty::type_has_rptrs(typ) {
tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::atttce_has_regions);
} else {
tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::atttce_resolved(typ));
}
tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::atttce_resolved(typ));
ret typ;
}
ret do_ast_ty_to_ty(tcx, ast_ty.id, mode, ast_ty);
ret do_ast_ty_to_ty(tcx, mode, ast_ty);
}
fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item)
@ -571,6 +538,37 @@ fn ty_of_native_item(tcx: ty::ctxt, mode: mode, it: @ast::native_item)
}
}
}
type next_region_param_id = { mut id: uint };
fn fixup_regions(tcx: ty::ctxt, next_region_param_id: next_region_param_id,
ty: ty::t) -> ty::t {
let cur_region_param = @mut next_region_param_id.id;
ret ty::fold_ty(tcx, ty::fm_rptr({|region, under_rptr|
alt region {
ty::re_inferred {
if !under_rptr {
*cur_region_param = next_region_param_id.id;
next_region_param_id.id += 1u;
}
ty::re_param(*cur_region_param)
}
_ { region }
}
}), ty);
}
fn fixup_regions_to_block(tcx: ty::ctxt, ty: ty::t, ast_ty: @ast::ty)
-> ty::t {
let region = tcx.region_map.ast_type_to_inferred_region.get(ast_ty.id);
ret ty::fold_ty(tcx, ty::fm_rptr({|this_region, _under_rptr|
alt this_region {
ty::re_inferred { region }
_ { this_region }
}
}), ty);
}
fn ty_of_arg(tcx: ty::ctxt, mode: mode, a: ast::arg) -> ty::arg {
fn arg_mode(tcx: ty::ctxt, m: ast::mode, ty: ty::t) -> ast::mode {
alt m {
@ -603,8 +601,38 @@ fn ty_of_fn_decl(tcx: ty::ctxt,
mode: mode,
proto: ast::proto,
decl: ast::fn_decl) -> ty::fn_ty {
let input_tys = vec::map(decl.inputs) {|a| ty_of_arg(tcx, mode, a) };
let output_ty = ast_ty_to_ty(tcx, mode, decl.output);
let mut has_regions: bool = false;
let mut max_region_param: @mut uint = @mut 0u;
let mut input_tys = vec::map(decl.inputs) {|a|
let arg_ty = ty_of_arg(tcx, mode, a);
if ty::type_has_rptrs(arg_ty.ty) {
has_regions = true;
let _ = ty::fold_ty(tcx, ty::fm_rptr({|r, _under_rptr|
alt r {
ty::re_param(n) {
*max_region_param = uint::max(n, *max_region_param);
}
_ { /* no-op */ }
};
r
}), arg_ty.ty);
}
arg_ty
};
let mut output_ty = ast_ty_to_ty(tcx, mode, decl.output);
if has_regions {
let next_region_param_id = { mut id: *max_region_param };
input_tys = vec::map(input_tys, {|input_ty|
{ty: fixup_regions(tcx, next_region_param_id, input_ty.ty)
with input_ty}
});
output_ty = fixup_regions(tcx, next_region_param_id, output_ty);
}
let out_constrs = vec::map(decl.constraints) {|constr|
ty::ast_constr_to_constr(tcx, constr)
@ -843,9 +871,9 @@ fn fixup_self_in_method_ty(cx: ty::ctxt, mty: ty::t, m_substs: [ty::t],
fn fixup_self_region_in_method_ty(fcx: @fn_ctxt, mty: ty::t,
self_expr: @ast::expr) -> ty::t {
let self_region = region_of(fcx, self_expr);
ty::fold_ty(fcx.ccx.tcx, ty::fm_rptr({|r|
ty::fold_ty(fcx.ccx.tcx, ty::fm_rptr({|r, _under_rptr|
alt r {
ty::re_self(_) { self_region }
ty::re_self { self_region }
_ { r }
}
}), mty)
@ -876,7 +904,13 @@ mod collect {
// should be called to resolve named types.
let mut args: [arg] = [];
for va: ast::variant_arg in variant.node.args {
let arg_ty = ast_ty_to_ty(tcx, m_collect, va.ty);
let mut arg_ty = ast_ty_to_ty(tcx, m_collect, va.ty);
if ty::type_has_rptrs(arg_ty) {
let next_region_param_id = { mut id: 0u };
arg_ty = fixup_regions(tcx, next_region_param_id,
arg_ty);
}
args += [{mode: ast::expl(ast::by_copy), ty: arg_ty}];
}
// FIXME: this will be different for constrained types
@ -1504,8 +1538,16 @@ fn gather_locals(ccx: @crate_ctxt,
// Add explicitly-declared locals.
let visit_local = fn@(local: @ast::local, &&e: (), v: visit::vt<()>) {
let local_ty = ast_ty_to_ty_crate_infer(ccx, local.node.ty);
assign(local.node.id, local_ty);
let mut local_ty_opt = ast_ty_to_ty_crate_infer(ccx, local.node.ty);
alt local_ty_opt {
some(local_ty) if ty::type_has_rptrs(local_ty) {
local_ty_opt = some(fixup_regions_to_block(ccx.tcx, local_ty,
local.node.ty));
}
_ { /* nothing to do */ }
}
assign(local.node.id, local_ty_opt);
visit::visit_local(local, e, v);
};
@ -1571,10 +1613,9 @@ type pat_ctxt = {
fn instantiate_self_regions(tcx: ty::ctxt, region: ty::region, &&ty: ty::t)
-> ty::t {
if ty::type_has_rptrs(ty) {
ty::fold_ty(tcx, ty::fm_rptr({|r|
ty::fold_ty(tcx, ty::fm_rptr({|r, _under_rptr|
alt r {
// FIXME: Should not happen for re_param.
ty::re_param(_) | ty::re_caller(_) | ty::re_self(_) { region }
ty::re_inferred | ty::re_self | ty::re_param(_) { region }
_ { r }
}
}), ty)
@ -1588,9 +1629,9 @@ fn instantiate_self_regions(tcx: ty::ctxt, region: ty::region, &&ty: ty::t)
// refer to inferred regions.
fn universally_quantify_regions(tcx: ty::ctxt, ty: ty::t) -> ty::t {
if ty::type_has_rptrs(ty) {
ty::fold_ty(tcx, ty::fm_rptr({|_r|
// FIXME: Very wrong. Shouldn't be 0u.
ty::re_param(0u)
ty::fold_ty(tcx, ty::fm_rptr({|_r, _under_rptr|
// FIXME: Should these all be different variables?
ty::re_var(0u)
}), ty)
} else {
ty
@ -1606,7 +1647,7 @@ fn replace_region_params(tcx: ty::ctxt,
-> ty::t {
if ty::type_has_rptrs(ty) {
ty::fold_ty(tcx, ty::fm_rptr({ |r|
ty::fold_ty(tcx, ty::fm_rptr({ |r, _under_rptr|
alt r {
ty::re_param(n) {
if n < ufind::set_count(rb.sets) {
@ -2085,13 +2126,14 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
for @{did, methods, _} in *impls {
alt vec::find(methods, {|m| m.ident == name}) {
some(m) {
let {n_tps, ty: self_ty} = impl_self_ty(tcx, did);
let {vars, ty: self_ty} = if n_tps > 0u {
let mut {n_tps, ty: self_ty} = impl_self_ty(tcx, did);
let mut {vars, ty: self_ty} = if n_tps > 0u {
bind_params(fcx, self_ty, n_tps)
} else {
{vars: [], ty: self_ty}
};
self_ty = universally_quantify_regions(tcx, self_ty);
let ty = universally_quantify_regions(tcx, ty);
alt unify::unify(fcx, self_ty, ty) {
@ -2223,32 +2265,23 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
// A generic function to factor out common logic from call and bind
// expressions.
fn check_call_or_bind(fcx: @fn_ctxt, sp: span, id: ast::node_id,
fty: ty::t, args: [option<@ast::expr>])
fn check_call_or_bind(fcx: @fn_ctxt, sp: span, fty: ty::t,
args: [option<@ast::expr>])
-> check_call_or_bind_result {
// Replaces "caller" regions in the arguments with the local region.
fn instantiate_caller_regions(fcx: @fn_ctxt, id: ast::node_id,
args: [ty::arg]) -> [ty::arg] {
let site_to_block = fcx.ccx.tcx.region_map.call_site_to_block;
let block_id = alt site_to_block.find(id) {
none {
// This can happen for those expressions that are
// synthesized during typechecking; e.g. during
// check_constraints().
ret args;
}
some(block_id) { block_id }
};
let region = ty::re_block(block_id);
// Replaces "caller" regions in the arguments with the local region.
fn instantiate_caller_regions(fcx: @fn_ctxt, args: [ty::arg])
-> [ty::arg] {
ret vec::map(args) {|arg|
if ty::type_has_rptrs(arg.ty) {
let ty = ty::fold_ty(fcx.ccx.tcx, ty::fm_rptr({|r|
let ty = ty::fold_ty(fcx.ccx.tcx,
ty::fm_rptr({|r, _under_rptr|
alt r {
ty::re_caller(_) {
ty::re_param(param) {
// FIXME: We should not recurse into nested
// function types here.
region
ty::re_var(param)
}
_ { r }
}
@ -2301,7 +2334,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
}
// FIXME: This should instantiate re_params instead.
arg_tys = instantiate_caller_regions(fcx, id, arg_tys);
arg_tys = instantiate_caller_regions(fcx, arg_tys);
// Check the arguments.
// We do this in a pretty awful way: first we typecheck any arguments
@ -2344,8 +2377,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
}
// A generic function for checking call expressions
fn check_call(fcx: @fn_ctxt, sp: span, id: ast::node_id, f: @ast::expr,
args: [@ast::expr])
fn check_call(fcx: @fn_ctxt, sp: span, f: @ast::expr, args: [@ast::expr])
-> check_call_or_bind_result {
let mut args_opt_0: [option<@ast::expr>] = [];
for arg: @ast::expr in args {
@ -2354,7 +2386,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
let bot = check_expr(fcx, f);
// Call the generic checker.
let ccobr = check_call_or_bind(fcx, sp, id, expr_ty(fcx.ccx.tcx, f),
let ccobr = check_call_or_bind(fcx, sp, expr_ty(fcx.ccx.tcx, f),
args_opt_0);
ret { bot: bot | ccobr.bot with ccobr };
}
@ -2362,7 +2394,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
// A generic function for doing all of the checking for call expressions
fn check_call_full(fcx: @fn_ctxt, sp: span, id: ast::node_id,
f: @ast::expr, args: [@ast::expr]) -> bool {
let ccobr = check_call(fcx, sp, id, f, args);
let ccobr = check_call(fcx, sp, f, args);
let mut bot = ccobr.bot;
/* need to restrict oper to being an explicit expr_path if we're
inside a pure function */
@ -2443,7 +2475,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
alt lookup_method(fcx, op_ex, callee_id, opname, self_t, []) {
some(origin) {
let method_ty = ty::node_id_to_type(fcx.ccx.tcx, callee_id);
check_call_or_bind(fcx, op_ex.span, op_ex.id, method_ty, args);
check_call_or_bind(fcx, op_ex.span, method_ty, args);
fcx.ccx.method_map.insert(op_ex.id, origin);
some(ty::ty_fn_ret(method_ty))
}
@ -2773,8 +2805,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
ast::expr_bind(f, args) {
// Call the generic checker.
bot = check_expr(fcx, f);
let ccobr = check_call_or_bind(fcx, expr.span, expr.id,
expr_ty(tcx, f), args);
let ccobr = check_call_or_bind(fcx, expr.span, expr_ty(tcx, f), args);
bot |= ccobr.bot;
// TODO: Perform substitutions on the return type.
@ -3482,9 +3513,9 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
check_fn(ccx, ast::proto_bare, decl, body, dtor_id, none);
}
ast::item_impl(tps, _, ty, ms) {
let self_ty = ast_ty_to_ty(ccx.tcx, m_check, ty);
let self_region = ty::re_self({crate: ast::local_crate, node: it.id});
let self_ty = instantiate_self_regions(ccx.tcx, self_region, self_ty);
let mut self_ty = ast_ty_to_ty(ccx.tcx, m_check, ty);
let self_region = ty::re_self;
self_ty = instantiate_self_regions(ccx.tcx, self_region, self_ty);
ccx.self_infos += [self_impl(self_ty)];
for m in ms { check_method(ccx, m); }
vec::pop(ccx.self_infos);

View file

@ -12,20 +12,6 @@ import driver::session::session;
fn region_to_str(cx: ctxt, region: region) -> str {
alt region {
re_named(_) { "<name>" } // TODO: include name
re_caller(def_id) {
if def_id.crate == ast::local_crate {
alt cx.items.get(def_id.node) {
ast_map::node_item(item, path) {
#fmt("<caller of %s::%s>", ast_map::path_to_str(*path),
item.ident)
}
_ { "<caller>" }
}
} else {
"<caller>"
}
}
re_block(node_id) {
alt cx.items.get(node_id) {
ast_map::node_block(blk) {
@ -35,8 +21,10 @@ fn region_to_str(cx: ctxt, region: region) -> str {
_ { cx.sess.bug("re_block refers to non-block") }
}
}
re_self(_) { "self" }
re_self { "self" }
re_inferred { "" }
re_param(id) { #fmt("<P%u>", id) } // TODO: do better than this
re_var(id) { #fmt("<R%u>", id) } // TODO: do better than this
}
}

View file

@ -7,5 +7,6 @@ impl clam for clam {
fn main() {
let clam = { chowder: &3 };
log(debug, *clam.get_chowder());
clam.get_chowder();
}