From 6a16f57c0a3f37d86b4c8e074f0796669fcd9528 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 2 Dec 2011 10:15:21 +0100 Subject: [PATCH] Get a very primitive form of typechecking/resolving to work for impls No conflict resolution or polymorphism yet. Issue #1227 --- src/comp/middle/resolve.rs | 38 ++++++------- src/comp/middle/trans.rs | 5 +- src/comp/middle/typeck.rs | 112 ++++++++++++++++++++++++------------- 3 files changed, 93 insertions(+), 62 deletions(-) diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index 4121771e8b6..22d5945a792 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -19,7 +19,7 @@ import option::{some, none, is_none, is_some}; import syntax::print::pprust::*; export resolve_crate; -export def_map, ext_map, exp_map, impl_map; +export def_map, ext_map, exp_map, impl_map, iscopes; // Resolving happens in two passes. The first pass collects defids of all // (internal) imports and modules, so that they can be looked up when needed, @@ -48,7 +48,7 @@ tag import_state { resolved(option::t, /* value */ option::t, /* type */ option::t, /* module */ - @[def_id], + @[@ast::item], /* used for reporting unused import warning */ ast::ident, codemap::span); } @@ -487,7 +487,7 @@ fn resolve_import(e: env, defid: ast::def_id, name: ast::ident, ids: [ast::ident], sp: codemap::span, sc: scopes) { fn register(e: env, id: node_id, cx: ctxt, sp: codemap::span, name: ast::ident, lookup: block(namespace) -> option::t, - impls: [def_id]) { + impls: [@ast::item]) { let val = lookup(ns_value), typ = lookup(ns_type), md = lookup(ns_module); if is_none(val) && is_none(typ) && is_none(md) { @@ -1623,13 +1623,14 @@ fn check_exports(e: @env) { fn resolve_impls(e: @env, c: @ast::crate) { visit::visit_crate(*c, nil, visit::mk_vt(@{ visit_block: bind visit_block_with_impl_scope(e, _, _, _), - visit_item: bind visit_item_with_impl_scope(e, _, _, _), + visit_mod: bind visit_mod_with_impl_scope(e, _, _, _, _), visit_expr: bind resolve_impl_in_expr(e, _, _, _) with *visit::default_visitor() })); } -fn find_impls_in_view_item(e: env, vi: @ast::view_item, &impls: [def_id]) { +fn find_impls_in_view_item(e: env, vi: @ast::view_item, + &impls: [@ast::item]) { alt vi.node { ast::view_item_import(ident, _, id) { // FIXME if single name, simply look in our own iscope @@ -1658,20 +1659,20 @@ fn find_impls_in_view_item(e: env, vi: @ast::view_item, &impls: [def_id]) { } } -fn find_impls_in_item(i: @ast::item, &impls: [def_id], +fn find_impls_in_item(i: @ast::item, &impls: [@ast::item], name: option::t, _dir: dir) { // FIXME check exports alt i.node { ast::item_impl(_, _, _) { if alt name { some(n) { n == i.ident } _ { true } } { - impls += [local_def(i.id)]; + impls += [i]; } } _ {} } } -fn find_impls_in_mod(e: env, m: def, &impls: [def_id], +fn find_impls_in_mod(e: env, m: def, &impls: [@ast::item], name: option::t) { alt m { ast::def_mod(defid) { @@ -1686,7 +1687,7 @@ fn find_impls_in_mod(e: env, m: def, &impls: [def_id], } } -type iscopes = list<@[def_id]>; +type iscopes = list<@[@ast::item]>; fn visit_block_with_impl_scope(e: @env, b: ast::blk, sc: iscopes, v: vt) { @@ -1704,19 +1705,12 @@ fn visit_block_with_impl_scope(e: @env, b: ast::blk, sc: iscopes, visit::visit_block(b, sc, v); } -fn visit_item_with_impl_scope(e: @env, i: @ast::item, sc: iscopes, - v: vt) { - let sc = sc; - alt i.node { - ast::item_mod(m) { - let impls = []; - for vi in m.view_items { find_impls_in_view_item(*e, vi, impls); } - for i in m.items { find_impls_in_item(i, impls, none, inside); } - if vec::len(impls) > 0u { sc = cons(@impls, @sc); } - } - _ {} - } - visit::visit_item(i, sc, v); +fn visit_mod_with_impl_scope(e: @env, m: ast::_mod, s: span, sc: iscopes, + v: vt) { + let impls = []; + for vi in m.view_items { find_impls_in_view_item(*e, vi, impls); } + for i in m.items { find_impls_in_item(i, impls, none, inside); } + visit::visit_mod(m, s, vec::len(impls) > 0u ? cons(@impls, @sc) : sc, v); } fn resolve_impl_in_expr(e: @env, x: @ast::expr, sc: iscopes, v: vt) { diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index bd25cc4e9bf..a0493b8cbc8 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -4949,7 +4949,10 @@ 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(_, _, _) { fail "FIXME[impl]"; } + ast::item_impl(_, _, _) { + + fail "FIXME[impl]"; + } ast::item_res(dtor, dtor_id, tps, ctor_id) { trans_res_ctor(cx, item.span, dtor, ctor_id, tps); diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 1150f4637de..10814ed61ae 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -457,7 +457,7 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item) tcx.tcache.insert(local_def(it.id), tpt); ret tpt; } - ast::item_mod(_) { fail; } + ast::item_impl(_, _, _) | ast::item_mod(_) | ast::item_native_mod(_) { fail; } } } @@ -689,17 +689,20 @@ mod collect { } fn convert(cx: @ctxt, it: @ast::item) { alt it.node { - ast::item_mod(_) | ast::item_impl(_, _, _) { - // ignore item_mod, it has no type. - } - ast::item_native_mod(native_mod) { - // do nothing, as native modules have no types. - } + // These don't define types. + ast::item_mod(_) | ast::item_native_mod(_) {} ast::item_tag(variants, ty_params) { let tpt = ty_of_item(cx.tcx, m_collect, it); write::ty_only(cx.tcx, it.id, tpt.ty); get_tag_variant_types(cx, local_def(it.id), variants, ty_params); } + ast::item_impl(_, _, ms) { + for m in ms { + write::ty_only(cx.tcx, m.node.id, + ty::method_ty_to_fn_ty(cx.tcx, ty_of_method( + cx.tcx, m_collect, m))); + } + } ast::item_obj(object, ty_params, ctor_id) { // Now we need to call ty_of_obj_ctor(); this is the type that // we write into the table for this item. @@ -714,8 +717,8 @@ mod collect { // ty_of_obj().) let method_types = ty_of_obj_methods(cx.tcx, m_collect, object); let i = 0u; - while i < vec::len::<@ast::method>(object.methods) { - write::ty_only(cx.tcx, object.methods[i].node.id, + for m in object.methods { + write::ty_only(cx.tcx, m.node.id, ty::method_ty_to_fn_ty(cx.tcx, method_types[i])); i += 1u; @@ -919,8 +922,6 @@ fn variant_arg_types(ccx: @crate_ctxt, _sp: span, vid: ast::def_id, let tpt = ty::lookup_item_type(ccx.tcx, vid); alt ty::struct(ccx.tcx, tpt.ty) { ty::ty_fn(_, ins, _, _, _) { - - // N-ary variant. for arg: ty::arg in ins { let arg_ty = @@ -930,7 +931,6 @@ fn variant_arg_types(ccx: @crate_ctxt, _sp: span, vid: ast::def_id, } _ { // Nullary variant. Do nothing, as there are no arguments. - } } /* result is a vector of the *expected* types of all the fields */ @@ -2144,35 +2144,70 @@ 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); - base_t = do_autoderef(fcx, expr.span, base_t); - alt structure_of(fcx, expr.span, base_t) { - ty::ty_rec(fields) { - let ix: uint = ty::field_idx(tcx.sess, expr.span, field, fields); - if ix >= vec::len::(fields) { - tcx.sess.span_fatal(expr.span, "bad index on record"); - } - write::ty_only_fixup(fcx, id, fields[ix].mt.ty); - } - ty::ty_obj(methods) { - let ix: uint = - ty::method_idx(tcx.sess, expr.span, field, methods); - if ix >= vec::len::(methods) { - tcx.sess.span_fatal(expr.span, "bad index on obj"); - } - let meth = methods[ix]; - let t = - ty::mk_fn(tcx, meth.proto, meth.inputs, meth.output, meth.cf, - meth.constrs); - write::ty_only_fixup(fcx, id, t); + 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); + let f_ty = ty::mk_fn(fcx.ccx.tcx, mt.proto, mt.inputs, + mt.output, mt.cf, mt.constrs); + write::ty_only_fixup(fcx, id, f_ty); } _ { - let t_err = resolve_type_vars_if_possible(fcx, base_t); - let msg = - #fmt["attempted field access on type %s", - ty_to_str(tcx, t_err)]; - tcx.sess.span_fatal(expr.span, msg); + base_t = do_autoderef(fcx, expr.span, base_t); + alt structure_of(fcx, expr.span, base_t) { + ty::ty_rec(fields) { + let ix = ty::field_idx(tcx.sess, expr.span, field, fields); + if ix >= vec::len::(fields) { + tcx.sess.span_fatal(expr.span, "bad index on record"); + } + write::ty_only_fixup(fcx, id, fields[ix].mt.ty); + } + ty::ty_obj(methods) { + let ix = ty::method_idx(tcx.sess, expr.span, field, methods); + if ix >= vec::len::(methods) { + tcx.sess.span_fatal(expr.span, "bad index on obj"); + } + let meth = methods[ix]; + let t = ty::mk_fn(tcx, meth.proto, meth.inputs, meth.output, + meth.cf, meth.constrs); + write::ty_only_fixup(fcx, id, t); + } + _ { + let t_err = resolve_type_vars_if_possible(fcx, base_t); + let msg = #fmt["attempted field access on type %s, but no \ + method implementation was found", + ty_to_str(tcx, t_err)]; + tcx.sess.span_fatal(expr.span, msg); + } + } } } } @@ -2602,13 +2637,12 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { ast::item_obj(ob, _, _) { // We're entering an object, so gather up the info we need. ccx.obj_infos += [regular_obj(ob.fields, it.id)]; - // Typecheck the methods. for method: @ast::method in ob.methods { check_method(ccx, method); } - // Now remove the info from the stack. vec::pop::(ccx.obj_infos); } + ast::item_impl(_, _, ms) { for m in ms { check_method(ccx, m); } } _ {/* nothing to do */ } } }