about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-08-16 13:24:04 +0200
committerMarijn Haverbeke <marijnh@gmail.com>2011-08-16 13:45:41 +0200
commite33af7e0b505de6d7c754d2ead26c9ee2bc8974e (patch)
tree1fc83feb9774a06079fa8fd0991d1b1e419c3295
parent92719e438c4cb38067446388d41a2abe651ab9a9 (diff)
Make let bindings' scope start at their definition
Also, allow let bindings in a block to shadow each other.
-rw-r--r--src/comp/middle/resolve.rs70
-rw-r--r--src/test/compile-fail/alt-join.rs4
-rw-r--r--src/test/compile-fail/capture1.rs4
-rw-r--r--src/test/compile-fail/duplicate-name.rs3
-rw-r--r--src/test/compile-fail/occurs-check-2.rs3
-rw-r--r--src/test/compile-fail/occurs-check-3.rs2
-rw-r--r--src/test/compile-fail/occurs-check.rs3
-rw-r--r--src/test/run-pass/shadow.rs (renamed from src/test/compile-fail/shadow.rs)9
8 files changed, 70 insertions, 28 deletions
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index 9e51e442838..76738fe8737 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -53,7 +53,7 @@ tag scope {
     scope_native_item(@ast::native_item);
     scope_loop(@ast::local); // there's only 1 decl per loop.
 
-    scope_block(ast::blk);
+    scope_block(ast::blk, @mutable uint, @mutable uint);
     scope_arm(ast::arm);
 }
 
