Skip to content

Commit dddb9b6

Browse files
committed
One failure down
1 parent cc072ac commit dddb9b6

File tree

3 files changed

+81
-78
lines changed

3 files changed

+81
-78
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ defmodule Module.Types.Expr do
346346
_ ->
347347
expected = if structs == [], do: @exception, else: Enum.reduce(structs, &union/2)
348348
formatter = fn expr -> {"rescue #{expr_to_string(expr)} ->", hints} end
349-
{_type, context} = Of.refine_var(var, expected, expr, formatter, stack, context)
349+
{_ok?, _type, context} = Of.refine_var(var, expected, expr, formatter, stack, context)
350350
context
351351
end
352352

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@ defmodule Module.Types.Of do
4747

4848
# We need to return error otherwise it leads to cascading errors
4949
if empty?(new_type) do
50-
{error_type(), error({:refine_var, old_type, type, var, context}, meta, stack, context)}
50+
{:error, error_type(),
51+
error({:refine_var, old_type, type, var, context}, meta, stack, context)}
5152
else
52-
{new_type, context}
53+
{:ok, new_type, context}
5354
end
5455

5556
%{} ->
@@ -61,7 +62,7 @@ defmodule Module.Types.Of do
6162
}
6263

6364
context = put_in(context.vars[version], data)
64-
{type, context}
65+
{:ok, type, context}
6566
end
6667
end
6768

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

Lines changed: 76 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -32,29 +32,27 @@ defmodule Module.Types.Pattern do
3232
dynamic = dynamic()
3333
expected_types = Enum.map(patterns, fn _ -> dynamic end)
3434

35-
with {:ok, _trees, types, context} <-
36-
of_pattern_args(patterns, expected_types, stack, context) do
37-
{_, context} = Enum.map_reduce(guards, context, &of_guard(&1, @guard, &1, stack, &2))
38-
{:ok, types, context}
39-
end
35+
{_trees, types, context} = of_pattern_args(patterns, expected_types, stack, context)
36+
{_, context} = Enum.map_reduce(guards, context, &of_guard(&1, @guard, &1, stack, &2))
37+
{:ok, types, context}
4038
end
4139

4240
defp of_pattern_args([], [], _stack, context) do
43-
{:ok, [], context}
41+
{[], [], context}
4442
end
4543

46-
defp of_pattern_args(patterns, expected_types, stack, init_context) do
47-
context = %{init_context | pattern_info: {%{}, %{}}, failed: false}
44+
defp of_pattern_args(patterns, expected_types, stack, context) do
45+
context = %{context | pattern_info: {%{}, %{}}}
4846
changed = :lists.seq(0, length(patterns) - 1)
4947

5048
{trees, context} = of_pattern_args_index(patterns, expected_types, 0, [], stack, context)
5149

52-
with {:ok, types, context} <-
53-
of_pattern_recur(expected_types, changed, stack, context, fn types, changed, context ->
54-
of_pattern_args_tree(trees, types, changed, 0, [], stack, context)
55-
end) do
56-
{:ok, trees, types, merge_failed(init_context, context)}
57-
end
50+
{types, context} =
51+
of_pattern_recur(expected_types, changed, stack, context, fn types, changed, context ->
52+
of_pattern_args_tree(trees, types, changed, 0, [], stack, context)
53+
end)
54+
55+
{trees, types, context}
5856
end
5957

