summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2012-03-13 17:31:04 -0700
committerPatrick Walton <pcwalton@mimiga.net>2012-03-13 17:31:34 -0700
commitfc50abe6c54d892e4cb7fbb93f959ba14ed68810 (patch)
tree9fea5902bc920d9e701e5b07de4504aa78f99b47 /src/rustc
parentaeb445b2ea25f9629df1d5d8fbd2906a92c8e719 (diff)
downloadrust-fc50abe6c54d892e4cb7fbb93f959ba14ed68810.tar.gz
rust-fc50abe6c54d892e4cb7fbb93f959ba14ed68810.zip
rustc: Instantiate "caller" regions when calling functions
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/middle/region.rs17
-rw-r--r--src/rustc/middle/typeck.rs59
2 files changed, 64 insertions, 12 deletions
diff --git a/src/rustc/middle/region.rs b/src/rustc/middle/region.rs
index 949155119d4..55b5842db25 100644
--- a/src/rustc/middle/region.rs
+++ b/src/rustc/middle/region.rs
@@ -38,7 +38,9 @@ type region_map = {
     /* Mapping from a region name to its function. */
     region_name_to_fn: hashmap<ast::def_id,ast::node_id>,
     /* Mapping from an AST type node to the region that `&` resolves to. */
-    ast_type_to_inferred_region: hashmap<ast::node_id,ty::region>
+    ast_type_to_inferred_region: hashmap<ast::node_id,ty::region>,
+    /* Mapping from a call site (or `bind` site) to its containing block. */
+    call_site_to_block: hashmap<ast::node_id,ast::node_id>
 };
 
 type ctxt = {
@@ -237,6 +239,16 @@ fn resolve_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
                           in_alt: false with cx};
             visit::visit_expr(expr, new_cx, visitor);
         }
+        ast::expr_call(_, _, _) | ast::expr_bind(_, _) {
+            // Record the block that this call appears in.
+            alt cx.parent {
+                pa_block(blk_id) {
+                    cx.region_map.call_site_to_block.insert(expr.id, blk_id);
+                }
+                _ { cx.sess.span_bug(expr.span, "expr outside of block?!"); }
+            }
+            visit::visit_expr(expr, cx, visitor);
+        }
         _ { visit::visit_expr(expr, cx, visitor); }
     }
 }
@@ -263,7 +275,8 @@ fn resolve_crate(sess: session, def_map: resolve::def_map, crate: @ast::crate)
                                   local_blocks: map::new_int_hash(),
                                   region_name_to_fn: new_def_hash(),
                                   ast_type_to_inferred_region:
-                                    map::new_int_hash()},
+                                    map::new_int_hash(),
+                                  call_site_to_block: map::new_int_hash()},
                     mut bindings: @list::nil,
                     mut queued_locals: [],
                     parent: pa_crate,
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index dbd0baf5dfa..c129d5cadc3 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -1970,8 +1970,42 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
 
     // A generic function to factor out common logic from call and bind
     // expressions.
