diff options
| author | Marijn Haverbeke <marijnh@gmail.com> | 2011-12-22 08:45:18 +0100 |
|---|---|---|
| committer | Marijn Haverbeke <marijnh@gmail.com> | 2011-12-23 18:11:36 +0100 |
| commit | 25e65239ad81af6123bcf9e4b5173dad2ced99c2 (patch) | |
| tree | 0ab4118d70109b3de721390ef6c3405e8c9dfa95 | |
| parent | 057617c6654bfd5a677112cd26141d0b9c137145 (diff) | |
| download | rust-25e65239ad81af6123bcf9e4b5173dad2ced99c2.tar.gz rust-25e65239ad81af6123bcf9e4b5173dad2ced99c2.zip | |
Check impls methods against the type of their iface.
| -rw-r--r-- | src/comp/metadata/tydecode.rs | 2 | ||||
| -rw-r--r-- | src/comp/middle/ty.rs | 55 | ||||
| -rw-r--r-- | src/comp/middle/typeck.rs | 56 | ||||
| -rw-r--r-- | src/comp/syntax/ast.rs | 2 | ||||
| -rw-r--r-- | src/comp/syntax/parse/parser.rs | 16 |
5 files changed, 87 insertions, 44 deletions
diff --git a/src/comp/metadata/tydecode.rs b/src/comp/metadata/tydecode.rs index 87dbb363da7..d4dbbe264dc 100644 --- a/src/comp/metadata/tydecode.rs +++ b/src/comp/metadata/tydecode.rs @@ -267,7 +267,7 @@ fn parse_ty(st: @pstate, sd: str_def) -> ty::t { while peek(st) as char != '[' { name += str::unsafe_from_byte(next(st)); } - methods += [{ident: name, + methods += [{ident: name, tps: [], fty: {proto: proto with parse_ty_fn(st, sd)}}]; } st.pos += 1u; diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index f668184acb6..df78cbc3d85 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -103,6 +103,7 @@ export substitute_type_params; export t; export new_ty_hash; export tag_variants; +export iface_methods, store_iface_methods; export tag_variant_with_id; export ty_param_substs_opt_and_ty; export ty_param_kinds_and_ty; @@ -191,7 +192,7 @@ type arg = {mode: mode, ty: t}; type field = {ident: ast::ident, mt: mt}; -type method = {ident: ast::ident, fty: fn_ty}; +type method = {ident: ast::ident, tps: [ast::kind], fty: fn_ty}; type constr_table = hashmap<ast::node_id, [constr]>; @@ -215,7 +216,8 @@ type ctxt = needs_drop_cache: hashmap<t, bool>, kind_cache: hashmap<t, ast::kind>, ast_ty_to_ty_cache: hashmap<@ast::ty, option::t<t>>, - tag_var_cache: hashmap<ast::def_id, @[variant_info]>}; + tag_var_cache: hashmap<ast::def_id, @[variant_info]>, + iface_method_cache: hashmap<def_id, @[method]>}; type ty_ctxt = ctxt; @@ -412,7 +414,8 @@ fn mk_ctxt(s: session::session, dm: resolve::def_map, amap: ast_map::map, kind_cache: new_ty_hash(), ast_ty_to_ty_cache: map::mk_hashmap(ast_util::hash_ty, ast_util::eq_ty), - tag_var_cache: new_def_hash()}; + tag_var_cache: new_def_hash(), + iface_method_cache: new_def_hash()}; populate_type_store(cx); ret cx; } @@ -752,7 +755,7 @@ fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t { let new_args = vec::map(m.fty.inputs, {|a| {mode: a.mode, ty: fold_ty(cx, fld, a.ty)} }); - {ident: m.ident, + {ident: m.ident, tps: m.tps, fty: {inputs: new_args, output: fold_ty(cx, fld, m.fty.output) with m.fty}} @@ -1961,7 +1964,8 @@ mod unify { ures_ok(tfn) { alt struct(cx.tcx, tfn) { ty_fn(f) { - result_meths += [{ident: e_meth.ident, fty: f}]; + result_meths += [{ident: e_meth.ident, + tps: a_meth.tps, fty: f}]; } } } @@ -2479,7 +2483,7 @@ fn same_type(cx: ctxt, a: t, b: t) -> bool { } } fn same_method(cx: ctxt, a: method, b: method) -> bool { - a.fty.proto == b.fty.proto && a.ident == b.ident && + a.tps == b.tps && a.fty.proto == b.fty.proto && a.ident == b.ident && vec::all2(a.fty.inputs, b.fty.inputs, {|a, b| a.mode == b.mode && same_type(cx, a.ty, b.ty) }) && same_type(cx, a.fty.output, b.fty.output) && @@ -2587,6 +2591,21 @@ fn def_has_ty_params(def: ast::def) -> bool { } } +fn store_iface_methods(cx: ctxt, id: ast::node_id, ms: @[method]) { + cx.iface_method_cache.insert(ast_util::local_def(id), ms); +} + +fn iface_methods(cx: ctxt, id: ast::def_id) -> @[method] { + alt cx.iface_method_cache.find(id) { + some(ms) { ret ms; } + _ {} + } + // Local interfaces are supposed to have been added explicitly. + assert id.crate != ast::local_crate; + let result = @[]; // FIXME[impl] + cx.iface_method_cache.insert(id, result); + result +} // Tag information type variant_info = @{args: [ty::t], ctor_ty: ty::t, id: ast::def_id}; @@ -2600,20 +2619,16 @@ fn tag_variants(cx: ctxt, id: ast::def_id) -> @[variant_info] { @csearch::get_tag_variants(cx, id) } else { alt cx.items.get(id.node) { - ast_map::node_item(item) { - alt item.node { - ast::item_tag(variants, _) { - @vec::map(variants, {|variant| - let ctor_ty = node_id_to_monotype(cx, variant.node.id); - let arg_tys = if vec::len(variant.node.args) > 0u { - vec::map(ty_fn_args(cx, ctor_ty), {|a| a.ty}) - } else { [] }; - @{args: arg_tys, - ctor_ty: ctor_ty, - id: ast_util::local_def(variant.node.id)} - }) - } - } + ast_map::node_item(@{node: ast::item_tag(variants, _), _}) { + @vec::map(variants, {|variant| + let ctor_ty = node_id_to_monotype(cx, variant.node.id); + let arg_tys = if vec::len(variant.node.args) > 0u { + vec::map(ty_fn_args(cx, ctor_ty), {|a| a.ty}) + } else { [] }; + @{args: arg_tys, + ctor_ty: ctor_ty, + id: ast_util::local_def(variant.node.id)} + }) } } }; diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 21adb2af201..3a137bab2ce 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -422,12 +422,15 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item) tcx.tcache.insert(local_def(it.id), tpt); ret tpt; } - ast::item_iface(tps, methods) { + ast::item_iface(tps, ms) { let t = ty::mk_named(tcx, ty::mk_iface(tcx, local_def(it.id), mk_ty_params(tcx, tps)), @it.ident); let tpt = {kinds: ty_param_kinds(tps), ty: t}; tcx.tcache.insert(local_def(it.id), tpt); + ty::store_iface_methods(tcx, it.id, @vec::map(ms, {|m| + ty_of_ty_method(tcx, m_collect, m) + })); ret tpt; } ast::item_impl(_, _, _, _) | ast::item_mod(_) | @@ -490,11 +493,13 @@ fn ty_of_native_fn_decl(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl, ret tpt; } fn ty_of_method(tcx: ty::ctxt, mode: mode, m: @ast::method) -> ty::method { - {ident: m.ident, fty: ty_of_fn_decl(tcx, mode, m.decl)} + {ident: m.ident, tps: vec::map(m.tps, {|tp| tp.kind}), + fty: ty_of_fn_decl(tcx, mode, m.decl)} } fn ty_of_ty_method(tcx: ty::ctxt, mode: mode, m: ast::ty_method) -> ty::method { - {ident: m.ident, fty: ty_of_fn_decl(tcx, mode, m.decl)} + {ident: m.ident, tps: vec::map(m.tps, {|tp| tp.kind}), + fty: ty_of_fn_decl(tcx, mode, m.decl)} } fn ty_of_obj(tcx: ty::ctxt, mode: mode, id: ast::ident, ob: ast::_obj, ty_params: [ast::ty_param]) -> ty::ty_param_kinds_and_ty { @@ -1493,7 +1498,7 @@ fn check_expr_fn_with_unifier(fcx: @fn_ctxt, // record projection work on type inferred arguments. unify(fcx, expr.span, expected, fty); - check_fn1(fcx.ccx, decl, body, expr.id, some(fcx)); + check_fn(fcx.ccx, decl, body, expr.id, some(fcx)); } fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier, @@ -2565,14 +2570,6 @@ fn check_constraints(fcx: @fn_ctxt, cs: [@ast::constr], args: [ast::arg]) { } fn check_fn(ccx: @crate_ctxt, - decl: ast::fn_decl, - body: ast::blk, - id: ast::node_id, - old_fcx: option::t<@fn_ctxt>) { - check_fn1(ccx, decl, body, id, old_fcx); -} - -fn check_fn1(ccx: @crate_ctxt, decl: ast::fn_decl, body: ast::blk, id: ast::node_id, @@ -2645,10 +2642,41 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { // Now remove the info from the stack. vec::pop(ccx.self_infos); } - ast::item_impl(_, _, ty, ms) { + ast::item_impl(_, ifce, ty, ms) { ccx.self_infos += [self_impl(ast_ty_to_ty(ccx.tcx, m_check, ty))]; - for m in ms { check_method(ccx, m); } + let my_methods = vec::map(ms, {|m| + check_method(ccx, m); + ty_of_method(ccx.tcx, m_check, m) + }); vec::pop(ccx.self_infos); + alt ifce { + some(ty) { + alt ty::struct(ccx.tcx, ast_ty_to_ty(ccx.tcx, m_check, ty)) { + ty::ty_iface(did, tys) { + for if_m in *ty::iface_methods(ccx.tcx, did) { + alt vec::find(my_methods, {|m| if_m.ident == m.ident}) { + some(m) { + if !ty::same_method(ccx.tcx, m, if_m) { + ccx.tcx.sess.span_err( + ty.span, "method " + if_m.ident + + " has the wrong type"); + } + } + none. { + ccx.tcx.sess.span_err(ty.span, "missing method " + + if_m.ident); + } + } + } + } + _ { + ccx.tcx.sess.span_err(ty.span, "can only implement interface \ + types"); + } + } + } + _ {} + } } _ {/* nothing to do */ } } diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index 9952dd55546..b1159affc10 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -309,7 +309,7 @@ type ty_field_ = {ident: ident, mt: mt}; type ty_field = spanned<ty_field_>; -type ty_method = {ident: ident, decl: fn_decl, span: span}; +type ty_method = {ident: ident, decl: fn_decl, tps: [ty_param], span: span}; tag int_ty { ty_i; ty_char; ty_i8; ty_i16; ty_i32; ty_i64; } diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 8299f23ae20..978b976eb03 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -285,21 +285,21 @@ fn parse_ty_fn(proto: ast::proto, p: parser) -> ast::ty_ { constraints: constrs}); } -fn parse_ty_methods(p: parser) -> [ast::ty_method] { - fn parse_method_sig(p: parser) -> ast::ty_method { +fn parse_ty_methods(p: parser, allow_tps: bool) -> [ast::ty_method] { + parse_seq(token::LBRACE, token::RBRACE, seq_sep_none(), {|p| let flo = p.get_lo_pos(); let proto: ast::proto = parse_method_proto(p); let ident = parse_value_ident(p); + let tps = allow_tps ? parse_ty_params(p) : []; let f = parse_ty_fn(proto, p), fhi = p.get_last_hi_pos(); expect(p, token::SEMI); alt f { ast::ty_fn(d) { - {ident: ident, decl: d, span: ast_util::mk_sp(flo, fhi)} + {ident: ident, decl: d, tps: tps, + span: ast_util::mk_sp(flo, fhi)} } } - } - parse_seq(token::LBRACE, token::RBRACE, seq_sep_none(), - parse_method_sig, p).node + }, p).node } fn parse_mt(p: parser) -> ast::mt { @@ -517,7 +517,7 @@ fn parse_ty(p: parser, colons_before_params: bool) -> @ast::ty { } else if eat_word(p, "sendfn") { t = parse_ty_fn(ast::proto_send, p); } else if eat_word(p, "obj") { - t = ast::ty_obj(parse_ty_methods(p)); + t = ast::ty_obj(parse_ty_methods(p, false)); } else if p.peek() == token::MOD_SEP || is_ident(p.peek()) { let path = parse_path(p); t = ast::ty_path(path, p.get_id()); @@ -1839,7 +1839,7 @@ fn parse_item_obj(p: parser, attrs: [ast::attribute]) -> @ast::item { fn parse_item_iface(p: parser, attrs: [ast::attribute]) -> @ast::item { let lo = p.get_last_lo_pos(), ident = parse_ident(p), - tps = parse_ty_params(p), meths = parse_ty_methods(p); + tps = parse_ty_params(p), meths = parse_ty_methods(p, true); ret mk_item(p, lo, p.get_last_hi_pos(), ident, ast::item_iface(tps, meths), attrs); } |
