@@ -46,8 +46,8 @@ defmodule Module.Types.Descr do
4646  @ not_non_empty_list  Map . delete ( @ term ,  :list ) 
4747  @ not_list  Map . replace! ( @ not_non_empty_list ,  :bitmap ,  @ bit_top  -  @ bit_empty_list ) 
4848
49-   @ empty_intersection  [ 0 ,  @ none ,   [ ] ,   :fun_bottom ] 
50-   @ empty_difference  [ 0 ,  [ ] ,   :fun_bottom ] 
49+   @ empty_intersection  [ 0 ,  [ ] ] 
50+   @ empty_difference  [ 0 ,  [ ] ] 
5151
5252  defguard  is_descr ( descr )  when  is_map ( descr )  or  descr  ==  :term 
5353
@@ -398,12 +398,20 @@ defmodule Module.Types.Descr do
398398  # Returning 0 from the callback is taken as none() for that subtype. 
399399  defp  intersection ( :atom ,  v1 ,  v2 ) ,  do:  atom_intersection ( v1 ,  v2 ) 
400400  defp  intersection ( :bitmap ,  v1 ,  v2 ) ,  do:  v1  &&&  v2 
401-   defp  intersection ( :dynamic ,  v1 ,  v2 ) ,  do:  dynamic_intersection ( v1 ,  v2 ) 
402401  defp  intersection ( :list ,  v1 ,  v2 ) ,  do:  list_intersection ( v1 ,  v2 ) 
403402  defp  intersection ( :map ,  v1 ,  v2 ) ,  do:  map_intersection ( v1 ,  v2 ) 
404403  defp  intersection ( :optional ,  1 ,  1 ) ,  do:  1 
405404  defp  intersection ( :tuple ,  v1 ,  v2 ) ,  do:  tuple_intersection ( v1 ,  v2 ) 
406-   defp  intersection ( :fun ,  v1 ,  v2 ) ,  do:  fun_intersection ( v1 ,  v2 ) 
405+ 
406+   defp  intersection ( :fun ,  v1 ,  v2 )  do 
407+     bdd  =  fun_intersection ( v1 ,  v2 ) 
408+     if  bdd  ==  :fun_bottom ,  do:  0 ,  else:  bdd 
409+   end 
410+ 
411+   defp  intersection ( :dynamic ,  v1 ,  v2 )  do 
412+     descr  =  dynamic_intersection ( v1 ,  v2 ) 
413+     if  descr  ==  @ none ,  do:  0 ,  else:  descr 
414+   end 
407415
408416  @ doc  """ 
409417  Computes the difference between two types. 
@@ -490,7 +498,11 @@ defmodule Module.Types.Descr do
490498  defp  difference ( :map ,  v1 ,  v2 ) ,  do:  map_difference ( v1 ,  v2 ) 
491499  defp  difference ( :optional ,  1 ,  1 ) ,  do:  0 
492500  defp  difference ( :tuple ,  v1 ,  v2 ) ,  do:  tuple_difference ( v1 ,  v2 ) 
493-   defp  difference ( :fun ,  v1 ,  v2 ) ,  do:  fun_difference ( v1 ,  v2 ) 
501+ 
502+   defp  difference ( :fun ,  v1 ,  v2 )  do 
503+     bdd  =  fun_difference ( v1 ,  v2 ) 
504+     if  bdd  ==  :fun_bottom ,  do:  0 ,  else:  bdd 
505+   end 
494506
495507  @ doc  """ 
496508  Compute the negation of a type. 
@@ -1159,7 +1171,7 @@ defmodule Module.Types.Descr do
11591171    with  { :ok ,  domain ,  static_arrows ,  dynamic_arrows }  <- 
11601172           fun_normalize_both ( fun_static ,  fun_dynamic ,  arity )  do 
11611173      cond  do 
1162-         empty? ( args_domain )  -> 
1174+         Enum . any? ( arguments ,   & empty? / 1 )  -> 
11631175          { :badarg ,  domain_to_flat_args ( domain ,  arity ) } 
11641176
11651177        not  subtype? ( args_domain ,  domain )  -> 
@@ -1170,26 +1182,21 @@ defmodule Module.Types.Descr do
11701182          end 
11711183
11721184        static?  -> 
1173-           { :ok ,  fun_apply_static ( arguments ,  static_arrows ,   false ) } 
1185+           { :ok ,  fun_apply_static ( arguments ,  static_arrows ) } 
11741186
11751187        static_arrows  ==  [ ]  -> 
11761188          # TODO: We need to validate this within the theory 
11771189          arguments  =  Enum . map ( arguments ,  & upper_bound / 1 ) 
1178-           { :ok ,  dynamic ( fun_apply_static ( arguments ,  dynamic_arrows ,   false ) ) } 
1190+           { :ok ,  dynamic ( fun_apply_static ( arguments ,  dynamic_arrows ) ) } 
11791191
11801192        true  -> 
11811193          # For dynamic cases, combine static and dynamic results 
1182-           { static_args ,  dynamic_args ,  maybe_empty? }  = 
1183-             if  args_dynamic?  do 
1184-               { Enum . map ( arguments ,  & upper_bound / 1 ) ,  Enum . map ( arguments ,  & lower_bound / 1 ) ,  true } 
1185-             else 
1186-               { arguments ,  arguments ,  false } 
1187-             end 
1194+           arguments  =  Enum . map ( arguments ,  & upper_bound / 1 ) 
11881195
11891196          { :ok , 
11901197           union ( 
1191-              fun_apply_static ( static_args ,  static_arrows ,   false ) , 
1192-              dynamic ( fun_apply_static ( dynamic_args ,  dynamic_arrows ,   maybe_empty? ) ) 
1198+              fun_apply_static ( arguments ,  static_arrows ) , 
1199+              dynamic ( fun_apply_static ( arguments ,  dynamic_arrows ) ) 
11931200           ) } 
11941201      end 
11951202    end 
@@ -1289,26 +1296,12 @@ defmodule Module.Types.Descr do
12891296    :badfun 
12901297  end 
12911298
1292-   defp  fun_apply_static ( arguments ,  arrows ,   maybe_empty? )  do 
1299+   defp  fun_apply_static ( arguments ,  arrows )  do 
12931300    type_args  =  args_to_domain ( arguments ) 
12941301
1295-     # Optimization: short-circuits when inner loop is none() or outer loop is term() 
1296-     if  maybe_empty?  and  empty? ( type_args )  do 
1297-       Enum . reduce_while ( arrows ,  none ( ) ,  fn  intersection_of_arrows ,  acc  -> 
1298-         Enum . reduce_while ( intersection_of_arrows ,  term ( ) ,  fn 
1299-           { _dom ,  _ret } ,  acc  when  acc  ==  @ none  ->  { :halt ,  acc } 
1300-           { _dom ,  ret } ,  acc  ->  { :cont ,  intersection ( acc ,  ret ) } 
1301-         end ) 
1302-         |>  case  do 
1303-           :term  ->  { :halt ,  :term } 
1304-           inner  ->  { :cont ,  union ( inner ,  acc ) } 
1305-         end 
1306-       end ) 
1307-     else 
1308-       Enum . reduce ( arrows ,  none ( ) ,  fn  intersection_of_arrows ,  acc  -> 
1309-         aux_apply ( acc ,  type_args ,  term ( ) ,  intersection_of_arrows ) 
1310-       end ) 
1311-     end 
1302+     Enum . reduce ( arrows ,  none ( ) ,  fn  intersection_of_arrows ,  acc  -> 
1303+       aux_apply ( acc ,  type_args ,  term ( ) ,  intersection_of_arrows ) 
1304+     end ) 
13121305  end 
13131306
13141307  # Helper function for function application that handles the application of 
@@ -1471,7 +1464,7 @@ defmodule Module.Types.Descr do
14711464    # This avoids the expensive recursive phi computation by checking only that applying the 
14721465    # input to the positive intersection yields a subtype of the return 
14731466    if  all_non_empty_domains? ( [ { arguments ,  return }  |  positives ] )  do 
1474-       fun_apply_static ( arguments ,  [ positives ] ,   false ) 
1467+       fun_apply_static ( arguments ,  [ positives ] ) 
14751468      |>  subtype? ( return ) 
14761469    else 
14771470      n  =  length ( arguments ) 
@@ -1496,45 +1489,44 @@ defmodule Module.Types.Descr do
14961489    # Create cache key from function arguments 
14971490    cache_key  =  { args ,  { b ,  ret } ,  [ { arguments ,  return }  |  rest_positive ] } 
14981491
1499-     case  Map . get ( cache ,  cache_key )  do 
1500-       nil  -> 
1492+     case  cache  do 
1493+       % { ^ cache_key  =>  value }  -> 
1494+         value 
1495+ 
1496+       % { }  -> 
15011497        # Compute result and cache it 
15021498        { result1 ,  cache }  =  phi ( args ,  { true ,  intersection ( ret ,  return ) } ,  rest_positive ,  cache ) 
15031499
15041500        if  not  result1  do 
1505-           # Store false result in cache 
15061501          cache  =  Map . put ( cache ,  cache_key ,  false ) 
15071502          { false ,  cache } 
15081503        else 
1509-           # This doesn't stop if one intermediate result is false? 
1510-           { result2 ,   cache }   = 
1511-             Enum . with_index ( arguments ) 
1512-             |>   Enum . reduce_while ( { true ,   cache } ,   fn   { type ,   index } ,   { acc_result ,   acc_cache }   -> 
1513-               { new_result ,   new_cache }   = 
1514-                 List . update_at ( args ,   index ,  fn  { _ ,  arg }  ->  { true ,  difference ( arg ,  type ) }  end ) 
1515-                 |>  phi ( { b ,  ret } ,  rest_positive ,  acc_cache ) 
1516- 
1517-               if  new_result  do 
1518-                 { :cont ,  { acc_result  and  new_result ,  new_cache } } 
1519-               else 
1520-                 { :halt ,  { false ,  new_cache } } 
1521-               end 
1504+           { _index ,   result2 ,   cache }   = 
1505+              Enum . reduce_while ( arguments ,   { 0 ,   true ,   cache } ,   fn 
1506+                type ,   { index ,   acc_result ,   acc_cache }   -> 
1507+                  { new_result ,   new_cache }   = 
1508+                    args 
1509+                    |>   List . update_at ( index ,  fn  { _ ,  arg }  ->  { true ,  difference ( arg ,  type ) }  end ) 
1510+                    |>  phi ( { b ,  ret } ,  rest_positive ,  acc_cache ) 
1511+ 
1512+                  if  new_result  do 
1513+                    { :cont ,  { index   +   1 ,   acc_result  and  new_result ,  new_cache } } 
1514+                  else 
1515+                    { :halt ,  { index   +   1 ,   false ,  new_cache } } 
1516+                  end 
15221517            end ) 
15231518
15241519          result  =  result1  and  result2 
1525-           # Store result in cache 
15261520          cache  =  Map . put ( cache ,  cache_key ,  result ) 
15271521          { result ,  cache } 
15281522        end 
1529- 
1530-       cached_result  -> 
1531-         # Return cached result 
1532-         { cached_result ,  cache } 
15331523    end 
15341524  end 
15351525
15361526  defp  all_non_empty_domains? ( positives )  do 
1537-     Enum . all? ( positives ,  fn  { args ,  _ret }  ->  not  empty? ( args_to_domain ( args ) )  end ) 
1527+     Enum . all? ( positives ,  fn  { args ,  _ret }  -> 
1528+       Enum . all? ( args ,  fn  arg  ->  not  empty? ( arg )  end ) 
1529+     end ) 
15381530  end 
15391531
15401532  defp  fun_union ( bdd1 ,  bdd2 )  do 
@@ -2392,10 +2384,6 @@ defmodule Module.Types.Descr do
23922384          :empty  ->  acc 
23932385        end 
23942386    end 
2395-     |>  case  do 
2396-       [ ]  ->  0 
2397-       acc  ->  acc 
2398-     end 
23992387  end 
24002388
24012389  # Intersects two map literals; throws if their intersection is empty. 
0 commit comments