Skip to content

Commit 6ff6b44

Browse files
committed
More refactor
1 parent b369df4 commit 6ff6b44

File tree

3 files changed

+75
-53
lines changed

3 files changed

+75
-53
lines changed

lib/elixir/lib/module/types/expr.ex

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,9 @@ defmodule Module.Types.Expr do
108108

109109
# %{map | ...}
110110
def of_expr({:%{}, _, [{:|, _, [map, args]}]}, stack, context) do
111-
with {:ok, _args_type, context} <- Of.closed_map(args, stack, context, &of_expr/3),
112-
{:ok, _map_type, context} <- of_expr(map, stack, context) do
111+
{_args_type, context} = Of.closed_map(args, stack, context, &of_expr/3)
112+
113+
with {:ok, _map_type, context} <- of_expr(map, stack, context) do
113114
# TODO: intersect map with keys of terms for args
114115
# TODO: Merge args_type into map_type with dynamic/static key requirement
115116
{:ok, dynamic(open_map()), context}
@@ -129,28 +130,33 @@ defmodule Module.Types.Expr do
129130
end
130131
end),
131132
# TODO: args_types could be an empty list
132-
{:ok, struct_type, context} <-
133+
{struct_type, context} =
133134
Of.struct(module, args_types, :only_defaults, struct_meta, stack, context),
134135
{:ok, map_type, context} <- of_expr(map, stack, context) do
135136
if disjoint?(struct_type, map_type) do
136137
warning = {:badupdate, :struct, expr, struct_type, map_type, context}
137138
{:ok, error_type(), error(__MODULE__, warning, update_meta, stack, context)}
138139
else
139140
# TODO: Merge args_type into map_type with dynamic/static key requirement
140-
Of.struct(module, args_types, :merge_defaults, struct_meta, stack, context)
141+
{type, context} =
142+
Of.struct(module, args_types, :merge_defaults, struct_meta, stack, context)
143+
144+
{:ok, type, context}
141145
end
142146
end
143147
end
144148

145149
# %{...}
146150
def of_expr({:%{}, _meta, args}, stack, context) do
147-
Of.closed_map(args, stack, context, &of_expr/3)
151+
{type, context} = Of.closed_map(args, stack, context, &of_expr/3)
152+
{:ok, type, context}
148153
end
149154

150155
# %Struct{}
151156
def of_expr({:%, _, [module, {:%{}, _, args}]} = expr, stack, context) do
152157
# TODO: We should not skip defaults
153-
Of.struct(expr, module, args, :skip_defaults, stack, context, &of_expr/3)
158+
{type, context} = Of.struct(expr, module, args, :skip_defaults, stack, context, &of_expr/3)
159+
{:ok, type, context}
154160
end
155161

