Skip to content

Commit 1085b58

Browse files
committed
Deal correctly with open types after unboxing
1 parent fc04399 commit 1085b58

File tree

5 files changed

+118
-33
lines changed

5 files changed

+118
-33
lines changed

testsuite/tests/typing-jkind-bounds/with_basics.ml

+24
Original file line numberDiff line numberDiff line change
@@ -1208,3 +1208,27 @@ Line 1, characters 65-66:
12081208
^
12091209
Error: This value is "nonportable" but expected to be "portable".
12101210
|}]
1211+
1212+
(*********************************************)
1213+
(* Reduction of error seen in the tree *)
1214+
(* This requires the [is_open] technology in Ctype. *)
1215+
1216+
type 'k t1 = T of Obj.t [@@unboxed]
1217+
1218+
type 'k t2 = { x : 'k t1 }
1219+
1220+
type packed = T : _ t2 -> packed [@@unboxed]
1221+
1222+
type q = { x : packed }
1223+
1224+
module type S = sig
1225+
type t = private q
1226+
end with type t = q
1227+
1228+
[%%expect{|
1229+
type 'k t1 = T of Obj.t [@@unboxed]
1230+
type 'k t2 = { x : 'k t1; }
1231+
type packed = T : 'a t2 -> packed [@@unboxed]
1232+
type q = { x : packed; }
1233+
module type S = sig type t = q end
1234+
|}]

typing/ctype.ml

+83-27
Original file line numberDiff line numberDiff line change
@@ -2100,9 +2100,14 @@ let expand_head_opt env ty =
21002100
let is_principal ty =
21012101
not !Clflags.principal || get_level ty = generic_level
21022102

2103+
type open_type_expr = { ty : type_expr; is_open : bool }
2104+
2105+
let mk_open_type_expr ty vars =
2106+
{ ty; is_open = List.compare_length_with vars 0 <> 0 }
2107+
21032108
type unbox_result =
21042109
(* unboxing process made a step: either an unboxing or removal of a [Tpoly] *)
2105-
| Stepped of type_expr
2110+
| Stepped of open_type_expr
21062111
(* unboxing process unboxed a product. Invariant: length >= 2 *)
21072112
| Stepped_record_unboxed_product of type_expr list
21082113
(* no step to make; we're all done here *)
@@ -2120,7 +2125,16 @@ let unbox_once env ty =
21202125
begin match find_unboxed_type decl with
21212126
| Some ty2 ->
21222127
let ty2 = match get_desc ty2 with Tpoly (t, _) -> t | _ -> ty2 in
2123-
Stepped (apply ty2)
2128+
let existentials =
2129+
match Env.find_type_descrs p env with
2130+
| Type_variant ([{ cstr_existentials }], _, _) -> cstr_existentials
2131+
| Type_variant (_not_one, _, _) ->
2132+
Misc.fatal_error "Ctype.unbox_once: not just one constructor"
2133+
| Type_abstract _ | Type_record _
2134+
| Type_record_unboxed_product _ | Type_open -> []
2135+
| exception Not_found -> (* but we found it earlier! *) assert false
2136+
in
2137+
Stepped (mk_open_type_expr (apply ty2) existentials)
21242138
| None -> begin match decl.type_kind with
21252139
| Type_record_unboxed_product ([_], Record_unboxed_product, _) ->
21262140
(* [find_unboxed_type] would have returned [Some] *)
@@ -2136,14 +2150,14 @@ let unbox_once env ty =
21362150
end
21372151
end
21382152
end
2139-
| Tpoly (ty, _) -> Stepped ty
2153+
| Tpoly (ty, bound_vars) -> Stepped (mk_open_type_expr ty bound_vars)
21402154
| _ -> Final_result
21412155

21422156
let contained_without_boxing env ty =
21432157
match get_desc ty with
21442158
| Tconstr _ ->
21452159
begin match unbox_once env ty with
2146-
| Stepped ty -> [ty]
2160+
| Stepped { ty; _ } -> [ty]
21472161
| Stepped_record_unboxed_product tys -> tys
21482162
| Final_result | Missing _ -> []
21492163
end
@@ -2157,15 +2171,20 @@ let contained_without_boxing env ty =
21572171
allowing us to return a type for which a definition was found even if
21582172
we eventually bottom out at a missing cmi file, or otherwise. *)
21592173
let rec get_unboxed_type_representation env ty_prev ty fuel =
2160-
if fuel < 0 then Error ty else
2174+
if fuel < 0 then Error { ty; is_open = false } else
21612175
(* We use expand_head_opt version of expand_head to get access
21622176
to the manifest type of private abbreviations. *)
21632177
let ty = expand_head_opt env ty in
21642178
match unbox_once env ty with
2165-
| Stepped ty2 ->
2166-
get_unboxed_type_representation env ty ty2 (fuel - 1)
2167-
| Stepped_record_unboxed_product _ | Final_result -> Ok ty
2168-
| Missing _ -> Ok ty_prev
2179+
| Stepped { ty = ty2; is_open = open1 } ->
2180+
begin match get_unboxed_type_representation env ty ty2 (fuel - 1) with
2181+
| Ok { ty = result; is_open = open2 } ->
2182+
Ok { ty = result; is_open = open1 || open2 }
2183+
| Error _ as err -> err
2184+
end
2185+
| Stepped_record_unboxed_product _ | Final_result ->
2186+
Ok { ty; is_open = false }
2187+
| Missing _ -> Ok { ty = ty_prev; is_open = false }
21692188

