@@ -2443,16 +2443,7 @@ defmodule Module.Types.Descr do
2443
2443
acc ->
2444
2444
try do
2445
2445
{ tag , fields } = map_literal_intersection ( tag1 , pos1 , tag2 , pos2 )
2446
- entry = { tag , fields , negs1 ++ negs2 }
2447
-
2448
- # Imagine a, b, c, where a is closed and b and c are open with
2449
- # no keys in common. The result in both cases will be a and we
2450
- # want to avoid adding duplicates, especially as intersection
2451
- # is a cartesian product.
2452
- case :lists . member ( entry , acc ) do
2453
- true -> acc
2454
- false -> [ entry | acc ]
2455
- end
2446
+ prepend_to_map_dnf ( tag , fields , negs1 ++ ( negs2 -- negs1 ) , acc )
2456
2447
catch
2457
2448
:empty -> acc
2458
2449
end
@@ -2567,42 +2558,61 @@ defmodule Module.Types.Descr do
2567
2558
if empty? ( type ) , do: throw ( :empty ) , else: type
2568
2559
end
2569
2560
2570
- defp map_difference ( _ , dnf ) when dnf == @ map_top do
2571
- 0
2572
- end
2561
+ defp map_difference ( _ , dnf ) when dnf == @ map_top , do: [ ]
2562
+ defp map_difference ( dnf , dnf ) , do: [ ]
2573
2563
2574
2564
defp map_difference ( dnf1 , dnf2 ) do
2575
2565
Enum . reduce ( dnf2 , dnf1 , fn
2576
- # Optimization: we are removing an open map with one field.
2577
- { :open , fields2 , [ ] } , dnf1 when map_size ( fields2 ) == 1 ->
2578
- Enum . reduce ( dnf1 , [ ] , fn { tag1 , fields1 , negs1 } , acc ->
2566
+ { :open , fields2 , [ ] } , current_dnf when map_size ( fields2 ) == 1 ->
2567
+ # Optimization: we are removing an open map with one field.
2568
+ Enum . reduce ( current_dnf , [ ] , fn { tag1 , fields1 , negs1 } , acc ->
2579
2569
{ key , value , _rest } = :maps . next ( :maps . iterator ( fields2 ) )
2580
2570
t_diff = difference ( Map . get ( fields1 , key , map_key_tag_to_type ( tag1 ) ) , value )
2581
2571
2582
2572
if empty? ( t_diff ) do
2583
2573
acc
2584
2574
else
2585
- [ { tag1 , Map . put ( fields1 , key , t_diff ) , negs1 } | acc ]
2575
+ { tag , pos } = { tag1 , Map . put ( fields1 , key , t_diff ) }
2576
+ entry = { tag , pos , negs1 }
2577
+
2578
+ cond do
2579
+ :lists . member ( { tag , pos } , negs1 ) -> acc
2580
+ :lists . member ( entry , acc ) -> acc
2581
+ true -> [ entry | acc ]
2582
+ end
2586
2583
end
2587
2584
end )
2588
2585
2589
- { tag2 , fields2 , negs2 } , dnf1 ->
2590
- Enum . reduce ( dnf1 , [ ] , fn { tag1 , fields1 , negs1 } , acc ->
2591
- acc = [ { tag1 , fields1 , [ { tag2 , fields2 } | negs1 ] } | acc ]
2586
+ { tag2 , fields2 , negs2 } , current_dnf ->
2587
+ Enum . reduce ( current_dnf , [ ] , fn { tag1 , fields1 , negs1 } , acc ->
2588
+ negs =
2589
+ if :lists . member ( { tag2 , fields2 } , negs1 ) do
2590
+ negs1
2591
+ else
2592
+ [ { tag2 , fields2 } | negs1 ]
2593
+ end
2594
+
2595
+ acc = prepend_to_map_dnf ( tag1 , fields1 , negs , acc )
2592
2596
2593
2597
Enum . reduce ( negs2 , acc , fn { neg_tag2 , neg_fields2 } , acc ->
2594
2598
try do
2595
2599
{ tag , fields } = map_literal_intersection ( tag1 , fields1 , neg_tag2 , neg_fields2 )
2596
- [ { tag , fields , negs1 } | acc ]
2600
+ prepend_to_map_dnf ( tag , fields , negs1 , acc )
2597
2601
catch
2598
2602
:empty -> acc
2599
2603
end
2600
2604
end )
2601
2605
end )
2602
2606
end )
2603
- |> case do
2604
- [ ] -> 0
2605
- acc -> acc
2607
+ end
2608
+
2609
+ defp prepend_to_map_dnf ( tag , fields , negs , acc ) do
2610
+ entry = { tag , fields , negs }
2611
+
2612
+ cond do
2613
+ :lists . member ( { tag , fields } , negs ) -> acc
2614
+ :lists . member ( entry , acc ) -> acc
2615
+ true -> [ entry | acc ]
2606
2616
end
2607
2617
end
2608
2618
0 commit comments