156162
# ()
@@ -361,7 +367,8 @@ defmodule Module.Types.Expr do
361367
# Exceptions are not validated in the compiler,
362368
# to avoid export dependencies. So we do it here.
363369
if Code.ensure_loaded?(exception) and function_exported?(exception, :__struct__, 0) do
364-
Of.struct(exception, args, :merge_defaults, meta, stack, context)
370+
{type, context} = Of.struct(exception, args, :merge_defaults, meta, stack, context)
371+
{:ok, type, context}
365372
else
366373
# If the exception cannot be found or is invalid,
367374
# we call Of.remote/5 to emit a warning.

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

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -91,53 +91,59 @@ defmodule Module.Types.Of do
9191
Builds a closed map.
9292
"""
9393
def closed_map(pairs, extra \\ [], stack, context, of_fun) do
94-
result =
95-
reduce_ok(pairs, {true, extra, [], context}, fn
94+
of_fun = fn arg1, arg2, arg3 ->
95+
case of_fun.(arg1, arg2, arg3) do
96+
{:ok, type, context} -> {type, context}
97+
{:error, context} -> {dynamic(), context}
98+
{type, context} -> {type, context}
99+
end
100+
end
101+
102+
{closed?, single, multiple, context} =
103+
Enum.reduce(pairs, {true, extra, [], context}, fn
96104
{key, value}, {closed?, single, multiple, context} ->
97-
with {:ok, keys, context} <- of_finite_key_type(key, stack, context, of_fun),
98-
{:ok, value_type, context} <- of_fun.(value, stack, context) do
99-
case keys do
100-
:none ->
101-
{:ok, {false, single, multiple, context}}
102-
103-
[key] when multiple == [] ->
104-
{:ok, {closed?, [{key, value_type} | single], multiple, context}}
105-
106-
keys ->
107-
{:ok, {closed?, single, [{keys, value_type} | multiple], context}}
108-
end
105+
{keys, context} = of_finite_key_type(key, stack, context, of_fun)
106+
{value_type, context} = of_fun.(value, stack, context)
107+
108+
case keys do
109+
:none ->
110+
{false, single, multiple, context}
111+
112+
[key] when multiple == [] ->
113+
{closed?, [{key, value_type} | single], multiple, context}
114+
115+
keys ->
116+
{closed?, single, [{keys, value_type} | multiple], context}
109117
end
110118
end)
111119

112-
with {:ok, {closed?, single, multiple, context}} <- result do
113-
map =
114-
case Enum.reverse(multiple) do
115-
[] ->
116-
pairs = Enum.reverse(single)
117-
if closed?, do: closed_map(pairs), else: open_map(pairs)
120+
map =
121+
case Enum.reverse(multiple) do
122+
[] ->
123+
pairs = Enum.reverse(single)
124+
if closed?, do: closed_map(pairs), else: open_map(pairs)
118125

119-
[{keys, type} | tail] ->
120-
for key <- keys, t <- cartesian_map(tail) do
121-
pairs = Enum.reverse(single, [{key, type} | t])
122-
if closed?, do: closed_map(pairs), else: open_map(pairs)
123-
end
124-
|> Enum.reduce(&union/2)
125-
end
126+
[{keys, type} | tail] ->
127+
for key <- keys, t <- cartesian_map(tail) do
128+
pairs = Enum.reverse(single, [{key, type} | t])
129+
if closed?, do: closed_map(pairs), else: open_map(pairs)
130+
end
131+
|> Enum.reduce(&union/2)
132+
end
126133

127-
{:ok, map, context}
128-
end
134+
{map, context}
129135
end
130136

131137
defp of_finite_key_type(key, _stack, context, _of_fun) when is_atom(key) do
132-
{:ok, [key], context}
138+
{[key], context}
133139
end
134140

135141
defp of_finite_key_type(key, stack, context, of_fun) do
136-
with {:ok, key_type, context} <- of_fun.(key, stack, context) do
137-
case atom_fetch(key_type) do
138-
{:finite, list} -> {:ok, list, context}
139-
_ -> {:ok, :none, context}
140-
end
142+
{key_type, context} = of_fun.(key, stack, context)
143+
144+
case atom_fetch(key_type) do
145+
{:finite, list} -> {list, context}
146+
_ -> {:none, context}
141147
end
142148
end
143149

@@ -156,15 +162,22 @@ defmodule Module.Types.Of do
156162
"""
157163
def struct({:%, meta, _}, struct, args, default_handling, stack, context, of_fun)
158164
when is_atom(struct) do
159-
# The compiler has already checked the keys are atoms and which ones are required.
160-
with {:ok, args_types, context} <-
161-
map_reduce_ok(args, context, fn {key, value}, context when is_atom(key) ->
162-
with {:ok, type, context} <- of_fun.(value, stack, context) do
163-
{:ok, {key, type}, context}
164-
end
165-
end) do
166-
struct(struct, args_types, default_handling, meta, stack, context)
165+
of_fun = fn arg1, arg2, arg3 ->
166+
case of_fun.(arg1, arg2, arg3) do
167+
{:ok, type, context} -> {type, context}
168+
{:error, context} -> {dynamic(), context}
169+
{type, context} -> {type, context}
170+
end
167171
end
172+
173+
# The compiler has already checked the keys are atoms and which ones are required.
174+
{args_types, context} =
175+
Enum.map_reduce(args, context, fn {key, value}, context when is_atom(key) ->
176+
{type, context} = of_fun.(value, stack, context)
177+
{{key, type}, context}
178+
end)
179+
180+
struct(struct, args_types, default_handling, meta, stack, context)
168181
end
169182

170183
@doc """
@@ -186,7 +199,7 @@ defmodule Module.Types.Of do
186199
:only_defaults -> [{:__struct__, atom([struct])} | defaults]
187200
end
188201

189-
{:ok, dynamic(closed_map(pairs)), context}
202+
{dynamic(closed_map(pairs)), context}
190203
end
191204

192205
@doc """

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -624,12 +624,14 @@ defmodule Module.Types.Pattern do
624624
def of_guard({:%, _, [module, {:%{}, _, args}]} = struct, _expected, _expr, stack, context)
625625
when is_atom(module) do
626626
fun = &of_guard(&1, dynamic(), struct, &2, &3)
627-
Of.struct(struct, module, args, :skip_defaults, stack, context, fun)
627+
{type, context} = Of.struct(struct, module, args, :skip_defaults, stack, context, fun)
628+
{:ok, type, context}
628629
end
629630

630631
# %{...}
631632
def of_guard({:%{}, _meta, args}, _expected, expr, stack, context) do
632-
Of.closed_map(args, stack, context, &of_guard(&1, dynamic(), expr, &2, &3))
633+
{type, context} = Of.closed_map(args, stack, context, &of_guard(&1, dynamic(), expr, &2, &3))
634+
{:ok, type, context}
633635
end
634636

635637
# <<>>

0 commit comments

Comments
 (0)