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.14.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.14.1
Choose a head ref

Commits on Sep 1, 2022

  1. Fix date

    josevalim committed Sep 1, 2022
    Copy the full SHA
    cfb51e3 View commit details

Commits on Sep 2, 2022

  1. Copy the full SHA
    62ec71a View commit details

Commits on Sep 4, 2022

  1. Copy the full SHA
    b78b480 View commit details

Commits on Sep 5, 2022

  1. Copy the full SHA
    bd63670 View commit details

Commits on Sep 6, 2022

  1. Copy the full SHA
    1457728 View commit details

Commits on Sep 7, 2022

  1. Copy the full SHA
    efcb90b View commit details
  2. Copy the full SHA
    d105533 View commit details
  3. Copy the full SHA
    f0943e7 View commit details

Commits on Sep 9, 2022

  1. Copy the full SHA
    d11d619 View commit details
  2. Fix bootstrap

    josevalim committed Sep 9, 2022
    Copy the full SHA
    d84f889 View commit details

Commits on Sep 14, 2022

  1. Add :close_stdin to System.shell/2

    It defaults to false as that was the behaviour
    in past Elixir versions.
    
    Closes #12135.
    josevalim committed Sep 14, 2022
    Copy the full SHA
    d600406 View commit details

Commits on Sep 15, 2022

  1. Copy the full SHA
    3f2ded0 View commit details
  2. Copy the full SHA
    1c39141 View commit details

Commits on Sep 16, 2022

  1. Copy the full SHA
    887e218 View commit details

Commits on Sep 23, 2022

  1. Copy the full SHA
    41fa1db View commit details
  2. Copy the full SHA
    7f494e6 View commit details
  3. Copy the full SHA
    78d6b88 View commit details

Commits on Sep 30, 2022

  1. Copy the full SHA
    87dc792 View commit details
  2. mix format

    josevalim committed Sep 30, 2022
    Copy the full SHA
    61b2601 View commit details

Commits on Oct 2, 2022

  1. Copy the full SHA
    e62a2d7 View commit details

Commits on Oct 3, 2022

  1. Copy the full SHA
    c2426ce View commit details
  2. Copy the full SHA
    f6f4f81 View commit details

Commits on Oct 4, 2022

  1. Copy the full SHA
    375f2bd View commit details
  2. Copy the full SHA
    7e76039 View commit details
  3. Copy the full SHA
    b213013 View commit details

Commits on Oct 5, 2022

  1. Copy the full SHA
    278eba5 View commit details

Commits on Oct 7, 2022

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

    josevalim committed Oct 7, 2022
    Copy the full SHA
    fd97c2f View commit details
  3. Copy the full SHA
    5f20a94 View commit details

Commits on Oct 8, 2022

  1. Copy the full SHA
    b5941d2 View commit details
  2. Copy the full SHA
    ee602cd View commit details

Commits on Oct 10, 2022

  1. Copy the full SHA
    bc936f7 View commit details
  2. Release v1.14.1

    josevalim committed Oct 10, 2022
    Copy the full SHA
    a285e58 View commit details
