diff options
author | Jacques Le Normand <rathereasy@gmail.com> | 2010-09-22 07:52:36 +0000 |
---|---|---|
committer | Jacques Le Normand <rathereasy@gmail.com> | 2010-09-22 07:52:36 +0000 |
commit | 5a750b3e54fee65a1cc3cdb805576fffdc247eb8 (patch) | |
tree | 8d0fc78bc95e84c75248e7ecde2007432ec0121e | |
parent | 10214937fee0c28cdf98d9c15c52ae0057de998e (diff) |
existentials are now treated correctly in patterns
git-svn-id: http://caml.inria.fr/svn/ocaml/branches/gadts@10687 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02
-rw-r--r-- | typing/ctype.ml | 211 | ||||
-rw-r--r-- | typing/ctype.mli | 2 | ||||
-rw-r--r-- | typing/typecore.ml | 11 |
3 files changed, 207 insertions, 17 deletions
diff --git a/typing/ctype.ml b/typing/ctype.ml index 333e350c7..17e084542 100644 --- a/typing/ctype.ml +++ b/typing/ctype.ml @@ -10,6 +10,180 @@ (* *) (***********************************************************************) + +module Printtyp_ = +struct + +open Misc +open Format +open Longident +open Path +open Asttypes +open Types +open Btype +open Outcometree + +(* Print a long identifier *) + +let rec longident ppf = function + | Lident s -> fprintf ppf "%s" s + | Ldot(p, s) -> fprintf ppf "%a.%s" longident p s + | Lapply(p1, p2) -> fprintf ppf "%a(%a)" longident p1 longident p2 + +(* Print an identifier *) + +let unique_names = ref Ident.empty + +let ident_name id = + try Ident.find_same id !unique_names with Not_found -> Ident.name id + +let add_unique id = + try ignore (Ident.find_same id !unique_names) + with Not_found -> + unique_names := Ident.add id (Ident.unique_toplevel_name id) !unique_names + +let ident ppf id = fprintf ppf "%s" (ident_name id) + +(* Print a path *) + +let ident_pervasive = Ident.create_persistent "Pervasives" + +let rec tree_of_path = function + | Pident id -> + Oide_ident (ident_name id) + | Pdot(Pident id, s, pos) when Ident.same id ident_pervasive -> + Oide_ident s + | Pdot(p, s, pos) -> + Oide_dot (tree_of_path p, s) + | Papply(p1, p2) -> + Oide_apply (tree_of_path p1, tree_of_path p2) + +let rec path ppf = function + | Pident id -> + ident ppf id + | Pdot(Pident id, s, pos) when Ident.same id ident_pervasive -> + fprintf ppf "%s" s + | Pdot(p, s, pos) -> + fprintf ppf "%a.%s" path p s + | Papply(p1, p2) -> + fprintf ppf "%a(%a)" path p1 path p2 + +(* Print a recursive annotation *) + +let tree_of_rec = function + | Trec_not -> Orec_not + | Trec_first -> Orec_first + | Trec_next -> Orec_next + +(* Print a raw type expression, with sharing *) + +let raw_list pr ppf = function + [] -> fprintf ppf "[]" + | a :: l -> + fprintf ppf "@[<1>[%a%t]@]" pr a + (fun ppf -> List.iter (fun x -> fprintf ppf ";@,%a" pr x) l) + +let rec safe_kind_repr v = function + Fvar {contents=Some k} -> + if List.memq k v then "Fvar loop" else + safe_kind_repr (k::v) k + | Fvar _ -> "Fvar None" + | Fpresent -> "Fpresent" + | Fabsent -> "Fabsent" + +let rec safe_commu_repr v = function + Cok -> "Cok" + | Cunknown -> "Cunknown" + | Clink r -> + if List.memq r v then "Clink loop" else + safe_commu_repr (r::v) !r + +let rec safe_repr v = function + {desc = Tlink t} when not (List.memq t v) -> + safe_repr (t::v) t + | t -> t + +let rec list_of_memo = function + Mnil -> [] + | Mcons (priv, p, t1, t2, rem) -> p :: list_of_memo rem + | Mlink rem -> list_of_memo !rem + +let visited = ref [] +let rec raw_type ppf ty = + let ty = safe_repr [] ty in + if List.memq ty !visited then fprintf ppf "{id=%d}" ty.id else begin + visited := ty :: !visited; + fprintf ppf "@[<1>{id=%d;level=%d;desc=@,%a}@]" ty.id ty.level + raw_type_desc ty.desc + end +and raw_type_list tl = raw_list raw_type tl +and raw_type_desc ppf = function + Tvar -> fprintf ppf "Tvar" + | Tarrow(l,t1,t2,c) -> + fprintf ppf "@[<hov1>Tarrow(%s,@,%a,@,%a,@,%s)@]" + l raw_type t1 raw_type t2 + (safe_commu_repr [] c) + | Ttuple tl -> + fprintf ppf "@[<1>Ttuple@,%a@]" raw_type_list tl + | Tconstr (p, tl, abbrev) -> + fprintf ppf "@[<hov1>Tconstr(@,%a,@,%a,@,%a)@]" path p + raw_type_list tl + (raw_list path) (list_of_memo !abbrev) + | Tobject (t, nm) -> + fprintf ppf "@[<hov1>Tobject(@,%a,@,@[<1>ref%t@])@]" raw_type t + (fun ppf -> + match !nm with None -> fprintf ppf " None" + | Some(p,tl) -> + fprintf ppf "(Some(@,%a,@,%a))" path p raw_type_list tl) + | Tfield (f, k, t1, t2) -> + fprintf ppf "@[<hov1>Tfield(@,%s,@,%s,@,%a,@;<0 -1>%a)@]" f + (safe_kind_repr [] k) + raw_type t1 raw_type t2 + | Tnil -> fprintf ppf "Tnil" + | Tlink t -> fprintf ppf "@[<1>Tlink@,%a@]" raw_type t + | Tsubst t -> fprintf ppf "@[<1>Tsubst@,%a@]" raw_type t + | Tunivar -> fprintf ppf "Tunivar" + | Tpoly (t, tl) -> + fprintf ppf "@[<hov1>Tpoly(@,%a,@,%a)@]" + raw_type t + raw_type_list tl + | Tvariant row -> + fprintf ppf + "@[<hov1>{@[%s@,%a;@]@ @[%s@,%a;@]@ %s%b;@ %s%b;@ @[<1>%s%t@]}@]" + "row_fields=" + (raw_list (fun ppf (l, f) -> + fprintf ppf "@[%s,@ %a@]" l raw_field f)) + row.row_fields + "row_more=" raw_type row.row_more + "row_closed=" row.row_closed + "row_fixed=" row.row_fixed + "row_name=" + (fun ppf -> + match row.row_name with None -> fprintf ppf "None" + | Some(p,tl) -> + fprintf ppf "Some(@,%a,@,%a)" path p raw_type_list tl) + | Tpackage (p, _, tl) -> + fprintf ppf "@[<hov1>Tpackage(@,%a@,%a)@]" path p + raw_type_list tl + +and raw_field ppf = function + Rpresent None -> fprintf ppf "Rpresent None" + | Rpresent (Some t) -> fprintf ppf "@[<1>Rpresent(Some@,%a)@]" raw_type t + | Reither (c,tl,m,e) -> + fprintf ppf "@[<hov1>Reither(%b,@,%a,@,%b,@,@[<1>ref%t@])@]" c + raw_type_list tl m + (fun ppf -> + match !e with None -> fprintf ppf " None" + | Some f -> fprintf ppf "@,@[<1>(%a)@]" raw_field f) + | Rabsent -> fprintf ppf "Rabsent" + +let raw_type_expr ppf t = + visited := []; + raw_type ppf t; + visited := [] +end + + (* $Id$ *) (* Operations on core types *) @@ -866,9 +1040,38 @@ let instance_list schl = cleanup_types (); tyl -let instance_constructor cstr = +let reified_var_counter = ref 0 + +let get_new_abstract_name () = + let ret = Printf.sprintf "&x%d" !reified_var_counter in + incr reified_var_counter; + ret + + +let instance_constructor ?(in_pattern=None) cstr = (* GAH : how the blazes does this work?? *) let ty_res = copy cstr.cstr_res in let ty_args = List.map copy cstr.cstr_args in + begin match in_pattern with + | None -> () + | Some env -> + let existentials = List.map copy cstr.cstr_existentials in + let process existential = + let decl = { + type_params = []; + type_arity = 0; + type_kind = Type_abstract; + type_private = Public; + type_manifest = None; + type_variance = []; + } + in + let ty = newvar () in + Ident.set_current_time ty.level; + let (id, new_env) = Env.enter_type (get_new_abstract_name ()) decl !env in + let to_unify = newty2 generic_level (Tconstr (Path.Pident id,[],ref Mnil)) in (* GAH : ask garrigue, what in the world is an abbrev_memo ?? *) + link_type existential to_unify + in + List.iter process existentials end; cleanup_types (); (ty_args, ty_res) @@ -1568,12 +1771,6 @@ let get_unification_type () = | true -> `Pattern | false -> `Expression -let reified_var_counter = ref 0 - -let get_new_abstract_name () = - let ret = Printf.sprintf "&x%d" !reified_var_counter in - incr reified_var_counter; - ret let reify env t = (* GAH: ask garrigue; is this right? *) let rec iterator ty = diff --git a/typing/ctype.mli b/typing/ctype.mli index a126c27fa..eef51699a 100644 --- a/typing/ctype.mli +++ b/typing/ctype.mli @@ -108,7 +108,7 @@ val instance: type_expr -> type_expr val instance_list: type_expr list -> type_expr list (* Take an instance of a list of type schemes *) val instance_constructor: - constructor_description -> type_expr list * type_expr + ?in_pattern:Env.t ref option -> constructor_description -> type_expr list * type_expr (* Same, for a constructor *) val instance_parameterized_type: type_expr list -> type_expr -> type_expr list * type_expr diff --git a/typing/typecore.ml b/typing/typecore.ml index 522da3956..bc2e51a90 100644 --- a/typing/typecore.ml +++ b/typing/typecore.ml @@ -492,22 +492,15 @@ let rec type_pat (env:Env.t ref) sp expected_ty = pat_type = expected_ty; pat_env = !env } |Ppat_construct(lid, sarg, explicit_arity) -> - - -(* if bare_tunivar expected_ty then - raise (Error(loc,Constructor_inhabit_tunivar(expected_ty,lid ))); (* GAH : this code is wrong, must change *)*) let constr = Typetexp.find_constructor !env loc lid in let _ = (* GAH : there must be an easier way to do this, ask garrigue *) let (_, ty_res) = instance_constructor constr in match (repr ty_res).desc with | Tconstr(p,args,m) -> - ty_res.desc <- Tconstr(p,List.map (fun _ -> newvar ()) args,m); + ty_res.desc <- Tconstr(p,List.map (fun _ -> newvar ()) args,m); (* GAH: ask garrigue if this is the best way to only unify the head *) unify_pat_types loc !env expected_ty ty_res | _ -> fatal_error "constructor type does not have correct description" in - - - let sargs = match sarg with None -> [] @@ -522,7 +515,7 @@ let rec type_pat (env:Env.t ref) sp expected_ty = if List.length sargs <> constr.cstr_arity then raise(Error(loc, Constructor_arity_mismatch(lid, constr.cstr_arity, List.length sargs))); - let (ty_args, ty_res) = instance_constructor constr in + let (ty_args, ty_res) = instance_constructor ~in_pattern:(Some env) constr in unify_pat_types_gadt loc env expected_ty ty_res; let args: Typedtree.pattern list = List.map2 (fun p t -> type_pat env p t) sargs ty_args in (* GAH : might be wrong *) rp { |