about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorMichael Sullivan <sully@msully.net>2011-06-28 16:11:41 -0700
committerMichael Sullivan <sully@msully.net>2011-07-26 12:30:14 -0700
commitac948b4ccd485f12019f0b1d11359990725dfab5 (patch)
treed186caf92fdc31a3db3725ec7acb805c4767396c /src/comp
parent8c8fa79312e4c357bd234df5112ceba75ef0dd34 (diff)
downloadrust-ac948b4ccd485f12019f0b1d11359990725dfab5.tar.gz
rust-ac948b4ccd485f12019f0b1d11359990725dfab5.zip
Resolve and typecheck alias-environment-capturing blocks.
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/metadata/tydecode.rs5
-rw-r--r--src/comp/metadata/tyencode.rs1
-rw-r--r--src/comp/middle/resolve.rs18
-rw-r--r--src/comp/middle/ty.rs1
-rw-r--r--src/comp/middle/typeck.rs116
5 files changed, 107 insertions, 34 deletions
diff --git a/src/comp/metadata/tydecode.rs b/src/comp/metadata/tydecode.rs
index 98c4b0438c8..f08fd5b8f3f 100644
--- a/src/comp/metadata/tydecode.rs
+++ b/src/comp/metadata/tydecode.rs
@@ -250,6 +250,11 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
             ret ty::mk_fn(st.tcx, ast::proto_iter, func.args, func.ty,
                           func.cf, func.cs);
         }