Showing with 685 additions and 334 deletions.
  1. +42 −2 CHANGELOG.md
  2. +1 −1 VERSION
  3. +3 −3 bin/elixir
  4. +1 −1 bin/elixir.bat
  5. +2 −2 lib/elixir/lib/application.ex
  6. +6 −0 lib/elixir/lib/calendar/datetime.ex
  7. +9 −5 lib/elixir/lib/code.ex
  8. +9 −1 lib/elixir/lib/code/normalizer.ex
  9. +21 −23 lib/elixir/lib/kernel.ex
  10. +11 −4 lib/elixir/lib/kernel/utils.ex
  11. +82 −19 lib/elixir/lib/macro.ex
  12. +5 −1 lib/elixir/lib/module.ex
  13. +20 −8 lib/elixir/lib/module/parallel_checker.ex
  14. +11 −7 lib/elixir/lib/module/types.ex
  15. +10 −6 lib/elixir/lib/module/types/expr.ex
  16. +6 −31 lib/elixir/lib/module/types/unify.ex
  17. +1 −1 lib/elixir/lib/protocol.ex
  18. +1 −1 lib/elixir/lib/range.ex
  19. +3 −2 lib/elixir/lib/string.ex
  20. +10 −3 lib/elixir/lib/system.ex
  21. +1 −1 lib/elixir/lib/uri.ex
  22. +5 −6 lib/elixir/src/elixir_erl_for.erl
  23. +1 −7 lib/elixir/src/elixir_erl_pass.erl
  24. +70 −52 lib/elixir/src/elixir_expand.erl
  25. +7 −1 lib/elixir/src/elixir_map.erl
  26. +9 −0 lib/elixir/test/elixir/calendar/datetime_test.exs
  27. +7 −0 lib/elixir/test/elixir/code_normalizer/quoted_ast_test.exs
  28. +30 −0 lib/elixir/test/elixir/kernel/comprehension_test.exs
  29. +17 −0 lib/elixir/test/elixir/kernel/errors_test.exs
  30. +3 −2 lib/elixir/test/elixir/kernel/expansion_test.exs
  31. +13 −1 lib/elixir/test/elixir/kernel/lexical_tracker_test.exs
  32. +20 −3 lib/elixir/test/elixir/macro_test.exs
  33. +4 −0 lib/elixir/test/elixir/map_test.exs
  34. +0 −19 lib/elixir/test/elixir/module/types/pattern_test.exs
  35. +19 −60 lib/elixir/test/elixir/module/types/types_test.exs
  36. +82 −1 lib/elixir/test/elixir/string_test.exs
  37. +1 −1 lib/elixir/test/elixir/system_test.exs
  38. +25 −0 lib/elixir/test/elixir/uri_test.exs
  39. +5 −2 lib/ex_unit/lib/ex_unit/callbacks.ex
  40. +1 −1 lib/ex_unit/lib/ex_unit/doc_test.ex
  41. +4 −1 lib/ex_unit/test/ex_unit/doc_test_test.exs
  42. +15 −13 lib/iex/lib/iex/broker.ex
  43. +22 −14 lib/iex/lib/iex/cli.ex
  44. +4 −0 lib/mix/lib/mix/task.compiler.ex
  45. +0 −1 lib/mix/lib/mix/tasks/compile.elixir.ex
  46. +1 −0 lib/mix/lib/mix/tasks/compile.ex
  47. +27 −24 lib/mix/lib/mix/tasks/format.ex
  48. +3 −0 lib/mix/lib/mix/tasks/test.ex
  49. +34 −3 lib/mix/test/mix/tasks/format_test.exs
  50. +1 −0 lib/mix/test/mix/tasks/test_test.exs
  51. BIN tmp/SystemTest/test-Unix-cmd-3-with-absolute-and-relative-paths-f3bf3544/echo-elixir-test
44 changes: 42 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -241,7 +241,47 @@ protocol, giving developers more control over the struct representation.
See the updated documentation for `Inspect` for a general rundown on
the approaches and options available.

## v1.14.0 (2022-08-31)
## v1.14.1 (2022-10-10)

### 1. Enhancements

#### Elixir

* [Kernel] Perform partial expansion of literals in module attributes
* [Kernel] Do not add compile-time dependencies for literals as defaults in `Application.compile_env/3` inside module attributes
* [Macro] Add `Macro.expand_literals/2` and `Macro.expand_literals/3`
* [System] Add `:close_stdin` to `System.shell/2`

#### Mix

* [mix test] Accept `--all-warnings` option

## 2. Bug fixes

#### Elixir

* [Kernel] Fix misleading warning when `:uniq` is given in `for` comprehensions and the result is unused
* [Kernel] Improve error message for when there is a conflicting struct and ignoring module conflict
* [Kernel] Do not delete `@enforce_keys` attribute after `defstruct` declaration
* [Kernel] Do not crash the checker on modules with missing `:debug_info` chunk
* [Macro] Fix error in `Macro.to_string/2` when converting an AST with `:erlang.binary_to_atom/2`
* [String] Fix `String.split/3` and `String.next_grapheme/1` returning invalid results on invalid UTF-8 encoding
* [System] Do not close stdin by default in `System.shell/2`
* [URI] Do not return `uri.port` as `:undefined` in certain cases in `URI.new/1`

#### ExUnit

* [ExUnit.DocTest] Do not crash when both `:moduledoc` and functions are specified in `:only`

#### IEx

* [CLI] Fix invalid argument handling when `--no-pry` is given

#### Mix

* [mix format] Do not cache inputs from `.formatter.exs` so they are properly re-evaluted on every call

## v1.14.0 (2022-09-01)

### 1. Enhancements

