@@ -2443,16 +2443,7 @@ defmodule Module.Types.Descr do
24432443 acc ->
24442444 try do
24452445 { 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 )
24562447 catch
24572448 :empty -> acc
24582449 end
@@ -2567,42 +2558,61 @@ defmodule Module.Types.Descr do
25672558 if empty? ( type ) , do: throw ( :empty ) , else: type
25682559 end
25692560
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: [ ]
25732563
25742564 defp map_difference ( dnf1 , dnf2 ) do
25752565 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 ->
25792569 { key , value , _rest } = :maps . next ( :maps . iterator ( fields2 ) )
25802570 t_diff = difference ( Map . get ( fields1 , key , map_key_tag_to_type ( tag1 ) ) , value )
25812571
25822572 if empty? ( t_diff ) do
25832573 acc
25842574 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
25862583 end
25872584 end )
25882585
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 )
25922596
25932597 Enum . reduce ( negs2 , acc , fn { neg_tag2 , neg_fields2 } , acc ->
25942598 try do
25952599 { 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 )
25972601 catch
25982602 :empty -> acc
25992603 end
26002604 end )
26012605 end )
26022606 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 ]
26062616 end
26072617 end
26082618
0 commit comments