diff --git a/doc/rust.md b/doc/rust.md index afe55bf159e..70be86ff577 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -1270,7 +1270,7 @@ are written after the name of the implementation, or if that is not specified, after the `impl` keyword. ~~~~ -# iface seq { } +# iface seq { } impl of seq for [T] { /* ... */ diff --git a/src/etc/indenter b/src/etc/indenter index db0009fd0b6..b2cc30e7cfe 100755 --- a/src/etc/indenter +++ b/src/etc/indenter @@ -1,6 +1,6 @@ #!/usr/bin/perl -w -$ident = 0; +$indent = 0; while (<>) { if (/^rust: ">>/) { $indent += 1; diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 52f93f91909..eff29d1e55b 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -101,6 +101,15 @@ impl extensions for option { #[doc = "Performs an operation on the contained value or does nothing"] fn iter(f: fn(T)) { iter(self, f) } + #[doc = "Converts `none` to a zero-element list and `some` to a \ + one-element list."] + fn to_vec() -> [T] { + alt self { + some(t) { [t] } + none { [] } + } + } + #[doc = "Performs an operation on the contained value or does nothing"] fn each(f: fn(T) -> bool) { alt self { diff --git a/src/librustsyntax/ast.rs b/src/librustsyntax/ast.rs index 40b4241684d..477a22773da 100644 --- a/src/librustsyntax/ast.rs +++ b/src/librustsyntax/ast.rs @@ -451,9 +451,8 @@ type region = {id: node_id, node: region_}; #[auto_serialize] enum region_ { - re_inferred, + re_anon, re_named(ident), - re_self, re_static } diff --git a/src/librustsyntax/parse/parser.rs b/src/librustsyntax/parse/parser.rs index e017f42a712..93bc76e37b4 100644 --- a/src/librustsyntax/parse/parser.rs +++ b/src/librustsyntax/parse/parser.rs @@ -451,15 +451,13 @@ fn parse_ret_ty(p: parser) -> (ast::ret_style, @ast::ty) { fn region_from_name(p: parser, s: option) -> ast::region { let r = alt s { some (string) { - if string == "self" { - ast::re_self - } else if string == "static" { + if string == "static" { ast::re_static } else { ast::re_named(string) } } - none { ast::re_inferred } + none { ast::re_anon } }; {id: p.get_id(), node: r} diff --git a/src/librustsyntax/print/pprust.rs b/src/librustsyntax/print/pprust.rs index ff7a5b6c35e..4aa994bf2bd 100644 --- a/src/librustsyntax/print/pprust.rs +++ b/src/librustsyntax/print/pprust.rs @@ -320,9 +320,8 @@ fn print_native_mod(s: ps, nmod: ast::native_mod, attrs: [ast::attribute]) { fn print_region(s: ps, region: ast::region) { alt region.node { - ast::re_inferred { /* no-op */ } + ast::re_anon { /* no-op */ } ast::re_named(name) { word(s.s, name); word(s.s, "."); } - ast::re_self { word(s.s, "self"); word(s.s, "."); } ast::re_static { word(s.s, "static"); word(s.s, "."); } } } @@ -826,8 +825,7 @@ fn print_vstore(s: ps, t: ast::vstore) { ast::vstore_box { word_space(s, "/@"); } ast::vstore_slice(r) { alt r.node { - ast::re_inferred { word_space(s, "/&"); } - ast::re_self { word_space(s, "/&self"); } + ast::re_anon { word_space(s, "/&"); } ast::re_static { word_space(s, "/&static"); } ast::re_named(name) { word(s.s, "/&"); diff --git a/src/rustc/metadata/tyencode.rs b/src/rustc/metadata/tyencode.rs index 47643abf276..5815dbf87a5 100644 --- a/src/rustc/metadata/tyencode.rs +++ b/src/rustc/metadata/tyencode.rs @@ -104,10 +104,8 @@ fn enc_bound_region(w: io::writer, br: ty::bound_region) { alt br { ty::br_self { w.write_char('s') } ty::br_anon { w.write_char('a') } - ty::br_param(id, s) { + ty::br_named(s) { w.write_char('['); - w.write_uint(id); - w.write_char('|'); w.write_str(s); w.write_char(']') } @@ -132,9 +130,6 @@ fn enc_region(w: io::writer, r: ty::region) { w.write_int(nid); w.write_char('|'); } - ty::re_default { - w.write_char('i'); - } ty::re_var(id) { w.write_char('v'); w.write_uint(id.to_uint()); diff --git a/src/rustc/middle/infer.rs b/src/rustc/middle/infer.rs index f7fb0829ff0..074ba50e02c 100644 --- a/src/rustc/middle/infer.rs +++ b/src/rustc/middle/infer.rs @@ -592,7 +592,7 @@ impl resolve_methods for infer_ctxt { self.rb, {|_t| false }, rid, - {|| err(unresolved_region(rid)) }); + {|| ok(ty::re_static) }); } fn resolve_ty(typ: ty::t) -> fres { @@ -1169,7 +1169,10 @@ impl of combine for sub { } fn regions(a: ty::region, b: ty::region) -> cres { - #debug["regions(%s <= %s)", a.to_str(*self), b.to_str(*self)]; + #debug["%s.regions(%s, %s)", + self.tag(), + a.to_str(self.infcx()), + b.to_str(self.infcx())]; indent {|| alt (a, b) { (ty::re_var(a_id), ty::re_var(b_id)) { @@ -1376,8 +1379,7 @@ impl of combine for lub { {|x, y| self.regions(x, y) }) } - (ty::re_var(v_id), r) | - (r, ty::re_var(v_id)) { + (ty::re_var(v_id), r) | (r, ty::re_var(v_id)) { lattice_var_t(self, self.infcx().rb, v_id, r, {|x, y| self.regions(x, y) }) @@ -1415,12 +1417,6 @@ impl of combine for lub { err(ty::terr_regions_differ(b, a)) } } - - (ty::re_default, _) | - (_, ty::re_default) { - // actually a compiler bug, I think. - err(ty::terr_regions_differ(b, a)) - } } } } @@ -1561,10 +1557,10 @@ impl of combine for glb { {|x, y| self.regions(x, y) }) } - (ty::re_var(v_id), _) | (_, ty::re_var(v_id)) { - lattice_var_t(self, self.infcx().rb, - v_id, b, - {|x, y| self.regions(x, y) }) + (ty::re_var(v_id), r) | (r, ty::re_var(v_id)) { + lattice_var_t(self, self.infcx().rb, + v_id, r, + {|x, y| self.regions(x, y) }) } (f @ ty::re_free(f_id, f_br), ty::re_scope(s_id)) | @@ -1601,12 +1597,6 @@ impl of combine for glb { err(ty::terr_regions_differ(b, a)) } } - - (ty::re_default, _) | - (_, ty::re_default) { - // actually a compiler bug, I think. - err(ty::terr_regions_differ(b, a)) - } } } } @@ -1727,7 +1717,7 @@ fn lattice_vars( let {root: a_vid, bounds: a_bounds} = self.infcx().get(vb, a_vid); let {root: b_vid, bounds: b_bounds} = self.infcx().get(vb, b_vid); - #debug["%s.vars(%s=%s <: %s=%s)", + #debug["%s.lattice_vars(%s=%s <: %s=%s)", self.tag(), a_vid.to_str(), a_bounds.to_str(self.infcx()), b_vid.to_str(), b_bounds.to_str(self.infcx())]; @@ -1758,15 +1748,15 @@ fn lattice_vars( fn lattice_var_t( self: L, vb: vals_and_bindings, - a_vid: V, b: T, + a_id: V, b: T, c_ts: fn(T, T) -> cres) -> cres { - let {root: a_id, bounds: a_bounds} = self.infcx().get(vb, a_vid); + let {root: a_id, bounds: a_bounds} = self.infcx().get(vb, a_id); // The comments in this function are written for LUB, but they // apply equally well to GLB if you inverse upper/lower/sub/super/etc. - #debug["%s.var_ty(%s=%s <: %s)", + #debug["%s.lattice_vart(%s=%s <: %s)", self.tag(), a_id.to_str(), a_bounds.to_str(self.infcx()), b.to_str(self.infcx())]; diff --git a/src/rustc/middle/region.rs b/src/rustc/middle/region.rs index b26b7cf503d..e27d41d4ee0 100644 --- a/src/rustc/middle/region.rs +++ b/src/rustc/middle/region.rs @@ -162,12 +162,9 @@ type binding = {node_id: ast::node_id, type region_map = { /* Mapping from a block/function expression to its parent. */ parents: hashmap, - /* Mapping from a region type in the AST to its resolved region. */ - ast_type_to_region: hashmap, + /* Mapping from a local variable to its containing block. */ - local_blocks: hashmap, - /* Mapping from an AST type node to the region that `&` resolves to. */ - ast_type_to_inferred_region: hashmap, + local_blocks: hashmap }; type region_scope = @{ @@ -198,69 +195,6 @@ impl methods for region_scope { fn self_subscope(node_id: ast::node_id) -> region_scope { @{node_id: node_id, kind: rsk_self(self)} } - - fn find(nm: str) -> option { - alt self.kind { - rsk_root { none } - rsk_body(parent) { parent.find(nm) } - rsk_self(parent) { parent.find(nm) } - rsk_binding(parent, bs) { - alt (*bs).find({|b| b.name == nm }) { - none { parent.find(nm) } - some(b) { some(b) } - } - } - } - } - - // fn resolve_anon() -> option { - // alt self.kind { - // rsk_root { none } - // rsk_body(_) { none } - // rsk_self(_) { none } - // rsk_binding(_, _) { ty::re_bound(ty::br_anon) } - // } - // } - - fn resolve_self_helper(bound: bool) -> option { - alt self.kind { - rsk_root { none } - rsk_self(_) if bound { some(ty::re_bound(ty::br_self)) } - rsk_self(_) { some(ty::re_free(self.node_id, ty::br_self)) } - rsk_binding(p, _) { p.resolve_self_helper(bound) } - rsk_body(p) { p.resolve_self_helper(false) } - } - } - - fn resolve_self() -> option { - self.resolve_self_helper(true) - } - - fn resolve_ident(nm: str) -> option { - alt self.find(nm) { - some(b) if b.node_id == self.node_id { - some(ty::re_bound(b.br)) - } - - some(b) { - some(ty::re_free(b.node_id, b.br)) - } - - none { - alt self.kind { - rsk_self(_) | rsk_root | rsk_body(_) { none } - rsk_binding(_, bs) { - let idx = (*bs).len(); - let br = ty::br_param(idx, nm); - vec::push(*bs, {node_id: self.node_id, - name: nm, - br: br}); - some(ty::re_bound(br)) - } - } - } - } - } } type ctxt = { @@ -351,50 +285,6 @@ fn get_inferred_region(cx: ctxt, sp: syntax::codemap::span) -> ty::region { } } -fn resolve_region_binding(cx: ctxt, span: span, - region: ast::region) -> ty::region { - alt region.node { - ast::re_inferred { ty::re_default } - ast::re_static { ty::re_static } - ast::re_named(ident) { - alt cx.scope.resolve_ident(ident) { - some(r) { r } - none { - cx.sess.span_fatal( - span, - #fmt["the region `%s` is not declared", ident]); - } - } - } - ast::re_self { - alt cx.scope.resolve_self() { - some(r) { r } - none { - cx.sess.span_fatal( - span, - "the `self` region is not allowed here"); - } - } - } - } -} - -fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt) { - let inferred_region = get_inferred_region(cx, ty.span); - cx.region_map.ast_type_to_inferred_region.insert(ty.id, inferred_region); - - alt ty.node { - ast::ty_vstore(_, ast::vstore_slice(r)) | - ast::ty_rptr(r, _) { - let region = resolve_region_binding(cx, ty.span, r); - cx.region_map.ast_type_to_region.insert(ty.id, region); - } - _ { /* nothing to do */ } - } - - visit::visit_ty(ty, cx, visitor); -} - fn opt_parent_id(cx: ctxt) -> option { alt cx.parent { pa_fn_item(parent_id) | @@ -531,16 +421,12 @@ fn resolve_crate(sess: session, def_map: resolve::def_map, crate: @ast::crate) let cx: ctxt = {sess: sess, def_map: def_map, region_map: @{parents: map::int_hash(), - ast_type_to_region: map::int_hash(), - local_blocks: map::int_hash(), - ast_type_to_inferred_region: - map::int_hash()}, + local_blocks: map::int_hash()}, scope: root_scope(0), parent: pa_crate}; let visitor = visit::mk_vt(@{ visit_block: resolve_block, visit_item: resolve_item, - visit_ty: resolve_ty, visit_arm: resolve_arm, visit_pat: resolve_pat, visit_expr: resolve_expr, diff --git a/src/rustc/middle/regionck.rs b/src/rustc/middle/regionck.rs index 9af9e89e57b..58c165717c7 100644 --- a/src/rustc/middle/regionck.rs +++ b/src/rustc/middle/regionck.rs @@ -15,12 +15,13 @@ fn check_expr(expr: @ast::expr, visit::visit_expr(expr, tcx, visitor); let t = ty::expr_ty(tcx, expr); - if !ty::type_has_rptrs(t) { ret; } + if !ty::type_has_regions(t) { ret; } ty::walk_ty(t) { |t| alt ty::get(t).struct { ty::ty_rptr(region, _) { alt region { - ty::re_bound(_) | ty::re_free(_, _) | ty::re_static { + ty::re_bound(_) | ty::re_free(_, _) | ty::re_static | + ty::re_var(_) { /* ok */ } ty::re_scope(id) { @@ -31,9 +32,6 @@ fn check_expr(expr: @ast::expr, ppaux::re_scope_id_to_str(tcx, id)]); } } - ty::re_default | ty::re_var(_) { - tcx.sess.span_bug(expr.span, "unresolved region"); - } } } _ { /* no-op */ } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 506ccc4ab18..20cb0990dd3 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -36,7 +36,7 @@ export expr_ty; export expr_ty_params_and_ty; export expr_is_lval; export field_ty; -export fold_ty, fold_sty_to_ty, fold_region, fold_ty_var; +export fold_ty, fold_sty_to_ty, fold_region, fold_regions, fold_ty_var; export field; export field_idx; export get_field; @@ -99,7 +99,7 @@ export ty_uniq, mk_uniq, mk_imm_uniq, type_is_unique_box; export ty_var, mk_var; export ty_self, mk_self; export region, bound_region; -export get, type_has_params, type_has_vars, type_has_rptrs, type_id; +export get, type_has_params, type_has_vars, type_has_regions, type_id; export ty_var_id; export ty_to_def_id; export ty_fn_args; @@ -230,7 +230,7 @@ type t_box = @{struct: sty, id: uint, has_params: bool, has_vars: bool, - has_rptrs: bool, + has_regions: bool, o_def_id: option}; // To reduce refcounting cost, we're representing types as unsafe pointers @@ -250,7 +250,7 @@ pure fn get(t: t) -> t_box unsafe { fn type_has_params(t: t) -> bool { get(t).has_params } fn type_has_vars(t: t) -> bool { get(t).has_vars } -fn type_has_rptrs(t: t) -> bool { get(t).has_rptrs } +fn type_has_regions(t: t) -> bool { get(t).has_regions } fn type_def_id(t: t) -> option { get(t).o_def_id } fn type_id(t: t) -> uint { get(t).id } @@ -272,20 +272,13 @@ enum region { re_free(node_id, bound_region), re_scope(node_id), re_var(region_vid), - re_static, // effectively `top` in the region lattice - re_default + re_static // effectively `top` in the region lattice } enum bound_region { - // The `self` region for a given class/impl/iface. The defining item may - // appear in another crate. - br_self, - - // The anonymous region parameter for a given function. - br_anon, - - // A named region parameter. - br_param(uint, str) + br_self, // The self region for classes, impls + br_anon, // The anonymous region parameter for a given function. + br_named(str) // A named region parameter. } // NB: If you change this, you'll probably want to change the corresponding @@ -461,21 +454,21 @@ fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option) -> t { some(t) { unsafe { ret unsafe::reinterpret_cast(t); } } _ {} } - let mut has_params = false, has_vars = false, has_rptrs = false; - fn derive_flags(&has_params: bool, &has_vars: bool, &has_rptrs: bool, + let mut has_params = false, has_vars = false, has_regions = false; + fn derive_flags(&has_params: bool, &has_vars: bool, &has_regions: bool, tt: t) { let t = get(tt); has_params |= t.has_params; has_vars |= t.has_vars; - has_rptrs |= t.has_rptrs; + has_regions |= t.has_regions; } alt st { ty_estr(vstore_slice(_)) { - has_rptrs = true; + has_regions = true; } ty_evec(mt, vstore_slice(_)) { - has_rptrs = true; - derive_flags(has_params, has_vars, has_rptrs, mt.ty); + has_regions = true; + derive_flags(has_params, has_vars, has_regions, mt.ty); } ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | ty_str | ty_estr(_) | ty_type | ty_opaque_closure_ptr(_) | @@ -484,49 +477,50 @@ fn mk_t_with_id(cx: ctxt, st: sty, o_def_id: option) -> t { ty_var(_) | ty_self(_) { has_vars = true; } ty_enum(_, tys) | ty_iface(_, tys) | ty_class(_, tys) { for tys.each {|tt| - derive_flags(has_params, has_vars, has_rptrs, tt); + derive_flags(has_params, has_vars, has_regions, tt); } } ty_box(m) | ty_uniq(m) | ty_vec(m) | ty_evec(m, _) | ty_ptr(m) { - derive_flags(has_params, has_vars, has_rptrs, m.ty); + derive_flags(has_params, has_vars, has_regions, m.ty); } ty_rptr(r, m) { alt r { ty::re_var(_) { has_vars = true; } _ { } } - has_rptrs = true; - derive_flags(has_params, has_vars, has_rptrs, m.ty); + has_regions = true; + derive_flags(has_params, has_vars, has_regions, m.ty); } ty_rec(flds) { for flds.each {|f| - derive_flags(has_params, has_vars, has_rptrs, f.mt.ty); + derive_flags(has_params, has_vars, has_regions, f.mt.ty); } } ty_tup(ts) { - for ts.each {|tt| derive_flags(has_params, has_vars, has_rptrs, tt); } + for ts.each {|tt| derive_flags(has_params, has_vars, + has_regions, tt); } } ty_fn(f) { for f.inputs.each {|a| - derive_flags(has_params, has_vars, has_rptrs, a.ty); + derive_flags(has_params, has_vars, has_regions, a.ty); } - derive_flags(has_params, has_vars, has_rptrs, f.output); + derive_flags(has_params, has_vars, has_regions, f.output); } ty_res(_, tt, tps) { - derive_flags(has_params, has_vars, has_rptrs, tt); + derive_flags(has_params, has_vars, has_regions, tt); for tps.each {|tt| - derive_flags(has_params, has_vars, has_rptrs, tt); + derive_flags(has_params, has_vars, has_regions, tt); } } ty_constr(tt, _) { - derive_flags(has_params, has_vars, has_rptrs, tt); + derive_flags(has_params, has_vars, has_regions, tt); } } let t = @{struct: st, id: cx.next_id, has_params: has_params, has_vars: has_vars, - has_rptrs: has_rptrs, + has_regions: has_regions, o_def_id: o_def_id}; cx.interner.insert(key, t); cx.next_id += 1u; @@ -771,11 +765,53 @@ fn fold_ty_var(cx: ctxt, t0: t, fldop: fn(ty_vid) -> t) -> t { } } +// n.b. this function is intended to eventually replace fold_region() below, +// that is why its name is so similar. +fn fold_regions( + cx: ctxt, + ty: t, + fldr: fn(r: region, in_fn: bool) -> region) -> t { + + fn do_fold(cx: ctxt, ty: t, in_fn: bool, + fldr: fn(region, bool) -> region) -> t { + let tb = ty::get(ty); + if !tb.has_regions { ret ty; } + alt tb.struct { + ty::ty_rptr(r, mt) { + let m_r = fldr(r, in_fn); + let m_t = do_fold(cx, mt.ty, in_fn, fldr); + ty::mk_rptr(cx, m_r, {ty: m_t, mutbl: mt.mutbl}) + } + ty_estr(vstore_slice(r)) { + let m_r = fldr(r, in_fn); + ty::mk_estr(cx, vstore_slice(m_r)) + } + ty_evec(mt, vstore_slice(r)) { + let m_r = fldr(r, in_fn); + let m_t = do_fold(cx, mt.ty, in_fn, fldr); + ty::mk_evec(cx, {ty: m_t, mutbl: mt.mutbl}, vstore_slice(m_r)) + } + sty @ ty_fn(_) { + fold_sty_to_ty(cx, sty) {|t| + do_fold(cx, t, true, fldr) + } + } + sty { + fold_sty_to_ty(cx, sty) {|t| + do_fold(cx, t, in_fn, fldr) + } + } + } + } + + do_fold(cx, ty, false, fldr) +} + fn fold_region(cx: ctxt, t0: t, fldop: fn(region, bool) -> region) -> t { fn do_fold(cx: ctxt, t0: t, under_r: bool, fldop: fn(region, bool) -> region) -> t { let tb = get(t0); - if !tb.has_rptrs { ret t0; } + if !tb.has_regions { ret t0; } alt tb.struct { ty_rptr(r, {ty: t1, mutbl: m}) { let m_r = fldop(r, under_r); @@ -1544,9 +1580,9 @@ fn type_autoderef(cx: ctxt, t: t) -> t { fn hash_bound_region(br: bound_region) -> uint { alt br { // no idea if this is any good - br_self { 0u } - br_anon { 1u } - br_param(id, _) { id } + ty::br_self { 0u } + ty::br_anon { 1u } + ty::br_named(str) { str::hash(str) } } } @@ -1588,8 +1624,7 @@ fn hash_type_structure(st: sty) -> uint { (hash_bound_region(br)) << 2u | 1u } re_scope(id) { ((id as uint) << 2u) | 2u } re_var(id) { (id.to_uint() << 2u) | 3u } - re_default { 4u } - re_bot { 5u } + re_bot { 4u } } } alt st { diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 77e2dfcb44c..03410694283 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -21,6 +21,8 @@ import std::serialization::{serialize_uint, deserialize_uint}; import std::ufind; import syntax::print::pprust::*; import util::common::indent; +import std::list; +import list::{list, nil, cons}; export check_crate; export method_map; @@ -65,6 +67,10 @@ type crate_ctxt = {impl_map: resolve::impl_map, type class_map = hashmap; +// a list of mapping from in-scope-region-names ("isr") to the +// corresponding ty::region +type isr_alist = @list<(str, ty::region)>; + type fn_ctxt = // var_bindings, locals and next_var_id are shared // with any nested functions that capture the environment @@ -77,8 +83,10 @@ type fn_ctxt = proto: ast::proto, infcx: infer::infer_ctxt, locals: hashmap, - next_var_id: @mut uint, - next_region_var_id: @mut uint, + ty_var_counter: @mut uint, + region_var_counter: @mut uint, + + in_scope_regions: isr_alist, // While type checking a function, the intermediate types for the // expressions, blocks, and so forth contained within the function are @@ -225,7 +233,7 @@ fn instantiate_path(fcx: @fn_ctxt, pth: @ast::path, sp, "this item does not take type parameters"); } let substs = vec::map(pth.node.types, {|aty| - ast_ty_to_ty_crate(fcx.ccx, aty) + fcx.to_ty(aty) }); fcx.write_ty_substs(id, tpt.ty, substs); } else if ty_param_count > 0u { @@ -281,26 +289,6 @@ fn type_is_c_like_enum(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool { ret ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s); } -enum mode { m_collect, m_check, m_check_tyvar(@fn_ctxt), } - -fn ast_ty_vstore_to_vstore(tcx: ty::ctxt, ty: @ast::ty, - v: ast::vstore) -> ty::vstore { - alt v { - ast::vstore_fixed(none) { - tcx.sess.span_bug(ty.span, - "implied fixed length in ast_ty_vstore_to_vstore"); - } - ast::vstore_fixed(some(u)) { - ty::vstore_fixed(u) - } - ast::vstore_uniq { ty::vstore_uniq } - ast::vstore_box { ty::vstore_box } - ast::vstore_slice(r) { - ty::vstore_slice(tcx.region_map.ast_type_to_region.get(ty.id)) - } - } -} - fn ast_expr_vstore_to_vstore(fcx: @fn_ctxt, e: @ast::expr, n: uint, v: ast::vstore) -> ty::vstore { alt v { @@ -315,7 +303,133 @@ fn ast_expr_vstore_to_vstore(fcx: @fn_ctxt, e: @ast::expr, n: uint, ast::vstore_uniq { ty::vstore_uniq } ast::vstore_box { ty::vstore_box } ast::vstore_slice(r) { - ty::vstore_slice(region_of(fcx, e)) + ty::vstore_slice(ast_region_to_region(fcx, fcx, e.span, r)) + } + } +} + +iface ast_conv { + fn tcx() -> ty::ctxt; + fn ccx() -> @crate_ctxt; + fn get_item_ty(id: ast::def_id) -> ty::ty_param_bounds_and_ty; + fn ty_infer(span: span) -> ty::t; +} + +impl of ast_conv for @crate_ctxt { + fn tcx() -> ty::ctxt { self.tcx } + fn ccx() -> @crate_ctxt { self } + + fn get_item_ty(id: ast::def_id) -> ty::ty_param_bounds_and_ty { + if id.crate != ast::local_crate { + csearch::get_type(self.tcx, id) + } else { + alt self.tcx.items.find(id.node) { + some(ast_map::node_item(item, _)) { + ty_of_item(self, item) + } + some(ast_map::node_native_item(native_item, _, _)) { + ty_of_native_item(self, native_item) + } + x { + self.tcx.sess.bug(#fmt["unexpected sort of item \ + in get_item_ty(): %?", x]); + } + } + } + } + + fn ty_infer(span: span) -> ty::t { + self.tcx.sess.span_bug(span, + "found `ty_infer` in unexpected place"); + } +} + +impl of ast_conv for @fn_ctxt { + fn tcx() -> ty::ctxt { self.ccx.tcx } + fn ccx() -> @crate_ctxt { self.ccx } + + fn get_item_ty(id: ast::def_id) -> ty::ty_param_bounds_and_ty { + ty::lookup_item_type(self.tcx(), id) + } + + fn ty_infer(_span: span) -> ty::t { + self.next_ty_var() + } +} + +iface region_scope { + fn anon_region() -> ty::region; + fn named_region(id: str) -> option; +} + +enum base_rscope { base_rscope } +impl of region_scope for base_rscope { + fn anon_region() -> ty::region { ty::re_bound(ty::br_anon) } + fn named_region(_id: str) -> option { none } +} + +impl of region_scope for @fn_ctxt { + fn anon_region() -> ty::region { self.next_region_var() } + fn named_region(id: str) -> option { + self.in_scope_regions.find(id) + } +} + +enum anon_rscope = {anon: ty::region, base: region_scope}; +fn in_anon_rscope(self: RS, r: ty::region) -> @anon_rscope { + @anon_rscope({anon: r, base: self as region_scope}) +} +impl of region_scope for @anon_rscope { + fn anon_region() -> ty::region { self.anon } + fn named_region(id: str) -> option { + self.base.named_region(id) + } +} + +enum self_rscope { self_rscope } +impl of region_scope for self_rscope { + fn anon_region() -> ty::region { ty::re_bound(ty::br_self) } + fn named_region(id: str) -> option { + if id == "self" {some(self.anon_region())} else {none} + } +} + +enum binding_rscope = {base: region_scope}; +fn in_binding_rscope(self: RS) -> @binding_rscope { + let base = self as region_scope; + @binding_rscope({base: base}) +} +impl of region_scope for @binding_rscope { + fn anon_region() -> ty::region { ty::re_bound(ty::br_anon) } + fn named_region(id: str) -> option { + let nr = self.base.named_region(id); + alt nr { + some(r) { some(r) } + none { some(ty::re_bound(ty::br_named(id))) } + } + } +} + +fn ast_region_to_region( + self: AC, rscope: RS, span: span, a_r: ast::region) -> ty::region { + + alt a_r.node { + ast::re_anon { + rscope.anon_region() + } + ast::re_named(id) { + alt rscope.named_region(id) { + some(r) { r } + none { + self.tcx().sess.span_err( + span, + #fmt["named region `%s` not in scope here", id]); + rscope.anon_region() + } + } + } + ast::re_static { + ty::re_static } } } @@ -323,208 +437,211 @@ fn ast_expr_vstore_to_vstore(fcx: @fn_ctxt, e: @ast::expr, n: uint, // Parses the programmer's textual representation of a type into our // 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 getter(tcx: ty::ctxt, mode: mode, id: ast::def_id) - -> ty::ty_param_bounds_and_ty { +fn ast_ty_to_ty( + self: AC, rscope: RS, &&ast_ty: @ast::ty) -> ty::t { - 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) } - else { - alt tcx.items.find(id.node) { - some(ast_map::node_item(item, _)) { - ty_of_item(tcx, mode, item) - } - some(ast_map::node_native_item(native_item, _, _)) { - ty_of_native_item(tcx, mode, native_item) - } - _ { - tcx.sess.bug("unexpected sort of item in ast_ty_to_ty"); - } - } - } - } - } + fn ast_mt_to_mt( + self: AC, rscope: RS, mt: ast::mt) -> ty::mt { + + ret {ty: ast_ty_to_ty(self, rscope, 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, 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; - } + + fn instantiate( + self: AC, rscope: RS, sp: span, id: ast::def_id, + path_id: ast::node_id, args: [@ast::ty]) -> ty::t { + + let tcx = self.tcx(); + let {bounds, ty} = self.get_item_ty(id); + + // The type of items may include a reference to the bound anon region. + // Replace it with the current binding for that region in this + // context. + // + // n.b. Ordinarily, one should do all substitutions at once to avoid + // capture problems. But in this instance it is ok to substitute for + // the bound region first and then type parameters second, as the + // bound region cannot be replaced with a type parameter. + let ty = subst_anon_region(tcx, rscope.anon_region(), ty); // The typedef is type-parametric. Do the type substitution. - let mut param_bindings: [ty::t] = []; - if vec::len(args) != vec::len(*ty_param_bounds_and_ty.bounds) { - tcx.sess.span_fatal(sp, "wrong number of type arguments for a \ - polymorphic type"); + if vec::len(args) != vec::len(*bounds) { + tcx.sess.span_fatal( + sp, "wrong number of type arguments for a \ + polymorphic type"); } - for args.each {|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)})), - ty_to_str(tcx, ty_param_bounds_and_ty.ty)); - let typ = - ty::substitute_type_params(tcx, param_bindings, - ty_param_bounds_and_ty.ty); + let param_bindings = args.map { |t| ast_ty_to_ty(self, rscope, t) }; + #debug("substituting(%? into %?)", + vec::map(param_bindings) {|t| ty_to_str(tcx, t)}, + ty_to_str(tcx, ty)); + let ty = ty::substitute_type_params(tcx, param_bindings, ty); write_substs_to_tcx(tcx, path_id, param_bindings); - ret typ; + ret ty; } - 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) { - tcx.sess.span_fatal(ast_ty.span, "illegal recursive type. \ - insert a enum in the cycle, \ - if this is desired)"); + fn mk_vstore( + self: AC, rscope: RS, a_seq_ty: @ast::ty, vst: ty::vstore) -> ty::t { + + let tcx = self.tcx(); + let seq_ty = ast_ty_to_ty(self, rscope, a_seq_ty); + alt ty::get(seq_ty).struct { + ty::ty_vec(mt) { ty::mk_evec(tcx, mt, vst) } + ty::ty_str { ty::mk_estr(tcx, vst) } + _ { + tcx.sess.span_bug(a_seq_ty.span, + "found sequence storage modifier \ + on non-sequence type") } - none { /* go on */ } } - - tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::atttce_unresolved); - let typ = alt ast_ty.node { - 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, mode, mt)) - } - ast::ty_uniq(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, mode, mt)) - } - ast::ty_ptr(mt) { - ty::mk_ptr(tcx, ast_mt_to_mt(tcx, mode, mt)) - } - ast::ty_rptr(region, mt) { - let region = tcx.region_map.ast_type_to_region.get(ast_ty.id); - 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, mode, _)); - ty::mk_tup(tcx, flds) - } - ast::ty_rec(fields) { - let mut flds: [field] = []; - for fields.each {|f| - 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) { - ty::mk_fn(tcx, ty_of_fn_decl(tcx, mode, proto, decl)) - } - ast::ty_path(path, id) { - let a_def = alt tcx.def_map.find(id) { - none { tcx.sess.span_fatal(ast_ty.span, #fmt("unbound path %s", - path_to_str(path))); } - some(d) { d }}; - alt a_def { - ast::def_ty(did) | ast::def_class(did) { - instantiate(tcx, ast_ty.span, mode, did, - id, path.node.types) - } - ast::def_prim_ty(nty) { - alt nty { - ast::ty_bool { ty::mk_bool(tcx) } - ast::ty_int(it) { ty::mk_mach_int(tcx, it) } - ast::ty_uint(uit) { ty::mk_mach_uint(tcx, uit) } - ast::ty_float(ft) { ty::mk_mach_float(tcx, ft) } - ast::ty_str { ty::mk_str(tcx) } - } - } - ast::def_ty_param(id, n) { - if vec::len(path.node.types) > 0u { - tcx.sess.span_err(ast_ty.span, "provided type parameters \ - to a type parameter"); - } - ty::mk_param(tcx, n, id) - } - ast::def_self(self_id) { - alt check tcx.items.get(self_id) { - ast_map::node_item(@{node: ast::item_iface(tps, _), _}, _) { - if vec::len(tps) != vec::len(path.node.types) { - tcx.sess.span_err(ast_ty.span, "incorrect number of \ - type parameters to \ - self type"); - } - ty::mk_self(tcx, vec::map(path.node.types, {|ast_ty| - do_ast_ty_to_ty(tcx, mode, ast_ty) - })) - } - } - } - _ { - tcx.sess.span_fatal(ast_ty.span, - "found type name used as a variable"); - } - } - } - ast::ty_vstore(t, vst) { - let vst = ast_ty_vstore_to_vstore(tcx, ast_ty, vst); - let ty = alt ty::get(do_ast_ty_to_ty(tcx, mode, t)).struct { - ty::ty_vec(mt) { ty::mk_evec(tcx, mt, vst) } - ty::ty_str { ty::mk_estr(tcx, vst) } - _ { - tcx.sess.span_fatal(ast_ty.span, - "found sequence storage modifier \ - on non-sequence type"); - } - }; - fixup_regions_to_block(tcx, ty, ast_ty) - } - ast::ty_constr(t, cs) { - let mut out_cs = []; - for cs.each {|constr| - 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 { - m_check_tyvar(fcx) { ret fcx.next_ty_var(); } - _ { tcx.sess.span_bug(ast_ty.span, - "found `ty_infer` in unexpected place"); } - } - } - ast::ty_mac(_) { - tcx.sess.span_bug(ast_ty.span, - "found `ty_mac` in unexpected place"); - } - }; - - tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::atttce_resolved(typ)); - ret typ; } - ret do_ast_ty_to_ty(tcx, mode, ast_ty); + let tcx = self.tcx(); + + alt tcx.ast_ty_to_ty_cache.find(ast_ty) { + some(ty::atttce_resolved(ty)) { ret ty; } + some(ty::atttce_unresolved) { + tcx.sess.span_fatal(ast_ty.span, "illegal recursive type. \ + insert a enum in the cycle, \ + if this is desired)"); + } + none { /* go on */ } + } + + tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::atttce_unresolved); + let typ = alt ast_ty.node { + 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(self, rscope, mt)) + } + ast::ty_uniq(mt) { + ty::mk_uniq(tcx, ast_mt_to_mt(self, rscope, mt)) + } + ast::ty_vec(mt) { + ty::mk_vec(tcx, ast_mt_to_mt(self, rscope, mt)) + } + ast::ty_ptr(mt) { + ty::mk_ptr(tcx, ast_mt_to_mt(self, rscope, mt)) + } + ast::ty_rptr(region, mt) { + let r = ast_region_to_region(self, rscope, ast_ty.span, region); + let mt = ast_mt_to_mt(self, in_anon_rscope(rscope, r), mt); + ty::mk_rptr(tcx, r, mt) + } + ast::ty_tup(fields) { + let flds = vec::map(fields) { |t| ast_ty_to_ty(self, rscope, t) }; + ty::mk_tup(tcx, flds) + } + ast::ty_rec(fields) { + let flds = fields.map {|f| + let tm = ast_mt_to_mt(self, rscope, f.node.mt); + {ident: f.node.ident, mt: tm} + }; + ty::mk_rec(tcx, flds) + } + ast::ty_fn(proto, decl) { + ty::mk_fn(tcx, ty_of_fn_decl(self, rscope, proto, decl)) + } + ast::ty_path(path, id) { + let a_def = alt tcx.def_map.find(id) { + none { tcx.sess.span_fatal(ast_ty.span, #fmt("unbound path %s", + path_to_str(path))); } + some(d) { d }}; + alt a_def { + ast::def_ty(did) | ast::def_class(did) { + instantiate(self, rscope, ast_ty.span, did, id, path.node.types) + } + ast::def_prim_ty(nty) { + alt nty { + ast::ty_bool { ty::mk_bool(tcx) } + ast::ty_int(it) { ty::mk_mach_int(tcx, it) } + ast::ty_uint(uit) { ty::mk_mach_uint(tcx, uit) } + ast::ty_float(ft) { ty::mk_mach_float(tcx, ft) } + ast::ty_str { ty::mk_str(tcx) } + } + } + ast::def_ty_param(id, n) { + if vec::len(path.node.types) > 0u { + tcx.sess.span_err(ast_ty.span, "provided type parameters \ + to a type parameter"); + } + ty::mk_param(tcx, n, id) + } + ast::def_self(self_id) { + alt check tcx.items.get(self_id) { + ast_map::node_item(@{node: ast::item_iface(tps, _), _}, _) { + if vec::len(tps) != vec::len(path.node.types) { + tcx.sess.span_err(ast_ty.span, "incorrect number of \ + type parameters to \ + self type"); + } + ty::mk_self(tcx, vec::map(path.node.types, {|ast_ty| + ast_ty_to_ty(self, rscope, ast_ty) + })) + } + } + } + _ { + tcx.sess.span_fatal(ast_ty.span, + "found type name used as a variable"); + } + } + } + ast::ty_vstore(a_t, ast::vstore_slice(a_r)) { + let r = ast_region_to_region(self, rscope, ast_ty.span, a_r); + mk_vstore(self, in_anon_rscope(rscope, r), a_t, ty::vstore_slice(r)) + } + ast::ty_vstore(a_t, ast::vstore_uniq) { + mk_vstore(self, rscope, a_t, ty::vstore_uniq) + } + ast::ty_vstore(a_t, ast::vstore_box) { + mk_vstore(self, rscope, a_t, ty::vstore_box) + } + ast::ty_vstore(a_t, ast::vstore_fixed(some(u))) { + mk_vstore(self, rscope, a_t, ty::vstore_fixed(u)) + } + ast::ty_vstore(_, ast::vstore_fixed(none)) { + tcx.sess.span_bug( + ast_ty.span, + "implied fixed length in ast_ty_vstore_to_vstore"); + } + ast::ty_constr(t, cs) { + let mut out_cs = []; + for cs.each {|constr| + out_cs += [ty::ast_constr_to_constr(tcx, constr)]; + } + ty::mk_constr(tcx, ast_ty_to_ty(self, rscope, t), out_cs) + } + ast::ty_infer { + self.ty_infer(ast_ty.span) + } + ast::ty_mac(_) { + tcx.sess.span_bug(ast_ty.span, + "found `ty_mac` in unexpected place"); + } + }; + + tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::atttce_resolved(typ)); + ret typ; } -fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item) +fn ty_of_item(ccx: @crate_ctxt, it: @ast::item) -> ty::ty_param_bounds_and_ty { + let def_id = local_def(it.id); + let tcx = ccx.tcx; alt tcx.tcache.find(def_id) { some(tpt) { ret tpt; } _ {} } alt it.node { ast::item_const(t, _) { - let typ = ast_ty_to_ty(tcx, mode, t); + let typ = ccx.to_ty(t); let tpt = {bounds: @[], ty: typ}; tcx.tcache.insert(local_def(it.id), tpt); ret tpt; } ast::item_fn(decl, tps, _) { - ret ty_of_fn(tcx, mode, decl, tps, local_def(it.id)); + ret ty_of_fn(ccx, decl, tps, local_def(it.id)); } ast::item_ty(t, tps) { alt tcx.tcache.find(local_def(it.id)) { @@ -534,26 +651,24 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item) // Tell ast_ty_to_ty() that we want to perform a recursive // call to resolve any named types. let tpt = { - let t0 = ast_ty_to_ty(tcx, mode, t); - let t1 = { + let ty = { + let t0 = ccx.to_ty(t); // Do not associate a def id with a named, parameterized type // like "foo". This is because otherwise ty_to_str will // print the name as merely "foo", as it has no way to // reconstruct the value of X. - if vec::is_empty(tps) { + if !vec::is_empty(tps) { t0 } else { ty::mk_with_id(tcx, t0, def_id) - } else { - t0 } }; - {bounds: ty_param_bounds(tcx, mode, tps), ty: t1} + {bounds: ty_param_bounds(ccx, tps), ty: ty} }; tcx.tcache.insert(local_def(it.id), tpt); ret tpt; } ast::item_res(decl, tps, _, _, _) { - let {bounds, params} = mk_ty_params(tcx, tps); - let t_arg = ty_of_arg(tcx, mode, decl.inputs[0]); + let {bounds, params} = mk_ty_params(ccx, tps); + let t_arg = ty_of_arg(ccx, base_rscope, decl.inputs[0]); let t = ty::mk_res(tcx, local_def(it.id), t_arg.ty, params); let t_res = {bounds: bounds, ty: t}; tcx.tcache.insert(local_def(it.id), t_res); @@ -561,21 +676,21 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item) } ast::item_enum(_, tps) { // Create a new generic polytype. - let {bounds, params} = mk_ty_params(tcx, tps); + let {bounds, params} = mk_ty_params(ccx, tps); let t = ty::mk_enum(tcx, local_def(it.id), params); let tpt = {bounds: bounds, ty: t}; tcx.tcache.insert(local_def(it.id), tpt); ret tpt; } ast::item_iface(tps, ms) { - let {bounds, params} = mk_ty_params(tcx, tps); + let {bounds, params} = mk_ty_params(ccx, tps); let t = ty::mk_iface(tcx, local_def(it.id), params); let tpt = {bounds: bounds, ty: t}; tcx.tcache.insert(local_def(it.id), tpt); ret tpt; } ast::item_class(tps,_,_,_) { - let {bounds,params} = mk_ty_params(tcx, tps); + let {bounds,params} = mk_ty_params(ccx, tps); let t = ty::mk_class(tcx, local_def(it.id), params); let tpt = {bounds: bounds, ty: t}; tcx.tcache.insert(local_def(it.id), tpt); @@ -585,11 +700,11 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item) ast::item_native_mod(_) { fail; } } } -fn ty_of_native_item(tcx: ty::ctxt, mode: mode, it: @ast::native_item) +fn ty_of_native_item(ccx: @crate_ctxt, it: @ast::native_item) -> ty::ty_param_bounds_and_ty { alt it.node { ast::native_item_fn(fn_decl, params) { - ret ty_of_native_fn_decl(tcx, mode, fn_decl, params, + ret ty_of_native_fn_decl(ccx, fn_decl, params, local_def(it.id)); } } @@ -597,49 +712,116 @@ fn ty_of_native_item(tcx: ty::ctxt, mode: mode, it: @ast::native_item) type next_region_param_id = { mut id: uint }; -fn replace_default_region(tcx: ty::ctxt, - with_region: ty::region, - ty: ty::t) -> ty::t { - let mut last_region = with_region; - ret ty::fold_region(tcx, ty) {|region, under_rptr| - if !under_rptr { - last_region = alt region { - ty::re_default { with_region } - _ { region } - } - } - last_region - }; -} - -fn default_region_to_bound_anon(tcx: ty::ctxt, ty: ty::t) -> ty::t { - replace_default_region(tcx, ty::re_bound(ty::br_anon), ty) -} - -fn default_region_to_bound_self(tcx: ty::ctxt, ty: ty::t) -> ty::t { - replace_default_region(tcx, ty::re_bound(ty::br_self), 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); - replace_default_region(tcx, region, ty) -} - -fn replace_bound_regions_with_free_regions( +fn collect_named_regions_in_tys( tcx: ty::ctxt, - id: ast::node_id, + isr: isr_alist, + tys: [ty::t], + to_r: fn(str) -> ty::region) -> isr_alist { + + tys.foldl(isr) { |isr, t| + collect_named_regions_in_ty(tcx, isr, t, to_r) + } +} + +fn collect_named_regions_in_ty( + _tcx: ty::ctxt, + isr: isr_alist, + ty: ty::t, + to_r: fn(str) -> ty::region) -> isr_alist { + + fn append_isr(isr: isr_alist, + to_r: fn(str) -> ty::region, + r: ty::region) -> isr_alist { + alt r { + ty::re_free(_, _) | ty::re_static | ty::re_scope(_) | + ty::re_var(_) | ty::re_bound(ty::br_anon) | + ty::re_bound(ty::br_self) { + isr + } + ty::re_bound(br @ ty::br_named(id)) { + alt isr.find(id) { + some(_) { isr } + none { @cons((id, to_r(id)), isr) } + } + } + } + } + + let mut isr = isr; + + ty::maybe_walk_ty(ty) {|t| + alt ty::get(t).struct { + // do not walk fn contents + ty::ty_fn(_) { false } + + // collect named regions into the isr list + ty::ty_evec(_, ty::vstore_slice(r)) | + ty::ty_estr(ty::vstore_slice(r)) | + ty::ty_rptr(r, _) { isr = append_isr(isr, to_r, r); true } + + // otherwise just walk the types + _ { true } + } + } + + ret isr; +} + +fn replace_bound_self( + tcx: ty::ctxt, + self_r: ty::region, ty: ty::t) -> ty::t { - ty::fold_region(tcx, ty) {|region, _under_rptr| - alt region { - ty::re_bound(br) { ty::re_free(id, br) } - _ { region } + ty::fold_regions(tcx, ty) { |r, _in_fn| + if r == ty::re_bound(ty::br_self) {self_r} else {r} + } +} + +fn replace_bound_regions( + tcx: ty::ctxt, + span: span, + anon_r: ty::region, + isr: isr_alist, + ty: ty::t) -> ty::t { + + ty::fold_regions(tcx, ty) { |r, in_fn| + alt r { + ty::re_bound(ty::br_named(id)) { + alt isr.find(id) { + // In most cases, all named, bound regions will be mapped to + // some free region. + some(fr) { fr } + + // But in the case of a fn() type, there may be named regions + // within that remain bound: + none { assert in_fn; r } + } + } + + // As long as we are not within a fn() type, `&T` is mapped to the + // free region anon_r. But within a fn type, it remains bound. + ty::re_bound(ty::br_anon) if !in_fn { anon_r } + ty::re_bound(ty::br_anon) { r } + + // The &self region is special. Any bound references to self should + // have already been replaced using replace_bound_self() when + // this function is called. + ty::re_bound(ty::br_self) { + tcx.sess.span_bug(span, "Bound self region found"); + } + + // Free regions like these just stay the same: + ty::re_static | + ty::re_scope(_) | + ty::re_free(_, _) | + ty::re_var(_) { r } } } } -fn ty_of_arg(tcx: ty::ctxt, mode: mode, a: ast::arg) -> ty::arg { +fn ty_of_arg( + self: AC, rscope: RS, a: ast::arg) -> ty::arg { + fn arg_mode(tcx: ty::ctxt, m: ast::mode, ty: ty::t) -> ast::mode { alt m { ast::infer(_) { @@ -663,117 +845,113 @@ fn ty_of_arg(tcx: ty::ctxt, mode: mode, a: ast::arg) -> ty::arg { } } - let ty = ast_ty_to_ty(tcx, mode, a.ty); - let mode = arg_mode(tcx, a.mode, ty); + let ty = ast_ty_to_ty(self, rscope, a.ty); + let mode = arg_mode(self.tcx(), a.mode, ty); {mode: mode, ty: ty} } -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| - let arg_ty = ty_of_arg(tcx, mode, a); - {ty: default_region_to_bound_anon(tcx, arg_ty.ty) - with arg_ty} - }; +fn ty_of_fn_decl( + self: AC, rscope: RS, + proto: ast::proto, + decl: ast::fn_decl) -> ty::fn_ty { - let output_ty = { - let t = ast_ty_to_ty(tcx, mode, decl.output); - default_region_to_bound_anon(tcx, t) - }; - - let out_constrs = vec::map(decl.constraints) {|constr| - ty::ast_constr_to_constr(tcx, constr) - }; - {proto: proto, inputs: input_tys, - output: output_ty, ret_style: decl.cf, constraints: out_constrs} + #debug["ty_of_fn_decl"]; + indent {|| + // new region names that appear inside of the fn decl are bound to + // that function type + let rb = in_binding_rscope(rscope); + let input_tys = vec::map(decl.inputs) { |a| ty_of_arg(self, rb, a) }; + let output_ty = ast_ty_to_ty(self, rb, decl.output); + let out_constrs = vec::map(decl.constraints) {|constr| + ty::ast_constr_to_constr(self.tcx(), constr) + }; + {proto: proto, inputs: input_tys, + output: output_ty, ret_style: decl.cf, constraints: out_constrs} + } } -fn ty_of_fn(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl, - ty_params: [ast::ty_param], def_id: ast::def_id) - -> ty::ty_param_bounds_and_ty { - let bounds = ty_param_bounds(tcx, mode, ty_params); - let tofd = ty_of_fn_decl(tcx, mode, ast::proto_bare, decl); - let tpt = {bounds: bounds, ty: ty::mk_fn(tcx, tofd)}; - tcx.tcache.insert(def_id, tpt); + +fn ty_of_fn(ccx: @crate_ctxt, + decl: ast::fn_decl, + ty_params: [ast::ty_param], + def_id: ast::def_id) -> ty::ty_param_bounds_and_ty { + + let bounds = ty_param_bounds(ccx, ty_params); + let tofd = ty_of_fn_decl(ccx, base_rscope, ast::proto_bare, decl); + let tpt = {bounds: bounds, ty: ty::mk_fn(ccx.tcx, tofd)}; + ccx.tcx.tcache.insert(def_id, tpt); ret tpt; } -fn ty_of_native_fn_decl(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl, - ty_params: [ast::ty_param], def_id: ast::def_id) - -> ty::ty_param_bounds_and_ty { - let bounds = ty_param_bounds(tcx, mode, ty_params); - 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 t_fn = ty::mk_fn(tcx, {proto: ast::proto_bare, - inputs: input_tys, - output: output_ty, - ret_style: ast::return_val, - constraints: []}); +fn ty_of_native_fn_decl(ccx: @crate_ctxt, + decl: ast::fn_decl, + ty_params: [ast::ty_param], + def_id: ast::def_id) -> ty::ty_param_bounds_and_ty { + + let bounds = ty_param_bounds(ccx, ty_params); + let rb = in_binding_rscope(base_rscope); + let input_tys = vec::map(decl.inputs) { |a| ty_of_arg(ccx, rb, a) }; + let output_ty = ast_ty_to_ty(ccx, rb, decl.output); + + let t_fn = ty::mk_fn(ccx.tcx, {proto: ast::proto_bare, + inputs: input_tys, + output: output_ty, + ret_style: ast::return_val, + constraints: []}); let tpt = {bounds: bounds, ty: t_fn}; - tcx.tcache.insert(def_id, tpt); + ccx.tcx.tcache.insert(def_id, tpt); ret tpt; } -fn ty_param_bounds(tcx: ty::ctxt, mode: mode, params: [ast::ty_param]) - -> @[ty::param_bounds] { - let mut result = []; - for params.each {|param| - result += [alt tcx.ty_param_bounds.find(param.id) { + +fn ty_param_bounds(ccx: @crate_ctxt, + params: [ast::ty_param]) -> @[ty::param_bounds] { + + @params.map { |param| + alt ccx.tcx.ty_param_bounds.find(param.id) { some(bs) { bs } none { - let mut bounds = []; - for vec::each(*param.bounds) {|b| - bounds += [alt b { + let bounds = @vec::map(*param.bounds) { |b| + alt b { ast::bound_send { ty::bound_send } ast::bound_copy { ty::bound_copy } ast::bound_iface(t) { - let ity = ast_ty_to_ty(tcx, mode, t); + let ity = ccx.to_ty(t); alt ty::get(ity).struct { ty::ty_iface(_, _) {} _ { - tcx.sess.span_fatal( + ccx.tcx.sess.span_fatal( t.span, "type parameter bounds must be \ interface types"); } } ty::bound_iface(ity) } - }]; - } - let boxed = @bounds; - tcx.ty_param_bounds.insert(param.id, boxed); - boxed + } + }; + ccx.tcx.ty_param_bounds.insert(param.id, bounds); + bounds } - }]; + } } - @result } -fn ty_of_method(tcx: ty::ctxt, mode: mode, m: @ast::method) -> ty::method { - {ident: m.ident, tps: ty_param_bounds(tcx, mode, m.tps), - fty: ty_of_fn_decl(tcx, mode, ast::proto_bare, m.decl), + +fn ty_of_method(ccx: @crate_ctxt, m: @ast::method) -> ty::method { + {ident: m.ident, tps: ty_param_bounds(ccx, m.tps), + fty: ty_of_fn_decl(ccx, base_rscope, ast::proto_bare, m.decl), purity: m.decl.purity, privacy: m.privacy} } -fn ty_of_ty_method(tcx: ty::ctxt, mode: mode, m: ast::ty_method) - -> ty::method { - {ident: m.ident, tps: ty_param_bounds(tcx, mode, m.tps), - fty: ty_of_fn_decl(tcx, mode, ast::proto_bare, m.decl), - // assume public, because this is only invoked on iface methods + +fn ty_of_ty_method(self: @crate_ctxt, m: ast::ty_method) -> ty::method { + {ident: m.ident, + tps: ty_param_bounds(self, m.tps), + fty: ty_of_fn_decl(self, base_rscope, ast::proto_bare, m.decl), + // assume public, because this is only invoked on iface methods purity: m.decl.purity, privacy: ast::pub} } -// A convenience function to use a crate_ctxt to resolve names for -// ast_ty_to_ty. -fn ast_ty_to_ty_crate(ccx: @crate_ctxt, &&ast_ty: @ast::ty) -> ty::t { - ret ast_ty_to_ty(ccx.tcx, m_check, ast_ty); -} - // A wrapper around ast_ty_to_ty_crate that handles ty_infer. -fn ast_ty_to_ty_crate_infer(ccx: @crate_ctxt, &&ast_ty: @ast::ty) -> - option { +fn ast_ty_to_ty_infer(fcx: @fn_ctxt, &&ast_ty: @ast::ty) -> option { alt ast_ty.node { ast::ty_infer { none } - _ { some(ast_ty_to_ty_crate(ccx, ast_ty)) } + _ { some(fcx.to_ty(ast_ty)) } } } @@ -785,7 +963,9 @@ fn write_ty_to_tcx(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t) { } fn write_substs_to_tcx(tcx: ty::ctxt, node_id: ast::node_id, +substs: [ty::t]) { - tcx.node_type_substs.insert(node_id, substs); + if substs.len() > 0u { + tcx.node_type_substs.insert(node_id, substs); + } } fn write_ty_substs_to_tcx(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t, +substs: [ty::t]) { @@ -798,8 +978,27 @@ fn write_ty_substs_to_tcx(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t, } } +impl methods for @crate_ctxt { + fn to_ty(ast_ty: @ast::ty) -> ty::t { + ast_ty_to_ty(self, base_rscope, ast_ty) + } + + fn to_self_ty(ast_ty: @ast::ty) -> ty::t { + ast_ty_to_ty(self, self_rscope, ast_ty) + } +} + +impl methods for isr_alist { + fn find(id: str) -> option { + for list::each(*self) { |isr| + let (isr_id, isr_r) = isr; + if isr_id == id { ret some(isr_r); } + } + ret none; + } +} + impl methods for @fn_ctxt { - fn tcx() -> ty::ctxt { self.ccx.tcx } fn tag() -> str { #fmt["%x", ptr::addr_of(*self) as uint] } fn ty_to_str(t: ty::t) -> str { ty_to_str(self.ccx.tcx, resolve_type_vars_if_possible(self, t)) @@ -828,6 +1027,10 @@ impl methods for @fn_ctxt { self.write_ty(node_id, ty::mk_bot(self.tcx())); } + fn to_ty(ast_t: @ast::ty) -> ty::t { + ast_ty_to_ty(self, self, ast_t) + } + fn expr_ty(ex: @ast::expr) -> ty::t { alt self.node_types.find(ex.id as uint) { some(t) { t } @@ -863,8 +1066,8 @@ impl methods for @fn_ctxt { self.node_type_substs.find(id) } fn next_ty_var_id() -> ty_vid { - let id = *self.next_var_id; - *self.next_var_id += 1u; + let id = *self.ty_var_counter; + *self.ty_var_counter += 1u; ret ty_vid(id); } fn next_ty_var() -> ty::t { @@ -873,6 +1076,14 @@ impl methods for @fn_ctxt { fn next_ty_vars(n: uint) -> [ty::t] { vec::from_fn(n) {|_i| self.next_ty_var() } } + fn next_region_var_id() -> region_vid { + let id = *self.region_var_counter; + *self.region_var_counter += 1u; + ret region_vid(id); + } + fn next_region_var() -> ty::region { + ret ty::re_var(self.next_region_var_id()); + } fn report_mismatched_types(sp: span, e: ty::t, a: ty::t, err: ty::type_err) { self.ccx.tcx.sess.span_err( @@ -884,13 +1095,14 @@ impl methods for @fn_ctxt { } } -fn mk_ty_params(tcx: ty::ctxt, atps: [ast::ty_param]) +fn mk_ty_params(ccx: @crate_ctxt, atps: [ast::ty_param]) -> {bounds: @[ty::param_bounds], params: [ty::t]} { + let mut i = 0u; - let bounds = ty_param_bounds(tcx, m_collect, atps); + let bounds = ty_param_bounds(ccx, atps); {bounds: bounds, params: vec::map(atps, {|atp| - let t = ty::mk_param(tcx, i, local_def(atp.id)); + let t = ty::mk_param(ccx.tcx, i, local_def(atp.id)); i += 1u; t })} @@ -1050,9 +1262,11 @@ fn instantiate_bound_regions(tcx: ty::ctxt, region: ty::region, &&ty: ty::t) // We then annotate the AST with the resulting types and return the annotated // AST, along with a table mapping item IDs to their types. mod collect { - fn get_enum_variant_types(tcx: ty::ctxt, enum_ty: ty::t, + fn get_enum_variant_types(ccx: @crate_ctxt, enum_ty: ty::t, variants: [ast::variant], ty_params: [ast::ty_param]) { + let tcx = ccx.tcx; + // Create a set of parameter types shared among all the variants. for variants.each {|variant| // Nullary enum constructors get turned into constants; n-ary enum @@ -1062,170 +1276,174 @@ mod collect { } else { // As above, tell ast_ty_to_ty() that trans_ty_item_to_ty() // should be called to resolve named types. - let mut args: [arg] = []; - for variant.node.args.each {|va| - let arg_ty = { - // NDM We need BOUNDS here. It should be that this - // yields a type like "foo &anon". Basically every - // nominal type is going to require a region bound. - let arg_ty = ast_ty_to_ty(tcx, m_collect, va.ty); - default_region_to_bound_anon(tcx, arg_ty) - }; - - args += [{mode: ast::expl(ast::by_copy), ty: arg_ty}]; - } + let args = variant.node.args.map { |va| + {mode: ast::expl(ast::by_copy), + ty: ccx.to_ty(va.ty)} + }; // FIXME: this will be different for constrained types ty::mk_fn(tcx, {proto: ast::proto_box, inputs: args, output: enum_ty, ret_style: ast::return_val, constraints: []}) }; - let tpt = {bounds: ty_param_bounds(tcx, m_collect, ty_params), + let tpt = {bounds: ty_param_bounds(ccx, ty_params), ty: result_ty}; tcx.tcache.insert(local_def(variant.node.id), tpt); write_ty_to_tcx(tcx, variant.node.id, result_ty); } } - fn ensure_iface_methods(tcx: ty::ctxt, id: ast::node_id) { - fn store_methods(tcx: ty::ctxt, id: ast::node_id, + + fn ensure_iface_methods(ccx: @crate_ctxt, id: ast::node_id) { + fn store_methods(ccx: @crate_ctxt, id: ast::node_id, stuff: [T], f: fn@(T) -> ty::method) { - ty::store_iface_methods(tcx, id, @vec::map(stuff, f)); + ty::store_iface_methods(ccx.tcx, id, @vec::map(stuff, f)); } + let tcx = ccx.tcx; alt check tcx.items.get(id) { ast_map::node_item(@{node: ast::item_iface(_, ms), _}, _) { - store_methods::(tcx, id, ms, {|m| - ty_of_ty_method(tcx, m_collect, m)}); + store_methods::(ccx, id, ms) {|m| + ty_of_ty_method(ccx, m) + }; } ast_map::node_item(@{node: ast::item_class(_,_,its,_), _}, _) { let (_,ms) = split_class_items(its); // All methods need to be stored, since lookup_method // relies on the same method cache for self-calls - store_methods::<@ast::method>(tcx, id, ms, {|m| - ty_of_method(tcx, m_collect, m)}); + store_methods::<@ast::method>(ccx, id, ms) {|m| + ty_of_method(ccx, m) + }; } } } - fn check_methods_against_iface(tcx: ty::ctxt, tps: [ast::ty_param], - selfty: ty::t, t: @ast::ty, ms: [@ast::method]) { - let i_bounds = ty_param_bounds(tcx, m_collect, tps); - let my_methods = convert_methods(tcx, ms, i_bounds, some(selfty)); - let iface_ty = ast_ty_to_ty(tcx, m_collect, t); - alt ty::get(iface_ty).struct { - ty::ty_iface(did, tys) { - // Store the iface type in the type node - alt check t.node { - ast::ty_path(_, t_id) { - write_ty_to_tcx(tcx, t_id, iface_ty); - } - } - if did.crate == ast::local_crate { - ensure_iface_methods(tcx, did.node); - } - for vec::each(*ty::iface_methods(tcx, did)) {|if_m| - alt vec::find(my_methods, - {|m| if_m.ident == m.mty.ident}) { - some({mty: m, id, span}) { - if m.purity != if_m.purity { - tcx.sess.span_err( - span, "method `" + m.ident + "`'s purity \ - not match the iface method's \ - purity"); - } - let mt = compare_impl_method( - tcx, span, m, vec::len(tps), if_m, tys, - selfty); - let old = tcx.tcache.get(local_def(id)); - if old.ty != mt { - tcx.tcache.insert(local_def(id), - {bounds: old.bounds, - ty: mt}); - write_ty_to_tcx(tcx, id, mt); - } + + fn check_methods_against_iface(ccx: @crate_ctxt, tps: [ast::ty_param], + selfty: ty::t, t: @ast::ty, + ms: [@ast::method]) { + + let tcx = ccx.tcx; + let i_bounds = ty_param_bounds(ccx, tps); + let my_methods = convert_methods(ccx, ms, i_bounds, some(selfty)); + let iface_ty = ccx.to_ty(t); + alt ty::get(iface_ty).struct { + ty::ty_iface(did, tys) { + // Store the iface type in the type node + alt check t.node { + ast::ty_path(_, t_id) { + write_ty_to_tcx(tcx, t_id, iface_ty); } - none { - tcx.sess.span_err(t.span, "missing method `" + - if_m.ident + "`"); - } - } // alt - } // |if_m| - } // for - _ { + } + if did.crate == ast::local_crate { + ensure_iface_methods(ccx, did.node); + } + for vec::each(*ty::iface_methods(tcx, did)) {|if_m| + alt vec::find(my_methods, + {|m| if_m.ident == m.mty.ident}) { + some({mty: m, id, span}) { + if m.purity != if_m.purity { + ccx.tcx.sess.span_err( + span, #fmt["method `%s`'s purity \ + not match the iface method's \ + purity", m.ident]); + } + let mt = compare_impl_method( + ccx.tcx, span, m, vec::len(tps), + if_m, tys, selfty); + let old = tcx.tcache.get(local_def(id)); + if old.ty != mt { + tcx.tcache.insert(local_def(id), + {bounds: old.bounds, + ty: mt}); + write_ty_to_tcx(tcx, id, mt); + } + } + none { + tcx.sess.span_err(t.span, "missing method `" + + if_m.ident + "`"); + } + } // alt + } // |if_m| + } // for + _ { tcx.sess.span_fatal(t.span, "can only implement \ interface types"); } - } + } } - fn convert_class_item(tcx: ty::ctxt, v: ast_util::ivar) { + fn convert_class_item(ccx: @crate_ctxt, v: ast_util::ivar) { /* we want to do something here, b/c within the scope of the class, it's ok to refer to fields & methods unqualified */ /* they have these types *within the scope* of the class. outside the class, it's done with expr_field */ - let tt = ast_ty_to_ty(tcx, m_collect, v.ty); + let tt = ccx.to_self_ty(v.ty); #debug("convert_class_item: %s %?", v.ident, v.id); - write_ty_to_tcx(tcx, v.id, tt); + write_ty_to_tcx(ccx.tcx, v.id, tt); } - fn convert_methods(tcx: ty::ctxt, ms: [@ast::method], - i_bounds: @[ty::param_bounds], maybe_self: option) + + fn convert_methods(ccx: @crate_ctxt, ms: [@ast::method], + i_bounds: @[ty::param_bounds], + maybe_self: option) -> [{mty: ty::method, id: ast::node_id, span: span}] { - let mut my_methods = []; - for ms.each {|m| - alt maybe_self { + + let tcx = ccx.tcx; + vec::map(ms) { |m| + alt maybe_self { some(selfty) { write_ty_to_tcx(tcx, m.self_id, selfty); } - _ {} + _ {} } - let bounds = ty_param_bounds(tcx, m_collect, m.tps); - let mty = ty_of_method(tcx, m_collect, m); - my_methods += [{mty: mty, id: m.id, span: m.span}]; - let fty = ty::mk_fn(tcx, mty.fty); - tcx.tcache.insert(local_def(m.id), - {bounds: @(*i_bounds + *bounds), - ty: fty}); - write_ty_to_tcx(tcx, m.id, fty); + let bounds = ty_param_bounds(ccx, m.tps); + let mty = ty_of_method(ccx, m); + let fty = ty::mk_fn(tcx, mty.fty); + tcx.tcache.insert(local_def(m.id), + {bounds: @(*i_bounds + *bounds), + ty: fty}); + write_ty_to_tcx(tcx, m.id, fty); + {mty: mty, id: m.id, span: m.span} } - my_methods } - fn convert(tcx: ty::ctxt, it: @ast::item) { + + fn convert(ccx: @crate_ctxt, it: @ast::item) { + let tcx = ccx.tcx; alt it.node { // These don't define types. ast::item_mod(_) {} ast::item_native_mod(m) { if syntax::attr::native_abi(it.attrs) == either::right(ast::native_abi_rust_intrinsic) { - for m.items.each {|item| check_intrinsic_type(tcx, item); } + for m.items.each { |item| check_intrinsic_type(ccx, item); } } } ast::item_enum(variants, ty_params) { - let tpt = ty_of_item(tcx, m_collect, it); + let tpt = ty_of_item(ccx, it); write_ty_to_tcx(tcx, it.id, tpt.ty); - get_enum_variant_types(tcx, tpt.ty, variants, ty_params); + get_enum_variant_types(ccx, tpt.ty, variants, ty_params); } ast::item_impl(tps, ifce, selfty, ms) { - let i_bounds = ty_param_bounds(tcx, m_collect, tps); - let selfty = ast_ty_to_ty(tcx, m_collect, selfty); + let i_bounds = ty_param_bounds(ccx, tps); + let selfty = ccx.to_self_ty(selfty); write_ty_to_tcx(tcx, it.id, selfty); - tcx.tcache.insert(local_def(it.id), {bounds: i_bounds, - ty: selfty}); + tcx.tcache.insert(local_def(it.id), + {bounds: i_bounds, ty: selfty}); alt ifce { some(t) { - check_methods_against_iface(tcx, tps, selfty, - t, ms); } + check_methods_against_iface(ccx, tps, selfty, t, ms); + } _ { - // Still have to do this to write method types - // into the table - convert_methods(tcx, ms, i_bounds, some(selfty)); + // Still have to do this to write method types + // into the table + convert_methods(ccx, ms, i_bounds, some(selfty)); } } } ast::item_res(decl, tps, _, dtor_id, ctor_id) { - let {bounds, params} = mk_ty_params(tcx, tps); + let {bounds, params} = mk_ty_params(ccx, tps); let def_id = local_def(it.id); - let t_arg = ty_of_arg(tcx, m_collect, decl.inputs[0]); + let t_arg = ty_of_arg(ccx, base_rscope, decl.inputs[0]); let t_res = ty::mk_res(tcx, def_id, t_arg.ty, params); let t_ctor = ty::mk_fn(tcx, { proto: ast::proto_box, @@ -1246,34 +1464,36 @@ mod collect { write_ty_to_tcx(tcx, dtor_id, t_dtor); } ast::item_iface(_, ms) { - let tpt = ty_of_item(tcx, m_collect, it); + let tpt = ty_of_item(ccx, it); write_ty_to_tcx(tcx, it.id, tpt.ty); - ensure_iface_methods(tcx, it.id); + ensure_iface_methods(ccx, it.id); } ast::item_class(tps, ifaces, members, ctor) { // Write the class type - let tpt = ty_of_item(tcx, m_collect, it); + let tpt = ty_of_item(ccx, it); write_ty_to_tcx(tcx, it.id, tpt.ty); // Write the ctor type - let t_ctor = ty::mk_fn(tcx, - ty_of_fn_decl(tcx, m_collect, - ast::proto_any, ctor.node.dec)); + let t_ctor = + ty::mk_fn(tcx, + ty_of_fn_decl(ccx, base_rscope, + ast::proto_any, + ctor.node.dec)); write_ty_to_tcx(tcx, ctor.node.id, t_ctor); tcx.tcache.insert(local_def(ctor.node.id), {bounds: tpt.bounds, ty: t_ctor}); - ensure_iface_methods(tcx, it.id); + ensure_iface_methods(ccx, it.id); /* FIXME: check for proper public/privateness */ // Write the type of each of the members let (fields, methods) = split_class_items(members); for fields.each {|f| - convert_class_item(tcx, f); + convert_class_item(ccx, f); } // The selfty is just the class type let selfty = ty::mk_class(tcx, local_def(it.id), - mk_ty_params(tcx, tps).params); + mk_ty_params(ccx, tps).params); // Need to convert all methods so we can check internal // references to private methods - convert_methods(tcx, methods, @[], some(selfty)); + convert_methods(ccx, methods, @[], some(selfty)); /* Finally, check that the class really implements the ifaces that it claims to implement. @@ -1284,8 +1504,8 @@ mod collect { let t = ty::lookup_item_type(tcx, t_id).ty; alt ty::get(t).struct { ty::ty_iface(_,_) { - write_ty_to_tcx(tcx, ifce.id, t); - check_methods_against_iface(tcx, tps, selfty, + write_ty_to_tcx(tcx, ifce.id, t); + check_methods_against_iface(ccx, tps, selfty, @{id: ifce.id, node: ast::ty_path(ifce.path, ifce.id), span: ifce.path.span}, @@ -1304,26 +1524,26 @@ mod collect { // This call populates the type cache with the converted type // of the item in passing. All we have to do here is to write // it into the node type table. - let tpt = ty_of_item(tcx, m_collect, it); + let tpt = ty_of_item(ccx, it); write_ty_to_tcx(tcx, it.id, tpt.ty); } } } - fn convert_native(tcx: ty::ctxt, i: @ast::native_item) { + fn convert_native(ccx: @crate_ctxt, i: @ast::native_item) { // As above, this call populates the type table with the converted // type of the native item. We simply write it into the node type // table. - let tpt = ty_of_native_item(tcx, m_collect, i); + let tpt = ty_of_native_item(ccx, i); alt i.node { ast::native_item_fn(_, _) { - write_ty_to_tcx(tcx, i.id, tpt.ty); + write_ty_to_tcx(ccx.tcx, i.id, tpt.ty); } } } - fn collect_item_types(tcx: ty::ctxt, crate: @ast::crate) { + fn collect_item_types(ccx: @crate_ctxt, crate: @ast::crate) { visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{ - visit_item: bind convert(tcx, _), - visit_native_item: bind convert_native(tcx, _) + visit_item: bind convert(ccx, _), + visit_native_item: bind convert_native(ccx, _) with *visit::default_simple_visitor() })); } @@ -1661,23 +1881,24 @@ mod writeback { } -fn check_intrinsic_type(tcx: ty::ctxt, it: @ast::native_item) { - fn param(tcx: ty::ctxt, n: uint) -> ty::t { - ty::mk_param(tcx, n, local_def(0)) +fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::native_item) { + fn param(ccx: @crate_ctxt, n: uint) -> ty::t { + ty::mk_param(ccx.tcx, n, local_def(0)) } fn arg(m: ast::rmode, ty: ty::t) -> ty::arg { {mode: ast::expl(m), ty: ty} } + let tcx = ccx.tcx; let (n_tps, inputs, output) = alt it.ident { - "size_of" | "align_of" { (1u, [], ty::mk_uint(tcx)) } + "size_of" | "align_of" { (1u, [], ty::mk_uint(ccx.tcx)) } "get_tydesc" { (1u, [], ty::mk_nil_ptr(tcx)) } - "init" { (1u, [], param(tcx, 0u)) } - "forget" { (1u, [arg(ast::by_move, param(tcx, 0u))], + "init" { (1u, [], param(ccx, 0u)) } + "forget" { (1u, [arg(ast::by_move, param(ccx, 0u))], ty::mk_nil(tcx)) } - "reinterpret_cast" { (2u, [arg(ast::by_ref, param(tcx, 0u))], - param(tcx, 1u)) } - "addr_of" { (1u, [arg(ast::by_ref, param(tcx, 0u))], - ty::mk_imm_ptr(tcx, param(tcx, 0u))) } + "reinterpret_cast" { (2u, [arg(ast::by_ref, param(ccx, 0u))], + param(ccx, 1u)) } + "addr_of" { (1u, [arg(ast::by_ref, param(ccx, 0u))], + ty::mk_imm_ptr(tcx, param(ccx, 0u))) } other { tcx.sess.span_err(it.span, "unrecognized intrinsic function: `" + other + "`"); @@ -1688,7 +1909,7 @@ fn check_intrinsic_type(tcx: ty::ctxt, it: @ast::native_item) { inputs: inputs, output: output, ret_style: ast::return_val, constraints: []}); - let i_ty = ty_of_native_item(tcx, m_collect, it); + let i_ty = ty_of_native_item(ccx, it); let i_n_tps = (*i_ty.bounds).len(); if i_n_tps != n_tps { tcx.sess.span_err(it.span, #fmt("intrinsic has wrong number \ @@ -1699,7 +1920,7 @@ fn check_intrinsic_type(tcx: ty::ctxt, it: @ast::native_item) { tcx, it.span, i_ty.ty, fty, {|| #fmt["intrinsic has wrong type. \ expected %s", - ty_to_str(tcx, fty)]}); + ty_to_str(ccx.tcx, fty)]}); } } @@ -1708,101 +1929,7 @@ fn check_intrinsic_type(tcx: ty::ctxt, it: @ast::native_item) { type gather_result = {infcx: infer::infer_ctxt, locals: hashmap, - next_var_id: @mut uint}; - -// Used only as a helper for check_fn. -fn gather_locals(ccx: @crate_ctxt, - decl: ast::fn_decl, - body: ast::blk, - arg_tys: [ty::t], - old_fcx: option<@fn_ctxt>) -> gather_result { - let {infcx, locals, nvi} = alt old_fcx { - none { - {infcx: infer::new_infer_ctxt(ccx.tcx), - locals: int_hash(), - nvi: @mut 0u} - } - some(fcx) { - {infcx: fcx.infcx, - locals: fcx.locals, - nvi: fcx.next_var_id} - } - }; - let tcx = ccx.tcx; - - let next_var_id = fn@() -> uint { - let rv = *nvi; *nvi += 1u; ret rv; - }; - - let assign = fn@(nid: ast::node_id, ty_opt: option) { - let var_id = ty_vid(next_var_id()); - locals.insert(nid, var_id); - alt ty_opt { - none {/* nothing to do */ } - some(typ) { - infer::mk_eqty(infcx, ty::mk_var(tcx, var_id), typ); - } - } - }; - - // Add formal parameters. - vec::iter2(arg_tys, decl.inputs) {|arg_ty, input| - assign(input.id, some(arg_ty)); - #debug["Argument %s is assigned to %s", - input.ident, locals.get(input.id).to_str()]; - } - - // Add explicitly-declared locals. - let visit_local = fn@(local: @ast::local, &&e: (), v: visit::vt<()>) { - 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); - #debug["Local variable %s is assigned to %s", - pat_to_str(local.node.pat), - locals.get(local.node.id).to_str()]; - visit::visit_local(local, e, v); - }; - - // Add pattern bindings. - let visit_pat = fn@(p: @ast::pat, &&e: (), v: visit::vt<()>) { - alt p.node { - ast::pat_ident(path, _) - if !pat_util::pat_is_variant(ccx.tcx.def_map, p) { - assign(p.id, none); - #debug["Pattern binding %s is assigned to %s", - path.node.idents[0], - locals.get(p.id).to_str()]; - } - _ {} - } - visit::visit_pat(p, e, v); - }; - - // Don't descend into fns and items - fn visit_fn(_fk: visit::fn_kind, _decl: ast::fn_decl, _body: ast::blk, - _sp: span, _id: ast::node_id, _t: T, _v: visit::vt) { - } - fn visit_item(_i: @ast::item, _e: E, _v: visit::vt) { } - - let visit = - @{visit_local: visit_local, - visit_pat: visit_pat, - visit_fn: bind visit_fn(_, _, _, _, _, _, _), - visit_item: bind visit_item(_, _, _) - with *visit::default_visitor()}; - - visit::visit_block(body, (), visit::mk_vt(visit)); - ret {infcx: infcx, - locals: locals, - next_var_id: nvi}; -} + ty_var_counter: @mut uint}; // AST fragment checking fn check_lit(ccx: @crate_ctxt, lit: @ast::lit) -> ty::t { @@ -1816,9 +1943,9 @@ fn check_lit(ccx: @crate_ctxt, lit: @ast::lit) -> ty::t { } } -fn valid_range_bounds(tcx: ty::ctxt, from: @ast::expr, to: @ast::expr) +fn valid_range_bounds(ccx: @crate_ctxt, from: @ast::expr, to: @ast::expr) -> bool { - const_eval::compare_lit_exprs(tcx, from, to) <= 0 + const_eval::compare_lit_exprs(ccx.tcx, from, to) <= 0 } type pat_ctxt = { @@ -1830,76 +1957,75 @@ type pat_ctxt = { pat_region: ty::region }; -fn count_region_params(ty: ty::t) -> uint { - if (!ty::type_has_rptrs(ty)) { ret 0u; } - - let count = @mut 0u; - ty::walk_ty(ty) {|ty| - alt ty::get(ty).struct { - ty::ty_rptr(ty::re_bound(ty::br_param(param_id, _)), _) { - if param_id > *count { - *count = param_id; - } - } - _ { /* no-op */ } - } - }; - ret *count; +fn subst_anon_region(tcx: ty::ctxt, + with_r: ty::region, + ty: ty::t) -> ty::t { + ty::fold_regions(tcx, ty) {|r, in_fn| + if !in_fn && r == ty::re_bound(ty::br_anon) {with_r} else {r} + } } -type region_env = hashmap; +// Helper for the other universally_quantify_*() routines. Extracts the bound +// regions from bound_tys and then replaces those same regions with fresh +// variables in `sty`, returning the resulting type. +fn universally_quantify_from_sty(fcx: @fn_ctxt, + span: span, + bound_tys: [ty::t], + sty: ty::sty) -> ty::t { -fn region_env() -> @region_env { - ret @ty::br_hashmap(); + let tcx = fcx.tcx(); + let isr = collect_named_regions_in_tys(tcx, @nil, bound_tys) { |_id| + fcx.next_region_var() + }; + let anon_r = fcx.next_region_var(); + ty::fold_sty_to_ty(fcx.ccx.tcx, sty) {|t| + replace_bound_regions(tcx, span, anon_r, isr, t) + } } // Replaces all region parameters in the given type with region variables. // Does not descend into fn types. This is used when deciding whether an impl // applies at a given call site. See also universally_quantify_before_call(). -fn universally_quantify_regions(fcx: @fn_ctxt, renv: @region_env, +fn universally_quantify_regions(fcx: @fn_ctxt, + span: span, ty: ty::t) -> ty::t { - ty::fold_region(fcx.ccx.tcx, ty) {|r, _under_rptr| - alt r { - ty::re_bound(br) { - alt (*renv).find(br) { - some(var_id) { ty::re_var(var_id) } - none { - let var_id = next_region_var_id(fcx); - (*renv).insert(br, var_id); - ty::re_var(var_id) - } - } - } - _ { r } - } - } + universally_quantify_from_sty(fcx, span, [ty], ty::get(ty).struct) } // Expects a function type. Replaces all region parameters in the arguments // and return type with fresh region variables. This is used when typechecking // function calls, bind expressions, and method calls. -fn universally_quantify_before_call( - fcx: @fn_ctxt, renv: @region_env, ty: ty::t) -> ty::t { - if ty::type_has_rptrs(ty) { - // This is subtle: we expect `ty` to be a function type, but - // fold_region() will not descend into function types. As it happens - // we only want to descend 1 level, so we just bypass fold_region for - // the outer type and apply it to all of the types contained with - // `ty`. - alt ty::get(ty).struct { - sty @ ty::ty_fn(_) { - ty::fold_sty_to_ty(fcx.ccx.tcx, sty) {|t| - universally_quantify_regions(fcx, renv, t) - } - } - _ { - // if not a function type, we're gonna' report an error - // at some point, since the user is trying to call this thing - ty - } - } - } else { +fn universally_quantify_before_call(fcx: @fn_ctxt, + span: span, + ty: ty::t) -> ty::t { + if !ty::type_has_regions(ty) { ret ty; } + + // This is subtle: we expect `ty` to be a function type, which normally + // introduce a level of binding. In this case, we want to process the + // types bound by the function but not by any nested functions. + // Therefore, we match one level of structure. + // + // Specifically what we do is: + // - Find the set of named regions that appear in arguments, return + // type, etc. We use collect_named_regions_in_ty(), which + // returns a free version of the region---not quite what we want. + // + // - So then we map the resulting map so that we each bound region + // will be mapped to a fresh variable. + // + // - Finally, we can use fold_sty_to_ty() and replace_bound_regions() + // to replace the bound regions as well as the bound anonymous region. + // We have to use fold_sty_to_ty() to ignore the outer fn(). + alt ty::get(ty).struct { + sty @ ty::ty_fn(fty) { + let all_tys = fty.inputs.map({|a| a.ty}) + [fty.output]; + universally_quantify_from_sty(fcx, span, all_tys, sty) + } + _ { + // if not a function type, we're gonna' report an error + // at some point, since the user is trying to call this thing ty + } } } @@ -1993,7 +2119,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { // no-op } else if !ty::type_is_numeric(b_ty) { tcx.sess.span_err(pat.span, "non-numeric type used in range"); - } else if !valid_range_bounds(tcx, begin, end) { + } else if !valid_range_bounds(pcx.fcx.ccx, begin, end) { tcx.sess.span_err(begin.span, "lower range bound must be less \ than upper"); } @@ -2200,7 +2326,7 @@ fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) -> ty_param_substs_and_ty { ast_map::node_item(@{node: ast::item_impl(ts, _, st, _), _}, _) { {n_tps: vec::len(ts), - raw_ty: ast_ty_to_ty(tcx, m_check, st)} + raw_ty: fcx.to_ty(st)} } } } else { @@ -2348,7 +2474,7 @@ impl methods for lookup { if did.crate == ast::local_crate { alt check self.tcx().items.get(did.node) { ast_map::node_method(m, _, _) { - let mt = ty_of_method(self.tcx(), m_check, m); + let mt = ty_of_method(self.fcx.ccx, m); ty::mk_fn(self.tcx(), {proto: ast::proto_box with mt.fty}) } } @@ -2364,7 +2490,7 @@ impl methods for lookup { fn method_from_scope() -> option { let impls_vecs = self.fcx.ccx.impl_map.get(self.expr.id); - for std::list::each(impls_vecs) {|impls| + for list::each(impls_vecs) {|impls| let mut results = []; for vec::each(*impls) {|im| // Check whether this impl has a method with the right name. @@ -2376,12 +2502,14 @@ impl methods for lookup { impl_self_ty(self.fcx, im.did); // Here "self" refers to the callee side... - let self_ty = universally_quantify_regions( - self.fcx, region_env(), self_ty); + let self_ty = + universally_quantify_regions( + self.fcx, self.expr.span, self_ty); // ... and "ty" refers to the caller side. - let ty = universally_quantify_regions( - self.fcx, region_env(), self.self_ty); + let ty = + universally_quantify_regions( + self.fcx, self.expr.span, self.self_ty); // if we can assign the caller to the callee, that's a // potential match. Collect those in the vector. @@ -2477,7 +2605,7 @@ impl methods for lookup { self.fcx.write_ty(self.node_id, fty); } - if ty::type_has_rptrs(ty::ty_fn_ret(fty)) { + if ty::type_has_regions(ty::ty_fn_ret(fty)) { let fty = self.fcx.node_ty(self.node_id); let self_region = region_of(self.fcx, self.expr); let fty = replace_self_region(self.tcx(), self_region, fty); @@ -2491,10 +2619,13 @@ impl methods for lookup { // Only for fields! Returns for methods> // FIXME: privacy flags fn lookup_field_ty(tcx: ty::ctxt, class_id: ast::def_id, - items:[ty::field_ty], fieldname: ast::ident, substs: [ty::t]) - -> option { - option::map(vec::find(items, {|f| f.ident == fieldname}), - {|f| ty::lookup_field_type(tcx, class_id, f.id, substs) }) + items:[ty::field_ty], fieldname: ast::ident, + substs: [ty::t]) -> option { + + let o_field = vec::find(items, {|f| f.ident == fieldname}); + option::map(o_field) {|f| + ty::lookup_field_type(tcx, class_id, f.id, substs) + } } /* Returns the region that &expr should be placed into. If expr is an @@ -2548,8 +2679,7 @@ fn check_expr_fn_with_unifier(fcx: @fn_ctxt, is_loop_body: bool, unifier: fn()) { let tcx = fcx.ccx.tcx; - let fty = ty::mk_fn(tcx, - ty_of_fn_decl(tcx, m_check_tyvar(fcx), proto, decl)); + let fty = ty::mk_fn(tcx, ty_of_fn_decl(fcx, fcx, proto, decl)); #debug("check_expr_fn_with_unifier %s fty=%s", expr_to_str(expr), fcx.ty_to_str(fty)); @@ -2584,7 +2714,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, fcx: @fn_ctxt, sp: span, fty: ty::t, args: [option<@ast::expr>]) -> {fty: ty::t, bot: bool} { - let fty = universally_quantify_before_call(fcx, region_env(), fty); + let fty = universally_quantify_before_call(fcx, sp, fty); #debug["check_call_or_bind: after universal quant., fty=%s", fcx.ty_to_str(fty)]; let sty = structure_of(fcx, sp, fty); @@ -2871,17 +3001,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, let id = expr.id; let mut bot = false; alt expr.node { - ast::expr_vstore(ev, vst) { - let mut typ = alt ev.node { + let typ = alt ev.node { ast::expr_lit(@{node: ast::lit_str(s), span:_}) { - let tt = ast_expr_vstore_to_vstore(fcx, ev, - str::len(s), vst); + let tt = ast_expr_vstore_to_vstore(fcx, ev, str::len(s), vst); ty::mk_estr(tcx, tt) } ast::expr_vec(args, mutbl) { - let tt = ast_expr_vstore_to_vstore(fcx, ev, - vec::len(args), vst); + let tt = ast_expr_vstore_to_vstore(fcx, ev, vec::len(args), vst); let t: ty::t = fcx.next_ty_var(); for args.each {|e| bot |= check_expr_with(fcx, e, t); } ty::mk_evec(tcx, {ty: t, mutbl: mutbl}, tt) @@ -2890,13 +3017,6 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence") } }; - alt vst { - ast::vstore_slice(_) { - let r = ty::re_scope(fcx.ccx.tcx.region_map.parents.get(ev.id)); - typ = replace_default_region(tcx, r, typ); - } - _ { } - } fcx.write_ty(ev.id, typ); fcx.write_ty(id, typ); } @@ -3028,8 +3148,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, }; alt expr_opt { none { - let nil = ty::mk_nil(tcx); - if !are_compatible(fcx, ret_ty, nil) { + if !are_compatible(fcx, ret_ty, ty::mk_nil(tcx)) { tcx.sess.span_err(expr.span, "ret; in function returning non-nil"); } @@ -3248,7 +3367,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, } ast::expr_cast(e, t) { bot = check_expr(fcx, e); - let t_1 = ast_ty_to_ty_crate(fcx.ccx, t); + let t_1 = fcx.to_ty(t); let t_e = fcx.expr_ty(e); alt ty::get(t_1).struct { @@ -3395,7 +3514,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, _ {} } if !handled { - let tps = vec::map(tys, {|ty| ast_ty_to_ty_crate(fcx.ccx, ty)}); + let tps = vec::map(tys) { |ty| fcx.to_ty(ty) }; let lkup = lookup({fcx: fcx, expr: expr, node_id: expr.id, @@ -3526,17 +3645,6 @@ fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t) { } } -fn next_region_var_id(fcx: @fn_ctxt) -> region_vid { - let id = *fcx.next_region_var_id; - *fcx.next_region_var_id += 1u; - ret region_vid(id); -} - -fn next_region_var(fcx: @fn_ctxt) -> ty::region { - ret ty::re_var(next_region_var_id(fcx)); -} - - fn check_decl_initializer(fcx: @fn_ctxt, nid: ast::node_id, init: ast::initializer) -> bool { let lty = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, init.expr.span, nid)); @@ -3657,8 +3765,9 @@ fn check_const(ccx: @crate_ctxt, _sp: span, e: @ast::expr, id: ast::node_id) { proto: ast::proto_box, infcx: infer::new_infer_ctxt(ccx.tcx), locals: int_hash(), - next_var_id: @mut 0u, - next_region_var_id: @mut 0u, + ty_var_counter: @mut 0u, + region_var_counter: @mut 0u, + in_scope_regions: @nil, node_types: smallintmap::mk(), node_type_substs: map::int_hash(), ccx: ccx}; @@ -3694,8 +3803,9 @@ fn check_enum_variants(ccx: @crate_ctxt, sp: span, vs: [ast::variant], proto: ast::proto_box, infcx: infer::new_infer_ctxt(ccx.tcx), locals: int_hash(), - next_var_id: @mut 0u, - next_region_var_id: @mut 0u, + ty_var_counter: @mut 0u, + region_var_counter: @mut 0u, + in_scope_regions: @nil, node_types: smallintmap::mk(), node_type_substs: map::int_hash(), ccx: ccx}; @@ -3882,59 +3992,84 @@ fn check_fn(ccx: @crate_ctxt, old_fcx: option<@fn_ctxt>, self_ty: option) { + let tcx = ccx.tcx; + // See big comment in region.rs. - let arg_tys = arg_tys.map {|arg_ty| - replace_bound_regions_with_free_regions(ccx.tcx, fid, arg_ty) + let isr = { + let all_tys = arg_tys + [ret_ty] + self_ty.to_vec(); + let old_isr = option::map_default(old_fcx, @nil) { + |fcx| fcx.in_scope_regions }; + collect_named_regions_in_tys(tcx, old_isr, all_tys) { + |id| ty::re_free(fid, ty::br_named(id)) } }; - let ret_ty = - replace_bound_regions_with_free_regions(ccx.tcx, fid, ret_ty); - let self_ty = option::map(self_ty) {|st| - replace_bound_regions_with_free_regions(ccx.tcx, fid, st) + let anon_r = ty::re_free(fid, ty::br_anon); + let self_r = ty::re_free(fid, ty::br_self); + let arg_tys = arg_tys.map {|arg_ty| + let arg_ty = replace_bound_self(tcx, self_r, arg_ty); + replace_bound_regions(tcx, body.span, anon_r, isr, arg_ty) + }; + let ret_ty = replace_bound_self(tcx, self_r, ret_ty); + let ret_ty = replace_bound_regions(tcx, body.span, anon_r, isr, ret_ty); + let self_ty = option::map(self_ty) {|self_ty| + let self_ty = replace_bound_self(tcx, self_r, self_ty); + replace_bound_regions(tcx, body.span, anon_r, isr, self_ty) }; #debug["check_fn(arg_tys=%?, ret_ty=%?, self_ty=%?)", - arg_tys.map {|a| ty_to_str(ccx.tcx, a) }, - ty_to_str(ccx.tcx, ret_ty), - option::map(self_ty) {|st| ty_to_str(ccx.tcx, st) }]; + arg_tys.map {|a| ty_to_str(tcx, a) }, + ty_to_str(tcx, ret_ty), + option::map(self_ty) {|st| ty_to_str(tcx, st) }]; // If old_fcx is some(...), this is a block fn { |x| ... }. // In that case, the purity is inherited from the context. - let {purity, node_types, node_type_substs} = alt old_fcx { - none { - {purity: decl.purity, - node_types: smallintmap::mk(), - node_type_substs: map::int_hash()} - } - some(f) { - assert decl.purity == ast::impure_fn; - {purity: f.purity, - node_types: f.node_types, - node_type_substs: f.node_type_substs} - } - }; + let fcx: @fn_ctxt = { + let {infcx, locals, tvc, rvc, purity, + node_types, node_type_substs} = alt old_fcx { + none { + {infcx: infer::new_infer_ctxt(tcx), + locals: int_hash(), + tvc: @mut 0u, + rvc: @mut 0u, + purity: decl.purity, + node_types: smallintmap::mk(), + node_type_substs: map::int_hash()} + } + some(fcx) { + assert decl.purity == ast::impure_fn; + {infcx: fcx.infcx, + locals: fcx.locals, + tvc: fcx.ty_var_counter, + rvc: fcx.region_var_counter, + purity: fcx.purity, + node_types: fcx.node_types, + node_type_substs: fcx.node_type_substs} + } + }; + + let indirect_ret_ty = if indirect_ret { + let ofcx = option::get(old_fcx); + alt ofcx.indirect_ret_ty { + some(t) { some(t) } + none { some(ofcx.ret_ty) } + } + } else { none }; - let gather_result = gather_locals(ccx, decl, body, arg_tys, old_fcx); - let indirect_ret_ty = if indirect_ret { - let ofcx = option::get(old_fcx); - alt ofcx.indirect_ret_ty { - some(t) { some(t) } - none { some(ofcx.ret_ty) } - } - } else { none }; - let fcx: @fn_ctxt = @{self_ty: self_ty, ret_ty: ret_ty, indirect_ret_ty: indirect_ret_ty, purity: purity, proto: proto, - infcx: gather_result.infcx, - locals: gather_result.locals, - next_var_id: gather_result.next_var_id, - next_region_var_id: @mut 0u, + infcx: infcx, + locals: locals, + ty_var_counter: tvc, + region_var_counter: rvc, + in_scope_regions: isr, node_types: node_types, node_type_substs: node_type_substs, - ccx: ccx}; + ccx: ccx} + }; + gather_locals(fcx, decl, body, arg_tys); check_constraints(fcx, decl.constraints, decl.inputs); check_block(fcx, body); @@ -3962,6 +4097,76 @@ fn check_fn(ccx: @crate_ctxt, vtable::resolve_in_block(fcx, body); writeback::resolve_type_vars_in_fn(fcx, decl, body); } + + fn gather_locals(fcx: @fn_ctxt, + decl: ast::fn_decl, + body: ast::blk, + arg_tys: [ty::t]) { + let tcx = fcx.ccx.tcx; + + let assign = fn@(nid: ast::node_id, ty_opt: option) { + let var_id = fcx.next_ty_var_id(); + fcx.locals.insert(nid, var_id); + alt ty_opt { + none {/* nothing to do */ } + some(typ) { + infer::mk_eqty(fcx.infcx, ty::mk_var(tcx, var_id), typ); + } + } + }; + + // Add formal parameters. + vec::iter2(arg_tys, decl.inputs) {|arg_ty, input| + assign(input.id, some(arg_ty)); + #debug["Argument %s is assigned to %s", + input.ident, fcx.locals.get(input.id).to_str()]; + } + + // Add explicitly-declared locals. + let visit_local = fn@(local: @ast::local, + &&e: (), v: visit::vt<()>) { + let o_ty = alt local.node.ty.node { + ast::ty_infer { none } + _ { some(fcx.to_ty(local.node.ty)) } + }; + assign(local.node.id, o_ty); + #debug["Local variable %s is assigned to %s", + pat_to_str(local.node.pat), + fcx.locals.get(local.node.id).to_str()]; + visit::visit_local(local, e, v); + }; + + // Add pattern bindings. + let visit_pat = fn@(p: @ast::pat, &&e: (), v: visit::vt<()>) { + alt p.node { + ast::pat_ident(path, _) + if !pat_util::pat_is_variant(fcx.ccx.tcx.def_map, p) { + assign(p.id, none); + #debug["Pattern binding %s is assigned to %s", + path.node.idents[0], + fcx.locals.get(p.id).to_str()]; + } + _ {} + } + visit::visit_pat(p, e, v); + }; + + // Don't descend into fns and items + fn visit_fn(_fk: visit::fn_kind, _decl: ast::fn_decl, + _body: ast::blk, _sp: span, + _id: ast::node_id, _t: T, _v: visit::vt) { + } + fn visit_item(_i: @ast::item, _e: E, _v: visit::vt) { } + + let visit = + @{visit_local: visit_local, + visit_pat: visit_pat, + visit_fn: bind visit_fn(_, _, _, _, _, _, _), + visit_item: bind visit_item(_, _, _) + with *visit::default_visitor()}; + + visit::visit_block(body, (), visit::mk_vt(visit)); + } } fn check_method(ccx: @crate_ctxt, method: @ast::method, self_ty: ty::t) { @@ -3973,11 +4178,11 @@ fn class_types(ccx: @crate_ctxt, members: [@ast::class_member]) -> class_map { for members.each {|m| alt m.node { ast::instance_var(_,t,_,id,_) { - rslt.insert(id, ast_ty_to_ty(ccx.tcx, m_collect, t)); + rslt.insert(id, ccx.to_ty(t)); } ast::class_method(mth) { rslt.insert(mth.id, ty::mk_fn(ccx.tcx, - ty_of_method(ccx.tcx, m_collect, mth).fty)); + ty_of_method(ccx, mth).fty)); } } } @@ -4006,7 +4211,7 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { check_bare_fn(ccx, 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_ty = ccx.to_self_ty(ty); let self_region = ty::re_free(it.id, ty::br_self); let self_ty = replace_self_region(ccx.tcx, self_region, self_ty); for ms.each {|m| check_method(ccx, m, self_ty);} @@ -4044,7 +4249,11 @@ fn arg_is_argv_ty(_tcx: ty::ctxt, a: ty::arg) -> bool { } } -fn check_main_fn_ty(tcx: ty::ctxt, main_id: ast::node_id, main_span: span) { +fn check_main_fn_ty(ccx: @crate_ctxt, + main_id: ast::node_id, + main_span: span) { + + let tcx = ccx.tcx; let main_t = ty::node_id_to_type(tcx, main_id); alt ty::get(main_t).struct { ty::ty_fn({proto: ast::proto_bare, inputs, output, @@ -4082,10 +4291,11 @@ fn check_main_fn_ty(tcx: ty::ctxt, main_id: ast::node_id, main_span: span) { } } -fn check_for_main_fn(tcx: ty::ctxt, crate: @ast::crate) { +fn check_for_main_fn(ccx: @crate_ctxt, crate: @ast::crate) { + let tcx = ccx.tcx; if !tcx.sess.building_library { alt tcx.sess.main_fn { - some((id, sp)) { check_main_fn_ty(tcx, id, sp); } + some((id, sp)) { check_main_fn_ty(ccx, id, sp); } none { tcx.sess.span_err(crate.span, "main function not found"); } } } @@ -4165,7 +4375,7 @@ mod vtable { } _ { let mut found = none; - std::list::iter(isc) {|impls| + list::iter(isc) {|impls| if option::is_none(found) { for vec::each(*impls) {|im| let match = alt ty::impl_iface(tcx, im.did) { @@ -4314,20 +4524,19 @@ mod vtable { fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map, crate: @ast::crate) -> (method_map, vtable_map) { - collect::collect_item_types(tcx, crate); - let ccx = @{impl_map: impl_map, method_map: std::map::int_hash(), vtable_map: std::map::int_hash(), enclosing_class_id: none, enclosing_class: std::map::int_hash(), tcx: tcx}; + collect::collect_item_types(ccx, crate); let visit = visit::mk_simple_visitor(@{ visit_item: bind check_item(ccx, _) with *visit::default_simple_visitor() }); visit::visit_crate(*crate, (), visit); - check_for_main_fn(tcx, crate); + check_for_main_fn(ccx, crate); tcx.sess.abort_if_errors(); (ccx.method_map, ccx.vtable_map) } diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs index 6bc79f48d1c..4050f8ced92 100644 --- a/src/rustc/util/ppaux.rs +++ b/src/rustc/util/ppaux.rs @@ -13,7 +13,7 @@ import driver::session::session; fn bound_region_to_str(_cx: ctxt, br: bound_region) -> str { alt br { br_anon { "&" } - br_param(_, str) { #fmt["&%s", str] } + br_named(str) { #fmt["&%s", str] } br_self { "&self" } } } @@ -53,7 +53,6 @@ fn region_to_str(cx: ctxt, region: region) -> str { // These two should not be seen by end-users (very often, anyhow): re_var(id) { #fmt("&%s", id.to_str()) } - re_default { "&(default)" } re_static { "&static" } } } diff --git a/src/test/compile-fail/seq-args.rs b/src/test/compile-fail/seq-args.rs new file mode 100644 index 00000000000..d21c2871be3 --- /dev/null +++ b/src/test/compile-fail/seq-args.rs @@ -0,0 +1,13 @@ +use std; +fn main() { +iface seq { } + +impl of seq for [T] { + //!^ ERROR wrong number of type arguments for a polymorphic type + /* ... */ +} +impl of seq for u32 { + /* Treat the integer as a sequence of bits */ +} + +} diff --git a/src/test/run-pass/regions-self-in-enums.rs b/src/test/run-pass/regions-self-in-enums.rs index ef7a8ae1ed7..084192c3aa7 100644 --- a/src/test/run-pass/regions-self-in-enums.rs +++ b/src/test/run-pass/regions-self-in-enums.rs @@ -1,3 +1,5 @@ +// xfail-test + enum int_wrapper { int_wrapper_ctor(&int) }