@@ -254,6 +254,7 @@ fn resolve_names(e: &@env, c: &@ast::crate) {
         @{visit_native_item: visit_native_item_with_scope,
           visit_item: visit_item_with_scope,
           visit_block: visit_block_with_scope,
+          visit_decl: visit_decl_with_scope,
           visit_arm: bind walk_arm(e, _, _, _),
           visit_pat: bind walk_pat(e, _, _, _),
           visit_expr: bind walk_expr(e, _, _, _),
@@ -353,7 +354,30 @@ fn visit_fn_with_scope(e: &@env, f: &ast::_fn, tp: &[ast::ty_param],
 }
 
 fn visit_block_with_scope(b: &ast::blk, sc: &scopes, v: &vt[scopes]) {
-    visit::visit_block(b, cons(scope_block(b), @sc), v);
+    let pos = @mutable 0u, loc = @mutable 0u;
+    let block_sc = cons(scope_block(b, pos, loc), @sc);
+    for stmt in b.node.stmts {
+        v.visit_stmt(stmt, block_sc, v);
+        *pos += 1u;
+        *loc = 0u;
+    }
+    visit::visit_expr_opt(b.node.expr, block_sc, v);
+}
+
+fn visit_decl_with_scope(d: &@decl, sc: &scopes, v: &vt[scopes]) {
+    let loc_pos = alt list::car(sc) {
+      scope_block(_, _, pos) { pos }
+      _ { @mutable 0u }
+    };
+    alt d.node {
+      decl_local(locs) {
+        for loc in locs {
+            v.visit_local(loc, sc, v);
+            *loc_pos += 1u;
+        }
+      }
+      decl_item(it) { v.visit_item(it, sc, v); }
+    }
 }
 
 fn visit_arm_with_scope(a: &ast::arm, sc: &scopes, v: &vt[scopes]) {
@@ -650,7 +674,9 @@ fn lookup_in_scope(e: &env, sc: scopes, sp: &span, name: &ident,
                 }
             }
           }
-          scope_block(b) { ret lookup_in_block(name, b.node, ns); }
+          scope_block(b, pos, loc) {
+            ret lookup_in_block(name, b.node, *pos, *loc, ns);
+          }
           scope_arm(a) {
             if ns == ns_value {
                 ret option::map(ast::def_binding,
@@ -755,18 +781,26 @@ fn lookup_in_obj(name: &ident, ob: &ast::_obj, ty_params: &[ast::ty_param],
     }
 }
 
-fn lookup_in_block(name: &ident, b: &ast::blk_, ns: namespace) ->
-   option::t[def] {
-    for st: @ast::stmt in b.stmts {
+fn lookup_in_block(name: &ident, b: &ast::blk_, pos: uint, loc_pos: uint,
+                   ns: namespace) -> option::t[def] {
+    let i = ivec::len(b.stmts);
+    while i > 0u {
+        i -= 1u;
+        let st = b.stmts.(i);
         alt st.node {
           ast::stmt_decl(d, _) {
             alt d.node {
               ast::decl_local(locs) {
-                for loc: @ast::local in locs {
-                    if ns == ns_value {
-                        alt lookup_in_pat(name, loc.node.pat) {
-                          some(did) { ret some(ast::def_local(did)); }
-                          _ {}
+                if i <= pos {
+                    let j = ivec::len(locs);
+                    while j > 0u {
+                        j -= 1u;
+                        let loc = locs.(j);
+                        if ns == ns_value && (i < pos || j < loc_pos) {
+                            alt lookup_in_pat(name, loc.node.pat) {
+                              some(did) { ret some(ast::def_local(did)); }
+                              _ {}
+                            }
                         }
                     }
                 }
@@ -1272,8 +1306,13 @@ fn check_block(e: &@env, b: &ast::blk, x: &(), v: &vt[()]) {
           ast::stmt_decl(d, _) {
             alt d.node {
               ast::decl_local(locs) {
-                for loc: @ast::local in locs {
-                    check_pat(values, loc.node.pat);
+                let local_values = checker(*e, "value");
+                for loc in locs {
+                    for each p in ast::pat_bindings(loc.node.pat) {
+                        let ident = alt p.node { pat_bind(n) { n } };
+                        add_name(local_values, p.span, ident);
+                        check_name(values, p.span, ident);
+                    }
                 }
               }
               ast::decl_item(it) {
@@ -1339,12 +1378,15 @@ fn checker(e: &env, kind: str) -> checker {
     ret @{mutable seen: seen, kind: kind, sess: e.sess};
 }
 
-fn add_name(ch: &checker, sp: &span, name: &ident) {
+fn check_name(ch: &checker, sp: &span, name: &ident) {
     for s: ident in ch.seen {
         if str::eq(s, name) {
             ch.sess.span_fatal(sp, "duplicate " + ch.kind + " name: " + name);
         }
     }
+}
+fn add_name(ch: &checker, sp: &span, name: &ident) {
+    check_name(ch, sp, name);
     ch.seen += ~[name];
 }
 
diff --git a/src/test/compile-fail/alt-join.rs b/src/test/compile-fail/alt-join.rs
index bbd4ac5c73a..613e1e12382 100644
--- a/src/test/compile-fail/alt-join.rs
+++ b/src/test/compile-fail/alt-join.rs
@@ -1,12 +1,10 @@
-// error-pattern:Unsatisfied precondition constraint
+// error-pattern:unresolved name
 // a good test that we merge paths correctly in the presence of a
 // variable that's used before it's declared
-// should be rejected by typestate because we use x without initializing it
 
 fn my_fail() -> ! { fail; }
 
 fn main() {
-
     alt (true) {
       false { my_fail(); }
       true {}
diff --git a/src/test/compile-fail/capture1.rs b/src/test/compile-fail/capture1.rs
index 24232933dde..1e8e48aea02 100644
--- a/src/test/compile-fail/capture1.rs
+++ b/src/test/compile-fail/capture1.rs
@@ -3,8 +3,6 @@
 // error-pattern: attempted dynamic environment-capture
 
 fn main() {
-
-    fn foo() -> int { ret bar; }
-
     let bar: int = 5;
+    fn foo() -> int { ret bar; }
 }
\ No newline at end of file
diff --git a/src/test/compile-fail/duplicate-name.rs b/src/test/compile-fail/duplicate-name.rs
deleted file mode 100644
index 294d782f916..00000000000
--- a/src/test/compile-fail/duplicate-name.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-// error-pattern: duplicate value name: x
-
-fn main() { let x = 10; let x: int = 20; }
\ No newline at end of file
diff --git a/src/test/compile-fail/occurs-check-2.rs b/src/test/compile-fail/occurs-check-2.rs
index 9b5536e57c3..20a4cf314c4 100644
--- a/src/test/compile-fail/occurs-check-2.rs
+++ b/src/test/compile-fail/occurs-check-2.rs
@@ -1,5 +1,6 @@
 // error-pattern: Type inference failed because I could not find
 fn main() {
-    let f = @f;
+    let f;
+    f = @f;
     f();
 }
\ No newline at end of file
diff --git a/src/test/compile-fail/occurs-check-3.rs b/src/test/compile-fail/occurs-check-3.rs
index f0439b87aed..74a2328f107 100644
--- a/src/test/compile-fail/occurs-check-3.rs
+++ b/src/test/compile-fail/occurs-check-3.rs
@@ -1,4 +1,4 @@
 // error-pattern:mismatched types
 // From Issue #778
 tag clam[T] { a(T); }
-fn main() { let c = a(c); alt c { a[int](_) { } } }
+fn main() { let c; c = a(c); alt c { a[int](_) { } } }
diff --git a/src/test/compile-fail/occurs-check.rs b/src/test/compile-fail/occurs-check.rs
index a2bd12fcc35..16b2f94045e 100644
--- a/src/test/compile-fail/occurs-check.rs
+++ b/src/test/compile-fail/occurs-check.rs
@@ -1,4 +1,5 @@
 // error-pattern: Type inference failed because I could not find
 fn main() {
-    let f = @f;
+    let f;
+    f = @f;
 }
diff --git a/src/test/compile-fail/shadow.rs b/src/test/run-pass/shadow.rs
index 3576a1e4ded..238723b32bc 100644
--- a/src/test/compile-fail/shadow.rs
+++ b/src/test/run-pass/shadow.rs
@@ -1,5 +1,4 @@
 // -*- rust -*-
-// error-pattern:src/test/compile-fail/shadow.rs
 fn foo(c: [int]) {
     let a: int = 5;
     let b: [int] = ~[];
@@ -7,9 +6,15 @@ fn foo(c: [int]) {
 
     alt none[int] {
       some[int](_) { for i: int in c { log a; let a = 17; b += ~[a]; } }
+      _ {}
     }
 }
 
 tag t[T] { none; some(T); }
 
-fn main() { foo(~[]); }
+fn main() {
+    let x = 10;
+    let x = x + 20;
+    assert x == 30;
+    foo(~[]);
+}