@@ -1028,50 +1028,126 @@ defmodule Module.Types.Descr do
1028
1028
1029
1029
defp fun_apply_with_strategy ( fun_static , fun_dynamic , arguments ) do
1030
1030
args_dynamic? = are_arguments_dynamic? ( arguments )
1031
+ arity = length ( arguments )
1031
1032
1032
1033
# For non-dynamic function and arguments, just return the static result
1033
1034
if fun_dynamic == nil and not args_dynamic? do
1034
- fun_apply_static ( fun_static , arguments , :static , args_dynamic? )
1035
- else
1036
- # For dynamic cases, combine static and dynamic results
1037
- { static_args , dynamic_args , maybe_empty? } =
1038
- if args_dynamic? do
1039
- { materialize_arguments ( arguments , :up ) , materialize_arguments ( arguments , :down ) , true }
1035
+ with { :ok , static_domain , static_arrows } <- fun_normalize ( fun_static , arity , :static ) do
1036
+ if subtype? ( domain_descr ( arguments ) , static_domain ) do
1037
+ { :ok , fun_apply_static ( arguments , static_arrows , false ) }
1040
1038
else
1041
- { arguments , arguments , false }
1039
+ :badarg
1042
1040
end
1041
+ end
1042
+ else
1043
+ normalized =
1044
+ case fun_normalize ( fun_static , arity , :static ) do
1045
+ { :ok , static_domain , static_arrows } when fun_dynamic == nil ->
1046
+ # TODO: Should dynamic_arrows be [] or static_arrows
1047
+ { :ok , static_domain , static_arrows , static_arrows }
1048
+
1049
+ { :ok , static_domain , static_arrows } when fun_dynamic != nil ->
1050
+ case fun_normalize ( fun_dynamic , arity , :dynamic ) do
1051
+ { :ok , dynamic_domain , dynamic_arrows } ->
1052
+ domain = union ( dynamic_domain , dynamic ( union ( static_domain , dynamic_domain ) ) )
1053
+ { :ok , domain , static_arrows , dynamic_arrows }
1043
1054
1044
- case fun_apply_static ( fun_static , static_args , :static , false ) do
1045
- { :ok , res1 } when fun_dynamic == nil ->
1046
- # We need to compute which parts are dynamic
1047
- with { :ok , res2 } <- fun_apply_static ( fun_static , dynamic_args , :static , maybe_empty? ) do
1048
- { :ok , union ( res1 , dynamic ( res2 ) ) }
1049
- end
1055
+ _ ->
1056
+ # TODO: Should dynamic_arrows be [] or static_arrows
1057
+ { :ok , static_domain , static_arrows , static_arrows }
1058
+ end
1050
1059
1051
- { :ok , res1 } when fun_dynamic != nil ->
1052
- # If static succeeded, the dynamic part can fail, we don't care
1053
- case fun_apply_static ( fun_dynamic , dynamic_args , :dynamic , maybe_empty? ) do
1054
- { :ok , res2 } -> { :ok , union ( res1 , dynamic ( res2 ) ) }
1055
- _ -> { :ok , res1 }
1056
- end
1060
+ :badfun ->
1061
+ case fun_normalize ( fun_dynamic , arity , :dynamic ) do
1062
+ { :ok , dynamic_domain , dynamic_arrows } ->
1063
+ # TODO: Should static_arrows be [] or dynamic_arrows
1064
+ { :ok , dynamic_domain , [ ] , dynamic_arrows }
1057
1065
1058
- :badfun ->
1059
- # Then the dynamic call has to succeed
1060
- result =
1061
- if fun_dynamic do
1062
- fun_apply_static ( fun_dynamic , dynamic_args , :dynamic , maybe_empty? )
1063
- else
1064
- fun_apply_static ( fun_static , dynamic_args , :static , maybe_empty? )
1066
+ error ->
1067
+ error
1065
1068
end
1066
1069
1067
- with { :ok , descr } <- result do
1068
- { :ok , dynamic ( descr ) }
1069
- end
1070
+ error ->
1071
+ error
1072
+ end
1070
1073
1071
- # badarg/badarity
1072
- error ->
1073
- error
1074
+ with { :ok , domain , static_arrows , dynamic_arrows } <- normalized do
1075
+ if subtype? ( domain_descr ( arguments ) , domain ) do
1076
+ # For dynamic cases, combine static and dynamic results
1077
+ { static_args , dynamic_args , maybe_empty? } =
1078
+ if args_dynamic? do
1079
+ { materialize_arguments ( arguments , :up ) , materialize_arguments ( arguments , :down ) ,
1080
+ true }
1081
+ else
1082
+ { arguments , arguments , false }
1083
+ end
1084
+
1085
+ { :ok ,
1086
+ union (
1087
+ fun_apply_static ( static_args , static_arrows , false ) ,
1088
+ dynamic ( fun_apply_static ( dynamic_args , dynamic_arrows , maybe_empty? ) )
1089
+ ) }
1090
+ else
1091
+ :badarg
1092
+ end
1074
1093
end
1094
+
1095
+ # case fun_normalize(fun_static, arity, :static) do
1096
+ # {:ok, static_domain, static_arrow} when fun_dynamic == nil ->
1097
+ # with {:ok, res1} <-
1098
+ # new_fun_apply_static(static_domain, static_arrows, static_args, false),
1099
+ # {:ok, res2} <-
1100
+ # new_fun_apply_static(static_domain, static_arrows, dynamic_args, maybe_empty?) do
1101
+ # {:ok, union(res1, dynamic(res2))}
1102
+ # end
1103
+
1104
+ # {:ok, static_domain, static_arrows} when fun_dynamic != nil ->
1105
+ # case fun_normalize(fun_dynamic, arity, :dynamic) do
1106
+ # {:ok, dynamic_domain, dynamic_arrows} ->
1107
+ # with {:ok, res1} <-
1108
+ # checked_fun_apply_static(
1109
+ # union(dynamic_domain, static_domain),
1110
+ # static_domain,
1111
+ # static_arrows,
1112
+ # static_args,
1113
+ # false
1114
+ # ) do
1115
+ # case checked_fun_apply_static(
1116
+ # dynamic_domain,
1117
+ # dynamic_domain,
1118
+ # dynamic_arrows,
1119
+ # dynamic_args,
1120
+ # maybe_empty?
1121
+ # ) do
1122
+ # {:ok, res2} ->
1123
+ # {:ok, union(res1, dynamic(res2))}
1124
+
1125
+ # _ ->
1126
+ # {:ok, res1}
1127
+ # end
1128
+ # end
1129
+
1130
+ # _ ->
1131
+ # new_fun_apply_static(static_domain, static_arrows, static_args, false)
1132
+ # end
1133
+
1134
+ # :badfun ->
1135
+ # # Then the dynamic call has to succeed
1136
+ # result =
1137
+ # if fun_dynamic do
1138
+ # fun_apply_static(fun_dynamic, dynamic_args, :dynamic, maybe_empty?)
1139
+ # else
1140
+ # fun_apply_static(fun_static, dynamic_args, :static, maybe_empty?)
1141
+ # end
1142
+
1143
+ # with {:ok, descr} <- result do
1144
+ # {:ok, dynamic(descr)}
1145
+ # end
1146
+
1147
+ # # badarg/badarity
1148
+ # error ->
1149
+ # error
1150
+ # end
1075
1151
end
1076
1152
end
1077
1153
@@ -1081,46 +1157,76 @@ defmodule Module.Types.Descr do
1081
1157
1082
1158
defp are_arguments_dynamic? ( arguments ) , do: Enum . any? ( arguments , & match? ( % { dynamic: _ } , & 1 ) )
1083
1159
1084
- defp fun_apply_static ( % { fun: fun_bdd } , arguments , mode , maybe_empty? ) do
1085
- arity = length ( arguments )
1086
-
1087
- with { :ok , domain , arrows } <- fun_normalize ( fun_bdd , arity , mode ) do
1088
- type_args = domain_descr ( arguments )
1160
+ defp fun_apply_static ( arguments , arrows , maybe_empty? ) do
1161
+ type_args = domain_descr ( arguments )
1089
1162
1090
- cond do
1091
- # Optization: short-circuits when inner loop is none() or outer loop is term()
1092
- maybe_empty? and empty? ( type_args ) ->
1093
- result =
1094
- Enum . reduce_while ( arrows , none ( ) , fn intersection_of_arrows , acc ->
1095
- Enum . reduce_while ( intersection_of_arrows , term ( ) , fn
1096
- { _dom , _ret } , acc when acc == @ none -> { :halt , acc }
1097
- { _dom , ret } , acc -> { :cont , intersection ( acc , ret ) }
1098
- end )
1099
- |> case do
1100
- :term -> { :halt , :term }
1101
- inner -> { :cont , union ( inner , acc ) }
1102
- end
1103
- end )
1104
-
1105
- { :ok , result }
1106
-
1107
- subtype? ( type_args , domain ) ->
1108
- result =
1109
- Enum . reduce ( arrows , none ( ) , fn intersection_of_arrows , acc ->
1110
- aux_apply ( acc , type_args , term ( ) , intersection_of_arrows )
1111
- end )
1112
-
1113
- { :ok , result }
1114
-
1115
- true ->
1116
- :badarg
1117
- end
1163
+ # Optimization: short-circuits when inner loop is none() or outer loop is term()
1164
+ if maybe_empty? and empty? ( type_args ) do
1165
+ Enum . reduce_while ( arrows , none ( ) , fn intersection_of_arrows , acc ->
1166
+ Enum . reduce_while ( intersection_of_arrows , term ( ) , fn
1167
+ { _dom , _ret } , acc when acc == @ none -> { :halt , acc }
1168
+ { _dom , ret } , acc -> { :cont , intersection ( acc , ret ) }
1169
+ end )
1170
+ |> case do
1171
+ :term -> { :halt , :term }
1172
+ inner -> { :cont , union ( inner , acc ) }
1173
+ end
1174
+ end )
1175
+ else
1176
+ Enum . reduce ( arrows , none ( ) , fn intersection_of_arrows , acc ->
1177
+ aux_apply ( acc , type_args , term ( ) , intersection_of_arrows )
1178
+ end )
1118
1179
end
1119
1180
end
1120
1181
1121
- defp fun_apply_static ( % { } , _arguments , _mode , _maybe_empty? ) do
1122
- :badfun
1123
- end
1182
+ # defp fun_apply_static(descr, arguments, mode, maybe_empty?) do
1183
+ # arity = length(arguments)
1184
+
1185
+ # with {:ok, domain, arrows} <- fun_normalize(descr, arity, mode) do
1186
+ # new_fun_apply_static(domain, arrows, arguments, maybe_empty?)
1187
+ # end
1188
+ # end
1189
+
1190
+ # defp checked_fun_apply_static(check_domain, domain, arrows, arguments, maybe_empty?) do
1191
+ # if subtype?(domain_descr(arguments), check_domain) do
1192
+ # new_fun_apply_static(domain, arrows, arguments, maybe_empty?)
1193
+ # else
1194
+ # :badarg
1195
+ # end
1196
+ # end
1197
+
1198
+ # defp new_fun_apply_static(domain, arrows, arguments, maybe_empty?) do
1199
+ # type_args = domain_descr(arguments)
1200
+
1201
+ # cond do
1202
+ # # Optimization: short-circuits when inner loop is none() or outer loop is term()
1203
+ # maybe_empty? and empty?(type_args) ->
1204
+ # result =
1205
+ # Enum.reduce_while(arrows, none(), fn intersection_of_arrows, acc ->
1206
+ # Enum.reduce_while(intersection_of_arrows, term(), fn
1207
+ # {_dom, _ret}, acc when acc == @none -> {:halt, acc}
1208
+ # {_dom, ret}, acc -> {:cont, intersection(acc, ret)}
1209
+ # end)
1210
+ # |> case do
1211
+ # :term -> {:halt, :term}
1212
+ # inner -> {:cont, union(inner, acc)}
1213
+ # end
1214
+ # end)
1215
+
1216
+ # {:ok, result}
1217
+
1218
+ # subtype?(type_args, domain) ->
1219
+ # result =
1220
+ # Enum.reduce(arrows, none(), fn intersection_of_arrows, acc ->
1221
+ # aux_apply(acc, type_args, term(), intersection_of_arrows)
1222
+ # end)
1223
+
1224
+ # {:ok, result}
1225
+
1226
+ # true ->
1227
+ # :badarg
1228
+ # end
1229
+ # end
1124
1230
1125
1231
# Helper function for function application that handles the application of
1126
1232
# function arrows to input types.
@@ -1199,7 +1305,7 @@ defmodule Module.Types.Descr do
1199
1305
#
1200
1306
# This function is used internally by `fun_apply`, and others to
1201
1307
# ensure consistent handling of function types in all operations.
1202
- defp fun_normalize ( bdd , arity , mode ) do
1308
+ defp fun_normalize ( % { fun: bdd } , arity , mode ) do
1203
1309
{ domain , arrows , bad_arities } =
1204
1310
Enum . reduce ( fun_get ( bdd ) , { term ( ) , [ ] , [ ] } , fn
1205
1311
{ [ { args , _ } | _ ] = pos_funs , neg_funs } , { domain , arrows , bad_arities } ->
@@ -1235,6 +1341,10 @@ defmodule Module.Types.Descr do
1235
1341
end
1236
1342
end
1237
1343
1344
+ defp fun_normalize ( % { } , _arity , _mode ) do
1345
+ :badfun
1346
+ end
1347
+
1238
1348
# Checks if a function type is empty.
1239
1349
#
1240
1350
# A function type is empty if:
0 commit comments