@@ -1278,8 +1278,138 @@ defmodule Module.Types.Descr do
12781278
12791279  defp  map_only? ( descr ) ,  do:  empty? ( Map . delete ( descr ,  :map ) ) 
12801280
1281-   # Union is list concatenation 
1282-   defp  map_union ( dnf1 ,  dnf2 ) ,  do:  dnf1  ++  ( dnf2  --  dnf1 ) 
1281+   defp  map_union ( dnf1 ,  dnf2 )  do 
1282+     # Union is just concatenation, but we rely on some optimization strategies to 
1283+     # avoid the list to grow when possible 
1284+     # - 
1285+     # - 
1286+ 
1287+     # first pass trying to identify patterns where two maps can be fused as one 
1288+     with  [ { tag1 ,  pos1 ,  [ ] } ]  <-  dnf1 , 
1289+          [ { tag2 ,  pos2 ,  [ ] } ]  <-  dnf2 , 
1290+          strategy  when  strategy  !=  nil  <-  map_union_optimization_strategy ( tag1 ,  pos1 ,  tag2 ,  pos2 )  do 
1291+       case  strategy  do 
1292+         :all_equal  -> 
1293+           dnf1 
1294+ 
1295+         :any_map  -> 
1296+           [ { :open ,  % { } ,  [ ] } ] 
1297+ 
1298+         { :one_key_difference ,  key ,  v1 ,  v2 }  -> 
1299+           new_pos  =  Map . put ( pos1 ,  key ,  union ( v1 ,  v2 ) ) 
1300+           [ { tag1 ,  new_pos ,  [ ] } ] 
1301+ 
1302+         :left_subtype_of_right  -> 
1303+           dnf2 
1304+ 
1305+         :right_subtype_of_left  -> 
1306+           dnf1 
1307+ 
1308+         _  -> 
1309+           IO . inspect ( strategy:  strategy ) 
1310+           dnf1  ++  ( dnf2  --  dnf1 ) 
1311+       end 
1312+     else 
1313+       # otherwise we just concatenate and remove structural duplicates 
1314+       _  ->  dnf1  ++  ( dnf2  --  dnf1 ) 
1315+     end 
1316+   end 
1317+ 
1318+   defp  map_union_optimization_strategy ( tag1 ,  pos1 ,  tag2 ,  pos2 ) 
1319+   defp  map_union_optimization_strategy ( tag ,  pos ,  tag ,  pos ) ,  do:  :all_equal 
1320+   defp  map_union_optimization_strategy ( :open ,  empty ,  _ ,  _ )  when  empty  ==  % { } ,  do:  :any_map 
1321+   defp  map_union_optimization_strategy ( _ ,  _ ,  :open ,  empty )  when  empty  ==  % { } ,  do:  :any_map 
1322+ 
1323+   defp  map_union_optimization_strategy ( tag ,  pos1 ,  tag ,  pos2 ) 
1324+        when  map_size ( pos1 )  ==  map_size ( pos2 )  do 
1325+     :maps . iterator ( pos1 ) 
1326+     |>  :maps . next ( ) 
1327+     |>  do_map_union_optimization_strategy ( pos2 ,  :all_keys_equal ) 
1328+   end 
1329+ 
1330+   defp  map_union_optimization_strategy ( :open ,  pos1 ,  _ ,  pos2 ) 
1331+        when  map_size ( pos1 )  <=  map_size ( pos2 )  do 
1332+     :maps . iterator ( pos1 ) 
1333+     |>  :maps . next ( ) 
1334+     |>  do_map_union_optimization_strategy ( pos2 ,  :right_subtype_of_left ) 
1335+   end 
1336+ 
1337+   defp  map_union_optimization_strategy ( _ ,  pos1 ,  :open ,  pos2 ) 
1338+        when  map_size ( pos1 )  >=  map_size ( pos2 )  do 
1339+     :maps . iterator ( pos2 ) 
1340+     |>  :maps . next ( ) 
1341+     |>  do_map_union_optimization_strategy ( pos1 ,  :right_subtype_of_left ) 
1342+     |>  case  do 
1343+       :right_subtype_of_left  ->  :left_subtype_of_right 
1344+       nil  ->  nil 
1345+     end 
1346+   end 
1347+ 
1348+   defp  map_union_optimization_strategy ( _ ,  _ ,  _ ,  _ ) ,  do:  nil 
1349+ 
1350+   defp  do_map_union_optimization_strategy ( :none ,  _ ,  status ) ,  do:  status 
1351+ 
1352+   defp  do_map_union_optimization_strategy ( { key ,  v1 ,  iterator } ,  pos2 ,  status )  do 
1353+     case  { pos2 ,  status }  do 
1354+       { % { ^ key  =>  ^ v1 } ,  _ }  -> 
1355+         do_map_union_optimization_strategy ( :maps . next ( iterator ) ,  pos2 ,  status ) 
1356+ 
1357+       { % { ^ key  =>  v2 } ,  :all_keys_equal }  when  key  !=  :__struct__  -> 
1358+         status  =  { :one_key_difference ,  key ,  v1 ,  v2 } 
1359+         do_map_union_optimization_strategy ( :maps . next ( iterator ) ,  pos2 ,  status ) 
1360+ 
1361+       { % { ^ key  =>  v2 } ,  { :one_key_difference ,  _ ,  d1 ,  d2 } }  -> 
1362+         # we have at least two key differences now, we switch strategy 
1363+         # if both are subtypes in one direction, keep checking 
1364+         cond  do 
1365+           trivial_subtype? ( d1 ,  d2 )  and  trivial_subtype? ( v1 ,  v2 )  -> 
1366+             do_map_union_optimization_strategy ( :maps . next ( iterator ) ,  pos2 ,  :left_subtype_of_right ) 
1367+ 
1368+           trivial_subtype? ( d2 ,  d1 )  and  trivial_subtype? ( v2 ,  v1 )  -> 
1369+             do_map_union_optimization_strategy ( :maps . next ( iterator ) ,  pos2 ,  :right_subtype_of_left ) 
1370+ 
1371+           true  -> 
1372+             nil 
1373+         end 
1374+ 
1375+       { % { ^ key  =>  v2 } ,  :left_subtype_of_right }  -> 
1376+         if  trivial_subtype? ( v1 ,  v2 )  do 
1377+           do_map_union_optimization_strategy ( :maps . next ( iterator ) ,  pos2 ,  :left_subtype_of_right ) 
1378+         end 
1379+ 
1380+       { % { ^ key  =>  v2 } ,  :right_subtype_of_left }  -> 
1381+         if  trivial_subtype? ( v2 ,  v1 )  do 
1382+           do_map_union_optimization_strategy ( :maps . next ( iterator ) ,  pos2 ,  :right_subtype_of_left ) 
1383+         end 
1384+ 
1385+       _  -> 
1386+         nil 
1387+     end 
1388+   end 
1389+ 
1390+   # cheap to compute sub-typing 
1391+   # a trivial subtype is always a subtype, but not all subtypes are subtypes 
1392+   defp  trivial_subtype? ( _ ,  :term ) ,  do:  true 
1393+   defp  trivial_subtype? ( same ,  same ) ,  do:  true 
1394+ 
1395+   defp  trivial_subtype? ( % { }  =  left ,  % { }  =  right ) 
1396+        when  map_size ( left )  ==  1  and  map_size ( right )  ==  1  do 
1397+     case  { left ,  right }  do 
1398+       { % { atom:  _ } ,  % { atom:  { :negation ,  neg } } }  when  neg  ==  % { }  -> 
1399+         true 
1400+ 
1401+       { % { map:  _ } ,  % { map:  [ { :open ,  pos ,  [ ] } ] } }  when  pos  ==  % { }  -> 
1402+         true 
1403+ 
1404+       { % { bitmap:  bitmap1 } ,  % { bitmap:  bitmap2 } }  -> 
1405+         ( bitmap1  &&&  bitmap2 )  ===  bitmap2 
1406+ 
1407+       _  -> 
1408+         false 
1409+     end 
1410+   end 
1411+ 
1412+   defp  trivial_subtype? ( _ ,  _ ) ,  do:  false 
12831413
12841414  # Given two unions of maps, intersects each pair of maps. 
12851415  defp  map_intersection ( dnf1 ,  dnf2 )  do 
0 commit comments