@@ -138,7 +138,7 @@ defmodule Module.Types.Descr do
138138 Creates a function from overlapping function clauses.
139139 """
140140 def fun_from_inferred_clauses ( args_clauses ) do
141- if false do
141+ if true do
142142 domain_clauses =
143143 Enum . reduce ( args_clauses , [ ] , fn { args , return } , acc ->
144144 domain = args |> Enum . map ( & upper_bound / 1 ) |> args_to_domain ( )
@@ -1187,6 +1187,7 @@ defmodule Module.Types.Descr do
11871187
11881188 static_arrows == [ ] ->
11891189 # TODO: We need to validate this within the theory
1190+ arguments = Enum . map ( arguments , & upper_bound / 1 )
11901191 { :ok , dynamic ( fun_apply_static ( arguments , dynamic_arrows , false ) ) }
11911192
11921193 true ->
@@ -1305,22 +1306,25 @@ defmodule Module.Types.Descr do
13051306 type_args = args_to_domain ( arguments )
13061307
13071308 # Optimization: short-circuits when inner loop is none() or outer loop is term()
1308- if maybe_empty? and empty? ( type_args ) do
1309- Enum . reduce_while ( arrows , none ( ) , fn intersection_of_arrows , acc ->
1310- Enum . reduce_while ( intersection_of_arrows , term ( ) , fn
1311- { _dom , _ret } , acc when acc == @ none -> { :halt , acc }
1312- { _dom , ret } , acc -> { :cont , intersection ( acc , ret ) }
1309+ result =
1310+ if maybe_empty? and empty? ( type_args ) do
1311+ Enum . reduce_while ( arrows , none ( ) , fn intersection_of_arrows , acc ->
1312+ Enum . reduce_while ( intersection_of_arrows , term ( ) , fn
1313+ { _dom , _ret } , acc when acc == @ none -> { :halt , acc }
1314+ { _dom , ret } , acc -> { :cont , intersection ( acc , ret ) }
1315+ end )
1316+ |> case do
1317+ :term -> { :halt , :term }
1318+ inner -> { :cont , union ( inner , acc ) }
1319+ end
13131320 end )
1314- |> case do
1315- :term -> { :halt , :term }
1316- inner -> { :cont , union ( inner , acc ) }
1317- end
1318- end )
1319- else
1320- Enum . reduce ( arrows , none ( ) , fn intersection_of_arrows , acc ->
1321- aux_apply ( acc , type_args , term ( ) , intersection_of_arrows )
1322- end )
1323- end
1321+ else
1322+ Enum . reduce ( arrows , none ( ) , fn intersection_of_arrows , acc ->
1323+ aux_apply ( acc , type_args , term ( ) , intersection_of_arrows )
1324+ end )
1325+ end
1326+
1327+ result
13241328 end
13251329
13261330 # Helper function for function application that handles the application of
@@ -1337,11 +1341,32 @@ defmodule Module.Types.Descr do
13371341 # - arrow_intersections: The list of function arrows to process
13381342
13391343 # For more details, see Definitions 2.20 or 6.11 in https://vlanvin.fr/papers/thesis.pdf
1340- defp aux_apply ( result , _input , rets_reached , [ ] ) do
1344+ defp aux_apply ( result , _input , rets_reached , arrow_intersections , depth \\ 0 )
1345+
1346+ defp aux_apply ( result , _input , rets_reached , [ ] , depth ) do
13411347 if subtype? ( rets_reached , result ) , do: result , else: union ( result , rets_reached )
13421348 end
13431349
1344- defp aux_apply ( result , input , returns_reached , [ { dom , ret } | arrow_intersections ] ) do
1350+ defp aux_apply ( result , input , returns_reached , [ { dom , ret } | arrow_intersections ] , depth ) do
1351+ # Performance warning thresholds
1352+ if Map . has_key? ( input , :dynamic ) do
1353+ IO . puts ( "aux_apply called with dynamic input" )
1354+ raise "aux_apply called with dynamic input"
1355+ end
1356+
1357+ max_depth = 15
1358+
1359+ if depth > max_depth do
1360+ IO . puts ( "PERFORMANCE WARNING: aux_apply depth #{ depth } (threshold: #{ max_depth } )" )
1361+ IO . puts ( "aux_apply [depth:#{ depth } ]" )
1362+ IO . puts ( "input: #{ inspect ( input ) } " )
1363+ IO . puts ( "returns_reached: #{ inspect ( returns_reached ) } " )
1364+ IO . puts ( "dom: #{ inspect ( dom ) } " )
1365+ IO . puts ( "ret: #{ inspect ( ret ) } " )
1366+ IO . puts ( "arrow_intersections: #{ inspect ( arrow_intersections ) } " )
1367+ IO . puts ( "--------------------------------" )
1368+ end
1369+
13451370 # Calculate the part of the input not covered by this arrow's domain
13461371 dom_subtract = difference ( input , args_to_domain ( dom ) )
13471372
@@ -1359,7 +1384,7 @@ defmodule Module.Types.Descr do
13591384 if empty? ( dom_subtract ) do
13601385 result
13611386 else
1362- aux_apply ( result , dom_subtract , returns_reached , arrow_intersections )
1387+ aux_apply ( result , dom_subtract , returns_reached , arrow_intersections , depth + 1 )
13631388 end
13641389
13651390 # 2. Return type refinement
@@ -1369,7 +1394,7 @@ defmodule Module.Types.Descr do
13691394
13701395 # e.g. (integer()->atom()) and (integer()->pid()) when applied to integer()
13711396 # should result in (atom() ∩ pid()), which is none().
1372- aux_apply ( result , input , ret_refine , arrow_intersections )
1397+ aux_apply ( result , input , ret_refine , arrow_intersections , depth + 1 )
13731398 end
13741399
13751400 # Takes all the paths from the root to the leaves finishing with a 1,
@@ -1556,36 +1581,20 @@ defmodule Module.Types.Descr do
15561581 # and that applying the input type of the arrow to the intersection gives sth that is a subtype of the return type of the arrow
15571582 if all_non_empty_domains? ( positives ) and all_non_empty_domains? ( [ { arguments , return } ] ) do
15581583 return = negation ( return )
1584+
15591585 type_positives =
15601586 Enum . map ( positives , fn { args , ret } -> fun ( args , ret ) end ) |> Enum . reduce ( & intersection / 2 )
15611587
15621588 { :ok , _dom , static_arrows } = fun_normalize ( type_positives , length ( arguments ) , :static )
15631589 result = fun_apply_static ( arguments , static_arrows , false )
15641590
15651591 r = subtype? ( result , return )
1592+
15661593 if r do
15671594 r
15681595 else
15691596 false
15701597 end
1571-
1572- # positives_domain =
1573- # Enum.reduce(positives, none(), fn {args, _ret}, acc ->
1574- # union(acc, args_to_domain(args))
1575- # end)
1576-
1577- # 1. the positives domain must be a supertype of the domain of the arrow
1578- # result1 = subtype?(args_to_domain(arguments), positives_domain)
1579-
1580- # if result1 do
1581- # # 2. if we apply the input type of the arrow to the intersection, the result must be a subtype of the return type of the arrow
1582- # # 2.a) build the intersection of positives
1583-
1584- # # 2.b) check that the result is a subtype of the return type of the arrow
1585- # result2 = subtype?(apply_result, return)
1586- # else
1587- # false
1588- # end
15891598 else
15901599 # Show the caller of this function
15911600 # IO.puts("Starting phi starter with arguments: #{inspect(arguments)}")
@@ -1603,7 +1612,6 @@ defmodule Module.Types.Descr do
16031612 # end)
16041613 # )
16051614
1606-
16071615 # start_time = DateTime.utc_now()
16081616
16091617 n = length ( arguments )
@@ -3265,7 +3273,8 @@ defmodule Module.Types.Descr do
32653273 defp tuple_difference ( dnf1 , dnf2 ) do
32663274 Enum . reduce ( dnf2 , dnf1 , fn { tag2 , elements2 } , dnf1 ->
32673275 Enum . reduce ( dnf1 , [ ] , fn { tag1 , elements1 } , acc ->
3268- tuple_eliminate_single_negation ( tag1 , elements1 , { tag2 , elements2 } ) ++ acc
3276+ tuple_eliminate_single_negation ( tag1 , elements1 , { tag2 , elements2 } )
3277+ |> tuple_union ( acc )
32693278 end )
32703279 end )
32713280 end
@@ -3280,8 +3289,10 @@ defmodule Module.Types.Descr do
32803289 if ( tag == :closed and n < m ) or ( neg_tag == :closed and n > m ) do
32813290 [ { tag , elements } ]
32823291 else
3283- tuple_elim_content ( [ ] , tag , elements , neg_elements ) ++
3292+ tuple_union (
3293+ tuple_elim_content ( [ ] , tag , elements , neg_elements ) ,
32843294 tuple_elim_size ( n , m , tag , elements , neg_tag )
3295+ )
32853296 end
32863297 end
32873298
@@ -3945,4 +3956,6 @@ defmodule Module.Types.Descr do
39453956 defp non_empty_map_or ( [ head | tail ] , fun ) do
39463957 Enum . reduce ( tail , fun . ( head ) , & { :or , [ ] , [ & 2 , fun . ( & 1 ) ] } )
39473958 end
3959+
3960+ # Performance tracking helpers for aux_apply
39483961end
0 commit comments