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.16.0
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.16.1
Choose a head ref

Commits on Dec 23, 2023

  1. 1
    Copy the full SHA
    9137577 View commit details

Commits on Dec 24, 2023

  1. 1
    Copy the full SHA
    f84bc19 View commit details

Commits on Dec 26, 2023

  1. 1
    Copy the full SHA
    97c608c View commit details
  2. 1
    Copy the full SHA
    298acd1 View commit details
  3. 1
    Copy the full SHA
    1946611 View commit details

Commits on Dec 28, 2023

  1. 1
    Copy the full SHA
    ba8fb4d View commit details

Commits on Dec 31, 2023

  1. Update CHANGELOG, closes #13217

    josevalim committed Dec 31, 2023
    1
    Copy the full SHA
    9ae7c39 View commit details

Commits on Jan 2, 2024

  1. Copy the full SHA
    0d671da View commit details
  2. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    197351d View commit details

Commits on Jan 7, 2024

  1. Copy the full SHA
    1ece71a View commit details

Commits on Jan 8, 2024

  1. Copy the full SHA
    6f5715f View commit details
  2. Fix typo in docs: for -> force (#13215)

    Co-authored-by: Will Douglas <will.cavalcanti@vmtecnologia.io>
    2 people authored and sabiwara committed Jan 8, 2024
    Copy the full SHA
    f2dae09 View commit details
  3. Unverified

    This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
    Copy the full SHA
    6e29599 View commit details
  4. Fix typo in docs: initial_valye -> initial_value (#13211)

    Co-authored-by: Adebisi Adeyeye <adebisi.adeyeye@proebb.com>
    2 people authored and sabiwara committed Jan 8, 2024
    Copy the full SHA
    4de3315 View commit details
  5. Update design-anti-patterns.md (#13210)

    Not setting an option returns just the integer
    hussienliban authored and sabiwara committed Jan 8, 2024
    Copy the full SHA
    f83b4e4 View commit details

Commits on Jan 10, 2024

  1. Copy the full SHA
    17b9ba6 View commit details
  2. Copy the full SHA
    b96211a View commit details

Commits on Jan 13, 2024

  1. Copy the full SHA
    691d402 View commit details

Commits on Jan 15, 2024

  1. Fix the explanation to match the explained code example in docs (#13255)

    The description incorrectly states that both processes are initialized with 0, while in the code the second process receives a non-default initial value.
    RKushnir authored and josevalim committed Jan 15, 2024
    Copy the full SHA
    6b69c7f View commit details

Commits on Jan 17, 2024

  1. Copy the full SHA
    7d100ff View commit details
  2. Copy the full SHA
    9ea950c View commit details
  3. Fix :from_interpolation docs (#13251)

    mhanberg authored and sabiwara committed Jan 17, 2024
    Copy the full SHA
    6dccefe View commit details
  4. Copy the full SHA
    111b48d View commit details
  5. Improve ast metadata docs

    josevalim authored and sabiwara committed Jan 17, 2024
    Copy the full SHA
    bb8ad44 View commit details
  6. Improve end_of_expression docs

    josevalim authored and sabiwara committed Jan 17, 2024
    Copy the full SHA
    c35edd1 View commit details

Commits on Jan 19, 2024

  1. Copy the full SHA
    ad778a6 View commit details

Commits on Jan 27, 2024

  1. Fix docs link

    Related to #13284.
    josevalim committed Jan 27, 2024
    Copy the full SHA
    da0189e View commit details

Commits on Jan 29, 2024

  1. Escape rebar3 paths

    josevalim committed Jan 29, 2024
    Copy the full SHA
    740b2d7 View commit details

Commits on Jan 30, 2024

  1. Copy the full SHA
    8344e21 View commit details
  2. Copy the full SHA
    60dcd14 View commit details

Commits on Jan 31, 2024

  1. Copy the full SHA
    cf8c28c View commit details
  2. Release v1.16.1

    josevalim committed Jan 31, 2024
    Copy the full SHA
    e0658bb View commit details
Showing with 294 additions and 125 deletions.
  1. +23 −0 CHANGELOG.md
  2. +0 −1 Makefile
  3. +1 −1 VERSION
  4. +1 −1 bin/elixir
  5. +1 −1 bin/elixir.bat
  6. +5 −5 lib/elixir/lib/code/normalizer.ex
  7. +1 −1 lib/elixir/lib/enum.ex
  8. +31 −13 lib/elixir/lib/kernel/parallel_compiler.ex
  9. +8 −5 lib/elixir/lib/macro.ex
  10. +3 −7 lib/elixir/lib/module/parallel_checker.ex
  11. +1 −0 lib/elixir/lib/string.ex
  12. +12 −10 lib/elixir/pages/anti-patterns/code-anti-patterns.md
  13. +56 −8 lib/elixir/pages/anti-patterns/design-anti-patterns.md
  14. +4 −4 lib/elixir/pages/anti-patterns/macro-anti-patterns.md
  15. +3 −3 lib/elixir/pages/anti-patterns/process-anti-patterns.md
  16. +1 −1 lib/elixir/pages/getting-started/basic-types.md
  17. +1 −1 lib/elixir/pages/getting-started/binaries-strings-and-charlists.md
  18. +1 −1 lib/elixir/pages/getting-started/enumerable-and-streams.md
  19. +1 −1 lib/elixir/pages/meta-programming/macros.md
  20. +1 −1 lib/elixir/pages/mix-and-otp/dynamic-supervisor.md
  21. +1 −1 lib/elixir/pages/references/operators.md
  22. +5 −5 lib/elixir/pages/references/patterns-and-guards.md
  23. +2 −2 lib/elixir/pages/references/syntax-reference.md
  24. +1 −1 lib/elixir/pages/references/typespecs.md
  25. +1 −1 lib/elixir/pages/references/unicode-syntax.md
  26. +1 −0 lib/elixir/scripts/elixir_docs.exs
  27. +10 −7 lib/elixir/src/elixir_errors.erl
  28. +4 −0 lib/elixir/test/elixir/code_normalizer/quoted_ast_test.exs
  29. +24 −2 lib/elixir/test/elixir/kernel/parallel_compiler_test.exs
  30. +1 −0 lib/elixir/test/elixir/string_test.exs
  31. +2 −2 lib/ex_unit/lib/ex_unit/filters.ex
  32. +27 −21 lib/ex_unit/test/ex_unit/filters_test.exs
  33. +1 −3 lib/iex/lib/iex/autocomplete.ex
  34. +4 −3 lib/iex/lib/iex/evaluator.ex
  35. +2 −5 lib/iex/test/iex/autocomplete_test.exs
  36. +2 −2 lib/mix/lib/mix/rebar.ex
  37. +1 −1 lib/mix/lib/mix/tasks/compile.leex.ex
  38. +1 −1 lib/mix/lib/mix/tasks/compile.yecc.ex
  39. +6 −1 lib/mix/lib/mix/tasks/deps.compile.ex
  40. +22 −1 lib/mix/test/mix/rebar_test.exs
  41. +21 −1 lib/mix/test/mix/tasks/test_test.exs
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -78,6 +78,28 @@ Another [ExDoc](https://github.com/elixir-lang/ex_doc) feature we have incorpora

Finally, we have started enriching our documentation with [Mermaid.js](https://mermaid.js.org/) diagrams. You can find examples in the [GenServer](https://hexdocs.pm/elixir/main/GenServer.html) and [Supervisor](https://hexdocs.pm/elixir/main/Supervisor.html) docs.

## v1.16.1 (2024-01-31)

### 1. Bug fixes

#### Elixir

* [Code] Fix `Code.quoted_to_algebra/2` for operator with :do key as operand
* [Kernel.ParallelCompiler] Do not crash parallel compiler when it receives diagnostics from additional code evaluation
* [Kernel.ParallelCompiler] Always log errors at the end of compilation
* [String] Fix `String.capitalize/1` with a single codepoint

#### IEx

* [IEx] Fix autocompletion of function signatures on Erlang/OTP 26
* [IEx] Do not assume `$HOME` is set

#### Mix

* [mix deps.compile] Handle compilation of rebar3 dependencies when rebar3 is on a path with spaces on Unix
* [mix test] Properly resolve relative paths when running tests from individual files
* [mix test] Properly resolve Windows paths when running tests from individual files

## v1.16.0 (2023-12-22)

### 1. Enhancements
@@ -118,6 +140,7 @@ Finally, we have started enriching our documentation with [Mermaid.js](https://m
* [mix compile.elixir] Pass original exception down to diagnostic `:details` when possible
* [mix compile.elixir] Optimize scenario where there are thousands of files in `lib/` and one of them is changed
* [mix deps.clean] Emit a warning instead of crashing when a dependency cannot be removed
* [mix escript.build] Escripts now strip .beam files by default, which leads to smaller escripts. However, if you are using escripts to access Elixir docs or compile Elixir code, documentation and deprecation metadata is no longer available. Set `strip_beams: false` in your escript configuration in your `mix.exs` to keep all metadata
* [mix escript.install] Support `--sparse` option
* [mix release] Include `include/` directory in releases
* [mix test] Allow testing multiple file:line at once, such as `mix test test/foo_test.exs:13 test/bar_test.exs:27`
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -189,7 +189,6 @@ docs_elixir: compile ../ex_doc/bin/ex_doc
$(Q) rm -rf doc/elixir
$(call DOCS_COMPILE,Elixir,elixir,Kernel,--config "lib/elixir/scripts/elixir_docs.exs")
$(call DOCS_CONFIG,elixir)
cp -R lib/elixir/pages/images doc/elixir

docs_eex: compile ../ex_doc/bin/ex_doc
@ echo "==> ex_doc (eex)"
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.16.0
1.16.1
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.16.0
ELIXIR_VERSION=1.16.1

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.16.0
set ELIXIR_VERSION=1.16.1

setlocal enabledelayedexpansion
if ""%1""=="""" if ""%2""=="""" goto documentation
10 changes: 5 additions & 5 deletions lib/elixir/lib/code/normalizer.ex
Original file line number Diff line number Diff line change
@@ -352,6 +352,10 @@ defmodule Code.Normalizer do
last = List.last(args)

cond do
not allow_keyword?(form, arity) ->
args = normalize_args(args, %{state | parent_meta: meta})
{form, meta, args}

Keyword.has_key?(meta, :do) or match?([{{:__block__, _, [:do]}, _} | _], last) ->
# def foo do :ok end
# def foo, do: :ok
@@ -363,7 +367,7 @@ defmodule Code.Normalizer do
meta = meta ++ [do: [line: line], end: [line: line]]
normalize_kw_blocks(form, meta, args, state)

allow_keyword?(form, arity) ->
true ->
args = normalize_args(args, %{state | parent_meta: meta})
{last_arg, leading_args} = List.pop_at(args, -1, [])

@@ -384,10 +388,6 @@ defmodule Code.Normalizer do
end

{form, meta, leading_args ++ last_args}

true ->
args = normalize_args(args, %{state | parent_meta: meta})
{form, meta, args}
end
end

2 changes: 1 addition & 1 deletion lib/elixir/lib/enum.ex
Original file line number Diff line number Diff line change
@@ -261,7 +261,7 @@ defmodule Enum do
traversed as if it was an enumerable.
For a general overview of all functions in the `Enum` module, see
[the `Enum` cheatsheet](enum-cheat.html).
[the `Enum` cheatsheet](enum-cheat.cheatmd).
The functions in this module work in linear time. This means that, the
time it takes to perform an operation grows at the same rate as the length
44 changes: 31 additions & 13 deletions lib/elixir/lib/kernel/parallel_compiler.ex
Original file line number Diff line number Diff line change
@@ -455,7 +455,11 @@ defmodule Kernel.ParallelCompiler do
# No more queue, nothing waiting, this cycle is done
defp spawn_workers([], spawned, waiting, files, result, warnings, errors, state)
when map_size(spawned) == 0 and map_size(waiting) == 0 do
[] = errors
# Print any spurious error that we may have found
Enum.map(errors, fn {diagnostic, read_snippet} ->
:elixir_errors.print_diagnostic(diagnostic, read_snippet)
end)

[] = files
cycle_return = each_cycle_return(state.each_cycle.())
state = cycle_timing(result, state)
@@ -510,8 +514,9 @@ defmodule Kernel.ParallelCompiler do
if deadlocked do
spawn_workers(deadlocked, spawned, waiting, files, result, warnings, errors, state)
else
deadlock_errors = handle_deadlock(waiting, files)
{return_error(deadlock_errors ++ errors, warnings), state}
return_error(warnings, errors, state, fn ->
handle_deadlock(waiting, files)
end)
end
end

@@ -681,12 +686,13 @@ defmodule Kernel.ParallelCompiler do
state = %{state | timer_ref: timer_ref}
spawn_workers(queue, spawned, waiting, files, result, warnings, errors, state)

{:diagnostic, %{severity: :warning} = diagnostic} ->
warnings = [Module.ParallelChecker.format_diagnostic_file(diagnostic) | warnings]
{:diagnostic, %{severity: :warning, file: file} = diagnostic, read_snippet} ->
:elixir_errors.print_diagnostic(diagnostic, read_snippet)
warnings = [%{diagnostic | file: file && Path.absname(file)} | warnings]
wait_for_messages(queue, spawned, waiting, files, result, warnings, errors, state)

{:diagnostic, %{severity: :error} = diagnostic} ->
errors = [Module.ParallelChecker.format_diagnostic_file(diagnostic) | errors]
{:diagnostic, %{severity: :error} = diagnostic, read_snippet} ->
errors = [{diagnostic, read_snippet} | errors]
wait_for_messages(queue, spawned, waiting, files, result, warnings, errors, state)

{:file_ok, child_pid, ref, file, lexical} ->
@@ -706,10 +712,13 @@ defmodule Kernel.ParallelCompiler do
spawn_workers(queue, new_spawned, waiting, new_files, result, warnings, errors, state)

{:file_error, child_pid, file, {kind, reason, stack}} ->
print_error(file, kind, reason, stack)
{_file, _new_spawned, new_files} = discard_file_pid(spawned, files, child_pid)
terminate(new_files)
{return_error([to_error(file, kind, reason, stack) | errors], warnings), state}

return_error(warnings, errors, state, fn ->
print_error(file, kind, reason, stack)
[to_error(file, kind, reason, stack)]
end)

{:DOWN, ref, :process, pid, reason} when is_map_key(spawned, ref) ->
# async spawned processes have no file, so we always have to delete the ref directly
@@ -718,18 +727,27 @@ defmodule Kernel.ParallelCompiler do
{file, spawned, files} = discard_file_pid(spawned, files, pid)

if file do
print_error(file.file, :exit, reason, [])
terminate(files)
{return_error([to_error(file.file, :exit, reason, []) | errors], warnings), state}

return_error(warnings, errors, state, fn ->
print_error(file.file, :exit, reason, [])
[to_error(file.file, :exit, reason, [])]
end)
else
wait_for_messages(queue, spawned, waiting, files, result, warnings, errors, state)
end
end
end

defp return_error(errors, warnings) do
defp return_error(warnings, errors, state, fun) do
errors =
Enum.map(errors, fn {%{file: file} = diagnostic, read_snippet} ->
:elixir_errors.print_diagnostic(diagnostic, read_snippet)
%{diagnostic | file: file && Path.absname(file)}
end)

info = %{compile_warnings: Enum.reverse(warnings), runtime_warnings: []}
{:error, Enum.reverse(errors), info}
{{:error, Enum.reverse(errors, fun.()), info}, state}
end

defp update_result(result, kind, module, value) do
13 changes: 8 additions & 5 deletions lib/elixir/lib/macro.ex
Original file line number Diff line number Diff line change
@@ -115,7 +115,7 @@ defmodule Macro do
* `:from_brackets` - Used to determine whether a call to `Access.get/3` is from
bracket syntax.
* `:from_interpolation` - Used to determine whether a call to `Access.get/3` is
* `:from_interpolation` - Used to determine whether a call to `Kernel.to_string/1` is
from interpolation.
* `:generated` - Whether the code should be considered as generated by
@@ -136,8 +136,9 @@ defmodule Macro do
* `:closing` - contains metadata about the closing pair, such as a `}`
in a tuple or in a map, or such as the closing `)` in a function call
with parens. The `:closing` does not delimit the end of expression if
there are `:do` and `:end` metadata (when `:token_metadata` is true)
with parens (when `:token_metadata` is true). If the function call
has a do-end block attached to it, its metadata is found under the
`:do` and `:end` metadata
* `:column` - the column number of the AST node (when `:columns` is true).
Note column information is always discarded from quoted code.
@@ -154,8 +155,10 @@ defmodule Macro do
`do`-`end` blocks (when `:token_metadata` is true)
* `:end_of_expression` - denotes when the end of expression effectively
happens. Available for all expressions except the last one inside a
`__block__` (when `:token_metadata` is true)
happens (when `:token_metadata` is true). This is only available for
direct children of a `__block__`, and it is either the location of a
newline or of the `;` character. The last expression of `__block__`
does not have this metadata.
* `:indentation` - indentation of a sigil heredoc
10 changes: 3 additions & 7 deletions lib/elixir/lib/module/parallel_checker.ex
Original file line number Diff line number Diff line change
@@ -167,8 +167,9 @@ defmodule Module.ParallelChecker do

defp collect_results(count, diagnostics) do
receive do
{:diagnostic, diagnostic} ->
diagnostic = format_diagnostic_file(diagnostic)
{:diagnostic, %{file: file} = diagnostic, read_snippet} ->
:elixir_errors.print_diagnostic(diagnostic, read_snippet)
diagnostic = %{diagnostic | file: file && Path.absname(file)}
collect_results(count, [diagnostic | diagnostics])

{__MODULE__, _module, new_diagnostics} ->
@@ -287,11 +288,6 @@ defmodule Module.ParallelChecker do
end
end

@doc false
def format_diagnostic_file(%{file: file} = diagnostic) do
%{diagnostic | file: file && Path.absname(file)}
end

## Warning helpers

defp group_warnings(warnings) do
1 change: 1 addition & 0 deletions lib/elixir/lib/string.ex
Original file line number Diff line number Diff line change
@@ -966,6 +966,7 @@ defmodule String do

def capitalize(string, mode) when is_binary(string) do
case :unicode_util.gc(string) do
[gc] -> grapheme_to_binary(:string.titlecase([gc]))
[gc, rest] -> grapheme_to_binary(:string.titlecase([gc])) <> downcase(rest, mode)
[gc | rest] -> grapheme_to_binary(:string.titlecase([gc])) <> downcase(rest, mode)
[] -> ""
22 changes: 12 additions & 10 deletions lib/elixir/pages/anti-patterns/code-anti-patterns.md
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

This document outlines potential anti-patterns related to your code and particular Elixir idioms and features.

## Comments
## Comments overuse

#### Problem

@@ -251,7 +251,9 @@ end

#### Refactoring

To address this anti-pattern, related arguments can be grouped using maps, structs, or even tuples. This effectively reduces the number of arguments, simplifying the function's interface. In the case of `loan/6`, its arguments were grouped into two different maps, thereby reducing its arity to `loan/2`:
To address this anti-pattern, related arguments can be grouped using key-value data structures, such as maps, structs, or even keyword lists in the case of optional arguments. This effectively reduces the number of arguments and the key-value data structures adds clarity to the caller.

For this particular example, the arguments to `loan/6` can be grouped into two different maps, thereby reducing its arity to `loan/2`:

```elixir
defmodule Library do
@@ -315,7 +317,7 @@ When a key is expected to exist in a map, it must be accessed using the `map.key

When a key is optional, the `map[:key]` notation must be used instead. This way, if the informed key does not exist, `nil` is returned. This is the dynamic notation, as it also supports dynamic key access, such as `map[some_var]`.

When you use `map[:key]` to access a key that always exists in the map, you are making the code less clear for developers and for the compiler, as they now need to work with the assumption the key may not be there. This mismatch may also make it harder to track certain bugs. If the key is unexpected missing, you will have a `nil` value propagate through the system, instead of raising on map access.
When you use `map[:key]` to access a key that always exists in the map, you are making the code less clear for developers and for the compiler, as they now need to work with the assumption the key may not be there. This mismatch may also make it harder to track certain bugs. If the key is unexpectedly missing, you will have a `nil` value propagate through the system, instead of raising on map access.

#### Example

@@ -370,7 +372,7 @@ iex> Graphics.plot(point_2d)
{2, 3, nil}
iex> Graphics.plot(bad_point)
** (KeyError) key :x not found in: %{y: 3, z: 4} # <= explicitly warns that
graphic.ex:4: Graphics.plot/1 # <= the :z key does not exist!
graphic.ex:4: Graphics.plot/1 # <= the :x key does not exist!
```

Overall, the usage of `map.key` and `map[:key]` encode important information about your data structure, allowing developers to be clear about their intent. See both `Map` and `Access` module documentation for more information and examples.
@@ -379,17 +381,17 @@ An alternative to refactor this anti-pattern is to use pattern matching, definin

```elixir
defmodule Graphics do
# 2d
def plot(%{x: x, y: y}) do
# Some other code...
{x, y}
end

# 3d
def plot(%{x: x, y: y, z: z}) do
# Some other code...
{x, y, z}
end

# 2d
def plot(%{x: x, y: y}) do
# Some other code...
{x, y}
end
end
```

Loading