rustc: Replace region parameters in function return values

This commit is contained in:
Patrick Walton 2012-03-21 15:22:12 -07:00
parent 324f57a180
commit c8ab0c1b3b

View File

@ -16,6 +16,7 @@ import util::ppaux::ty_to_str;
import std::smallintmap; import std::smallintmap;
import std::map::{hashmap, int_hash}; import std::map::{hashmap, int_hash};
import std::serialization::{serialize_uint, deserialize_uint}; import std::serialization::{serialize_uint, deserialize_uint};
import std::ufind;
import syntax::print::pprust::*; import syntax::print::pprust::*;
export check_crate; export check_crate;
@ -1554,6 +1555,33 @@ fn universally_quantify_regions(tcx: ty::ctxt, ty: ty::t) -> ty::t {
} }
} }
// Replaces region parameter types in the given type with the appropriate
// bindings.
fn replace_region_params(tcx: ty::ctxt,
sp: span,
rb: @ty::unify::region_bindings,
ty: ty::t)
-> ty::t {
if ty::type_has_rptrs(ty) {
ty::fold_ty(tcx, ty::fm_rptr({ |r|
alt r {
ty::re_param(n) {
if n < ufind::set_count(rb.sets) {
smallintmap::get(rb.regions, ufind::find(rb.sets, n))
} else {
tcx.sess.span_err(sp, "unresolved region");
r
}
}
_ { r }
}
}), ty)
} else {
ty
}
}
fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path, fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path,
subpats: [@ast::pat], expected: ty::t) { subpats: [@ast::pat], expected: ty::t) {
// Typecheck the path. // Typecheck the path.
@ -2277,40 +2305,38 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
// A generic function for checking call expressions // A generic function for checking call expressions
fn check_call(fcx: @fn_ctxt, sp: span, id: ast::node_id, f: @ast::expr, fn check_call(fcx: @fn_ctxt, sp: span, id: ast::node_id, f: @ast::expr,
args: [@ast::expr]) args: [@ast::expr])
-> bool { -> check_call_or_bind_result {
let args_opt_0: [option<@ast::expr>] = []; let args_opt_0: [option<@ast::expr>] = [];
for arg: @ast::expr in args { for arg: @ast::expr in args {
args_opt_0 += [some::<@ast::expr>(arg)]; args_opt_0 += [some::<@ast::expr>(arg)];
} }
let mut bot = check_expr(fcx, f); let bot = check_expr(fcx, f);
// Call the generic checker. // Call the generic checker.
let ccobr = check_call_or_bind(fcx, sp, id, expr_ty(fcx.ccx.tcx, f), let ccobr = check_call_or_bind(fcx, sp, id, expr_ty(fcx.ccx.tcx, f),
args_opt_0); args_opt_0);
bot |= ccobr.bot; ret { bot: bot | ccobr.bot with ccobr };
// TODO: Munge return type.
ret bot;
} }
// A generic function for doing all of the checking for call expressions // A generic function for doing all of the checking for call expressions
fn check_call_full(fcx: @fn_ctxt, sp: span, id: ast::node_id, fn check_call_full(fcx: @fn_ctxt, sp: span, id: ast::node_id,
f: @ast::expr, args: [@ast::expr]) -> bool { f: @ast::expr, args: [@ast::expr]) -> bool {
let bot = check_call(fcx, sp, id, f, args); let ccobr = check_call(fcx, sp, id, f, args);
let mut bot = ccobr.bot;
/* need to restrict oper to being an explicit expr_path if we're /* need to restrict oper to being an explicit expr_path if we're
inside a pure function */ inside a pure function */
require_pure_call(fcx.ccx, fcx.purity, f, sp); require_pure_call(fcx.ccx, fcx.purity, f, sp);
// Pull the return type out of the type of the function. // Pull the return type out of the type of the function.
let fty = ty::expr_ty(fcx.ccx.tcx, f); let fty = ty::expr_ty(fcx.ccx.tcx, f);
let rt_1 = alt structure_of(fcx, sp, fty) { let mut rt_1 = alt structure_of(fcx, sp, fty) {
ty::ty_fn(f) { ty::ty_fn(f) {
bot |= f.ret_style == ast::noreturn; bot |= f.ret_style == ast::noreturn;
f.output f.output
} }
_ { fcx.ccx.tcx.sess.span_fatal(sp, "calling non-function"); } _ { fcx.ccx.tcx.sess.span_fatal(sp, "calling non-function"); }
}; };
rt_1 = replace_region_params(fcx.ccx.tcx, f.span, ccobr.rb, rt_1);
write_ty(fcx.ccx.tcx, id, rt_1); write_ty(fcx.ccx.tcx, id, rt_1);
ret bot; ret bot;
} }