about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/comp/front/ast.rs8
-rw-r--r--src/comp/middle/ty.rs12
-rw-r--r--src/comp/middle/typeck.rs14
-rw-r--r--src/test/compile-fail/type-recursive.rs4
4 files changed, 35 insertions, 3 deletions
diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs
index 0d53a8bde5d..1575631451c 100644
--- a/src/comp/front/ast.rs
+++ b/src/comp/front/ast.rs
@@ -503,6 +503,14 @@ fn is_constraint_arg(@expr e) -> bool {
     }
 }
 
+fn eq_ty(&@ty a, &@ty b) -> bool {
+    ret a == b;
+}
+
+fn hash_ty(&@ty t) -> uint {
+    ret t.span.lo << 16u + t.span.hi;
+}
+
 //
 // Local Variables:
 // mode: rust
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index f936d7513e5..70557a97ed4 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -61,6 +61,11 @@ type item_table = hashmap[ast::def_id,any_item];
 
 type mt = rec(t ty, ast::mutability mut);
 
+tag cached_ty {
+    in_progress;
+    done(t);
+}
+
 // Contains information needed to resolve types and (in the future) look up
 // the types of AST nodes.
 type creader_cache = hashmap[tup(int,uint,uint),ty::t];
@@ -71,7 +76,8 @@ type ctxt = rec(@type_store ts,
                 item_table items,
                 type_cache tcache,
                 creader_cache rcache,
-                hashmap[t,str] short_names_cache);
+                hashmap[t,str] short_names_cache,
+                hashmap[@ast::ty,cached_ty] ast_ty_to_ty_cache);
 type ty_ctxt = ctxt;    // Needed for disambiguation from unify::ctxt.
 
 // Convert from method type to function type.  Pretty easy; we just drop
@@ -245,7 +251,9 @@ fn mk_ctxt(session::session s, resolve::def_map dm) -> ctxt {
             tcache = tcache,
             rcache = mk_rcache(),
             short_names_cache =
-            map::mk_hashmap[ty::t,str](ty::hash_ty, ty::eq_ty));
+            map::mk_hashmap[ty::t,str](ty::hash_ty, ty::eq_ty),
+            ast_ty_to_ty_cache = 
+            map::mk_hashmap[@ast::ty,cached_ty](ast::hash_ty, ast::eq_ty));
 
     populate_type_store(cx);
     ret cx;
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 6b69dba49ae..690ecd4aba8 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -227,6 +227,16 @@ fn ast_mode_to_mode(ast::mode mode) -> ty::mode {
 // notion of a type. `getter` is a function that returns the type
 // corresponding to a definition ID:
 fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t {
+    alt (tcx.ast_ty_to_ty_cache.find(ast_ty)) {
+        case (some[ty::cached_ty](ty::done(?ty))) { ret ty; } 
+        case (some[ty::cached_ty](ty::in_progress)) {
+            tcx.sess.span_err(ast_ty.span, "illegal recursive type "
+                + "(insert a tag in the cycle, if this is desired)");
+        }
+        case (none[ty::cached_ty]) { } /* go on */
+    }
+    tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::in_progress);
+    
     fn ast_arg_to_arg(&ty::ctxt tcx,
                       &ty_getter getter,
                       &rec(ast::mode mode, @ast::ty ty) arg)
@@ -329,7 +339,7 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t {
                 case (_)                   {
                     tcx.sess.span_err(ast_ty.span,
                        "found type name used as a variable");
-                    fail; }
+                }
             }
 
             cname = some(path_to_str(path));
@@ -360,6 +370,8 @@ fn ast_ty_to_ty(&ty::ctxt tcx, &ty_getter getter, &@ast::ty ast_ty) -> ty::t {
             typ = ty::rename(tcx, typ, cname_str);
         }
     }
+
+    tcx.ast_ty_to_ty_cache.insert(ast_ty, ty::done(typ));
     ret typ;
 }
 
diff --git a/src/test/compile-fail/type-recursive.rs b/src/test/compile-fail/type-recursive.rs
new file mode 100644
index 00000000000..763f1f9b3e4
--- /dev/null
+++ b/src/test/compile-fail/type-recursive.rs
@@ -0,0 +1,4 @@
+// error-pattern:illegal recursive type
+type t1 = rec(int foo, t1 foolish);
+
+fn main() {}
\ No newline at end of file