rustc: Redo region inference to be a bit less broken
This commit is contained in:
parent
84019aa0dc
commit
7931a61ebb
8 changed files with 392 additions and 330 deletions
|
|
@ -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); }
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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, _}) |
|
||||
|
|
|
|||
|
|
@ -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) {||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,5 +7,6 @@ impl clam for clam {
|
|||
fn main() {
|
||||
let clam = { chowder: &3 };
|
||||
log(debug, *clam.get_chowder());
|
||||
clam.get_chowder();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue