Skip to content

Commit a1b77dc

Browse files
authored
flambda-backend: Fix issue with gadts and layouts (#2618)
* Fix issue with gadts and layouts * Improved fix * Guard fix * when clauses should be pure
1 parent 6a8b0e3 commit a1b77dc

File tree

2 files changed

+110
-2
lines changed

2 files changed

+110
-2
lines changed

testsuite/tests/typing-layouts/basics.ml

+77
Original file line numberDiff line numberDiff line change
@@ -2493,3 +2493,80 @@ Line 1, characters 13-47:
24932493
Error: The primitive [%sendcache] is used in an invalid declaration.
24942494
The declaration contains argument/return types with the wrong layout.
24952495
|}]
2496+
2497+
(*********************************************************)
2498+
(* Test 43: GADT refinement works on layouts as expected *)
2499+
2500+
type ('a : any) t_gadt_simple =
2501+
| Float64 : ('a : float64) t_gadt_simple
2502+
2503+
let f_match_allowed (type a : any) (x : a t_gadt_simple) : int =
2504+
match x with
2505+
| Float64 -> 1;;
2506+
[%%expect{|
2507+
type ('a : any) t_gadt_simple = Float64 : ('a : float64). 'a t_gadt_simple
2508+
val f_match_allowed : ('a : any). 'a t_gadt_simple -> int = <fun>
2509+
|}]
2510+
2511+
let not_magic (type a : any) (x : a t_gadt_simple) : 'b =
2512+
match x with
2513+
| _ -> .
2514+
[%%expect{|
2515+
Line 3, characters 4-5:
2516+
3 | | _ -> .
2517+
^
2518+
Error: This match case could not be refuted.
2519+
Here is an example of a value that would reach it: Float64
2520+
|}]
2521+
2522+
type ('a : any) t =
2523+
| UFloat : float# t
2524+
| Float : float t
2525+
| Int : int t
2526+
2527+
let make_pi (type a : any) (x : a t) : unit -> a =
2528+
match x with
2529+
| UFloat -> fun () -> #3.14
2530+
| Float -> fun () -> 3.14
2531+
| Int -> fun () -> 3;;
2532+
[%%expect{|
2533+
type ('a : any) t = UFloat : float# t | Float : float t | Int : int t
2534+
val make_pi : ('a : any). 'a t -> unit -> 'a = <fun>
2535+
|}]
2536+
2537+
type ('a : any) repr =
2538+
| Float64 : ('a : float64) repr
2539+
| Value : ('a : value) repr
2540+
2541+
let lpoly_id (type a : any) (x : a repr) : a -> a =
2542+
match x with
2543+
| Float64 -> fun x -> x
2544+
| Value -> fun x -> x
2545+
[%%expect{|
2546+
type ('a : any) repr = Float64 : ('a : float64). 'a repr | Value : 'a repr
2547+
val lpoly_id : ('a : any). 'a repr -> 'a -> 'a = <fun>
2548+
|}]
2549+
2550+
type 'a s = 'a
2551+
2552+
module M = struct
2553+
type t : immediate
2554+
end
2555+
2556+
module N = struct
2557+
type ('a,'b) eq =
2558+
| Refl : ('a, 'a) eq
2559+
2560+
let f (x : (M.t, 'a s) eq) : int =
2561+
match x with
2562+
| Refl -> 42
2563+
end
2564+
[%%expect{|
2565+
type 'a s = 'a
2566+
module M : sig type t : immediate end
2567+
module N :
2568+
sig
2569+
type ('a, 'b) eq = Refl : ('a, 'a) eq
2570+
val f : (M.t, M.t s) eq -> int
2571+
end
2572+
|}]

typing/ctype.ml

+33-2
Original file line numberDiff line numberDiff line change
@@ -3333,7 +3333,10 @@ let unify1_var env t1 t2 =
33333333
| _ -> assert false
33343334
in
33353335
occur_for Unify env t1 t2;
3336-
match occur_univar_for Unify env t2 with
3336+
match
3337+
occur_univar_for Unify env t2;
3338+
unification_jkind_check env t2 jkind
3339+
with
33373340
| () ->
33383341
begin
33393342
try
@@ -3342,7 +3345,6 @@ let unify1_var env t1 t2 =
33423345
with Escape e ->
33433346
raise_for Unify (Escape e)
33443347
end;
3345-
unification_jkind_check env t2 jkind;
33463348
link_type t1 t2;
33473349
true
33483350
| exception Unify_trace _ when in_pattern_mode () ->
@@ -3364,6 +3366,18 @@ let unify3_var env jkind1 t1' t2 t2' =
33643366
record_equation t1' t2';
33653367
end
33663368

3369+
(* This is used to check whether we should add a gadt equation refining a
3370+
Tconstr's jkind during pattern unification. *)
3371+
let constr_jkind_refinable env t jkind =
3372+
let snap = Btype.snapshot () in
3373+
let refinable =
3374+
match unification_jkind_check env t jkind with
3375+
| () -> false
3376+
| exception Unify_trace _ -> true
3377+
in
3378+
Btype.backtrack snap;
3379+
refinable
3380+
33673381
(*
33683382
1. When unifying two non-abbreviated types, one type is made a link
33693383
to the other. When unifying an abbreviated type with a
@@ -3491,6 +3505,23 @@ and unify3 env t1 t1' t2 t2' =
34913505
(Tunivar { jkind = k1 }, Tunivar { jkind = k2 }) ->
34923506
unify_univar_for Unify t1' t2' k1 k2 !univar_pairs;
34933507
link_type t1' t2'
3508+
(* Before layouts, the following two cases were unnecessary because unifying a
3509+
[Tconstr] and a [Tvar] couldn't refine the [Tconstr] in any interesting
3510+
way. *)
3511+
| (Tconstr (path,[],_), Tvar { jkind })
3512+
when is_instantiable !env ~for_jkind_eqn:false path
3513+
&& can_generate_equations ()
3514+
&& constr_jkind_refinable !env t1' jkind ->
3515+
reify env t2';
3516+
record_equation t1' t2';
3517+
add_gadt_equation env path t2'
3518+
| (Tvar { jkind }, Tconstr (path,[],_))
3519+
when is_instantiable !env ~for_jkind_eqn:false path
3520+
&& can_generate_equations ()
3521+
&& constr_jkind_refinable !env t2' jkind ->
3522+
reify env t1';
3523+
record_equation t1' t2';
3524+
add_gadt_equation env path t1'
34943525
| (Tvar { jkind }, _) ->
34953526
unify3_var env jkind t1' t2 t2'
34963527
| (_, Tvar { jkind }) ->

0 commit comments

Comments
 (0)