diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 90ea9b3a6b14..d06e7c55d0c0 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -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), diff --git a/src/rustc/middle/typeck/infer.rs b/src/rustc/middle/typeck/infer.rs index c47bd4a9f543..4eaef9aa062b 100644 --- a/src/rustc/middle/typeck/infer.rs +++ b/src/rustc/middle/typeck/infer.rs @@ -394,7 +394,8 @@ enum infer_ctxt = @{ ty_var_integral_bindings: vals_and_bindings, // For region variables. - region_var_bindings: vals_and_bindings>, + region_var_bindings: vals_and_bindings>, // 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( + fn var_integral_sub_t( vb: &vals_and_bindings, 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( } (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( } (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( } (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) ) } _ => { diff --git a/src/test/compile-fail/regions-glb-free-free.rs b/src/test/compile-fail/regions-glb-free-free.rs new file mode 100644 index 000000000000..94cf76330a9f --- /dev/null +++ b/src/test/compile-fail/regions-glb-free-free.rs @@ -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"; +}