summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2012-03-11 13:28:43 -0700
committerPatrick Walton <pcwalton@mimiga.net>2012-03-11 13:28:43 -0700
commit3e8bb22af17f7c97e2513ac4d99323dcb46ca6fe (patch)
tree25bc18dd39e7560bb9bd7acc1d58b3a9d221460d /src
parentf7efc29b38853a9c29eb2aafb65cd972fd1dc1c3 (diff)
rustc: Unify regions in most cases. (Nested functions aren't properly handled yet.)
Diffstat (limited to 'src')
-rw-r--r--src/rustc/middle/region.rs14
-rw-r--r--src/rustc/middle/ty.rs53
-rw-r--r--src/rustc/middle/typeck.rs5
3 files changed, 67 insertions, 5 deletions
diff --git a/src/rustc/middle/region.rs b/src/rustc/middle/region.rs
index 303ad24513d..90be3f5b12e 100644
--- a/src/rustc/middle/region.rs
+++ b/src/rustc/middle/region.rs
@@ -43,6 +43,20 @@ type ctxt = {
     parent: parent
 };
 
+// Returns true if `subblock` is equal to or is lexically nested inside
+// `superblock` and false otherwise.
+fn block_contains(region_map: @region_map, superblock: ast::node_id,
+                  subblock: ast::node_id) -> bool {
+    let subblock = subblock;
+    while superblock != subblock {
+        alt region_map.parent_blocks.find(subblock) {
+            none { ret false; }
+            some(blk) { subblock = blk; }
+        }
+    }
+    ret true;
+}
+
 fn resolve_ty(ty: @ast::ty, cx: ctxt, visitor: visit::vt<ctxt>) {
     alt ty.node {
         ast::ty_rptr({id: region_id, node: node}, _) {
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index 800caaf639c..a9a71f51100 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -283,6 +283,7 @@ enum type_err {
     terr_mode_mismatch(mode, mode),
     terr_constr_len(uint, uint),
     terr_constr_mismatch(@type_constr, @type_constr),
+    terr_regions_differ,
 }
 
 enum param_bound {
@@ -1885,6 +1886,45 @@ mod unify {
           }
         }
     }
+    fn unify_regions(cx: @uctxt, e_region: region, a_region: region,
+                     variance: variance) -> option<region> {
+        let sub, super;
+        alt variance {
+            covariant { super = e_region; sub = a_region; }
+            contravariant { super = a_region; sub = e_region; }
+            invariant {
+                ret if e_region == a_region { some(e_region) } else { none };
+            }
+        }
+
+        alt (super, sub) {
+            (re_caller(_), re_caller(_)) {
+                // FIXME: This is wrong w/r/t nested functions.
+                ret some(super);
+            }
+            (re_caller(_), re_named(_)) | (re_named(_), re_caller(_)) {
+                ret none;
+            }
+            (re_named(a), re_named(b)) {
+                ret if a == b { some(super) } else { none }
+            }
+            (re_caller(_), re_block(_)) | (re_named(_), re_block(_)) {
+                // FIXME: This is wrong w/r/t nested functions.
+                ret some(super);
+            }
+            (re_block(_), re_caller(_)) | (re_block(_), re_named(_)) {
+                ret none;
+            }
+            (re_block(superblock), re_block(subblock)) {
+                if region::block_contains(cx.tcx.region_map, superblock,
+                                          subblock) {
+                    ret some(super);
+                } else {
+                    ret none;
+                }
+            }
+        }
+    }
 
     fn unify_step(cx: @uctxt, expected: t, actual: t,
                   variance: variance) -> result {
@@ -1943,9 +1983,13 @@ mod unify {
             unify_mt(cx, e_mt, a_mt, variance, terr_ptr_mutability, mk_ptr)
           }
           (ty_rptr(e_region, e_mt), ty_rptr(a_region, a_mt)) {
-            // TODO: Unify regions. Take covariance/invariance into account.
-            unify_mt(cx, e_mt, a_mt, variance, terr_ref_mutability,
-                     bind mk_rptr(_, re_block(0), _))
+            alt unify_regions(cx, e_region, a_region, variance) {
+                none { ures_err(terr_regions_differ) }
+                some(r_region) {
+                    unify_mt(cx, e_mt, a_mt, variance, terr_ref_mutability,
+                             bind mk_rptr(_, r_region, _))
+                }
+            }
           }
           (ty_res(e_id, e_inner, e_tps), ty_res(a_id, a_inner, a_tps))
           if e_id == a_id {
@@ -2154,6 +2198,9 @@ fn type_err_to_str(err: type_err) -> str {
                 " but found one with constraint " +
                 ty_constr_to_str(a_constr);
       }
+      terr_regions_differ {
+        ret "inconsistent pointer lifetimes"
+      }
     }
 }
 
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index 728d9f82a75..7bc779429fb 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -319,8 +319,9 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
       ast::ty_ptr(mt) {
         ty::mk_ptr(tcx, ast_mt_to_mt(tcx, mode, mt))
       }
-      ast::ty_rptr(_, mt) {
-        ty::mk_rptr(tcx, ty::re_block(0), ast_mt_to_mt(tcx, mode, mt))
+      ast::ty_rptr(region, mt) {
+        let region = tcx.region_map.ast_type_to_region.get(region.id);
+        ty::mk_rptr(tcx, region, ast_mt_to_mt(tcx, mode, mt))
       }
       ast::ty_tup(fields) {
         let flds = vec::map(fields, bind ast_ty_to_ty(tcx, mode, _));