Skip to content

Commit 0886ec6

Browse files
committed
Fix bug with join
1 parent 104e883 commit 0886ec6

File tree

3 files changed

+88
-60
lines changed

3 files changed

+88
-60
lines changed

middle_end/flambda2/types/meet_and_join_new.ml

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1716,8 +1716,8 @@ and join_row_like :
17161716
join_shape:('shape -> 'shape -> 'shape Or_unknown.t) ->
17171717
merge_map_known:
17181718
(('row_tag ->
1719-
('lattice, 'shape, 'maps_to) TG.Row_like_case.t option ->
1720-
('lattice, 'shape, 'maps_to) TG.Row_like_case.t option ->
1719+
('lattice, 'shape, 'maps_to) TG.Row_like_case.t Or_unknown.t option ->
1720+
('lattice, 'shape, 'maps_to) TG.Row_like_case.t Or_unknown.t option ->
17211721
('lattice, 'shape, 'maps_to) TG.Row_like_case.t Or_unknown.t option) ->
17221722
'known ->
17231723
'known ->
@@ -1771,11 +1771,16 @@ and join_row_like :
17711771
in
17721772
TG.Row_like_case.create ~maps_to ~index ~env_extension)
17731773
in
1774-
let join_knowns case1 case2 :
1774+
let join_knowns
1775+
(case1 :
1776+
('lattice, 'shape, 'maps_to) TG.Row_like_case.t Or_unknown.t option)
1777+
(case2 :
1778+
('lattice, 'shape, 'maps_to) TG.Row_like_case.t Or_unknown.t option) :
17751779
('lattice, 'shape, 'maps_to) TG.Row_like_case.t Or_unknown.t option =
17761780
match case1, case2 with
17771781
| None, None -> None
1778-
| Some case1, None -> (
1782+
| Some Unknown, _ | _, Some Unknown -> Some Unknown
1783+
| Some (Known case1), None -> (
17791784
let only_case1 () =
17801785
(* cf. Type_descr.join_head_or_unknown_or_bottom, we need to join these
17811786
to ensure that free variables not present in the target env are
@@ -1793,7 +1798,7 @@ and join_row_like :
17931798
match other2 with
17941799
| Bottom -> only_case1 ()
17951800
| Ok other_case -> Some (join_case join_env case1 other_case))
1796-
| None, Some case2 -> (
1801+
| None, Some (Known case2) -> (
17971802
let only_case2 () =
17981803
(* See at the other bottom case *)
17991804
let join_env =
@@ -1808,7 +1813,8 @@ and join_row_like :
18081813
match other1 with
18091814
| Bottom -> only_case2 ()
18101815
| Ok other_case -> Some (join_case join_env other_case case2))
1811-
| Some case1, Some case2 -> Some (join_case join_env case1 case2)
1816+
| Some (Known case1), Some (Known case2) ->
1817+
Some (join_case join_env case1 case2)
18121818
in
18131819
let known =
18141820
merge_map_known
@@ -1853,22 +1859,11 @@ and join_row_like_for_blocks env
18531859
let join_shape shape1 shape2 : _ Or_unknown.t =
18541860
if K.Block_shape.equal shape1 shape2 then Known shape1 else Unknown
18551861
in
1856-
let merge_map_known join_case known1 known2 =
1857-
Tag.Map.merge
1858-
(fun tag (case1 : _ Or_unknown.t option) (case2 : _ Or_unknown.t option) :
1859-
_ Or_unknown.t option ->
1860-
match case1, case2 with
1861-
| None, case | case, None -> case
1862-
| Some Unknown, Some _ | Some _, Some Unknown -> Some Unknown
1863-
| Some (Known case1), Some (Known case2) ->
1864-
join_case tag (Some case1) (Some case2))
1865-
known1 known2
1866-
in
18671862
Or_unknown.map
18681863
(join_row_like ~join_maps_to:join_int_indexed_product
18691864
~equal_index:TG.Block_size.equal ~inter_index:TG.Block_size.inter
1870-
~join_shape ~merge_map_known env ~known1 ~known2 ~other1 ~other2)
1871-
~f:(fun (known_tags, other_tags) ->
1865+
~join_shape ~merge_map_known:Tag.Map.merge env ~known1 ~known2 ~other1
1866+
~other2) ~f:(fun (known_tags, other_tags) ->
18721867
let alloc_mode = join_alloc_mode alloc_mode1 alloc_mode2 in
18731868
TG.Row_like_for_blocks.create_raw ~known_tags ~other_tags ~alloc_mode)
18741869

@@ -1880,17 +1875,13 @@ and join_row_like_for_closures env
18801875
let merge_map_known join_case known1 known2 =
18811876
Function_slot.Map.merge
18821877
(fun function_slot case1 case2 ->
1883-
match case1, case2 with
1884-
| None, case | case, None -> case
1885-
| Some case1, Some case2 -> (
1886-
match
1887-
(join_case function_slot (Some case1) (Some case2)
1888-
: _ Or_unknown.t option)
1889-
with
1890-
| None -> None
1891-
| Some (Known case) -> Some case
1892-
| Some Unknown ->
1893-
Misc.fatal_error "Join row_like case for closures returned Unknown"))
1878+
let case1 = Option.map (fun case -> Or_unknown.Known case) case1 in
1879+
let case2 = Option.map (fun case -> Or_unknown.Known case) case2 in
1880+
match (join_case function_slot case1 case2 : _ Or_unknown.t option) with
1881+
| None -> None
1882+
| Some (Known case) -> Some case
1883+
| Some Unknown ->
1884+
Misc.fatal_error "Join row_like case for closures returned Unknown")
18941885
known1 known2
18951886
in
18961887
match

middle_end/flambda2/types/meet_and_join_old.ml

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,8 +1444,8 @@ and join_row_like :
14441444
join_shape:('shape -> 'shape -> 'shape Or_unknown.t) ->
14451445
merge_map_known:
14461446
(('row_tag ->
1447-
('lattice, 'shape, 'maps_to) TG.Row_like_case.t option ->
1448-
('lattice, 'shape, 'maps_to) TG.Row_like_case.t option ->
1447+
('lattice, 'shape, 'maps_to) TG.Row_like_case.t Or_unknown.t option ->
1448+
('lattice, 'shape, 'maps_to) TG.Row_like_case.t Or_unknown.t option ->
14491449
('lattice, 'shape, 'maps_to) TG.Row_like_case.t Or_unknown.t option) ->
14501450
'known ->
14511451
'known ->
@@ -1499,11 +1499,16 @@ and join_row_like :
14991499
in
15001500
TG.Row_like_case.create ~maps_to ~index ~env_extension)
15011501
in
1502-
let join_knowns case1 case2 :
1502+
let join_knowns
1503+
(case1 :
1504+
('lattice, 'shape, 'maps_to) TG.Row_like_case.t Or_unknown.t option)
1505+
(case2 :
1506+
('lattice, 'shape, 'maps_to) TG.Row_like_case.t Or_unknown.t option) :
15031507
('lattice, 'shape, 'maps_to) TG.Row_like_case.t Or_unknown.t option =
15041508
match case1, case2 with
15051509
| None, None -> None
1506-
| Some case1, None -> (
1510+
| Some Unknown, _ | _, Some Unknown -> Some Unknown
1511+
| Some (Known case1), None -> (
15071512
let only_case1 () =
15081513
(* cf. Type_descr.join_head_or_unknown_or_bottom, we need to join these
15091514
to ensure that free variables not present in the target env are
@@ -1521,7 +1526,7 @@ and join_row_like :
15211526
match other2 with
15221527
| Bottom -> only_case1 ()
15231528
| Ok other_case -> Some (join_case join_env case1 other_case))
1524-
| None, Some case2 -> (
1529+
| None, Some (Known case2) -> (
15251530
let only_case2 () =
15261531
(* See at the other bottom case *)
15271532
let join_env =
@@ -1536,7 +1541,8 @@ and join_row_like :
15361541
match other1 with
15371542
| Bottom -> only_case2 ()
15381543
| Ok other_case -> Some (join_case join_env other_case case2))
1539-
| Some case1, Some case2 -> Some (join_case join_env case1 case2)
1544+
| Some (Known case1), Some (Known case2) ->
1545+
Some (join_case join_env case1 case2)
15401546
in
15411547
let known =
15421548
merge_map_known
@@ -1581,22 +1587,11 @@ and join_row_like_for_blocks env
15811587
let join_shape shape1 shape2 : _ Or_unknown.t =
15821588
if K.Block_shape.equal shape1 shape2 then Known shape1 else Unknown
15831589
in
1584-
let merge_map_known join_case known1 known2 =
1585-
Tag.Map.merge
1586-
(fun tag (case1 : _ Or_unknown.t option) (case2 : _ Or_unknown.t option) :
1587-
_ Or_unknown.t option ->
1588-
match case1, case2 with
1589-
| None, case | case, None -> case
1590-
| Some Unknown, Some _ | Some _, Some Unknown -> Some Unknown
1591-
| Some (Known case1), Some (Known case2) ->
1592-
join_case tag (Some case1) (Some case2))
1593-
known1 known2
1594-
in
15951590
Or_unknown.map
15961591
(join_row_like ~join_maps_to:join_int_indexed_product
15971592
~equal_index:TG.Block_size.equal ~inter_index:TG.Block_size.inter
1598-
~join_shape ~merge_map_known env ~known1 ~known2 ~other1 ~other2)
1599-
~f:(fun (known_tags, other_tags) ->
1593+
~join_shape ~merge_map_known:Tag.Map.merge env ~known1 ~known2 ~other1
1594+
~other2) ~f:(fun (known_tags, other_tags) ->
16001595
let alloc_mode = join_alloc_mode alloc_mode1 alloc_mode2 in
16011596
TG.Row_like_for_blocks.create_raw ~known_tags ~other_tags ~alloc_mode)
16021597

@@ -1608,17 +1603,13 @@ and join_row_like_for_closures env
16081603
let merge_map_known join_case known1 known2 =
16091604
Function_slot.Map.merge
16101605
(fun function_slot case1 case2 ->
1611-
match case1, case2 with
1612-
| None, case | case, None -> case
1613-
| Some case1, Some case2 -> (
1614-
match
1615-
(join_case function_slot (Some case1) (Some case2)
1616-
: _ Or_unknown.t option)
1617-
with
1618-
| None -> None
1619-
| Some (Known case) -> Some case
1620-
| Some Unknown ->
1621-
Misc.fatal_error "Join row_like case for closures returned Unknown"))
1606+
let case1 = Option.map (fun case -> Or_unknown.Known case) case1 in
1607+
let case2 = Option.map (fun case -> Or_unknown.Known case) case2 in
1608+
match (join_case function_slot case1 case2 : _ Or_unknown.t option) with
1609+
| None -> None
1610+
| Some (Known case) -> Some case
1611+
| Some Unknown ->
1612+
Misc.fatal_error "Join row_like case for closures returned Unknown")
16221613
known1 known2
16231614
in
16241615
match
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
(* TEST *)
2+
3+
(* Tests a corner case of the Flambda2 join algorithm.
4+
This checks that joining a row-like type where the tags are known,
5+
with a row-like type where the tag is not known, correctly
6+
takes both sides into account. *)
7+
8+
(* GADTs allow us to hide kind information *)
9+
type _ t = A : (int * int) t | B : (int * int) t
10+
11+
let[@inline never] f (type a) (x : a) (cond : a t) =
12+
let result : a =
13+
match cond with
14+
| A -> (0, 1) (* Known tag *)
15+
| B -> begin
16+
let r = fst x in (* Creates an equation on [x] with unknown tag *)
17+
ignore (Sys.opaque_identity r);
18+
x
19+
end
20+
in
21+
(* At this point, [result] has been joined with no kind information.
22+
If everything went well, we should know that:
23+
- It can have tag 0 (as branch A has this tag)
24+
- It can have any tag (as branch B doesn't restrict the tag)
25+
The point of this test is to check that the approximation for
26+
[result] doesn't assume that if it has tag 0, it must have come
27+
from branch A. *)
28+
(* We now need to cast it back to a tuple: *)
29+
let result : int * int = match cond with A -> result | B -> result in
30+
(* Then we need to actually introduce the constraint on the tag.
31+
This is done by storing it into a block with a known shape: *)
32+
let ignored : (unit * (int * int)) = (), result in
33+
(* Now, if we wrongly assumed that only branch A has tag 0,
34+
we would be able to propagate that information here and replace
35+
[a + b] by the constant 1.*)
36+
let a, b = result in
37+
(* [ignored] is returned to make sure we don't remove the block
38+
creation primitive that adds the tag constraint *)
39+
a + b, ignored
40+
41+
let test () =
42+
let r, _ = f (2, 3) B in
43+
assert (r == 5);
44+
()
45+
46+
let () = test ()

0 commit comments

Comments
 (0)