-    fn check_call_or_bind(fcx: @fn_ctxt, sp: span, fty: ty::t,
-                          args: [option<@ast::expr>]) -> bool {
+    fn check_call_or_bind(fcx: @fn_ctxt, sp: span, id: ast::node_id,
+                          fty: ty::t, args: [option<@ast::expr>]) -> bool {
+        // Replaces "caller" regions in the arguments with the local region.
+        fn instantiate_caller_regions(fcx: @fn_ctxt, id: ast::node_id,
+                                      args: [ty::arg]) -> [ty::arg] {
+            let site_to_block = fcx.ccx.tcx.region_map.call_site_to_block;
+            let block_id = alt site_to_block.find(id) {
+                none {
+                    // This can happen for those expressions that are
+                    // synthesized during typechecking; e.g. during
+                    // check_constraints().
+                    ret args;
+                }
+                some(block_id) { block_id }
+            };
+
+            let region = ty::re_block(block_id);
+            ret vec::map(args) {|arg|
+                if ty::type_has_rptrs(arg.ty) {
+                    let ty = ty::fold_ty(fcx.ccx.tcx, ty::fm_rptr({|r|
+                        alt r {
+                            ty::re_caller(_) {
+                                // FIXME: We should not recurse into nested
+                                // function types here.
+                                region
+                            }
+                            _ { r }
+                        }
+                    }), arg.ty);
+                    {ty: ty with arg}
+                } else {
+                    arg
+                }
+            };
+        }
+
         let sty = structure_of(fcx, sp, fty);
         // Grab the argument types
         let arg_tys = alt sty {
@@ -2009,6 +2043,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
             arg_tys = vec::from_elem(supplied_arg_count, dummy);
         }
 
+        arg_tys = instantiate_caller_regions(fcx, id, arg_tys);
+
         // Check the arguments.
         // We do this in a pretty awful way: first we typecheck any arguments
         // that are not anonymous functions, then we typecheck the anonymous
@@ -2049,7 +2085,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
     }
 
     // A generic function for checking call expressions
-    fn check_call(fcx: @fn_ctxt, sp: span, f: @ast::expr, args: [@ast::expr])
+    fn check_call(fcx: @fn_ctxt, sp: span, id: ast::node_id, f: @ast::expr,
+                  args: [@ast::expr])
         -> bool {
         let args_opt_0: [option<@ast::expr>] = [];
         for arg: @ast::expr in args {
@@ -2058,13 +2095,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
 
         let bot = check_expr(fcx, f);
         // Call the generic checker.
-        bot | check_call_or_bind(fcx, sp, expr_ty(fcx.ccx.tcx, f), args_opt_0)
+        bot | check_call_or_bind(fcx, sp, id, expr_ty(fcx.ccx.tcx, f),
+                                 args_opt_0)
     }
 
     // A generic function for doing all of the checking for call expressions
-    fn check_call_full(fcx: @fn_ctxt, sp: span, f: @ast::expr,
-                       args: [@ast::expr], id: ast::node_id) -> bool {
-        let bot = check_call(fcx, sp, f, args);
+    fn check_call_full(fcx: @fn_ctxt, sp: span, id: ast::node_id,
+                       f: @ast::expr, args: [@ast::expr]) -> bool {
+        let bot = check_call(fcx, sp, id, f, args);
         /* here we're kind of hosed, as f can be any expr
         need to restrict it to being an explicit expr_path if we're
         inside a pure function, and need an environment mapping from
@@ -2145,7 +2183,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
         alt lookup_method(fcx, op_ex, callee_id, opname, self_t, []) {
           some(origin) {
             let method_ty = ty::node_id_to_type(fcx.ccx.tcx, callee_id);
-            check_call_or_bind(fcx, op_ex.span, method_ty, args);
+            check_call_or_bind(fcx, op_ex.span, op_ex.id, method_ty, args);
             fcx.ccx.method_map.insert(op_ex.id, origin);
             some(ty::ty_fn_ret(method_ty))
           }
@@ -2472,7 +2510,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
       ast::expr_bind(f, args) {
         // Call the generic checker.
         bot = check_expr(fcx, f);
-        bot |= check_call_or_bind(fcx, expr.span, expr_ty(tcx, f), args);
+        bot |= check_call_or_bind(fcx, expr.span, expr.id, expr_ty(tcx, f),
+                                  args);
 
         // Pull the argument and return types out.
         let proto, arg_tys, rt, cf, constrs;
@@ -2518,7 +2557,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
         write_ty(tcx, id, ft);
       }
       ast::expr_call(f, args, _) {
-        bot = check_call_full(fcx, expr.span, f, args, expr.id);
+        bot = check_call_full(fcx, expr.span, expr.id, f, args);
       }
       ast::expr_cast(e, t) {
         bot = check_expr(fcx, e);