@@ -287,7 +327,7 @@ the approaches and options available.
* [Keyword] Add `Keyword.from_keys/2` and `Keyword.replace_lazy/3`
* [List] Add `List.keysort/3` with support for a `sorter` function
* [Macro] Add `Macro.classify_atom/1` and `Macro.inspect_atom/2`
* [Macro] Add `Macro.expand_literal/2` and `Macro.path/2`
* [Macro] Add `Macro.path/2`
* [Macro.Env] Add `Macro.Env.prune_compile_info/1`
* [Map] Add `Map.from_keys/2` and `Map.replace_lazy/3`
* [MapSet] Add `MapSet.filter/2`, `MapSet.reject/2`, and `MapSet.symmetric_difference/2`
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.14.0
1.14.1
6 changes: 3 additions & 3 deletions bin/elixir
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/sh
set -e

ELIXIR_VERSION=1.14.0
ELIXIR_VERSION=1.14.1

if [ $# -eq 0 ] || { [ $# -eq 1 ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; }; then
cat <<USAGE >&2
@@ -112,10 +112,10 @@ while [ $I -le $LENGTH ]; do
C=1
MODE="elixirc"
;;
-v|--no-halt)
-v|--no-halt|--no-pry)
C=1
;;
-e|-r|-pr|-pa|-pz|--app|--eval|--remsh|--dot-iex|--no-pry)
-e|-r|-pr|-pa|-pz|--app|--eval|--remsh|--dot-iex)
C=2
;;
--rpc-eval)
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.14.0
set ELIXIR_VERSION=1.14.1

setlocal enabledelayedexpansion
if ""%1""=="""" if ""%2""=="""" goto documentation
4 changes: 2 additions & 2 deletions lib/elixir/lib/application.ex
Original file line number Diff line number Diff line change
@@ -532,7 +532,7 @@ defmodule Application do
raise "Application.compile_env/3 cannot be called inside functions, only in the module body"
end

key_or_path = Macro.expand_literal(key_or_path, %{__CALLER__ | function: {:__info__, 1}})
key_or_path = Macro.expand_literals(key_or_path, %{__CALLER__ | function: {:__info__, 1}})

quote do
Application.compile_env(__ENV__, unquote(app), unquote(key_or_path), unquote(default))
@@ -572,7 +572,7 @@ defmodule Application do
raise "Application.compile_env!/2 cannot be called inside functions, only in the module body"
end

key_or_path = Macro.expand_literal(key_or_path, %{__CALLER__ | function: {:__info__, 1}})
key_or_path = Macro.expand_literals(key_or_path, %{__CALLER__ | function: {:__info__, 1}})

quote do
Application.compile_env!(__ENV__, unquote(app), unquote(key_or_path))
6 changes: 6 additions & 0 deletions lib/elixir/lib/calendar/datetime.ex
Original file line number Diff line number Diff line change
@@ -1529,6 +1529,12 @@ defmodule DateTime do
microsecond: {_, precision}
} = datetime

if not is_integer(unit) and
unit not in ~w(second millisecond microsecond nanosecond)a do
raise ArgumentError,
"unsupported time unit. Expected :day, :hour, :minute, :second, :millisecond, :microsecond, :nanosecond, or a positive integer, got #{inspect(unit)}"
end

ppd = System.convert_time_unit(86400, :second, unit)
total_offset = System.convert_time_unit(utc_offset + std_offset, :second, unit)

14 changes: 9 additions & 5 deletions lib/elixir/lib/code.ex
Original file line number Diff line number Diff line change
@@ -1334,12 +1334,16 @@ defmodule Code do
Available options are:
* `:docs` - when `true`, retain documentation in the compiled module.
* `:docs` - when `true`, retains documentation in the compiled module.
Defaults to `true`.
* `:debug_info` - when `true`, retain debug information in the compiled
module. This allows a developer to reconstruct the original source
code. Defaults to `true`.
* `:debug_info` - when `true`, retains debug information in the compiled
module. This enables static analysis tools as it allows developers to
partially reconstruct the original source code. Therefore, disabling
`:debug_info` is not recommended as it removes the ability of the
Elixir compiler and other tools to provide feedback. If you want to
remove the `:debug_info` while deploying, tools like `mix release`
already do such by default.
* `:ignore_already_consolidated` - when `true`, does not warn when a protocol
has already been consolidated and a new implementation is added. Defaults
@@ -1348,7 +1352,7 @@ defmodule Code do
* `:ignore_module_conflict` - when `true`, does not warn when a module has
already been defined. Defaults to `false`.
* `:relative_paths` - when `true`, use relative paths in quoted nodes,
* `:relative_paths` - when `true`, uses relative paths in quoted nodes,
warnings, and errors generated by the compiler. Note disabling this option
won't affect runtime warnings and errors. Defaults to `true`.
10 changes: 9 additions & 1 deletion lib/elixir/lib/code/normalizer.ex
Original file line number Diff line number Diff line change
@@ -77,14 +77,22 @@ defmodule Code.Normalizer do
dot_meta = patch_meta_line(dot_meta, state.parent_meta)
call_meta = patch_meta_line(call_meta, dot_meta)

