Skip to content

Commit 00b1aad

Browse files
author
José Valim
committed
Add a __struct__ field on defstruct and ensure proper message on struct body access
1 parent c1fedcc commit 00b1aad

File tree

5 files changed

+29
-7
lines changed

5 files changed

+29
-7
lines changed

lib/elixir/lib/inspect.ex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -555,10 +555,10 @@ defimpl Inspect, for: Any do
555555
rescue
556556
_ -> Inspect.Map.inspect(map, opts)
557557
else
558-
inner ->
559-
outer = :maps.remove(:__struct__, map)
560-
if :maps.keys(inner) == :maps.keys(outer) do
561-
Inspect.Map.inspect(outer, Inspect.Atom.inspect(struct, opts), opts)
558+
dunder ->
559+
if :maps.keys(dunder) == :maps.keys(map) do
560+
Inspect.Map.inspect(:maps.remove(:__struct__, map),
561+
Inspect.Atom.inspect(struct, opts), opts)
562562
else
563563
Inspect.Map.inspect(map, opts)
564564
end

lib/elixir/lib/kernel.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3201,7 +3201,7 @@ defmodule Kernel do
32013201
end)
32023202

32033203
def __struct__() do
3204-
%{ unquote_splicing(opts) }
3204+
%{ unquote_splicing(opts), __struct__: __MODULE__ }
32053205
end
32063206
end
32073207
end

lib/elixir/src/elixir_map.erl

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,17 @@ expand_struct(Meta, Left, Right, E) ->
2323
EMeta =
2424
case lists:member(ELeft, E#elixir_env.context_modules) andalso
2525
elixir_module:is_open(ELeft) of
26-
true -> [{ struct, context }|Meta];
26+
true ->
27+
case (ELeft == E#elixir_env.module) and
28+
(E#elixir_env.function == nil) of
29+
true ->
30+
compile_error(Meta, E#elixir_env.file,
31+
"cannot access struct ~ts in body of the module that defines it as "
32+
"the struct fields are not yet accessible",
33+
[elixir_aliases:inspect(ELeft)]);
34+
false ->
35+
[{ struct, context }|Meta]
36+
end;
2737
false -> elixir_aliases:ensure_loaded(Meta, ELeft, E), Meta
2838
end,
2939

lib/elixir/test/elixir/inspect_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ defmodule Inspect.MapTest do
266266

267267
defmodule Public do
268268
def __struct__ do
269-
%{key: 0}
269+
%{key: 0, __struct__: Public}
270270
end
271271
end
272272

lib/elixir/test/elixir/kernel/errors_test.exs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,18 @@ defmodule Kernel.ErrorsTest do
195195
'%{ :a, :b }{ a: :b }'
196196
end
197197

198+
test :struct_access_on_body do
199+
assert_compile_fail CompileError,
200+
"nofile:3: cannot access struct TZ in body of the module that defines it " <>
201+
"as the struct fields are not yet accessible",
202+
'''
203+
defmodule TZ do
204+
defstruct %{name: "Brasilia"}
205+
%TZ{}
206+
end
207+
'''
208+
end
209+
198210
test :unbound_map_key_var do
199211
assert_compile_fail CompileError,
200212
"nofile:1: cannot bind variable x in map key",

0 commit comments

Comments
 (0)