From 5cd10d2fef8ffa68903b18726f19ac52a04725cc Mon Sep 17 00:00:00 2001 From: Paul Stansifer Date: Thu, 2 Jun 2011 14:03:17 -0700 Subject: [PATCH] Error message, instead of segfault, when recursive types are used. --- src/comp/front/ast.rs | 8 ++++++++ src/comp/middle/ty.rs | 12 ++++++++++-- src/comp/middle/typeck.rs | 14 +++++++++++++- src/test/compile-fail/type-recursive.rs | 4 ++++ 4 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 src/test/compile-fail/type-recursive.rs diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 0d53a8bde5d4..1575631451c8 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 f936d7513e5c..70557a97ed47 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 6b69dba49ae1..690ecd4aba86 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 000000000000..763f1f9b3e42 --- /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