+        case ('B') {
+            auto func = parse_ty_fn(st, sd);
+            ret ty::mk_fn(st.tcx, ast::proto_block, func.args, func.ty,
+                          func.cf, func.cs);
+        }
         case ('N') {
             auto abi;
             alt (next(st) as char) {
diff --git a/src/comp/metadata/tyencode.rs b/src/comp/metadata/tyencode.rs
index e89480182ef..2935e244c4f 100644
--- a/src/comp/metadata/tyencode.rs
+++ b/src/comp/metadata/tyencode.rs
@@ -200,6 +200,7 @@ fn enc_proto(&ioivec::writer w, proto proto) {
     alt (proto) {
         case (proto_iter) { w.write_char('W'); }
         case (proto_fn) { w.write_char('F'); }
+        case (proto_block) { w.write_char('B'); }
     }
 }
 
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index 14dcb923d50..46b15688898 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -49,7 +49,7 @@ export def_map;
 tag scope {
     scope_crate;
     scope_item(@ast::item);
-    scope_fn(ast::fn_decl, ast::ty_param[]);
+    scope_fn(ast::fn_decl, ast::proto, ast::ty_param[]);
     scope_native_item(@ast::native_item);
     scope_loop(@ast::local); // there's only 1 decl per loop.
     scope_block(ast::blk);
@@ -360,7 +360,7 @@ fn visit_fn_with_scope(&@env e, &ast::_fn f, &ast::ty_param[] tp, &span sp,
         resolve_constr(e, id, c, sc, v);
     }
     visit::visit_fn(f, tp, sp, name, id,
-                    cons(scope_fn(f.decl, tp), @sc), v);
+                    cons(scope_fn(f.decl, f.proto, tp), @sc), v);
 }
 
 fn visit_block_with_scope(&ast::blk b, &scopes sc, &vt[scopes] v) {
@@ -381,7 +381,7 @@ fn visit_expr_with_scope(&@ast::expr x, &scopes sc, &vt[scopes] v) {
         v.visit_block(blk, new_sc, v);
       }
       ast::expr_fn(?f) {
-        visit::visit_expr(x, cons(scope_fn(f.decl, ~[]), @sc), v);
+        visit::visit_expr(x, cons(scope_fn(f.decl, f.proto, ~[]), @sc), v);
       }
       _ { visit::visit_expr(x, sc, v); }
     };
@@ -536,7 +536,7 @@ fn unresolved_err(&env e, &scopes sc, &span sp, &ident name, &str kind) {
             alt sc {
               cons(?cur, ?rest) {
                 alt cur {
-                  scope_crate | scope_fn(_, _) |
+                  scope_crate | scope_fn(_, _, _) |
                   scope_item(@{node: ast::item_mod(_), _}) {
                     ret cur;
                   }
@@ -602,9 +602,11 @@ fn lookup_in_scope_strict(&env e, scopes sc, &span sp, &ident name,
 
 fn scope_is_fn(&scope sc) -> bool {
     ret alt (sc) {
-            scope_fn(_, _) | scope_native_item(_) { true }
-            _ { false }
-        };
+        scope_fn(_, ast::proto_iter, _) |
+            scope_fn(_, ast::proto_fn, _) |
+            scope_native_item(_) { true }
+        _ { false }
+    };
 }
 
 fn def_is_local(&def d) -> bool {
@@ -663,7 +665,7 @@ fn lookup_in_scope(&env e, scopes sc, &span sp, &ident name, namespace ns) ->
                     }
                 }
             }
-            case (scope_fn(?decl, ?ty_params)) {
+            case (scope_fn(?decl, _, ?ty_params)) {
                 ret lookup_in_fn(name, decl, ty_params, ns);
             }
             case (scope_loop(?local)) {
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index f0594bd36b3..6c29b204da9 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -889,6 +889,7 @@ fn type_is_structural(&ctxt cx, &t ty) -> bool {
 fn type_is_copyable(&ctxt cx, &t ty) -> bool {
     ret alt (struct(cx, ty)) {
         case (ty_res(_, _, _)) { false }
+        case (ty_fn(proto_block, _, _, _, _)) { false }
         case (_) { true }
     };
 }
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index f72762a588a..a205ebf18cb 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -65,10 +65,13 @@ type crate_ctxt = rec(mutable obj_info[] obj_infos, ty::ctxt tcx);
 type fn_ctxt =
     rec(ty::t ret_ty,
         ast::purity purity,
+        // var_bindings, locals, local_names, and next_var_id are shared
+        // with any nested functions that capture the environment
+        // (and with any functions whose environment is being captured).
         @ty::unify::var_bindings var_bindings,
         hashmap[ast::node_id, int] locals,
         hashmap[ast::node_id, ast::ident] local_names,
-        mutable int next_var_id,
+        @mutable int next_var_id,
         mutable ast::node_id[] fixups,
         @crate_ctxt ccx);
 
@@ -237,6 +240,18 @@ fn structure_of(&@fn_ctxt fcx, &span sp, ty::t typ) -> ty::sty {
     ret ty::struct(fcx.ccx.tcx, structurally_resolved_type(fcx, sp, typ));
 }
 
+// Returns the one-level-deep structure of the given type or none if it
+// is not known yet.
+fn structure_of_maybe(&@fn_ctxt fcx, &span sp, ty::t typ)
+    -> option::t[ty::sty] {
+    auto r =
+        ty::unify::resolve_type_structure(fcx.ccx.tcx, fcx.var_bindings, typ);
+    ret alt (r) {
+      case (fix_ok(?typ_s)) { some(ty::struct(fcx.ccx.tcx, typ_s)) }
+      case (fix_err(_)) { none }
+    }
+}
+
 fn type_is_integral(&@fn_ctxt fcx, &span sp, ty::t typ) -> bool {
     auto typ_s = structurally_resolved_type(fcx, sp, typ);
     ret ty::type_is_integral(fcx.ccx.tcx, typ_s);
@@ -470,6 +485,15 @@ mod write {
     }
 }
 
+// Determine the proto for a fn type given the proto for its associated
+// code. This is needed because fn and lambda have fn type while iter
+// has iter type and block has block type. This may end up changing.
+fn proto_to_ty_proto(&ast::proto proto) -> ast::proto {
+    ret alt (proto) {
+        ast::proto_iter | ast::proto_block { proto }
+        _ { ast::proto_fn }
+    };
+}
 
 // Item collection - a pair of bootstrap passes:
 //
@@ -511,8 +535,8 @@ mod collect {
             out_constrs += ~[ty::ast_constr_to_constr(cx.tcx, constr)];
         }
         auto t_fn =
-            ty::mk_fn(cx.tcx, proto, input_tys, output_ty, decl.cf,
-                      out_constrs);
+            ty::mk_fn(cx.tcx, proto_to_ty_proto(proto), input_tys,
+                      output_ty, decl.cf, out_constrs);
         auto ty_param_count = ivec::len[ast::ty_param](ty_params);
         auto tpt = rec(count=ty_param_count, ty=t_fn);
         alt (def_id) {
@@ -590,9 +614,9 @@ mod collect {
         for (@ast::constr constr in m.node.meth.decl.constraints) {
             out_constrs += ~[ty::ast_constr_to_constr(cx.tcx, constr)];
         }
-        ret rec(proto=m.node.meth.proto, ident=m.node.ident,
-                inputs=inputs, output=output, cf=m.node.meth.decl.cf,
-                constrs=out_constrs);
+        ret rec(proto=proto_to_ty_proto(m.node.meth.proto),
+                ident=m.node.ident, inputs=inputs, output=output,
+                cf=m.node.meth.decl.cf, constrs=out_constrs);
     }
     fn ty_of_obj(@ctxt cx, &ast::ident id, &ast::_obj ob,
                  &ast::ty_param[] ty_params) -> ty::ty_param_count_and_ty {
@@ -872,7 +896,7 @@ mod unify {
     }
 }
 
-tag autoderef_kind { AUTODEREF_OK; NO_AUTODEREF; }
+tag autoderef_kind { AUTODEREF_OK; NO_AUTODEREF; AUTODEREF_BLOCK_COERCE; }
 
 // FIXME This is almost a duplicate of ty::type_autoderef, with structure_of
 // instead of ty::struct.
@@ -917,6 +941,29 @@ fn count_boxes(&@fn_ctxt fcx, &span sp, &ty::t t) -> uint {
     fail;
 }
 
+fn do_fn_block_coerce(&@fn_ctxt fcx, &span sp,
+                      &ty::t actual, &ty::t expected) -> ty::t {
+    // fns can be silently coerced to blocks when being used as
+    // function call or bind arguments, but not the reverse.
+    // If our actual type is a fn and our expected type is a block,
+    // build up a new expected type that is identical to the old one
+    // except for its proto. If we don't know the expected or actual
+    // types, that's fine, but we can't do the coercion.
+    ret alt (structure_of_maybe(fcx, sp, actual)) {
+      some(ty::ty_fn(ast::proto_fn, ?args, ?ret_ty, ?cf, ?constrs)) {
+        alt (structure_of_maybe(fcx, sp, expected)) {
+          some(ty::ty_fn(ast::proto_block, _, _, _, _)) {
+            ty::mk_fn(fcx.ccx.tcx,
+                      ast::proto_block, args, ret_ty, cf, constrs)
+          }
+          _ { actual }
+        }
+      }
+      _ { actual }
+    }
+}
+
+
 fn resolve_type_vars_if_possible(&@fn_ctxt fcx, ty::t typ) -> ty::t {
     alt (ty::unify::fixup_vars(fcx.ccx.tcx, fcx.var_bindings, typ)) {
         case (fix_ok(?new_type)) { ret new_type; }
@@ -951,6 +998,8 @@ mod demand {
             expected_1 = do_autoderef(fcx, sp, expected_1);
             actual_1 = do_autoderef(fcx, sp, actual_1);
             implicit_boxes = count_boxes(fcx, sp, actual);
+        } else if (adk == AUTODEREF_BLOCK_COERCE) {
+            actual_1 = do_fn_block_coerce(fcx, sp, actual, expected);
         }
         let ty::t[mutable] ty_param_substs = ~[mutable];
         let int[] ty_param_subst_var_ids = ~[];
@@ -1175,11 +1224,12 @@ type gather_result =
     rec(@ty::unify::var_bindings var_bindings,
         hashmap[ast::node_id, int] locals,
         hashmap[ast::node_id, ast::ident] local_names,
-        int next_var_id);
+        @mutable int next_var_id);
 
 // Used only as a helper for check_fn.
 fn gather_locals(&@crate_ctxt ccx, &ast::_fn f,
-                 &ast::node_id id) -> gather_result {
+                 &ast::node_id id, &option::t[@fn_ctxt] old_fcx)
+    -> gather_result {
     fn next_var_id(@mutable int nvi) -> int {
         auto rv = *nvi;
         *nvi += 1;
@@ -1201,10 +1251,22 @@ fn gather_locals(&@crate_ctxt ccx, &ast::_fn f,
             }
         }
     }
-    auto vb = ty::unify::mk_var_bindings();
-    auto locals = new_int_hash[int]();
-    auto local_names = new_int_hash[ast::ident]();
-    auto nvi = @mutable 0;
+
+    auto vb; auto locals; auto local_names; auto nvi;
+    alt (old_fcx) {
+        none {
+            vb = ty::unify::mk_var_bindings();
+            locals = new_int_hash[int]();
+            local_names = new_int_hash[ast::ident]();
+            nvi = @mutable 0;
+        }
+        some(?fcx) {
+            vb = fcx.var_bindings;
+            locals = fcx.locals;
+            local_names = fcx.local_names;
+            nvi = fcx.next_var_id;
+        }
+    }
 
     // Add object fields, if any.
     auto obj_fields = ~[];
@@ -1288,7 +1350,7 @@ fn gather_locals(&@crate_ctxt ccx, &ast::_fn f,
     ret rec(var_bindings=vb,
             locals=locals,
             local_names=local_names,
-            next_var_id=*nvi);
+            next_var_id=nvi);
 }
 
 // AST fragment checking
@@ -1555,8 +1617,9 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
             alt (a_opt) {
                 case (some(?a)) {
                     check_expr(fcx, a);
-                    demand::simple(fcx, a.span, arg_tys.(i).ty,
-                                   expr_ty(fcx.ccx.tcx, a));
+                    demand::full(fcx, a.span, arg_tys.(i).ty,
+                                 expr_ty(fcx.ccx.tcx, a), ~[],
+                                 AUTODEREF_BLOCK_COERCE);
                 }
                 case (none) {
                     check_ty_vars = true;
@@ -2013,7 +2076,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
                 collect::ty_of_fn_decl(cx, convert, ty_of_arg, f.decl,
                                        f.proto, ~[], none).ty;
             write::ty_only_fixup(fcx, id, fty);
-            check_fn(fcx.ccx, f, id);
+            check_fn(fcx.ccx, f, id, some(fcx));
         }
         case (ast::expr_block(?b)) {
             check_block(fcx, b);
@@ -2487,8 +2550,8 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
 }
 
 fn next_ty_var_id(@fn_ctxt fcx) -> int {
-    auto id = fcx.next_var_id;
-    fcx.next_var_id += 1;
+    auto id = *fcx.next_var_id;
+    *fcx.next_var_id = fcx.next_var_id + 1;
     ret id;
 }
 
@@ -2586,16 +2649,17 @@ fn check_const(&@crate_ctxt ccx, &span sp, &@ast::expr e, &ast::node_id id) {
              var_bindings=ty::unify::mk_var_bindings(),
              locals=new_int_hash[int](),
              local_names=new_int_hash[ast::ident](),
-             mutable next_var_id=0,
+             next_var_id=@mutable 0,
              mutable fixups=fixups,
              ccx=ccx);
     check_expr(fcx, e);
 }
 
-fn check_fn(&@crate_ctxt ccx, &ast::_fn f, &ast::node_id id) {
+fn check_fn(&@crate_ctxt ccx, &ast::_fn f, &ast::node_id id,
+            &option::t[@fn_ctxt] old_fcx) {
     auto decl = f.decl;
     auto body = f.body;
-    auto gather_result = gather_locals(ccx, f, id);
+    auto gather_result = gather_locals(ccx, f, id, old_fcx);
     let ast::node_id[] fixups = ~[];
     let @fn_ctxt fcx =
         @rec(ret_ty=ast_ty_to_ty_crate(ccx, decl.output),
@@ -2603,7 +2667,7 @@ fn check_fn(&@crate_ctxt ccx, &ast::_fn f, &ast::node_id id) {
              var_bindings=gather_result.var_bindings,
              locals=gather_result.locals,
              local_names=gather_result.local_names,
-             mutable next_var_id=gather_result.next_var_id,
+             next_var_id=gather_result.next_var_id,
              mutable fixups=fixups,
              ccx=ccx);
 
@@ -2636,7 +2700,7 @@ fn check_fn(&@crate_ctxt ccx, &ast::_fn f, &ast::node_id id) {
 }
 
 fn check_method(&@crate_ctxt ccx, &@ast::method method) {
-    check_fn(ccx, method.node.meth, method.node.id);
+    check_fn(ccx, method.node.meth, method.node.id, none);
 }
 
 fn check_item(@crate_ctxt ccx, &@ast::item it) {
@@ -2645,10 +2709,10 @@ fn check_item(@crate_ctxt ccx, &@ast::item it) {
             check_const(ccx, it.span, e, it.id);
         }
         case (ast::item_fn(?f, _)) {
-            check_fn(ccx, f, it.id);
+            check_fn(ccx, f, it.id, none);
         }
         case (ast::item_res(?f, ?dtor_id, _, _)) {
-            check_fn(ccx, f, dtor_id);
+            check_fn(ccx, f, dtor_id, none);
         }
         case (ast::item_obj(?ob, _, _)) {
             // We're entering an object, so gather up the info we need.