Skip to content

Commit

Permalink
More progress
Browse files Browse the repository at this point in the history
  • Loading branch information
josevalim committed Oct 15, 2024
1 parent b0d8be2 commit dfaf7ca
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 19 deletions.
57 changes: 39 additions & 18 deletions lib/elixir/lib/module/types/pattern.ex
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ defmodule Module.Types.Pattern do
{:ok, type}
end

defp of_pattern_var([:__struct__ | rest], type) do
case map_fetch(type, :__struct__) do
{_optional?, type} -> of_pattern_var(rest, intersection(type, atom()))
_reason -> :error
end
end

defp of_pattern_var([{:key, field} | rest], type) when is_atom(field) do
case map_fetch(type, field) do
{_optional?, type} -> of_pattern_var(rest, type)
Expand All @@ -153,7 +160,7 @@ defmodule Module.Types.Pattern do

defp of_pattern_tree({:closed_map, static, dynamic}, context) do
dynamic = Enum.map(dynamic, fn {key, value} -> {key, of_pattern_tree(value, context)} end)
open_map(static ++ dynamic)
closed_map(static ++ dynamic)
end

defp of_pattern_tree({:intersection, entries}, context) do
Expand Down Expand Up @@ -199,6 +206,7 @@ defmodule Module.Types.Pattern do
# TODO: Simplify signature of Of.refine_var
# TODO: Simplify signature of Of.intersect
# TODO: Remove expr from of_pattern
# TODO: Remove prepend_path

# :atom
defp of_pattern(atom, _expected_expr, _stack, context) when is_atom(atom),
Expand Down Expand Up @@ -234,7 +242,6 @@ defmodule Module.Types.Pattern do
end

# left = right
# TODO: Track variables and handle nesting
defp of_pattern({:=, _meta, [_, _]} = match, {path, expr}, stack, context) do
match
|> unpack_match([])
Expand Down Expand Up @@ -262,19 +269,6 @@ defmodule Module.Types.Pattern do
end
end

# %var{...} and %^var{...}
defp of_pattern(
{:%, _meta, [struct_var, {:%{}, _meta2, args}]} = expr,
expected_expr,
stack,
context
)
when not is_atom(struct_var) do
with {:ok, _, context} <- of_match_var(struct_var, {atom(), expr}, stack, context) do
of_open_map([__struct__: struct_var] ++ args, expected_expr, stack, context)
end
end

# %Struct{...}
# TODO: Once we support typed structs, we need to type check them here.
defp of_pattern({:%, meta, [struct, {:%{}, _, args}]}, {path, expr}, stack, context)
Expand Down Expand Up @@ -318,9 +312,36 @@ defmodule Module.Types.Pattern do
end
end

# %var{...}
defp of_pattern(
{:%, _meta, [{name, _, ctx} = var, {:%{}, _meta2, args}]} = expr,
{path, _expr},
stack,
context
)
when is_atom(name) and is_atom(ctx) and name != :_ do
var_path = prepend_path(:__struct__, path)

with {:ok, var, context} <- of_pattern(var, {var_path, expr}, stack, context) do
of_open_map(args, [], [__struct__: var], {path, expr}, stack, context)
end
end

# %^var{...} and %_{...}
defp of_pattern(
{:%, _meta, [var, {:%{}, _meta2, args}]} = expr,
expected_expr,
stack,
context
) do
with {:ok, refined, context} <- of_match_var(var, {atom(), expr}, stack, context) do
of_open_map(args, [__struct__: refined], [], expected_expr, stack, context)
end
end

# %{...}
defp of_pattern({:%{}, _meta, args}, expected_expr, stack, context) do
of_open_map(args, expected_expr, stack, context)
of_open_map(args, [], [], expected_expr, stack, context)
end

# <<...>>>
Expand Down Expand Up @@ -403,9 +424,9 @@ defmodule Module.Types.Pattern do

# TODO: Properly traverse domain keys
# TODO: Properly handle pin operator in keys
defp of_open_map(args, {expected, expr}, stack, context) do
defp of_open_map(args, static, dynamic, {expected, expr}, stack, context) do
result =
reduce_ok(args, {[], [], context}, fn {key, value}, {static, dynamic, context} ->
reduce_ok(args, {static, dynamic, context}, fn {key, value}, {static, dynamic, context} ->
expected = prepend_path({:key, key}, expected)

with {:ok, value_type, context} <- of_pattern(value, {expected, expr}, stack, context) do
Expand Down
2 changes: 1 addition & 1 deletion lib/elixir/test/elixir/module/types/pattern_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ defmodule Module.Types.PatternTest do
assert typecheck!([x = %_{}], x) == dynamic(open_map(__struct__: atom()))

assert typecheck!([x = %m{}, m = Point], x) ==
dynamic(open_map(__struct__: atom()))
dynamic(open_map(__struct__: atom([Point])))

assert typecheck!([m = Point, x = %m{}], x) ==
dynamic(open_map(__struct__: atom([Point])))
Expand Down

0 comments on commit dfaf7ca

Please sign in to comment.