Skip to content

Commit a7e1a35

Browse files
committed
Properly typecheck and compile invocations of generic methods.
Aligning the type parameters of the ifaces, impls, and methods correctly in typeck is almost brain surgery. Seems to work now for everything I threw at it, but might still break in other corner cases. Issue #1227
1 parent d1ffe50 commit a7e1a35

File tree

6 files changed

+236
-167
lines changed

6 files changed

+236
-167
lines changed

src/comp/middle/resolve.rs

+18-11
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ tag scope {
3737
scope_loop(@ast::local); // there's only 1 decl per loop.
3838
scope_block(ast::blk, @mutable uint, @mutable uint);
3939
scope_arm(ast::arm);
40-
scope_self(ast::node_id);
40+
scope_method(ast::node_id, [ast::ty_param]);
4141
}
4242

4343
type scopes = list<scope>;
@@ -404,9 +404,17 @@ fn visit_item_with_scope(i: @ast::item, sc: scopes, v: vt<scopes>) {
404404
alt ifce { some(ty) { v.visit_ty(ty, sc, v); } _ {} }
405405
v.visit_ty(sty, sc, v);
406406
for m in methods {
407-
v.visit_fn(visit::fk_method(m.ident, tps + m.tps),
408-
m.decl, m.body, m.span,
409-
m.id, sc, v);
407+
let msc = cons(scope_method(i.id, tps + m.tps), @sc);
408+
v.visit_fn(visit::fk_method(m.ident, []),
409+
m.decl, m.body, m.span, m.id, msc, v);
410+
}
411+
}
412+
ast::item_iface(tps, methods) {
413+
visit::visit_ty_params(tps, sc, v);
414+
for m in methods {
415+
let msc = cons(scope_method(i.id, tps + m.tps), @sc);
416+
for a in m.decl.inputs { v.visit_ty(a.ty, msc, v); }
417+
v.visit_ty(m.decl.output, msc, v);
410418
}
411419
}
412420
_ { visit::visit_item(i, sc, v); }
@@ -437,8 +445,8 @@ fn visit_fn_with_scope(e: @env, fk: visit::fn_kind, decl: ast::fn_decl,
437445
// for f's constrs in the table.
438446
for c: @ast::constr in decl.constraints { resolve_constr(e, c, sc, v); }
439447
let scope = alt fk {
440-
visit::fk_item_fn(_, tps) | visit::fk_method(_, tps) |
441-
visit::fk_res(_, tps) {
448+
visit::fk_item_fn(_, tps) | visit::fk_res(_, tps) |
449+
visit::fk_method(_, tps) {
442450
scope_bare_fn(decl, id, tps)
443451
}
444452
visit::fk_anon(_) | visit::fk_fn_block. {
@@ -491,7 +499,7 @@ fn visit_expr_with_scope(x: @ast::expr, sc: scopes, v: vt<scopes>) {
491499
v.visit_block(blk, new_sc, v);
492500
}
493501
ast::expr_anon_obj(_) {
494-
visit::visit_expr(x, cons(scope_self(x.id), @sc), v);
502+
visit::visit_expr(x, cons(scope_method(x.id, []), @sc), v);
495503
}
496504
_ { visit::visit_expr(x, sc, v); }
497505
}
@@ -801,9 +809,6 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
801809
ret lookup_in_obj(name, ob, ty_params, ns, it.id);
802810
}
803811
ast::item_impl(ty_params, _, _, _) {
804-
if (name == "self" && ns == ns_value) {
805-
ret some(ast::def_self(local_def(it.id)));
806-
}
807812
if ns == ns_type { ret lookup_in_ty_params(name, ty_params); }
808813
}
809814
ast::item_iface(tps, _) | ast::item_tag(_, tps) |
@@ -819,9 +824,11 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
819824
_ { }
820825
}
821826
}
822-
scope_self(id) {
827+
scope_method(id, tps) {
823828
if (name == "self" && ns == ns_value) {
824829
ret some(ast::def_self(local_def(id)));
830+
} else if ns == ns_type {
831+
ret lookup_in_ty_params(name, tps);
825832
}
826833
}
827834
scope_native_item(it) {

src/comp/middle/trans_impl.rs

+21-3
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,13 @@ fn trans_static_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
3737
{env: obj_env(val) with lval_static_fn(bcx, did, e.id)}
3838
}
3939

40-
fn trans_dict_callee(bcx: @block_ctxt, _e: @ast::expr, base: @ast::expr,
40+
fn trans_dict_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
4141
iface_id: ast::def_id, n_method: uint,
4242
n_param: uint, n_bound: uint) -> lval_maybe_callee {
43+
let tcx = bcx_tcx(bcx);
4344
let {bcx, val} = trans_self_arg(bcx, base);
4445
let dict = option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound];
45-
let method = ty::iface_methods(bcx_tcx(bcx), iface_id)[n_method];
46+
let method = ty::iface_methods(tcx, iface_id)[n_method];
4647
let bare_fn_ty = type_of_fn(bcx_ccx(bcx), ast_util::dummy_sp(),
4748
false, method.fty.inputs, method.fty.output,
4849
*method.tps);
@@ -51,9 +52,26 @@ fn trans_dict_callee(bcx: @block_ctxt, _e: @ast::expr, base: @ast::expr,
5152
let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])),
5253
T_ptr(T_array(T_ptr(fn_ty), n_method + 1u)));
5354
let mptr = Load(bcx, GEPi(bcx, vtable, [0, n_method as int]));
55+
let generic = none;
56+
if vec::len(*method.tps) > 0u {
57+
let tydescs = [], tis = [];
58+
for t in ty::node_id_to_type_params(tcx, e.id) {
59+
// TODO: Doesn't always escape.
60+
let ti = none;
61+
let td = get_tydesc(bcx, t, true, tps_normal, ti).result;
62+
tis += [ti];
63+
tydescs += [td.val];
64+
bcx = td.bcx;
65+
}
66+
generic = some({item_type: ty::mk_fn(tcx, method.fty),
67+
static_tis: tis,
68+
tydescs: tydescs,
69+
param_bounds: method.tps,
70+
origins: bcx_ccx(bcx).dict_map.find(e.id)});
71+
}
5472
{bcx: bcx, val: mptr, kind: owned,
5573
env: dict_env(dict, val),
56-
generic: none} // FIXME[impl] fetch generic info for method
74+
generic: generic}
5775
}
5876

