about summary refs log tree commit diff
path: root/src/comp/middle
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-12-29 11:23:35 +0100
committerMarijn Haverbeke <marijnh@gmail.com>2012-01-02 15:15:27 +0100
commit40d5f288c35865dc636e19d993260d5983b4fa55 (patch)
tree7fa887a717e5a108274e55bc24f20f25ee2970e2 /src/comp/middle
parent7ea175f23fb3aa35f430d55595b9564a5ab632f8 (diff)
Check that type parameter bounds are interface types
Issue #1227
Diffstat (limited to 'src/comp/middle')
-rw-r--r--src/comp/middle/trans.rs3
-rw-r--r--src/comp/middle/ty.rs45
-rw-r--r--src/comp/middle/typeck.rs58
3 files changed, 73 insertions, 33 deletions
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index a9564f87eb1..99a112321c8 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -4658,7 +4658,8 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
     let ty_param_substs: [ty::t] = [];
     i = 0u;
     for tp: ast::ty_param in ty_params {
-        ty_param_substs += [ty::mk_param(ccx.tcx, i, @[])];
+        ty_param_substs += [ty::mk_param(ccx.tcx, i,
+                                         ast_util::local_def(tp.id))];
         i += 1u;
     }
     let arg_tys = arg_tys_of_fn(ccx, variant.node.id);
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index 2f853f5eb84..f893801d2f0 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -218,7 +218,7 @@ type ctxt =
       needs_drop_cache: hashmap<t, bool>,
       kind_cache: hashmap<t, 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<def_id, @[variant_info]>,
       iface_method_cache: hashmap<def_id, @[method]>,
       ty_param_bounds: hashmap<def_id, @[param_bound]>};
 
