From 4da44bb6ff81caeff7a6c186f1befdce20d82316 Mon Sep 17 00:00:00 2001 From: Alex Gubarev Date: Tue, 14 Jul 2026 16:38:29 +0300 Subject: [PATCH 1/2] Fix Map.from_struct/1 typecheck --- lib/elixir/lib/module/types/apply.ex | 23 ++++++++++++++----- .../test/elixir/module/types/map_test.exs | 12 +++++----- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/lib/elixir/lib/module/types/apply.ex b/lib/elixir/lib/module/types/apply.ex index 9dffd1e28f9..42203248d80 100644 --- a/lib/elixir/lib/module/types/apply.ex +++ b/lib/elixir/lib/module/types/apply.ex @@ -254,7 +254,7 @@ defmodule Module.Types.Apply do {Map, :fetch, [{[open_map(), term()], tuple([atom([:ok]), term()]) |> opt_union(atom([:error]))}]}, {Map, :fetch!, [{[open_map(), term()], term()}]}, - {Map, :from_struct, [{[open_map()], open_map(__struct__: not_set())}]}, + {Map, :from_struct, [{[open_map(__struct__: atom())], open_map(__struct__: not_set())}]}, {Map, :get, [{[open_map(), term()], term()}]}, {Map, :get, [{[open_map(), term(), term()], term()}]}, {Map, :get_lazy, [{[open_map(), term(), fun(0)], term()}]}, @@ -1129,11 +1129,22 @@ defmodule Module.Types.Apply do @struct_key atom([:__struct__]) @nil_atom atom([nil]) - defp remote_apply(Map, :from_struct, _info, [map] = args_types, stack) do - case map_update(map, @struct_key, not_set(), false, true) do - {_value, descr, _errors} -> {:ok, return(descr, args_types, stack)} - :badmap -> {:error, badremote(Map, :from_struct, args_types)} - {:error, _errors} -> {:ok, map} + defp remote_apply(Map, :from_struct, info, [map] = args_types, stack) do + case remote_apply(info, args_types, stack) do + {:ok, _type} -> + case map_update(map, @struct_key, not_set(), false, true) do + {_value, descr, _errors} -> + {:ok, return(descr, args_types, stack)} + + :badmap -> + {:error, badremote(Map, :from_struct, args_types)} + + {:error, _errors} -> + {:error, badremote(Map, :from_struct, args_types)} + end + + other -> + other end end diff --git a/lib/elixir/test/elixir/module/types/map_test.exs b/lib/elixir/test/elixir/module/types/map_test.exs index e0cc57c24c9..24b0df12d74 100644 --- a/lib/elixir/test/elixir/module/types/map_test.exs +++ b/lib/elixir/test/elixir/module/types/map_test.exs @@ -330,11 +330,8 @@ defmodule Module.Types.MapTest do describe "Map.from_struct/1" do test "checking" do - assert typecheck!(Map.from_struct(%{})) == - empty_map() - - assert typecheck!(Map.from_struct(%{key: 123})) == - closed_map(key: integer()) + assert typecheck!(Map.from_struct(%{__struct__: URI, port: 433})) == + closed_map(port: integer()) assert typecheck!(Map.from_struct(%URI{})) == closed_map( @@ -359,12 +356,15 @@ defmodule Module.Types.MapTest do _ = Map.from_struct(x) x ) - ) == dynamic(open_map()) + ) == dynamic(open_map(__struct__: atom())) end test "errors" do assert typeerror!([x = []], Map.from_struct(x)) =~ "incompatible types given to Map.from_struct/1" + + assert typeerror!(Map.from_struct(%{})) =~ + "incompatible types given to Map.from_struct/1" end end From d61719bf8e824892ca1cbccab5c21bf5ff571f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 14 Jul 2026 16:38:31 +0200 Subject: [PATCH 2/2] Apply suggestion from @josevalim --- lib/elixir/lib/module/types/apply.ex | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/elixir/lib/module/types/apply.ex b/lib/elixir/lib/module/types/apply.ex index 42203248d80..c6a18b93cf3 100644 --- a/lib/elixir/lib/module/types/apply.ex +++ b/lib/elixir/lib/module/types/apply.ex @@ -1136,10 +1136,7 @@ defmodule Module.Types.Apply do {_value, descr, _errors} -> {:ok, return(descr, args_types, stack)} - :badmap -> - {:error, badremote(Map, :from_struct, args_types)} - - {:error, _errors} -> + _ -> {:error, badremote(Map, :from_struct, args_types)} end