From 8136b92ee8e47fc460e64eb7ab65bc59f33efb71 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 14 Oct 2011 17:34:41 -0700 Subject: [PATCH] Give subtype relationships to function types --- src/comp/middle/ty.rs | 59 +++++++++++++++++++++++++++- src/test/run-pass/fn-coerce-field.rs | 7 ++++ 2 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/fn-coerce-field.rs 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 { + 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