utf8 =
if args == [] or interpolated?(string) do
# a non-normalized :utf8 atom signals an atom interpolation
:utf8
else
normalize_literal(:utf8, [], state)
end

string =
if state.escape do
normalize_bitstring(string, state, true)
else
normalize_bitstring(string, state)
end

{{:., dot_meta, [:erlang, :binary_to_atom]}, call_meta, [string, :utf8]}
{{:., dot_meta, [:erlang, :binary_to_atom]}, call_meta, [string, utf8]}
end

# Charlists with interpolations
44 changes: 21 additions & 23 deletions lib/elixir/lib/kernel.ex
Original file line number Diff line number Diff line change
@@ -3590,33 +3590,31 @@ defmodule Kernel do
defp collect_traces(:after_verify, arg, _env), do: {arg, []}
defp collect_traces(:on_definition, arg, _env), do: {arg, []}

defp collect_traces(_name, arg, env) do
case is_pid(env.lexical_tracker) and Macro.quoted_literal?(arg) do
true ->
env = %{env | function: {:__info__, 1}}

{arg, aliases} =
Macro.prewalk(arg, %{}, fn
{:__aliases__, _, _} = alias, acc ->
case Macro.expand(alias, env) do
atom when is_atom(atom) -> {atom, Map.put(acc, atom, [])}
_ -> {alias, acc}
end

node, acc ->
{node, acc}
end)
defp collect_traces(_name, arg, %{lexical_tracker: pid} = env) when is_pid(pid) do
env = %{env | function: {:__info__, 1}}

{arg, aliases} =
Macro.expand_literals(arg, %{}, fn
{:__aliases__, _, _} = alias, acc ->
case Macro.expand(alias, env) do
atom when is_atom(atom) -> {atom, Map.put(acc, atom, [])}
_ -> {alias, acc}
end

case map_size(aliases) do
0 -> {arg, []}
_ -> {arg, [{env.line, env.lexical_tracker, env.tracers, :maps.keys(aliases)}]}
end
node, acc ->
{Macro.expand(node, env), acc}
end)

false ->
{arg, []}
case map_size(aliases) do
0 -> {arg, []}
_ -> {arg, [{env.line, env.lexical_tracker, env.tracers, :maps.keys(aliases)}]}
end
end

defp collect_traces(_name, arg, _env) do
{arg, []}
end

defp typespec?(:type), do: true
defp typespec?(:typep), do: true
defp typespec?(:opaque), do: true
@@ -5746,7 +5744,7 @@ defmodule Kernel do
"""
defmacro defdelegate(funs, opts) do
funs = Macro.escape(funs, unquote: true)
opts = Macro.expand_literal(opts, %{__CALLER__ | function: {:__info__, 1}})
opts = Macro.expand_literals(opts, %{__CALLER__ | function: {:__info__, 1}})

quote bind_quoted: [funs: funs, opts: opts] do
target = Kernel.Utils.defdelegate_all(funs, opts, __ENV__)
15 changes: 11 additions & 4 deletions lib/elixir/lib/kernel/utils.ex
Original file line number Diff line number Diff line change
@@ -138,10 +138,17 @@ defmodule Kernel.Utils do
fields = :lists.map(mapper, fields)

enforce_keys =
case :ets.take(set, :enforce_keys) do
[{_, enforce_keys, _, _}] when is_list(enforce_keys) -> enforce_keys
[{_, enforce_key, _, _}] -> [enforce_key]
[] -> []
case :ets.lookup(set, :enforce_keys) do
[{_, enforce_keys, _, _}] when is_list(enforce_keys) ->
:ets.update_element(set, :enforce_keys, {3, :used})
enforce_keys

[{_, enforce_key, _, _}] ->
:ets.update_element(set, :enforce_keys, {3, :used})
[enforce_key]

[] ->
[]
end

# TODO: Make it raise on v2.0
101 changes: 82 additions & 19 deletions lib/elixir/lib/macro.ex
Original file line number Diff line number Diff line change
@@ -1966,42 +1966,105 @@ defmodule Macro do

def quoted_literal?({:%{}, _, args}), do: quoted_literal?(args)
def quoted_literal?({:{}, _, args}), do: quoted_literal?(args)
def quoted_literal?({:__MODULE__, _, ctx}) when is_atom(ctx), do: true
def quoted_literal?({left, right}), do: quoted_literal?(left) and quoted_literal?(right)
def quoted_literal?(list) when is_list(list), do: :lists.all(&quoted_literal?/1, list)
def quoted_literal?(term), do: is_atom(term) or is_number(term) or is_binary(term)

@doc """
Expands the `ast` representing a quoted literal within the given `env`.
@doc false
@deprecated "Use Macro.expand_literals/2 instead"
def expand_literal(ast, env) do
expand_literals(ast, env)
end

