Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: elixir-lang/elixir
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.13.1
Choose a base ref
...
head repository: elixir-lang/elixir
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.13.2
Choose a head ref
  • 14 commits
  • 23 files changed
  • 6 contributors

Commits on Dec 16, 2021

  1. Copy the full SHA
    e61ed47 View commit details
  2. Update CHANGELOG

    josevalim committed Dec 16, 2021
    1
    Copy the full SHA
    2dc3fd2 View commit details
  3. Copy the full SHA
    3d3453c View commit details

Commits on Dec 20, 2021

  1. Copy the full SHA
    0712854 View commit details
  2. Allow bypassing application mode validation in release spec (#11506)

    Today, there is a mode validation check when doing a Mix Release that
    prevents a parent application that has an application mode of
    `:permanent`, for example, while a child application has mode `:load`,
    as it might be unsafe.
    
    However, some complex applications may need more control over the
    application load/start order.  For such cases, the user would need a
    way to tell Mix.Release to don't be strict while constructing the
    `.rel` file.
    
    To allow for better control over the mode validation check instead of
    simply disabling the check completely, we introduce the
    `:skip_mode_validation_for` to allow users to specify a list of
    applications for which the strict application mode validations should
    not be enforced.
    thalesmg authored and josevalim committed Dec 20, 2021
    Copy the full SHA
    280215c View commit details

Commits on Dec 22, 2021

  1. Copy the full SHA
    4431ac6 View commit details
  2. Copy the full SHA
    6549b00 View commit details
  3. Copy the full SHA
    ab1da11 View commit details

Commits on Dec 31, 2021

  1. Copy the full SHA
    d5e7446 View commit details

Commits on Jan 1, 2022

  1. Fix the nested uniq: acc name clash by preserving a scope (#11532)

    Aleksei Matiushkin authored and josevalim committed Jan 1, 2022
    Copy the full SHA
    01a4889 View commit details

Commits on Jan 2, 2022

  1. Mix.Tasks.Test.Coverage warns on failure (#11457)

    Adds an explicit warning when exiting with an error code because of a
    failed test coverage threshold.
    
    Example:
    ```
    -----------|--------------------------
        62.35% | Total
    
    Coverage test failed, threshold not met:
            Coverage:   62.35%
            Threshold: 100.00%
    ```
    agundy authored and josevalim committed Jan 2, 2022
    Copy the full SHA
    66b4ab1 View commit details

Commits on Jan 12, 2022

  1. Bring back filter/reject on Map and Keyword

    They are already being used in projects, which
    means it is too late for a deprecation. The docs
    instead discuss when to use them.
    josevalim committed Jan 12, 2022
    Copy the full SHA
    d25ce48 View commit details
  2. Update CHANGELOG

    josevalim committed Jan 12, 2022
    Copy the full SHA
    16292c6 View commit details

Commits on Jan 13, 2022

  1. Release v1.13.2

    josevalim committed Jan 13, 2022
    Copy the full SHA
    9ad1829 View commit details
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -128,6 +128,27 @@ Now any application can use your formatter as follows:

Finally, the `Code` module has also been augmented with two functions: `Code.string_to_quoted_with_comments/2` and `Code.quoted_to_algebra/2`. Those functions allow someone to retrieve the Elixir AST with their original source code comments, and then convert this AST to formatted code. In other words, those functions provide a wrapper around the Elixir Code Formatter, supporting developers who wish to create tools that directly manipulate and custom format Elixir source code.

## v1.13.2 (2022-01-13)

### 1. Enhancements

#### Mix

* [mix format] Allow plugins to also format `.ex` and `.exs` files
* [mix release] Allow bypassing application mode validation in release spec
* [mix test] Print a message when the suite fails due to the coverage threshold

### 2. Bug fixes

#### Elixir

* [Code] Do not emit warnings on `Code.Fragment.container_cursor_to_quoted/2`
* [Kernel] Fix a crash when a for-comprehension with `:uniq` was used inside another comprehension with `:uniq`
* [Kernel] Ensure `env.context_modules` is properly set inside optimized `defmodule`
* [Keyword] Deprecate the recently added `Keyword.map/2` as it is equivalent to `Keyword.new/2`
* [Map] Deprecate the recently added `Map.map/2` as it is equivalent to `Map.new/2`
* [Protocol] Warn on zero arity callbacks inside protocols

## v1.13.1 (2021-12-14)

### 1. Bug fixes
@@ -210,6 +231,7 @@ Finally, the `Code` module has also been augmented with two functions: `Code.str
#### Logger

* [Logger] Add `Logger.put_application_level/2`
* [Logger] Print all log levels in accordance to Erlang/OTP. This also means `[warn]` is now shown as `[warning]`

#### Mix

2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.13.1
1.13.2
2 changes: 1 addition & 1 deletion bin/elixir
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/sh
set -e

ELIXIR_VERSION=1.13.1
ELIXIR_VERSION=1.13.2

if [ $# -eq 0 ] || { [ $# -eq 1 ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; }; then
cat <<USAGE >&2
2 changes: 1 addition & 1 deletion bin/elixir.bat
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@if defined ELIXIR_CLI_ECHO (@echo on) else (@echo off)

set ELIXIR_VERSION=1.13.1
set ELIXIR_VERSION=1.13.2

setlocal enabledelayedexpansion
if ""%1""=="""" if ""%2""=="""" goto documentation
2 changes: 1 addition & 1 deletion lib/elixir/lib/code/fragment.ex
Original file line number Diff line number Diff line change
@@ -827,7 +827,7 @@ defmodule Code.Fragment do

case :elixir_tokenizer.tokenize(fragment, line, column, tokenizer_opts) do
{:ok, _, _, _warnings, tokens} ->
:elixir.tokens_to_quoted(tokens, file, columns: columns, token_metadata: token_metadata)
:elixir.tokens_to_quoted(tokens, nil, columns: columns, token_metadata: token_metadata)

{:error, {line, column, {prefix, suffix}, token}, _rest, _warnings, _so_far} ->
location = [line: line, column: column]
26 changes: 4 additions & 22 deletions lib/elixir/lib/keyword.ex
Original file line number Diff line number Diff line change
@@ -1374,27 +1374,9 @@ defmodule Keyword do
end
end

@doc """
Maps the function `fun` over all key-value pairs in `keywords`,
returning a keyword list with all the values replaced with
the result of the function.
## Examples
iex> Keyword.map([one: 1, two: 2, three: 3], fn {_key, val} -> to_string(val) end)
[one: "1", two: "2", three: "3"]
"""
@doc since: "1.13.0"
@spec map(t, ({key, value} -> value)) :: t
def map(keywords, fun) when is_list(keywords) and is_function(fun, 1) do
do_map(keywords, fun)
end

defp do_map([], _fun), do: []

defp do_map([{key, value} | rest], fun) do
new_value = fun.({key, value})
[{key, new_value} | do_map(rest, fun)]
@doc false
@deprecated "Use Keyword.new/2 instead"
def map(keywords, fun) when is_list(keywords) do
Enum.map(keywords, fn {k, v} -> {k, fun.({k, v})} end)
end
end
38 changes: 6 additions & 32 deletions lib/elixir/lib/map.ex
Original file line number Diff line number Diff line change
@@ -982,8 +982,8 @@ defmodule Map do
See also `reject/2` which discards all elements where the
function returns a truthy value.
> Note: if you find yourself doing multiple calls to `Map.map/2`
> and `Map.filter/2` in a pipeline, it is likely more efficient
> Note: if you find yourself doing multiple calls to `Map.filter/2`
> and `Map.reject/2` in a pipeline, it is likely more efficient
> to use `Enum.map/2` and `Enum.filter/2` instead and convert to
> a map at the end using `Map.new/1`.
@@ -1041,35 +1041,9 @@ defmodule Map do
end
end

@doc """
Maps the function `fun` over all key-value pairs in `map`
It returns a map with all the values replaced with the result
of the function.
> Note: if you find yourself doing multiple calls to `Map.map/2`
> and `Map.filter/2` in a pipeline, it is likely more efficient
> to use `Enum.map/2` and `Enum.filter/2` instead and convert to
> a map at the end using `Map.new/1`.
## Examples
iex> Map.map(%{1 => "joe", 2 => "mike", 3 => "robert"}, fn {_key, val} -> String.capitalize(val) end)
%{1 => "Joe", 2 => "Mike", 3 => "Robert"}
"""
@doc since: "1.13.0"
@spec map(map, ({key, value} -> value)) :: map
def map(map, fun) when is_map(map) and is_function(fun, 1) do
iter = :maps.iterator(map)
next = :maps.next(iter)
:maps.from_list(do_map(next, fun))
end

defp do_map(:none, _fun), do: []

defp do_map({key, value, iter}, fun) do
new_value = fun.({key, value})
[{key, new_value} | do_map(:maps.next(iter), fun)]
@doc false
@deprecated "Use Map.new/2 instead"
def map(map, fun) when is_map(map) do
new(map, fn {k, v} -> {k, fun.({k, v})} end)
end
end
6 changes: 5 additions & 1 deletion lib/elixir/lib/process.ex
Original file line number Diff line number Diff line change
@@ -383,7 +383,7 @@ defmodule Process do
@type spawn_opt ::
:link
| :monitor
| {:monitor, :erlang.monitor_option()}
| {:monitor, monitor_option()}
| {:priority, :low | :normal | :high}
| {:fullsweep_after, non_neg_integer}
| {:min_heap_size, non_neg_integer}
@@ -392,6 +392,10 @@ defmodule Process do
| {:message_queue_data, :off_heap | :on_heap}
@type spawn_opts :: [spawn_opt]

# TODO: Use :erlang.monitor_option() on Erlang/OTP 24+
@typep monitor_option ::
[alias: :explicit_unalias | :demonitor | :reply_demonitor, tag: term()]

@doc """
Spawns the given function according to the given options.
4 changes: 2 additions & 2 deletions lib/elixir/lib/protocol.ex
Original file line number Diff line number Diff line change
@@ -723,14 +723,14 @@ defmodule Protocol do

defp callback_ast_to_fa({kind, {:"::", meta, [{name, _, args}, _return]}, _pos})
when kind in [:callback, :macrocallback] do
[{{name, length(args)}, meta}]
[{{name, length(List.wrap(args))}, meta}]
end

defp callback_ast_to_fa(
{kind, {:when, _, [{:"::", meta, [{name, _, args}, _return]}, _vars]}, _pos}
)
when kind in [:callback, :macrocallback] do
[{{name, length(args)}, meta}]
[{{name, length(List.wrap(args))}, meta}]
end

defp callback_ast_to_fa({kind, _, _pos}) when kind in [:callback, :macrocallback] do
10 changes: 5 additions & 5 deletions lib/elixir/src/elixir.erl
Original file line number Diff line number Diff line change
@@ -359,8 +359,8 @@ string_to_tokens(String, StartLine, StartColumn, File, Opts) when is_integer(Sta
{error, {Location, to_binary(Error), to_binary(Token)}}
end.

tokens_to_quoted(Tokens, File, Opts) ->
handle_parsing_opts(File, Opts),
tokens_to_quoted(Tokens, WarningFile, Opts) ->
handle_parsing_opts(WarningFile, Opts),

try elixir_parser:parse(Tokens) of
{ok, Forms} ->
@@ -370,7 +370,7 @@ tokens_to_quoted(Tokens, File, Opts) ->
{error, {Line, _, [Error, Token]}} ->
{error, {parser_location(Line), to_binary(Error), to_binary(Token)}}
after
erase(elixir_parser_file),
erase(elixir_parser_warning_file),
erase(elixir_parser_columns),
erase(elixir_token_metadata),
erase(elixir_literal_encoder)
@@ -406,15 +406,15 @@ parser_location(Meta) ->
to_binary(List) when is_list(List) -> elixir_utils:characters_to_binary(List);
to_binary(Atom) when is_atom(Atom) -> atom_to_binary(Atom, utf8).

handle_parsing_opts(File, Opts) ->
handle_parsing_opts(WarningFile, Opts) ->
LiteralEncoder =
case lists:keyfind(literal_encoder, 1, Opts) of
{literal_encoder, Fun} -> Fun;
false -> false
end,
TokenMetadata = lists:keyfind(token_metadata, 1, Opts) == {token_metadata, true},
Columns = lists:keyfind(columns, 1, Opts) == {columns, true},
put(elixir_parser_file, File),
put(elixir_parser_warning_file, WarningFile),
put(elixir_parser_columns, Columns),
put(elixir_token_metadata, TokenMetadata),
put(elixir_literal_encoder, LiteralEncoder).
3 changes: 2 additions & 1 deletion lib/elixir/src/elixir_compiler.erl
Original file line number Diff line number Diff line change
@@ -133,7 +133,8 @@ fast_compile({defmodule, Meta, [Mod, [{do, TailBlock}]]}, NoLineE) ->
'Elixir.Macro':expand(Mod, E)
end,

elixir_module:compile(Expanded, Block, [], E).
ContextModules = [Expanded | ?key(E, context_modules)],
elixir_module:compile(Expanded, Block, [], E#{context_modules := ContextModules}).

%% Bootstrapper

20 changes: 10 additions & 10 deletions lib/elixir/src/elixir_erl_for.erl
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ translate_reduce(Meta, Cases, Expr, Reduce, S) ->
({'case', CaseAnn, _, CaseBlock}, InnerAcc) -> {'case', CaseAnn, InnerAcc, CaseBlock}
end,

{build_reduce(Ann, TCases, InnerFun, TExpr, TReduce, false, SE), SE}.
build_reduce(Ann, TCases, InnerFun, TExpr, TReduce, false, SE).

translate_into(Meta, Cases, Expr, Opts, Return, S) ->
Ann = ?ann(Meta),
@@ -115,11 +115,11 @@ build_inline(Ann, Clauses, Expr, Into, Uniq, S) ->

build_inline_each(Ann, Clauses, Expr, false, Uniq, S) ->
InnerFun = fun(InnerExpr, _InnerAcc) -> InnerExpr end,
{build_reduce(Ann, Clauses, InnerFun, Expr, {nil, Ann}, Uniq, S), S};
build_reduce(Ann, Clauses, InnerFun, Expr, {nil, Ann}, Uniq, S);
build_inline_each(Ann, Clauses, Expr, {nil, _} = Into, Uniq, S) ->
InnerFun = fun(InnerExpr, InnerAcc) -> {cons, Ann, InnerExpr, InnerAcc} end,
ReduceExpr = build_reduce(Ann, Clauses, InnerFun, Expr, Into, Uniq, S),
{?remote(Ann, lists, reverse, [ReduceExpr]), S};
{ReduceExpr, SR} = build_reduce(Ann, Clauses, InnerFun, Expr, Into, Uniq, S),
{?remote(Ann, lists, reverse, [ReduceExpr]), SR};
build_inline_each(Ann, Clauses, Expr, {bin, _, []}, Uniq, S) ->
{InnerValue, SV} = build_var(Ann, S),
Generated = erl_anno:set_generated(true, Ann),
@@ -138,8 +138,8 @@ build_inline_each(Ann, Clauses, Expr, {bin, _, []}, Uniq, S) ->
]}
end,

ReduceExpr = build_reduce(Ann, Clauses, InnerFun, Expr, {nil, Ann}, Uniq, SV),
{?remote(Ann, erlang, list_to_bitstring, [ReduceExpr]), SV}.
{ReduceExpr, SR} = build_reduce(Ann, Clauses, InnerFun, Expr, {nil, Ann}, Uniq, SV),
{?remote(Ann, erlang, list_to_bitstring, [ReduceExpr]), SR}.

build_into(Ann, Clauses, Expr, {map, _, []}, Uniq, S) ->
{ReduceExpr, SR} = build_inline_each(Ann, Clauses, Expr, {nil, Ann}, Uniq, S),
@@ -161,7 +161,7 @@ build_into(Ann, Clauses, Expr, Into, Uniq, S) ->
?remote(Ann, 'Elixir.Collectable', into, [Into])
},

IntoReduceExpr = build_reduce(Ann, Clauses, InnerFun, Expr, Acc, Uniq, SD),
{IntoReduceExpr, SN} = build_reduce(Ann, Clauses, InnerFun, Expr, Acc, Uniq, SD),

TryExpr =
{'try', Ann,
@@ -173,7 +173,7 @@ build_into(Ann, Clauses, Expr, Into, Uniq, S) ->
[stacktrace_clause(Ann, Fun, Acc, Kind, Reason, Stack)],
[]},

{{block, Ann, [MatchExpr, TryExpr]}, SD}.
{{block, Ann, [MatchExpr, TryExpr]}, SN}.

stacktrace_clause(Ann, Fun, Acc, Kind, Reason, Stack) ->
{clause, Ann,
@@ -186,7 +186,7 @@ stacktrace_clause(Ann, Fun, Acc, Kind, Reason, Stack) ->

build_reduce(Ann, Clauses, InnerFun, Expr, Into, false, S) ->
{Acc, SA} = build_var(Ann, S),
build_reduce_each(Clauses, InnerFun(Expr, Acc), Into, Acc, SA);
{build_reduce_each(Clauses, InnerFun(Expr, Acc), Into, Acc, SA), SA};
build_reduce(Ann, Clauses, InnerFun, Expr, Into, true, S) ->
%% Those variables are used only inside the anonymous function
%% so we don't need to worry about returning the scope.
@@ -209,7 +209,7 @@ build_reduce(Ann, Clauses, InnerFun, Expr, Into, true, S) ->
]},

EnumReduceCall = build_reduce_each(Clauses, InnerExpr, NewInto, Acc, SU),
?remote(Ann, erlang, element, [{integer, Ann, 1}, EnumReduceCall]).
{?remote(Ann, erlang, element, [{integer, Ann, 1}, EnumReduceCall]), SU}.

build_reduce_each([{enum, Meta, Left, Right, Filters} | T], Expr, Arg, Acc, S) ->
Ann = ?ann(Meta),
32 changes: 21 additions & 11 deletions lib/elixir/src/elixir_parser.yrl
Original file line number Diff line number Diff line change
@@ -640,7 +640,6 @@ map -> struct_op struct_expr eol map_args : {'%', meta_from_token('$1'), ['$2',

Erlang code.

-define(file(), get(elixir_parser_file)).
-define(columns(), get(elixir_parser_columns)).
-define(token_metadata(), get(elixir_token_metadata)).

@@ -729,10 +728,12 @@ build_op(AST, {_Kind, Location, '//'}, Right) ->

build_op({UOp, _, [Left]}, {_Kind, {Line, Column, _} = Location, 'in'}, Right) when ?rearrange_uop(UOp) ->
%% TODO: Remove "not left in right" rearrangement on v2.0
elixir_errors:erl_warn({Line, Column}, ?file(),
warn(
{Line, Column},
"\"not expr1 in expr2\" is deprecated. "
"Instead use \"expr1 not in expr2\" if you require Elixir v1.5+, "
"or \"not(expr1 in expr2)\" if you have to support earlier Elixir versions"),
"or \"not(expr1 in expr2)\" if you have to support earlier Elixir versions"
),
Meta = meta_from_location(Location),
{UOp, Meta, [{'in', Meta, [Left, Right]}]};

@@ -1169,21 +1170,22 @@ error_invalid_kw_identifier({_, Location, KW}) ->

%% TODO: Make this an error on v2.0
warn_trailing_comma({',', {Line, Column, _}}) ->
elixir_errors:erl_warn({Line, Column}, ?file(),
"trailing commas are not allowed inside function/macro call arguments"
).
warn({Line, Column}, "trailing commas are not allowed inside function/macro call arguments").

%% TODO: Make this an error on v2.0
warn_empty_paren({_, {Line, Column, _}}) ->
elixir_errors:erl_warn({Line, Column}, ?file(),
warn(
{Line, Column},
"invalid expression (). "
"If you want to invoke or define a function, make sure there are "
"no spaces between the function name and its arguments. If you wanted "
"to pass an empty block or code, pass a value instead, such as a nil or an atom").
"to pass an empty block or code, pass a value instead, such as a nil or an atom"
).

%% TODO: Make this an error on v2.0
warn_pipe({arrow_op, {Line, Column, _}, Op}, {_, [_ | _], [_ | _]}) ->
elixir_errors:erl_warn({Line, Column}, ?file(),
warn(
{Line, Column},
io_lib:format(
"parentheses are required when piping into a function call. For example:\n\n"
" foo 1 ~ts bar 2 ~ts baz 3\n\n"
@@ -1197,6 +1199,14 @@ warn_pipe(_Token, _) ->
ok.

warn_empty_stab_clause({stab_op, {Line, Column, _}, '->'}) ->
elixir_errors:erl_warn({Line, Column}, ?file(),
warn(
{Line, Column},
"an expression is always required on the right side of ->. "
"Please provide a value after ->").
"Please provide a value after ->"
).

warn(LineColumn, Message) ->
case get(elixir_parser_warning_file) of
nil -> ok;
File -> elixir_errors:erl_warn(LineColumn, File, Message)
end.
5 changes: 5 additions & 0 deletions lib/elixir/test/elixir/code_fragment_test.exs
Original file line number Diff line number Diff line change
@@ -915,6 +915,11 @@ defmodule CodeFragmentTest do
assert cc2q("foo(123, ~r/") == s2q("foo(123, __cursor__())")
end

test "no warnings" do
assert cc2q(~s"?\\ ") == s2q("__cursor__()")
assert cc2q(~s"{fn -> end, ") == s2q("{fn -> nil end, __cursor__()}")
end

test "options" do
opts = [columns: true]
assert cc2q("foo(", opts) == s2q("foo(__cursor__())", opts)
Loading