6058
defp of_pattern_args_index(
@@ -107,80 +105,86 @@ defmodule Module.Types.Pattern do
107105
Return the type and typing context of a pattern expression with
108106
the given expected and expr or an error in case of a typing conflict.
109107
"""
110-
def of_match(pattern, expected, expr, stack, init_context) do
111-
context = %{init_context | pattern_info: {%{}, %{}}, failed: false}
108+
def of_match(pattern, expected, expr, stack, context) do
109+
context = %{context | pattern_info: {%{}, %{}}}
112110
{tree, context} = of_pattern(pattern, [{:arg, 0, expected, expr}], stack, context)
113111

114-
with {:ok, [type], context} <-
115-
of_pattern_recur([expected], [0], stack, context, fn [type], [0], context ->
116-
with {:ok, type, context} <- of_pattern_intersect(tree, type, expr, stack, context) do
117-
{:ok, [type], context}
118-
end
119-
end) do
120-
{type, merge_failed(init_context, context)}
121-
else
122-
{:error, context} -> {error_type(), context}
123-
end
112+
{[type], context} =
113+
of_pattern_recur([expected], [0], stack, context, fn [type], [0], context ->
114+
with {:ok, type, context} <- of_pattern_intersect(tree, type, expr, stack, context) do
115+
{:ok, [type], context}
116+
end
117+
end)
118+
119+
{type, context}
124120
end
125121

126122
defp of_pattern_recur(types, changed, stack, context, callback) do
127123
%{pattern_info: {pattern_vars, pattern_args}} = context
128124
context = %{context | pattern_info: nil}
129125
pattern_vars = Map.to_list(pattern_vars)
130126
of_pattern_recur(types, changed, pattern_vars, pattern_args, stack, context, callback)
127+
catch
128+
{types, context} -> {types, context}
131129
end
132130

133131
defp of_pattern_recur(types, [], _vars, _args, _stack, context, _callback) do
134-
{:ok, types, context}
135-
end
136-
137-
defp of_pattern_recur(_types, _, _vars, _args, _stack, %{failed: true} = context, _callback) do
138-
{:error, context}
132+
{types, context}
139133
end
140134

141135
defp of_pattern_recur(types, changed, vars, args, stack, context, callback) do
142-
with {:ok, types, %{vars: context_vars} = context} <- callback.(types, changed, context) do
143-
{changed, context} =
144-
Enum.reduce(vars, {[], context}, fn {version, paths}, {changed, context} ->
145-
current_type = context_vars[version][:type]
146-
147-
{var_changed?, context} =
148-
Enum.reduce(paths, {false, context}, fn
149-
[var, {:arg, index, expected, expr} | path], {var_changed?, context} ->
150-
actual = Enum.fetch!(types, index)
151-
152-
case of_pattern_var(path, actual) do
153-
{:ok, type} ->
154-
{type, context} = Of.refine_var(var, type, expr, stack, context)
155-
{var_changed? or current_type != type, context}
156-
157-
:error ->
158-
{var_changed?, Of.incompatible_error(expr, expected, actual, stack, context)}
159-
end
160-
end)
161-
162-
case var_changed? do
163-
false ->
164-
{changed, context}
165-
166-
true ->
167-
case paths do
168-
# A single change, check if there are other variables in this index.
169-
[[_var, {:arg, index, _, _} | _]] ->
170-
case args do
171-
%{^index => true} -> {[index | changed], context}
172-
%{^index => false} -> {changed, context}
136+
case callback.(types, changed, context) do
137+
{:ok, types, %{vars: context_vars} = context} ->
138+
{changed, context} =
139+
Enum.reduce(vars, {[], context}, fn {version, paths}, {changed, context} ->
140+
current_type = context_vars[version][:type]
141+
142+
{var_changed?, context} =
143+
Enum.reduce(paths, {false, context}, fn
144+
[var, {:arg, index, expected, expr} | path], {var_changed?, context} ->
145+
actual = Enum.fetch!(types, index)
146+
147+
case of_pattern_var(path, actual) do
148+
{:ok, type} ->
149+
case Of.refine_var(var, type, expr, stack, context) do
150+
{:ok, type, context} ->
151+
{var_changed? or current_type != type, context}
152+
153+
{:error, _type, context} ->
154+
throw({types, context})
155+
end
156+
157+
:error ->
158+
context = Of.incompatible_error(expr, expected, actual, stack, context)
159+
throw({types, context})
173160
end
161+
end)
162+
163+
case var_changed? do
164+
false ->
165+
{changed, context}
166+
167+
true ->
168+
case paths do
169+
# A single change, check if there are other variables in this index.
170+
[[_var, {:arg, index, _, _} | _]] ->
171+
case args do
172+
%{^index => true} -> {[index | changed], context}
173+
%{^index => false} -> {changed, context}
174+
end
175+
176+
# Several changes, we have to recompute all indexes.
177+
_ ->
178+
var_changed = Enum.map(paths, fn [_var, {:arg, index, _, _} | _] -> index end)
179+
{var_changed ++ changed, context}
180+
end
181+
end
182+
end)
174183

175-
# Several changes, we have to recompute all indexes.
176-
_ ->
177-
var_changed = Enum.map(paths, fn [_var, {:arg, index, _, _} | _] -> index end)
178-
{var_changed ++ changed, context}
179-
end
180-
end
181-
end)
184+
of_pattern_recur(types, :lists.usort(changed), vars, args, stack, context, callback)
182185

183-
of_pattern_recur(types, :lists.usort(changed), vars, args, stack, context, callback)
186+
{:error, context} ->
187+
{types, context}
184188
end
185189
end
186190

@@ -284,7 +288,8 @@ defmodule Module.Types.Pattern do
284288
end
285289

286290
def of_match_var(var, expected, expr, stack, context) when is_var(var) do
287-
Of.refine_var(var, expected, expr, stack, context)
291+
{_ok?, type, context} = Of.refine_var(var, expected, expr, stack, context)
292+
{type, context}
288293
end
289294

290295
def of_match_var(ast, expected, expr, stack, context) do
@@ -657,9 +662,6 @@ defmodule Module.Types.Pattern do
657662

658663
## Helpers
659664

660-
defp merge_failed(%{failed: false}, %{failed: false} = post), do: post
661-
defp merge_failed(_pre, post), do: %{post | failed: true}
662-
663665
def format_diagnostic({:invalid_pattern, expr, context}) do
664666
traces = collect_traces(expr, context)
665667

0 commit comments

Comments
 (0)