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, /* Mapping from an AST type node to the region that `&` resolves to. */ - ast_type_to_inferred_region: hashmap + ast_type_to_inferred_region: hashmap, + /* Mapping from a call site (or `bind` site) to its containing block. */ + call_site_to_block: hashmap }; type ctxt = { @@ -237,6 +239,16 @@ fn resolve_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt) { 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);