]> git.lizzy.rs Git - rust.git/commitdiff
Check impls methods against the type of their iface.
authorMarijn Haverbeke <marijnh@gmail.com>
Thu, 22 Dec 2011 07:45:18 +0000 (08:45 +0100)
committerMarijn Haverbeke <marijnh@gmail.com>
Fri, 23 Dec 2011 17:11:36 +0000 (18:11 +0100)
src/comp/metadata/tydecode.rs
src/comp/middle/ty.rs
src/comp/middle/typeck.rs
src/comp/syntax/ast.rs
src/comp/syntax/parse/parser.rs

index 87dbb363da798471f135bd48ffe4b471e39e5610..d4dbbe264dcb6c107be2ecdb0d86bd3edb5190ad 100644 (file)
@@ -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;
index f668184acb60a91bb61ff04273166d1147d845de..df78cbc3d85c86789c727e2aa39894869adcd47b 100644 (file)
 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;
 
 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]>;
 
       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 eq_raw_ty(&&a: @raw_t, &&b: @raw_t) -> bool {
           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 @@ fn unify_obj(cx: @ctxt, expected_meths: [method],
               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)}
+            })
           }
         }
     };
index 21adb2af201ffff744adc07da3edd2cb435f3adf..3a137bab2ce62ff36e49e4a3a4022bd8af6495e9 100644 (file)
@@ -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 */ }
     }
index 9952dd55546c70efd7b3fed1d407b764229098c8..b1159affc10241ffc0b634b5211d3329a7b4788a 100644 (file)
@@ -309,7 +309,7 @@ fn proto_kind(p: proto) -> kind {
 
 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; }
 
index 8299f23ae2032c2067073ffcd03841781c3a1ec9..978b976eb03acedc660c1efbb528971398aeeb11 100644 (file)
@@ -285,21 +285,21 @@ fn parse_fn_input_ty(p: parser) -> ast::arg {
                     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);
 }