diff options
author | José Valim <jose.valim@plataformatec.com.br> | 2019-08-09 16:11:16 +0200 |
---|---|---|
committer | José Valim <jose.valim@plataformatec.com.br> | 2019-08-09 16:11:16 +0200 |
commit | 99f504e9dcb47875f18dc0b9d52d05d2da47485f (patch) | |
tree | 785a0299a5287453bc8fd356c95cded95f6f149f | |
parent | 9a959eac258d3596dea5d1fcd8b895f87dbac2be (diff) | |
download | elixir-99f504e9dcb47875f18dc0b9d52d05d2da47485f.tar.gz |
Use read-only naming for Module operations
-rw-r--r-- | lib/elixir/lib/module.ex | 33 | ||||
-rw-r--r-- | lib/elixir/src/elixir_code_server.erl | 14 | ||||
-rw-r--r-- | lib/elixir/src/elixir_module.erl | 19 | ||||
-rw-r--r-- | lib/elixir/test/elixir/module_test.exs | 6 |
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__ |