@@ -1040,122 +1040,124 @@ defmodule Module.Types.Descr do
1040
1040
end
1041
1041
end
1042
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 }
1043
+ with { :ok , domain , static_arrows , dynamic_arrows } <-
1044
+ fun_normalize_both ( fun_static , fun_dynamic , arity ) do
1045
+ cond do
1046
+ not subtype? ( domain_descr ( arguments ) , domain ) ->
1047
+ :badarg
1048
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 }
1049
+ static_arrows == [ ] ->
1050
+ { :ok , dynamic ( fun_apply_static ( arguments , dynamic_arrows , false ) ) }
1054
1051
1055
- _ ->
1056
- # TODO: Should dynamic_arrows be [] or static_arrows
1057
- { :ok , static_domain , static_arrows , static_arrows }
1058
- end
1052
+ true ->
1053
+ # For dynamic cases, combine static and dynamic results
1054
+ { static_args , dynamic_args , maybe_empty? } =
1055
+ if args_dynamic? do
1056
+ { materialize_arguments ( arguments , :up ) , materialize_arguments ( arguments , :down ) ,
1057
+ true }
1058
+ else
1059
+ { arguments , arguments , false }
1060
+ end
1061
+
1062
+ { :ok ,
1063
+ union (
1064
+ fun_apply_static ( static_args , static_arrows , false ) ,
1065
+ dynamic ( fun_apply_static ( dynamic_args , dynamic_arrows , maybe_empty? ) )
1066
+ ) }
1067
+ end
1068
+ end
1069
+ end
1070
+ end
1059
1071
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 }
1072
+ # Materializes arguments using the specified direction (up or down)
1073
+ defp materialize_arguments ( arguments , :up ) , do: Enum . map ( arguments , & upper_bound / 1 )
1074
+ defp materialize_arguments ( arguments , :down ) , do: Enum . map ( arguments , & lower_bound / 1 )
1065
1075
1066
- error ->
1067
- error
1068
- end
1076
+ defp are_arguments_dynamic? ( arguments ) , do: Enum . any? ( arguments , & match? ( % { dynamic: _ } , & 1 ) )
1069
1077
1070
- error ->
1071
- error
1078
+ defp fun_normalize_both ( fun_static , fun_dynamic , arity ) do
1079
+ case fun_normalize ( fun_static , arity , :static ) do
1080
+ { :ok , static_domain , static_arrows } when fun_dynamic == nil ->
1081
+ { :ok , static_domain , static_arrows , static_arrows }
1082
+
1083
+ { :ok , static_domain , static_arrows } when fun_dynamic != nil ->
1084
+ case fun_normalize ( fun_dynamic , arity , :dynamic ) do
1085
+ { :ok , dynamic_domain , dynamic_arrows } ->
1086
+ domain = union ( dynamic_domain , dynamic ( static_domain ) )
1087
+ { :ok , domain , static_arrows , dynamic_arrows }
1088
+
1089
+ _ ->
1090
+ { :ok , static_domain , static_arrows , static_arrows }
1072
1091
end
1073
1092
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
1093
+ :badfun ->
1094
+ case fun_normalize ( fun_dynamic , arity , :dynamic ) do
1095
+ { :ok , dynamic_domain , dynamic_arrows } ->
1096
+ { :ok , dynamic_domain , [ ] , dynamic_arrows }
1084
1097
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
1098
+ error ->
1099
+ error
1092
1100
end
1093
- end
1094
1101
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
1102
+ error ->
1103
+ error
1151
1104
end
1152
1105
end
1153
1106
1154
- # Materializes arguments using the specified direction (up or down)
1155
- defp materialize_arguments ( arguments , :up ) , do: Enum . map ( arguments , & upper_bound / 1 )
1156
- defp materialize_arguments ( arguments , :down ) , do: Enum . map ( arguments , & lower_bound / 1 )
1107
+ # Transforms a binary decision diagram (BDD) into the canonical form {domain, arrows, arity}:
1108
+ #
1109
+ # 1. **domain**: The union of all domains from positive functions in the BDD
1110
+ # 2. **arrows**: List of lists, where each inner list contains an intersection of function arrows
1111
+ # 3. **arity**: Function arity (number of parameters)
1112
+ #
1113
+ ## Return Values
1114
+ #
1115
+ # - `{domain, arrows, arity}` for valid function BDDs
1116
+ # - `:badfun` if the BDD represents an empty function type
1117
+ #
1118
+ # ## Internal Use
1119
+ #
1120
+ # This function is used internally by `fun_apply`, and others to
1121
+ # ensure consistent handling of function types in all operations.
1122
+ defp fun_normalize ( % { fun: bdd } , arity , mode ) do
1123
+ { domain , arrows , bad_arities } =
1124
+ Enum . reduce ( fun_get ( bdd ) , { term ( ) , [ ] , [ ] } , fn
1125
+ { [ { args , _ } | _ ] = pos_funs , neg_funs } , { domain , arrows , bad_arities } ->
1126
+ arrow_arity = length ( args )
1157
1127
1158
- defp are_arguments_dynamic? ( arguments ) , do: Enum . any? ( arguments , & match? ( % { dynamic: _ } , & 1 ) )
1128
+ cond do
1129
+ arrow_arity != arity ->
1130
+ { domain , arrows , [ arrow_arity | bad_arities ] }
1131
+
1132
+ fun_empty? ( pos_funs , neg_funs ) ->
1133
+ { domain , arrows , bad_arities }
1134
+
1135
+ true ->
1136
+ # Calculate domain from all positive functions
1137
+ path_domain =
1138
+ Enum . reduce ( pos_funs , none ( ) , fn { args , _ } , acc ->
1139
+ union ( acc , domain_descr ( args ) )
1140
+ end )
1141
+
1142
+ { intersection ( domain , path_domain ) , [ pos_funs | arrows ] , bad_arities }
1143
+ end
1144
+ end )
1145
+
1146
+ case { arrows , bad_arities } do
1147
+ { [ ] , [ ] } ->
1148
+ :badfun
1149
+
1150
+ { arrows , [ _ | _ ] = bad_arities } when mode == :static or arrows == [ ] ->
1151
+ { :badarity , Enum . uniq ( bad_arities ) }
1152
+
1153
+ { _ , _ } ->
1154
+ { :ok , domain , arrows }
1155
+ end
1156
+ end
1157
+
1158
+ defp fun_normalize ( % { } , _arity , _mode ) do
1159
+ :badfun
1160
+ end
1159
1161
1160
1162
defp fun_apply_static ( arguments , arrows , maybe_empty? ) do
1161
1163
type_args = domain_descr ( arguments )
@@ -1179,55 +1181,6 @@ defmodule Module.Types.Descr do
1179
1181
end
1180
1182
end
1181
1183
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
1230
-
1231
1184
# Helper function for function application that handles the application of
1232
1185
# function arrows to input types.
1233
1186
@@ -1290,61 +1243,6 @@ defmodule Module.Types.Descr do
1290
1243
end
1291
1244
end
1292
1245
1293
- # Transforms a binary decision diagram (BDD) into the canonical form {domain, arrows, arity}:
1294
- #
1295
- # 1. **domain**: The union of all domains from positive functions in the BDD
1296
- # 2. **arrows**: List of lists, where each inner list contains an intersection of function arrows
1297
- # 3. **arity**: Function arity (number of parameters)
1298
- #
1299
- ## Return Values
1300
- #
1301
- # - `{domain, arrows, arity}` for valid function BDDs
1302
- # - `:badfun` if the BDD represents an empty function type
1303
- #
1304
- # ## Internal Use
1305
- #
1306
- # This function is used internally by `fun_apply`, and others to
1307
- # ensure consistent handling of function types in all operations.
1308
- defp fun_normalize ( % { fun: bdd } , arity , mode ) do
1309
- { domain , arrows , bad_arities } =
1310
- Enum . reduce ( fun_get ( bdd ) , { term ( ) , [ ] , [ ] } , fn
1311
- { [ { args , _ } | _ ] = pos_funs , neg_funs } , { domain , arrows , bad_arities } ->
1312
- arrow_arity = length ( args )
1313
-
1314
- cond do
1315
- arrow_arity != arity ->
1316
- { domain , arrows , [ arrow_arity | bad_arities ] }
1317
-
1318
- fun_empty? ( pos_funs , neg_funs ) ->
1319
- { domain , arrows , bad_arities }
1320
-
1321
- true ->
1322
- # Calculate domain from all positive functions
1323
- path_domain =
1324
- Enum . reduce ( pos_funs , none ( ) , fn { args , _ } , acc ->
1325
- union ( acc , domain_descr ( args ) )
1326
- end )
1327
-
1328
- { intersection ( domain , path_domain ) , [ pos_funs | arrows ] , bad_arities }
1329
- end
1330
- end )
1331
-
1332
- case { arrows , bad_arities } do
1333
- { [ ] , [ ] } ->
1334
- :badfun
1335
-
1336
- { arrows , [ _ | _ ] = bad_arities } when mode == :static or arrows == [ ] ->
1337
- { :badarity , Enum . uniq ( bad_arities ) }
1338
-
1339
- { _ , _ } ->
1340
- { :ok , domain , arrows }
1341
- end
1342
- end
1343
-
1344
- defp fun_normalize ( % { } , _arity , _mode ) do
1345
- :badfun
1346
- end
1347
-
1348
1246
# Checks if a function type is empty.
1349
1247
#
1350
1248
# A function type is empty if:
0 commit comments