about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2011-10-14 17:34:41 -0700
committerBrian Anderson <banderson@mozilla.com>2011-10-20 18:23:48 -0700
commit8136b92ee8e47fc460e64eb7ab65bc59f33efb71 (patch)
tree825ddf213ee65f9a7804e0b868b6b49866a9f88d
parented985b61d5c1e35b10a135ec8872aec2fbf66531 (diff)
downloadrust-8136b92ee8e47fc460e64eb7ab65bc59f33efb71.tar.gz
rust-8136b92ee8e47fc460e64eb7ab65bc59f33efb71.zip
Give subtype relationships to function types
-rw-r--r--src/comp/middle/ty.rs59
-rw-r--r--src/test/run-pass/fn-coerce-field.rs7
2 files changed, 64 insertions, 2 deletions
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index 1288de9fa22..71521abb538 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -1010,9 +1010,11 @@ fn type_kind(cx: ctxt, ty: t) -> ast::kind {
       // here yet, leading to weirdness around closure.
       ty_fn(proto, _, _, _, _) {
         result = alt proto {
+          ast::proto_iter. { ast::kind_shared }
           ast::proto_block. { ast::kind_pinned }
           ast::proto_closure. { ast::kind_shared }
-          _ { ast::kind_unique }
+          ast::proto_fn. { ast::kind_shared }
+          ast::proto_bare. { ast::kind_unique }
         };
       }
       // Those with refcounts-to-inner raise pinned to shared,
@@ -2018,6 +2020,54 @@ mod unify {
           _ { ret fn_common_res_err(result); }
         }
     }
+    fn unify_fn_proto(e_proto: ast::proto, a_proto: ast::proto,
+                      variance: variance) -> option::t<result> {
+        fn gt(e_proto: ast::proto, a_proto: ast::proto) -> bool {
+            alt e_proto {
+              ast::proto_block. {
+                // Every function type is a subtype of block
+                false
+              }
+              ast::proto_closure. | ast::proto_fn. {
+                a_proto == ast::proto_block
+              }
+              ast::proto_bare. {
+                a_proto != ast::proto_bare
+              }
+            }
+        }
+
+        ret if (e_proto == ast::proto_iter
+            || a_proto == ast::proto_iter) {
+            if e_proto != a_proto {
+                some(ures_err(terr_mismatch))
+            } else {
+                none
+            }
+        } else if e_proto == a_proto {
+            none
+        } else if variance == invariant {
+            if e_proto != a_proto {
+                some(ures_err(terr_mismatch))
+            } else {
+                fail
+            }
+        } else if variance == covariant {
+            if gt(e_proto, a_proto) {
+                some(ures_err(terr_mismatch))
+            } else {
+                none
+            }
+        } else if variance == contravariant {
+            if gt(a_proto, e_proto) {
+                some(ures_err(terr_mismatch))
+            } else {
+                none
+            }
+        } else {
+            fail
+        }
+    }
     fn unify_fn(cx: @ctxt, e_proto: ast::proto, a_proto: ast::proto,
                 expected: t, actual: t, expected_inputs: [arg],
                 expected_output: t, actual_inputs: [arg], actual_output: t,
@@ -2025,7 +2075,12 @@ mod unify {
                 _expected_constrs: [@constr], actual_constrs: [@constr],
                 variance: variance) ->
        result {
-        if e_proto != a_proto { ret ures_err(terr_mismatch); }
+
+        alt unify_fn_proto(e_proto, a_proto, variance) {
+          some(err) { ret err; }
+          none. { /* fall through */ }
+        }
+
         if actual_cf != ast::noreturn && actual_cf != expected_cf {
             /* even though typestate checking is mostly
                responsible for checking control flow annotations,
diff --git a/src/test/run-pass/fn-coerce-field.rs b/src/test/run-pass/fn-coerce-field.rs
new file mode 100644
index 00000000000..759ab37585d
--- /dev/null
+++ b/src/test/run-pass/fn-coerce-field.rs
@@ -0,0 +1,7 @@
+type r = {
+    field: fn@()
+};
+
+fn main() {
+    let i: r = {field: fn#() { }};
+}
\ No newline at end of file