@@ -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