From e9ac7489b5032b4a922a0df1dd611471260b31ef Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 28 Aug 2012 19:31:56 -0700 Subject: [PATCH] Refactor representation of borrowing so that it is tracked by fn_ctxt and not infer --- src/libstd/test.rs | 1 + src/rustc/middle/typeck/check.rs | 412 +++++++++++--------- src/rustc/middle/typeck/check/alt.rs | 29 +- src/rustc/middle/typeck/check/demand.rs | 12 +- src/rustc/middle/typeck/check/method.rs | 88 ++--- src/rustc/middle/typeck/check/regionck.rs | 6 +- src/rustc/middle/typeck/check/vtable.rs | 31 +- src/rustc/middle/typeck/check/writeback.rs | 102 +++-- src/rustc/middle/typeck/infer.rs | 93 ++--- src/rustc/middle/typeck/infer/assignment.rs | 226 +++++------ 10 files changed, 514 insertions(+), 486 deletions(-) diff --git a/src/libstd/test.rs b/src/libstd/test.rs index 2ebf8827154..2c055e497dd 100644 --- a/src/libstd/test.rs +++ b/src/libstd/test.rs @@ -106,6 +106,7 @@ fn run_tests_console(opts: test_opts, tests: ~[test_desc]) -> bool { fn callback(event: testevent, st: console_test_state) { + debug!("callback(event=%?)", event); match event { te_filtered(filtered_tests) => { st.total = vec::len(filtered_tests); diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index bc9762a43e5..f6e2e4ac6f5 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -75,6 +75,7 @@ bound_self_region}; import syntax::ast::ty_i; import typeck::infer::{resolve_type, force_tvar}; +import result::{Result, Ok, Err}; import std::map::{str_hash, uint_hash}; @@ -85,6 +86,24 @@ explicit_self: ast::self_ty }; +/// Fields that are part of a `fn_ctxt` which are inherited by +/// closures defined within the function. For example: +/// +/// fn foo() { +/// do bar() { ... } +/// } +/// +/// Here, the function `foo()` and the closure passed to +/// `bar()` will each have their own `fn_ctxt`, but they will +/// share the inherited fields. +struct inherited { + infcx: infer::infer_ctxt; + locals: hashmap; + node_types: hashmap; + node_type_substs: hashmap; + borrowings: hashmap; +} + struct fn_ctxt { // var_bindings, locals and next_var_id are shared // with any nested functions that capture the environment @@ -94,8 +113,6 @@ struct fn_ctxt { // Used by loop bodies that return from the outer function indirect_ret_ty: Option; purity: ast::purity; - infcx: infer::infer_ctxt; - locals: hashmap; // Sometimes we generate region pointers where the precise region // to use is not known. For example, an expression like `&x.f` @@ -114,12 +131,21 @@ struct fn_ctxt { in_scope_regions: isr_alist; - node_types: hashmap; - node_type_substs: hashmap; + inh: @inherited; ccx: @crate_ctxt; } +fn blank_inherited(ccx: @crate_ctxt) -> @inherited { + @inherited { + infcx: infer::new_infer_ctxt(ccx.tcx), + locals: int_hash(), + node_types: map::int_hash(), + node_type_substs: map::int_hash(), + borrowings: map::int_hash() + } +} + // Used by check_const and check_enum_variants fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t, region_bnd: ast::node_id) -> @fn_ctxt { @@ -130,12 +156,9 @@ fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t, ret_ty: rty, indirect_ret_ty: None, purity: ast::pure_fn, - infcx: infer::new_infer_ctxt(ccx.tcx), - locals: int_hash(), mut region_lb: region_bnd, in_scope_regions: @nil, - node_types: map::int_hash(), - node_type_substs: map::int_hash(), + inh: blank_inherited(ccx), ccx: ccx } } @@ -220,23 +243,16 @@ fn check_fn(ccx: @crate_ctxt, // Create the function context. This is either derived from scratch or, // in the case of function expressions, based on the outer context. let fcx: @fn_ctxt = { - let {infcx, locals, purity, node_types, node_type_substs} = - match old_fcx { - None => { - {infcx: infer::new_infer_ctxt(tcx), - locals: int_hash(), - purity: fn_ty.purity, - node_types: map::int_hash(), - node_type_substs: map::int_hash()} - } - Some(fcx) => { - {infcx: fcx.infcx, - locals: fcx.locals, - purity: ty::determine_inherited_purity(fcx.purity, fn_ty.purity, - fn_ty.proto), - node_types: fcx.node_types, - node_type_substs: fcx.node_type_substs} - } + let (purity, inherited) = match old_fcx { + None => { + (fn_ty.purity, + blank_inherited(ccx)) + } + Some(fcx) => { + (ty::determine_inherited_purity(fcx.purity, fn_ty.purity, + fn_ty.proto), + fcx.inh) + } }; let indirect_ret_ty = if indirect_ret { @@ -252,12 +268,9 @@ fn check_fn(ccx: @crate_ctxt, ret_ty: ret_ty, indirect_ret_ty: indirect_ret_ty, purity: purity, - infcx: infcx, - locals: locals, mut region_lb: body.node.id, in_scope_regions: isr, - node_types: node_types, - node_type_substs: node_type_substs, + inh: inherited, ccx: ccx } }; @@ -316,14 +329,14 @@ fn gather_locals(fcx: @fn_ctxt, let assign = fn@(span: span, nid: ast::node_id, ty_opt: Option) { - let var_id = fcx.infcx.next_ty_var_id(); - fcx.locals.insert(nid, var_id); + let var_id = fcx.infcx().next_ty_var_id(); + fcx.inh.locals.insert(nid, var_id); match ty_opt { - None => {/* nothing to do */ } - Some(typ) => { - infer::mk_eqty(fcx.infcx, false, span, - ty::mk_var(tcx, var_id), typ); - } + None => {/* nothing to do */ } + Some(typ) => { + infer::mk_eqty(fcx.infcx(), false, span, + ty::mk_var(tcx, var_id), typ); + } } }; @@ -332,7 +345,7 @@ fn gather_locals(fcx: @fn_ctxt, assign(info.explicit_self.span, info.self_id, Some(info.self_ty)); debug!("self is assigned to %s", - fcx.locals.get(info.self_id).to_str()); + fcx.inh.locals.get(info.self_id).to_str()); } // Add formal parameters. @@ -340,7 +353,7 @@ fn gather_locals(fcx: @fn_ctxt, assign(input.ty.span, input.id, Some(arg_ty)); debug!("Argument %s is assigned to %s", tcx.sess.str_of(input.ident), - fcx.locals.get(input.id).to_str()); + fcx.inh.locals.get(input.id).to_str()); } // Add explicitly-declared locals. @@ -353,7 +366,7 @@ fn gather_locals(fcx: @fn_ctxt, assign(local.span, local.node.id, o_ty); debug!("Local variable %s is assigned to %s", pat_to_str(local.node.pat, tcx.sess.intr()), - fcx.locals.get(local.node.id).to_str()); + fcx.inh.locals.get(local.node.id).to_str()); visit::visit_local(local, e, v); }; @@ -365,7 +378,7 @@ fn gather_locals(fcx: @fn_ctxt, assign(p.span, p.id, None); debug!("Pattern binding %s is assigned to %s", tcx.sess.str_of(path.idents[0]), - fcx.locals.get(p.id).to_str()); + fcx.inh.locals.get(p.id).to_str()); } _ => {} } @@ -540,6 +553,7 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { } impl @fn_ctxt: ast_conv { + fn infcx() -> infer::infer_ctxt { self.inh.infcx } fn tcx() -> ty::ctxt { self.ccx.tcx } fn ccx() -> @crate_ctxt { self.ccx } @@ -548,13 +562,13 @@ fn get_item_ty(id: ast::def_id) -> ty::ty_param_bounds_and_ty { } fn ty_infer(_span: span) -> ty::t { - self.infcx.next_ty_var() + self.infcx().next_ty_var() } } impl @fn_ctxt: region_scope { fn anon_region(span: span) -> Result { - result::Ok(self.infcx.next_region_var_nb(span)) + result::Ok(self.infcx().next_region_var_nb(span)) } fn named_region(span: span, id: ast::ident) -> Result { do empty_rscope.named_region(span, id).chain_err |_e| { @@ -580,11 +594,11 @@ fn block_region() -> ty::region { fn write_ty(node_id: ast::node_id, ty: ty::t) { debug!("write_ty(%d, %s) in fcx %s", node_id, ty_to_str(self.tcx(), ty), self.tag()); - self.node_types.insert(node_id, ty); + self.inh.node_types.insert(node_id, ty); } fn write_substs(node_id: ast::node_id, +substs: ty::substs) { if !ty::substs_is_noop(&substs) { - self.node_type_substs.insert(node_id, substs); + self.inh.node_type_substs.insert(node_id, substs); } } fn write_ty_substs(node_id: ast::node_id, ty: ty::t, @@ -605,44 +619,44 @@ fn to_ty(ast_t: @ast::ty) -> ty::t { } fn expr_ty(ex: @ast::expr) -> ty::t { - match self.node_types.find(ex.id) { - Some(t) => t, - None => { - self.tcx().sess.bug( - fmt!("no type for expr %d (%s) in fcx %s", - ex.id, expr_to_str(ex, self.ccx.tcx.sess.intr()), - self.tag())); - } + match self.inh.node_types.find(ex.id) { + Some(t) => t, + None => { + self.tcx().sess.bug( + fmt!("no type for expr %d (%s) in fcx %s", + ex.id, expr_to_str(ex, self.ccx.tcx.sess.intr()), + self.tag())); + } } } fn node_ty(id: ast::node_id) -> ty::t { - match self.node_types.find(id) { - Some(t) => t, - None => { - self.tcx().sess.bug( - fmt!("no type for node %d: %s in fcx %s", - id, ast_map::node_id_to_str( - self.tcx().items, id, - self.tcx().sess.parse_sess.interner), - self.tag())); - } + match self.inh.node_types.find(id) { + Some(t) => t, + None => { + self.tcx().sess.bug( + fmt!("no type for node %d: %s in fcx %s", + id, ast_map::node_id_to_str( + self.tcx().items, id, + self.tcx().sess.parse_sess.interner), + self.tag())); + } } } fn node_ty_substs(id: ast::node_id) -> ty::substs { - match self.node_type_substs.find(id) { - Some(ts) => ts, - None => { - self.tcx().sess.bug( - fmt!("no type substs for node %d: %s in fcx %s", - id, ast_map::node_id_to_str( - self.tcx().items, id, - self.tcx().sess.parse_sess.interner), - self.tag())); - } + match self.inh.node_type_substs.find(id) { + Some(ts) => ts, + None => { + self.tcx().sess.bug( + fmt!("no type substs for node %d: %s in fcx %s", + id, ast_map::node_id_to_str( + self.tcx().items, id, + self.tcx().sess.parse_sess.interner), + self.tag())); + } } } fn opt_node_ty_substs(id: ast::node_id) -> Option { - self.node_type_substs.find(id) + self.inh.node_type_substs.find(id) } fn report_mismatched_types(sp: span, e: ty::t, a: ty::t, @@ -650,42 +664,52 @@ fn report_mismatched_types(sp: span, e: ty::t, a: ty::t, self.ccx.tcx.sess.span_err( sp, fmt!("mismatched types: expected `%s` but found `%s` (%s)", - self.infcx.ty_to_str(e), - self.infcx.ty_to_str(a), + self.infcx().ty_to_str(e), + self.infcx().ty_to_str(a), ty::type_err_to_str(self.ccx.tcx, err))); } fn mk_subty(a_is_expected: bool, span: span, sub: ty::t, sup: ty::t) -> Result<(), ty::type_err> { - infer::mk_subty(self.infcx, a_is_expected, span, sub, sup) + infer::mk_subty(self.infcx(), a_is_expected, span, sub, sup) } fn can_mk_subty(sub: ty::t, sup: ty::t) -> Result<(), ty::type_err> { - infer::can_mk_subty(self.infcx, sub, sup) + infer::can_mk_subty(self.infcx(), sub, sup) } fn mk_assignty(expr: @ast::expr, borrow_lb: ast::node_id, sub: ty::t, sup: ty::t) -> Result<(), ty::type_err> { - let anmnt = &{expr_id: expr.id, span: expr.span, - borrow_lb: borrow_lb}; - infer::mk_assignty(self.infcx, anmnt, sub, sup) + match infer::mk_assignty(self.infcx(), false, expr.span, sub, sup) { + Ok(None) => result::Ok(()), + Err(e) => result::Err(e), + Ok(Some(borrow)) => { + match self.mk_subr(true, expr.span, + ty::re_scope(borrow_lb), borrow.region) { + Err(e) => Err(e), + Ok(()) => { + debug!("inserting borrowing of expr %?: %?", + expr.id, borrow); + self.inh.borrowings.insert(expr.id, borrow); + Ok(()) + } + } + } + } } - fn can_mk_assignty(expr: @ast::expr, borrow_lb: ast::node_id, - sub: ty::t, sup: ty::t) -> Result<(), ty::type_err> { - let anmnt = &{expr_id: expr.id, span: expr.span, - borrow_lb: borrow_lb}; - infer::can_mk_assignty(self.infcx, anmnt, sub, sup) + fn can_mk_assignty(sub: ty::t, sup: ty::t) -> Result<(), ty::type_err> { + infer::can_mk_assignty(self.infcx(), sub, sup) } fn mk_eqty(a_is_expected: bool, span: span, sub: ty::t, sup: ty::t) -> Result<(), ty::type_err> { - infer::mk_eqty(self.infcx, a_is_expected, span, sub, sup) + infer::mk_eqty(self.infcx(), a_is_expected, span, sub, sup) } fn mk_subr(a_is_expected: bool, span: span, sub: ty::region, sup: ty::region) -> Result<(), ty::type_err> { - infer::mk_subr(self.infcx, a_is_expected, span, sub, sup) + infer::mk_subr(self.infcx(), a_is_expected, span, sub, sup) } fn require_unsafe(sp: span, op: ~str) { @@ -712,8 +736,7 @@ fn region_var_if_parameterized(rp: Option, -> Option { rp.map( - |_rp| self.infcx.next_region_var_with_lb(span, - lower_bound)) + |_rp| self.infcx().next_region_var_with_lb(span, lower_bound)) } } @@ -767,7 +790,7 @@ fn check_lit(fcx: @fn_ctxt, lit: @ast::lit) -> ty::t { ast::lit_int_unsuffixed(_) => { // An unsuffixed integer literal could have any integral type, // so we create an integral type variable for it. - ty::mk_var_integral(tcx, fcx.infcx.next_ty_var_integral_id()) + ty::mk_var_integral(tcx, fcx.infcx().next_ty_var_integral_id()) } ast::lit_float(_, t) => ty::mk_mach_float(tcx, t), ast::lit_nil => ty::mk_nil(tcx), @@ -836,11 +859,11 @@ fn impl_self_ty(fcx: @fn_ctxt, }; let self_r = if region_param.is_some() || require_rp { - Some(fcx.infcx.next_region_var(expr.span, expr.id)) + Some(fcx.infcx().next_region_var(expr.span, expr.id)) } else { None }; - let tps = fcx.infcx.next_ty_vars(n_tps); + let tps = fcx.infcx().next_ty_vars(n_tps); let substs = {self_r: self_r, self_ty: None, tps: tps}; let substd_ty = ty::subst(tcx, &substs, raw_ty); @@ -884,7 +907,7 @@ fn check_call_inner( // type with fresh region variables. debug!("check_call_inner: before universal quant., in_fty=%s", - fcx.infcx.ty_to_str(in_fty)); + fcx.infcx().ty_to_str(in_fty)); // This is subtle: we expect `fty` to be a function type, which // normally introduce a level of binding. In this case, we want to @@ -895,8 +918,8 @@ fn check_call_inner( ty::ty_fn(ref fn_ty) => { replace_bound_regions_in_fn_ty( fcx.ccx.tcx, @nil, None, fn_ty, - |_br| fcx.infcx.next_region_var(sp, - call_expr_id)).fn_ty + |_br| fcx.infcx().next_region_var(sp, + call_expr_id)).fn_ty } _ => { // I would like to make this span_err, but it's @@ -905,13 +928,13 @@ fn check_call_inner( fcx.ccx.tcx.sess.span_fatal(sp, ~"mismatched types: \ expected function or foreign \ function but found " - + fcx.infcx.ty_to_str(in_fty)); + + fcx.infcx().ty_to_str(in_fty)); } }; let fty = ty::mk_fn(fcx.tcx(), fn_ty); debug!("check_call_inner: after universal quant., fty=%s", - fcx.infcx.ty_to_str(fty)); + fcx.infcx().ty_to_str(fty)); let supplied_arg_count = vec::len(args); @@ -935,7 +958,7 @@ fn check_call_inner( } else { ~"s were" })); - fcx.infcx.next_ty_vars(supplied_arg_count) + fcx.infcx().next_ty_vars(supplied_arg_count) }; // Check the arguments. @@ -1035,18 +1058,18 @@ fn check_then_else(fcx: @fn_ctxt, thn: ast::blk, _sp: span) -> bool { let (if_t, if_bot) = match elsopt { - Some(els) => { - let if_t = fcx.infcx.next_ty_var(); - let thn_bot = check_block(fcx, thn); - let thn_t = fcx.node_ty(thn.node.id); - demand::suptype(fcx, thn.span, if_t, thn_t); - let els_bot = check_expr_with(fcx, els, if_t); - (if_t, thn_bot & els_bot) - } - None => { - check_block_no_value(fcx, thn); - (ty::mk_nil(fcx.ccx.tcx), false) - } + Some(els) => { + let if_t = fcx.infcx().next_ty_var(); + let thn_bot = check_block(fcx, thn); + let thn_t = fcx.node_ty(thn.node.id); + demand::suptype(fcx, thn.span, if_t, thn_t); + let els_bot = check_expr_with(fcx, els, if_t); + (if_t, thn_bot & els_bot) + } + None => { + check_block_no_value(fcx, thn); + (ty::mk_nil(fcx.ccx.tcx), false) + } }; fcx.write_ty(id, if_t); return if_bot; @@ -1092,7 +1115,7 @@ fn check_binop(fcx: @fn_ctxt, expr: @ast::expr, } (_, _) if ty::is_binopable(tcx, lhs_t, op) => { - let tvar = fcx.infcx.next_ty_var(); + let tvar = fcx.infcx().next_ty_var(); demand::suptype(fcx, expr.span, tvar, lhs_t); let rhs_bot = check_expr_with(fcx, rhs, tvar); let rhs_t = match op { @@ -1139,7 +1162,7 @@ fn check_user_binop(fcx: @fn_ctxt, ex: @ast::expr, tcx.sess.span_err( ex.span, ~"binary operation " + ast_util::binop_to_str(op) + ~" cannot be applied to type `" + - fcx.infcx.ty_to_str(lhs_resolved_t) + + fcx.infcx().ty_to_str(lhs_resolved_t) + ~"`"); // If the or operator is used it might be that the user forgot to @@ -1165,7 +1188,7 @@ fn check_user_unop(fcx: @fn_ctxt, op_str: ~str, mname: ~str, _ => { fcx.ccx.tcx.sess.span_err( ex.span, fmt!("cannot apply unary operator `%s` to type `%s`", - op_str, fcx.infcx.ty_to_str(rhs_t))); + op_str, fcx.infcx().ty_to_str(rhs_t))); rhs_t } } @@ -1179,13 +1202,13 @@ fn unpack_expected(fcx: @fn_ctxt, expected: Option, unpack: fn(ty::sty) -> Option) -> Option { match expected { - Some(t) => { - match resolve_type(fcx.infcx, t, force_tvar) { - result::Ok(t) => unpack(ty::get(t).struct), - _ => None + Some(t) => { + match resolve_type(fcx.infcx(), t, force_tvar) { + Ok(t) => unpack(ty::get(t).struct), + _ => None + } } - } - _ => None + _ => None } } @@ -1249,7 +1272,8 @@ fn check_expr_fn(fcx: @fn_ctxt, let fty = ty::mk_fn(tcx, fn_ty); debug!("check_expr_fn_with_unifier %s fty=%s", - expr_to_str(expr, tcx.sess.intr()), fcx.infcx.ty_to_str(fty)); + expr_to_str(expr, tcx.sess.intr()), + fcx.infcx().ty_to_str(fty)); fcx.write_ty(expr.id, fty); @@ -1326,29 +1350,32 @@ fn check_field(fcx: @fn_ctxt, expr: @ast::expr, is_callee: bool, expr.id, field, expr_t, tps, is_self_ref); match lkup.method() { - Some(entry) => { - fcx.ccx.method_map.insert(expr.id, entry); - - // If we have resolved to a method but this is not in - // a callee position, error - if !is_callee { - tcx.sess.span_err( - expr.span, - ~"attempted to take value of method \ - (try writing an anonymous function)"); + Some(entry) => { + fcx.ccx.method_map.insert(expr.id, entry); + + // If we have resolved to a method but this is not in + // a callee position, error + if !is_callee { + tcx.sess.span_err( + expr.span, + ~"attempted to take value of method \ + (try writing an anonymous function)"); + } + } + None => { + let t_err = + fcx.infcx().resolve_type_vars_if_possible(expr_t); + let msg = + fmt!( + "attempted access of field `%s` on type `%s`, \ + but no public field or method with that name \ + was found", + tcx.sess.str_of(field), + fcx.infcx().ty_to_str(t_err)); + tcx.sess.span_err(expr.span, msg); + // NB: Add bogus type to allow typechecking to continue + fcx.write_ty(expr.id, fcx.infcx().next_ty_var()); } - } - None => { - let t_err = fcx.infcx.resolve_type_vars_if_possible(expr_t); - let msg = fmt!("attempted access of field `%s` on type `%s`, \ - but no public field or method with that name \ - was found", - tcx.sess.str_of(field), - fcx.infcx.ty_to_str(t_err)); - tcx.sess.span_err(expr.span, msg); - // NB: Adding a bogus type to allow typechecking to continue - fcx.write_ty(expr.id, fcx.infcx.next_ty_var()); - } } } return bot; @@ -1367,7 +1394,7 @@ fn check_field(fcx: @fn_ctxt, expr: @ast::expr, is_callee: bool, } ast::expr_vec(args, mutbl) => { let tt = ast_expr_vstore_to_vstore(fcx, ev, vec::len(args), vst); - let t: ty::t = fcx.infcx.next_ty_var(); + let t: ty::t = fcx.infcx().next_ty_var(); for args.each |e| { bot |= check_expr_with(fcx, e, t); } ty::mk_evec(tcx, {ty: t, mutbl: mutbl}, tt) } @@ -1375,7 +1402,7 @@ fn check_field(fcx: @fn_ctxt, expr: @ast::expr, is_callee: bool, let count = ty::eval_repeat_count(tcx, count_expr, expr.span); fcx.write_ty(count_expr.id, ty::mk_uint(tcx)); let tt = ast_expr_vstore_to_vstore(fcx, ev, count, vst); - let t: ty::t = fcx.infcx.next_ty_var(); + let t: ty::t = fcx.infcx().next_ty_var(); bot |= check_expr_with(fcx, element, t); ty::mk_evec(tcx, {ty: t, mutbl: mutbl}, tt) } @@ -1404,7 +1431,7 @@ fn check_field(fcx: @fn_ctxt, expr: @ast::expr, is_callee: bool, ast::expr_binary(ast::gt, lhs, rhs) | ast::expr_binary(ast::ge, lhs, rhs) => { let tcx = fcx.ccx.tcx; - let tvar = fcx.infcx.next_ty_var(); + let tvar = fcx.infcx().next_ty_var(); bot |= check_expr_with(fcx, lhs, tvar); bot |= check_expr_with(fcx, rhs, tvar); fcx.write_ty(id, ty::mk_bool(tcx)); @@ -1472,7 +1499,7 @@ fn check_field(fcx: @fn_ctxt, expr: @ast::expr, is_callee: bool, tcx.sess.span_err( expr.span, fmt!("type %s cannot be dereferenced", - fcx.infcx.ty_to_str(oprnd_t))); + fcx.infcx().ty_to_str(oprnd_t))); } } } @@ -1516,7 +1543,7 @@ fn check_field(fcx: @fn_ctxt, expr: @ast::expr, is_callee: bool, // borrowck is charged with guaranteeing that the value whose // address was taken can actually be made to live as long as // it needs to live. - let region = fcx.infcx.next_region_var(expr.span, expr.id); + let region = fcx.infcx().next_region_var(expr.span, expr.id); let tm = { ty: fcx.expr_ty(oprnd), mutbl: mutbl }; let oprnd_t = ty::mk_rptr(tcx, region, tm); @@ -1631,7 +1658,7 @@ fn check_field(fcx: @fn_ctxt, expr: @ast::expr, is_callee: bool, tcx.sess.span_fatal( expr.span, fmt!("a `loop` function's last argument \ should return `bool`, not `%s`", - fcx.infcx.ty_to_str(fty.output))); + fcx.infcx().ty_to_str(fty.output))); } } ty::mk_fn(tcx, {output: ty::mk_nil(tcx) with fty}) @@ -1713,8 +1740,8 @@ fn check_field(fcx: @fn_ctxt, expr: @ast::expr, is_callee: bool, let t_1 = fcx.to_ty(t); let t_e = fcx.expr_ty(e); - debug!("t_1=%s", fcx.infcx.ty_to_str(t_1)); - debug!("t_e=%s", fcx.infcx.ty_to_str(t_e)); + debug!("t_1=%s", fcx.infcx().ty_to_str(t_1)); + debug!("t_e=%s", fcx.infcx().ty_to_str(t_e)); match ty::get(t_1).struct { // This will be looked up later on @@ -1723,12 +1750,12 @@ fn check_field(fcx: @fn_ctxt, expr: @ast::expr, is_callee: bool, _ => { if ty::type_is_nil(t_e) { tcx.sess.span_err(expr.span, ~"cast from nil: " + - fcx.infcx.ty_to_str(t_e) + ~" as " + - fcx.infcx.ty_to_str(t_1)); + fcx.infcx().ty_to_str(t_e) + ~" as " + + fcx.infcx().ty_to_str(t_1)); } else if ty::type_is_nil(t_1) { tcx.sess.span_err(expr.span, ~"cast to nil: " + - fcx.infcx.ty_to_str(t_e) + ~" as " + - fcx.infcx.ty_to_str(t_1)); + fcx.infcx().ty_to_str(t_e) + ~" as " + + fcx.infcx().ty_to_str(t_1)); } let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1); @@ -1742,15 +1769,15 @@ fn check_field(fcx: @fn_ctxt, expr: @ast::expr, is_callee: bool, */ tcx.sess.span_err(expr.span, ~"non-scalar cast: " + - fcx.infcx.ty_to_str(t_e) + ~" as " + - fcx.infcx.ty_to_str(t_1)); + fcx.infcx().ty_to_str(t_e) + ~" as " + + fcx.infcx().ty_to_str(t_1)); } } } fcx.write_ty(id, t_1); } ast::expr_vec(args, mutbl) => { - let t: ty::t = fcx.infcx.next_ty_var(); + let t: ty::t = fcx.infcx().next_ty_var(); for args.each |e| { bot |= check_expr_with(fcx, e, t); } let typ = ty::mk_evec(tcx, {ty: t, mutbl: mutbl}, ty::vstore_fixed(args.len())); @@ -1759,7 +1786,7 @@ fn check_field(fcx: @fn_ctxt, expr: @ast::expr, is_callee: bool, ast::expr_repeat(element, count_expr, mutbl) => { let count = ty::eval_repeat_count(tcx, count_expr, expr.span); fcx.write_ty(count_expr.id, ty::mk_uint(tcx)); - let t: ty::t = fcx.infcx.next_ty_var(); + let t: ty::t = fcx.infcx().next_ty_var(); bot |= check_expr_with(fcx, element, t); let t = ty::mk_evec(tcx, {ty: t, mutbl: mutbl}, ty::vstore_fixed(count)); @@ -1890,7 +1917,7 @@ fn get_node(f: spanned) -> field { f.node } fcx.region_var_if_parameterized(region_parameterized, expr.span, ty::re_scope(expr.id)); - let type_parameters = fcx.infcx.next_ty_vars(type_parameter_count); + let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); let substitutions = { self_r: self_region, self_ty: None, @@ -1995,7 +2022,7 @@ fn get_node(f: spanned) -> field { f.node } _ => { tcx.sess.span_fatal( expr.span, ~"cannot index a value of type `" + - fcx.infcx.ty_to_str(base_t) + ~"`"); + fcx.infcx().ty_to_str(base_t) + ~"`"); } } } @@ -2022,7 +2049,7 @@ fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t) { if !type_is_integral(fcx, sp, t) { fcx.ccx.tcx.sess.span_err(sp, ~"mismatched types: expected \ integral type but found `" - + fcx.infcx.ty_to_str(t) + ~"`"); + + fcx.infcx().ty_to_str(t) + ~"`"); } } @@ -2035,7 +2062,7 @@ fn check_decl_initializer(fcx: @fn_ctxt, nid: ast::node_id, fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool { let mut bot = false; - let t = ty::mk_var(fcx.ccx.tcx, fcx.locals.get(local.node.id)); + let t = ty::mk_var(fcx.ccx.tcx, fcx.inh.locals.get(local.node.id)); fcx.write_ty(local.node.id, t); match local.node.init { Some(init) => { @@ -2282,12 +2309,13 @@ fn self_ref(fcx: @fn_ctxt, id: ast::node_id) -> bool { } fn lookup_local(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> tv_vid { - match fcx.locals.find(id) { - Some(x) => x, - _ => { - fcx.ccx.tcx.sess.span_fatal(sp, - ~"internal error looking up a local var") - } + match fcx.inh.locals.find(id) { + Some(x) => x, + _ => { + fcx.ccx.tcx.sess.span_fatal( + sp, + ~"internal error looking up a local var") + } } } @@ -2302,7 +2330,7 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) -> match defn { ast::def_arg(nid, _) | ast::def_local(nid, _) | ast::def_self(nid) | ast::def_binding(nid, _) => { - assert (fcx.locals.contains_key(nid)); + assert (fcx.inh.locals.contains_key(nid)); let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid)); return no_params(typ); } @@ -2392,19 +2420,19 @@ fn instantiate_path(fcx: @fn_ctxt, // determine values for type parameters, using the values given by // the user (if any) and otherwise using fresh type variables let tps = if ty_substs_len == 0u { - fcx.infcx.next_ty_vars(ty_param_count) + fcx.infcx().next_ty_vars(ty_param_count) } else if ty_param_count == 0u { fcx.ccx.tcx.sess.span_err (span, ~"this item does not take type parameters"); - fcx.infcx.next_ty_vars(ty_param_count) + fcx.infcx().next_ty_vars(ty_param_count) } else if ty_substs_len > ty_param_count { fcx.ccx.tcx.sess.span_err (span, ~"too many type parameters provided for this item"); - fcx.infcx.next_ty_vars(ty_param_count) + fcx.infcx().next_ty_vars(ty_param_count) } else if ty_substs_len < ty_param_count { fcx.ccx.tcx.sess.span_err (span, ~"not enough type parameters provided for this item"); - fcx.infcx.next_ty_vars(ty_param_count) + fcx.infcx().next_ty_vars(ty_param_count) } else { pth.types.map(|aty| fcx.to_ty(aty)) }; @@ -2416,12 +2444,12 @@ fn instantiate_path(fcx: @fn_ctxt, // Resolves `typ` by a single level if `typ` is a type variable. If no // resolution is possible, then an error is reported. fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t { - match infer::resolve_type(fcx.infcx, tp, force_tvar) { - result::Ok(t_s) if !ty::type_is_var(t_s) => return t_s, - _ => { - fcx.ccx.tcx.sess.span_fatal - (sp, ~"the type of this value must be known in this context"); - } + match infer::resolve_type(fcx.infcx(), tp, force_tvar) { + Ok(t_s) if !ty::type_is_var(t_s) => return t_s, + _ => { + fcx.ccx.tcx.sess.span_fatal + (sp, ~"the type of this value must be known in this context"); + } } } @@ -2448,20 +2476,20 @@ fn type_is_c_like_enum(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool { fn ast_expr_vstore_to_vstore(fcx: @fn_ctxt, e: @ast::expr, n: uint, v: ast::vstore) -> ty::vstore { match v { - ast::vstore_fixed(None) => ty::vstore_fixed(n), - ast::vstore_fixed(Some(u)) => { - if n != u { - let s = fmt!("fixed-size sequence mismatch: %u vs. %u",u, n); - fcx.ccx.tcx.sess.span_err(e.span,s); + ast::vstore_fixed(None) => ty::vstore_fixed(n), + ast::vstore_fixed(Some(u)) => { + if n != u { + let s = fmt!("fixed-size sequence mismatch: %u vs. %u",u, n); + fcx.ccx.tcx.sess.span_err(e.span,s); + } + ty::vstore_fixed(u) + } + ast::vstore_uniq => ty::vstore_uniq, + ast::vstore_box => ty::vstore_box, + ast::vstore_slice(_) => { + let r = fcx.infcx().next_region_var(e.span, e.id); + ty::vstore_slice(r) } - ty::vstore_fixed(u) - } - ast::vstore_uniq => ty::vstore_uniq, - ast::vstore_box => ty::vstore_box, - ast::vstore_slice(_) => { - let r = fcx.infcx.next_region_var(e.span, e.id); - ty::vstore_slice(r) - } } } diff --git a/src/rustc/middle/typeck/check/alt.rs b/src/rustc/middle/typeck/check/alt.rs index 764c9d3d297..00562144ef6 100644 --- a/src/rustc/middle/typeck/check/alt.rs +++ b/src/rustc/middle/typeck/check/alt.rs @@ -7,7 +7,7 @@ fn check_alt(fcx: @fn_ctxt, let tcx = fcx.ccx.tcx; let mut bot; - let pattern_ty = fcx.infcx.next_ty_var(); + let pattern_ty = fcx.infcx().next_ty_var(); bot = check_expr_with(fcx, discrim, pattern_ty); let is_lvalue = ty::expr_is_lval(fcx.ccx.method_map, discrim); @@ -30,7 +30,7 @@ fn check_alt(fcx: @fn_ctxt, for arm.pats.each |p| { check_pat(pcx, p, pattern_ty);} } // Now typecheck the blocks. - let mut result_ty = fcx.infcx.next_ty_var(); + let mut result_ty = fcx.infcx().next_ty_var(); let mut arm_non_bot = false; for arms.each |arm| { match arm.guard { @@ -128,7 +128,7 @@ fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path, tcx.sess.span_fatal (pat.span, fmt!("mismatched types: expected enum but found `%s`", - fcx.infcx.ty_to_str(expected))); + fcx.infcx().ty_to_str(expected))); } } } @@ -151,14 +151,15 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { check_expr_with(fcx, begin, expected); check_expr_with(fcx, end, expected); let b_ty = - fcx.infcx.resolve_type_vars_if_possible(fcx.expr_ty(begin)); + fcx.infcx().resolve_type_vars_if_possible(fcx.expr_ty(begin)); let e_ty = - fcx.infcx.resolve_type_vars_if_possible(fcx.expr_ty(end)); + fcx.infcx().resolve_type_vars_if_possible(fcx.expr_ty(end)); debug!("pat_range beginning type: %?", b_ty); debug!("pat_range ending type: %?", e_ty); if !require_same_types( - tcx, Some(fcx.infcx), false, pat.span, b_ty, e_ty, - || ~"mismatched types in range") { + tcx, Some(fcx.infcx()), false, pat.span, b_ty, e_ty, + || ~"mismatched types in range") + { // no-op } else if !ty::type_is_numeric(b_ty) { tcx.sess.span_err(pat.span, ~"non-numeric type used in range"); @@ -180,7 +181,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { // then the type of x is &M T where M is the mutability // and T is the expected type let region_var = - fcx.infcx.next_region_var_with_lb( + fcx.infcx().next_region_var_with_lb( pat.span, pcx.block_region); let mt = {ty: expected, mutbl: mutbl}; let region_ty = ty::mk_rptr(tcx, region_var, mt); @@ -241,7 +242,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { tcx.sess.span_fatal (pat.span, fmt!("mismatched types: expected `%s` but found record", - fcx.infcx.ty_to_str(expected))); + fcx.infcx().ty_to_str(expected))); } }; let f_count = vec::len(fields); @@ -284,7 +285,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { tcx.sess.span_fatal(pat.span, fmt!("mismatched types: expected `%s` \ but found struct", - fcx.infcx.ty_to_str(expected))); + fcx.infcx().ty_to_str(expected))); } } @@ -299,7 +300,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { tcx.sess.span_err(pat.span, fmt!("mismatched types: expected `%s` but \ found `%s`", - fcx.infcx.ty_to_str(expected), + fcx.infcx().ty_to_str(expected), name)); } _ => { @@ -364,7 +365,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { tcx.sess.span_fatal (pat.span, fmt!("mismatched types: expected `%s`, found tuple", - fcx.infcx.ty_to_str(expected))); + fcx.infcx().ty_to_str(expected))); } }; let e_count = vec::len(elts); @@ -392,7 +393,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { tcx.sess.span_fatal( pat.span, ~"mismatched types: expected `" + - fcx.infcx.ty_to_str(expected) + + fcx.infcx().ty_to_str(expected) + ~"` found box"); } } @@ -407,7 +408,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { tcx.sess.span_fatal( pat.span, ~"mismatched types: expected `" + - fcx.infcx.ty_to_str(expected) + + fcx.infcx().ty_to_str(expected) + ~"` found uniq"); } } diff --git a/src/rustc/middle/typeck/check/demand.rs b/src/rustc/middle/typeck/check/demand.rs index 7dc1dc2606b..55272b8c419 100644 --- a/src/rustc/middle/typeck/check/demand.rs +++ b/src/rustc/middle/typeck/check/demand.rs @@ -6,7 +6,7 @@ fn suptype(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t) { // n.b.: order of actual, expected is reversed - match infer::mk_subty(fcx.infcx, false, sp, + match infer::mk_subty(fcx.infcx(), false, sp, actual, expected) { result::Ok(()) => { /* ok */ } result::Err(ref err) => { @@ -18,11 +18,11 @@ fn suptype(fcx: @fn_ctxt, sp: span, fn eqtype(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t) { - match infer::mk_eqty(fcx.infcx, false, sp, actual, expected) { - result::Ok(()) => { /* ok */ } - result::Err(ref err) => { - fcx.report_mismatched_types(sp, expected, actual, err); - } + match infer::mk_eqty(fcx.infcx(), false, sp, actual, expected) { + Ok(()) => { /* ok */ } + Err(ref err) => { + fcx.report_mismatched_types(sp, expected, actual, err); + } } } diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs index c232b8cd94b..fb4d2565c44 100644 --- a/src/rustc/middle/typeck/check/method.rs +++ b/src/rustc/middle/typeck/check/method.rs @@ -108,14 +108,14 @@ struct lookup { fn method() -> Option { debug!("method lookup(m_name=%s, self_ty=%s, %?)", self.fcx.tcx().sess.str_of(self.m_name), - self.fcx.infcx.ty_to_str(self.self_ty), + self.fcx.infcx().ty_to_str(self.self_ty), ty::get(self.self_ty).struct); // Determine if there are any inherent methods we can call. // (An inherent method is one that belongs to no trait, but is // inherent to a class or impl.) let optional_inherent_methods; - match get_base_type_def_id(self.fcx.infcx, + match get_base_type_def_id(self.fcx.infcx(), self.self_expr.span, self.self_ty) { None => { @@ -438,35 +438,27 @@ fn check_type_match(impl_ty: ty::t, // Depending on our argument, we find potential matches by // checking subtypability, type assignability, or reference // subtypability. Collect the matches. - let matches; match mode { - subtyping_mode => { - matches = self.fcx.can_mk_subty(self.self_ty, impl_ty); - } - assignability_mode => { - matches = self.fcx.can_mk_assignty(self.self_expr, - self.borrow_lb, - self.self_ty, - impl_ty); - } - immutable_reference_mode => { - let region = self.fcx.infcx.next_region_var( - self.self_expr.span, - self.self_expr.id); - let tm = { ty: self.self_ty, mutbl: ast::m_imm }; - let ref_ty = ty::mk_rptr(self.tcx(), region, tm); - matches = self.fcx.can_mk_subty(ref_ty, impl_ty); - } - mutable_reference_mode => { - let region = self.fcx.infcx.next_region_var( - self.self_expr.span, - self.self_expr.id); - let tm = { ty: self.self_ty, mutbl: ast::m_mutbl }; - let ref_ty = ty::mk_rptr(self.tcx(), region, tm); - matches = self.fcx.can_mk_subty(ref_ty, impl_ty); - } + subtyping_mode => self.fcx.can_mk_subty(self.self_ty, impl_ty), + assignability_mode => self.fcx.can_mk_assignty(self.self_ty, + impl_ty), + immutable_reference_mode => { + let region = self.fcx.infcx().next_region_var( + self.self_expr.span, + self.self_expr.id); + let tm = { ty: self.self_ty, mutbl: ast::m_imm }; + let ref_ty = ty::mk_rptr(self.tcx(), region, tm); + self.fcx.can_mk_subty(ref_ty, impl_ty) + } + mutable_reference_mode => { + let region = self.fcx.infcx().next_region_var( + self.self_expr.span, + self.self_expr.id); + let tm = { ty: self.self_ty, mutbl: ast::m_mutbl }; + let ref_ty = ty::mk_rptr(self.tcx(), region, tm); + self.fcx.can_mk_subty(ref_ty, impl_ty) + } } - matches } // Returns true if any were added and false otherwise. @@ -530,7 +522,7 @@ fn add_candidates_from_m(inner_ty: ty::t, None => { match m.self_ty { ast::sty_region(_) => - Some(self.fcx.infcx.next_region_var( + Some(self.fcx.infcx().next_region_var( self.self_expr.span, self.self_expr.id)), _ => None @@ -640,7 +632,7 @@ fn write_mty_from_candidate(cand: candidate) -> method_map_entry { debug!("write_mty_from_candidate(n_tps_m=%u, fty=%s, entry=%?)", cand.n_tps_m, - self.fcx.infcx.ty_to_str(cand.fty), + self.fcx.infcx().ty_to_str(cand.fty), cand.entry); match cand.mode { @@ -655,30 +647,18 @@ fn write_mty_from_candidate(cand: candidate) -> method_map_entry { self.tcx().sess.span_bug( self.expr.span, fmt!("%s was assignable to %s but now is not?", - self.fcx.infcx.ty_to_str(cand.self_ty), - self.fcx.infcx.ty_to_str(cand.rcvr_ty))); + self.fcx.infcx().ty_to_str(cand.self_ty), + self.fcx.infcx().ty_to_str(cand.rcvr_ty))); } } } immutable_reference_mode => { // Borrow as an immutable reference. - let region_var = self.fcx.infcx.next_region_var( - self.self_expr.span, - self.self_expr.id); - self.fcx.infcx.borrowings.push({expr_id: self.self_expr.id, - span: self.self_expr.span, - scope: region_var, - mutbl: ast::m_imm}); + self.add_borrow(ast::m_imm); } mutable_reference_mode => { // Borrow as a mutable reference. - let region_var = self.fcx.infcx.next_region_var( - self.self_expr.span, - self.self_expr.id); - self.fcx.infcx.borrowings.push({expr_id: self.self_expr.id, - span: self.self_expr.span, - scope: region_var, - mutbl: ast::m_mutbl}); + self.add_borrow(ast::m_mutbl); } } @@ -688,18 +668,18 @@ fn write_mty_from_candidate(cand: candidate) -> method_map_entry { let n_tps_m = cand.n_tps_m; let m_substs = { if n_tps_supplied == 0u { - self.fcx.infcx.next_ty_vars(n_tps_m) + self.fcx.infcx().next_ty_vars(n_tps_m) } else if n_tps_m == 0u { tcx.sess.span_err( self.expr.span, ~"this method does not take type parameters"); - self.fcx.infcx.next_ty_vars(n_tps_m) + self.fcx.infcx().next_ty_vars(n_tps_m) } else if n_tps_supplied != n_tps_m { tcx.sess.span_err( self.expr.span, ~"incorrect number of type \ parameters given for this method"); - self.fcx.infcx.next_ty_vars(n_tps_m) + self.fcx.infcx().next_ty_vars(n_tps_m) } else { self.supplied_tps } @@ -712,5 +692,13 @@ fn write_mty_from_candidate(cand: candidate) -> method_map_entry { return cand.entry; } + + fn add_borrow(mutbl: ast::mutability) { + let region_var = self.fcx.infcx().next_region_var( + self.self_expr.span, + self.self_expr.id); + self.fcx.inh.borrowings.insert(self.self_expr.id, {region: region_var, + mutbl: mutbl}); + } } diff --git a/src/rustc/middle/typeck/check/regionck.rs b/src/rustc/middle/typeck/check/regionck.rs index ee8c20592b4..01286bff38a 100644 --- a/src/rustc/middle/typeck/check/regionck.rs +++ b/src/rustc/middle/typeck/check/regionck.rs @@ -81,7 +81,7 @@ impl @rcx { /// that `` be bigger than the let and the `*b` expression, so we /// will effectively resolve `` to be the block B. fn resolve_type(unresolved_ty: ty::t) -> fres { - resolve_type(self.fcx.infcx, unresolved_ty, + resolve_type(self.fcx.infcx(), unresolved_ty, resolve_and_force_all_but_regions) } @@ -95,7 +95,7 @@ fn regionck_expr(fcx: @fn_ctxt, e: @ast::expr) { let rcx = rcx_({fcx:fcx, mut errors_reported: 0u}); let v = regionck_visitor(); v.visit_expr(e, @rcx, v); - fcx.infcx.resolve_regions(); + fcx.infcx().resolve_regions(); } fn regionck_fn(fcx: @fn_ctxt, @@ -104,7 +104,7 @@ fn regionck_fn(fcx: @fn_ctxt, let rcx = rcx_({fcx:fcx, mut errors_reported: 0u}); let v = regionck_visitor(); v.visit_block(blk, @rcx, v); - fcx.infcx.resolve_regions(); + fcx.infcx().resolve_regions(); } fn regionck_visitor() -> rvt { diff --git a/src/rustc/middle/typeck/check/vtable.rs b/src/rustc/middle/typeck/check/vtable.rs index afb5701fd5f..b349d502b02 100644 --- a/src/rustc/middle/typeck/check/vtable.rs +++ b/src/rustc/middle/typeck/check/vtable.rs @@ -3,6 +3,7 @@ fixup_err_to_str}; import ast_util::new_def_hash; import syntax::print::pprust; +import result::{Result, Ok, Err}; // vtable resolution looks for places where trait bounds are // subsituted in and figures out which vtable is used. There is some @@ -85,7 +86,7 @@ fn lookup_vtable(fcx: @fn_ctxt, { debug!("lookup_vtable(ty=%s, trait_ty=%s)", - fcx.infcx.ty_to_str(ty), fcx.infcx.ty_to_str(trait_ty)); + fcx.infcx().ty_to_str(ty), fcx.inh.infcx.ty_to_str(trait_ty)); let _i = indenter(); let tcx = fcx.ccx.tcx; @@ -253,8 +254,8 @@ impl self_ty: some_trait { ... } debug!("(checking vtable) @2 relating trait ty %s to \ of_ty %s", - fcx.infcx.ty_to_str(trait_ty), - fcx.infcx.ty_to_str(of_ty)); + fcx.infcx().ty_to_str(trait_ty), + fcx.infcx().ty_to_str(of_ty)); let of_ty = ty::subst(tcx, &substs, of_ty); relate_trait_tys(fcx, expr, trait_ty, of_ty); @@ -347,18 +348,18 @@ fn fixup_ty(fcx: @fn_ctxt, is_early: bool) -> Option { let tcx = fcx.ccx.tcx; - match resolve_type(fcx.infcx, ty, resolve_and_force_all_but_regions) { - result::Ok(new_type) => Some(new_type), - result::Err(e) if !is_early => { - tcx.sess.span_fatal( - expr.span, - fmt!("cannot determine a type \ - for this bounded type parameter: %s", - fixup_err_to_str(e))) - } - result::Err(_) => { - None - } + match resolve_type(fcx.infcx(), ty, resolve_and_force_all_but_regions) { + Ok(new_type) => Some(new_type), + Err(e) if !is_early => { + tcx.sess.span_fatal( + expr.span, + fmt!("cannot determine a type \ + for this bounded type parameter: %s", + fixup_err_to_str(e))) + } + Err(_) => { + None + } } } diff --git a/src/rustc/middle/typeck/check/writeback.rs b/src/rustc/middle/typeck/check/writeback.rs index 6bbd757ac98..dfb807de9ca 100644 --- a/src/rustc/middle/typeck/check/writeback.rs +++ b/src/rustc/middle/typeck/check/writeback.rs @@ -3,30 +3,58 @@ // substitutions. import check::{fn_ctxt, lookup_local}; -import infer::{resolve_type, resolve_all, force_all}; +import infer::{resolve_type, resolve_region, resolve_all, force_all}; export resolve_type_vars_in_fn; export resolve_type_vars_in_expr; +import result::{Result, Ok, Err}; -fn resolve_type_vars_in_type(fcx: @fn_ctxt, sp: span, typ: ty::t) -> - Option { +fn resolve_type_vars_in_type(fcx: @fn_ctxt, sp: span, typ: ty::t) + -> Option +{ if !ty::type_needs_infer(typ) { return Some(typ); } - match resolve_type(fcx.infcx, typ, resolve_all | force_all) { - result::Ok(new_type) => return Some(new_type), - result::Err(e) => { - if !fcx.ccx.tcx.sess.has_errors() { - fcx.ccx.tcx.sess.span_err( - sp, - fmt!("cannot determine a type \ - for this expression: %s", - infer::fixup_err_to_str(e))) + match resolve_type(fcx.infcx(), typ, resolve_all | force_all) { + Ok(new_type) => return Some(new_type), + Err(e) => { + if !fcx.ccx.tcx.sess.has_errors() { + fcx.ccx.tcx.sess.span_err( + sp, + fmt!("cannot determine a type \ + for this expression: %s", + infer::fixup_err_to_str(e))) + } + return None; } - return None; - } } } + fn resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span, id: ast::node_id) - -> Option { + -> Option +{ let fcx = wbcx.fcx, tcx = fcx.ccx.tcx; + + // Resolve any borrowings for the node with id `id` + match fcx.inh.borrowings.find(id) { + None => (), + Some(borrow) => { + match resolve_region(fcx.infcx(), borrow.region, + resolve_all | force_all) { + Err(e) => { + // This should not, I think, happen. + fcx.ccx.tcx.sess.span_err( + sp, fmt!("cannot resolve scope of borrow: %s", + infer::fixup_err_to_str(e))); + } + Ok(r) => { + debug!("Borrowing node %d -> region %?, mutbl %?", + id, r, borrow.mutbl); + fcx.tcx().borrowings.insert(id, {region: r, + mutbl: borrow.mutbl}); + } + } + } + } + + // Resolve the type of the node with id `id` let n_ty = fcx.node_ty(id); match resolve_type_vars_in_type(fcx, sp, n_ty) { None => { @@ -58,8 +86,9 @@ fn resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span, id: ast::node_id) fn maybe_resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span, id: ast::node_id) - -> Option { - if wbcx.fcx.node_types.contains_key(id) { + -> Option +{ + if wbcx.fcx.inh.node_types.contains_key(id) { resolve_type_vars_for_node(wbcx, sp, id) } else { None @@ -118,7 +147,7 @@ fn visit_pat(p: @ast::pat, wbcx: wb_ctxt, v: wb_vt) { resolve_type_vars_for_node(wbcx, p.span, p.id); debug!("Type for pattern binding %s (id %d) resolved to %s", pat_to_str(p, wbcx.fcx.ccx.tcx.sess.intr()), p.id, - wbcx.fcx.infcx.ty_to_str( + wbcx.fcx.infcx().ty_to_str( ty::node_id_to_type(wbcx.fcx.ccx.tcx, p.id))); visit::visit_pat(p, wbcx, v); @@ -127,21 +156,22 @@ fn visit_local(l: @ast::local, wbcx: wb_ctxt, v: wb_vt) { if !wbcx.success { return; } let var_id = lookup_local(wbcx.fcx, l.span, l.node.id); let var_ty = ty::mk_var(wbcx.fcx.tcx(), var_id); - match resolve_type(wbcx.fcx.infcx, var_ty, resolve_all | force_all) { - result::Ok(lty) => { - debug!("Type for local %s (id %d) resolved to %s", - pat_to_str(l.node.pat, wbcx.fcx.ccx.tcx.sess.intr()),l.node.id, - wbcx.fcx.infcx.ty_to_str(lty)); - write_ty_to_tcx(wbcx.fcx.ccx.tcx, l.node.id, lty); - } - result::Err(e) => { - wbcx.fcx.ccx.tcx.sess.span_err( - l.span, - fmt!("cannot determine a type \ - for this local variable: %s", - infer::fixup_err_to_str(e))); - wbcx.success = false; - } + match resolve_type(wbcx.fcx.infcx(), var_ty, resolve_all | force_all) { + Ok(lty) => { + debug!("Type for local %s (id %d) resolved to %s", + pat_to_str(l.node.pat, wbcx.fcx.tcx().sess.intr()), + l.node.id, + wbcx.fcx.infcx().ty_to_str(lty)); + write_ty_to_tcx(wbcx.fcx.ccx.tcx, l.node.id, lty); + } + Err(e) => { + wbcx.fcx.ccx.tcx.sess.span_err( + l.span, + fmt!("cannot determine a type \ + for this local variable: %s", + infer::fixup_err_to_str(e))); + wbcx.success = false; + } } visit::visit_local(l, wbcx, v); } @@ -163,9 +193,6 @@ fn resolve_type_vars_in_expr(fcx: @fn_ctxt, e: @ast::expr) -> bool { let wbcx = {fcx: fcx, mut success: true}; let visit = mk_visitor(); visit.visit_expr(e, wbcx, visit); - if wbcx.success { - infer::resolve_borrowings(fcx.infcx); - } return wbcx.success; } @@ -184,8 +211,5 @@ fn resolve_type_vars_in_fn(fcx: @fn_ctxt, for decl.inputs.each |arg| { resolve_type_vars_for_node(wbcx, arg.ty.span, arg.id); } - if wbcx.success { - infer::resolve_borrowings(fcx.infcx); - } return wbcx.success; } diff --git a/src/rustc/middle/typeck/infer.rs b/src/rustc/middle/typeck/infer.rs index 765dbf81da4..ce52a2f7436 100644 --- a/src/rustc/middle/typeck/infer.rs +++ b/src/rustc/middle/typeck/infer.rs @@ -273,6 +273,7 @@ fn bar() { import unify::{vals_and_bindings, root}; import integral::{int_ty_set, int_ty_set_all}; import combine::{combine_fields, eq_tys}; +import assignment::Assign; import sub::Sub; import lub::Lub; @@ -296,20 +297,13 @@ fn bar() { export root, to_str; export int_ty_set_all; -// Extra information needed to perform an assignment that may borrow. -// The `expr_id` and `span` are the id/span of the expression -// whose type is being assigned, and `borrow_scope` is the region -// scope to use if the value should be borrowed. -type assignment = { - expr_id: ast::node_id, - span: span, - borrow_lb: ast::node_id, -}; - type bound = Option; type bounds = {lb: bound, ub: bound}; -type cres = Result; +type cres = Result; // "combine result" +type ures = cres<()>; // "unify result" +type fres = Result; // "fixup result" +type ares = cres>; // "assignment result" enum infer_ctxt = @{ tcx: ty::ctxt, @@ -329,12 +323,7 @@ enum infer_ctxt = @{ // For keeping track of existing type and region variables. ty_var_counter: @mut uint, ty_var_integral_counter: @mut uint, - region_var_counter: @mut uint, - - borrowings: DVec<{expr_id: ast::node_id, - span: span, - scope: ty::region, - mutbl: ast::mutability}> + region_var_counter: @mut uint }; enum fixup_err { @@ -358,9 +347,6 @@ fn fixup_err_to_str(f: fixup_err) -> ~str { } } -type ures = result::Result<(), ty::type_err>; -type fres = result::Result; - fn new_vals_and_bindings() -> vals_and_bindings { vals_and_bindings { vals: smallintmap::mk(), @@ -375,19 +361,14 @@ fn new_infer_ctxt(tcx: ty::ctxt) -> infer_ctxt { region_vars: RegionVarBindings(tcx), ty_var_counter: @mut 0u, ty_var_integral_counter: @mut 0u, - region_var_counter: @mut 0u, - borrowings: DVec()})} - -fn mk_sub(cx: infer_ctxt, a_is_expected: bool, span: span) -> Sub { - Sub(combine_fields {infcx: cx, a_is_expected: a_is_expected, span: span}) -} + region_var_counter: @mut 0u})} fn mk_subty(cx: infer_ctxt, a_is_expected: bool, span: span, a: ty::t, b: ty::t) -> ures { debug!("mk_subty(%s <: %s)", a.to_str(cx), b.to_str(cx)); do indent { do cx.commit { - mk_sub(cx, a_is_expected, span).tys(a, b) + cx.sub(a_is_expected, span).tys(a, b) } }.to_ures() } @@ -396,7 +377,7 @@ fn can_mk_subty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures { debug!("can_mk_subty(%s <: %s)", a.to_str(cx), b.to_str(cx)); do indent { do cx.probe { - mk_sub(cx, true, ast_util::dummy_sp()).tys(a, b) + cx.sub(true, ast_util::dummy_sp()).tys(a, b) } }.to_ures() } @@ -406,7 +387,7 @@ fn mk_subr(cx: infer_ctxt, a_is_expected: bool, span: span, debug!("mk_subr(%s <: %s)", a.to_str(cx), b.to_str(cx)); do indent { do cx.commit { - mk_sub(cx, a_is_expected, span).regions(a, b) + cx.sub(a_is_expected, span).regions(a, b) } }.to_ures() } @@ -416,37 +397,30 @@ fn mk_eqty(cx: infer_ctxt, a_is_expected: bool, span: span, debug!("mk_eqty(%s <: %s)", a.to_str(cx), b.to_str(cx)); do indent { do cx.commit { - let suber = mk_sub(cx, a_is_expected, span); + let suber = cx.sub(a_is_expected, span); eq_tys(&suber, a, b) } }.to_ures() } -fn mk_assignty(cx: infer_ctxt, anmnt: &assignment, - a: ty::t, b: ty::t) -> ures { - debug!("mk_assignty(%? / %s <: %s)", - anmnt, a.to_str(cx), b.to_str(cx)); +fn mk_assignty(cx: infer_ctxt, a_is_expected: bool, span: span, + a: ty::t, b: ty::t) -> ares { + debug!("mk_assignty(%s -> %s)", a.to_str(cx), b.to_str(cx)); do indent { do cx.commit { - cx.assign_tys(anmnt, a, b) + Assign(cx.combine_fields(a_is_expected, span)).tys(a, b) } - }.to_ures() + } } -fn can_mk_assignty(cx: infer_ctxt, anmnt: &assignment, - a: ty::t, b: ty::t) -> ures { - debug!("can_mk_assignty(%? / %s <: %s)", - anmnt, a.to_str(cx), b.to_str(cx)); - - // FIXME(#2593)---this will not unroll any entries we make in the - // borrowings table. But this is OK for the moment because this - // is only used in method lookup, and there must be exactly one - // match or an error is reported. Still, it should be fixed. (#2593) - // NDM OUTDATED - - indent(|| cx.probe(|| - cx.assign_tys(anmnt, a, b) - ) ).to_ures() +fn can_mk_assignty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures { + debug!("can_mk_assignty(%s -> %s)", a.to_str(cx), b.to_str(cx)); + do indent { + do cx.probe { + let span = ast_util::dummy_sp(); + Assign(cx.combine_fields(true, span)).tys(a, b) + } + }.to_ures() } // See comment on the type `resolve_state` below @@ -460,6 +434,7 @@ fn resolve_region(cx: infer_ctxt, r: ty::region, modes: uint) resolver(cx, modes).resolve_region_chk(r) } +/* fn resolve_borrowings(cx: infer_ctxt) { for cx.borrowings.each |item| { match resolve_region(cx, item.scope, resolve_all|force_all) { @@ -479,6 +454,7 @@ fn resolve_borrowings(cx: infer_ctxt) { } } } +*/ trait then { fn then(f: fn() -> Result) @@ -533,10 +509,20 @@ struct Snapshot { ty_var_bindings_len: uint; ty_var_integral_bindings_len: uint; region_vars_snapshot: uint; - borrowings_len: uint; } impl infer_ctxt { + fn combine_fields(a_is_expected: bool, + span: span) -> combine_fields { + combine_fields {infcx: self, + a_is_expected: a_is_expected, + span: span} + } + + fn sub(a_is_expected: bool, span: span) -> Sub { + Sub(self.combine_fields(a_is_expected, span)) + } + fn in_snapshot() -> bool { self.region_vars.in_snapshot() } @@ -549,8 +535,6 @@ fn start_snapshot() -> Snapshot { self.ty_var_integral_bindings.bindings.len(), region_vars_snapshot: self.region_vars.start_snapshot(), - borrowings_len: - self.borrowings.len() } } @@ -564,9 +548,6 @@ fn rollback_to(snapshot: &Snapshot) { self.region_vars.rollback_to( snapshot.region_vars_snapshot); - while self.borrowings.len() != snapshot.borrowings_len { - self.borrowings.pop(); - } } /// Execute `f` and commit the bindings if successful diff --git a/src/rustc/middle/typeck/infer/assignment.rs b/src/rustc/middle/typeck/infer/assignment.rs index b27cac57262..620929f4bd9 100644 --- a/src/rustc/middle/typeck/infer/assignment.rs +++ b/src/rustc/middle/typeck/infer/assignment.rs @@ -49,70 +49,74 @@ // needed. import to_str::to_str; +import combine::combine_fields; -impl infer_ctxt { - fn assign_tys(anmnt: &assignment, a: ty::t, b: ty::t) -> ures { +fn to_ares(+c: cres) -> ares { + match c { + Ok(_) => Ok(None), + Err(e) => Err(e) + } +} - fn select(fst: Option, snd: Option) -> Option { - match fst { - Some(t) => Some(t), - None => match snd { - Some(t) => Some(t), - None => None - } - } - } +// Note: Assign is not actually a combiner, in that it does not +// conform to the same interface, though it performs a similar +// function. +enum Assign = combine_fields; - debug!("assign_tys(anmnt=%?, %s -> %s)", - anmnt, a.to_str(self), b.to_str(self)); +impl Assign { + fn tys(a: ty::t, b: ty::t) -> ares { + debug!("Assign.tys(%s -> %s)", + a.to_str(self.infcx), + b.to_str(self.infcx)); let _r = indenter(); match (ty::get(a).struct, ty::get(b).struct) { - (ty::ty_bot, _) => { - uok() - } - - (ty::ty_var(a_id), ty::ty_var(b_id)) => { - let nde_a = self.get(&self.ty_var_bindings, a_id); - let nde_b = self.get(&self.ty_var_bindings, b_id); - let a_bounds = nde_a.possible_types; - let b_bounds = nde_b.possible_types; - - let a_bnd = select(a_bounds.ub, a_bounds.lb); - let b_bnd = select(b_bounds.lb, b_bounds.ub); - self.assign_tys_or_sub(anmnt, a, b, a_bnd, b_bnd) - } - - (ty::ty_var(a_id), _) => { - let nde_a = self.get(&self.ty_var_bindings, a_id); - let a_bounds = nde_a.possible_types; - - let a_bnd = select(a_bounds.ub, a_bounds.lb); - self.assign_tys_or_sub(anmnt, a, b, a_bnd, Some(b)) - } - - (_, ty::ty_var(b_id)) => { - let nde_b = self.get(&self.ty_var_bindings, b_id); - let b_bounds = nde_b.possible_types; - - let b_bnd = select(b_bounds.lb, b_bounds.ub); - self.assign_tys_or_sub(anmnt, a, b, Some(a), b_bnd) - } - - (_, _) => { - self.assign_tys_or_sub(anmnt, a, b, Some(a), Some(b)) - } + (ty::ty_bot, _) => { + Ok(None) + } + + (ty::ty_var(a_id), ty::ty_var(b_id)) => { + let nde_a = self.infcx.get(&self.infcx.ty_var_bindings, a_id); + let nde_b = self.infcx.get(&self.infcx.ty_var_bindings, b_id); + let a_bounds = nde_a.possible_types; + let b_bounds = nde_b.possible_types; + + let a_bnd = option::or(a_bounds.ub, a_bounds.lb); + let b_bnd = option::or(b_bounds.lb, b_bounds.ub); + self.assign_tys_or_sub(a, b, a_bnd, b_bnd) + } + + (ty::ty_var(a_id), _) => { + let nde_a = self.infcx.get(&self.infcx.ty_var_bindings, a_id); + let a_bounds = nde_a.possible_types; + + let a_bnd = option::or(a_bounds.ub, a_bounds.lb); + self.assign_tys_or_sub(a, b, a_bnd, Some(b)) + } + + (_, ty::ty_var(b_id)) => { + let nde_b = self.infcx.get(&self.infcx.ty_var_bindings, b_id); + let b_bounds = nde_b.possible_types; + + let b_bnd = option::or(b_bounds.lb, b_bounds.ub); + self.assign_tys_or_sub(a, b, Some(a), b_bnd) + } + + (_, _) => { + self.assign_tys_or_sub(a, b, Some(a), Some(b)) + } } } +} +priv impl Assign { fn assign_tys_or_sub( - anmnt: &assignment, a: ty::t, b: ty::t, - +a_bnd: Option, +b_bnd: Option) -> ures { + +a_bnd: Option, +b_bnd: Option) -> ares { - debug!("assign_tys_or_sub(anmnt=%?, %s -> %s, %s -> %s)", - anmnt, a.to_str(self), b.to_str(self), - a_bnd.to_str(self), b_bnd.to_str(self)); + debug!("Assign.assign_tys_or_sub(%s -> %s, %s -> %s)", + a.to_str(self.infcx), b.to_str(self.infcx), + a_bnd.to_str(self.infcx), b_bnd.to_str(self.infcx)); let _r = indenter(); fn is_borrowable(v: ty::vstore) -> bool { @@ -123,73 +127,73 @@ fn is_borrowable(v: ty::vstore) -> bool { } match (a_bnd, b_bnd) { - (Some(a_bnd), Some(b_bnd)) => { - match (ty::get(a_bnd).struct, ty::get(b_bnd).struct) { - (ty::ty_box(*), ty::ty_rptr(r_b, mt_b)) => { - let nr_b = ty::mk_box(self.tcx, {ty: mt_b.ty, - mutbl: m_const}); - self.crosspollinate(anmnt, a, nr_b, mt_b.mutbl, r_b) - } - (ty::ty_uniq(*), ty::ty_rptr(r_b, mt_b)) => { - let nr_b = ty::mk_uniq(self.tcx, {ty: mt_b.ty, - mutbl: m_const}); - self.crosspollinate(anmnt, a, nr_b, mt_b.mutbl, r_b) - } - (ty::ty_estr(vs_a), - ty::ty_estr(ty::vstore_slice(r_b))) - if is_borrowable(vs_a) => { - let nr_b = ty::mk_estr(self.tcx, vs_a); - self.crosspollinate(anmnt, a, nr_b, m_imm, r_b) - } - - (ty::ty_evec(_, vs_a), - ty::ty_evec(mt_b, ty::vstore_slice(r_b))) - if is_borrowable(vs_a) => { - let nr_b = ty::mk_evec(self.tcx, {ty: mt_b.ty, - mutbl: m_const}, vs_a); - self.crosspollinate(anmnt, a, nr_b, mt_b.mutbl, r_b) - } - - _ => { - mk_sub(self, false, anmnt.span).tys(a, b).to_ures() - } + (Some(a_bnd), Some(b_bnd)) => { + // check for a case where a non-region pointer (@, ~) is + // being assigned to a region pointer: + match (ty::get(a_bnd).struct, ty::get(b_bnd).struct) { + (ty::ty_box(_), ty::ty_rptr(r_b, mt_b)) => { + let nr_b = ty::mk_box(self.infcx.tcx, + {ty: mt_b.ty, mutbl: m_const}); + self.try_assign(a, nr_b, mt_b.mutbl, r_b) + } + (ty::ty_uniq(_), ty::ty_rptr(r_b, mt_b)) => { + let nr_b = ty::mk_uniq(self.infcx.tcx, + {ty: mt_b.ty, mutbl: m_const}); + self.try_assign(a, nr_b, mt_b.mutbl, r_b) + } + (ty::ty_estr(vs_a), + ty::ty_estr(ty::vstore_slice(r_b))) + if is_borrowable(vs_a) => { + let nr_b = ty::mk_estr(self.infcx.tcx, vs_a); + self.try_assign(a, nr_b, m_imm, r_b) + } + + (ty::ty_evec(_, vs_a), + ty::ty_evec(mt_b, ty::vstore_slice(r_b))) + if is_borrowable(vs_a) => { + let nr_b = ty::mk_evec(self.infcx.tcx, + {ty: mt_b.ty, mutbl: m_const}, + vs_a); + self.try_assign(a, nr_b, mt_b.mutbl, r_b) + } + + _ => { + // otherwise, assignment follows normal subtype rules: + to_ares(Sub(*self).tys(a, b)) + } + } + } + _ => { + // if insufficient bounds were available, just follow + // normal subtype rules: + to_ares(Sub(*self).tys(a, b)) } - } - _ => { - mk_sub(self, false, anmnt.span).tys(a, b).to_ures() - } } } - fn crosspollinate(anmnt: &assignment, - a: ty::t, - nr_b: ty::t, - m: ast::mutability, - r_b: ty::region) -> ures { - - debug!("crosspollinate(anmnt=%?, a=%s, nr_b=%s, r_b=%s)", - anmnt, a.to_str(self), nr_b.to_str(self), - r_b.to_str(self)); + /// Given an assignment from a type like `@a` to `&r_b/m nr_b`, + /// this function checks that `a <: nr_b`. In that case, the + /// assignment is permitted, so it constructs a fresh region + /// variable `r_a >= r_b` and returns a corresponding assignment + /// record. See the discussion at the top of this file for more + /// details. + fn try_assign(a: ty::t, + nr_b: ty::t, + m: ast::mutability, + r_b: ty::region) -> ares { + + debug!("try_assign(a=%s, nr_b=%s, m=%?, r_b=%s)", + a.to_str(self.infcx), + nr_b.to_str(self.infcx), + m, + r_b.to_str(self.infcx)); do indent { - let sub = mk_sub(self, false, anmnt.span); + let sub = Sub(*self); do sub.tys(a, nr_b).chain |_t| { - // Create a fresh region variable `r_a` with the given - // borrow bounds: - let r_a = self.next_region_var(anmnt.span, - anmnt.borrow_lb); - - debug!("anmnt=%?", anmnt); + let r_a = self.infcx.next_region_var_nb(self.span); do sub.contraregions(r_a, r_b).chain |_r| { - // if successful, add an entry indicating that - // borrowing occurred - debug!("borrowing expression #%?, scope=%?, m=%?", - anmnt, r_a, m); - self.borrowings.push({expr_id: anmnt.expr_id, - span: anmnt.span, - scope: r_a, - mutbl: m}); - uok() + Ok(Some({region: r_a, mutbl: m})) } } } -- GitLab