Skip to content

Commit 40d5f28

Browse files
committed
Check that type parameter bounds are interface types
Issue #1227
1 parent 7ea175f commit 40d5f28

File tree

6 files changed

+96
-45
lines changed

6 files changed

+96
-45
lines changed

src/comp/metadata/decoder.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,8 @@ fn item_ty_param_bounds(item: ebml::doc, this_cnum: ast::crate_num,
129129

130130
fn item_ty_param_count(item: ebml::doc) -> uint {
131131
let n = 0u;
132-
ebml::tagged_docs(item, tag_items_data_item_ty_param_bounds) {|p|
133-
for byte in ebml::doc_data(p) {
134-
if byte as char == '.' { n += 1u; }
135-
}
136-
}
132+
ebml::tagged_docs(item, tag_items_data_item_ty_param_bounds,
133+
{|_p| n += 1u; });
137134
n
138135
}
139136

src/comp/metadata/tydecode.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,9 +202,17 @@ fn parse_ty(st: @pstate, sd: str_def) -> ty::t {
202202
st.pos = st.pos + 1u;
203203
ret ty::mk_tag(st.tcx, def, params);
204204
}
205+
'x' {
206+
assert (next(st) as char == '[');
207+
let def = parse_def(st, sd);
208+
let params: [ty::t] = [];
209+
while peek(st) as char != ']' { params += [parse_ty(st, sd)]; }
210+
st.pos = st.pos + 1u;
211+
ret ty::mk_iface(st.tcx, def, params);
212+
}
205213
'p' {
206-
let bounds = parse_bounds(st, sd);
207-
ret ty::mk_param(st.tcx, parse_int(st) as uint, bounds);
214+
let did = parse_def(st, sd);
215+
ret ty::mk_param(st.tcx, parse_int(st) as uint, did);
208216
}
209217
'@' { ret ty::mk_box(st.tcx, parse_mt(st, sd)); }
210218
'~' { 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)
401409

402410
fn parse_bounds(st: @pstate, sd: str_def) -> @[ty::param_bound] {
403411
let bounds = [];
404-
while peek(st) as char == '.' {
405-
next(st);
412+
while peek(st) != 0u8 {
406413
bounds += [alt next(st) as char {
407414
'S' { ty::bound_send }
408415
'C' { ty::bound_copy }

src/comp/metadata/tyencode.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,13 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
126126
for t: ty::t in tys { enc_ty(w, cx, t); }
127127
w.write_char(']');
128128
}
129+
ty::ty_iface(def, tys) {
130+
w.write_str("x[");
131+
w.write_str(cx.ds(def));
132+
w.write_char('|');
133+
for t: ty::t in tys { enc_ty(w, cx, t); }
134+
w.write_char(']');
135+
}
129136
ty::ty_tup(ts) {
130137
w.write_str("T[");
131138
for t in ts { enc_ty(w, cx, t); }
@@ -176,9 +183,10 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
176183
w.write_str(cx.ds(def));
177184
w.write_char('|');
178185
}
179-
ty::ty_param(id, bounds) {
186+
ty::ty_param(id, did) {
180187
w.write_char('p');
181-
enc_bounds(w, cx, bounds);
188+
w.write_str(cx.ds(did));
189+
w.write_char('|');
182190
w.write_str(uint::str(id));
183191
}
184192
ty::ty_type. { w.write_char('Y'); }
@@ -265,7 +273,6 @@ fn enc_ty_constr(w: io::writer, cx: @ctxt, c: @ty::type_constr) {
265273

266274
fn enc_bounds(w: io::writer, cx: @ctxt, bs: @[ty::param_bound]) {
267275
for bound in *bs {
268-
w.write_char('.');
269276
alt bound {
270277
ty::bound_send. { w.write_char('S'); }
271278
ty::bound_copy. { w.write_char('C'); }

src/comp/middle/trans.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4658,7 +4658,8 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
46584658
let ty_param_substs: [ty::t] = [];
46594659
i = 0u;
46604660
for tp: ast::ty_param in ty_params {
4661-
ty_param_substs += [ty::mk_param(ccx.tcx, i, @[])];
4661+
ty_param_substs += [ty::mk_param(ccx.tcx, i,
4662+
ast_util::local_def(tp.id))];
46624663
i += 1u;
46634664
}
46644665
let arg_tys = arg_tys_of_fn(ccx, variant.node.id);

src/comp/middle/ty.rs

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ type ctxt =
218218
needs_drop_cache: hashmap<t, bool>,
219219
kind_cache: hashmap<t, kind>,
220220
ast_ty_to_ty_cache: hashmap<@ast::ty, option::t<t>>,
221-
tag_var_cache: hashmap<ast::def_id, @[variant_info]>,
221+
tag_var_cache: hashmap<def_id, @[variant_info]>,
222222
iface_method_cache: hashmap<def_id, @[method]>,
223223
ty_param_bounds: hashmap<def_id, @[param_bound]>};
224224

@@ -268,7 +268,7 @@ tag sty {
268268
ty_tup([t]);
269269
ty_var(int); // type variable
270270

271-
ty_param(uint, @[param_bound]); // fn/tag type param
271+
ty_param(uint, def_id); // fn/tag type param
272272

273273
ty_type; // type_desc*
274274
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 {
624624

625625
fn mk_var(cx: ctxt, v: int) -> t { ret gen_ty(cx, ty_var(v)); }
626626

627-
fn mk_param(cx: ctxt, n: uint, k: @[param_bound]) -> t {
627+
fn mk_param(cx: ctxt, n: uint, k: def_id) -> t {
628628
ret gen_ty(cx, ty_param(n, k));
629629
}
630630

@@ -722,7 +722,7 @@ fn walk_ty(cx: ctxt, walker: ty_walk, ty: t) {
722722

723723
tag fold_mode {
724724
fm_var(fn@(int) -> t);
725-
fm_param(fn@(uint, @[param_bound]) -> t);
725+
fm_param(fn@(uint, def_id) -> t);
726726
fm_general(fn@(t) -> t);
727727
}
728728

@@ -813,8 +813,8 @@ fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t {
813813
ty_var(id) {
814814
alt fld { fm_var(folder) { ty = folder(id); } _ {/* no-op */ } }
815815
}
816-
ty_param(id, k) {
817-
alt fld { fm_param(folder) { ty = folder(id, k); } _ {/* no-op */ } }
816+
ty_param(id, did) {
817+
alt fld { fm_param(folder) { ty = folder(id, did); } _ {/* no-op */ } }
818818
}
819819
}
820820

@@ -1083,7 +1083,7 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
10831083
}
10841084
// Resources are always noncopyable.
10851085
ty_res(did, inner, tps) { kind_noncopyable }
1086-
ty_param(_, bounds) { param_bounds_to_kind(bounds) }
1086+
ty_param(_, did) { param_bounds_to_kind(cx.ty_param_bounds.get(did)) }
10871087
ty_constr(t, _) { type_kind(cx, t) }
10881088
};
10891089

@@ -1131,7 +1131,7 @@ fn type_structurally_contains(cx: ctxt, ty: t, test: fn(sty) -> bool) ->
11311131
}
11321132
}
11331133

1134-
pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool {
1134+
pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool unchecked {
11351135

11361136
/* type_structurally_contains can't be declared pure
11371137
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 {
11411141
actually checkable. It seems to me like a lot of properties
11421142
that the type context tracks about types should be immutable.)
11431143
*/
1144-
unchecked{
1145-
type_structurally_contains(cx, ty,
1146-
fn (sty: sty) -> bool {
1147-
ret alt sty {
1148-
ty_param(_, _) { true }
1149-
_ { false }
1150-
};
1151-
})
1152-
}
1144+
type_structurally_contains(cx, ty, fn (sty: sty) -> bool {
1145+
alt sty { ty_param(_, _) { true } _ { false }}
1146+
})
11531147
}
11541148

11551149
// Returns true for noncopyable types and types where a copy of a value can be
@@ -2205,7 +2199,14 @@ mod unify {
22052199
_ { ret ures_err(terr_mismatch); }
22062200
}
22072201
}
2208-
ty::ty_param(_, _) { ret struct_cmp(cx, expected, actual); }
2202+
ty::ty_param(expected_n, _) {
2203+
alt struct(cx.tcx, actual) {
2204+
ty::ty_param(actual_n, _) when expected_n == actual_n {
2205+
ret ures_ok(expected);
2206+
}
2207+
_ { ret ures_err(terr_mismatch); }
2208+
}
2209+
}
22092210
ty::ty_tag(expected_id, expected_tps) {
22102211
alt struct(cx.tcx, actual) {
22112212
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,
26272628
let i = 0u;
26282629
while i < ty_param_count { *param_var_ids += [next_ty_var()]; i += 1u; }
26292630
fn binder(sp: span, cx: ctxt, param_var_ids: @mutable [int],
2630-
_next_ty_var: fn@() -> int, index: uint,
2631-
_bounds: @[param_bound]) -> t {
2631+
_next_ty_var: fn@() -> int, index: uint, _did: def_id) -> t {
26322632
if index < vec::len(*param_var_ids) {
26332633
ret mk_var(cx, param_var_ids[index]);
26342634
} else {
@@ -2647,9 +2647,8 @@ fn bind_params_in_type(sp: span, cx: ctxt, next_ty_var: fn@() -> int, typ: t,
26472647
// substitions.
26482648
fn substitute_type_params(cx: ctxt, substs: [ty::t], typ: t) -> t {
26492649
if !type_contains_params(cx, typ) { ret typ; }
2650-
fn substituter(_cx: ctxt, substs: @[ty::t], idx: uint,
2651-
_bounds: @[param_bound])
2652-
-> t {
2650+
fn substituter(_cx: ctxt, substs: @[ty::t], idx: uint, _did: def_id)
2651+
-> t {
26532652
// FIXME: bounds check can fail
26542653
ret substs[idx];
26552654
}

src/comp/middle/typeck.rs

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
343343
}
344344
some(ast::def_native_ty(id)) { typ = getter(tcx, mode, id).ty; }
345345
some(ast::def_ty_param(id, n)) {
346-
typ = ty::mk_param(tcx, n, tcx.ty_param_bounds.get(id));
346+
typ = ty::mk_param(tcx, n, id);
347347
}
348348
some(_) {
349349
tcx.sess.span_fatal(ast_ty.span,
@@ -625,8 +625,8 @@ fn mk_ty_params(tcx: ty::ctxt, atps: [ast::ty_param])
625625
-> {bounds: [@[ty::param_bound]], params: [ty::t]} {
626626
let i = 0u, bounds = ty_param_bounds(tcx, m_collect, atps);
627627
{bounds: bounds,
628-
params: vec::map(atps, {|_atp|
629-
let t = ty::mk_param(tcx, i, bounds[i]);
628+
params: vec::map(atps, {|atp|
629+
let t = ty::mk_param(tcx, i, local_def(atp.id));
630630
i += 1u;
631631
t
632632
})}
@@ -2666,13 +2666,16 @@ fn check_method(ccx: @crate_ctxt, method: @ast::method) {
26662666
fn check_item(ccx: @crate_ctxt, it: @ast::item) {
26672667
alt it.node {
26682668
ast::item_const(_, e) { check_const(ccx, it.span, e, it.id); }
2669-
ast::item_fn(decl, _, body) {
2669+
ast::item_fn(decl, tps, body) {
2670+
check_ty_params(ccx, tps);
26702671
check_fn(ccx, ast::proto_bare, decl, body, it.id, none);
26712672
}
2672-
ast::item_res(decl, _, body, dtor_id, _) {
2673+
ast::item_res(decl, tps, body, dtor_id, _) {
2674+
check_ty_params(ccx, tps);
26732675
check_fn(ccx, ast::proto_bare, decl, body, dtor_id, none);
26742676
}
2675-
ast::item_obj(ob, _, _) {
2677+
ast::item_obj(ob, tps, _) {
2678+
check_ty_params(ccx, tps);
26762679
// We're entering an object, so gather up the info we need.
26772680
ccx.self_infos += [self_obj(ob.fields,
26782681
ccx.tcx.tcache.get(local_def(it.id)).ty)];
@@ -2681,9 +2684,11 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
26812684
// Now remove the info from the stack.
26822685
vec::pop(ccx.self_infos);
26832686
}
2684-
ast::item_impl(_, ifce, ty, ms) {
2687+
ast::item_impl(tps, ifce, ty, ms) {
2688+
check_ty_params(ccx, tps);
26852689
ccx.self_infos += [self_impl(ast_ty_to_ty(ccx.tcx, m_check, ty))];
26862690
let my_methods = vec::map(ms, {|m|
2691+
check_ty_params(ccx, m.tps);
26872692
check_method(ccx, m);
26882693
ty_of_method(ccx.tcx, m_check, m)
26892694
});
@@ -2717,10 +2722,43 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
27172722
_ {}
27182723
}
27192724
}
2725+
ast::item_iface(tps, _) | ast::item_ty(_, tps) | ast::item_tag(_, tps) {
2726+
check_ty_params(ccx, tps);
2727+
}
27202728
_ {/* nothing to do */ }
27212729
}
27222730
}
27232731

2732+
fn check_native_item(ccx: @crate_ctxt, it: @ast::native_item) {
2733+
alt it.node {
2734+
ast::native_item_fn(_, tps) { check_ty_params(ccx, tps); }
2735+
_ {}
2736+
}
2737+
}
2738+
2739+
fn check_ty_params(ccx: @crate_ctxt, tps: [ast::ty_param]) {
2740+
for tp in tps {
2741+
let i = 0u;
2742+
for bound in *tp.bounds {
2743+
alt bound {
2744+
ast::bound_iface(at) {
2745+
let tbound = ccx.tcx.ty_param_bounds.get(local_def(tp.id))[i];
2746+
let bound_ty = alt tbound { ty::bound_iface(t) { t } };
2747+
alt ty::struct(ccx.tcx, bound_ty) {
2748+
ty::ty_iface(_, _) {}
2749+
_ {
2750+
ccx.tcx.sess.span_err(at.span, "type parameter bounds \
2751+
must be interface types");
2752+
}
2753+
}
2754+
}
2755+
_ {}
2756+
}
2757+
i += 1u;
2758+
}
2759+
}
2760+
}
2761+
27242762
fn arg_is_argv_ty(tcx: ty::ctxt, a: ty::arg) -> bool {
27252763
alt ty::struct(tcx, a.ty) {
27262764
ty::ty_vec(mt) {
@@ -2778,8 +2816,10 @@ fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map,
27782816
method_map: std::map::new_int_hash(),
27792817
tcx: tcx};
27802818
let visit =
2781-
visit::mk_simple_visitor(@{visit_item: bind check_item(ccx, _)
2782-
with *visit::default_simple_visitor()});
2819+
visit::mk_simple_visitor(@{visit_item: bind check_item(ccx, _),
2820+
visit_native_item:
2821+
bind check_native_item(ccx, _)
2822+
with *visit::default_simple_visitor()});
27832823
visit::visit_crate(*crate, (), visit);
27842824
check_for_main_fn(tcx, crate);
27852825
tcx.sess.abort_if_errors();

0 commit comments

Comments
 (0)