diff --git a/src/rustc/metadata/tyencode.rs b/src/rustc/metadata/tyencode.rs index c526777f37e9..80f830ce88da 100644 --- a/src/rustc/metadata/tyencode.rs +++ b/src/rustc/metadata/tyencode.rs @@ -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); } diff --git a/src/rustc/middle/region.rs b/src/rustc/middle/region.rs index a6806b642e82..3998c2525ac2 100644 --- a/src/rustc/middle/region.rs +++ b/src/rustc/middle/region.rs @@ -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, /* Mapping from a local variable to its containing block. */ local_blocks: hashmap, - /* Mapping from a region name to its function. */ - region_name_to_fn: hashmap, /* Mapping from an AST type node to the region that `&` resolves to. */ ast_type_to_inferred_region: hashmap, - /* Mapping from a call site (or `bind` site) to its containing block. */ - call_site_to_block: hashmap, /* * 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 -}; + /* 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) { 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) { 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) { 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) { fn resolve_item(item: @ast::item, cx: ctxt, visitor: visit::vt) { // Items create a new outer block scope as far as we're concerned. let 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, diff --git a/src/rustc/middle/regionck.rs b/src/rustc/middle/regionck.rs index 26316422106a..a969785cd2e1 100644 --- a/src/rustc/middle/regionck.rs +++ b/src/rustc/middle/regionck.rs @@ -28,7 +28,7 @@ fn check_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt) { 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) { "escapes its block"); } } - ty::re_param(_) { + ty::re_var(_) { cx.tcx.sess.span_bug(expr.span, "unresolved region"); } diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs index ad5243a01a93..5a4c1ae1d7a1 100644 --- a/src/rustc/middle/resolve.rs +++ b/src/rustc/middle/resolve.rs @@ -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, _}) | diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 38d2ba369ec6..b3f6a565c756 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -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}; 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::(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) -> ures { - 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( @@ -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) {|| diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 6e0b39373a1d..19c3e2739491 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -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); diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs index 9cfd0299919a..032f3620631d 100644 --- a/src/rustc/util/ppaux.rs +++ b/src/rustc/util/ppaux.rs @@ -12,20 +12,6 @@ import driver::session::session; fn region_to_str(cx: ctxt, region: region) -> str { alt region { - re_named(_) { "" } // 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("", ast_map::path_to_str(*path), - item.ident) - } - _ { "" } - } - } else { - "" - } - } 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("", id) } // TODO: do better than this + re_var(id) { #fmt("", id) } // TODO: do better than this } } diff --git a/src/test/run-pass/regions-self-impls.rs b/src/test/run-pass/regions-self-impls.rs index 1de392c44009..4e0cd5b1aee1 100644 --- a/src/test/run-pass/regions-self-impls.rs +++ b/src/test/run-pass/regions-self-impls.rs @@ -7,5 +7,6 @@ impl clam for clam { fn main() { let clam = { chowder: &3 }; log(debug, *clam.get_chowder()); + clam.get_chowder(); }