diff --git a/lib/elixir/lib/module/types/of.ex b/lib/elixir/lib/module/types/of.ex index ed1de24a809..44599256cf0 100644 --- a/lib/elixir/lib/module/types/of.ex +++ b/lib/elixir/lib/module/types/of.ex @@ -291,7 +291,11 @@ defmodule Module.Types.Of do # so we need to deal with such cases accordingly. # TODO: Assume implementation is available on Elixir v2.0. # A warning is emitted since v1.19+. - if info = mode == :closed && Code.ensure_loaded?(struct) && struct.__info__(:struct) do + info = + mode == :closed and Code.ensure_loaded?(struct) and + function_exported?(struct, :__info__, 1) and struct.__info__(:struct) + + if info do struct_type(struct, info) else open_map(__struct__: {atom([struct]), false}) diff --git a/lib/elixir/test/elixir/module/types/integration_test.exs b/lib/elixir/test/elixir/module/types/integration_test.exs index a9cca324daa..8da5403accb 100644 --- a/lib/elixir/test/elixir/module/types/integration_test.exs +++ b/lib/elixir/test/elixir/module/types/integration_test.exs @@ -163,6 +163,31 @@ defmodule Module.Types.IntegrationTest do dynamic(open_map(__struct__: {atom([Unknown]), false})) end + test "writes exports for implementations of Erlang modules" do + files = %{ + "pe.ex" => """ + defprotocol Erl do + def erl(data) + end + + defimpl Erl, for: :gen_server do + def erl(data), do: data + end + """ + } + + modules = compile_modules(files) + + {_, %{sig: {:infer, nil, [{[domain], _return}]}}} = + List.keyfind( + read_chunk(modules[Module.concat(Erl, :gen_server)]).exports, + {:erl, 1}, + 0 + ) + + assert domain == open_map(__struct__: {atom([:gen_server]), false}) + end + test "ignores additional callbacks on implementations" do files = %{ "p.ex" => """