This function checks if the given AST represents a quoted literal
(using `quoted_literal?/1`) and then expands all relevant nodes.
If a literal node is not given, then it returns the AST as is.
At the moment, the only expandable literal nodes in an AST are
aliases, so this function only expands aliases.
@doc """
Expands all literals in `ast` with the given `env`.
This function is mostly used to remove compile-time dependencies
from AST nodes. In such cases, the given environment is usually
manipulate to represent a function:
manipulated to represent a function:
Macro.expand_literal(ast, %{env | function: {:my_code, 1}})
Macro.expand_literals(ast, %{env | function: {:my_code, 1}})
At the moment, the only expandable literal nodes in an AST are
aliases, so this function only expands aliases.
However, be careful when removing compile-time dependencies between
modules. If you remove them but you still invoke the module at
compile-time, you may end-up with broken behaviour.
compile-time, Elixir will be unable to properly recompile modules
when they change.
"""
@doc since: "1.14.0"
@spec expand_literal(t(), Macro.Env.t()) :: t()
def expand_literal(ast, env) do
if quoted_literal?(ast) do
prewalk(ast, fn
{:__aliases__, _, _} = alias -> expand(alias, env)
other -> other
end)
@doc since: "1.14.1"
@spec expand_literals(t(), Macro.Env.t()) :: t()
def expand_literals(ast, env) do
{ast, :ok} = expand_literals(ast, :ok, fn node, :ok -> {expand(node, env), :ok} end)
ast
end

@doc """
Expands all literals in `ast` with the given `acc` and `fun`.
`fun` will be invoked with an expandable AST node and `acc` and
must return a new node with `acc`. This is a general version of
`expand_literals/2` which supports a custom expansion function.
Please check `expand_literals/2` for use cases and pitfalls.
"""
@doc since: "1.14.1"
@spec expand_literals(t(), acc, (t(), acc -> {t(), acc})) :: t() when acc: term()
def expand_literals(ast, acc, fun)

def expand_literals({:__aliases__, meta, args}, acc, fun) do
{args, acc} = expand_literals(args, acc, fun)

if :lists.all(&is_atom/1, args) do
fun.({:__aliases__, meta, args}, acc)
else
ast
{{:__aliases__, meta, args}, acc}
end
end

def expand_literals({:__MODULE__, _meta, ctx} = node, acc, fun) when is_atom(ctx) do
fun.(node, acc)
end

def expand_literals({:%, meta, [left, right]}, acc, fun) do
{left, acc} = expand_literals(left, acc, fun)
{right, acc} = expand_literals(right, acc, fun)
{{:%, meta, [left, right]}, acc}
end

def expand_literals({:%{}, meta, args}, acc, fun) do
{args, acc} = expand_literals(args, acc, fun)
{{:%{}, meta, args}, acc}
end

def expand_literals({:{}, meta, args}, acc, fun) do
{args, acc} = expand_literals(args, acc, fun)
{{:{}, meta, args}, acc}
end

def expand_literals({left, right}, acc, fun) do
{left, acc} = expand_literals(left, acc, fun)
{right, acc} = expand_literals(right, acc, fun)
{{left, right}, acc}
end

def expand_literals(list, acc, fun) when is_list(list) do
:lists.mapfoldl(&expand_literals(&1, &2, fun), acc, list)
end

def expand_literals(
{{:., _, [{:__aliases__, _, [:Application]}, :compile_env]} = node, meta,
[app, key, default]},
acc,
fun
) do
{default, acc} = expand_literals(default, acc, fun)
{{node, meta, [app, key, default]}, acc}
end

def expand_literals(term, acc, _fun), do: {term, acc}

@doc """
Receives an AST node and expands it until it can no longer
be expanded.
Loading