Skip to content

Commit 551de4f

Browse files
committed
All green
1 parent 303031c commit 551de4f

2 files changed

Lines changed: 66 additions & 63 deletions

File tree

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

Lines changed: 55 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -185,12 +185,15 @@ defmodule Module.Types.Pattern do
185185
{version, context}
186186
end)
187187

188-
try do
189-
{types, of_pattern_var_deps(changed, vars_paths, vars_deps, tag, stack, context)}
190-
catch
191-
{:error, context} -> {types, error_vars(pattern_info, context)}
192-
end
188+
context =
189+
Enum.reduce(changed, context, fn version, context ->
190+
{_, context} = of_pattern_var_dep(vars_paths, version, tag, stack, context)
191+
context
192+
end)
193+
194+
{types, of_pattern_var_deps(changed, vars_paths, vars_deps, tag, stack, context)}
193195
catch
196+
{:error, context} -> {types, error_vars(pattern_info, context)}
194197
{types, context} -> {types, error_vars(pattern_info, context)}
195198
end
196199
end
@@ -201,52 +204,55 @@ defmodule Module.Types.Pattern do
201204

202205
defp of_pattern_var_deps(previous_changed, vars_paths, vars_deps, tag, stack, context) do
203206
{changed, context} =
204-
Enum.reduce(previous_changed, {[], context}, fn version, {changed, context} ->
205-
paths = Map.get(vars_paths, version, [])
206-
207-
{var_changed?, context} =
208-
Enum.reduce(paths, {false, context}, fn
209-
%{var: var, expr: expr, root: root, path: path}, {var_changed?, context} ->
210-
index = 0
211-
actual = of_pattern_tree(root, context)
212-
213-
case of_pattern_var(path, actual, context) do
214-
{:ok, type} ->
215-
# Optimization: if current type is already a subtype, there is nothing to refine.
216-
with %{^version => %{type: current_type}} <- context.vars,
217-
true <- subtype?(current_type, type) do
218-
{var_changed?, context}
219-
else
220-
_ ->
221-
case Of.refine_head_var(var, type, expr, stack, context) do
222-
{:ok, _type, context} ->
223-
{true, context}
224-
225-
{:error, old_type, context} ->
226-
throw({:error, refine_error(var, old_type, type, stack, context)})
227-
end
228-
end
229-
230-
:error ->
231-
throw({:error, badpattern_error(expr, index, tag, stack, context)})
232-
end
233-
end)
207+
previous_changed
208+
|> Enum.reduce(%{}, fn version, acc ->
209+
case vars_deps do
210+
%{^version => deps} -> Map.merge(acc, deps)
211+
%{} -> acc
212+
end
213+
end)
214+
|> Map.keys()
215+
|> Enum.reduce({[], context}, fn version, {changed, context} ->
216+
{var_changed?, context} = of_pattern_var_dep(vars_paths, version, tag, stack, context)
234217

235218
case var_changed? do
236219
false -> {changed, context}
237220
true -> {[version | changed], context}
238221
end
239222
end)
240223

241-
changed
242-
|> Enum.reduce(%{}, fn version, acc ->
243-
case vars_deps do
244-
%{^version => deps} -> Map.merge(acc, deps)
245-
%{} -> acc
246-
end
224+
of_pattern_var_deps(changed, vars_paths, vars_deps, tag, stack, context)
225+
end
226+
227+
defp of_pattern_var_dep(vars_paths, version, tag, stack, context) do
228+
paths = Map.get(vars_paths, version, [])
229+
230+
Enum.reduce(paths, {false, context}, fn
231+
%{var: var, expr: expr, root: root, path: path}, {var_changed?, context} ->
232+
index = 0
233+
actual = of_pattern_tree(root, context)
234+
235+
case of_pattern_var(path, actual, context) do
236+
{:ok, type} ->
237+
# Optimization: if current type is already a subtype, there is nothing to refine.
238+
with %{^version => %{type: current_type}} <- context.vars,
239+
true <- subtype?(current_type, type) do
240+
{var_changed?, context}
241+
else
242+
_ ->
243+
case Of.refine_head_var(var, type, expr, stack, context) do
244+
{:ok, _type, context} ->
245+
{true, context}
246+
247+
{:error, old_type, context} ->
248+
throw({:error, refine_error(var, old_type, type, stack, context)})
249+
end
250+
end
251+
252+
:error ->
253+
throw({:error, badpattern_error(expr, index, tag, stack, context)})
254+
end
247255
end)
248-
|> Map.keys()
249-
|> of_pattern_var_deps(vars_paths, vars_deps, tag, stack, context)
250256
end
251257

252258
defp error_vars({args_paths, vars_paths, _vars_deps}, context) do
@@ -431,7 +437,7 @@ defmodule Module.Types.Pattern do
431437
{match, version, var} =
432438
match
433439
|> unpack_match([])
434-
|> Enum.split_while(&(not is_var(&1)))
440+
|> Enum.split_while(&(not is_versioned_var(&1)))
435441
|> case do
436442
{match, []} ->
437443
version = make_ref()
@@ -575,6 +581,11 @@ defmodule Module.Types.Pattern do
575581
{{:var, version}, context}
576582
end
577583

584+
defp is_versioned_var({name, _meta, ctx}) when is_atom(name) and is_atom(ctx) and name != :_,
585+
do: true
586+
587+
defp is_versioned_var(_), do: false
588+
578589
defp of_var(var, version, reverse_path, context) do
579590
{args_paths, vars_paths, vars_deps} = context.pattern_info
580591
[%{root: root, expr: expr} | path] = Enum.reverse(reverse_path)

lib/elixir/test/elixir/module/types/pattern_test.exs

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,21 @@ defmodule Module.Types.PatternTest do
5252
end
5353

5454
test "errors on conflicting refinements" do
55-
assert typeerror!([a = b, a = :foo, b = :bar], {a, b}) ==
56-
~l"""
57-
incompatible types assigned to "a":
55+
assert typeerror!([a = b, a = :foo, b = :bar], {a, b}) == ~l"""
56+
incompatible types assigned to "a":
5857
59-
dynamic(:foo) !~ dynamic(:bar)
58+
dynamic(:foo) !~ dynamic(:bar)
6059
61-
where "a" was given the types:
60+
where "a" was given the types:
6261
63-
# type: dynamic(:foo)
64-
# from: types_test.ex:55
65-
a = :foo
62+
# type: dynamic(:foo)
63+
# from: types_test.ex:LINE
64+
a = :foo
6665
67-
# type: dynamic(:bar)
68-
# from: types_test.ex:55
69-
a = b
70-
"""
66+
# type: dynamic(:bar)
67+
# from: types_test.ex:LINE
68+
a = b
69+
"""
7170
end
7271

7372
test "can be accessed even if they don't match" do
@@ -114,13 +113,6 @@ defmodule Module.Types.PatternTest do
114113
) == dynamic(tuple([atom([:foo]), integer()]))
115114
end
116115

117-
test "parallel match with map" do
118-
assert typecheck!(
119-
[%{key: value} = context = %{key: %{}}],
120-
{context, value}
121-
) == dynamic(tuple([atom([:foo]), integer()]))
122-
end
123-
124116
test "reports incompatible types" do
125117
assert typeerror!([x = {:ok, _} = {:error, _, _}], x) == ~l"""
126118
the following pattern will never match:

0 commit comments

Comments
 (0)