@@ -46,8 +46,8 @@ defmodule Module.Types.Descr do
46
46
@ not_non_empty_list Map . delete ( @ term , :list )
47
47
@ not_list Map . replace! ( @ not_non_empty_list , :bitmap , @ bit_top - @ bit_empty_list )
48
48
49
- @ empty_intersection [ 0 , @ none , [ ] , :fun_bottom ]
50
- @ empty_difference [ 0 , [ ] , :fun_bottom ]
49
+ @ empty_intersection [ 0 , [ ] ]
50
+ @ empty_difference [ 0 , [ ] ]
51
51
52
52
defguard is_descr ( descr ) when is_map ( descr ) or descr == :term
53
53
@@ -398,12 +398,20 @@ defmodule Module.Types.Descr do
398
398
# Returning 0 from the callback is taken as none() for that subtype.
399
399
defp intersection ( :atom , v1 , v2 ) , do: atom_intersection ( v1 , v2 )
400
400
defp intersection ( :bitmap , v1 , v2 ) , do: v1 &&& v2
401
- defp intersection ( :dynamic , v1 , v2 ) , do: dynamic_intersection ( v1 , v2 )
402
401
defp intersection ( :list , v1 , v2 ) , do: list_intersection ( v1 , v2 )
403
402
defp intersection ( :map , v1 , v2 ) , do: map_intersection ( v1 , v2 )
404
403
defp intersection ( :optional , 1 , 1 ) , do: 1
405
404
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
407
415
408
416
@ doc """
409
417
Computes the difference between two types.
@@ -490,7 +498,11 @@ defmodule Module.Types.Descr do
490
498
defp difference ( :map , v1 , v2 ) , do: map_difference ( v1 , v2 )
491
499
defp difference ( :optional , 1 , 1 ) , do: 0
492
500
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
494
506
495
507
@ doc """
496
508
Compute the negation of a type.
@@ -1159,7 +1171,7 @@ defmodule Module.Types.Descr do
1159
1171
with { :ok , domain , static_arrows , dynamic_arrows } <-
1160
1172
fun_normalize_both ( fun_static , fun_dynamic , arity ) do
1161
1173
cond do
1162
- empty? ( args_domain ) ->
1174
+ Enum . any? ( arguments , & empty? / 1 ) ->
1163
1175
{ :badarg , domain_to_flat_args ( domain , arity ) }
1164
1176
1165
1177
not subtype? ( args_domain , domain ) ->
@@ -1170,26 +1182,21 @@ defmodule Module.Types.Descr do
1170
1182
end
1171
1183
1172
1184
static? ->
1173
- { :ok , fun_apply_static ( arguments , static_arrows , false ) }
1185
+ { :ok , fun_apply_static ( arguments , static_arrows ) }
1174
1186
1175
1187
static_arrows == [ ] ->
1176
1188
# TODO: We need to validate this within the theory
1177
1189
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 ) ) }
1179
1191
1180
1192
true ->
1181
1193
# 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 )
1188
1195
1189
1196
{ :ok ,
1190
1197
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 ) )
1193
1200
) }
1194
1201
end
1195
1202
end
@@ -1289,26 +1296,12 @@ defmodule Module.Types.Descr do
1289
1296
:badfun
1290
1297
end
1291
1298
1292
- defp fun_apply_static ( arguments , arrows , maybe_empty? ) do
1299
+ defp fun_apply_static ( arguments , arrows ) do
1293
1300
type_args = args_to_domain ( arguments )
1294
1301
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 )
1312
1305
end
1313
1306
1314
1307
# Helper function for function application that handles the application of
@@ -1471,7 +1464,7 @@ defmodule Module.Types.Descr do
1471
1464
# This avoids the expensive recursive phi computation by checking only that applying the
1472
1465
# input to the positive intersection yields a subtype of the return
1473
1466
if all_non_empty_domains? ( [ { arguments , return } | positives ] ) do
1474
- fun_apply_static ( arguments , [ positives ] , false )
1467
+ fun_apply_static ( arguments , [ positives ] )
1475
1468
|> subtype? ( return )
1476
1469
else
1477
1470
n = length ( arguments )
@@ -1496,45 +1489,44 @@ defmodule Module.Types.Descr do
1496
1489
# Create cache key from function arguments
1497
1490
cache_key = { args , { b , ret } , [ { arguments , return } | rest_positive ] }
1498
1491
1499
- case Map . get ( cache , cache_key ) do
1500
- nil ->
1492
+ case cache do
1493
+ % { ^ cache_key => value } ->
1494
+ value
1495
+
1496
+ % { } ->
1501
1497
# Compute result and cache it
1502
1498
{ result1 , cache } = phi ( args , { true , intersection ( ret , return ) } , rest_positive , cache )
1503
1499
1504
1500
if not result1 do
1505
- # Store false result in cache
1506
1501
cache = Map . put ( cache , cache_key , false )
1507
1502
{ false , cache }
1508
1503
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
1522
1517
end )
1523
1518
1524
1519
result = result1 and result2
1525
- # Store result in cache
1526
1520
cache = Map . put ( cache , cache_key , result )
1527
1521
{ result , cache }
1528
1522
end
1529
-
1530
- cached_result ->
1531
- # Return cached result
1532
- { cached_result , cache }
1533
1523
end
1534
1524
end
1535
1525
1536
1526
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 )
1538
1530
end
1539
1531
1540
1532
defp fun_union ( bdd1 , bdd2 ) do
@@ -2392,10 +2384,6 @@ defmodule Module.Types.Descr do
2392
2384
:empty -> acc
2393
2385
end
2394
2386
end
2395
- |> case do
2396
- [ ] -> 0
2397
- acc -> acc
2398
- end
2399
2387
end
2400
2388
2401
2389
# Intersects two map literals; throws if their intersection is empty.
0 commit comments