520 lines
18 KiB
Diff
520 lines
18 KiB
Diff
Index: typing/env.ml
|
|
===================================================================
|
|
--- typing/env.ml (revision 11214)
|
|
+++ typing/env.ml (working copy)
|
|
@@ -20,6 +20,7 @@
|
|
open Longident
|
|
open Path
|
|
open Types
|
|
+open Btype
|
|
|
|
|
|
type error =
|
|
@@ -56,7 +57,7 @@
|
|
cltypes: (Path.t * cltype_declaration) Ident.tbl;
|
|
summary: summary;
|
|
local_constraints: bool;
|
|
- level_map: (int * int) list;
|
|
+ gadt_instances: (int * TypeSet.t ref) list;
|
|
}
|
|
|
|
and module_components = module_components_repr Lazy.t
|
|
@@ -96,7 +97,7 @@
|
|
modules = Ident.empty; modtypes = Ident.empty;
|
|
components = Ident.empty; classes = Ident.empty;
|
|
cltypes = Ident.empty;
|
|
- summary = Env_empty; local_constraints = false; level_map = [] }
|
|
+ summary = Env_empty; local_constraints = false; gadt_instances = [] }
|
|
|
|
let diff_keys is_local tbl1 tbl2 =
|
|
let keys2 = Ident.keys tbl2 in
|
|
@@ -286,13 +287,14 @@
|
|
(* the level is changed when updating newtype definitions *)
|
|
if !Clflags.principal then begin
|
|
match level, decl.type_newtype_level with
|
|
- Some level, Some def_level when level < def_level -> raise Not_found
|
|
+ Some level, Some (_, exp_level) when level < exp_level -> raise Not_found
|
|
| _ -> ()
|
|
end;
|
|
match decl.type_manifest with
|
|
| Some body when decl.type_private = Public
|
|
|| decl.type_kind <> Type_abstract
|
|
- || Btype.has_constr_row body -> (decl.type_params, body)
|
|
+ || Btype.has_constr_row body ->
|
|
+ (decl.type_params, body, may_map snd decl.type_newtype_level)
|
|
(* The manifest type of Private abstract data types without
|
|
private row are still considered unknown to the type system.
|
|
Hence, this case is caught by the following clause that also handles
|
|
@@ -308,7 +310,7 @@
|
|
match decl.type_manifest with
|
|
(* The manifest type of Private abstract data types can still get
|
|
an approximation using their manifest type. *)
|
|
- | Some body -> (decl.type_params, body)
|
|
+ | Some body -> (decl.type_params, body, may_map snd decl.type_newtype_level)
|
|
| _ -> raise Not_found
|
|
|
|
let find_modtype_expansion path env =
|
|
@@ -453,32 +455,42 @@
|
|
and lookup_cltype =
|
|
lookup (fun env -> env.cltypes) (fun sc -> sc.comp_cltypes)
|
|
|
|
-(* Level handling *)
|
|
+(* GADT instance tracking *)
|
|
|
|
-(* The level map is a list of pairs describing separate segments (lv,lv'),
|
|
- lv < lv', organized in decreasing order.
|
|
- The definition level is obtained by mapping a level in a segment to the
|
|
- high limit of this segment.
|
|
- The definition level of a newtype should be greater or equal to
|
|
- the highest level of the newtypes in its manifest type.
|
|
- *)
|
|
+let add_gadt_instance_level lv env =
|
|
+ {env with
|
|
+ gadt_instances = (lv, ref TypeSet.empty) :: env.gadt_instances}
|
|
|
|
-let rec map_level lv = function
|
|
- | [] -> lv
|
|
- | (lv1, lv2) :: rem ->
|
|
- if lv > lv2 then lv else
|
|
- if lv >= lv1 then lv2 else map_level lv rem
|
|
+let is_Tlink = function {desc = Tlink _} -> true | _ -> false
|
|
|
|
-let map_newtype_level env lv = map_level lv env.level_map
|
|
+let gadt_instance_level env t =
|
|
+ let rec find_instance = function
|
|
+ [] -> None
|
|
+ | (lv, r) :: rem ->
|
|
+ if TypeSet.exists is_Tlink !r then
|
|
+ r := TypeSet.fold (fun ty -> TypeSet.add (repr ty)) !r TypeSet.empty;
|
|
+ if TypeSet.mem t !r then Some lv else find_instance rem
|
|
+ in find_instance env.gadt_instances
|
|
|
|
-(* precondition: lv < lv' *)
|
|
-let rec add_level lv lv' = function
|
|
- | [] -> [lv, lv']
|
|
- | (lv1, lv2) :: rem as l ->
|
|
- if lv2 < lv then (lv, lv') :: l else
|
|
- if lv' < lv1 then (lv1, lv2) :: add_level lv lv' rem
|
|
- else add_level (max lv lv1) (min lv' lv2) rem
|
|
+let add_gadt_instances env lv tl =
|
|
+ let r =
|
|
+ try List.assoc lv env.gadt_instances with Not_found -> assert false in
|
|
+ r := List.fold_right TypeSet.add tl !r
|
|
|
|
+(* Only use this after expand_head! *)
|
|
+let add_gadt_instance_chain env lv t =
|
|
+ let r =
|
|
+ try List.assoc lv env.gadt_instances with Not_found -> assert false in
|
|
+ let rec add_instance t =
|
|
+ let t = repr t in
|
|
+ if not (TypeSet.mem t !r) then begin
|
|
+ r := TypeSet.add t !r;
|
|
+ match t.desc with
|
|
+ Tconstr (p, _, memo) ->
|
|
+ may add_instance (find_expans Private p !memo)
|
|
+ | _ -> ()
|
|
+ end
|
|
+ in add_instance t
|
|
|
|
(* Expand manifest module type names at the top of the given module type *)
|
|
|
|
@@ -497,7 +509,7 @@
|
|
let constructors_of_type ty_path decl =
|
|
let handle_variants cstrs =
|
|
Datarepr.constructor_descrs
|
|
- (Btype.newgenty (Tconstr(ty_path, decl.type_params, ref Mnil)))
|
|
+ (newgenty (Tconstr(ty_path, decl.type_params, ref Mnil)))
|
|
cstrs decl.type_private
|
|
in
|
|
match decl.type_kind with
|
|
@@ -510,7 +522,7 @@
|
|
match decl.type_kind with
|
|
Type_record(labels, rep) ->
|
|
Datarepr.label_descrs
|
|
- (Btype.newgenty (Tconstr(ty_path, decl.type_params, ref Mnil)))
|
|
+ (newgenty (Tconstr(ty_path, decl.type_params, ref Mnil)))
|
|
labels rep decl.type_private
|
|
| Type_variant _ | Type_abstract -> []
|
|
|
|
@@ -773,14 +785,13 @@
|
|
and add_cltype id ty env =
|
|
store_cltype id (Pident id) ty env
|
|
|
|
-let add_local_constraint id info mlv env =
|
|
+let add_local_constraint id info elv env =
|
|
match info with
|
|
- {type_manifest = Some ty; type_newtype_level = Some lv} ->
|
|
- (* use the newtype level for this definition, lv is the old one *)
|
|
- let env = add_type id {info with type_newtype_level = Some mlv} env in
|
|
- let level_map =
|
|
- if lv < mlv then add_level lv mlv env.level_map else env.level_map in
|
|
- { env with local_constraints = true; level_map = level_map }
|
|
+ {type_manifest = Some ty; type_newtype_level = Some (lv, _)} ->
|
|
+ (* elv is the expansion level, lv is the definition level *)
|
|
+ let env =
|
|
+ add_type id {info with type_newtype_level = Some (lv, elv)} env in
|
|
+ { env with local_constraints = true }
|
|
| _ -> assert false
|
|
|
|
(* Insertion of bindings by name *)
|
|
Index: typing/typecore.ml
|
|
===================================================================
|
|
--- typing/typecore.ml (revision 11214)
|
|
+++ typing/typecore.ml (working copy)
|
|
@@ -1989,6 +1989,7 @@
|
|
end
|
|
| Pexp_newtype(name, sbody) ->
|
|
(* Create a fake abstract type declaration for name. *)
|
|
+ let level = get_current_level () in
|
|
let decl = {
|
|
type_params = [];
|
|
type_arity = 0;
|
|
@@ -1996,7 +1997,7 @@
|
|
type_private = Public;
|
|
type_manifest = None;
|
|
type_variance = [];
|
|
- type_newtype_level = Some (get_current_level ());
|
|
+ type_newtype_level = Some (level, level);
|
|
}
|
|
in
|
|
let ty = newvar () in
|
|
@@ -2421,6 +2422,7 @@
|
|
begin_def ();
|
|
Ident.set_current_time (get_current_level ());
|
|
let lev = Ident.current_time () in
|
|
+ let env = Env.add_gadt_instance_level lev env in
|
|
Ctype.init_def (lev+1000);
|
|
if !Clflags.principal then begin_def (); (* propagation of the argument *)
|
|
let ty_arg' = newvar () in
|
|
Index: typing/typedecl.ml
|
|
===================================================================
|
|
--- typing/typedecl.ml (revision 11214)
|
|
+++ typing/typedecl.ml (working copy)
|
|
@@ -404,7 +404,7 @@
|
|
else if to_check path' && not (List.mem path' prev_exp) then begin
|
|
try
|
|
(* Attempt expansion *)
|
|
- let (params0, body0) = Env.find_type_expansion path' env in
|
|
+ let (params0, body0, _) = Env.find_type_expansion path' env in
|
|
let (params, body) =
|
|
Ctype.instance_parameterized_type params0 body0 in
|
|
begin
|
|
Index: typing/types.mli
|
|
===================================================================
|
|
--- typing/types.mli (revision 11214)
|
|
+++ typing/types.mli (working copy)
|
|
@@ -144,9 +144,9 @@
|
|
type_manifest: type_expr option;
|
|
type_variance: (bool * bool * bool) list;
|
|
(* covariant, contravariant, weakly contravariant *)
|
|
- type_newtype_level: int option }
|
|
+ type_newtype_level: (int * int) option }
|
|
+ (* definition level * expansion level *)
|
|
|
|
-
|
|
and type_kind =
|
|
Type_abstract
|
|
| Type_record of
|
|
Index: typing/ctype.ml
|
|
===================================================================
|
|
--- typing/ctype.ml (revision 11214)
|
|
+++ typing/ctype.ml (working copy)
|
|
@@ -470,7 +470,7 @@
|
|
free_variables := (ty, real) :: !free_variables
|
|
| Tconstr (path, tl, _), Some env ->
|
|
begin try
|
|
- let (_, body) = Env.find_type_expansion path env in
|
|
+ let (_, body, _) = Env.find_type_expansion path env in
|
|
if (repr body).level <> generic_level then
|
|
free_variables := (ty, real) :: !free_variables
|
|
with Not_found -> ()
|
|
@@ -687,7 +687,7 @@
|
|
try
|
|
match (Env.find_type p env).type_newtype_level with
|
|
| None -> Path.binding_time p
|
|
- | Some x -> x
|
|
+ | Some (x, _) -> x
|
|
with
|
|
| _ ->
|
|
(* no newtypes in predef *)
|
|
@@ -696,9 +696,13 @@
|
|
let rec update_level env level ty =
|
|
let ty = repr ty in
|
|
if ty.level > level then begin
|
|
+ if !Clflags.principal && Env.has_local_constraints env then begin
|
|
+ match Env.gadt_instance_level env ty with
|
|
+ Some lv -> if level < lv then raise (Unify [(ty, newvar2 level)])
|
|
+ | None -> ()
|
|
+ end;
|
|
match ty.desc with
|
|
- Tconstr(p, tl, abbrev)
|
|
- when level < Env.map_newtype_level env (get_level env p) ->
|
|
+ Tconstr(p, tl, abbrev) when level < get_level env p ->
|
|
(* Try first to replace an abbreviation by its expansion. *)
|
|
begin try
|
|
(* if is_newtype env p then raise Cannot_expand; *)
|
|
@@ -1025,7 +1029,7 @@
|
|
| Some (env, newtype_lev) ->
|
|
let existentials = List.map copy cstr.cstr_existentials in
|
|
let process existential =
|
|
- let decl = new_declaration (Some newtype_lev) None in
|
|
+ let decl = new_declaration (Some (newtype_lev, newtype_lev)) None in
|
|
let (id, new_env) =
|
|
Env.enter_type (get_new_abstract_name ()) decl !env in
|
|
env := new_env;
|
|
@@ -1271,7 +1275,7 @@
|
|
end;
|
|
ty
|
|
| None ->
|
|
- let (params, body) =
|
|
+ let (params, body, lv) =
|
|
try find_type_expansion level path env with Not_found ->
|
|
raise Cannot_expand
|
|
in
|
|
@@ -1284,6 +1288,15 @@
|
|
ty.desc <- Tvariant { row with row_name = Some (path, args) }
|
|
| _ -> ()
|
|
end;
|
|
+ (* For gadts, remember type as non exportable *)
|
|
+ if !Clflags.principal then begin
|
|
+ match lv with
|
|
+ Some lv -> Env.add_gadt_instances env lv [ty; ty']
|
|
+ | None ->
|
|
+ match Env.gadt_instance_level env ty with
|
|
+ Some lv -> Env.add_gadt_instances env lv [ty']
|
|
+ | None -> ()
|
|
+ end;
|
|
ty'
|
|
end
|
|
| _ ->
|
|
@@ -1306,15 +1319,7 @@
|
|
let try_expand_once env ty =
|
|
let ty = repr ty in
|
|
match ty.desc with
|
|
- Tconstr (p, _, _) ->
|
|
- let ty' = repr (expand_abbrev env ty) in
|
|
- if !Clflags.principal then begin
|
|
- match (Env.find_type p env).type_newtype_level with
|
|
- Some lv when ty.level < Env.map_newtype_level env lv ->
|
|
- link_type ty ty'
|
|
- | _ -> ()
|
|
- end;
|
|
- ty'
|
|
+ Tconstr (p, _, _) -> repr (expand_abbrev env ty)
|
|
| _ -> raise Cannot_expand
|
|
|
|
let _ = forward_try_expand_once := try_expand_once
|
|
@@ -1324,11 +1329,16 @@
|
|
May raise Unify, if a recursion was hidden in the type. *)
|
|
let rec try_expand_head env ty =
|
|
let ty' = try_expand_once env ty in
|
|
- begin try
|
|
- try_expand_head env ty'
|
|
- with Cannot_expand ->
|
|
- ty'
|
|
- end
|
|
+ let ty'' =
|
|
+ try try_expand_head env ty'
|
|
+ with Cannot_expand -> ty'
|
|
+ in
|
|
+ if !Clflags.principal then begin
|
|
+ match Env.gadt_instance_level env ty'' with
|
|
+ None -> ()
|
|
+ | Some lv -> Env.add_gadt_instance_chain env lv ty
|
|
+ end;
|
|
+ ty''
|
|
|
|
(* Expand once the head of a type *)
|
|
let expand_head_once env ty =
|
|
@@ -1405,7 +1415,7 @@
|
|
*)
|
|
let generic_abbrev env path =
|
|
try
|
|
- let (_, body) = Env.find_type_expansion path env in
|
|
+ let (_, body, _) = Env.find_type_expansion path env in
|
|
(repr body).level = generic_level
|
|
with
|
|
Not_found ->
|
|
@@ -1742,7 +1752,7 @@
|
|
let reify env t =
|
|
let newtype_level = get_newtype_level () in
|
|
let create_fresh_constr lev row =
|
|
- let decl = new_declaration (Some (newtype_level)) None in
|
|
+ let decl = new_declaration (Some (newtype_level, newtype_level)) None in
|
|
let name =
|
|
let name = get_new_abstract_name () in
|
|
if row then name ^ "#row" else name
|
|
@@ -2065,7 +2075,7 @@
|
|
update_level !env t1.level t2;
|
|
link_type t1 t2
|
|
| (Tconstr (p1, [], a1), Tconstr (p2, [], a2))
|
|
- when Path.same p1 p2 && actual_mode !env = Old
|
|
+ when Path.same p1 p2 (* && actual_mode !env = Old *)
|
|
(* This optimization assumes that t1 does not expand to t2
|
|
(and conversely), so we fall back to the general case
|
|
when any of the types has a cached expansion. *)
|
|
@@ -2091,6 +2101,15 @@
|
|
if unify_eq !env t1' t2' then () else
|
|
|
|
let t1 = repr t1 and t2 = repr t2 in
|
|
+ if !Clflags.principal then begin
|
|
+ match Env.gadt_instance_level !env t1',Env.gadt_instance_level !env t2' with
|
|
+ Some lv1, Some lv2 ->
|
|
+ if lv1 > lv2 then Env.add_gadt_instance_chain !env lv1 t2 else
|
|
+ if lv2 > lv2 then Env.add_gadt_instance_chain !env lv2 t1
|
|
+ | Some lv1, None -> Env.add_gadt_instance_chain !env lv1 t2
|
|
+ | None, Some lv2 -> Env.add_gadt_instance_chain !env lv2 t1
|
|
+ | None, None -> ()
|
|
+ end;
|
|
if unify_eq !env t1 t1' || not (unify_eq !env t2 t2') then
|
|
unify3 env t1 t1' t2 t2'
|
|
else
|
|
Index: typing/env.mli
|
|
===================================================================
|
|
--- typing/env.mli (revision 11214)
|
|
+++ typing/env.mli (working copy)
|
|
@@ -33,14 +33,19 @@
|
|
val find_cltype: Path.t -> t -> cltype_declaration
|
|
|
|
val find_type_expansion:
|
|
- ?use_local:bool -> ?level:int -> Path.t -> t -> type_expr list * type_expr
|
|
-val find_type_expansion_opt: Path.t -> t -> type_expr list * type_expr
|
|
+ ?use_local:bool -> ?level:int -> Path.t -> t ->
|
|
+ type_expr list * type_expr * int option
|
|
+val find_type_expansion_opt:
|
|
+ Path.t -> t -> type_expr list * type_expr * int option
|
|
(* Find the manifest type information associated to a type for the sake
|
|
of the compiler's type-based optimisations. *)
|
|
val find_modtype_expansion: Path.t -> t -> Types.module_type
|
|
|
|
val has_local_constraints: t -> bool
|
|
-val map_newtype_level: t -> int -> int
|
|
+val add_gadt_instance_level: int -> t -> t
|
|
+val gadt_instance_level: t -> type_expr -> int option
|
|
+val add_gadt_instances: t -> int -> type_expr list -> unit
|
|
+val add_gadt_instance_chain: t -> int -> type_expr -> unit
|
|
|
|
(* Lookup by long identifiers *)
|
|
|
|
Index: typing/types.ml
|
|
===================================================================
|
|
--- typing/types.ml (revision 11214)
|
|
+++ typing/types.ml (working copy)
|
|
@@ -146,8 +146,8 @@
|
|
type_private: private_flag;
|
|
type_manifest: type_expr option;
|
|
type_variance: (bool * bool * bool) list;
|
|
- type_newtype_level: int option }
|
|
(* covariant, contravariant, weakly contravariant *)
|
|
+ type_newtype_level: (int * int) option }
|
|
|
|
and type_kind =
|
|
Type_abstract
|
|
Index: testsuite/tests/typing-gadts/test.ml
|
|
===================================================================
|
|
--- testsuite/tests/typing-gadts/test.ml (revision 11214)
|
|
+++ testsuite/tests/typing-gadts/test.ml (working copy)
|
|
@@ -159,17 +159,21 @@
|
|
|
|
let ky x y = ignore (x = y); x ;;
|
|
|
|
+let test : type a. a t -> a =
|
|
+ function Int -> ky (1 : a) 1
|
|
+;;
|
|
+
|
|
let test : type a. a t -> a = fun x ->
|
|
- let r = match x with Int -> ky (1 : a) 1
|
|
+ let r = match x with Int -> ky (1 : a) 1 (* fails *)
|
|
in r
|
|
;;
|
|
let test : type a. a t -> a = fun x ->
|
|
- let r = match x with Int -> ky 1 (1 : a)
|
|
+ let r = match x with Int -> ky 1 (1 : a) (* fails *)
|
|
in r
|
|
;;
|
|
let test : type a. a t -> a = fun x ->
|
|
- let r = match x with Int -> (1 : a)
|
|
- in r (* fails too *)
|
|
+ let r = match x with Int -> (1 : a) (* ok! *)
|
|
+ in r
|
|
;;
|
|
let test : type a. a t -> a = fun x ->
|
|
let r : a = match x with Int -> 1
|
|
@@ -178,7 +182,7 @@
|
|
let test2 : type a. a t -> a option = fun x ->
|
|
let r = ref None in
|
|
begin match x with Int -> r := Some (1 : a) end;
|
|
- !r (* normalized to int option *)
|
|
+ !r (* ok *)
|
|
;;
|
|
let test2 : type a. a t -> a option = fun x ->
|
|
let r : a option ref = ref None in
|
|
@@ -190,19 +194,19 @@
|
|
let u = ref None in
|
|
begin match x with Int -> r := Some 1; u := !r end;
|
|
!u
|
|
-;; (* fail *)
|
|
+;; (* ok (u non-ambiguous) *)
|
|
let test2 : type a. a t -> a option = fun x ->
|
|
let r : a option ref = ref None in
|
|
let u = ref None in
|
|
begin match x with Int -> u := Some 1; r := !u end;
|
|
!u
|
|
-;; (* fail *)
|
|
+;; (* fails because u : (int | a) option ref *)
|
|
let test2 : type a. a t -> a option = fun x ->
|
|
let u = ref None in
|
|
let r : a option ref = ref None in
|
|
begin match x with Int -> r := Some 1; u := !r end;
|
|
!u
|
|
-;; (* fail *)
|
|
+;; (* ok *)
|
|
let test2 : type a. a t -> a option = fun x ->
|
|
let u = ref None in
|
|
let a =
|
|
@@ -210,32 +214,32 @@
|
|
begin match x with Int -> r := Some 1; u := !r end;
|
|
!u
|
|
in a
|
|
-;; (* fail *)
|
|
+;; (* ok *)
|
|
|
|
(* Effect of external consraints *)
|
|
|
|
let f (type a) (x : a t) y =
|
|
ignore (y : a);
|
|
- let r = match x with Int -> (y : a) in (* fails *)
|
|
+ let r = match x with Int -> (y : a) in (* ok *)
|
|
r
|
|
;;
|
|
let f (type a) (x : a t) y =
|
|
let r = match x with Int -> (y : a) in
|
|
- ignore (y : a); (* fails *)
|
|
+ ignore (y : a); (* ok *)
|
|
r
|
|
;;
|
|
let f (type a) (x : a t) y =
|
|
ignore (y : a);
|
|
- let r = match x with Int -> y in
|
|
+ let r = match x with Int -> y in (* ok *)
|
|
r
|
|
;;
|
|
let f (type a) (x : a t) y =
|
|
let r = match x with Int -> y in
|
|
- ignore (y : a);
|
|
+ ignore (y : a); (* ok *)
|
|
r
|
|
;;
|
|
let f (type a) (x : a t) (y : a) =
|
|
- match x with Int -> y (* should return an int! *)
|
|
+ match x with Int -> y (* returns 'a *)
|
|
;;
|
|
|
|
(* Pattern matching *)
|
|
@@ -307,4 +311,4 @@
|
|
| {left=TE TC; right=D [|1.0|]} -> 14
|
|
| {left=TA; right=D 0} -> -1
|
|
| {left=TA; right=D z} -> z
|
|
-;; (* warn *)
|
|
+;; (* ok *)
|