Skip to content

Commit d9b98a6

Browse files
author
José Valim
committed
Check if the module is in the same context before checking if it is open
1 parent 78a0abc commit d9b98a6

File tree

8 files changed

+34
-21
lines changed

8 files changed

+34
-21
lines changed

lib/elixir/include/elixir.hrl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
extra_guards=nil, %% extra guards from args expansion
2323
counter=[], %% a counter for the variables defined
2424
local=nil, %% the scope to evaluate local functions against
25-
scheduled=[], %% scheduled modules to be loaded
25+
context_modules=[], %% modules defined in the current context
2626
macro_aliases=[], %% keep aliases defined inside a macro
2727
aliases, %% an orddict with aliases by new -> old names
2828
file, %% the current scope filename

lib/elixir/lib/kernel.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3247,7 +3247,7 @@ defmodule Kernel do
32473247
true ->
32483248
fields =
32493249
try do
3250-
case caller.module == atom or Module.open?(atom) do
3250+
case :lists.member(atom, caller.context_modules) and Module.open?(atom) do
32513251
true -> Module.get_attribute(atom, :record_fields)
32523252
false -> atom.__record__(:fields)
32533253
end
@@ -3258,7 +3258,7 @@ defmodule Kernel do
32583258
# conflicts.
32593259
case :code.ensure_loaded(atom) do
32603260
{ :error, _ } ->
3261-
raise "expected module #{inspect atom} to be loaded and defined"
3261+
:elixir_aliases.ensure_loaded(caller.line, caller.file, atom, caller.context_modules)
32623262
_ ->
32633263
raise "cannot use module #{inspect atom} in access protocol because it does not export __record__/1"
32643264
end

