checkpoioint before refactor

This commit is contained in:
Kacper Marzecki 2025-06-16 17:07:36 +02:00
parent cc62c5ce8e
commit 1ede4de72c

View File

@ -584,8 +584,10 @@ defp check_integer_logic(assumptions_map, primary_true_predicates) do
:alt -> :alt ->
is_integer(current_interval_max) && current_interval_max < n_val is_integer(current_interval_max) && current_interval_max < n_val
:cgt -> :cgt ->
is_integer(current_interval_min) && current_interval_min > n_val is_integer(current_interval_min) && current_interval_min > n_val
_ -> _ ->
false false
end end
@ -595,10 +597,13 @@ defp check_integer_logic(assumptions_map, primary_true_predicates) do
:beq -> :beq ->
(is_integer(current_interval_min) && current_interval_min > n_val) || (is_integer(current_interval_min) && current_interval_min > n_val) ||
(is_integer(current_interval_max) && current_interval_max < n_val) (is_integer(current_interval_max) && current_interval_max < n_val)
:alt -> :alt ->
is_integer(current_interval_min) && current_interval_min >= n_val is_integer(current_interval_min) && current_interval_min >= n_val
:cgt -> :cgt ->
is_integer(current_interval_max) && current_interval_max <= n_val is_integer(current_interval_max) && current_interval_max <= n_val
_ -> _ ->
false false
end end
@ -636,8 +641,10 @@ defp check_integer_logic(assumptions_map, primary_true_predicates) do
# A predicate on head or tail exists, e.g. {{5, :head, _}, _} # A predicate on head or tail exists, e.g. {{5, :head, _}, _}
has_head_or_tail_pred = has_head_or_tail_pred =
Enum.any?(assumptions_map, fn {{_cat, ptype, _}, _} -> ptype == :head or ptype == :tail Enum.any?(assumptions_map, fn
_ -> false end) {{_cat, ptype, _}, _} -> ptype == :head or ptype == :tail
_ -> false
end)
cond do cond do
# Contradiction: list-specific rule is assumed, but type is not a list. # Contradiction: list-specific rule is assumed, but type is not a list.
@ -926,6 +933,7 @@ defp check_integer_logic(assumptions_map, primary_true_predicates) do
# 5. Simplify the final result. # 5. Simplify the final result.
simplify_with_constraints(raw_final_tdd, %{}) simplify_with_constraints(raw_final_tdd, %{})
end end
def type_list_of(element_type_id) when is_integer(element_type_id) do def type_list_of(element_type_id) when is_integer(element_type_id) do
# An empty list satisfies any list_of constraint vacuously. # An empty list satisfies any list_of constraint vacuously.
# The type is effectively `[] | [X | list(X)]` # The type is effectively `[] | [X | list(X)]`
@ -935,11 +943,19 @@ def type_list_of(element_type_id) when is_integer(element_type_id) do
if element_type_id == type_any() do if element_type_id == type_any() do
type_list() type_list()
else else
all_elems_check = make_node_raw(v_list_all_elements_are(element_type_id), @true_node_id, @false_node_id, @false_node_id) all_elems_check =
make_node_raw(
v_list_all_elements_are(element_type_id),
@true_node_id,
@false_node_id,
@false_node_id
)
raw_node = make_node_raw(v_is_list(), all_elems_check, @false_node_id, @false_node_id) raw_node = make_node_raw(v_is_list(), all_elems_check, @false_node_id, @false_node_id)
simplify_with_constraints(raw_node, %{}) simplify_with_constraints(raw_node, %{})
end end
end end
def type_int_eq(n) do def type_int_eq(n) do
int_eq_node = make_node_raw(v_int_eq(n), @true_node_id, @false_node_id, @false_node_id) int_eq_node = make_node_raw(v_int_eq(n), @true_node_id, @false_node_id, @false_node_id)
raw_node = make_node_raw(@v_is_integer, int_eq_node, @false_node_id, @false_node_id) raw_node = make_node_raw(@v_is_integer, int_eq_node, @false_node_id, @false_node_id)
@ -1843,6 +1859,7 @@ defmodule ListTests do
IO.inspect(Process.get(:test_failures, []), label: "ListTests failures") IO.inspect(Process.get(:test_failures, []), label: "ListTests failures")
end end
end end
defmodule ListOfTests do defmodule ListOfTests do
import Tdd import Tdd
@ -1865,9 +1882,12 @@ defmodule ListOfTests do
# --- Specific List Types --- # --- Specific List Types ---
t_list = type_list() t_list = type_list()
t_empty_list = type_empty_list() t_empty_list = type_empty_list()
t_list_one_int = type_cons(t_int_5, t_empty_list) # [5] # [5]
t_list_one_atom = type_cons(type_atom_literal(:foo), t_empty_list) # [:foo] t_list_one_int = type_cons(t_int_5, t_empty_list)
t_list_int_and_atom = type_cons(t_int_5, type_cons(type_atom_literal(:foo), t_empty_list)) # [5, :foo] # [:foo]
t_list_one_atom = type_cons(type_atom_literal(:foo), t_empty_list)
# [5, :foo]
t_list_int_and_atom = type_cons(t_int_5, type_cons(type_atom_literal(:foo), t_empty_list))
IO.puts("\n--- Section: Basic list(X) Subtyping ---") IO.puts("\n--- Section: Basic list(X) Subtyping ---")
test_fn.("list(integer) <: list()", true, is_subtype(t_list_of_int, t_list)) test_fn.("list(integer) <: list()", true, is_subtype(t_list_of_int, t_list))
@ -1876,16 +1896,36 @@ defmodule ListOfTests do
test_fn.("[5] <: list(integer)", true, is_subtype(t_list_one_int, t_list_of_int)) test_fn.("[5] <: list(integer)", true, is_subtype(t_list_one_int, t_list_of_int))
test_fn.("[:foo] <: list(integer)", false, is_subtype(t_list_one_atom, t_list_of_int)) test_fn.("[:foo] <: list(integer)", false, is_subtype(t_list_one_atom, t_list_of_int))
test_fn.("[5, :foo] <: list(integer)", false, is_subtype(t_list_int_and_atom, t_list_of_int)) test_fn.("[5, :foo] <: list(integer)", false, is_subtype(t_list_int_and_atom, t_list_of_int))
test_fn.("[5, :foo] <: list(any)", true, is_subtype(t_list_int_and_atom, type_list_of(type_any())))
test_fn.(
"[5, :foo] <: list(any)",
true,
is_subtype(t_list_int_and_atom, type_list_of(type_any()))
)
IO.puts("\n--- Section: Covariance of list(X) ---") IO.puts("\n--- Section: Covariance of list(X) ---")
test_fn.("list(pos_integer) <: list(integer)", true, is_subtype(t_list_of_pos_int, t_list_of_int))
test_fn.("list(integer) <: list(pos_integer)", false, is_subtype(t_list_of_int, t_list_of_pos_int)) test_fn.(
"list(pos_integer) <: list(integer)",
true,
is_subtype(t_list_of_pos_int, t_list_of_int)
)
test_fn.(
"list(integer) <: list(pos_integer)",
false,
is_subtype(t_list_of_int, t_list_of_pos_int)
)
IO.puts("\n--- Section: Intersection of list(X) ---") IO.puts("\n--- Section: Intersection of list(X) ---")
# list(integer) & list(pos_integer) should be list(pos_integer) # list(integer) & list(pos_integer) should be list(pos_integer)
intersect1 = intersect(t_list_of_int, t_list_of_pos_int) intersect1 = intersect(t_list_of_int, t_list_of_pos_int)
test_fn.("(list(int) & list(pos_int)) == list(pos_int)", true, intersect1 == t_list_of_pos_int)
test_fn.(
"(list(int) & list(pos_int)) == list(pos_int)",
true,
intersect1 == t_list_of_pos_int
)
# list(integer) & list(atom) should be just [] (empty list is the only common member) # list(integer) & list(atom) should be just [] (empty list is the only common member)
# The system simplifies this intersection to a type that only accepts the empty list. # The system simplifies this intersection to a type that only accepts the empty list.
@ -1896,7 +1936,6 @@ defmodule ListOfTests do
# It should be equivalent to `type_empty_list` # It should be equivalent to `type_empty_list`
test_fn.("(list(int) & list(atom)) == []", true, intersect2 == t_empty_list) test_fn.("(list(int) & list(atom)) == []", true, intersect2 == t_empty_list)
IO.puts("\n--- Section: Intersection of list(X) with cons ---") IO.puts("\n--- Section: Intersection of list(X) with cons ---")
# list(integer) & [:foo | []] -> should be none # list(integer) & [:foo | []] -> should be none
intersect3 = intersect(t_list_of_int, t_list_one_atom) intersect3 = intersect(t_list_of_int, t_list_one_atom)
@ -1913,6 +1952,7 @@ defmodule ListOfTests do
IO.inspect(Process.get(:test_failures, []), label: "ListOfTests failures") IO.inspect(Process.get(:test_failures, []), label: "ListOfTests failures")
end end
end end
test_all.() test_all.()
IntegerTests.run(test) IntegerTests.run(test)
TupleTests.run(test) TupleTests.run(test)