Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions lib/elixir/lib/macro/env.ex
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ defmodule Macro.Env do

* `export_vars` - a list keeping all variables to be exported in a
construct (may be `nil`)
* `match_vars` - a list of variables defined in a given match (is
`nil` when not inside a match)
* `match_vars` - controls how "new" variables are handled. Inside a
match it is a list with all variables in a match. Outside of a match
is either `:warn` or `:apply`
* `prematch_vars` - a list of variables defined before a match (is
`nil` when not inside a match)

Expand All @@ -66,7 +67,7 @@ defmodule Macro.Env do
@type local :: atom | nil

@opaque export_vars :: vars | nil
@opaque match_vars :: vars | nil
@opaque match_vars :: vars | :warn | :apply
@opaque prematch_vars :: vars | nil

@type t :: %{__struct__: __MODULE__,
Expand Down Expand Up @@ -103,7 +104,7 @@ defmodule Macro.Env do
vars: [],
lexical_tracker: nil,
export_vars: nil,
match_vars: nil,
match_vars: :warn,
prematch_vars: nil}
end

Expand Down
8 changes: 7 additions & 1 deletion lib/elixir/src/elixir.erl
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,14 @@ env_for_eval(Env, Opts) ->
false -> nil
end,

FA = case lists:keyfind(function, 1, Opts) of
{function, {Function, Arity}} when is_atom(Function), is_integer(Arity) -> {Function, Arity};
{function, nil} -> nil;
false -> nil
end,

Env#{
file := File, module := Module,
file := File, module := Module, function := FA,
macros := Macros, functions := Functions,
requires := Requires, aliases := Aliases, line := Line
}.
Expand Down
8 changes: 4 additions & 4 deletions lib/elixir/src/elixir_clauses.erl
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@

match(Fun, Expr, #{context := match} = E) ->
Fun(Expr, E);
match(Fun, Expr, #{context := Context, match_vars := nil, prematch_vars := nil, vars := Vars} = E) ->
match(Fun, Expr, #{context := Context, match_vars := Match, prematch_vars := nil, vars := Vars} = E) ->
{EExpr, EE} = Fun(Expr, E#{context := match, match_vars := [], prematch_vars := Vars}),
{EExpr, EE#{context := Context, match_vars := nil, prematch_vars := nil}}.
{EExpr, EE#{context := Context, match_vars := Match, prematch_vars := nil}}.

def({Meta, Args, Guards, Body}, E) ->
def({Meta, Args, Guards, Body}, #{match_vars := Match} = E) ->
{EArgs, EA} = elixir_expand:expand(Args, E#{context := match, match_vars := []}),
{EGuards, EG} = guard(Guards, EA#{context := guard, match_vars := nil}),
{EGuards, EG} = guard(Guards, EA#{context := guard, match_vars := Match}),
{EBody, _} = elixir_expand:expand(Body, EG#{context := ?key(E, context)}),
{Meta, EArgs, EGuards, EBody}.

Expand Down
4 changes: 2 additions & 2 deletions lib/elixir/src/elixir_env.erl
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ new() ->
lexical_tracker => nil, %% holds the lexical tracker PID
vars => [], %% a set of defined variables
export_vars => nil, %% a set of variables to be exported in some constructs
match_vars => nil, %% a set of variables defined in the current match
prematch_vars => nil}. %% a set of variables defined before the current match
prematch_vars => nil, %% a set of variables defined before the current match
match_vars => warn}. %% handling of new variables

linify({Line, Env}) ->
Env#{line := Line};
Expand Down
6 changes: 3 additions & 3 deletions lib/elixir/src/elixir_erl_try.erl
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ each_clause({'catch', Meta, Raw, Expr}, S) ->

each_clause({rescue, Meta, [{in, _, [Left, Right]}], Expr}, S) ->
{TempName, _, CS} = elixir_erl_var:build('_', S),
TempVar = {TempName, Meta, nil},
TempVar = {TempName, Meta, 'Elixir'},
{Parts, Safe, FS} = rescue_guards(Meta, TempVar, Right, CS),
Body = rescue_clause_body(Left, Expr, Safe, TempVar, Meta),
build_rescue(Meta, Parts, Body, FS);

each_clause({rescue, Meta, [{VarName, _, Context} = Left], Expr}, S) when is_atom(VarName), is_atom(Context) ->
{TempName, _, CS} = elixir_erl_var:build('_', S),
TempVar = {TempName, Meta, nil},
TempVar = {TempName, Meta, 'Elixir'},
Body = rescue_clause_body(Left, Expr, false, TempVar, Meta),
build_rescue(Meta, [{TempVar, []}], Body, CS).

Expand Down Expand Up @@ -76,7 +76,7 @@ rescue_guards(Meta, Var, Aliases, S) ->
[] -> {[], S};
_ ->
{VarName, _, CS} = elixir_erl_var:build('_', S),
StructVar = {VarName, Meta, nil},
StructVar = {VarName, Meta, 'Elixir'},
Map = {'%{}', Meta, [{'__struct__', StructVar}, {'__exception__', true}]},
Match = {'=', Meta, [Map, Var]},
Guards = [{erl(Meta, '=='), Meta, [StructVar, Mod]} || Mod <- Elixir],
Expand Down
13 changes: 9 additions & 4 deletions lib/elixir/src/elixir_expand.erl
Original file line number Diff line number Diff line change
Expand Up @@ -357,10 +357,15 @@ expand({Name, Meta, Kind} = Var, #{vars := Vars} = E) when is_atom(Name), is_ato
{var, true} ->
form_error(Meta, ?key(E, file), ?MODULE, {undefined_var, Name, Kind});
_ ->
Message =
io_lib:format("variable \"~ts\" does not exist and is being expanded to \"~ts()\","
" please use parentheses to remove the ambiguity or change the variable name", [Name, Name]),
elixir_errors:warn(?line(Meta), ?key(E, file), Message),
case ?key(E, match_vars) of
warn ->
Message =
io_lib:format("variable \"~ts\" does not exist and is being expanded to \"~ts()\","
" please use parentheses to remove the ambiguity or change the variable name", [Name, Name]),
elixir_errors:warn(?line(Meta), ?key(E, file), Message);
apply ->
ok
end,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kind of hacky, isn't it? It's just to get around the foo warning. It also makes the regular shell and shell-in-pry behave differently for code like this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation is sound but the idea is debatable. I have tried the following approaches:

  1. Autocompletion of nullary calls - it is a bad user experience because it works only some times (for example, it wouldn't work for open/0 and whereami/0 because we also have other arities)
  2. Parens autocompletion of all calls - if we add only (, we get incomplete input most of the times. If we add both, then we need to go back one position (currently it is not possible to add both and then put the cursor on the middle)
  3. Accept continue in the shell - the UX is great, the inconsistency is, well, inconsistent

We can bring the warning back once we figure out autocompletion but since this feature is about the user experience, I have put it first here.

expand({Name, Meta, []}, E)
end
end;
Expand Down
Loading