diff --git a/src/libcore/dvec.rs b/src/libcore/dvec.rs
index ecbff6f12dfa4..1c50e948185b3 100644
--- a/src/libcore/dvec.rs
+++ b/src/libcore/dvec.rs
@@ -90,7 +90,7 @@ priv impl DVec {
}
#[inline(always)]
- fn borrow(f: fn(-~[mut A]) -> B) -> B {
+ fn check_out(f: fn(-~[mut A]) -> B) -> B {
unsafe {
let mut data = unsafe::reinterpret_cast(null::<()>());
data <-> self.data;
@@ -124,13 +124,13 @@ impl DVec {
*/
#[inline(always)]
fn swap(f: fn(-~[mut A]) -> ~[mut A]) {
- self.borrow(|v| self.give_back(f(v)))
+ self.check_out(|v| self.give_back(f(v)))
}
/// Returns the number of elements currently in the dvec
pure fn len() -> uint {
unchecked {
- do self.borrow |v| {
+ do self.check_out |v| {
let l = v.len();
self.give_back(v);
l
@@ -146,7 +146,7 @@ impl DVec {
/// Remove and return the last element
fn pop() -> A {
- do self.borrow |v| {
+ do self.check_out |v| {
let mut v <- v;
let result = vec::pop(v);
self.give_back(v);
@@ -176,7 +176,7 @@ impl DVec {
/// Remove and return the first element
fn shift() -> A {
- do self.borrow |v| {
+ do self.check_out |v| {
let mut v = vec::from_mut(v);
let result = vec::shift(v);
self.give_back(vec::to_mut(v));
@@ -184,10 +184,29 @@ impl DVec {
}
}
- // Reverse the elements in the list, in place
+ /// Reverse the elements in the list, in place
fn reverse() {
- do self.borrow |v| {
+ do self.check_out |v| {
vec::reverse(v);
+ self.give_back(v);
+ }
+ }
+
+ /// Gives access to the vector as a slice with immutable contents
+ fn borrow(op: fn(x: &[A]) -> R) -> R {
+ do self.check_out |v| {
+ let result = op(v);
+ self.give_back(v);
+ result
+ }
+ }
+
+ /// Gives access to the vector as a slice with mutable contents
+ fn borrow_mut(op: fn(x: &[mut A]) -> R) -> R {
+ do self.check_out |v| {
+ let result = op(v);
+ self.give_back(v);
+ result
}
}
}
@@ -249,7 +268,7 @@ impl DVec {
*/
pure fn get() -> ~[A] {
unchecked {
- do self.borrow |v| {
+ do self.check_out |v| {
let w = vec::from_mut(copy v);
self.give_back(v);
w
diff --git a/src/libcore/task.rs b/src/libcore/task.rs
index 2cd9c547bf9de..28f9486a67793 100644
--- a/src/libcore/task.rs
+++ b/src/libcore/task.rs
@@ -1187,7 +1187,9 @@ fn spawn_raw(+opts: TaskOpts, +f: fn~()) {
};
if result {
// Unwinding function in case any ancestral enlisting fails
- let bail = |tg| { leave_taskgroup(tg, child, false) };
+ let bail = |tg: TaskGroupInner| {
+ leave_taskgroup(tg, child, false)
+ };
// Attempt to join every ancestor group.
result =
for each_ancestor(ancestors, some(bail)) |ancestor_tg| {
diff --git a/src/libstd/cell.rs b/src/libstd/cell.rs
index 3d8f63c26cd3e..016ed8aecdd70 100644
--- a/src/libstd/cell.rs
+++ b/src/libstd/cell.rs
@@ -41,10 +41,11 @@ impl Cell {
}
// Calls a closure with a reference to the value.
- fn with_ref(f: fn(v: &T)) {
- let val = move self.take();
- f(&val);
- self.put_back(move val);
+ fn with_ref(op: fn(v: &T) -> R) -> R {
+ let v = self.take();
+ let r = op(&v);
+ self.put_back(v);
+ return move r;
}
}
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index bc74f654ca84d..1415084c22e89 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -16,7 +16,7 @@ import middle::lint;
import middle::lint::{get_lint_level, allow};
import syntax::ast::*;
import syntax::print::pprust::*;
-import util::ppaux::{ty_to_str, tys_to_str};
+import util::ppaux::{ty_to_str, proto_ty_to_str, tys_to_str};
export tv_vid, tvi_vid, region_vid, vid;
export br_hashmap;
@@ -119,6 +119,7 @@ export proto_kind, kind_lteq, type_kind;
export operators;
export type_err, terr_vstore_kind;
export type_err_to_str;
+export expected_found;
export type_needs_drop;
export type_is_empty;
export type_is_integral;
@@ -179,6 +180,7 @@ export fn_proto, proto_bare, proto_vstore;
export ast_proto_to_proto;
export is_blockish;
export method_call_bounds;
+export hash_region;
// Data types
@@ -368,7 +370,7 @@ enum region {
re_static,
/// A region variable. Should not exist after typeck.
- re_var(region_vid),
+ re_var(region_vid)
}
enum bound_region {
@@ -455,30 +457,35 @@ enum terr_vstore_kind {
terr_vec, terr_str, terr_fn, terr_trait
}
+struct expected_found {
+ expected: T;
+ found: T;
+}
+
// Data structures used in type unification
enum type_err {
terr_mismatch,
- terr_ret_style_mismatch(ast::ret_style, ast::ret_style),
- terr_purity_mismatch(purity, purity),
+ terr_ret_style_mismatch(expected_found),
+ terr_purity_mismatch(expected_found),
terr_mutability,
- terr_proto_mismatch(ty::fn_proto, ty::fn_proto),
+ terr_proto_mismatch(expected_found),
terr_box_mutability,
terr_ptr_mutability,
terr_ref_mutability,
terr_vec_mutability,
- terr_tuple_size(uint, uint),
- terr_ty_param_size(uint, uint),
- terr_record_size(uint, uint),
+ terr_tuple_size(expected_found),
+ terr_ty_param_size(expected_found),
+ terr_record_size(expected_found),
terr_record_mutability,
- terr_record_fields(ast::ident, ast::ident),
+ terr_record_fields(expected_found),
terr_arg_count,
- terr_mode_mismatch(mode, mode),
+ terr_mode_mismatch(expected_found),
terr_regions_does_not_outlive(region, region),
terr_regions_not_same(region, region),
terr_regions_no_overlap(region, region),
- terr_vstores_differ(terr_vstore_kind, vstore, vstore),
+ terr_vstores_differ(terr_vstore_kind, expected_found),
terr_in_field(@type_err, ast::ident),
- terr_sorts(t, t),
+ terr_sorts(expected_found),
terr_self_substs,
terr_no_integral_type,
}
@@ -512,7 +519,7 @@ impl tvi_vid: vid {
impl region_vid: vid {
pure fn to_uint() -> uint { *self }
- pure fn to_str() -> ~str { fmt!{"", self.to_uint()} }
+ pure fn to_str() -> ~str { fmt!{"%?", self} }
}
trait purity_to_str {
@@ -2195,6 +2202,17 @@ fn br_hashmap() -> hashmap {
map::hashmap(hash_bound_region, sys::shape_eq)
}
+pure fn hash_region(r: ®ion) -> uint {
+ match *r { // no idea if this is any good
+ re_bound(br) => (hash_bound_region(&br)) << 2u | 0u,
+ re_free(id, br) => ((id as uint) << 4u) |
+ (hash_bound_region(&br)) << 2u | 1u,
+ re_scope(id) => ((id as uint) << 2u) | 2u,
+ re_var(id) => (id.to_uint() << 2u) | 3u,
+ re_bot => 4u
+ }
+}
+
// Type hashing.
pure fn hash_type_structure(st: &sty) -> uint {
pure fn hash_uint(id: uint, n: uint) -> uint { (id << 2u) + n }
@@ -2210,16 +2228,6 @@ pure fn hash_type_structure(st: &sty) -> uint {
for vec::each(subtys) |s| { h = (h << 2u) + type_id(s) }
h
}
- pure fn hash_region(r: ®ion) -> uint {
- match *r { // no idea if this is any good
- re_bound(br) => (hash_bound_region(&br)) << 2u | 0u,
- re_free(id, br) => ((id as uint) << 4u) |
- (hash_bound_region(&br)) << 2u | 1u,
- re_scope(id) => ((id as uint) << 2u) | 2u,
- re_var(id) => (id.to_uint() << 2u) | 3u,
- re_bot => 4u
- }
- }
pure fn hash_substs(h: uint, substs: &substs) -> uint {
let h = hash_subtys(h, substs.tps);
h + substs.self_r.map_default(0u, |r| hash_region(&r))
@@ -2569,8 +2577,11 @@ fn resolved_mode(cx: ctxt, m: ast::mode) -> ast::rmode {
fn arg_mode(cx: ctxt, a: arg) -> ast::rmode { resolved_mode(cx, a.mode) }
// Unifies `m1` and `m2`. Returns unified value or failure code.
-fn unify_mode(cx: ctxt, m1: ast::mode, m2: ast::mode)
+fn unify_mode(cx: ctxt, modes: expected_found)
-> result {
+
+ let m1 = modes.expected;
+ let m2 = modes.found;
match (canon_mode(cx, m1), canon_mode(cx, m2)) {
(m1, m2) if (m1 == m2) => {
result::ok(m1)
@@ -2584,7 +2595,7 @@ fn unify_mode(cx: ctxt, m1: ast::mode, m2: ast::mode)
result::ok(m1)
}
(m1, m2) => {
- result::err(terr_mode_mismatch(m1, m2))
+ result::err(terr_mode_mismatch(modes))
}
}
}
@@ -2638,91 +2649,96 @@ fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
}
match *err {
- terr_mismatch => return ~"types differ",
- terr_ret_style_mismatch(expect, actual) => {
+ terr_mismatch => ~"types differ",
+ terr_ret_style_mismatch(values) => {
fn to_str(s: ast::ret_style) -> ~str {
match s {
ast::noreturn => ~"non-returning",
ast::return_val => ~"return-by-value"
}
}
- return to_str(actual) + ~" function found where " + to_str(expect) +
- ~" function was expected";
- }
- terr_purity_mismatch(f1, f2) => {
- return fmt!{"expected %s fn but found %s fn",
- purity_to_str(f1), purity_to_str(f2)};
- }
- terr_proto_mismatch(e, a) => {
- return fmt!{"closure protocol mismatch (%s vs %s)",
- util::ppaux::proto_ty_to_str(cx, e),
- util::ppaux::proto_ty_to_str(cx, a)};
- }
- terr_mutability => return ~"values differ in mutability",
- terr_box_mutability => return ~"boxed values differ in mutability",
- terr_vec_mutability => return ~"vectors differ in mutability",
- terr_ptr_mutability => return ~"pointers differ in mutability",
- terr_ref_mutability => return ~"references differ in mutability",
- terr_ty_param_size(e_sz, a_sz) => {
- return ~"expected a type with " + uint::to_str(e_sz, 10u) +
- ~" type params but found one with " + uint::to_str(a_sz, 10u) +
- ~" type params";
- }
- terr_tuple_size(e_sz, a_sz) => {
- return ~"expected a tuple with " + uint::to_str(e_sz, 10u) +
- ~" elements but found one with " + uint::to_str(a_sz, 10u) +
- ~" elements";
- }
- terr_record_size(e_sz, a_sz) => {
- return ~"expected a record with " + uint::to_str(e_sz, 10u) +
- ~" fields but found one with " + uint::to_str(a_sz, 10u) +
- ~" fields";
+ fmt!("expected %s function, found %s function",
+ to_str(values.expected),
+ to_str(values.expected))
+ }
+ terr_purity_mismatch(values) => {
+ fmt!{"expected %s fn but found %s fn",
+ purity_to_str(values.expected),
+ purity_to_str(values.found)}
+ }
+ terr_proto_mismatch(values) => {
+ fmt!{"expected %s closure, found %s closure",
+ proto_ty_to_str(cx, values.expected),
+ proto_ty_to_str(cx, values.found)}
+ }
+ terr_mutability => ~"values differ in mutability",
+ terr_box_mutability => ~"boxed values differ in mutability",
+ terr_vec_mutability => ~"vectors differ in mutability",
+ terr_ptr_mutability => ~"pointers differ in mutability",
+ terr_ref_mutability => ~"references differ in mutability",
+ terr_ty_param_size(values) => {
+ fmt!("expected a type with %? type params \
+ but found one with %? type params",
+ values.expected, values.found)
+ }
+ terr_tuple_size(values) => {
+ fmt!("expected a tuple with %? elements \
+ but found one with %? elements",
+ values.expected, values.found)
+ }
+ terr_record_size(values) => {
+ fmt!("expected a record with %? fields \
+ but found one with %? fields",
+ values.expected, values.found)
}
terr_record_mutability => {
- return ~"record elements differ in mutability";
+ ~"record elements differ in mutability"
}
- terr_record_fields(e_fld, a_fld) => {
- return ~"expected a record with field `" + *e_fld +
- ~"` but found one with field `" + *a_fld + ~"`";
+ terr_record_fields(values) => {
+ fmt!("expected a record with field `%s` \
+ but found one with field `%s`",
+ *values.expected, *values.found)
}
- terr_arg_count => return ~"incorrect number of function parameters",
- terr_mode_mismatch(e_mode, a_mode) => {
- return ~"expected argument mode " + mode_to_str(e_mode) +
- ~" but found " + mode_to_str(a_mode);
+ terr_arg_count => ~"incorrect number of function parameters",
+ terr_mode_mismatch(values) => {
+ fmt!("expected argument mode %s, but found %s",
+ mode_to_str(values.expected), mode_to_str(values.found))
}
terr_regions_does_not_outlive(subregion, superregion) => {
- return fmt!{"%s does not necessarily outlive %s",
- explain_region(cx, subregion),
- explain_region(cx, superregion)};
+ fmt!{"%s does not necessarily outlive %s",
+ explain_region(cx, superregion),
+ explain_region(cx, subregion)}
}
terr_regions_not_same(region1, region2) => {
- return fmt!{"%s is not the same as %s",
- explain_region(cx, region1),
- explain_region(cx, region2)};
+ fmt!{"%s is not the same as %s",
+ explain_region(cx, region1),
+ explain_region(cx, region2)}
}
terr_regions_no_overlap(region1, region2) => {
- return fmt!{"%s does not intersect %s",
- explain_region(cx, region1),
- explain_region(cx, region2)};
+ fmt!("%s does not intersect %s",
+ explain_region(cx, region1),
+ explain_region(cx, region2))
}
- terr_vstores_differ(k, e_vs, a_vs) => {
- return fmt!{"%s storage differs: expected %s but found %s",
- terr_vstore_kind_to_str(k),
- vstore_to_str(cx, e_vs),
- vstore_to_str(cx, a_vs)};
+ terr_vstores_differ(k, values) => {
+ fmt!("%s storage differs: expected %s but found %s",
+ terr_vstore_kind_to_str(k),
+ vstore_to_str(cx, values.expected),
+ vstore_to_str(cx, values.found))
}
terr_in_field(err, fname) => {
- return fmt!{"in field `%s`, %s", *fname, type_err_to_str(cx, err)};
+ fmt!{"in field `%s`, %s", *fname, type_err_to_str(cx, err)}
}
- terr_sorts(exp, act) => {
- return fmt!{"%s vs %s", ty_sort_str(cx, exp), ty_sort_str(cx, act)};
+ terr_sorts(values) => {
+ fmt!{"expected %s but found %s",
+ ty_sort_str(cx, values.expected),
+ ty_sort_str(cx, values.found)}
}
terr_self_substs => {
- return ~"inconsistent self substitution"; // XXX this is more of a bug
+ ~"inconsistent self substitution" // XXX this is more of a bug
}
terr_no_integral_type => {
- return ~"couldn't determine an appropriate integral type for integer \
- literal";
+ ~"couldn't determine an appropriate integral type for integer \
+ literal"
}
}
}
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index ded6a2b41f891..807aff1617462 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -206,6 +206,7 @@ fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty {
fn require_same_types(
tcx: ty::ctxt,
maybe_infcx: option,
+ t1_is_expected: bool,
span: span,
t1: ty::t,
t2: ty::t,
@@ -223,7 +224,7 @@ fn require_same_types(
}
}
- match infer::mk_eqty(l_infcx, t1, t2) {
+ match infer::mk_eqty(l_infcx, t1_is_expected, span, t1, t2) {
result::ok(()) => true,
result::err(ref terr) => {
l_tcx.sess.span_err(span, msg() + ~": " +
diff --git a/src/rustc/middle/typeck/astconv.rs b/src/rustc/middle/typeck/astconv.rs
index 64d4cdbd97991..145d0fd0bd51b 100644
--- a/src/rustc/middle/typeck/astconv.rs
+++ b/src/rustc/middle/typeck/astconv.rs
@@ -72,8 +72,8 @@ fn ast_region_to_region(
self: AC, rscope: RS, span: span, a_r: @ast::region) -> ty::region {
let res = match a_r.node {
- ast::re_anon => rscope.anon_region(),
- ast::re_named(id) => rscope.named_region(id)
+ ast::re_anon => rscope.anon_region(span),
+ ast::re_named(id) => rscope.named_region(span, id)
};
get_region_reporting_err(self.tcx(), span, res)
@@ -106,7 +106,7 @@ fn ast_path_to_substs_and_ty(
none
}
(true, none) => {
- let res = rscope.anon_region();
+ let res = rscope.anon_region(path.span);
let r = get_region_reporting_err(self.tcx(), path.span, res);
some(r)
}
@@ -409,8 +409,10 @@ fn ty_of_arg(
let mode = {
match a.mode {
ast::infer(_) if expected_ty.is_some() => {
- result::get(ty::unify_mode(self.tcx(), a.mode,
- expected_ty.get().mode))
+ result::get(ty::unify_mode(
+ self.tcx(),
+ ty::expected_found {expected: expected_ty.get().mode,
+ found: a.mode}))
}
ast::infer(_) => {
match ty::get(ty).struct {
@@ -425,7 +427,10 @@ fn ty_of_arg(
// will have been unified with m yet:
_ => {
let m1 = ast::expl(ty::default_arg_mode_for_ty(ty));
- result::get(ty::unify_mode(self.tcx(), a.mode, m1))
+ result::get(ty::unify_mode(
+ self.tcx(),
+ ty::expected_found {expected: m1,
+ found: a.mode}))
}
}
}
@@ -446,7 +451,7 @@ fn ast_proto_to_proto(
ast::proto_box =>
ty::proto_vstore(ty::vstore_box),
ast::proto_block => {
- let result = rscope.anon_region();
+ let result = rscope.anon_region(span);
let region = get_region_reporting_err(self.tcx(), span, result);
ty::proto_vstore(ty::vstore_slice(region))
}
diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs
index 7f1647d03de09..a810478788cde 100644
--- a/src/rustc/middle/typeck/check.rs
+++ b/src/rustc/middle/typeck/check.rs
@@ -102,12 +102,12 @@ type fn_ctxt_ =
// the end of (almost) any enclosing block or expression. We
// want to pick the narrowest block that encompasses all uses.
//
- // What we do in such cases is to generate a region variable and
- // assign it the following two fields as bounds. The lower bound
- // is always the innermost enclosing expression. The upper bound
- // is the outermost enclosing expression that we could legally
- // use. In practice, this is the innermost loop or function
- // body.
+ // What we do in such cases is to generate a region variable with
+ // `region_lb` as a lower bound. The regionck pass then adds
+ // other constriants based on how the variable is used and region
+ // inference selects the ultimate value. Finally, 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.
mut region_lb: ast::node_id,
in_scope_regions: isr_alist,
@@ -292,20 +292,22 @@ fn check_fn(ccx: @crate_ctxt,
arg_tys: ~[ty::t]) {
let tcx = fcx.ccx.tcx;
- let assign = fn@(nid: ast::node_id, ty_opt: option) {
+ 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);
match ty_opt {
none => {/* nothing to do */ }
some(typ) => {
- infer::mk_eqty(fcx.infcx, ty::mk_var(tcx, var_id), typ);
+ infer::mk_eqty(fcx.infcx, false, span,
+ ty::mk_var(tcx, var_id), typ);
}
}
};
// Add formal parameters.
do vec::iter2(arg_tys, decl.inputs) |arg_ty, input| {
- assign(input.id, some(arg_ty));
+ assign(input.ty.span, input.id, some(arg_ty));
debug!{"Argument %s is assigned to %s",
*input.ident, fcx.locals.get(input.id).to_str()};
}
@@ -317,7 +319,7 @@ fn check_fn(ccx: @crate_ctxt,
ast::ty_infer => none,
_ => some(fcx.to_ty(local.node.ty))
};
- assign(local.node.id, o_ty);
+ assign(local.span, local.node.id, o_ty);
debug!{"Local variable %s is assigned to %s",
pat_to_str(local.node.pat),
fcx.locals.get(local.node.id).to_str()};
@@ -329,7 +331,7 @@ fn check_fn(ccx: @crate_ctxt,
match p.node {
ast::pat_ident(_, path, _)
if !pat_util::pat_is_variant(fcx.ccx.tcx.def_map, p) => {
- assign(p.id, none);
+ assign(p.span, p.id, none);
debug!{"Pattern binding %s is assigned to %s",
*path.idents[0],
fcx.locals.get(p.id).to_str()};
@@ -525,14 +527,14 @@ impl @fn_ctxt: ast_conv {
}
impl @fn_ctxt: region_scope {
- fn anon_region() -> result {
- result::ok(self.infcx.next_region_var_nb())
+ fn anon_region(span: span) -> result {
+ result::ok(self.infcx.next_region_var_nb(span))
}
- fn named_region(id: ast::ident) -> result {
- do empty_rscope.named_region(id).chain_err |_e| {
+ fn named_region(span: span, id: ast::ident) -> result {
+ do empty_rscope.named_region(span, id).chain_err |_e| {
match self.in_scope_regions.find(ty::br_named(id)) {
some(r) => result::ok(r),
- none if *id == ~"blk" => self.block_region(),
+ none if *id == ~"blk" => result::ok(self.block_region()),
none => {
result::err(fmt!{"named region `%s` not in scope here", *id})
}
@@ -543,8 +545,8 @@ impl @fn_ctxt: region_scope {
impl @fn_ctxt {
fn tag() -> ~str { fmt!{"%x", ptr::addr_of(*self) as uint} }
- fn block_region() -> result {
- result::ok(ty::re_scope(self.region_lb))
+ fn block_region() -> ty::region {
+ ty::re_scope(self.region_lb)
}
#[inline(always)]
fn write_ty(node_id: ast::node_id, ty: ty::t) {
@@ -619,8 +621,9 @@ impl @fn_ctxt {
ty::type_err_to_str(self.ccx.tcx, err)});
}
- fn mk_subty(sub: ty::t, sup: ty::t) -> result<(), ty::type_err> {
- infer::mk_subty(self.infcx, sub, sup)
+ 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)
}
fn can_mk_subty(sub: ty::t, sup: ty::t) -> result<(), ty::type_err> {
@@ -641,12 +644,14 @@ impl @fn_ctxt {
infer::can_mk_assignty(self.infcx, anmnt, sub, sup)
}
- fn mk_eqty(sub: ty::t, sup: ty::t) -> result<(), ty::type_err> {
- infer::mk_eqty(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)
}
- fn mk_subr(sub: ty::region, sup: ty::region) -> result<(), ty::type_err> {
- infer::mk_subr(self.infcx, 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)
}
fn require_unsafe(sp: span, op: ~str) {
@@ -748,8 +753,10 @@ fn check_expr(fcx: @fn_ctxt, expr: @ast::expr,
// declared on the impl declaration e.g., `impl for ~[(A,B)]`
// would return ($0, $1) where $0 and $1 are freshly instantiated type
// variables.
-fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id, require_rp: bool)
- -> ty_param_substs_and_ty {
+fn impl_self_ty(fcx: @fn_ctxt,
+ expr: @ast::expr, // (potential) receiver for this impl
+ did: ast::def_id,
+ require_rp: bool) -> ty_param_substs_and_ty {
let tcx = fcx.ccx.tcx;
let {n_tps, rp, raw_ty} = if did.crate == ast::local_crate {
@@ -786,7 +793,8 @@ fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id, require_rp: bool)
};
let rp = rp || require_rp;
- let self_r = if rp {some(fcx.infcx.next_region_var_nb())} else {none};
+ let self_r = if rp {some(fcx.infcx.next_region_var(expr.span, expr.id))}
+ else {none};
let tps = fcx.infcx.next_ty_vars(n_tps);
let substs = {self_r: self_r, self_ty: none, tps: tps};
@@ -840,7 +848,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
sty @ 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_nb()).fn_ty
+ |_br| fcx.infcx.next_region_var(sp,
+ call_expr_id)).fn_ty
}
sty => {
// I would like to make this span_err, but it's
@@ -1442,8 +1451,23 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
bot = check_expr(fcx, oprnd, unpack_expected(fcx, expected, |ty|
match ty { ty::ty_rptr(_, mt) => some(mt.ty), _ => none }
));
- //let region = region_of(fcx, oprnd);
- let region = fcx.infcx.next_region_var_with_scope_lb(expr.id);
+
+ // Note: at this point, we cannot say what the best lifetime
+ // is to use for resulting pointer. We want to use the
+ // shortest lifetime possible so as to avoid spurious borrowck
+ // errors. Moreover, the longest lifetime will depend on the
+ // precise details of the value whose address is being taken
+ // (and how long it is valid), which we don't know yet until type
+ // inference is complete.
+ //
+ // Therefore, here we simply generate a region variable with
+ // the current expression as a lower bound. The region
+ // inferencer will then select the ultimate value. Finally,
+ // 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 tm = { ty: fcx.expr_ty(oprnd), mutbl: mutbl };
let oprnd_t = ty::mk_rptr(tcx, region, tm);
fcx.write_ty(id, oprnd_t);
@@ -1452,7 +1476,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
let defn = lookup_def(fcx, pth.span, id);
let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
- instantiate_path(fcx, pth, tpt, expr.span, expr.id);
+ let region_lb = ty::re_scope(expr.id);
+ instantiate_path(fcx, pth, tpt, expr.span, expr.id, region_lb);
}
ast::expr_mac(_) => tcx.sess.bug(~"unexpanded macro"),
ast::expr_fail(expr_opt) => {
@@ -1474,7 +1499,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
some(t) => t, none => fcx.ret_ty
};
match expr_opt {
- none => match fcx.mk_eqty(ret_ty, ty::mk_nil(tcx)) {
+ none => match fcx.mk_eqty(false, expr.span,
+ ret_ty, ty::mk_nil(tcx)) {
result::ok(_) => { /* fall through */ }
result::err(_) => {
tcx.sess.span_err(
@@ -1550,7 +1576,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
let expected_sty = unpack_expected(fcx, expected, |x| some(x));
let (inner_ty, proto) = match expected_sty {
some(ty::ty_fn(fty)) => {
- match infer::mk_subty(fcx.infcx, fty.output, ty::mk_bool(tcx)) {
+ match fcx.mk_subty(false, expr.span,
+ fty.output, ty::mk_bool(tcx)) {
result::ok(_) => (),
result::err(err) => {
tcx.sess.span_fatal(
@@ -1809,7 +1836,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
// Generate the struct type.
let self_region;
if region_parameterized {
- self_region = some(fcx.infcx.next_region_var_nb());
+ self_region = some(fcx.infcx.next_region_var(expr.span, expr.id));
} else {
self_region = none;
}
@@ -2307,8 +2334,9 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
fn instantiate_path(fcx: @fn_ctxt,
pth: @ast::path,
tpt: ty_param_bounds_and_ty,
- sp: span,
- id: ast::node_id) {
+ span: span,
+ node_id: ast::node_id,
+ region_lb: ty::region) {
let ty_param_count = vec::len(*tpt.bounds);
let ty_substs_len = vec::len(pth.types);
@@ -2317,14 +2345,14 @@ fn instantiate_path(fcx: @fn_ctxt,
let self_r = match pth.rp {
some(r) if !tpt.rp => {
fcx.ccx.tcx.sess.span_err
- (sp, ~"this item is not region-parameterized");
+ (span, ~"this item is not region-parameterized");
none
}
some(r) => {
- some(ast_region_to_region(fcx, fcx, sp, r))
+ some(ast_region_to_region(fcx, fcx, span, r))
}
none if tpt.rp => {
- some(fcx.infcx.next_region_var_nb())
+ some(fcx.infcx.next_region_var_with_lb(span, region_lb))
}
none => {
none
@@ -2337,22 +2365,22 @@ fn instantiate_path(fcx: @fn_ctxt,
fcx.infcx.next_ty_vars(ty_param_count)
} else if ty_param_count == 0u {
fcx.ccx.tcx.sess.span_err
- (sp, ~"this item does not take type parameters");
+ (span, ~"this item does not take type parameters");
fcx.infcx.next_ty_vars(ty_param_count)
} else if ty_substs_len > ty_param_count {
fcx.ccx.tcx.sess.span_err
- (sp, ~"too many type parameters provided for this item");
+ (span, ~"too many type parameters provided for this item");
fcx.infcx.next_ty_vars(ty_param_count)
} else if ty_substs_len < ty_param_count {
fcx.ccx.tcx.sess.span_err
- (sp, ~"not enough type parameters provided for this item");
+ (span, ~"not enough type parameters provided for this item");
fcx.infcx.next_ty_vars(ty_param_count)
} else {
pth.types.map(|aty| fcx.to_ty(aty))
};
let substs = {self_r: self_r, self_ty: none, tps: tps};
- fcx.write_ty_substs(id, tpt.ty, substs);
+ fcx.write_ty_substs(node_id, tpt.ty, substs);
}
// Resolves `typ` by a single level if `typ` is a type variable. If no
@@ -2400,15 +2428,9 @@ fn ast_expr_vstore_to_vstore(fcx: @fn_ctxt, e: @ast::expr, n: uint,
}
ast::vstore_uniq => ty::vstore_uniq,
ast::vstore_box => ty::vstore_box,
- ast::vstore_slice(a_r) => match fcx.block_region() {
- result::ok(b_r) => {
- let r = fcx.infcx.next_region_var_with_scope_lb(e.id);
- ty::vstore_slice(r)
- }
- result::err(msg) => {
- fcx.ccx.tcx.sess.span_err(e.span, msg);
- ty::vstore_slice(ty::re_static)
- }
+ ast::vstore_slice(a_r) => {
+ let r = fcx.infcx.next_region_var(e.span, e.id);
+ ty::vstore_slice(r)
}
}
}
@@ -2523,7 +2545,7 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
expected %u", i_n_tps, n_tps});
} else {
require_same_types(
- tcx, none, it.span, i_ty.ty, fty,
+ tcx, none, false, it.span, i_ty.ty, fty,
|| fmt!{"intrinsic has wrong type: \
expected `%s`",
ty_to_str(ccx.tcx, fty)});
diff --git a/src/rustc/middle/typeck/check/alt.rs b/src/rustc/middle/typeck/check/alt.rs
index e99836e078b0e..d136b13eaacbc 100644
--- a/src/rustc/middle/typeck/check/alt.rs
+++ b/src/rustc/middle/typeck/check/alt.rs
@@ -63,7 +63,8 @@ fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path,
// Assign the pattern the type of the *enum*, not the variant.
let enum_tpt = ty::lookup_item_type(tcx, v_def_ids.enm);
- instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id);
+ instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id,
+ pcx.block_region);
// Take the enum type params out of `expected`.
match structure_of(pcx.fcx, pat.span, expected) {
@@ -143,7 +144,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
debug!{"pat_range beginning type: %?", b_ty};
debug!{"pat_range ending type: %?", e_ty};
if !require_same_types(
- tcx, some(fcx.infcx), pat.span, b_ty, e_ty,
+ 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) {
@@ -165,8 +166,8 @@ 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({lb: some(pcx.block_region),
- ub: none});
+ 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);
demand::eqtype(fcx, pat.span, region_ty, typ);
diff --git a/src/rustc/middle/typeck/check/demand.rs b/src/rustc/middle/typeck/check/demand.rs
index 224de47f0ccae..f835cffca2580 100644
--- a/src/rustc/middle/typeck/check/demand.rs
+++ b/src/rustc/middle/typeck/check/demand.rs
@@ -6,7 +6,8 @@ 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, actual, expected) {
+ match infer::mk_subty(fcx.infcx, false, sp,
+ actual, expected) {
result::ok(()) => { /* ok */ }
result::err(ref err) => {
fcx.report_mismatched_types(sp, expected, actual, err);
@@ -17,7 +18,7 @@ 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, actual, expected) {
+ 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);
diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs
index a885fa0b5c0f9..26ca4d07c9458 100644
--- a/src/rustc/middle/typeck/check/method.rs
+++ b/src/rustc/middle/typeck/check/method.rs
@@ -439,7 +439,7 @@ struct lookup {
// determine the `self` of the impl with fresh
// variables for each parameter:
let {substs: impl_substs, ty: impl_ty} =
- impl_self_ty(self.fcx, im.did, need_rp);
+ impl_self_ty(self.fcx, self.self_expr, im.did, need_rp);
let impl_ty = transform_self_type_for_method(
self.tcx(), impl_substs.self_r,
@@ -458,15 +458,17 @@ struct lookup {
self.self_ty,
impl_ty),
immutable_reference_mode => {
- let region = self.fcx.infcx.next_region_var_with_scope_lb
- (self.self_expr.id);
+ 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_with_scope_lb
- (self.self_expr.id);
+ 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);
@@ -609,8 +611,9 @@ struct lookup {
}
immutable_reference_mode => {
// Borrow as an immutable reference.
- let region_var = self.fcx.infcx.next_region_var_with_scope_lb
- (self.self_expr.id);
+ 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,
@@ -618,8 +621,9 @@ struct lookup {
}
mutable_reference_mode => {
// Borrow as a mutable reference.
- let region_var = self.fcx.infcx.next_region_var_with_scope_lb
- (self.self_expr.id);
+ 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,
diff --git a/src/rustc/middle/typeck/check/regionck.rs b/src/rustc/middle/typeck/check/regionck.rs
index c4127eb2e48b5..fc0112ddc8dbb 100644
--- a/src/rustc/middle/typeck/check/regionck.rs
+++ b/src/rustc/middle/typeck/check/regionck.rs
@@ -18,9 +18,9 @@ this point a bit better.
*/
import util::ppaux;
+import ppaux::{note_and_explain_region, ty_to_str};
import syntax::print::pprust;
-import infer::{resolve_type, resolve_all, force_all,
- resolve_rvar, force_rvar, fres};
+import infer::{resolve_and_force_all_but_regions, fres};
import middle::kind::check_owned;
import middle::pat_util::pat_bindings;
@@ -52,8 +52,7 @@ impl @rcx {
/// will effectively resolve `` to be the block B.
fn resolve_type(unresolved_ty: ty::t) -> fres {
resolve_type(self.fcx.infcx, unresolved_ty,
- (resolve_all | force_all) -
- (resolve_rvar | force_rvar))
+ resolve_and_force_all_but_regions)
}
/// Try to resolve the type for the given node.
@@ -66,6 +65,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();
}
fn regionck_fn(fcx: @fn_ctxt,
@@ -74,6 +74,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();
}
fn regionck_visitor() -> rvt {
@@ -209,10 +210,8 @@ fn visit_node(id: ast::node_id, span: span, rcx: @rcx) -> bool {
let tcx = fcx.ccx.tcx;
let encl_region = ty::encl_region(tcx, id);
- debug!{"visit_node(ty=%s, id=%d, encl_region=%s)",
- ppaux::ty_to_str(tcx, ty),
- id,
- ppaux::region_to_str(tcx, encl_region)};
+ debug!{"visit_node(ty=%s, id=%d, encl_region=%?)",
+ ty_to_str(tcx, ty), id, encl_region};
// Otherwise, look at the type and see if it is a region pointer.
return constrain_regions_in_type(rcx, encl_region, span, ty);
@@ -237,9 +236,8 @@ fn constrain_regions_in_type(
region: ty::region) {
let tcx = rcx.fcx.ccx.tcx;
- debug!{"constrain_region(encl_region=%s, region=%s)",
- ppaux::region_to_str(tcx, encl_region),
- ppaux::region_to_str(tcx, region)};
+ debug!{"constrain_region(encl_region=%?, region=%?)",
+ encl_region, region};
match region {
ty::re_bound(_) => {
@@ -252,14 +250,15 @@ fn constrain_regions_in_type(
_ => ()
}
- match rcx.fcx.mk_subr(encl_region, region) {
+ match rcx.fcx.mk_subr(true, span, encl_region, region) {
result::err(_) => {
- let region1 = rcx.fcx.infcx.resolve_region_if_possible(region);
tcx.sess.span_err(
span,
- fmt!{"reference is not valid outside \
- of its lifetime, %s",
- ppaux::region_to_str(tcx, region1)});
+ fmt!("reference is not valid outside of its lifetime"));
+ note_and_explain_region(
+ tcx,
+ ~"the reference is only valid for",
+ region);
rcx.errors_reported += 1u;
}
result::ok(()) => {
diff --git a/src/rustc/middle/typeck/check/vtable.rs b/src/rustc/middle/typeck/check/vtable.rs
index 5f75452fa1181..fa0acf79dbed9 100644
--- a/src/rustc/middle/typeck/check/vtable.rs
+++ b/src/rustc/middle/typeck/check/vtable.rs
@@ -1,6 +1,8 @@
import check::{fn_ctxt, impl_self_ty};
-import infer::{resolve_type, resolve_all, force_all, fixup_err_to_str};
+import infer::{resolve_type, resolve_and_force_all_but_regions,
+ fixup_err_to_str};
import ast_util::new_def_hash;
+import syntax::print::pprust;
// vtable resolution looks for places where trait bounds are
// subsituted in and figures out which vtable is used. There is some
@@ -27,7 +29,7 @@ fn has_trait_bounds(tps: ~[ty::param_bounds]) -> bool {
}
fn lookup_vtables(fcx: @fn_ctxt,
- sp: span,
+ expr: @ast::expr,
bounds: @~[ty::param_bounds],
substs: &ty::substs,
allow_unsafe: bool,
@@ -39,7 +41,7 @@ fn lookup_vtables(fcx: @fn_ctxt,
match bound {
ty::bound_trait(i_ty) => {
let i_ty = ty::subst(tcx, substs, i_ty);
- vec::push(result, lookup_vtable(fcx, sp, ty, i_ty,
+ vec::push(result, lookup_vtable(fcx, expr, ty, i_ty,
allow_unsafe, is_early));
}
_ => ()
@@ -50,31 +52,36 @@ fn lookup_vtables(fcx: @fn_ctxt,
@result
}
-fn fixup_substs(fcx: @fn_ctxt, sp: span,
+fn fixup_substs(fcx: @fn_ctxt, expr: @ast::expr,
id: ast::def_id, substs: ty::substs,
is_early: bool) -> option {
let tcx = fcx.ccx.tcx;
// use a dummy type just to package up the substs that need fixing up
let t = ty::mk_trait(tcx, id, substs, ty::vstore_slice(ty::re_static));
- do fixup_ty(fcx, sp, t, is_early).map |t_f| {
+ do fixup_ty(fcx, expr, t, is_early).map |t_f| {
match check ty::get(t_f).struct {
ty::ty_trait(_, substs_f, _) => substs_f,
}
}
}
-fn relate_trait_tys(fcx: @fn_ctxt, sp: span,
+fn relate_trait_tys(fcx: @fn_ctxt, expr: @ast::expr,
exp_trait_ty: ty::t, act_trait_ty: ty::t) {
- demand::suptype(fcx, sp, exp_trait_ty, act_trait_ty)
+ demand::suptype(fcx, expr.span, exp_trait_ty, act_trait_ty)
}
/*
Look up the vtable to use when treating an item of type
as if it has type
*/
-fn lookup_vtable(fcx: @fn_ctxt, sp: span, ty: ty::t, trait_ty: ty::t,
- allow_unsafe: bool, is_early: bool)
- -> vtable_origin {
+fn lookup_vtable(fcx: @fn_ctxt,
+ expr: @ast::expr,
+ ty: ty::t,
+ trait_ty: ty::t,
+ allow_unsafe: bool,
+ is_early: bool)
+ -> vtable_origin
+{
debug!{"lookup_vtable(ty=%s, trait_ty=%s)",
fcx.infcx.ty_to_str(ty), fcx.infcx.ty_to_str(trait_ty)};
@@ -84,7 +91,7 @@ fn lookup_vtable(fcx: @fn_ctxt, sp: span, ty: ty::t, trait_ty: ty::t,
let (trait_id, trait_substs) = match check ty::get(trait_ty).struct {
ty::ty_trait(did, substs, _) => (did, substs)
};
- let ty = match fixup_ty(fcx, sp, ty, is_early) {
+ let ty = match fixup_ty(fcx, expr, ty, is_early) {
some(ty) => ty,
none => {
// fixup_ty can only fail if this is early resolution
@@ -111,7 +118,7 @@ fn lookup_vtable(fcx: @fn_ctxt, sp: span, ty: ty::t, trait_ty: ty::t,
if trait_id == idid {
debug!{"(checking vtable) @0 relating ty to trait ty
with did %?", idid};
- relate_trait_tys(fcx, sp, trait_ty, ity);
+ relate_trait_tys(fcx, expr, trait_ty, ity);
return vtable_param(n, n_bound);
}
}
@@ -126,17 +133,19 @@ fn lookup_vtable(fcx: @fn_ctxt, sp: span, ty: ty::t, trait_ty: ty::t,
debug!{"(checking vtable) @1 relating ty to trait ty with did %?",
did};
- relate_trait_tys(fcx, sp, trait_ty, ty);
+ relate_trait_tys(fcx, expr, trait_ty, ty);
if !allow_unsafe && !is_early {
for vec::each(*ty::trait_methods(tcx, did)) |m| {
if ty::type_has_self(ty::mk_fn(tcx, m.fty)) {
tcx.sess.span_err(
- sp, ~"a boxed trait with self types may not be \
- passed as a bounded type");
+ expr.span,
+ ~"a boxed trait with self types may not be \
+ passed as a bounded type");
} else if (*m.tps).len() > 0u {
tcx.sess.span_err(
- sp, ~"a boxed trait with generic methods may not \
- be passed as a bounded type");
+ expr.span,
+ ~"a boxed trait with generic methods may not \
+ be passed as a bounded type");
}
}
@@ -176,9 +185,9 @@ fn lookup_vtable(fcx: @fn_ctxt, sp: span, ty: ty::t, trait_ty: ty::t,
// check whether the type unifies with the type
// that the impl is for, and continue if not
let {substs: substs, ty: for_ty} =
- impl_self_ty(fcx, im.did, false);
+ impl_self_ty(fcx, expr, im.did, false);
let im_bs = ty::lookup_item_type(tcx, im.did).bounds;
- match fcx.mk_subty(ty, for_ty) {
+ match fcx.mk_subty(false, expr.span, ty, for_ty) {
result::err(_) => again,
result::ok(()) => ()
}
@@ -189,12 +198,12 @@ fn lookup_vtable(fcx: @fn_ctxt, sp: span, ty: ty::t, trait_ty: ty::t,
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, sp, trait_ty, of_ty);
+ relate_trait_tys(fcx, expr, trait_ty, of_ty);
// recursively process the bounds.
let trait_tps = trait_substs.tps;
// see comments around the earlier call to fixup_ty
- let substs_f = match fixup_substs(fcx, sp, trait_id,
+ let substs_f = match fixup_substs(fcx, expr, trait_id,
substs, is_early) {
some(substs) => substs,
none => {
@@ -204,10 +213,11 @@ fn lookup_vtable(fcx: @fn_ctxt, sp: span, ty: ty::t, trait_ty: ty::t,
}
};
- connect_trait_tps(fcx, sp, substs_f.tps,
+ connect_trait_tps(fcx, expr, substs_f.tps,
trait_tps, im.did);
- let subres = lookup_vtables(fcx, sp, im_bs, &substs_f,
- false, is_early);
+ let subres = lookup_vtables(
+ fcx, expr, im_bs, &substs_f,
+ false, is_early);
vec::push(found,
vtable_static(im.did, substs_f.tps,
subres));
@@ -222,7 +232,8 @@ fn lookup_vtable(fcx: @fn_ctxt, sp: span, ty: ty::t, trait_ty: ty::t,
_ => {
if !is_early {
fcx.ccx.tcx.sess.span_err(
- sp, ~"multiple applicable methods in scope");
+ expr.span,
+ ~"multiple applicable methods in scope");
}
return found[0];
}
@@ -231,19 +242,22 @@ fn lookup_vtable(fcx: @fn_ctxt, sp: span, ty: ty::t, trait_ty: ty::t,
}
tcx.sess.span_fatal(
- sp, ~"failed to find an implementation of trait " +
- ty_to_str(tcx, trait_ty) + ~" for " +
- ty_to_str(tcx, ty));
+ expr.span,
+ fmt!("failed to find an implementation of trait %s for %s",
+ ty_to_str(tcx, trait_ty), ty_to_str(tcx, ty)));
}
-fn fixup_ty(fcx: @fn_ctxt, sp: span, ty: ty::t, is_early: bool)
- -> option {
+fn fixup_ty(fcx: @fn_ctxt,
+ expr: @ast::expr,
+ ty: ty::t,
+ is_early: bool) -> option
+{
let tcx = fcx.ccx.tcx;
- match resolve_type(fcx.infcx, ty, resolve_all | force_all) {
+ 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(
- sp,
+ expr.span,
fmt!{"cannot determine a type \
for this bounded type parameter: %s",
fixup_err_to_str(e)})
@@ -254,7 +268,7 @@ fn fixup_ty(fcx: @fn_ctxt, sp: span, ty: ty::t, is_early: bool)
}
}
-fn connect_trait_tps(fcx: @fn_ctxt, sp: span, impl_tys: ~[ty::t],
+fn connect_trait_tps(fcx: @fn_ctxt, expr: @ast::expr, impl_tys: ~[ty::t],
trait_tys: ~[ty::t], impl_did: ast::def_id) {
let tcx = fcx.ccx.tcx;
@@ -266,22 +280,23 @@ fn connect_trait_tps(fcx: @fn_ctxt, sp: span, impl_tys: ~[ty::t],
match check ty::get(trait_ty).struct {
ty::ty_trait(_, substs, _) => {
vec::iter2(substs.tps, trait_tys,
- |a, b| demand::suptype(fcx, sp, a, b));
+ |a, b| demand::suptype(fcx, expr.span, a, b));
}
}
}
fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
+ debug!("vtable: early_resolve_expr() ex with id %?: %s",
+ ex.id, expr_to_str(ex));
let cx = fcx.ccx;
match ex.node {
ast::expr_path(*) => {
- debug!("(vtable - resolving expr) resolving path expr");
match fcx.opt_node_ty_substs(ex.id) {
some(ref substs) => {
let did = ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id));
let item_ty = ty::lookup_item_type(cx.tcx, did);
if has_trait_bounds(*item_ty.bounds) {
- let vtbls = lookup_vtables(fcx, ex.span, item_ty.bounds,
+ let vtbls = lookup_vtables(fcx, ex, item_ty.bounds,
substs, false, is_early);
if !is_early { cx.vtable_map.insert(ex.id, vtbls); }
}
@@ -293,8 +308,6 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
ast::expr_field(*) | ast::expr_binary(*) |
ast::expr_unary(*) | ast::expr_assign_op(*) |
ast::expr_index(*) => {
- debug!("(vtable - resolving expr) resolving field/binary/unary/\
- assign/index expr");
match ty::method_call_bounds(cx.tcx, cx.method_map, ex.id) {
some(bounds) => {
if has_trait_bounds(*bounds) {
@@ -303,7 +316,7 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
_ => ex.callee_id
};
let substs = fcx.node_ty_substs(callee_id);
- let vtbls = lookup_vtables(fcx, ex.span, bounds,
+ let vtbls = lookup_vtables(fcx, ex, bounds,
&substs, false, is_early);
if !is_early { cx.vtable_map.insert(callee_id, vtbls); }
}
@@ -312,7 +325,6 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
}
}
ast::expr_cast(src, _) => {
- debug!("(vtable - resolving expr) resolving cast expr");
let target_ty = fcx.expr_ty(ex);
match ty::get(target_ty).struct {
ty::ty_trait(*) => {
@@ -320,7 +332,7 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
Look up vtables for the type we're casting to,
passing in the source and target type
*/
- let vtable = lookup_vtable(fcx, ex.span, fcx.expr_ty(src),
+ let vtable = lookup_vtable(fcx, ex, fcx.expr_ty(src),
target_ty, true, is_early);
/*
Map this expression to that vtable (that is: "ex has
diff --git a/src/rustc/middle/typeck/coherence.rs b/src/rustc/middle/typeck/coherence.rs
index bfc2365f1a9a5..ffed540323a4d 100644
--- a/src/rustc/middle/typeck/coherence.rs
+++ b/src/rustc/middle/typeck/coherence.rs
@@ -15,7 +15,7 @@ import middle::ty::{ty_float, ty_estr, ty_evec, ty_rec};
import middle::ty::{ty_fn, ty_trait, ty_tup, ty_var, ty_var_integral};
import middle::ty::{ty_param, ty_self, ty_type, ty_opaque_box};
import middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, type_is_var};
-import middle::typeck::infer::{infer_ctxt, mk_subty};
+import middle::typeck::infer::{infer_ctxt, can_mk_subty};
import middle::typeck::infer::{new_infer_ctxt, resolve_ivar, resolve_type};
import syntax::ast::{crate, def_id, def_mod};
import syntax::ast::{item, item_class, item_const, item_enum, item_fn};
@@ -387,18 +387,22 @@ struct CoherenceChecker {
let monotype_a = self.universally_quantify_polytype(polytype_a);
let monotype_b = self.universally_quantify_polytype(polytype_b);
- return
- mk_subty(self.inference_context, monotype_a, monotype_b).is_ok()
- || mk_subty(self.inference_context, monotype_b, monotype_a).is_ok();
+ return can_mk_subty(self.inference_context,
+ monotype_a, monotype_b).is_ok()
+ || can_mk_subty(self.inference_context,
+ monotype_b, monotype_a).is_ok();
}
// Converts a polytype to a monotype by replacing all parameters with
// type variables.
fn universally_quantify_polytype(polytype: ty_param_bounds_and_ty) -> t {
- let self_region =
- if !polytype.rp {none}
- else {some(self.inference_context.next_region_var_nb())};
+ // NDM--this span is bogus.
+ let self_region = if !polytype.rp {
+ none
+ } else {
+ some(self.inference_context.next_region_var_nb(dummy_sp()))
+ };
let bounds_count = polytype.bounds.len();
let type_parameters =
diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs
index c98746f945a62..18f17c18725c2 100644
--- a/src/rustc/middle/typeck/collect.rs
+++ b/src/rustc/middle/typeck/collect.rs
@@ -298,7 +298,7 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span,
ty::subst(tcx, &substs, trait_fty)
};
require_same_types(
- tcx, none, sp, impl_fty, trait_fty,
+ tcx, none, false, sp, impl_fty, trait_fty,
|| ~"method `" + *trait_m.ident + ~"` has an incompatible type");
return;
diff --git a/src/rustc/middle/typeck/infer.rs b/src/rustc/middle/typeck/infer.rs
index d2f799ff4f780..3620a728d6bd4 100644
--- a/src/rustc/middle/typeck/infer.rs
+++ b/src/rustc/middle/typeck/infer.rs
@@ -1,4 +1,4 @@
-/*
+/*!
# Type inference engine
@@ -263,6 +263,20 @@ import util::common::{indent, indenter};
import ast::{unsafe_fn, impure_fn, pure_fn, extern_fn};
import ast::{m_const, m_imm, m_mutbl};
import dvec::{DVec, dvec};
+import region_var_bindings::{RegionVarBindings};
+import ast_util::dummy_sp;
+
+// From submodules:
+import resolve::{resolve_nested_tvar, resolve_rvar, resolve_ivar, resolve_all,
+ force_tvar, force_rvar, force_ivar, force_all, not_regions,
+ resolve_and_force_all_but_regions, resolver};
+import unify::{vals_and_bindings, root};
+import integral::{int_ty_set, int_ty_set_all};
+import combine::{combine_fields, eq_tys};
+
+import sub::Sub;
+import lub::Lub;
+import glb::Glb;
export infer_ctxt;
export new_infer_ctxt;
@@ -272,86 +286,16 @@ export mk_eqty;
export mk_assignty, can_mk_assignty;
export resolve_nested_tvar, resolve_rvar, resolve_ivar, resolve_all;
export force_tvar, force_rvar, force_ivar, force_all;
+export resolve_and_force_all_but_regions, not_regions;
export resolve_type, resolve_region;
export resolve_borrowings;
export methods; // for infer_ctxt
export unify_methods; // for infer_ctxt
-export fres, fixup_err, fixup_err_to_str;
+export cres, fres, fixup_err, fixup_err_to_str;
export assignment;
export root, to_str;
export int_ty_set_all;
-// Bitvector to represent sets of integral types
-enum int_ty_set = uint;
-
-// Constants representing singleton sets containing each of the
-// integral types
-const INT_TY_SET_EMPTY : uint = 0b00_0000_0000u;
-const INT_TY_SET_i8 : uint = 0b00_0000_0001u;
-const INT_TY_SET_u8 : uint = 0b00_0000_0010u;
-const INT_TY_SET_i16 : uint = 0b00_0000_0100u;
-const INT_TY_SET_u16 : uint = 0b00_0000_1000u;
-const INT_TY_SET_i32 : uint = 0b00_0001_0000u;
-const INT_TY_SET_u32 : uint = 0b00_0010_0000u;
-const INT_TY_SET_i64 : uint = 0b00_0100_0000u;
-const INT_TY_SET_u64 : uint = 0b00_1000_0000u;
-const INT_TY_SET_i : uint = 0b01_0000_0000u;
-const INT_TY_SET_u : uint = 0b10_0000_0000u;
-
-fn int_ty_set_all() -> int_ty_set {
- int_ty_set(INT_TY_SET_i8 | INT_TY_SET_u8 |
- INT_TY_SET_i16 | INT_TY_SET_u16 |
- INT_TY_SET_i32 | INT_TY_SET_u32 |
- INT_TY_SET_i64 | INT_TY_SET_u64 |
- INT_TY_SET_i | INT_TY_SET_u)
-}
-
-fn intersection(a: int_ty_set, b: int_ty_set) -> int_ty_set {
- int_ty_set(*a & *b)
-}
-
-fn single_type_contained_in(tcx: ty::ctxt, a: int_ty_set) ->
- option {
- debug!{"single_type_contained_in(a=%s)", uint::to_str(*a, 10u)};
-
- if *a == INT_TY_SET_i8 { return some(ty::mk_i8(tcx)); }
- if *a == INT_TY_SET_u8 { return some(ty::mk_u8(tcx)); }
- if *a == INT_TY_SET_i16 { return some(ty::mk_i16(tcx)); }
- if *a == INT_TY_SET_u16 { return some(ty::mk_u16(tcx)); }
- if *a == INT_TY_SET_i32 { return some(ty::mk_i32(tcx)); }
- if *a == INT_TY_SET_u32 { return some(ty::mk_u32(tcx)); }
- if *a == INT_TY_SET_i64 { return some(ty::mk_i64(tcx)); }
- if *a == INT_TY_SET_u64 { return some(ty::mk_u64(tcx)); }
- if *a == INT_TY_SET_i { return some(ty::mk_int(tcx)); }
- if *a == INT_TY_SET_u { return some(ty::mk_uint(tcx)); }
- return none;
-}
-
-fn convert_integral_ty_to_int_ty_set(tcx: ty::ctxt, t: ty::t)
- -> int_ty_set {
-
- match get(t).struct {
- ty_int(int_ty) => match int_ty {
- ast::ty_i8 => int_ty_set(INT_TY_SET_i8),
- ast::ty_i16 => int_ty_set(INT_TY_SET_i16),
- ast::ty_i32 => int_ty_set(INT_TY_SET_i32),
- ast::ty_i64 => int_ty_set(INT_TY_SET_i64),
- ast::ty_i => int_ty_set(INT_TY_SET_i),
- ast::ty_char => tcx.sess.bug(
- ~"char type passed to convert_integral_ty_to_int_ty_set()")
- },
- ty_uint(uint_ty) => match uint_ty {
- ast::ty_u8 => int_ty_set(INT_TY_SET_u8),
- ast::ty_u16 => int_ty_set(INT_TY_SET_u16),
- ast::ty_u32 => int_ty_set(INT_TY_SET_u32),
- ast::ty_u64 => int_ty_set(INT_TY_SET_u64),
- ast::ty_u => int_ty_set(INT_TY_SET_u)
- },
- _ => tcx.sess.bug(~"non-integral type passed to \
- convert_integral_ty_to_int_ty_set()")
- }
-}
-
// 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
@@ -365,21 +309,7 @@ type assignment = {
type bound = option;
type bounds = {lb: bound, ub: bound};
-enum var_value {
- redirect(V),
- root(T, uint),
-}
-
-struct vals_and_bindings {
- vals: smallintmap>;
- mut bindings: ~[(V, var_value)];
-}
-
-struct node {
- root: V;
- possible_types: T;
- rank: uint;
-}
+type cres = result;
enum infer_ctxt = @{
tcx: ty::ctxt,
@@ -394,8 +324,7 @@ enum infer_ctxt = @{
ty_var_integral_bindings: vals_and_bindings,
// For region variables.
- region_var_bindings: vals_and_bindings>,
+ region_vars: RegionVarBindings,
// For keeping track of existing type and region variables.
ty_var_counter: @mut uint,
@@ -443,39 +372,65 @@ fn new_infer_ctxt(tcx: ty::ctxt) -> infer_ctxt {
infer_ctxt(@{tcx: tcx,
ty_var_bindings: new_vals_and_bindings(),
ty_var_integral_bindings: new_vals_and_bindings(),
- region_var_bindings: new_vals_and_bindings(),
+ region_vars: RegionVarBindings(tcx),
ty_var_counter: @mut 0u,
ty_var_integral_counter: @mut 0u,
region_var_counter: @mut 0u,
borrowings: dvec()})}
-fn mk_subty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
+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})
+}
+
+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)};
- indent(|| cx.commit(|| (&sub(cx)).tys(a, b) ) ).to_ures()
+ do indent {
+ do cx.commit {
+ mk_sub(cx, a_is_expected, span).tys(a, b)
+ }
+ }.to_ures()
}
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)};
- indent(|| cx.probe(|| (&sub(cx)).tys(a, b) ) ).to_ures()
+ do indent {
+ do cx.probe {
+ mk_sub(cx, true, ast_util::dummy_sp()).tys(a, b)
+ }
+ }.to_ures()
}
-fn mk_subr(cx: infer_ctxt, a: ty::region, b: ty::region) -> ures {
+fn mk_subr(cx: infer_ctxt, a_is_expected: bool, span: span,
+ a: ty::region, b: ty::region) -> ures {
debug!{"mk_subr(%s <: %s)", a.to_str(cx), b.to_str(cx)};
- indent(|| cx.commit(|| (&sub(cx)).regions(a, b) ) ).to_ures()
+ do indent {
+ do cx.commit {
+ mk_sub(cx, a_is_expected, span).regions(a, b)
+ }
+ }.to_ures()
}
-fn mk_eqty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
+fn mk_eqty(cx: infer_ctxt, a_is_expected: bool, span: span,
+ a: ty::t, b: ty::t) -> ures {
debug!{"mk_eqty(%s <: %s)", a.to_str(cx), b.to_str(cx)};
- indent(|| cx.commit(|| cx.eq_tys(a, b) ) ).to_ures()
+ do indent {
+ do cx.commit {
+ let suber = mk_sub(cx, 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)};
- indent(|| cx.commit(||
- cx.assign_tys(anmnt, a, b)
- ) ).to_ures()
+ do indent {
+ do cx.commit {
+ cx.assign_tys(anmnt, a, b)
+ }
+ }.to_ures()
}
fn can_mk_assignty(cx: infer_ctxt, anmnt: &assignment,
@@ -561,156 +516,100 @@ impl cres: cres_helpers {
}
}
-trait to_str {
- fn to_str(cx: infer_ctxt) -> ~str;
-}
-
-impl ty::t: to_str {
- fn to_str(cx: infer_ctxt) -> ~str {
- ty_to_str(cx.tcx, self)
- }
-}
-
-impl ty::mt: to_str {
- fn to_str(cx: infer_ctxt) -> ~str {
- mt_to_str(cx.tcx, self)
- }
+fn uok() -> ures {
+ ok(())
}
-impl ty::region: to_str {
- fn to_str(cx: infer_ctxt) -> ~str {
- util::ppaux::region_to_str(cx.tcx, self)
- }
-}
+fn rollback_to(
+ vb: &vals_and_bindings, len: uint) {
-impl bound: to_str {
- fn to_str(cx: infer_ctxt) -> ~str {
- match self {
- some(v) => v.to_str(cx),
- none => ~"none"
- }
+ while vb.bindings.len() != len {
+ let (vid, old_v) = vec::pop(vb.bindings);
+ vb.vals.insert(vid.to_uint(), old_v);
}
}
-impl bounds: to_str {
- fn to_str(cx: infer_ctxt) -> ~str {
- fmt!{"{%s <: %s}",
- self.lb.to_str(cx),
- self.ub.to_str(cx)}
- }
+struct Snapshot {
+ ty_var_bindings_len: uint;
+ ty_var_integral_bindings_len: uint;
+ region_vars_snapshot: uint;
+ borrowings_len: uint;
}
-impl int_ty_set: to_str {
- fn to_str(_cx: infer_ctxt) -> ~str {
- match self {
- int_ty_set(v) => uint::to_str(v, 10u)
- }
+impl infer_ctxt {
+ fn in_snapshot() -> bool {
+ self.region_vars.in_snapshot()
}
-}
-impl var_value: to_str {
- fn to_str(cx: infer_ctxt) -> ~str {
- match self {
- redirect(vid) => fmt!{"redirect(%s)", vid.to_str()},
- root(pt, rk) => fmt!{"root(%s, %s)", pt.to_str(cx),
- uint::to_str(rk, 10u)}
+ fn start_snapshot() -> Snapshot {
+ Snapshot {
+ ty_var_bindings_len:
+ self.ty_var_bindings.bindings.len(),
+ ty_var_integral_bindings_len:
+ self.ty_var_integral_bindings.bindings.len(),
+ region_vars_snapshot:
+ self.region_vars.start_snapshot(),
+ borrowings_len:
+ self.borrowings.len()
}
}
-}
-
-trait st {
- fn sub(infcx: infer_ctxt, b: self) -> ures;
- fn lub(infcx: infer_ctxt, b: self) -> cres;
- fn glb(infcx: infer_ctxt, b: self) -> cres;
-}
-
-impl ty::t: st {
- fn sub(infcx: infer_ctxt, &&b: ty::t) -> ures {
- (&sub(infcx)).tys(self, b).to_ures()
- }
-
- fn lub(infcx: infer_ctxt, &&b: ty::t) -> cres {
- (&lub(infcx)).tys(self, b)
- }
-
- fn glb(infcx: infer_ctxt, &&b: ty::t) -> cres {
- (&glb(infcx)).tys(self, b)
- }
-}
-
-impl ty::region: st {
- fn sub(infcx: infer_ctxt, &&b: ty::region) -> ures {
- (&sub(infcx)).regions(self, b).chain(|_r| ok(()))
- }
-
- fn lub(infcx: infer_ctxt, &&b: ty::region) -> cres {
- (&lub(infcx)).regions(self, b)
- }
- fn glb(infcx: infer_ctxt, &&b: ty::region) -> cres {
- (&glb(infcx)).regions(self, b)
- }
-}
-
-fn uok() -> ures {
- ok(())
-}
+ fn rollback_to(snapshot: &Snapshot) {
+ debug!("rollback!");
+ rollback_to(&self.ty_var_bindings, snapshot.ty_var_bindings_len);
-fn rollback_to(
- vb: &vals_and_bindings, len: uint) {
+ // FIXME(#3211) -- ty_var_integral not transactional
+ //rollback_to(&self.ty_var_integral_bindings,
+ // snapshot.ty_var_integral_bindings_len);
- while vb.bindings.len() != len {
- let (vid, old_v) = vec::pop(vb.bindings);
- vb.vals.insert(vid.to_uint(), old_v);
+ self.region_vars.rollback_to(
+ snapshot.region_vars_snapshot);
+ while self.borrowings.len() != snapshot.borrowings_len {
+ self.borrowings.pop();
+ }
}
-}
-impl infer_ctxt {
/// Execute `f` and commit the bindings if successful
fn commit(f: fn() -> result) -> result {
+ assert !self.in_snapshot();
- assert self.ty_var_bindings.bindings.len() == 0u;
- assert self.region_var_bindings.bindings.len() == 0u;
-
- let r <- self.try(f);
-
- // FIXME (#2814)---could use a vec::clear() that ran destructors but
- // kept the vec at its currently allocated length
- self.ty_var_bindings.bindings = ~[];
- self.region_var_bindings.bindings = ~[];
+ debug!{"commit()"};
+ do indent {
+ let r <- self.try(f);
- return r;
+ // FIXME (#2814)---could use a vec::clear() that ran
+ // destructors but kept the vec at its currently allocated
+ // length
+ self.ty_var_bindings.bindings = ~[];
+ self.ty_var_integral_bindings.bindings = ~[];
+ self.region_vars.commit();
+ r
+ }
}
/// Execute `f`, unroll bindings on failure
fn try(f: fn() -> result) -> result {
-
- let tvbl = self.ty_var_bindings.bindings.len();
- let rbl = self.region_var_bindings.bindings.len();
- let bl = self.borrowings.len();
-
- debug!{"try(tvbl=%u, rbl=%u)", tvbl, rbl};
- let r <- f();
- match r {
- result::ok(_) => debug!{"try--ok"},
- result::err(_) => {
- debug!{"try--rollback"};
- rollback_to(&self.ty_var_bindings, tvbl);
- rollback_to(&self.region_var_bindings, rbl);
- while self.borrowings.len() != bl { self.borrowings.pop(); }
- }
+ debug!{"try()"};
+ do indent {
+ let snapshot = self.start_snapshot();
+ let r = f();
+ match r {
+ ok(_) => (),
+ err(_) => self.rollback_to(&snapshot)
+ }
+ r
}
- return r;
}
/// Execute `f` then unroll any bindings it creates
fn probe(f: fn() -> result) -> result {
- assert self.ty_var_bindings.bindings.len() == 0u;
- assert self.region_var_bindings.bindings.len() == 0u;
- let r <- f();
- rollback_to(&self.ty_var_bindings, 0u);
- rollback_to(&self.region_var_bindings, 0u);
- return r;
+ debug!{"probe()"};
+ do indent {
+ let snapshot = self.start_snapshot();
+ let r = self.try(f);
+ self.rollback_to(&snapshot);
+ r
+ }
}
}
@@ -719,7 +618,7 @@ impl infer_ctxt {
let id = *self.ty_var_counter;
*self.ty_var_counter += 1u;
self.ty_var_bindings.vals.insert(id,
- root({lb: none, ub: none}, 0u));
+ root({lb: none, ub: none}, 0u));
return tv_vid(id);
}
@@ -744,24 +643,28 @@ impl infer_ctxt {
ty::mk_var_integral(self.tcx, self.next_ty_var_integral_id())
}
- fn next_region_var_id(bnds: bounds) -> region_vid {
- let id = *self.region_var_counter;
- *self.region_var_counter += 1u;
- self.region_var_bindings.vals.insert(id, root(bnds, 0));
- return region_vid(id);
+ fn next_region_var_nb(span: span) -> ty::region {
+ ty::re_var(self.region_vars.new_region_var(span))
}
- fn next_region_var_with_scope_lb(scope_id: ast::node_id) -> ty::region {
- self.next_region_var({lb: some(ty::re_scope(scope_id)),
- ub: none})
+ fn next_region_var_with_lb(span: span,
+ lb_region: ty::region) -> ty::region {
+ let region_var = self.next_region_var_nb(span);
+
+ // add lb_region as a lower bound on the newly built variable
+ assert self.region_vars.make_subregion(span,
+ lb_region,
+ region_var).is_ok();
+
+ return region_var;
}
- fn next_region_var(bnds: bounds) -> ty::region {
- ty::re_var(self.next_region_var_id(bnds))
+ fn next_region_var(span: span, scope_id: ast::node_id) -> ty::region {
+ self.next_region_var_with_lb(span, ty::re_scope(scope_id))
}
- fn next_region_var_nb() -> ty::region { // nb == "no bounds"
- self.next_region_var({lb: none, ub: none})
+ fn resolve_regions() {
+ self.region_vars.resolve_regions();
}
fn ty_to_str(t: ty::t) -> ~str {
@@ -770,1993 +673,10 @@ impl infer_ctxt {
}
fn resolve_type_vars_if_possible(typ: ty::t) -> ty::t {
- match resolve_type(self, typ, resolve_all) {
- result::ok(new_type) => return new_type,
- result::err(_) => return typ
- }
- }
-
- fn resolve_region_if_possible(oldr: ty::region) -> ty::region {
- match resolve_region(self, oldr, resolve_all) {
- result::ok(newr) => return newr,
- result::err(_) => return oldr
- }
- }
-}
-
-impl infer_ctxt {
-
- fn set(
- vb: &vals_and_bindings, vid: V,
- +new_v: var_value) {
-
- let old_v = vb.vals.get(vid.to_uint());
- vec::push(vb.bindings, (vid, old_v));
- vb.vals.insert(vid.to_uint(), new_v);
-
- debug!{"Updating variable %s from %s to %s",
- vid.to_str(), old_v.to_str(self), new_v.to_str(self)};
- }
-
- fn get(
- vb: &vals_and_bindings, vid: V)
- -> node {
-
- let vid_u = vid.to_uint();
- match vb.vals.find(vid_u) {
- none => {
- self.tcx.sess.bug(fmt!{"failed lookup of vid `%u`", vid_u});
- }
- some(var_val) => {
- match var_val {
- redirect(vid) => {
- let node = self.get(vb, vid);
- if node.root != vid {
- // Path compression
- vb.vals.insert(vid.to_uint(), redirect(node.root));
- }
- node
- }
- root(pt, rk) => {
- node {root: vid, possible_types: pt, rank: rk}
- }
- }
- }
- }
- }
-
- // Combines the two bounds into a more general bound.
- fn merge_bnd(
- a: bound, b: bound,
- merge_op: fn(V,V) -> cres) -> cres> {
-
- debug!{"merge_bnd(%s,%s)", a.to_str(self), b.to_str(self)};
- let _r = indenter();
-
- match (a, b) {
- (none, none) => ok(none),
- (some(_), none) => ok(a),
- (none, some(_)) => ok(b),
- (some(v_a), some(v_b)) => {
- do merge_op(v_a, v_b).chain |v| {
- ok(some(v))
- }
- }
- }
- }
-
- fn merge_bnds(
- a: bounds, b: bounds,
- lub: fn(V,V) -> cres,
- glb: fn(V,V) -> cres) -> cres> {
-
- let _r = indenter();
- do self.merge_bnd(a.ub, b.ub, glb).chain |ub| {
- debug!{"glb of ubs %s and %s is %s",
- a.ub.to_str(self), b.ub.to_str(self),
- ub.to_str(self)};
- do self.merge_bnd(a.lb, b.lb, lub).chain |lb| {
- debug!{"lub of lbs %s and %s is %s",
- a.lb.to_str(self), b.lb.to_str(self),
- lb.to_str(self)};
- ok({lb: lb, ub: ub})
- }
- }
- }
-
- // Updates the bounds for the variable `v_id` to be the intersection
- // of `a` and `b`. That is, the new bounds for `v_id` will be
- // a bounds c such that:
- // c.ub <: a.ub
- // c.ub <: b.ub
- // a.lb <: c.lb
- // b.lb <: c.lb
- // If this cannot be achieved, the result is failure.
-
- fn set_var_to_merged_bounds(
- vb: &vals_and_bindings>,
- v_id: V, a: bounds, b: bounds, rank: uint) -> ures {
-
- // Think of the two diamonds, we want to find the
- // intersection. There are basically four possibilities (you
- // can swap A/B in these pictures):
- //
- // A A
- // / \ / \
- // / B \ / B \
- // / / \ \ / / \ \
- // * * * * * / * *
- // \ \ / / \ / /
- // \ B / / \ / /
- // \ / * \ /
- // A \ / A
- // B
-
- debug!{"merge(%s,%s,%s)",
- v_id.to_str(),
- a.to_str(self),
- b.to_str(self)};
-
- // First, relate the lower/upper bounds of A and B.
- // Note that these relations *must* hold for us to
- // to be able to merge A and B at all, and relating
- // them explicitly gives the type inferencer more
- // information and helps to produce tighter bounds
- // when necessary.
- do indent {
- do self.bnds(a.lb, b.ub).then {
- do self.bnds(b.lb, a.ub).then {
- do self.merge_bnd(a.ub, b.ub, |x, y| x.glb(self, y) ).chain |ub| {
- do self.merge_bnd(a.lb, b.lb, |x, y| x.lub(self, y) ).chain |lb| {
- let bnds = {lb: lb, ub: ub};
- debug!{"merge(%s): bnds=%s",
- v_id.to_str(),
- bnds.to_str(self)};
-
- // the new bounds must themselves
- // be relatable:
- do self.bnds(bnds.lb, bnds.ub).then {
- self.set(vb, v_id, root(bnds, rank));
- uok()
- }
- }}}}}
- }
-
- /// Ensure that variable A is a subtype of variable B. This is a
- /// subtle and tricky process, as described in detail at the top
- /// of this file.
- fn var_sub_var(
- vb: &vals_and_bindings>,
- a_id: V, b_id: V) -> ures {
-
- // Need to make sub_id a subtype of sup_id.
- let nde_a = self.get(vb, a_id);
- let nde_b = self.get(vb, b_id);
- let a_id = nde_a.root;
- let b_id = nde_b.root;
- let a_bounds = nde_a.possible_types;
- let b_bounds = nde_b.possible_types;
-
- debug!{"vars(%s=%s <: %s=%s)",
- a_id.to_str(), a_bounds.to_str(self),
- b_id.to_str(), b_bounds.to_str(self)};
-
- if a_id == b_id { return uok(); }
-
- // If both A's UB and B's LB have already been bound to types,
- // see if we can make those types subtypes.
- match (a_bounds.ub, b_bounds.lb) {
- (some(a_ub), some(b_lb)) => {
- let r = self.try(|| a_ub.sub(self, b_lb));
- match r {
- ok(()) => return result::ok(()),
- err(_) => { /*fallthrough */ }
- }
- }
- _ => { /*fallthrough*/ }
- }
-
- // Otherwise, we need to merge A and B so as to guarantee that
- // A remains a subtype of B. Actually, there are other options,
- // but that's the route we choose to take.
-
- // Rank optimization
-
- // Make the node with greater rank the parent of the node with
- // smaller rank.
- if nde_a.rank > nde_b.rank {
- debug!{"vars(): a has smaller rank"};
- // a has greater rank, so a should become b's parent,
- // i.e., b should redirect to a.
- self.set(vb, b_id, redirect(a_id));
- self.set_var_to_merged_bounds(
- vb, a_id, a_bounds, b_bounds, nde_a.rank).then(|| uok() )
- } else if nde_a.rank < nde_b.rank {
- debug!{"vars(): b has smaller rank"};
- // b has greater rank, so a should redirect to b.
- self.set(vb, a_id, redirect(b_id));
- self.set_var_to_merged_bounds(
- vb, b_id, a_bounds, b_bounds, nde_b.rank).then(|| uok() )
- } else {
- debug!{"vars(): a and b have equal rank"};
- assert nde_a.rank == nde_b.rank;
- // If equal, just redirect one to the other and increment
- // the other's rank. We choose arbitrarily to redirect b
- // to a and increment a's rank.
- self.set(vb, b_id, redirect(a_id));
- self.set_var_to_merged_bounds(
- vb, a_id, a_bounds, b_bounds, nde_a.rank + 1u
- ).then(|| uok() )
- }
- }
-
- fn vars_integral(
- vb: &vals_and_bindings,
- a_id: V, b_id: V) -> ures {
-
- let nde_a = self.get(vb, a_id);
- let nde_b = self.get(vb, b_id);
- let a_id = nde_a.root;
- let b_id = nde_b.root;
- let a_pt = nde_a.possible_types;
- let b_pt = nde_b.possible_types;
-
- // If we're already dealing with the same two variables,
- // there's nothing to do.
- if a_id == b_id { return uok(); }
-
- // Otherwise, take the intersection of the two sets of
- // possible types.
- let intersection = intersection(a_pt, b_pt);
- if *intersection == INT_TY_SET_EMPTY {
- return err(ty::terr_no_integral_type);
- }
-
- // Rank optimization
- if nde_a.rank > nde_b.rank {
- debug!{"vars_integral(): a has smaller rank"};
- // a has greater rank, so a should become b's parent,
- // i.e., b should redirect to a.
- self.set(vb, a_id, root(intersection, nde_a.rank));
- self.set(vb, b_id, redirect(a_id));
- } else if nde_a.rank < nde_b.rank {
- debug!{"vars_integral(): b has smaller rank"};
- // b has greater rank, so a should redirect to b.
- self.set(vb, b_id, root(intersection, nde_b.rank));
- self.set(vb, a_id, redirect(b_id));
- } else {
- debug!{"vars_integral(): a and b have equal rank"};
- assert nde_a.rank == nde_b.rank;
- // If equal, just redirect one to the other and increment
- // the other's rank. We choose arbitrarily to redirect b
- // to a and increment a's rank.
- self.set(vb, a_id, root(intersection, nde_a.rank + 1u));
- self.set(vb, b_id, redirect(a_id));
- };
-
- uok()
- }
-
- /// make variable a subtype of T
- fn var_sub_t(
- vb: &vals_and_bindings>,
- a_id: V, b: T) -> ures {
-
- let nde_a = self.get(vb, a_id);
- let a_id = nde_a.root;
- let a_bounds = nde_a.possible_types;
-
- debug!{"var_sub_t(%s=%s <: %s)",
- a_id.to_str(), a_bounds.to_str(self),
- b.to_str(self)};
- let b_bounds = {lb: none, ub: some(b)};
- self.set_var_to_merged_bounds(vb, a_id, a_bounds, b_bounds,
- nde_a.rank)
- }
-
- fn var_integral_sub_t(
- vb: &vals_and_bindings,
- a_id: V, b: ty::t) -> ures {
-
- assert ty::type_is_integral(b);
-
- let nde_a = self.get(vb, a_id);
- let a_id = nde_a.root;
- let a_pt = nde_a.possible_types;
-
- let intersection =
- intersection(a_pt, convert_integral_ty_to_int_ty_set(
- self.tcx, b));
- if *intersection == INT_TY_SET_EMPTY {
- return err(ty::terr_no_integral_type);
- }
- self.set(vb, a_id, root(intersection, nde_a.rank));
- uok()
- }
-
- /// make T a subtype of variable
- fn t_sub_var(
- vb: &vals_and_bindings>,
- a: T, b_id: V) -> ures {
-
- let a_bounds = {lb: some(a), ub: none};
- let nde_b = self.get(vb, b_id);
- let b_id = nde_b.root;
- let b_bounds = nde_b.possible_types;
-
- debug!{"t_sub_var(%s <: %s=%s)",
- a.to_str(self),
- b_id.to_str(), b_bounds.to_str(self)};
- self.set_var_to_merged_bounds(vb, b_id, a_bounds, b_bounds,
- nde_b.rank)
- }
-
- fn t_sub_var_integral(
- vb: &vals_and_bindings,
- a: ty::t, b_id: V) -> ures {
-
- assert ty::type_is_integral(a);
-
- let nde_b = self.get(vb, b_id);
- let b_id = nde_b.root;
- let b_pt = nde_b.possible_types;
-
- let intersection =
- intersection(b_pt, convert_integral_ty_to_int_ty_set(
- self.tcx, a));
- if *intersection == INT_TY_SET_EMPTY {
- return err(ty::terr_no_integral_type);
- }
- self.set(vb, b_id, root(intersection, nde_b.rank));
- uok()
- }
-
- fn bnds(
- a: bound, b: bound) -> ures {
-
- debug!{"bnds(%s <: %s)", a.to_str(self), b.to_str(self)};
- do indent {
- match (a, b) {
- (none, none) |
- (some(_), none) |
- (none, some(_)) => {
- uok()
- }
- (some(t_a), some(t_b)) => {
- t_a.sub(self, t_b)
- }
- }
- }
- }
-
- fn sub_tys(a: ty::t, b: ty::t) -> ures {
- (&sub(self)).tys(a, b).chain(|_t| ok(()) )
- }
-
- fn sub_regions(a: ty::region, b: ty::region) -> ures {
- (&sub(self)).regions(a, b).chain(|_t| ok(()) )
- }
-
- fn eq_tys(a: ty::t, b: ty::t) -> ures {
- self.sub_tys(a, b).then(|| {
- self.sub_tys(b, a)
- })
- }
-
- fn eq_regions(a: ty::region, b: ty::region) -> ures {
- debug!{"eq_regions(%s, %s)",
- a.to_str(self), b.to_str(self)};
- do indent {
- self.try(|| {
- do self.sub_regions(a, b).then {
- self.sub_regions(b, a)
- }
- }).chain_err(|e| {
- // substitute a better error, but use the regions
- // found in the original error
- match e {
- ty::terr_regions_does_not_outlive(a1, b1) =>
- err(ty::terr_regions_not_same(a1, b1)),
- _ => err(e)
- }
- })
- }
- }
-}
-
-// Resolution is the process of removing type variables and replacing
-// them with their inferred values. Unfortunately our inference has
-// become fairly complex and so there are a number of options to
-// control *just how much* you want to resolve and how you want to do
-// it.
-//
-// # Controlling the scope of resolution
-//
-// The options resolve_* determine what kinds of variables get
-// resolved. Generally resolution starts with a top-level type
-// variable; we will always resolve this. However, once we have
-// resolved that variable, we may end up with a type that still
-// contains type variables. For example, if we resolve `` we may
-// end up with something like `[]`. If the option
-// `resolve_nested_tvar` is passed, we will then go and recursively
-// resolve ``.
-//
-// The options `resolve_rvar` and `resolve_ivar` control whether we
-// resolve region and integral variables, respectively.
-//
-// # What do if things are unconstrained
-//
-// Sometimes we will encounter a variable that has no constraints, and
-// therefore cannot sensibly be mapped to any particular result. By
-// default, we will leave such variables as is (so you will get back a
-// variable in your result). The options force_* will cause the
-// resolution to fail in this case intead, except for the case of
-// integral variables, which resolve to `int` if forced.
-//
-// # resolve_all and force_all
-//
-// The options are a bit set, so you can use the *_all to resolve or
-// force all kinds of variables (including those we may add in the
-// future). If you want to resolve everything but one type, you are
-// probably better off writing `resolve_all - resolve_ivar`.
-
-const resolve_nested_tvar: uint = 0b00000001;
-const resolve_rvar: uint = 0b00000010;
-const resolve_ivar: uint = 0b00000100;
-const resolve_all: uint = 0b00000111;
-const force_tvar: uint = 0b00010000;
-const force_rvar: uint = 0b00100000;
-const force_ivar: uint = 0b01000000;
-const force_all: uint = 0b01110000;
-
-type resolve_state_ = {
- infcx: infer_ctxt,
- modes: uint,
- mut err: option,
- mut v_seen: ~[tv_vid]
-};
-
-enum resolve_state {
- resolve_state_(@resolve_state_)
-}
-
-fn resolver(infcx: infer_ctxt, modes: uint) -> resolve_state {
- resolve_state_(@{infcx: infcx,
- modes: modes,
- mut err: none,
- mut v_seen: ~[]})
-}
-
-impl resolve_state {
- fn should(mode: uint) -> bool {
- (self.modes & mode) == mode
- }
-
- fn resolve_type_chk(typ: ty::t) -> fres {
- self.err = none;
-
- debug!{"Resolving %s (modes=%x)",
- ty_to_str(self.infcx.tcx, typ),
- self.modes};
-
- // n.b. This is a hokey mess because the current fold doesn't
- // allow us to pass back errors in any useful way.
-
- assert vec::is_empty(self.v_seen);
- let rty = indent(|| self.resolve_type(typ) );
- assert vec::is_empty(self.v_seen);
- match self.err {
- none => {
- debug!{"Resolved to %s (modes=%x)",
- ty_to_str(self.infcx.tcx, rty),
- self.modes};
- return ok(rty);
- }
- some(e) => return err(e)
- }
- }
-
- fn resolve_region_chk(orig: ty::region) -> fres {
- self.err = none;
- let resolved = indent(|| self.resolve_region(orig) );
- match self.err {
- none => ok(resolved),
- some(e) => err(e)
- }
- }
-
- fn resolve_type(typ: ty::t) -> ty::t {
- debug!{"resolve_type(%s)", typ.to_str(self.infcx)};
- indent(fn&() -> ty::t {
- if !ty::type_needs_infer(typ) { return typ; }
-
- match ty::get(typ).struct {
- ty::ty_var(vid) => {
- self.resolve_ty_var(vid)
- }
- ty::ty_var_integral(vid) => {
- self.resolve_ty_var_integral(vid)
- }
- _ => {
- if !self.should(resolve_rvar) &&
- !self.should(resolve_nested_tvar) {
- // shortcircuit for efficiency
- typ
- } else {
- ty::fold_regions_and_ty(
- self.infcx.tcx, typ,
- |r| self.resolve_region(r),
- |t| self.resolve_nested_tvar(t),
- |t| self.resolve_nested_tvar(t))
- }
- }
- }
- })
- }
-
- fn resolve_nested_tvar(typ: ty::t) -> ty::t {
- debug!{"Resolve_if_deep(%s)", typ.to_str(self.infcx)};
- if !self.should(resolve_nested_tvar) {
- typ
- } else {
- self.resolve_type(typ)
- }
- }
-
- fn resolve_region(orig: ty::region) -> ty::region {
- debug!{"Resolve_region(%s)", orig.to_str(self.infcx)};
- match orig {
- ty::re_var(rid) => self.resolve_region_var(rid),
- _ => orig
- }
- }
-
- fn resolve_region_var(rid: region_vid) -> ty::region {
- if !self.should(resolve_rvar) {
- return ty::re_var(rid)
- }
- let nde = self.infcx.get(&self.infcx.region_var_bindings, rid);
- let bounds = nde.possible_types;
- match bounds {
- { ub:_, lb:some(r) } => { self.assert_not_rvar(rid, r); r }
- { ub:some(r), lb:_ } => { self.assert_not_rvar(rid, r); r }
- { ub:none, lb:none } => {
- if self.should(force_rvar) {
- self.err = some(unresolved_region(rid));
- }
- ty::re_var(rid)
- }
- }
- }
-
- fn assert_not_rvar(rid: region_vid, r: ty::region) {
- match r {
- ty::re_var(rid2) => {
- self.err = some(region_var_bound_by_region_var(rid, rid2));
- }
- _ => { }
- }
- }
-
- fn resolve_ty_var(vid: tv_vid) -> ty::t {
- if vec::contains(self.v_seen, vid) {
- self.err = some(cyclic_ty(vid));
- return ty::mk_var(self.infcx.tcx, vid);
- } else {
- vec::push(self.v_seen, vid);
- let tcx = self.infcx.tcx;
-
- // Nonobvious: prefer the most specific type
- // (i.e., the lower bound) to the more general
- // one. More general types in Rust (e.g., fn())
- // tend to carry more restrictions or higher
- // perf. penalties, so it pays to know more.
-
- let nde = self.infcx.get(&self.infcx.ty_var_bindings, vid);
- let bounds = nde.possible_types;
-
- let t1 = match bounds {
- { ub:_, lb:some(t) } if !type_is_bot(t) => self.resolve_type(t),
- { ub:some(t), lb:_ } => self.resolve_type(t),
- { ub:_, lb:some(t) } => self.resolve_type(t),
- { ub:none, lb:none } => {
- if self.should(force_tvar) {
- self.err = some(unresolved_ty(vid));
- }
- ty::mk_var(tcx, vid)
- }
- };
- vec::pop(self.v_seen);
- return t1;
- }
- }
-
- fn resolve_ty_var_integral(vid: tvi_vid) -> ty::t {
- if !self.should(resolve_ivar) {
- return ty::mk_var_integral(self.infcx.tcx, vid);
- }
-
- let nde = self.infcx.get(&self.infcx.ty_var_integral_bindings, vid);
- let pt = nde.possible_types;
-
- // If there's only one type in the set of possible types, then
- // that's the answer.
- match single_type_contained_in(self.infcx.tcx, pt) {
- some(t) => t,
- none => {
- if self.should(force_ivar) {
- // As a last resort, default to int.
- let ty = ty::mk_int(self.infcx.tcx);
- self.infcx.set(
- &self.infcx.ty_var_integral_bindings, vid,
- root(convert_integral_ty_to_int_ty_set(self.infcx.tcx,
- ty),
- nde.rank));
- ty
- } else {
- ty::mk_var_integral(self.infcx.tcx, vid)
- }
- }
- }
- }
-}
-
-// ______________________________________________________________________
-// Type assignment
-//
-// True if rvalues of type `a` can be assigned to lvalues of type `b`.
-// This may cause borrowing to the region scope enclosing `a_node_id`.
-//
-// The strategy here is somewhat non-obvious. The problem is
-// that the constraint we wish to contend with is not a subtyping
-// constraint. Currently, for variables, we only track what it
-// must be a subtype of, not what types it must be assignable to
-// (or from). Possibly, we should track that, but I leave that
-// refactoring for another day.
-//
-// Instead, we look at each variable involved and try to extract
-// *some* sort of bound. Typically, the type a is the argument
-// supplied to a call; it typically has a *lower bound* (which
-// comes from having been assigned a value). What we'd actually
-// *like* here is an upper-bound, but we generally don't have
-// one. The type b is the expected type and it typically has a
-// lower-bound too, which is good.
-//
-// The way we deal with the fact that we often don't have the
-// bounds we need is to be a bit careful. We try to get *some*
-// bound from each side, preferring the upper from a and the
-// lower from b. If we fail to get a bound from both sides, then
-// we just fall back to requiring that a <: b.
-//
-// Assuming we have a bound from both sides, we will then examine
-// these bounds and see if they have the form (@M_a T_a, &rb.M_b T_b)
-// (resp. ~M_a T_a, ~[M_a T_a], etc). If they do not, we fall back to
-// subtyping.
-//
-// If they *do*, then we know that the two types could never be
-// subtypes of one another. We will then construct a type @const T_b
-// and ensure that type a is a subtype of that. This allows for the
-// possibility of assigning from a type like (say) @~[mut T1] to a type
-// &~[T2] where T1 <: T2. This might seem surprising, since the `@`
-// points at mutable memory but the `&` points at immutable memory.
-// This would in fact be unsound, except for the borrowck, which comes
-// later and guarantees that such mutability conversions are safe.
-// See borrowck for more details. Next we require that the region for
-// the enclosing scope be a superregion of the region r.
-//
-// You might wonder why we don't make the type &e.const T_a where e is
-// the enclosing region and check that &e.const T_a <: B. The reason
-// is that the type of A is (generally) just a *lower-bound*, so this
-// would be imposing that lower-bound also as the upper-bound on type
-// A. But this upper-bound might be stricter than what is truly
-// needed.
-
-impl infer_ctxt {
- fn assign_tys(anmnt: &assignment, a: ty::t, b: ty::t) -> ures {
-
- fn select(fst: option, snd: option) -> option {
- match fst {
- some(t) => some(t),
- none => match snd {
- some(t) => some(t),
- none => none
- }
- }
- }
-
- debug!{"assign_tys(anmnt=%?, %s -> %s)",
- anmnt, a.to_str(self), b.to_str(self)};
- 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))
- }
- }
- }
-
- fn assign_tys_or_sub(
- anmnt: &assignment,
- a: ty::t, b: ty::t,
- +a_bnd: option, +b_bnd: option) -> ures {
-
- 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)};
- let _r = indenter();
-
- fn is_borrowable(v: ty::vstore) -> bool {
- match v {
- ty::vstore_fixed(_) | ty::vstore_uniq | ty::vstore_box => true,
- ty::vstore_slice(_) => false
- }
- }
-
- 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(mt_a), 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(mt_a), 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(mt_a, 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)
- }
- _ => {
- self.sub_tys(a, b)
- }
- }
- }
- _ => {
- self.sub_tys(a, b)
- }
- }
- }
-
- 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)};
-
- do indent {
- do self.sub_tys(a, nr_b).then {
- // Create a fresh region variable `r_a` with the given
- // borrow bounds:
- let r_a = self.next_region_var_with_scope_lb(anmnt.borrow_lb);
-
- debug!{"anmnt=%?", anmnt};
- do (&sub(self)).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()
- }
- }
+ match resolve_type(self, typ, resolve_nested_tvar | resolve_ivar) {
+ result::ok(new_type) => new_type,
+ result::err(_) => typ
}
}
}
-// ______________________________________________________________________
-// Type combining
-//
-// There are three type combiners: sub, lub, and glb. Each implements
-// the trait `combine` and contains methods for combining two
-// instances of various things and yielding a new instance. These
-// combiner methods always yield a `result`---failure is propagated
-// upward using `chain()` methods.
-//
-// There is a lot of common code for these operations, which is
-// abstracted out into functions named `super_X()` which take a combiner
-// instance as the first parameter. This would be better implemented
-// using traits. For this system to work properly, you should not
-// call the `super_X(foo, ...)` functions directly, but rather call
-// `foo.X(...)`. The implementation of `X()` can then choose to delegate
-// to the `super` routine or to do other things.
-//
-// In reality, the sub operation is rather different from lub/glb, but
-// they are combined into one trait to avoid duplication (they used to
-// be separate but there were many bugs because there were two copies
-// of most routines).
-//
-// The differences are:
-//
-// - when making two things have a sub relationship, the order of the
-// arguments is significant (a <: b) and the return value of the
-// combine functions is largely irrelevant. The important thing is
-// whether the action succeeds or fails. If it succeeds, then side
-// effects have been committed into the type variables.
-//
-// - for GLB/LUB, the order of arguments is not significant (GLB(a,b) ==
-// GLB(b,a)) and the return value is important (it is the GLB). Of
-// course GLB/LUB may also have side effects.
-//
-// Contravariance
-//
-// When you are relating two things which have a contravariant
-// relationship, you should use `contratys()` or `contraregions()`,
-// rather than inversing the order of arguments! This is necessary
-// because the order of arguments is not relevant for LUB and GLB. It
-// is also useful to track which value is the "expected" value in
-// terms of error reporting, although we do not do that properly right
-// now.
-
-type cres = result;
-
-trait combine {
- fn infcx() -> infer_ctxt;
- fn tag() -> ~str;
-
- fn mts(a: ty::mt, b: ty::mt) -> cres;
- fn contratys(a: ty::t, b: ty::t) -> cres;
- fn tys(a: ty::t, b: ty::t) -> cres;
- fn tps(as: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]>;
- fn self_tys(a: option, b: option) -> cres