correct glb computation, improve region error msgs

cc #3180
This commit is contained in:
Niko Matsakis 2012-08-11 10:21:22 -07:00
parent 0475406178
commit 9169a1b26a
3 changed files with 97 additions and 33 deletions

View file

@ -168,7 +168,8 @@ export bound_const;
export terr_no_integral_type, terr_ty_param_size, terr_self_substs;
export terr_in_field, terr_record_fields, terr_vstores_differ, terr_arg_count;
export terr_sorts, terr_vec, terr_str, terr_record_size, terr_tuple_size;
export terr_regions_differ, terr_mutability, terr_purity_mismatch;
export terr_regions_does_not_outlive, terr_mutability, terr_purity_mismatch;
export terr_regions_not_same, terr_regions_no_overlap;
export terr_proto_mismatch;
export terr_ret_style_mismatch;
export purity_to_str;
@ -463,7 +464,9 @@ enum type_err {
terr_record_fields(ast::ident, ast::ident),
terr_arg_count,
terr_mode_mismatch(mode, mode),
terr_regions_differ(region, region),
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_in_field(@type_err, ast::ident),
terr_sorts(t, t),
@ -2631,11 +2634,21 @@ fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
return ~"expected argument mode " + mode_to_str(e_mode) +
~" but found " + mode_to_str(a_mode);
}
terr_regions_differ(subregion, superregion) => {
terr_regions_does_not_outlive(subregion, superregion) => {
return fmt!{"%s does not necessarily outlive %s",
explain_region(cx, subregion),
explain_region(cx, superregion)};
}
terr_regions_not_same(region1, region2) => {
return 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)};
}
terr_vstores_differ(k, e_vs, a_vs) => {
return fmt!{"%s storage differs: expected %s but found %s",
terr_vstore_kind_to_str(k),

View file

@ -394,7 +394,8 @@ enum infer_ctxt = @{
ty_var_integral_bindings: vals_and_bindings<ty::tvi_vid, int_ty_set>,
// For region variables.
region_var_bindings: vals_and_bindings<ty::region_vid, bounds<ty::region>>,
region_var_bindings: vals_and_bindings<ty::region_vid,
bounds<ty::region>>,
// For keeping track of existing type and region variables.
ty_var_counter: @mut uint,
@ -1053,7 +1054,7 @@ impl infer_ctxt {
nde_a.rank)
}
fn var_sub_t_integral<V: copy vid>(
fn var_integral_sub_t<V: copy vid>(
vb: &vals_and_bindings<V, int_ty_set>,
a_id: V, b: ty::t) -> ures {
@ -1146,9 +1147,19 @@ impl infer_ctxt {
debug!{"eq_regions(%s, %s)",
a.to_str(self), b.to_str(self)};
do indent {
do self.sub_regions(a, b).then {
self.sub_regions(b, a)
}
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)
}
})
}
}
}
@ -1847,15 +1858,15 @@ fn super_tys<C:combine>(
}
(ty::ty_var_integral(a_id), ty::ty_int(_)) |
(ty::ty_var_integral(a_id), ty::ty_uint(_)) => {
self.infcx().vart_integral(&self.infcx().ty_var_integral_bindings,
a_id, b)
.then(|| ok(a) )
self.infcx().var_integral_sub_t(
&self.infcx().ty_var_integral_bindings,
a_id, b).then(|| ok(a) )
}
(ty::ty_int(_), ty::ty_var_integral(b_id)) |
(ty::ty_uint(_), ty::ty_var_integral(b_id)) => {
self.infcx().t_sub_var_integral(&self.infcx().ty_var_integral_bindings,
a, b_id)
.then(|| ok(a) )
self.infcx().t_sub_var_integral(
&self.infcx().ty_var_integral_bindings,
a, b_id).then(|| ok(a) )
}
(ty::ty_int(_), _) |
@ -2015,8 +2026,8 @@ impl sub: combine {
}
_ => {
do (&self.lub()).regions(a, b).compare(b) {
ty::terr_regions_differ(b, a)
}
ty::terr_regions_does_not_outlive(b, a)
}
}
}
}
@ -2460,20 +2471,26 @@ impl glb: combine {
let rm = self.infcx().tcx.region_map;
match region::nearest_common_ancestor(rm, f_id, s_id) {
some(r_id) if r_id == f_id => ok(s),
_ => err(ty::terr_regions_differ(b, a))
_ => err(ty::terr_regions_no_overlap(b, a))
}
}
(ty::re_scope(a_id), ty::re_scope(b_id)) |
(ty::re_free(a_id, _), ty::re_free(b_id, _)) => {
// We want to generate a region that is contained by both of
// these: so, if one of these scopes is a subscope of the
// other, return it. Otherwise fail.
let rm = self.infcx().tcx.region_map;
match region::nearest_common_ancestor(rm, a_id, b_id) {
some(r_id) if a_id == r_id => ok(b),
some(r_id) if b_id == r_id => ok(a),
_ => err(ty::terr_regions_differ(b, a))
if a == b {
// Same scope or same free identifier, easy case.
ok(a)
} else {
// We want to generate the intersection of two
// scopes or two free regions. So, if one of
// these scopes is a subscope of the other, return
// it. Otherwise fail.
let rm = self.infcx().tcx.region_map;
match region::nearest_common_ancestor(rm, a_id, b_id) {
some(r_id) if a_id == r_id => ok(ty::re_scope(b_id)),
some(r_id) if b_id == r_id => ok(ty::re_scope(a_id)),
_ => err(ty::terr_regions_no_overlap(b, a))
}
}
}
@ -2487,7 +2504,7 @@ impl glb: combine {
if a == b {
ok(a)
} else {
err(ty::terr_regions_differ(b, a))
err(ty::terr_regions_no_overlap(b, a))
}
}
}
@ -2589,13 +2606,13 @@ fn lattice_tys<L:lattice_ops combine>(
}
(ty::ty_var(a_id), _) => {
lattice_var_t(self, &self.infcx().ty_var_bindings, a_id, b,
|x, y| self.tys(x, y) )
lattice_var_and_t(self, &self.infcx().ty_var_bindings, a_id, b,
|x, y| self.tys(x, y) )
}
(_, ty::ty_var(b_id)) => {
lattice_var_t(self, &self.infcx().ty_var_bindings, b_id, a,
|x, y| self.tys(x, y) )
lattice_var_and_t(self, &self.infcx().ty_var_bindings, b_id, a,
|x, y| self.tys(x, y) )
}
_ => {
super_tys(self, a, b)
@ -2616,9 +2633,9 @@ fn lattice_rvars<L:lattice_ops combine>(
}
(ty::re_var(v_id), r) | (r, ty::re_var(v_id)) => {
lattice_var_t(self, &self.infcx().region_var_bindings,
v_id, r,
|x, y| self.regions(x, y) )
lattice_var_and_t(self, &self.infcx().region_var_bindings,
v_id, r,
|x, y| self.regions(x, y) )
}
_ => {

View file

@ -0,0 +1,34 @@
mod argparse {
use std;
import std::map;
import either::{either, left, right};
struct Flag {
name: &str;
desc: &str;
max_count: uint;
mut value: uint;
}
fn flag(name: &str, desc: &str) -> Flag {
Flag { name: name, desc: desc, max_count: 1, value: 0 }
}
impl Flag {
fn set_desc(self, s: &str) -> Flag {
Flag { //~ ERROR mismatched types
name: self.name,
desc: s,
max_count: self.max_count,
value: self.value
}
}
}
}
fn main () {
let f : argparse::Flag = argparse::flag(~"flag", ~"My flag");
let updated_flag = f.set_desc(~"My new flag");
assert updated_flag.desc == "My new flag";
}