1-module(elixir_module).
2-export([file/1, data_tables/1, is_open/1, mode/1, delete_definition_attributes/6,
3         compile/4, expand_callback/6, format_error/1, compiler_modules/0,
4         write_cache/3, read_cache/2, next_counter/1]).
5-include("elixir.hrl").
6-define(counter_attr, {elixir, counter}).
7
8%% Stores modules currently being defined by the compiler
9
10compiler_modules() ->
11  case erlang:get(elixir_compiler_modules) of
12    undefined -> [];
13    M when is_list(M) -> M
14  end.
15
16put_compiler_modules([]) ->
17  erlang:erase(elixir_compiler_modules);
18put_compiler_modules(M) when is_list(M) ->
19  erlang:put(elixir_compiler_modules, M).
20
21%% Table functions
22
23file(Module) ->
24  ets:lookup_element(elixir_modules, Module, 4).
25
26data_tables(Module) ->
27  ets:lookup_element(elixir_modules, Module, 2).
28
29is_open(Module) ->
30  ets:member(elixir_modules, Module).
31
32mode(Module) ->
33  try ets:lookup_element(elixir_modules, Module, 5) of
34    Mode -> Mode
35  catch
36    _:badarg -> closed
37  end.
38
39make_readonly(Module) ->
40  ets:update_element(elixir_modules, Module, {5, readonly}).
41
42delete_definition_attributes(#{module := Module}, _, _, _, _, _) ->
43  {DataSet, _} = data_tables(Module),
44  ets:delete(DataSet, doc),
45  ets:delete(DataSet, deprecated),
46  ets:delete(DataSet, impl).
47
48write_cache(Module, Key, Value) ->
49  {DataSet, _} = data_tables(Module),
50  ets:insert(DataSet, {{cache, Key}, Value}).
51
52read_cache(Module, Key) ->
53  {DataSet, _} = data_tables(Module),
54  ets:lookup_element(DataSet, {cache, Key}, 2).
55
56next_counter(nil) -> erlang:unique_integer();
57next_counter(Module) ->
58  try
59    {DataSet, _} = data_tables(Module),
60    {Module, ets:update_counter(DataSet, ?counter_attr, 1)}
61  catch
62    _:_ -> erlang:unique_integer()
63  end.
64
65%% Compilation hook
66
67compile(Module, _Block, _Vars, #{line := Line, file := File}) when Module == nil; is_boolean(Module) ->
68  elixir_errors:form_error([{line, Line}], File, ?MODULE, {invalid_module, Module});
69compile(Module, Block, Vars, Env) when is_atom(Module) ->
70  #{line := Line, current_vars := {Read, _}, function := Function} = Env,
71
72  %% In case we are generating a module from inside a function,
73  %% we get rid of the lexical tracker information as, at this
74  %% point, the lexical tracker process is long gone.
75  ResetEnv = elixir_env:reset_unused_vars(Env),
76
77  MaybeLexEnv =
78    case Function of
79      nil -> ResetEnv#{module := Module, current_vars := {Read, false}};
80      _   -> ResetEnv#{lexical_tracker := nil, tracers := [], function := nil, module := Module, current_vars := {Read, false}}
81    end,
82
83  case MaybeLexEnv of
84    #{lexical_tracker := nil} ->
85      elixir_lexical:run(
86        MaybeLexEnv,
87        fun(LexEnv) -> compile(Line, Module, Block, Vars, LexEnv) end,
88        fun(_LexEnv) -> ok end
89      );
90    _ ->
91      compile(Line, Module, Block, Vars, MaybeLexEnv)
92  end;
93compile(Module, _Block, _Vars, #{line := Line, file := File}) ->
94  elixir_errors:form_error([{line, Line}], File, ?MODULE, {invalid_module, Module}).
95
96compile(Line, Module, Block, Vars, E) ->
97  File = ?key(E, file),
98  check_module_availability(Line, File, Module),
99
100  CompilerModules = compiler_modules(),
101  {Tables, Ref} = build(Line, File, Module),
102  {DataSet, DataBag} = Tables,
103
104  try
105    put_compiler_modules([Module | CompilerModules]),
106    elixir_env:trace({defmodule, [{line, Line}]}, E),
107    {Result, NE} = eval_form(Line, Module, DataBag, Block, Vars, E),
108
109    PersistedAttributes = ets:lookup_element(DataBag, persisted_attributes, 2),
110    Attributes = attributes(DataSet, DataBag, PersistedAttributes),
111    {AllDefinitions, Private} = elixir_def:fetch_definitions(File, Module),
112
113    OnLoadAttribute = lists:keyfind(on_load, 1, Attributes),
114    NewPrivate = validate_on_load_attribute(OnLoadAttribute, AllDefinitions, Private, File, Line),
115
116    DialyzerAttribute = lists:keyfind(dialyzer, 1, Attributes),
117    validate_dialyzer_attribute(DialyzerAttribute, AllDefinitions, File, Line),
118
119    Unreachable = elixir_locals:warn_unused_local(File, Module, AllDefinitions, NewPrivate),
120    elixir_locals:ensure_no_undefined_local(File, Module, AllDefinitions),
121    elixir_locals:ensure_no_import_conflict(File, Module, AllDefinitions),
122
123    %% We stop tracking locals here to avoid race conditions in case after_load
124    %% evaluates code in a separate process that may write to locals table.
125    elixir_locals:stop({DataSet, DataBag}),
126    make_readonly(Module),
127
128    (not elixir_config:get(bootstrap)) andalso
129     'Elixir.Module':check_behaviours_and_impls(E, DataSet, DataBag, AllDefinitions),
130
131    RawCompileOpts = bag_lookup_element(DataBag, {accumulate, compile}, 2),
132    CompileOpts = validate_compile_opts(RawCompileOpts, AllDefinitions, Unreachable, File, Line),
133
134    ModuleMap = #{
135      struct => get_struct(DataSet),
136      module => Module,
137      line => Line,
138      file => File,
139      relative_file => elixir_utils:relative_to_cwd(File),
140      attributes => Attributes,
141      definitions => AllDefinitions,
142      unreachable => Unreachable,
143      compile_opts => CompileOpts,
144      deprecated => get_deprecated(DataBag),
145      is_behaviour => is_behaviour(DataBag)
146    },
147
148    Binary = elixir_erl:compile(ModuleMap),
149    autoload_module(Module, Binary, CompileOpts, NE),
150    eval_callbacks(Line, DataBag, after_compile, [NE, Binary], NE),
151    warn_unused_attributes(File, DataSet, DataBag, PersistedAttributes),
152    make_module_available(Module, Binary, ModuleMap),
153    {module, Module, Binary, Result}
154  catch
155    error:undef:Stacktrace ->
156      case Stacktrace of
157        [{Module, Fun, Args, _Info} | _] = Stack when is_list(Args) ->
158          compile_undef(Module, Fun, length(Args), Stack);
159        [{Module, Fun, Arity, _Info} | _] = Stack ->
160          compile_undef(Module, Fun, Arity, Stack);
161        Stack ->
162          erlang:raise(error, undef, Stack)
163      end
164  after
165    put_compiler_modules(CompilerModules),
166    ets:delete(DataSet),
167    ets:delete(DataBag),
168    elixir_code_server:call({undefmodule, Ref})
169  end.
170
171validate_compile_opts(Opts, Defs, Unreachable, File, Line) ->
172  lists:flatmap(fun (Opt) -> validate_compile_opt(Opt, Defs, Unreachable, File, Line) end, Opts).
173
174%% TODO: Make this an error on v2.0
175validate_compile_opt({parse_transform, Module} = Opt, _Defs, _Unreachable, File, Line) ->
176  elixir_errors:form_warn([{line, Line}], File, ?MODULE, {parse_transform, Module}),
177  [Opt];
178validate_compile_opt({inline, Inlines}, Defs, Unreachable, File, Line) ->
179  case validate_inlines(Inlines, Defs, Unreachable, []) of
180    {ok, []} -> [];
181    {ok, FilteredInlines} -> [{inline, FilteredInlines}];
182    {error, Def} -> elixir_errors:form_error([{line, Line}], File, ?MODULE, {bad_inline, Def})
183  end;
184validate_compile_opt(Opt, Defs, Unreachable, File, Line) when is_list(Opt) ->
185  validate_compile_opts(Opt, Defs, Unreachable, File, Line);
186validate_compile_opt(Opt, _Defs, _Unreachable, _File, _Line) ->
187  [Opt].
188
189validate_inlines([Inline | Inlines], Defs, Unreachable, Acc) ->
190  case lists:keyfind(Inline, 1, Defs) of
191    false -> {error, Inline};
192    _ ->
193      case lists:member(Inline, Unreachable) of
194        true -> validate_inlines(Inlines, Defs, Unreachable, Acc);
195        false -> validate_inlines(Inlines, Defs, Unreachable, [Inline | Acc])
196      end
197  end;
198validate_inlines([], _Defs, _Unreachable, Acc) -> {ok, Acc}.
199
200validate_on_load_attribute({on_load, Def}, Defs, Private, File, Line) ->
201  case lists:keyfind(Def, 1, Defs) of
202    false ->
203      elixir_errors:form_error([{line, Line}], File, ?MODULE, {undefined_on_load, Def});
204    {_, Kind, _, _} when Kind == def; Kind == defp ->
205      lists:keydelete(Def, 1, Private);
206    {_, WrongKind, _, _} ->
207      elixir_errors:form_error([{line, Line}], File, ?MODULE, {wrong_kind_on_load, Def, WrongKind})
208  end;
209validate_on_load_attribute(false, _Module, Private, _File, _Line) -> Private.
210
211validate_dialyzer_attribute({dialyzer, Dialyzer}, Defs, File, Line) ->
212  [case lists:keyfind(Fun, 1, Defs) of
213    false ->
214      elixir_errors:form_error([{line, Line}], File, ?MODULE, {bad_dialyzer, Key, Fun});
215    _ ->
216      ok
217   end || {Key, Funs} <- lists:flatten([Dialyzer]), Fun <- lists:flatten([Funs])];
218validate_dialyzer_attribute(false, _Defs, _File, _Line) ->
219  ok.
220
221is_behaviour(DataBag) ->
222  ets:member(DataBag, {accumulate, callback}) orelse ets:member(DataBag, {accumulate, macrocallback}).
223
224%% An undef error for a function in the module being compiled might result in an
225%% exception message suggesting the current module is not loaded. This is
226%% misleading so use a custom reason.
227compile_undef(Module, Fun, Arity, Stack) ->
228  case elixir_config:get(bootstrap) of
229    false ->
230      Opts = [{module, Module}, {function, Fun}, {arity, Arity},
231              {reason, 'function not available'}],
232      Exception = 'Elixir.UndefinedFunctionError':exception(Opts),
233      erlang:raise(error, Exception, Stack);
234    true ->
235      erlang:raise(error, undef, Stack)
236  end.
237
238%% Handle reserved modules and duplicates.
239
240check_module_availability(Line, File, Module) ->
241  Reserved = ['Elixir.Any', 'Elixir.BitString', 'Elixir.PID',
242              'Elixir.Reference', 'Elixir.Elixir', 'Elixir'],
243
244  case lists:member(Module, Reserved) of
245    true  -> elixir_errors:form_error([{line, Line}], File, ?MODULE, {module_reserved, Module});
246    false -> ok
247  end,
248
249  case elixir_config:get(ignore_module_conflict) of
250    false ->
251      case code:ensure_loaded(Module) of
252        {module, _} ->
253          elixir_errors:form_warn([{line, Line}], File, ?MODULE, {module_defined, Module});
254        {error, _}  ->
255          ok
256      end;
257    true ->
258      ok
259  end.
260
261%% Hook that builds both attribute and functions and set up common hooks.
262
263build(Line, File, Module) ->
264  %% In the set table we store:
265  %%
266  %% * {Attribute, Value, AccumulateOrReadOrUnreadline}
267  %% * {{elixir, ...}, ...}
268  %% * {{cache, ...}, ...}
269  %% * {{function, Tuple}, ...}, {{macro, Tuple}, ...}
270  %% * {{type, Tuple}, ...}, {{opaque, Tuple}, ...}
271  %% * {{callback, Tuple}, ...}, {{macrocallback, Tuple}, ...}
272  %% * {{def, Tuple}, ...} (from elixir_def)
273  %% * {{import, Tuple}, ...} (from elixir_locals)
274  %% * {{overridable, Tuple}, ...} (from elixir_overridable)
275  %%
276  DataSet = ets:new(Module, [set, public]),
277
278  %% In the bag table we store:
279  %%
280  %% * {{accumulate, Attribute}, ...} (includes typespecs)
281  %% * {warn_attributes, ...}
282  %% * {impls, ...}
283  %% * {deprecated, ...}
284  %% * {persisted_attributes, ...}
285  %% * {defs, ...} (from elixir_def)
286  %% * {overridables, ...} (from elixir_overridable)
287  %% * {{default, Name}, ...} (from elixir_def)
288  %% * {{clauses, Tuple}, ...} (from elixir_def)
289  %% * {reattach, ...} (from elixir_locals)
290  %% * {{local, Tuple}, ...} (from elixir_locals)
291  %%
292  DataBag = ets:new(Module, [duplicate_bag, public]),
293
294  ets:insert(DataSet, [
295    % {Key, Value, ReadOrUnreadLine}
296    {moduledoc, nil, nil},
297
298    % {Key, Value, accumulate}
299    {after_compile, [], accumulate},
300    {before_compile, [], accumulate},
301    {behaviour, [], accumulate},
302    {compile, [], accumulate},
303    {derive, [], accumulate},
304    {dialyzer, [], accumulate},
305    {external_resource, [], accumulate},
306    {on_definition, [], accumulate},
307    {type, [], accumulate},
308    {opaque, [], accumulate},
309    {typep, [], accumulate},
310    {spec, [], accumulate},
311    {callback, [], accumulate},
312    {macrocallback, [], accumulate},
313    {optional_callbacks, [], accumulate},
314
315    % Others
316    {?counter_attr, 0}
317  ]),
318
319  Persisted = [behaviour, on_load, external_resource, dialyzer, vsn],
320  ets:insert(DataBag, [{persisted_attributes, Attr} || Attr <- Persisted]),
321
322  OnDefinition =
323    case elixir_config:get(bootstrap) of
324      false -> {'Elixir.Module', compile_definition_attributes};
325      _ -> {elixir_module, delete_definition_attributes}
326    end,
327  ets:insert(DataBag, {{accumulate, on_definition}, OnDefinition}),
328
329  %% Setup definition related modules
330  Tables = {DataSet, DataBag},
331  elixir_def:setup(Tables),
332  elixir_locals:setup(Tables),
333  Tuple = {Module, Tables, Line, File, all},
334
335  Ref =
336    case elixir_code_server:call({defmodule, Module, self(), Tuple}) of
337      {ok, ModuleRef} ->
338        ModuleRef;
339      {error, {Module, _, OldLine, OldFile, _}} ->
340        ets:delete(DataSet),
341        ets:delete(DataBag),
342        Error = {module_in_definition, Module, OldFile, OldLine},
343        elixir_errors:form_error([{line, Line}], File, ?MODULE, Error)
344    end,
345
346  {Tables, Ref}.
347
348%% Handles module and callback evaluations.
349
350eval_form(Line, Module, DataBag, Block, Vars, E) ->
351  {Value, EE} = elixir_compiler:eval_forms(Block, Vars, E),
352  elixir_overridable:store_not_overridden(Module),
353  EV = elixir_env:linify({Line, elixir_env:reset_vars(EE)}),
354  EC = eval_callbacks(Line, DataBag, before_compile, [EV], EV),
355  elixir_overridable:store_not_overridden(Module),
356  {Value, EC}.
357
358eval_callbacks(Line, DataBag, Name, Args, E) ->
359  Callbacks = bag_lookup_element(DataBag, {accumulate, Name}, 2),
360  lists:foldl(fun({M, F}, Acc) ->
361    expand_callback(Line, M, F, Args, elixir_env:reset_vars(Acc),
362                    fun(AM, AF, AA) -> apply(AM, AF, AA) end)
363  end, E, Callbacks).
364
365expand_callback(Line, M, F, Args, E, Fun) ->
366  Meta = [{line, Line}, {required, true}],
367
368  {EE, ET} = elixir_dispatch:dispatch_require(Meta, M, F, Args, E, fun(AM, AF, AA) ->
369    Fun(AM, AF, AA),
370    {ok, E}
371  end),
372
373  if
374    is_atom(EE) ->
375      ET;
376    true ->
377      try
378        {_Value, _Binding, EF} = elixir:eval_forms(EE, [], ET),
379        EF
380      catch
381        Kind:Reason:Stacktrace ->
382          Info = {M, F, length(Args), location(Line, E)},
383          erlang:raise(Kind, Reason, prune_stacktrace(Info, Stacktrace))
384      end
385  end.
386
387%% Add attributes handling to the form
388
389attributes(DataSet, DataBag, PersistedAttributes) ->
390  [{Key, Value} || Key <- PersistedAttributes, Value <- lookup_attribute(DataSet, DataBag, Key)].
391
392lookup_attribute(DataSet, DataBag, Key) when is_atom(Key) ->
393  case ets:lookup(DataSet, Key) of
394    [{_, _, accumulate}] -> bag_lookup_element(DataBag, {accumulate, Key}, 2);
395    [{_, _, unset}] -> [];
396    [{_, Value, _}] -> [Value];
397    [] -> []
398  end.
399
400warn_unused_attributes(File, DataSet, DataBag, PersistedAttrs) ->
401  StoredAttrs = bag_lookup_element(DataBag, warn_attributes, 2),
402  %% This is the same list as in Module.put_attribute
403  %% without moduledoc which are never warned on.
404  Attrs = [doc, typedoc, impl, deprecated | StoredAttrs -- PersistedAttrs],
405  Query = [{{Attr, '_', '$1'}, [{is_integer, '$1'}], [[Attr, '$1']]} || Attr <- Attrs],
406  [elixir_errors:form_warn([{line, Line}], File, ?MODULE, {unused_attribute, Key})
407   || [Key, Line] <- ets:select(DataSet, Query)].
408
409get_struct(Set) ->
410  case ets:lookup(Set, '__struct__') of
411    [] -> nil;
412    [{_, Struct, _}] ->
413      case ets:lookup(Set, enforce_keys) of
414        [] -> {Struct, []};
415        [{_, EnforceKeys, _}] when is_list(EnforceKeys) -> {Struct, EnforceKeys};
416        [{_, EnforceKeys, _}] -> {Struct, [EnforceKeys]}
417      end
418  end.
419
420get_deprecated(Bag) ->
421  lists:usort(bag_lookup_element(Bag, deprecated, 2)).
422
423bag_lookup_element(Table, Name, Pos) ->
424  try
425    ets:lookup_element(Table, Name, Pos)
426  catch
427    error:badarg -> []
428  end.
429
430%% Takes care of autoloading the module if configured.
431
432autoload_module(Module, Binary, Opts, E) ->
433  case proplists:get_value(autoload, Opts, true) of
434    true  -> code:load_binary(Module, beam_location(E), Binary);
435    false -> ok
436  end.
437
438beam_location(#{module := Module}) ->
439  case get(elixir_compiler_dest) of
440    Dest when is_binary(Dest) ->
441      filename:join(elixir_utils:characters_to_list(Dest), atom_to_list(Module) ++ ".beam");
442    _ ->
443      ""
444  end.
445
446%% Integration with elixir_compiler that makes the module available
447
448make_module_available(Module, Binary, ModuleMap) ->
449  case get(elixir_module_binaries) of
450    Current when is_list(Current) ->
451      put(elixir_module_binaries, [{Module, ModuleMap, Binary} | Current]);
452    _ ->
453      ok
454  end,
455
456  case get(elixir_compiler_pid) of
457    undefined ->
458      ok;
459    PID ->
460      Ref = make_ref(),
461      PID ! {module_available, self(), Ref, get(elixir_compiler_file), Module, Binary, ModuleMap},
462      receive {Ref, ack} -> ok end
463  end.
464
465%% Error handling and helpers.
466
467%% We've reached the elixir_module or eval internals, skip it with the rest
468prune_stacktrace(Info, [{elixir, eval_forms, _, _} | _]) ->
469  [Info];
470prune_stacktrace(Info, [{elixir_module, _, _, _} | _]) ->
471  [Info];
472prune_stacktrace(Info, [H | T]) ->
473  [H | prune_stacktrace(Info, T)];
474prune_stacktrace(Info, []) ->
475  [Info].
476
477location(Line, E) ->
478  [{file, elixir_utils:characters_to_list(?key(E, file))}, {line, Line}].
479
480format_error({unused_attribute, typedoc}) ->
481  "module attribute @typedoc was set but no type follows it";
482format_error({unused_attribute, doc}) ->
483  "module attribute @doc was set but no definition follows it";
484format_error({unused_attribute, impl}) ->
485  "module attribute @impl was set but no definition follows it";
486format_error({unused_attribute, deprecated}) ->
487  "module attribute @deprecated was set but no definition follows it";
488format_error({unused_attribute, Attr}) ->
489  io_lib:format("module attribute @~ts was set but never used", [Attr]);
490format_error({invalid_module, Module}) ->
491  io_lib:format("invalid module name: ~ts", ['Elixir.Kernel':inspect(Module)]);
492format_error({module_defined, Module}) ->
493  Extra =
494    case code:which(Module) of
495      "" ->
496        " (current version defined in memory)";
497      Path when is_list(Path) ->
498        io_lib:format(" (current version loaded from ~ts)", [elixir_utils:relative_to_cwd(Path)]);
499      _ ->
500        ""
501    end,
502  io_lib:format("redefining module ~ts~ts", [elixir_aliases:inspect(Module), Extra]);
503format_error({module_reserved, Module}) ->
504  io_lib:format("module ~ts is reserved and cannot be defined", [elixir_aliases:inspect(Module)]);
505format_error({module_in_definition, Module, File, Line}) ->
506  io_lib:format("cannot define module ~ts because it is currently being defined in ~ts:~B",
507    [elixir_aliases:inspect(Module), elixir_utils:relative_to_cwd(File), Line]);
508format_error({bad_inline, {Name, Arity}}) ->
509  io_lib:format("inlined function ~ts/~B undefined", [Name, Arity]);
510format_error({bad_dialyzer, Key, {Name, Arity}}) ->
511  io_lib:format("undefined function ~ts/~B given to @dialyzer :~ts", [Name, Arity, Key]);
512format_error({undefined_on_load, {Name, Arity}}) ->
513  io_lib:format("@on_load function ~ts/~B is undefined", [Name, Arity]);
514format_error({wrong_kind_on_load, {Name, Arity}, WrongKind}) ->
515  io_lib:format("expected @on_load function ~ts/~B to be a function, got \"~ts\"",
516                [Name, Arity, WrongKind]);
517format_error({parse_transform, Module}) ->
518  io_lib:format("@compile {:parse_transform, ~ts} is deprecated. Elixir will no longer support "
519                "Erlang-based transforms in future versions", [elixir_aliases:inspect(Module)]).
520