about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-08-11 10:21:22 -0700
committerNiko Matsakis <niko@alum.mit.edu>2012-08-11 20:24:11 -0700
commit9169a1b26a556bbd5befd344a5b0912901859e5d (patch)
tree8e721ac58741a582893f02d991cafa10265758de /src
parent04754061781b855b4d230a9ae3bc97799373aff4 (diff)
correct glb computation, improve region error msgs
cc #3180
Diffstat (limited to 'src')
-rw-r--r--src/rustc/middle/ty.rs19
-rw-r--r--src/rustc/middle/typeck/infer.rs77
-rw-r--r--src/test/compile-fail/regions-glb-free-free.rs34
3 files changed, 97 insertions, 33 deletions
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index 90ea9b3a6b1..d06e7c55d0c 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 c47bd4a9f54..4eaef9aa062 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<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) )
       }
 
       _ => {
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 00000000000..94cf76330a9
--- /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";
+}