@@ -268,7 +268,7 @@ tag sty {
     ty_tup([t]);
     ty_var(int); // type variable
 
-    ty_param(uint, @[param_bound]); // fn/tag type param
+    ty_param(uint, def_id); // fn/tag type param
 
     ty_type; // type_desc*
     ty_send_type; // type_desc* that has been cloned into exchange heap
@@ -624,7 +624,7 @@ fn mk_res(cx: ctxt, did: ast::def_id, inner: t, tps: [t]) -> t {
 
 fn mk_var(cx: ctxt, v: int) -> t { ret gen_ty(cx, ty_var(v)); }
 
-fn mk_param(cx: ctxt, n: uint, k: @[param_bound]) -> t {
+fn mk_param(cx: ctxt, n: uint, k: def_id) -> t {
     ret gen_ty(cx, ty_param(n, k));
 }
 
@@ -722,7 +722,7 @@ fn walk_ty(cx: ctxt, walker: ty_walk, ty: t) {
 
 tag fold_mode {
     fm_var(fn@(int) -> t);
-    fm_param(fn@(uint, @[param_bound]) -> t);
+    fm_param(fn@(uint, def_id) -> t);
     fm_general(fn@(t) -> t);
 }
 
@@ -813,8 +813,8 @@ fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t {
       ty_var(id) {
         alt fld { fm_var(folder) { ty = folder(id); } _ {/* no-op */ } }
       }
-      ty_param(id, k) {
-        alt fld { fm_param(folder) { ty = folder(id, k); } _ {/* no-op */ } }
+      ty_param(id, did) {
+        alt fld { fm_param(folder) { ty = folder(id, did); } _ {/* no-op */ } }
       }
     }
 
@@ -1083,7 +1083,7 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
       }
       // Resources are always noncopyable.
       ty_res(did, inner, tps) { kind_noncopyable }
-      ty_param(_, bounds) { param_bounds_to_kind(bounds) }
+      ty_param(_, did) { param_bounds_to_kind(cx.ty_param_bounds.get(did)) }
       ty_constr(t, _) { type_kind(cx, t) }
     };
 
@@ -1131,7 +1131,7 @@ fn type_structurally_contains(cx: ctxt, ty: t, test: fn(sty) -> bool) ->
     }
 }
 
-pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool {
+pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool unchecked {
 
     /* type_structurally_contains can't be declared pure
     because it takes a function argument. But it should be
@@ -1141,15 +1141,9 @@ pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool {
     actually checkable. It seems to me like a lot of properties
     that the type context tracks about types should be immutable.)
     */
-    unchecked{
-        type_structurally_contains(cx, ty,
-                                   fn (sty: sty) -> bool {
-                                       ret alt sty {
-                                             ty_param(_, _) { true }
-                                             _ { false }
-                                           };
-                                   })
-    }
+    type_structurally_contains(cx, ty, fn (sty: sty) -> bool {
+        alt sty { ty_param(_, _) { true } _ { false }}
+    })
 }
 
 // Returns true for noncopyable types and types where a copy of a value can be
@@ -2205,7 +2199,14 @@ mod unify {
               _ { ret ures_err(terr_mismatch); }
             }
           }
-          ty::ty_param(_, _) { ret struct_cmp(cx, expected, actual); }
+          ty::ty_param(expected_n, _) {
+            alt struct(cx.tcx, actual) {
+              ty::ty_param(actual_n, _) when expected_n == actual_n {
+                ret ures_ok(expected);
+              }
+              _ { ret ures_err(terr_mismatch); }
+            }
+          }
           ty::ty_tag(expected_id, expected_tps) {
             alt struct(cx.tcx, actual) {
               ty::ty_tag(actual_id, actual_tps) {
@@ -2627,8 +2628,7 @@ fn bind_params_in_type(sp: span, cx: ctxt, next_ty_var: fn@() -> int, typ: t,
     let i = 0u;
     while i < ty_param_count { *param_var_ids += [next_ty_var()]; i += 1u; }
     fn binder(sp: span, cx: ctxt, param_var_ids: @mutable [int],
-              _next_ty_var: fn@() -> int, index: uint,
-              _bounds: @[param_bound]) -> t {
+              _next_ty_var: fn@() -> int, index: uint, _did: def_id) -> t {
         if index < vec::len(*param_var_ids) {
             ret mk_var(cx, param_var_ids[index]);
         } else {
@@ -2647,9 +2647,8 @@ fn bind_params_in_type(sp: span, cx: ctxt, next_ty_var: fn@() -> int, typ: t,
 // substitions.
 fn substitute_type_params(cx: ctxt, substs: [ty::t], typ: t) -> t {
     if !type_contains_params(cx, typ) { ret typ; }
-    fn substituter(_cx: ctxt, substs: @[ty::t], idx: uint,
-                   _bounds: @[param_bound])
-       -> t {
+    fn substituter(_cx: ctxt, substs: @[ty::t], idx: uint, _did: def_id)
+        -> t {
         // FIXME: bounds check can fail
         ret substs[idx];
     }
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 5d65ce78049..313023ba108 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -343,7 +343,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
           }
           some(ast::def_native_ty(id)) { typ = getter(tcx, mode, id).ty; }
           some(ast::def_ty_param(id, n)) {
-            typ = ty::mk_param(tcx, n, tcx.ty_param_bounds.get(id));
+            typ = ty::mk_param(tcx, n, id);
           }
           some(_) {
             tcx.sess.span_fatal(ast_ty.span,
@@ -625,8 +625,8 @@ fn mk_ty_params(tcx: ty::ctxt, atps: [ast::ty_param])
     -> {bounds: [@[ty::param_bound]], params: [ty::t]} {
     let i = 0u, bounds = ty_param_bounds(tcx, m_collect, atps);
     {bounds: bounds,
-     params: vec::map(atps, {|_atp|
-         let t = ty::mk_param(tcx, i, bounds[i]);
+     params: vec::map(atps, {|atp|
+         let t = ty::mk_param(tcx, i, local_def(atp.id));
          i += 1u;
          t
      })}
@@ -2666,13 +2666,16 @@ fn check_method(ccx: @crate_ctxt, method: @ast::method) {
 fn check_item(ccx: @crate_ctxt, it: @ast::item) {
     alt it.node {
       ast::item_const(_, e) { check_const(ccx, it.span, e, it.id); }
-      ast::item_fn(decl, _, body) {
+      ast::item_fn(decl, tps, body) {
+        check_ty_params(ccx, tps);
         check_fn(ccx, ast::proto_bare, decl, body, it.id, none);
       }
-      ast::item_res(decl, _, body, dtor_id, _) {
+      ast::item_res(decl, tps, body, dtor_id, _) {
+        check_ty_params(ccx, tps);
         check_fn(ccx, ast::proto_bare, decl, body, dtor_id, none);
       }
-      ast::item_obj(ob, _, _) {
+      ast::item_obj(ob, tps, _) {
+        check_ty_params(ccx, tps);
         // We're entering an object, so gather up the info we need.
         ccx.self_infos += [self_obj(ob.fields,
                                     ccx.tcx.tcache.get(local_def(it.id)).ty)];
@@ -2681,9 +2684,11 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
         // Now remove the info from the stack.
         vec::pop(ccx.self_infos);
       }
-      ast::item_impl(_, ifce, ty, ms) {
+      ast::item_impl(tps, ifce, ty, ms) {
+        check_ty_params(ccx, tps);
         ccx.self_infos += [self_impl(ast_ty_to_ty(ccx.tcx, m_check, ty))];
         let my_methods = vec::map(ms, {|m|
+            check_ty_params(ccx, m.tps);
             check_method(ccx, m);
             ty_of_method(ccx.tcx, m_check, m)
         });
@@ -2717,10 +2722,43 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
           _ {}
         }
       }
+      ast::item_iface(tps, _) | ast::item_ty(_, tps) | ast::item_tag(_, tps) {
+        check_ty_params(ccx, tps);
+      }
       _ {/* nothing to do */ }
     }
 }
 
+fn check_native_item(ccx: @crate_ctxt, it: @ast::native_item) {
+    alt it.node {
+      ast::native_item_fn(_, tps) { check_ty_params(ccx, tps); }
+      _ {}
+    }
+}
+
+fn check_ty_params(ccx: @crate_ctxt, tps: [ast::ty_param]) {
+    for tp in tps {
+        let i = 0u;
+        for bound in *tp.bounds {
+            alt bound {
+              ast::bound_iface(at) {
+                let tbound = ccx.tcx.ty_param_bounds.get(local_def(tp.id))[i];
+                let bound_ty = alt tbound { ty::bound_iface(t) { t } };
+                alt ty::struct(ccx.tcx, bound_ty) {
+                  ty::ty_iface(_, _) {}
+                  _ {
+                    ccx.tcx.sess.span_err(at.span, "type parameter bounds \
+                                                    must be interface types");
+                  }
+                }
+              }
+              _ {}
+            }
+            i += 1u;
+        }
+    }
+}
+
 fn arg_is_argv_ty(tcx: ty::ctxt, a: ty::arg) -> bool {
     alt ty::struct(tcx, a.ty) {
       ty::ty_vec(mt) {
@@ -2778,8 +2816,10 @@ fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map,
                 method_map: std::map::new_int_hash(),
                 tcx: tcx};
     let visit =
-        visit::mk_simple_visitor(@{visit_item: bind check_item(ccx, _)
-                                      with *visit::default_simple_visitor()});
+        visit::mk_simple_visitor(@{visit_item: bind check_item(ccx, _),
+                                   visit_native_item:
+                                       bind check_native_item(ccx, _)
+                                   with *visit::default_simple_visitor()});
     visit::visit_crate(*crate, (), visit);
     check_for_main_fn(tcx, crate);
     tcx.sess.abort_if_errors();