diff options
| author | Brian Anderson <banderson@mozilla.com> | 2011-10-14 17:34:41 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2011-10-20 18:23:48 -0700 |
| commit | 8136b92ee8e47fc460e64eb7ab65bc59f33efb71 (patch) | |
| tree | 825ddf213ee65f9a7804e0b868b6b49866a9f88d | |
| parent | ed985b61d5c1e35b10a135ec8872aec2fbf66531 (diff) | |
| download | rust-8136b92ee8e47fc460e64eb7ab65bc59f33efb71.tar.gz rust-8136b92ee8e47fc460e64eb7ab65bc59f33efb71.zip | |
Give subtype relationships to function types
| -rw-r--r-- | src/comp/middle/ty.rs | 59 | ||||
| -rw-r--r-- | src/test/run-pass/fn-coerce-field.rs | 7 |
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 |
