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.2
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.3
Choose a head ref

Commits on Nov 11, 2022

  1. Copy the full SHA
    e3fc947 View commit details

Commits on Nov 15, 2022

  1. Verified

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

Commits on Nov 17, 2022

  1. Verified

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

Commits on Nov 19, 2022

  1. Fix unused for optimization (#12252)

    sabiwara authored and josevalim committed Nov 19, 2022

    Verified

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

Commits on Nov 20, 2022

  1. Fix wildcard edge case (#12255)

    NickNeck authored and josevalim committed Nov 20, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    abe2af4 View commit details

Commits on Nov 23, 2022

  1. Copy the full SHA
    bfa799b View commit details
  2. Copy the full SHA
    94e0e38 View commit details
  3. Copy the full SHA
    80564fc View commit details

Commits on Nov 24, 2022

  1. Copy the full SHA
    950bcc0 View commit details

Commits on Dec 1, 2022

  1. Copy the full SHA
    ff73830 View commit details

Commits on Dec 4, 2022

  1. Copy the full SHA
    a1a37c6 View commit details

Commits on Dec 5, 2022

  1. Fix Range.disjoint?/2

    josevalim committed Dec 5, 2022
    Copy the full SHA
    a72f18b View commit details
  2. Ensure all runtime_modules loaded before mapping their paths (#12287)

    Co-authored-by: Alex Naser <alex.naser@remote.com>
    2 people authored and josevalim committed Dec 5, 2022
    Copy the full SHA
    a8aea1c View commit details

Commits on Dec 8, 2022

  1. Revert "Ensure all runtime_modules loaded before mapping their paths (#…

    …12287)"
    
    We don't want to load all modules because some may be
    specified as `@compile {:autoload, false}`.
    
    This reverts commit a8aea1c.
    josevalim committed Dec 8, 2022
    Copy the full SHA
    71d2791 View commit details
  2. Precompile runtime module paths (#12294)

    Co-authored-by: José Valim <jose.valim@dashbit.co>
    naserca and josevalim authored Dec 8, 2022
    Copy the full SHA
    6549d20 View commit details

Commits on Dec 12, 2022

  1. Copy the full SHA
    ec31cc2 View commit details

Commits on Dec 18, 2022

  1. Copy the full SHA
    5a583c7 View commit details

Commits on Jan 6, 2023

  1. Copy the full SHA
    2146bb4 View commit details

Commits on Jan 10, 2023

  1. Copy the full SHA
    ff2ea69 View commit details

Commits on Jan 14, 2023

  1. Copy the full SHA
    fb4ccfa View commit details
  2. Release v1.14.3

    josevalim committed Jan 14, 2023
    Copy the full SHA
    6730d66 View commit details
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -241,6 +241,37 @@ 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.3 (2023-01-14)

### 1. Enhancements

#### Elixir

* [Kernel] Speed up loading of runtime modules in the parallel compiler
* [Range] Optimize range membership implementation

#### ExUnit

* [ExUnit] Return values from running doctests and make their order consistent

### 2. Bug fixes

#### Elixir

* [Calendar] Fix handling of negative years in `Calendar.strftime/2`
* [Exception] Improve blaming of FunctionClauseError with `is_struct/2` guards
* [Kernel] Fix invalid variable scoping in `defguard` expansion
* [Kernel] Do not warn on captured underscored vars from `defmodule`
* [Kernel] Do not crash for missing line info on type warnings
* [Macro] Fix `Macro.to_string/1` for large negative integers
* [Macro] Properly type and escape expansion of `__ENV__` in macros
* [Path] Make sure `Path.wildcard/2` expands `..` symlinks accordingly
* [Range] Address corner cases in `Range.disjoint?/2` implementation

#### ExUnit

* [ExUnit.DocTest] Remove unnecessary literal quotes from error message on reports

## v1.14.2 (2022-11-11)

### 1. Enhancements
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.14.2
1.14.3
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.14.2
ELIXIR_VERSION=1.14.3

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.14.2
set ELIXIR_VERSION=1.14.3

setlocal enabledelayedexpansion
if ""%1""=="""" if ""%2""=="""" goto documentation
9 changes: 8 additions & 1 deletion lib/elixir/lib/calendar.ex
Original file line number Diff line number Diff line change
@@ -791,7 +791,14 @@ defmodule Calendar do

# Year
defp format_modifiers("Y" <> rest, width, pad, datetime, format_options, acc) do
result = datetime.year |> Integer.to_string() |> pad_leading(width, pad)
{sign, year} =
if datetime.year < 0 do
{?-, -datetime.year}
else
{[], datetime.year}
end

result = [sign | year |> Integer.to_string() |> pad_leading(width, pad)]
parse(rest, datetime, format_options, [result | acc])
end

8 changes: 8 additions & 0 deletions lib/elixir/lib/calendar/datetime.ex
Original file line number Diff line number Diff line change
@@ -1493,6 +1493,13 @@ defmodule DateTime do
iex> dt |> DateTime.add(1, :day, FakeTimeZoneDatabase)
#DateTime<2019-04-01 02:00:00+02:00 CEST Europe/Copenhagen>
This operation merges the precision of the naive date time with the given unit:
iex> result = DateTime.add(~U[2014-10-02 00:29:10Z], 21, :millisecond)
~U[2014-10-02 00:29:10.021Z]
iex> result.microsecond
{21000, 3}
"""
@doc since: "1.8.0"
@spec add(
@@ -1537,6 +1544,7 @@ defmodule DateTime do

ppd = System.convert_time_unit(86400, :second, unit)
total_offset = System.convert_time_unit(utc_offset + std_offset, :second, unit)
precision = max(Calendar.ISO.time_unit_to_precision(unit), precision)

result =
datetime
11 changes: 11 additions & 0 deletions lib/elixir/lib/calendar/iso.ex
Original file line number Diff line number Diff line change
@@ -247,6 +247,17 @@ defmodule Calendar.ISO do
defguardp is_utc_offset(offset) when is_integer(offset)
defguardp is_std_offset(offset) when is_integer(offset)

@doc """
Converts a `t:System.time_unit/0` to precision.
Integer-based time units always get maximum precision.
"""
def time_unit_to_precision(:nanosecond), do: 6
def time_unit_to_precision(:microsecond), do: 6
def time_unit_to_precision(:millisecond), do: 3
def time_unit_to_precision(:second), do: 0
def time_unit_to_precision(_), do: 6

@doc """
Parses a time `string` in the `:extended` format.
17 changes: 7 additions & 10 deletions lib/elixir/lib/calendar/naive_datetime.ex
Original file line number Diff line number Diff line change
@@ -379,7 +379,7 @@ defmodule NaiveDateTime do
It can also work with subsecond precisions:
iex> NaiveDateTime.add(~N[2014-10-02 00:29:10], 2_000, :millisecond)
~N[2014-10-02 00:29:12]
~N[2014-10-02 00:29:12.000]
As well as days/hours/minutes:
@@ -390,16 +390,12 @@ defmodule NaiveDateTime do
iex> NaiveDateTime.add(~N[2015-02-28 00:29:10], 60, :minute)
~N[2015-02-28 01:29:10]
This operation keeps the precision of the naive date time:
iex> NaiveDateTime.add(~N[2014-10-02 00:29:10.021], 21, :second)
~N[2014-10-02 00:29:31.021]
And ignores any changes below the precision:
This operation merges the precision of the naive date time with the given unit:
iex> hidden = NaiveDateTime.add(~N[2014-10-02 00:29:10], 21, :millisecond)
iex> hidden.microsecond # ~N[2014-10-02 00:29:10]
{21000, 0}
iex> result = NaiveDateTime.add(~N[2014-10-02 00:29:10], 21, :millisecond)
~N[2014-10-02 00:29:10.021]
iex> result.microsecond
{21000, 3}
Operations on top of gregorian seconds or the Unix epoch are optimized:
@@ -440,6 +436,7 @@ defmodule NaiveDateTime do
)
when is_integer(amount_to_add) do
ppd = System.convert_time_unit(86400, :second, unit)
precision = max(Calendar.ISO.time_unit_to_precision(unit), precision)

naive_datetime
|> to_iso_days()
12 changes: 10 additions & 2 deletions lib/elixir/lib/calendar/time.ex
Original file line number Diff line number Diff line change
@@ -493,6 +493,13 @@ defmodule Time do
iex> Time.add(~T[17:10:05], 30, :minute)
~T[17:40:05]
This operation merges the precision of the time with the given unit:
iex> result = Time.add(~T[00:29:10], 21, :millisecond)
~T[00:29:10.021]
iex> result.microsecond
{21000, 3}
"""
@doc since: "1.6.0"
@spec add(Calendar.time(), integer, :hour | :minute | System.time_unit()) :: t
@@ -511,6 +518,7 @@ defmodule Time do
amount_to_add = System.convert_time_unit(amount_to_add, unit, :microsecond)
total = time_to_microseconds(time) + amount_to_add
parts = Integer.mod(total, @parts_per_day)
precision = max(Calendar.ISO.time_unit_to_precision(unit), precision)

{hour, minute, second, {microsecond, _}} =
calendar.time_from_day_fraction({parts, @parts_per_day})
@@ -736,14 +744,14 @@ defmodule Time do
hour: hour1,
minute: minute1,
second: second1,
microsecond: {microsecond1, @parts_per_day}
microsecond: {microsecond1, _}
},
%{
calendar: Calendar.ISO,
hour: hour2,
minute: minute2,
second: second2,
microsecond: {microsecond2, @parts_per_day}
microsecond: {microsecond2, _}
},
unit
) do
4 changes: 4 additions & 0 deletions lib/elixir/lib/code/formatter.ex
Original file line number Diff line number Diff line change
@@ -1583,6 +1583,10 @@ defmodule Code.Formatter do
insert_underscores(int_part) <> "." <> decimal_part
end

defp insert_underscores("-" <> digits) do
"-" <> insert_underscores(digits)
end

defp insert_underscores(digits) do
cond do
digits =~ "_" ->
57 changes: 32 additions & 25 deletions lib/elixir/lib/code/normalizer.ex
Original file line number Diff line number Diff line change
@@ -70,15 +70,15 @@ defmodule Code.Normalizer do
# Atoms with interpolations
defp do_normalize(
{{:., dot_meta, [:erlang, :binary_to_atom]}, call_meta,
[{:<<>>, _, args} = string, :utf8]},
[{:<<>>, _, parts} = string, :utf8]},
state
)
when is_list(args) do
when is_list(parts) 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
if parts == [] or binary_interpolated?(parts) do
# a non-normalized :utf8 atom signals an atom interpolation
:utf8
else
@@ -96,23 +96,27 @@ defmodule Code.Normalizer do
end

# Charlists with interpolations
defp do_normalize({{:., dot_meta, [List, :to_charlist]}, call_meta, [parts]}, state) do
parts =
Enum.map(parts, fn
{{:., part_dot_meta, [Kernel, :to_string]}, part_call_meta, args} ->
args = normalize_args(args, state)

{{:., part_dot_meta, [Kernel, :to_string]}, part_call_meta, args}

part ->
if state.escape do
maybe_escape_literal(part, state)
else
part
end
end)
defp do_normalize({{:., dot_meta, [List, :to_charlist]}, call_meta, [parts]} = quoted, state) do
if list_interpolated?(parts) do
parts =
Enum.map(parts, fn
{{:., part_dot_meta, [Kernel, :to_string]}, part_call_meta, args} ->
args = normalize_args(args, state)

{{:., part_dot_meta, [Kernel, :to_string]}, part_call_meta, args}

part when is_binary(part) ->
if state.escape do
maybe_escape_literal(part, state)
else
part
end
end)

{{:., dot_meta, [List, :to_charlist]}, call_meta, [parts]}
{{:., dot_meta, [List, :to_charlist]}, call_meta, [parts]}
else
normalize_call(quoted, state)
end
end

# Don't normalize the `Access` atom in access syntax
@@ -389,11 +393,11 @@ defmodule Code.Normalizer do
defp allow_keyword?(:{}, _), do: false
defp allow_keyword?(op, arity), do: not is_atom(op) or not Macro.operator?(op, arity)

defp normalize_bitstring({:<<>>, meta, parts} = quoted, state, escape_interpolation \\ false) do
defp normalize_bitstring({:<<>>, meta, parts}, state, escape_interpolation \\ false) do
meta = patch_meta_line(meta, state.parent_meta)

parts =
if interpolated?(quoted) do
if binary_interpolated?(parts) do
normalize_interpolation_parts(parts, %{state | parent_meta: meta}, escape_interpolation)
else
state = %{state | parent_meta: meta}
@@ -543,17 +547,20 @@ defmodule Code.Normalizer do
term
end

# Check if we have an interpolated string.
defp interpolated?({:<<>>, _, [_ | _] = parts}) do
defp binary_interpolated?(parts) do
Enum.all?(parts, fn
{:"::", _, [{{:., _, [Kernel, :to_string]}, _, [_]}, {:binary, _, _}]} -> true
binary when is_binary(binary) -> true
_ -> false
end)
end

defp interpolated?(_) do
false
defp list_interpolated?(parts) do
Enum.all?(parts, fn
{{:., _, [Kernel, :to_string]}, _, [_]} -> true
binary when is_binary(binary) -> true
_ -> false
end)
end

defp patch_meta_line(meta, parent_meta) do
8 changes: 3 additions & 5 deletions lib/elixir/lib/exception.ex
Original file line number Diff line number Diff line change
@@ -294,13 +294,11 @@ defmodule Exception do
end
end

defp undo_is_struct_guard(
{:and, meta, [_, %{node: {_, _, [{_, _, [_, {struct, _, _}]} | optional]}}]}
) do
defp undo_is_struct_guard({:and, meta, [_, %{node: {_, _, [{_, _, [_, arg]} | optional]}}]}) do
args =
case optional do
[] -> [{struct, meta, nil}]
[module] -> [{struct, meta, nil}, module]
[] -> [arg]
[module] -> [arg, module]
end

%{match?: meta[:value], node: {:is_struct, meta, args}}
2 changes: 1 addition & 1 deletion lib/elixir/lib/kernel.ex
Original file line number Diff line number Diff line change
@@ -4806,7 +4806,7 @@ defmodule Kernel do
var_meta =
case prune do
true -> [generated: true, keep_unused: true]
false -> [generated: false]
false -> [generated: true]
end

module_vars = :lists.map(&module_var(&1, var_meta), :maps.keys(versioned_vars))
6 changes: 0 additions & 6 deletions lib/elixir/lib/kernel/parallel_compiler.ex
Original file line number Diff line number Diff line change
@@ -271,12 +271,6 @@ defmodule Kernel.ParallelCompiler do
for {{:module, module}, _} <- result,
do: module

runtime_modules =
for module <- runtime_modules,
path = :code.which(module),
is_list(path) and path != [],
do: {module, path}

profile_checker(profile, compiled_modules, runtime_modules, fn ->
Module.ParallelChecker.verify(checker, runtime_modules)
end)
6 changes: 3 additions & 3 deletions lib/elixir/lib/kernel/utils.ex
Original file line number Diff line number Diff line change
@@ -331,7 +331,7 @@ defmodule Kernel.Utils do
quote do
case Macro.Env.in_guard?(__CALLER__) do
true -> unquote(literal_quote(unquote_every_ref(expr, vars)))
false -> unquote(literal_quote(unquote_refs_once(expr, vars)))
false -> unquote(literal_quote(unquote_refs_once(expr, vars, env.module)))
end
end
end
@@ -361,7 +361,7 @@ defmodule Kernel.Utils do
end

# Prefaces `guard` with unquoted versions of `refs`.
defp unquote_refs_once(guard, refs) do
defp unquote_refs_once(guard, refs, module) do
{guard, used_refs} =
Macro.postwalk(guard, %{}, fn
{ref, meta, context} = var, acc when is_atom(ref) and is_atom(context) ->
@@ -375,7 +375,7 @@ defmodule Kernel.Utils do

%{} ->
generated = String.to_atom("arg" <> Integer.to_string(map_size(acc) + 1))
new_var = Macro.unique_var(generated, Elixir)
new_var = Macro.unique_var(generated, module)
{new_var, Map.put(acc, pair, {new_var, var})}
end

Loading