Make polymorphic impl methods work

Something will still have to be done to the AST to make it possible to
say `x.foo::<int>()`, since currently field access never allows type
parameters.

Issue #1227
This commit is contained in:
Marijn Haverbeke 2011-12-16 11:37:38 +01:00
parent cff6bdd036
commit d529757515
7 changed files with 82 additions and 56 deletions

View file

@ -751,10 +751,11 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
ast::item_obj(ob, ty_params, _) {
ret lookup_in_obj(name, ob, ty_params, ns, it.id);
}
ast::item_impl(_, _, _) {
ast::item_impl(ty_params, _, _) {
if (name == "self" && ns == ns_value) {
ret some(ast::def_self(local_def(it.id)));
}
if ns == ns_type { ret lookup_in_ty_params(name, ty_params); }
}
ast::item_tag(_, ty_params) {
if ns == ns_type { ret lookup_in_ty_params(name, ty_params); }

View file

@ -4353,15 +4353,19 @@ fn create_llargs_for_fn_args(cx: @fn_ctxt, ty_self: self_arg,
// way.
let arg_n = 2u;
alt ty_self {
obj_self(tt) | impl_self(tt) { cx.llself = some({v: cx.llenv, t: tt}); }
no_self. {
let i = 0u;
for tp: ast::ty_param in ty_params {
obj_self(tt) | impl_self(tt) {
cx.llself = some({v: cx.llenv, t: tt});
}
no_self. {}
}
alt ty_self {
obj_self(_) {}
_ {
for tp in ty_params {
let llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
assert (llarg as int != 0);
cx.lltydescs += [llarg];
arg_n += 1u;
i += 1u;
}
}
}
@ -4659,14 +4663,14 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
}
fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method],
id: ast::node_id) {
id: ast::node_id, tps: [ast::ty_param]) {
let sub_cx = extend_path(cx, name);
for m in methods {
alt cx.ccx.item_ids.find(m.node.id) {
some(llfn) {
trans_fn(extend_path(sub_cx, m.node.ident), m.span, m.node.meth,
llfn, impl_self(ty::node_id_to_monotype(cx.ccx.tcx, id)),
[], m.node.id);
tps + m.node.tps, m.node.id);
}
}
}
@ -4980,7 +4984,9 @@ fn trans_item(cx: @local_ctxt, item: ast::item) {
with *extend_path(cx, item.ident)};
trans_obj(sub_cx, item.span, ob, ctor_id, tps);
}
ast::item_impl(_, _, ms) { trans_impl(cx, item.ident, ms, item.id); }
ast::item_impl(tps, _, ms) {
trans_impl(cx, item.ident, ms, item.id, tps);
}
ast::item_res(dtor, dtor_id, tps, ctor_id) {
trans_res_ctor(cx, item.span, dtor, ctor_id, tps);
@ -5304,11 +5310,11 @@ fn collect_item_2(ccx: @crate_ctxt, i: @ast::item, &&pt: [str],
ccx.obj_methods.insert(m.node.id, ());
}
}
ast::item_impl(_, _, methods) {
ast::item_impl(tps, _, methods) {
let name = ccx.names.next(i.ident);
for m in methods {
register_fn(ccx, i.span, pt + [name, m.node.ident],
"impl_method", [], m.node.id);
"impl_method", tps + m.node.tps, m.node.id);
}
}
ast::item_res(_, dtor_id, tps, ctor_id) {

View file

@ -962,8 +962,7 @@ mod writeback {
typ) {
fix_ok(new_type) { ret some(new_type); }
fix_err(vid) {
fcx.ccx.tcx.sess.span_err(sp,
"cannot determine a type \
fcx.ccx.tcx.sess.span_err(sp, "cannot determine a type \
for this expression");
ret none;
}
@ -1461,6 +1460,42 @@ fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool {
ret check_expr_with_unifier(fcx, expr, demand::simple, expected);
}
// FIXME[impl] notice/resolve conflicts
fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
name: ast::ident, ty: ty::t)
-> option::t<{method: @ast::method, ids: [int]}> {
let result = none;
std::list::iter(isc) {|impls|
for im in *impls {
alt im.node {
ast::item_impl(tps, slf, mthds) {
let self_ty = ast_ty_to_ty_crate(fcx.ccx, slf);
let tp_count = vec::len(tps);
let {ids, ty: self_ty} = if tp_count > 0u {
bind_params_in_type(ast_util::dummy_sp(), fcx.ccx.tcx,
bind next_ty_var_id(fcx), self_ty,
tp_count)
} else { {ids: [], ty: self_ty} };
// FIXME[impl] Don't unify in the current fcx, use
// scratch context
alt unify::unify(fcx, ty, self_ty) {
ures_ok(_) {
for m in mthds {
if m.node.ident == name {
result = some({method: m, ids: ids});
ret;
}
}
}
_ {}
}
}
}
}
}
result
}
fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
expected: ty::t) -> bool {
//log_err "typechecking expr " + syntax::print::pprust::expr_to_str(expr);
@ -2089,42 +2124,24 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
}
}
ast::expr_field(base, field) {
// FIXME proper type compare, notice conflicts
fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
name: ast::ident, ty: ty::t)
-> option::t<@ast::method> {
let result = none;
std::list::iter(isc) {|impls|
for im in *impls {
alt im.node {
ast::item_impl(_, slf, mthds) {
let self_ty = ast_ty_to_ty_crate(fcx.ccx, slf);
alt unify::unify(fcx, ty, self_ty) {
ures_ok(_) {}
_ { cont; }
}
for m in mthds {
if m.node.ident == name {
result = some(m);
ret;
}
}
}
}
}
}
result
}
bot |= check_expr(fcx, base);
let base_t = expr_ty(tcx, base);
let iscope = fcx.ccx.impl_map.get(expr.id);
alt lookup_method(fcx, iscope, field, base_t) {
some(method) {
let mt = ty_of_method(fcx.ccx.tcx, m_check, method);
some({method, ids}) {
let mt = ty_of_method(fcx.ccx.tcx, m_check, method), ids = ids;
let fty = ty::mk_fn(fcx.ccx.tcx, mt.proto, mt.inputs,
mt.output, mt.cf, mt.constrs);
write::ty_only_fixup(fcx, id, fty);
let tp_count = vec::len(method.node.tps);
if tp_count > 0u {
let b = bind_params_in_type(expr.span, tcx,
bind next_ty_var_id(fcx),
fty, tp_count);
ids += b.ids;
fty = b.ty;
}
let substs = vec::map({|id| ty::mk_var(tcx, id)}, ids);
write::ty_fixup(fcx, id, {substs: some(substs), ty: fty});
fcx.ccx.method_map.insert(id, local_def(method.node.id));
}
_ {