summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosé Valim <jose.valim@plataformatec.com.br>2019-08-09 16:11:16 +0200
committerJosé Valim <jose.valim@plataformatec.com.br>2019-08-09 16:11:16 +0200
commit99f504e9dcb47875f18dc0b9d52d05d2da47485f (patch)
tree785a0299a5287453bc8fd356c95cded95f6f149f
parent9a959eac258d3596dea5d1fcd8b895f87dbac2be (diff)
downloadelixir-99f504e9dcb47875f18dc0b9d52d05d2da47485f.tar.gz
Use read-only naming for Module operations
-rw-r--r--lib/elixir/lib/module.ex33
-rw-r--r--lib/elixir/src/elixir_code_server.erl14
-rw-r--r--lib/elixir/src/elixir_module.erl19
-rw-r--r--lib/elixir/test/elixir/module_test.exs6
4 files changed, 36 insertions, 36 deletions
diff --git a/lib/elixir/lib/module.ex b/lib/elixir/lib/module.ex
index 06895ce23..59fde20d5 100644
--- a/lib/elixir/lib/module.ex
+++ b/lib/elixir/lib/module.ex
@@ -549,11 +549,6 @@ defmodule Module do
:elixir_module.is_open(module)
end
- @spec not_closing?(module) :: boolean
- defp not_closing?(module) when is_atom(module) do
- :elixir_module.is_not_closing(module)
- end
-
@doc """
Evaluates the quoted contents in the given module's context.
@@ -612,7 +607,7 @@ defmodule Module do
def eval_quoted(module, quoted, binding, opts)
when is_atom(module) and is_list(binding) and is_list(opts) do
- assert_not_closing!(__ENV__.function, module)
+ assert_not_compiled!(__ENV__.function, module)
:elixir_def.reset_last(module)
{value, binding, _env, _scope} =
@@ -1075,7 +1070,7 @@ defmodule Module do
"""
@spec make_overridable(module, [definition]) :: :ok
def make_overridable(module, tuples) when is_atom(module) and is_list(tuples) do
- assert_not_closing!(__ENV__.function, module)
+ assert_not_readonly!(__ENV__.function, module)
func = fn
{function_name, arity} = tuple
@@ -1287,7 +1282,7 @@ defmodule Module do
"""
@spec delete_attribute(module, atom) :: term
def delete_attribute(module, key) when is_atom(module) and is_atom(key) do
- assert_not_closing!(__ENV__.function, module)
+ assert_not_readonly!(__ENV__.function, module)
{set, bag} = data_tables_for(module)
case :ets.lookup(set, key) do
@@ -1339,7 +1334,7 @@ defmodule Module do
@spec register_attribute(module, atom, [{:accumulate, boolean}, {:persist, boolean}]) :: :ok
def register_attribute(module, attribute, options)
when is_atom(module) and is_atom(attribute) and is_list(options) do
- assert_not_closing!(__ENV__.function, module)
+ assert_not_readonly!(__ENV__.function, module)
{set, bag} = data_tables_for(module)
if Keyword.get(options, :persist) do
@@ -1844,7 +1839,7 @@ defmodule Module do
# Used internally by Kernel's @.
# This function is private and must be used only internally.
def __put_attribute__(module, key, value, line) when is_atom(key) do
- assert_not_closing!(__ENV__.function, module)
+ assert_not_readonly!(__ENV__.function, module)
{set, bag} = data_tables_for(module)
value = preprocess_attribute(key, value)
put_attribute(module, key, value, line, set, bag)
@@ -2089,10 +2084,20 @@ defmodule Module do
assert_not_compiled_message(function_name_arity, module, extra_msg)
end
- defp assert_not_closing!(function_name_arity, module, extra_msg \\ "") do
- (open?(module) and not_closing?(module)) ||
- raise ArgumentError,
- assert_not_compiled_message(function_name_arity, module, extra_msg)
+ defp assert_not_readonly!({function_name, arity}, module) do
+ case :elixir_module.mode(module) do
+ :all ->
+ :ok
+
+ :readonly ->
+ raise ArgumentError,
+ "could not call Module.#{function_name}/#{arity} because the module " <>
+ "#{inspect(module)} is in read-only mode (@after_compile)"
+
+ :closed ->
+ raise ArgumentError,
+ assert_not_compiled_message({function_name, arity}, module, "")
+ end
end
defp assert_not_compiled_message({function_name, arity}, module, extra_msg) do
diff --git a/lib/elixir/src/elixir_code_server.erl b/lib/elixir/src/elixir_code_server.erl
index 46fd5ec93..96dede31f 100644
--- a/lib/elixir/src/elixir_code_server.erl
+++ b/lib/elixir/src/elixir_code_server.erl
@@ -25,7 +25,7 @@ start_link() ->
init(ok) ->
%% The table where we store module definitions
- _ = ets:new(elixir_modules, [set, protected, named_table, {read_concurrency, true}]),
+ _ = ets:new(elixir_modules, [set, public, named_table, {read_concurrency, true}]),
{ok, #elixir_code_server{}}.
handle_call({defmodule, Module, Pid, Tuple}, _From, Config) ->
@@ -40,9 +40,6 @@ handle_call({defmodule, Module, Pid, Tuple}, _From, Config) ->
handle_call({undefmodule, Ref}, _From, Config) ->
{reply, ok, undefmodule(Ref, Config)};
-handle_call({unopenmodule, Ref}, _From, Config) ->
- {reply, ok, unopenmodule(Ref, Config)};
-
handle_call({acquire, Path}, From, Config) ->
Current = Config#elixir_code_server.required,
case maps:find(Path, Current) of
@@ -158,12 +155,3 @@ undefmodule(Ref, #elixir_code_server{mod_ets=ModEts} = Config) ->
error ->
Config
end.
-
-unopenmodule(Ref, #elixir_code_server{mod_ets=ModEts} = Config) ->
- case maps:find(Ref, ModEts) of
- {ok, Mod} ->
- ets:update_element(elixir_modules, Mod, {5, false}),
- Config;
- error ->
- Config
- end.
diff --git a/lib/elixir/src/elixir_module.erl b/lib/elixir/src/elixir_module.erl
index 494ff944a..8286a3552 100644
--- a/lib/elixir/src/elixir_module.erl
+++ b/lib/elixir/src/elixir_module.erl
@@ -1,5 +1,5 @@
-module(elixir_module).
--export([file/1, data_tables/1, is_open/1, is_not_closing/1, delete_definition_attributes/6,
+-export([file/1, data_tables/1, is_open/1, mode/1, delete_definition_attributes/6,
compile/4, expand_callback/6, format_error/1, compiler_modules/0,
write_cache/3, read_cache/2, next_counter/1]).
-include("elixir.hrl").
@@ -29,8 +29,15 @@ data_tables(Module) ->
is_open(Module) ->
ets:member(elixir_modules, Module).
-is_not_closing(Module) ->
- ets:lookup_element(elixir_modules, Module, 5).
+mode(Module) ->
+ try ets:lookup_element(elixir_modules, Module, 5) of
+ Mode -> Mode
+ catch
+ _:badarg -> closed
+ end.
+
+make_readonly(Module) ->
+ ets:update_element(elixir_modules, Module, {5, readonly}).
delete_definition_attributes(#{module := Module}, _, _, _, _, _) ->
{DataSet, _} = data_tables(Module),
@@ -99,6 +106,7 @@ compile(Line, Module, Block, Vars, E) ->
%% We stop tracking locals here to avoid race conditions in case after_load
%% evaluates code in a separate process that may write to locals table.
elixir_locals:stop({DataSet, DataBag}),
+ make_readonly(Module),
(not elixir_config:get(bootstrap)) andalso
'Elixir.Module':check_behaviours_and_impls(E, DataSet, DataBag, AllDefinitions),
@@ -122,11 +130,10 @@ compile(Line, Module, Block, Vars, E) ->
},
Binary = elixir_erl:compile(ModuleMap),
- elixir_code_server:call({unopenmodule, Ref}),
warn_unused_attributes(File, DataSet, DataBag, PersistedAttributes),
autoload_module(Module, Binary, CompileOpts, NE),
- make_module_available(Module, Binary, ModuleMap),
eval_callbacks(Line, DataBag, after_compile, [NE, Binary], NE),
+ make_module_available(Module, Binary, ModuleMap),
{module, Module, Binary, Result}
catch
?WITH_STACKTRACE(error, undef, Stacktrace)
@@ -294,7 +301,7 @@ build(Line, File, Module) ->
Tables = {DataSet, DataBag},
elixir_def:setup(Tables),
elixir_locals:setup(Tables),
- Tuple = {Module, Tables, Line, File, true},
+ Tuple = {Module, Tables, Line, File, all},
Ref =
case elixir_code_server:call({defmodule, Module, self(), Tuple}) of
diff --git a/lib/elixir/test/elixir/module_test.exs b/lib/elixir/test/elixir/module_test.exs
index d3f8aac64..5346750f0 100644
--- a/lib/elixir/test/elixir/module_test.exs
+++ b/lib/elixir/test/elixir/module_test.exs
@@ -77,7 +77,7 @@ defmodule ModuleTest do
end
end
- test "module raises on write access attempts from __after_compile__/2" do
+ test "raises on write access attempts from __after_compile__/2" do
contents =
quote do
@after_compile __MODULE__
@@ -88,13 +88,13 @@ defmodule ModuleTest do
end
assert_raise ArgumentError,
- "could not call Module.__put_attribute__/4 because the module ModuleTest.Raise is already compiled",
+ "could not call Module.__put_attribute__/4 because the module ModuleTest.Raise is in read-only mode (@after_compile)",
fn ->
Module.create(ModuleTest.Raise, contents, __ENV__)
end
end
- test "module supports read access to module from __after_compile__/2" do
+ test "supports read access to module from __after_compile__/2" do
contents =
quote do
@after_compile __MODULE__