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