@@ -2370,6 +2370,8 @@ defmodule Module.Types.Descr do
23702370    if  subtype? ( v2 ,  v1 ) ,  do:  :right_subtype_of_left 
23712371  end 
23722372
2373+   defp  map_intersection ( dnf ,  dnf ) ,  do:  dnf 
2374+ 
23732375  # Given two unions of maps, intersects each pair of maps. 
23742376  defp  map_intersection ( dnf1 ,  dnf2 )  do 
23752377    for  { tag1 ,  pos1 ,  negs1 }  <-  dnf1 , 
@@ -2378,15 +2380,17 @@ defmodule Module.Types.Descr do
23782380      acc  -> 
23792381        try  do 
23802382          { tag ,  fields }  =  map_literal_intersection ( tag1 ,  pos1 ,  tag2 ,  pos2 ) 
2381-           entry  =  { tag ,  fields ,  negs1  ++  negs2 } 
2383+           negs  =  negs1  ++  ( negs2  --  negs1 ) 
2384+           entry  =  { tag ,  fields ,  negs } 
23822385
23832386          # Imagine a, b, c, where a is closed and b and c are open with 
23842387          # no keys in common. The result in both cases will be a and we 
23852388          # want to avoid adding duplicates, especially as intersection 
23862389          # is a cartesian product. 
2387-           case  :lists . member ( entry ,  acc )  do 
2388-             true  ->  acc 
2389-             false  ->  [ entry  |  acc ] 
2390+           cond  do 
2391+             :lists . member ( { tag ,  fields } ,  negs )  ->  acc 
2392+             :lists . member ( entry ,  acc )  ->  acc 
2393+             true  ->  [ entry  |  acc ] 
23902394          end 
23912395        catch 
23922396          :empty  ->  acc 
@@ -2454,33 +2458,55 @@ defmodule Module.Types.Descr do
24542458    if  empty? ( type ) ,  do:  throw ( :empty ) ,  else:  type 
24552459  end 
24562460
2457-   defp  map_difference ( _ ,  dnf )  when  dnf  ==  @ map_top  do 
2458-     0 
2459-   end 
2461+   defp  map_difference ( _ ,  dnf )  when  dnf  ==  @ map_top ,  do:  0 
2462+   defp  map_difference ( dnf ,  dnf ) ,  do:  0 
24602463
24612464  defp  map_difference ( dnf1 ,  dnf2 )  do 
24622465    Enum . reduce ( dnf2 ,  dnf1 ,  fn 
2463-       # Optimization: we are removing an open map with one field. 
2464-       { :open ,   fields2 ,   [ ] } ,   dnf1   when   map_size ( fields2 )   ==   1   -> 
2465-         Enum . reduce ( dnf1 ,  [ ] ,  fn  { tag1 ,  fields1 ,  negs1 } ,  acc  -> 
2466+       { :open ,   fields2 ,   [ ] } ,   current_dnf   when   map_size ( fields2 )   ==   1   -> 
2467+          # Optimization: we are removing an open map with one field. 
2468+         Enum . reduce ( current_dnf ,  [ ] ,  fn  { tag1 ,  fields1 ,  negs1 } ,  acc  -> 
24662469          { key ,  value ,  _rest }  =  :maps . next ( :maps . iterator ( fields2 ) ) 
24672470          t_diff  =  difference ( Map . get ( fields1 ,  key ,  tag_to_type ( tag1 ) ) ,  value ) 
24682471
24692472          if  empty? ( t_diff )  do 
24702473            acc 
24712474          else 
2472-             [ { tag1 ,  Map . put ( fields1 ,  key ,  t_diff ) ,  negs1 }  |  acc ] 
2475+             { tag ,  pos }  =  { tag1 ,  Map . put ( fields1 ,  key ,  t_diff ) } 
2476+             entry  =  { tag ,  pos ,  negs1 } 
2477+ 
2478+             cond  do 
2479+               :lists . member ( { tag ,  pos } ,  negs1 )  ->  acc 
2480+               :lists . member ( entry ,  acc )  ->  acc 
2481+               true  ->  [ entry  |  acc ] 
2482+             end 
24732483          end 
24742484        end ) 
24752485
2476-       { tag2 ,  fields2 ,  negs2 } ,  dnf1  -> 
2477-         Enum . reduce ( dnf1 ,  [ ] ,  fn  { tag1 ,  fields1 ,  negs1 } ,  acc  -> 
2478-           acc  =  [ { tag1 ,  fields1 ,  [ { tag2 ,  fields2 }  |  negs1 ] }  |  acc ] 
2486+       { tag2 ,  fields2 ,  negs2 } ,  current_dnf  -> 
2487+         Enum . reduce ( current_dnf ,  [ ] ,  fn  { tag1 ,  fields1 ,  negs1 } ,  acc  -> 
2488+           negs  = 
2489+             if  :lists . member ( { tag2 ,  fields2 } ,  negs1 ) ,  do:  negs1 ,  else:  [ { tag2 ,  fields2 }  |  negs1 ] 
2490+ 
2491+           entry  =  { tag1 ,  fields1 ,  negs } 
2492+ 
2493+           acc  = 
2494+             cond  do 
2495+               :lists . member ( { tag1 ,  fields1 } ,  negs )  ->  acc 
2496+               :lists . member ( entry ,  acc )  ->  acc 
2497+               true  ->  [ entry  |  acc ] 
2498+             end 
24792499
24802500          Enum . reduce ( negs2 ,  acc ,  fn  { neg_tag2 ,  neg_fields2 } ,  acc  -> 
24812501            try  do 
24822502              { tag ,  fields }  =  map_literal_intersection ( tag1 ,  fields1 ,  neg_tag2 ,  neg_fields2 ) 
2483-               [ { tag ,  fields ,  negs1 }  |  acc ] 
2503+               entry  =  { tag ,  fields ,  negs1 } 
2504+ 
2505+               cond  do 
2506+                 :lists . member ( { tag ,  fields } ,  negs1 )  ->  acc 
2507+                 :lists . member ( entry ,  acc )  ->  acc 
2508+                 true  ->  [ entry  |  acc ] 
2509+               end 
24842510            catch 
24852511              :empty  ->  acc 
24862512            end 
0 commit comments