Commits

Anonymous committed 03a2bde

Fix stack overflow by checking cycles for all types before regularity

git-svn-id: http://caml.inria.fr/svn/ocaml/trunk@12608f963ae5c-01c2-4b8c-9fe0-0dff7051ff02

Comments (0)

Files changed (3)

testsuite/tests/typing-misc/constraints.ml

 
 type 'a t = [`A of 'a] as 'a;;
 
-(* XXX Todo : Fix stack overflow *)
-(*
-type 'a v = [`A of u v] constraint 'a = t and t = u and u = t;;
-*)
+type 'a v = [`A of u v] constraint 'a = t and t = u and u = t;; (* fails *)
 
 type 'a t = 'a;;
 let f (x : 'a t as 'a) = ();; (* fails *)

testsuite/tests/typing-misc/constraints.ml.reference

 #   type 'a t = [ `A of 'a t t ] constraint 'a = 'a t
 #   type 'a t = [ `A of 'a t ] constraint 'a = 'a t
 #   type 'a t = 'a constraint 'a = [ `A of 'a ]
-#     * *     type 'a t = 'a
+#   Characters 47-52:
+  type 'a v = [`A of u v] constraint 'a = t and t = u and u = t;; (* fails *)
+                                                ^^^^^
+Error: The type abbreviation t is cyclic
+#   type 'a t = 'a
 # Characters 11-21:
   let f (x : 'a t as 'a) = ();; (* fails *)
              ^^^^^^^^^^

typing/typedecl.ml

       end
   | _ -> ()
 
+(* Check that recursion is well-founded *)
+
+let check_well_founded env loc path decl =
+  Misc.may
+    (fun body ->
+      try Ctype.correct_abbrev env path decl.type_params body with
+      | Ctype.Recursive_abbrev ->
+          raise(Error(loc, Recursive_abbrev (Path.name path)))
+      | Ctype.Unify trace -> raise(Error(loc, Type_clash trace)))
+    decl.type_manifest
+
 (* Check for ill-defined abbrevs *)
 
 let check_recursion env loc path decl to_check =
   (* to_check is true for potentially mutually recursive paths.
      (path, decl) is the type declaration to be checked. *)
 
+  if decl.type_params = [] then () else
+
   let visited = ref [] in
 
   let rec check_regular cpath args prev_exp ty =
           Btype.iter_type_expr (check_regular cpath args prev_exp) ty
     end in
 
-  match decl.type_manifest with
-  | None -> ()
-  | Some body ->
-      (* Check that recursion is well-founded *)
-      begin try
-        Ctype.correct_abbrev env path decl.type_params body
-      with Ctype.Recursive_abbrev ->
-        raise(Error(loc, Recursive_abbrev (Path.name path)))
-      | Ctype.Unify trace -> raise(Error(loc, Type_clash trace))
-      end;
-      (* Check that recursion is regular *)
-      if decl.type_params = [] then () else
+  Misc.may
+    (fun body ->
       let (args, body) =
         Ctype.instance_parameterized_type
           ~keep_names:true decl.type_params body in
-      check_regular path args [] body
+      check_regular path args [] body)
+    decl.type_manifest
 
 let check_abbrev_recursion env id_loc_list (id, _, tdecl) =
   let decl = tdecl.typ_type in
     List.map2 (fun id (_,sdecl) -> (id, sdecl.ptype_loc))
       id_list name_sdecl_list
   in
+  List.iter (fun (id, decl) ->
+    check_well_founded newenv (List.assoc id id_loc_list) (Path.Pident id) decl)
+    decls;
   List.iter (check_abbrev_recursion newenv id_loc_list) tdecls;
   (* Check that all type variable are closed *)
   List.iter2
 let check_recmod_typedecl env loc recmod_ids path decl =
   (* recmod_ids is the list of recursively-defined module idents.
      (path, decl) is the type declaration to be checked. *)
+  check_well_founded env loc path decl;
   check_recursion env loc path decl
     (fun path -> List.exists (fun id -> Path.isfree id path) recmod_ids)