Skip to content

Commit caea8bc

Browse files
committed
Move conditional vars into an official API
1 parent a4e7a2d commit caea8bc

2 files changed

Lines changed: 46 additions & 27 deletions

File tree

lib/elixir/lib/module/types/of.ex

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,45 @@ defmodule Module.Types.Of do
163163
defp new_trace(expr, type, stack, traces),
164164
do: [{expr, stack.file, type} | traces]
165165

166+
@doc """
167+
Executes the args with acc using conditional variables.
168+
"""
169+
def with_conditional_vars(args, acc, expr, stack, context, fun) do
170+
%{vars: vars, conditional_vars: conditional_vars} = context
171+
172+
{vars_conds, {acc, context}} =
173+
Enum.map_reduce(args, {acc, context}, fn arg, {acc, context} ->
174+
{acc, context} = fun.(arg, acc, %{context | vars: vars, conditional_vars: %{}})
175+
%{vars: vars, conditional_vars: cond_vars} = context
176+
{{vars, cond_vars}, {acc, context}}
177+
end)
178+
179+
context = %{context | vars: vars, conditional_vars: conditional_vars}
180+
{acc, reduce_conditional_vars(vars_conds, expr, stack, context)}
181+
end
182+
183+
@doc """
184+
Reduces conditional variables collected separately.
185+
"""
186+
def reduce_conditional_vars([{vars, cond} | vars_conds], expr, stack, context) do
187+
Enum.reduce(Map.keys(cond), context, fn version, context ->
188+
if Enum.all?(vars_conds, fn {_vars, cond} -> is_map_key(cond, version) end) do
189+
%{^version => %{type: type}} = vars
190+
191+
type =
192+
Enum.reduce(vars_conds, type, fn {vars, _cond}, acc ->
193+
%{^version => %{type: type}} = vars
194+
union(acc, type)
195+
end)
196+
197+
{_, context} = refine_body_var(version, type, expr, stack, context)
198+
context
199+
else
200+
context
201+
end
202+
end)
203+
end
204+
166205
## Implementations
167206

168207
impls = [

lib/elixir/lib/module/types/pattern.ex

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -745,16 +745,15 @@ defmodule Module.Types.Pattern do
745745
end
746746

747747
defp of_guards(guards, stack, context) do
748-
cond_context = %{context | conditional_vars: %{}}
748+
expr = Enum.reduce(guards, {:_, [], []}, &{:when, [], [&2, &1]})
749749

750-
{vars_conds, context} =
751-
Enum.map_reduce(guards, context, fn guard, context ->
752-
{type, %{vars: vars, conditional_vars: cond_vars}} = of_guard(guard, stack, cond_context)
753-
{{vars, cond_vars}, maybe_badguard(type, guard, stack, context)}
750+
{:ok, context} =
751+
Of.with_conditional_vars(guards, :ok, expr, stack, context, fn guard, :ok, context ->
752+
{type, context} = of_guard(guard, stack, context)
753+
{:ok, maybe_badguard(type, guard, stack, context)}
754754
end)
755755

756-
when_expr = Enum.reduce(guards, {:_, [], []}, &{:when, [], [&2, &1]})
757-
of_cond_vars(vars_conds, when_expr, stack, context)
756+
context
758757
end
759758

760759
defp maybe_badguard(type, guard, stack, context) do
@@ -901,7 +900,7 @@ defmodule Module.Types.Pattern do
901900
{type, vars_conds} =
902901
of_logical_cond([left | right], true, expected, abort_domain, stack, cond_context, [])
903902

904-
{type, of_cond_vars(vars_conds, call, stack, context)}
903+
{type, Of.reduce_conditional_vars(vars_conds, call, stack, context)}
905904
end
906905
end
907906

@@ -959,25 +958,6 @@ defmodule Module.Types.Pattern do
959958
of_logical_cond(tail, disjoint?, expected, to_abort, stack, context, acc)
960959
end
961960

962-
defp of_cond_vars([{vars, cond} | vars_conds], expr, stack, context) do
963-
Enum.reduce(Map.keys(cond), context, fn version, context ->
964-
if Enum.all?(vars_conds, fn {_vars, cond} -> is_map_key(cond, version) end) do
965-
%{^version => %{type: type}} = vars
966-
967-
type =
968-
Enum.reduce(vars_conds, type, fn {vars, _cond}, acc ->
969-
%{^version => %{type: type}} = vars
970-
union(acc, type)
971-
end)
972-
973-
{_, context} = Of.refine_body_var(version, type, expr, stack, context)
974-
context
975-
else
976-
context
977-
end
978-
end)
979-
end
980-
981961
## Helpers
982962

983963
def format_diagnostic({:badguard, type, expr, context}) do

0 commit comments

Comments
 (0)