5977
fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} {

src/comp/middle/ty.rs

+14-32
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import util::common::*;
1818
import syntax::util::interner;
1919
import util::ppaux::ty_to_str;
2020
import util::ppaux::ty_constr_to_str;
21-
import util::ppaux::mode_str_1;
21+
import util::ppaux::mode_str;
2222
import syntax::print::pprust::*;
2323

2424
export node_id_to_monotype;
@@ -1739,7 +1739,7 @@ mod unify {
17391739
export ures_ok;
17401740
export ures_err;
17411741
export var_bindings;
1742-
export precise, in_bindings, bind_params;
1742+
export precise, in_bindings;
17431743

17441744
tag result { ures_ok(t); ures_err(type_err); }
17451745
tag union_result { unres_ok; unres_err(type_err); }
@@ -1753,7 +1753,6 @@ mod unify {
17531753
tag unify_style {
17541754
precise;
17551755
in_bindings(@var_bindings);
1756-
bind_params(@mutable [mutable option::t<t>]);
17571756
}
17581757
type ctxt = {st: unify_style, tcx: ty_ctxt};
17591758

@@ -2172,16 +2171,6 @@ mod unify {
21722171
}
21732172
ret ures_ok(mk_var(cx.tcx, actual_id));
21742173
}
2175-
ty::ty_param(n, _) {
2176-
alt cx.st {
2177-
bind_params(cell) {
2178-
while vec::len(*cell) < n + 1u { *cell += [mutable none]; }
2179-
cell[n] = some(expected);
2180-
ret ures_ok(expected);
2181-
}
2182-
_ {}
2183-
}
2184-
}
21852174
_ {/* empty */ }
21862175
}
21872176
alt struct(cx.tcx, expected) {
@@ -2627,8 +2616,8 @@ fn type_err_to_str(err: ty::type_err) -> str {
26272616
"' but found one with method '" + a_meth + "'";
26282617
}
26292618
terr_mode_mismatch(e_mode, a_mode) {
2630-
ret "expected argument mode " + mode_str_1(e_mode) + " but found " +
2631-
mode_str_1(a_mode);
2619+
ret "expected argument mode " + mode_str(e_mode) + " but found " +
2620+
mode_str(a_mode);
26322621
}
26332622
terr_constr_len(e_len, a_len) {
26342623
ret "Expected a type with " + uint::str(e_len) +
@@ -2646,24 +2635,17 @@ fn type_err_to_str(err: ty::type_err) -> str {
26462635

26472636
// Converts type parameters in a type to type variables and returns the
26482637
// resulting type along with a list of type variable IDs.
2649-
fn bind_params_in_type(sp: span, cx: ctxt, next_ty_var: fn@() -> int, typ: t,
2638+
fn bind_params_in_type(cx: ctxt, next_ty_var: block() -> int, typ: t,
26502639
ty_param_count: uint) -> {ids: [int], ty: t} {
2651-
let param_var_ids: @mutable [int] = @mutable [];
2652-
let i = 0u;
2653-
while i < ty_param_count { *param_var_ids += [next_ty_var()]; i += 1u; }
2654-
fn binder(sp: span, cx: ctxt, param_var_ids: @mutable [int],
2655-
_next_ty_var: fn@() -> int, index: uint, _did: def_id) -> t {
2656-
if index < vec::len(*param_var_ids) {
2657-
ret mk_var(cx, param_var_ids[index]);
2658-
} else {
2659-
cx.sess.span_fatal(sp, "Unbound type parameter in callee's type");
2660-
}
2661-
}
2662-
let new_typ =
2663-
fold_ty(cx,
2664-
fm_param(bind binder(sp, cx, param_var_ids, next_ty_var, _,
2665-
_)), typ);
2666-
ret {ids: *param_var_ids, ty: new_typ};
2640+
let param_var_ids = [], i = 0u;
2641+
while i < ty_param_count { param_var_ids += [next_ty_var()]; i += 1u; }
2642+
let param_var_ids = @param_var_ids;
2643+
fn binder(cx: ctxt, param_var_ids: @[int], index: uint,
2644+
_did: def_id) -> t {
2645+
ret mk_var(cx, param_var_ids[index]);
2646+
}
2647+
{ids: *param_var_ids,
2648+
ty: fold_ty(cx, fm_param(bind binder(cx, param_var_ids, _, _)), typ)}
26672649
}
26682650

26692651

0 commit comments

Comments
 (0)