lib/elixir/lib/macro/env.ex

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ defmodule Macro.Env do
1919
* `requires` - the list of required modules
2020
* `functions` - a list of functions imported from each module
2121
* `macros` - a list of macros imported from each module
22+
* `context_modules` - a list of modules defined in the current context
2223
"""
2324

2425
@type name_arity :: { atom, non_neg_integer }
@@ -29,13 +30,14 @@ defmodule Macro.Env do
2930
@type requires :: [module]
3031
@type functions :: [{ module, [name_arity] }]
3132
@type macros :: [{ module, [name_arity] }]
33+
@type context_modules :: [module]
3234

33-
fields = [:module, :file, :line, :function,
34-
:aliases, :context, :requires, :functions, :macros]
35+
fields = [:module, :file, :line, :function, :aliases,
36+
:context, :requires, :functions, :macros, :context_modules]
3537

3638
types = quote do: [module: module, file: file, line: line,
3739
function: name_arity, aliases: aliases, requires: requires,
38-
functions: functions, macros: macros]
40+
functions: functions, macros: macros, context_modules: context_modules]
3941

4042
Record.deffunctions(fields, __MODULE__)
4143
Record.deftypes(fields, types, __MODULE__)

lib/elixir/src/elixir_aliases.erl

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
-module(elixir_aliases).
22
-export([nesting_alias/2, last/1, concat/1, safe_concat/1,
3-
format_error/1, ensure_loaded/3, expand/3, store/4]).
3+
format_error/1, ensure_loaded/3, ensure_loaded/4, expand/3, store/4]).
44
-include("elixir.hrl").
55
-compile({parse_transform, elixir_transform}).
66

@@ -65,19 +65,22 @@ expand_one(H, Aliases) ->
6565

6666
%% Ensure a module is loaded before its usage.
6767

68-
ensure_loaded(_Line, 'Elixir.Kernel', _S) ->
68+
ensure_loaded(Line, Ref, S) ->
69+
ensure_loaded(Line, S#elixir_scope.file, Ref, S#elixir_scope.context_modules).
70+
71+
ensure_loaded(_Line, _File, 'Elixir.Kernel', FileModules) ->
6972
ok;
7073

71-
ensure_loaded(Line, Ref, S) ->
74+
ensure_loaded(Line, File, Ref, FileModules) ->
7275
try
7376
Ref:module_info(compile)
7477
catch
7578
error:undef ->
76-
Kind = case lists:member(Ref, S#elixir_scope.scheduled) of
79+
Kind = case lists:member(Ref, FileModules) of
7780
true -> scheduled_module;
7881
false -> unloaded_module
7982
end,
80-
elixir_errors:form_error(Line, S#elixir_scope.file, ?MODULE, { Kind, Ref })
83+
elixir_errors:form_error(Line, File, ?MODULE, { Kind, Ref })
8184
end.
8285

8386
%% Receives an atom and returns the last bit as an alias.

lib/elixir/src/elixir_macros.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ translate({defmodule, Meta, [Ref, KV]}, S) ->
205205

206206
{
207207
{ atom, Meta, FullModule },
208-
RS#elixir_scope{scheduled=[FullModule|S#elixir_scope.scheduled]}
208+
RS#elixir_scope{context_modules=[FullModule|S#elixir_scope.context_modules]}
209209
};
210210
_ ->
211211
{ TRef, S }

lib/elixir/src/elixir_module.erl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,13 @@ translate(Meta, Ref, Block, S) ->
5050

5151
%% The compilation hook.
5252

53-
compile(Line, Module, Block, Vars, #elixir_scope{} = S) when is_atom(Module) ->
53+
compile(Line, Module, Block, Vars, #elixir_scope{context_modules=FileModules} = RawS) when is_atom(Module) ->
5454
C = elixir_compiler:get_opts(),
55+
S = case lists:member(Module, FileModules) of
56+
true -> RawS;
57+
false -> RawS#elixir_scope{context_modules=[Module|FileModules]}
58+
end,
59+
5560
File = S#elixir_scope.file,
5661
FileList = binary_to_list(File),
5762

lib/elixir/src/elixir_scope.erl

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,18 @@ build_ex_var(Line, Key, Name, S) when is_integer(Line) ->
7777

7878
% Handle Macro.Env conversion
7979

80-
to_erl_env({ 'Elixir.Macro.Env', Module, File, _Line, Function, Aliases, Context, Requires, Functions, Macros }) ->
80+
to_erl_env({ 'Elixir.Macro.Env', Module, File, _Line, Function, Aliases, Context, Requires, Functions, Macros, FileModules }) ->
8181
#elixir_scope{module=Module,file=File,
8282
function=Function,aliases=Aliases,context=Context,
83-
requires=Requires,macros=Macros,functions=Functions}.
83+
requires=Requires,macros=Macros,functions=Functions,
84+
context_modules=FileModules}.
8485

8586
to_ex_env({ Line, #elixir_scope{module=Module,file=File,
8687
function=Function,aliases=Aliases,context=Context,
87-
requires=Requires,macros=Macros,functions=Functions} }) when is_integer(Line) ->
88-
{ 'Elixir.Macro.Env', Module, File, Line, Function, Aliases, Context, Requires, Functions, Macros }.
88+
requires=Requires,macros=Macros,functions=Functions,
89+
context_modules=FileModules} }) when is_integer(Line) ->
90+
{ 'Elixir.Macro.Env', Module, File, Line, Function, Aliases,
91+
Context, Requires, Functions, Macros, FileModules }.
8992

9093
% Provides a tuple with only the scope information we want to serialize.
9194

@@ -94,7 +97,7 @@ serialize(S) ->
9497
{ S#elixir_scope.file, S#elixir_scope.functions,
9598
S#elixir_scope.requires, S#elixir_scope.macros, S#elixir_scope.aliases,
9699
S#elixir_scope.macro_functions, S#elixir_scope.macro_macros, S#elixir_scope.macro_aliases,
97-
S#elixir_scope.scheduled }
100+
S#elixir_scope.context_modules }
98101
).
99102

100103
serialize_with_vars(Line, S) when is_integer(Line) ->
@@ -113,7 +116,7 @@ serialize_with_vars(Line, S) when is_integer(Line) ->
113116
deserialize(Tuple) -> deserialize_with_vars(Tuple, []).
114117

115118
deserialize_with_vars({ File, Functions, Requires, Macros,
116-
Aliases, MacroFunctions, MacroMacros, MacroAliases, Scheduled }, Vars) ->
119+
Aliases, MacroFunctions, MacroMacros, MacroAliases, FileModules }, Vars) ->
117120
#elixir_scope{
118121
file=File,
119122
functions=Functions,
@@ -123,7 +126,7 @@ deserialize_with_vars({ File, Functions, Requires, Macros,
123126
macro_functions=MacroFunctions,
124127
macro_macros=MacroMacros,
125128
macro_aliases=MacroAliases,
126-
scheduled=Scheduled,
129+
context_modules=FileModules,
127130
vars=orddict:from_list(Vars),
128131
counter=[{'',length(Vars)}]
129132
}.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ defmodule Kernel.ErrorsTest do
205205
end
206206

207207
test :invalid_access_protocol_not_available do
208-
assert "expected module Unknown to be loaded and defined" ==
208+
assert "nofile:2: module Unknown is not loaded and could not be found" ==
209209
format_rescue 'defmodule Foo do\ndef sample(Unknown[integer: 0]), do: true\nend'
210210
end
211211

0 commit comments

Comments
 (0)