diff --git a/src/comp/metadata/decoder.rs b/src/comp/metadata/decoder.rs index adb5e581ae5..8271c5d9849 100644 --- a/src/comp/metadata/decoder.rs +++ b/src/comp/metadata/decoder.rs @@ -129,11 +129,8 @@ fn item_ty_param_bounds(item: ebml::doc, this_cnum: ast::crate_num, fn item_ty_param_count(item: ebml::doc) -> uint { let n = 0u; - ebml::tagged_docs(item, tag_items_data_item_ty_param_bounds) {|p| - for byte in ebml::doc_data(p) { - if byte as char == '.' { n += 1u; } - } - } + ebml::tagged_docs(item, tag_items_data_item_ty_param_bounds, + {|_p| n += 1u; }); n } diff --git a/src/comp/metadata/tydecode.rs b/src/comp/metadata/tydecode.rs index 4f4c7f41c5e..0ecf2095e7e 100644 --- a/src/comp/metadata/tydecode.rs +++ b/src/comp/metadata/tydecode.rs @@ -202,9 +202,17 @@ fn parse_ty(st: @pstate, sd: str_def) -> ty::t { st.pos = st.pos + 1u; ret ty::mk_tag(st.tcx, def, params); } + 'x' { + assert (next(st) as char == '['); + let def = parse_def(st, sd); + let params: [ty::t] = []; + while peek(st) as char != ']' { params += [parse_ty(st, sd)]; } + st.pos = st.pos + 1u; + ret ty::mk_iface(st.tcx, def, params); + } 'p' { - let bounds = parse_bounds(st, sd); - ret ty::mk_param(st.tcx, parse_int(st) as uint, bounds); + let did = parse_def(st, sd); + ret ty::mk_param(st.tcx, parse_int(st) as uint, did); } '@' { ret ty::mk_box(st.tcx, parse_mt(st, sd)); } '~' { ret ty::mk_uniq(st.tcx, parse_mt(st, sd)); } @@ -401,8 +409,7 @@ fn parse_bounds_data(data: @[u8], crate_num: int, sd: str_def, tcx: ty::ctxt) fn parse_bounds(st: @pstate, sd: str_def) -> @[ty::param_bound] { let bounds = []; - while peek(st) as char == '.' { - next(st); + while peek(st) != 0u8 { bounds += [alt next(st) as char { 'S' { ty::bound_send } 'C' { ty::bound_copy } diff --git a/src/comp/metadata/tyencode.rs b/src/comp/metadata/tyencode.rs index 88885153e77..73d44472723 100644 --- a/src/comp/metadata/tyencode.rs +++ b/src/comp/metadata/tyencode.rs @@ -126,6 +126,13 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) { for t: ty::t in tys { enc_ty(w, cx, t); } w.write_char(']'); } + ty::ty_iface(def, tys) { + w.write_str("x["); + w.write_str(cx.ds(def)); + w.write_char('|'); + for t: ty::t in tys { enc_ty(w, cx, t); } + w.write_char(']'); + } ty::ty_tup(ts) { w.write_str("T["); for t in ts { enc_ty(w, cx, t); } @@ -176,9 +183,10 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) { w.write_str(cx.ds(def)); w.write_char('|'); } - ty::ty_param(id, bounds) { + ty::ty_param(id, did) { w.write_char('p'); - enc_bounds(w, cx, bounds); + w.write_str(cx.ds(did)); + w.write_char('|'); w.write_str(uint::str(id)); } ty::ty_type. { w.write_char('Y'); } @@ -265,7 +273,6 @@ fn enc_ty_constr(w: io::writer, cx: @ctxt, c: @ty::type_constr) { fn enc_bounds(w: io::writer, cx: @ctxt, bs: @[ty::param_bound]) { for bound in *bs { - w.write_char('.'); alt bound { ty::bound_send. { w.write_char('S'); } ty::bound_copy. { w.write_char('C'); } diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index a9564f87eb1..99a112321c8 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -4658,7 +4658,8 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id, let ty_param_substs: [ty::t] = []; i = 0u; for tp: ast::ty_param in ty_params { - ty_param_substs += [ty::mk_param(ccx.tcx, i, @[])]; + ty_param_substs += [ty::mk_param(ccx.tcx, i, + ast_util::local_def(tp.id))]; i += 1u; } let arg_tys = arg_tys_of_fn(ccx, variant.node.id); diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 2f853f5eb84..f893801d2f0 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -218,7 +218,7 @@ type ctxt = needs_drop_cache: hashmap, kind_cache: hashmap, ast_ty_to_ty_cache: hashmap<@ast::ty, option::t>, - tag_var_cache: hashmap, + tag_var_cache: hashmap, iface_method_cache: hashmap, ty_param_bounds: hashmap}; @@ -268,7 +268,7 @@ tag sty { ty_tup([t]); ty_var(int); // type variable - ty_param(uint, @[param_bound]); // fn/tag type param + ty_param(uint, def_id); // fn/tag type param ty_type; // type_desc* ty_send_type; // type_desc* that has been cloned into exchange heap @@ -624,7 +624,7 @@ fn mk_res(cx: ctxt, did: ast::def_id, inner: t, tps: [t]) -> t { fn mk_var(cx: ctxt, v: int) -> t { ret gen_ty(cx, ty_var(v)); } -fn mk_param(cx: ctxt, n: uint, k: @[param_bound]) -> t { +fn mk_param(cx: ctxt, n: uint, k: def_id) -> t { ret gen_ty(cx, ty_param(n, k)); } @@ -722,7 +722,7 @@ fn walk_ty(cx: ctxt, walker: ty_walk, ty: t) { tag fold_mode { fm_var(fn@(int) -> t); - fm_param(fn@(uint, @[param_bound]) -> t); + fm_param(fn@(uint, def_id) -> t); fm_general(fn@(t) -> t); } @@ -813,8 +813,8 @@ fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t { ty_var(id) { alt fld { fm_var(folder) { ty = folder(id); } _ {/* no-op */ } } } - ty_param(id, k) { - alt fld { fm_param(folder) { ty = folder(id, k); } _ {/* no-op */ } } + ty_param(id, did) { + alt fld { fm_param(folder) { ty = folder(id, did); } _ {/* no-op */ } } } } @@ -1083,7 +1083,7 @@ fn type_kind(cx: ctxt, ty: t) -> kind { } // Resources are always noncopyable. ty_res(did, inner, tps) { kind_noncopyable } - ty_param(_, bounds) { param_bounds_to_kind(bounds) } + ty_param(_, did) { param_bounds_to_kind(cx.ty_param_bounds.get(did)) } ty_constr(t, _) { type_kind(cx, t) } }; @@ -1131,7 +1131,7 @@ fn type_structurally_contains(cx: ctxt, ty: t, test: fn(sty) -> bool) -> } } -pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool { +pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool unchecked { /* type_structurally_contains can't be declared pure because it takes a function argument. But it should be @@ -1141,15 +1141,9 @@ pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool { actually checkable. It seems to me like a lot of properties that the type context tracks about types should be immutable.) */ - unchecked{ - type_structurally_contains(cx, ty, - fn (sty: sty) -> bool { - ret alt sty { - ty_param(_, _) { true } - _ { false } - }; - }) - } + type_structurally_contains(cx, ty, fn (sty: sty) -> bool { + alt sty { ty_param(_, _) { true } _ { false }} + }) } // Returns true for noncopyable types and types where a copy of a value can be @@ -2205,7 +2199,14 @@ mod unify { _ { ret ures_err(terr_mismatch); } } } - ty::ty_param(_, _) { ret struct_cmp(cx, expected, actual); } + ty::ty_param(expected_n, _) { + alt struct(cx.tcx, actual) { + ty::ty_param(actual_n, _) when expected_n == actual_n { + ret ures_ok(expected); + } + _ { ret ures_err(terr_mismatch); } + } + } ty::ty_tag(expected_id, expected_tps) { alt struct(cx.tcx, actual) { ty::ty_tag(actual_id, actual_tps) { @@ -2627,8 +2628,7 @@ fn bind_params_in_type(sp: span, cx: ctxt, next_ty_var: fn@() -> int, typ: t, let i = 0u; while i < ty_param_count { *param_var_ids += [next_ty_var()]; i += 1u; } fn binder(sp: span, cx: ctxt, param_var_ids: @mutable [int], - _next_ty_var: fn@() -> int, index: uint, - _bounds: @[param_bound]) -> t { + _next_ty_var: fn@() -> int, index: uint, _did: def_id) -> t { if index < vec::len(*param_var_ids) { ret mk_var(cx, param_var_ids[index]); } else { @@ -2647,9 +2647,8 @@ fn bind_params_in_type(sp: span, cx: ctxt, next_ty_var: fn@() -> int, typ: t, // substitions. fn substitute_type_params(cx: ctxt, substs: [ty::t], typ: t) -> t { if !type_contains_params(cx, typ) { ret typ; } - fn substituter(_cx: ctxt, substs: @[ty::t], idx: uint, - _bounds: @[param_bound]) - -> t { + fn substituter(_cx: ctxt, substs: @[ty::t], idx: uint, _did: def_id) + -> t { // FIXME: bounds check can fail ret substs[idx]; } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 5d65ce78049..313023ba108 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -343,7 +343,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t { } some(ast::def_native_ty(id)) { typ = getter(tcx, mode, id).ty; } some(ast::def_ty_param(id, n)) { - typ = ty::mk_param(tcx, n, tcx.ty_param_bounds.get(id)); + typ = ty::mk_param(tcx, n, id); } some(_) { tcx.sess.span_fatal(ast_ty.span, @@ -625,8 +625,8 @@ fn mk_ty_params(tcx: ty::ctxt, atps: [ast::ty_param]) -> {bounds: [@[ty::param_bound]], params: [ty::t]} { let i = 0u, bounds = ty_param_bounds(tcx, m_collect, atps); {bounds: bounds, - params: vec::map(atps, {|_atp| - let t = ty::mk_param(tcx, i, bounds[i]); + params: vec::map(atps, {|atp| + let t = ty::mk_param(tcx, i, local_def(atp.id)); i += 1u; t })} @@ -2666,13 +2666,16 @@ fn check_method(ccx: @crate_ctxt, method: @ast::method) { fn check_item(ccx: @crate_ctxt, it: @ast::item) { alt it.node { ast::item_const(_, e) { check_const(ccx, it.span, e, it.id); } - ast::item_fn(decl, _, body) { + ast::item_fn(decl, tps, body) { + check_ty_params(ccx, tps); check_fn(ccx, ast::proto_bare, decl, body, it.id, none); } - ast::item_res(decl, _, body, dtor_id, _) { + ast::item_res(decl, tps, body, dtor_id, _) { + check_ty_params(ccx, tps); check_fn(ccx, ast::proto_bare, decl, body, dtor_id, none); } - ast::item_obj(ob, _, _) { + ast::item_obj(ob, tps, _) { + check_ty_params(ccx, tps); // We're entering an object, so gather up the info we need. ccx.self_infos += [self_obj(ob.fields, ccx.tcx.tcache.get(local_def(it.id)).ty)]; @@ -2681,9 +2684,11 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { // Now remove the info from the stack. vec::pop(ccx.self_infos); } - ast::item_impl(_, ifce, ty, ms) { + ast::item_impl(tps, ifce, ty, ms) { + check_ty_params(ccx, tps); ccx.self_infos += [self_impl(ast_ty_to_ty(ccx.tcx, m_check, ty))]; let my_methods = vec::map(ms, {|m| + check_ty_params(ccx, m.tps); check_method(ccx, m); ty_of_method(ccx.tcx, m_check, m) }); @@ -2717,10 +2722,43 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { _ {} } } + ast::item_iface(tps, _) | ast::item_ty(_, tps) | ast::item_tag(_, tps) { + check_ty_params(ccx, tps); + } _ {/* nothing to do */ } } } +fn check_native_item(ccx: @crate_ctxt, it: @ast::native_item) { + alt it.node { + ast::native_item_fn(_, tps) { check_ty_params(ccx, tps); } + _ {} + } +} + +fn check_ty_params(ccx: @crate_ctxt, tps: [ast::ty_param]) { + for tp in tps { + let i = 0u; + for bound in *tp.bounds { + alt bound { + ast::bound_iface(at) { + let tbound = ccx.tcx.ty_param_bounds.get(local_def(tp.id))[i]; + let bound_ty = alt tbound { ty::bound_iface(t) { t } }; + alt ty::struct(ccx.tcx, bound_ty) { + ty::ty_iface(_, _) {} + _ { + ccx.tcx.sess.span_err(at.span, "type parameter bounds \ + must be interface types"); + } + } + } + _ {} + } + i += 1u; + } + } +} + fn arg_is_argv_ty(tcx: ty::ctxt, a: ty::arg) -> bool { alt ty::struct(tcx, a.ty) { ty::ty_vec(mt) { @@ -2778,8 +2816,10 @@ fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map, method_map: std::map::new_int_hash(), tcx: tcx}; let visit = - visit::mk_simple_visitor(@{visit_item: bind check_item(ccx, _) - with *visit::default_simple_visitor()}); + visit::mk_simple_visitor(@{visit_item: bind check_item(ccx, _), + visit_native_item: + bind check_native_item(ccx, _) + with *visit::default_simple_visitor()}); visit::visit_crate(*crate, (), visit); check_for_main_fn(tcx, crate); tcx.sess.abort_if_errors();