21702189
let get_unboxed_type_representation env ty =
21712190
(* Do not give too much fuel: PR#7424 *)
@@ -2194,21 +2213,23 @@ let type_jkind_purely_if_principal' =
21942213
(* We parameterize [estimate_type_jkind] by a function
21952214
[expand_component] because some callers want expansion of types and others
21962215
don't. *)
2197-
let rec estimate_type_jkind ~expand_component env ty =
2216+
let rec estimate_type_jkind ~(expand_component : type_expr -> open_type_expr) env ty =
21982217
match get_desc ty with
21992218
| Tvar { jkind } -> Jkind.disallow_right jkind
22002219
| Tarrow _ -> Jkind.for_arrow
22012220
| Ttuple _ -> Jkind.Builtin.value ~why:Tuple
22022221
| Tunboxed_tuple ltys ->
2203-
let tys_modalities =
2204-
List.map (fun (_, ty) -> expand_component ty,
2205-
Mode.Modality.Value.Const.id) ltys
2222+
let is_open, tys_modalities =
2223+
List.fold_left_map
2224+
(fun is_open1 (_lbl, ty) ->
2225+
let { ty; is_open = is_open2 } = expand_component ty in
2226+
(is_open1 || is_open2), (ty, Mode.Modality.Value.Const.id))
2227+
false ltys
22062228
in
22072229
(* CR layouts v2.8: This pretty ridiculous use of [estimate_type_jkind]
22082230
just to throw most of it away will go away once we get [layout_of]. *)
22092231
let jkinds =
2210-
List.map
2211-
(fun (ty, _) -> estimate_type_jkind ~expand_component env ty)
2232+
List.map (fun (ty, _) -> estimate_type_jkind ~expand_component env ty)
22122233
tys_modalities
22132234
in
22142235
let layouts = List.map Jkind.extract_layout jkinds in
@@ -2220,7 +2241,8 @@ let rec estimate_type_jkind ~expand_component env ty =
22202241
| _ -> Misc.fatal_error
22212242
"Ctype.estimate_type_jkind: use of jkind_of_first_type \
22222243
with more than 1 type")
2223-
~why:Unboxed_tuple tys_modalities layouts
2244+
~why:Unboxed_tuple tys_modalities layouts |>
2245+
close_open_jkind ~expand_component ~is_open env
22242246
| Tconstr (p, args, _) -> begin try
22252247
let type_decl = Env.find_type p env in
22262248
let jkind = type_decl.type_jkind in
@@ -2264,8 +2286,25 @@ let rec estimate_type_jkind ~expand_component env ty =
22642286
Jkind.disallow_right
22652287
| Tpackage _ -> Jkind.Builtin.value ~why:First_class_module
22662288

2289+
and close_open_jkind ~expand_component ~is_open env jkind =
2290+
if is_open (* if the type has free variables, we can't let these leak into
2291+
with-bounds *)
2292+
(* CR layouts v2.8: Do better, by tracking the actual free variables and
2293+
rounding only those variables up. *)
2294+
then
2295+
let jkind_of_type ty =
2296+
Some (estimate_type_jkind ~expand_component env ty)
2297+
in
2298+
Jkind.round_up ~jkind_of_type jkind |> Jkind.disallow_right
2299+
else jkind
2300+
2301+
let estimate_type_jkind_open ~expand_component env { ty; is_open } =
2302+
estimate_type_jkind ~expand_component env ty |>
2303+
close_open_jkind ~expand_component ~is_open env
2304+
22672305
let type_jkind env ty =
2268-
estimate_type_jkind ~expand_component:(get_unboxed_type_approximation env) env
2306+
estimate_type_jkind_open
2307+
~expand_component:(get_unboxed_type_approximation env) env
22692308
(get_unboxed_type_approximation env ty)
22702309

22712310
(* CR layouts v2.8: This function is quite suspect. See Jane Street internal
@@ -2289,7 +2328,13 @@ let type_jkind_purely_if_principal env ty =
22892328
| false -> None
22902329
let () = type_jkind_purely_if_principal' := type_jkind_purely_if_principal
22912330

2292-
let estimate_type_jkind = estimate_type_jkind ~expand_component:Fun.id
2331+
let estimate_type_jkind =
2332+
let expand_component ty = { ty; is_open = false } in
2333+
estimate_type_jkind ~expand_component
2334+
2335+
let estimate_type_jkind_open =
2336+
let expand_component ty = { ty; is_open = false } in
2337+
estimate_type_jkind_open ~expand_component
22932338

22942339
(**** checking jkind relationships ****)
22952340

@@ -2315,8 +2360,11 @@ let constrain_type_jkind ~fixed env ty jkind =
23152360
ensure it's a valid argument to [t]. (We believe there are still loops
23162361
like this that can occur, though, and may need a more principled solution
23172362
later).
2363+
2364+
As this unboxes types, it might unbox an existential type. We thus keep
2365+
track of whether [ty] [is_open].
23182366
*)
2319-
let rec loop ~fuel ~expanded ty ty's_jkind jkind =
2367+
let rec loop ~fuel ~expanded ty ~is_open ty's_jkind jkind =
23202368
(* Just succeed if we're comparing against [any] *)
23212369
if Jkind.is_obviously_max jkind then Ok () else
23222370
if fuel < 0 then
@@ -2326,7 +2374,8 @@ let constrain_type_jkind ~fixed env ty jkind =
23262374
else
23272375
match get_desc ty with
23282376
(* The [ty's_jkind] we get here is an **r** jkind, necessary for
2329-
the call to [intersection_or_error]. *)
2377+
the call to [intersection_or_error]. And even if [ty] has unbound
2378+
variables, [ty's_jkind] can't have any variables in it, so we're OK. *)
23302379
| Tvar { jkind = ty's_jkind } when not fixed ->
23312380
(* Unfixed tyvars are special in at least two ways:
23322381
@@ -2356,7 +2405,11 @@ let constrain_type_jkind ~fixed env ty jkind =
23562405

23572406
(* Handle the [Tpoly] case out here so [Tvar]s wrapped in [Tpoly]s can get
23582407
the treatment above. *)
2359-
| Tpoly (t, _) -> loop ~fuel ~expanded:false t ty's_jkind jkind
2408+
| Tpoly (t, bound_vars) ->
2409+
let is_open =
2410+
is_open || match bound_vars with | [] -> false | _ :: _ -> true
2411+
in
2412+
loop ~fuel ~expanded:false t ~is_open ty's_jkind jkind
23602413

23612414
| _ ->
23622415
match
@@ -2381,7 +2434,7 @@ let constrain_type_jkind ~fixed env ty jkind =
23812434
let recur ty's_jkinds jkinds =
23822435
let results =
23832436
Misc.Stdlib.List.map3
2384-
(loop ~fuel ~expanded:false) tys ty's_jkinds jkinds
2437+
(loop ~fuel ~expanded:false ~is_open) tys ty's_jkinds jkinds
23852438
in
23862439
if List.for_all Result.is_ok results
23872440
then Ok ()
@@ -2413,7 +2466,8 @@ let constrain_type_jkind ~fixed env ty jkind =
24132466
if not expanded
24142467
then
24152468
let ty = expand_head_opt env ty in
2416-
loop ~fuel ~expanded:true ty (estimate_type_jkind env ty) jkind
2469+
loop ~fuel ~expanded:true ty ~is_open
2470+
(estimate_type_jkind_open env { ty; is_open }) jkind
24172471
else
24182472
begin match unbox_once env ty with
24192473
| Missing path -> Error (Jkind.Violation.of_
@@ -2424,9 +2478,10 @@ let constrain_type_jkind ~fixed env ty jkind =
24242478
Error
24252479
(Jkind.Violation.of_ ~jkind_of_type
24262480
(Not_a_subjkind (ty's_jkind, jkind, sub_failure_reasons)))
2427-
| Stepped ty ->
2428-
loop ~fuel:(fuel - 1) ~expanded:false ty
2429-
(estimate_type_jkind env ty) jkind
2481+
| Stepped { ty; is_open = is_open2 } ->
2482+
let is_open = is_open || is_open2 in
2483+
loop ~fuel:(fuel - 1) ~expanded:false ty ~is_open
2484+
(estimate_type_jkind_open env { ty; is_open }) jkind
24302485
| Stepped_record_unboxed_product tys ->
24312486
product ~fuel:(fuel - 1) tys
24322487
end
@@ -2440,7 +2495,8 @@ let constrain_type_jkind ~fixed env ty jkind =
24402495
Error (Jkind.Violation.of_ ~jkind_of_type
24412496
(Not_a_subjkind (ty's_jkind, jkind, sub_failure_reasons)))
24422497
in
2443-
loop ~fuel:100 ~expanded:false ty (estimate_type_jkind env ty) jkind
2498+
loop ~fuel:100 ~expanded:false ty ~is_open:false
2499+
(estimate_type_jkind env ty) jkind
24442500

24452501
let type_sort ~why ~fixed env ty =
24462502
let jkind, sort = Jkind.of_new_sort_var ~why in

typing/ctype.mli

+8-3
Original file line numberDiff line numberDiff line change
@@ -569,21 +569,26 @@ val package_subtype :
569569
(* Raises [Incompatible] *)
570570
val mcomp : Env.t -> type_expr -> type_expr -> unit
571571

572+
(* A type with whether it has any unbound variables. This could easily
573+
be changed to actually track the variables, if there is ever a need. *)
574+
type open_type_expr = { ty : type_expr; is_open : bool }
575+
572576
val get_unboxed_type_representation :
573-
Env.t -> type_expr -> (type_expr, type_expr) result
577+
Env.t -> type_expr -> (open_type_expr, open_type_expr) result
574578
(* [get_unboxed_type_representation] attempts to fully expand the input
575579
type_expr, descending through [@@unboxed] types. May fail in the case of
576580
circular types or very deeply nested unboxed types, in which case it
577581
returns the most expanded version it was able to compute. *)
578582

579-
val get_unboxed_type_approximation : Env.t -> type_expr -> type_expr
583+
val get_unboxed_type_approximation : Env.t -> type_expr -> open_type_expr
580584
(* [get_unboxed_type_approximation] does the same thing as
581585
[get_unboxed_type_representation], but doesn't indicate whether the type
582586
was fully expanded or not. *)
583587

584588
val contained_without_boxing : Env.t -> type_expr -> type_expr list
585589
(* Return all types that are directly contained without boxing
586-
(or "without indirection" or "flatly") *)
590+
(or "without indirection" or "flatly"); in the case of [@@unboxed]
591+
existentials, these types might have free variables*)
587592

588593
(* Given the row from a variant type, determine if it is immediate. Currently
589594
just checks that all constructors have no arguments, doesn't consider

typing/typedecl.ml

+2-2
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ let update_type temp_env env id loc =
369369
be possible.
370370
*)
371371
let is_float env ty =
372-
match get_desc (Ctype.get_unboxed_type_approximation env ty) with
372+
match get_desc (Ctype.get_unboxed_type_approximation env ty).ty with
373373
Tconstr(p, _, _) -> Path.same p Predef.path_float
374374
| _ -> false
375375

@@ -3188,7 +3188,7 @@ let type_sort_external ~is_layout_poly ~why env loc typ =
31883188
let make_native_repr env core_type ty ~global_repr ~is_layout_poly ~why =
31893189
error_if_has_deep_native_repr_attributes core_type;
31903190
let sort_or_poly =
3191-
match get_desc (Ctype.get_unboxed_type_approximation env ty) with
3191+
match get_desc (Ctype.get_unboxed_type_approximation env ty).ty with
31923192
(* This only captures tvars with layout [any] explicitly quantified within
31933193
the declaration.
31943194

typing/typeopt.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ let scrape_ty env ty =
5858
begin match get_desc ty' with
5959
| Tconstr (p, _, _) ->
6060
begin match find_unboxed_type (Env.find_type p env) with
61-
| Some _ -> Ctype.get_unboxed_type_approximation env ty'
61+
| Some _ -> (Ctype.get_unboxed_type_approximation env ty').ty
6262
| None -> ty'
6363
| exception Not_found -> ty (* missing cmi file *)
6464
end

0 commit comments

Comments
 (0)