Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package elixir for openSUSE:Factory checked in at 2022-02-27 22:42:57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/elixir (Old) and /work/SRC/openSUSE:Factory/.elixir.new.1958 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "elixir" Sun Feb 27 22:42:57 2022 rev:21 rq:957806 version:1.13.3 Changes: -------- --- /work/SRC/openSUSE:Factory/elixir/elixir.changes 2022-01-17 22:35:00.602282039 +0100 +++ /work/SRC/openSUSE:Factory/.elixir.new.1958/elixir.changes 2022-02-27 22:43:21.294635008 +0100 @@ -1,0 +2,25 @@ +Tue Feb 22 20:01:32 UTC 2022 - Fabrizio Sestito <[email protected]> + +- Elixir 1.13.3 + * 1. Enhancements + Mix + + [mix format] Supply file and line to formatter plugins + [mix format] Support embedded Elixir expressions inside formatter plugins + + * 2. Bug fixes + Elixir + + [Code] Fix duplicate bindings causing errors during evaluation + [Kernel] Make sure signatures stored in the Documentation chunk does not contain newlines + [Kernel] Fix infinite loop when compiling guards with recursive map access + [Macro] Fix error on Macro.to_string/1 when the plain alias Elixir is given + [String] Fix error for certain codepoint combinations in String.split_at/2 + + Mix + + [mix compile] Recompile project files when exports from dependencies change + [mix test] Fix total coverage always showing in red even when above the threshold + + +------------------------------------------------------------------- Old: ---- elixir-1.13.2.tar.gz New: ---- elixir-1.13.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ elixir-doc.spec ++++++ --- /var/tmp/diff_new_pack.zGzCHS/_old 2022-02-27 22:43:21.842635168 +0100 +++ /var/tmp/diff_new_pack.zGzCHS/_new 2022-02-27 22:43:21.850635169 +0100 @@ -17,7 +17,7 @@ Name: elixir-doc -Version: 1.13.2 +Version: 1.13.3 Release: 0 Summary: Documentation for elixir License: Apache-2.0 elixir.spec: same change ++++++ elixir-1.13.2.tar.gz -> elixir-1.13.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/CHANGELOG.md new/elixir-1.13.3/CHANGELOG.md --- old/elixir-1.13.2/CHANGELOG.md 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/CHANGELOG.md 2022-02-09 16:26:17.000000000 +0100 @@ -128,6 +128,30 @@ 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.3 (2022-02-09) + +### 1. Enhancements + +#### Mix + + * [mix format] Supply file and line to formatter plugins + * [mix format] Support embedded Elixir expressions inside formatter plugins + +### 2. Bug fixes + +#### Elixir + + * [Code] Fix duplicate bindings causing errors during evaluation + * [Kernel] Make sure signatures stored in the Documentation chunk does not contain newlines + * [Kernel] Fix infinite loop when compiling guards with recursive map access + * [Macro] Fix error on `Macro.to_string/1` when the plain alias `Elixir` is given + * [String] Fix error for certain codepoint combinations in `String.split_at/2` + +#### Mix + + * [mix compile] Recompile project files when exports from dependencies change + * [mix test] Fix total coverage always showing in red even when above the threshold + ## v1.13.2 (2022-01-13) ### 1. Enhancements diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/VERSION new/elixir-1.13.3/VERSION --- old/elixir-1.13.2/VERSION 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/VERSION 2022-02-09 16:26:17.000000000 +0100 @@ -1 +1 @@ -1.13.2 \ No newline at end of file +1.13.3 \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/bin/elixir new/elixir-1.13.3/bin/elixir --- old/elixir-1.13.2/bin/elixir 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/bin/elixir 2022-02-09 16:26:17.000000000 +0100 @@ -1,7 +1,7 @@ #!/bin/sh set -e -ELIXIR_VERSION=1.13.2 +ELIXIR_VERSION=1.13.3 if [ $# -eq 0 ] || { [ $# -eq 1 ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; }; then cat <<USAGE >&2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/bin/elixir.bat new/elixir-1.13.3/bin/elixir.bat --- old/elixir-1.13.2/bin/elixir.bat 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/bin/elixir.bat 2022-02-09 16:26:17.000000000 +0100 @@ -1,6 +1,6 @@ @if defined ELIXIR_CLI_ECHO (@echo on) else (@echo off) -set ELIXIR_VERSION=1.13.2 +set ELIXIR_VERSION=1.13.3 setlocal enabledelayedexpansion if ""%1""=="""" if ""%2""=="""" goto documentation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/elixir/lib/code/formatter.ex new/elixir-1.13.3/lib/elixir/lib/code/formatter.ex --- old/elixir-1.13.2/lib/elixir/lib/code/formatter.ex 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/elixir/lib/code/formatter.ex 2022-02-09 16:26:17.000000000 +0100 @@ -177,6 +177,7 @@ defp state(comments, opts) do force_do_end_blocks = Keyword.get(opts, :force_do_end_blocks, false) locals_without_parens = Keyword.get(opts, :locals_without_parens, []) + file = Keyword.get(opts, :file, nil) sigils = Keyword.get(opts, :sigils, []) sigils = @@ -199,7 +200,8 @@ operand_nesting: 2, skip_eol: false, comments: comments, - sigils: sigils + sigils: sigils, + file: file } end @@ -1320,7 +1322,14 @@ entries = case state.sigils do %{^name => callback} -> - case callback.(hd(entries), sigil: List.to_atom([name]), modifiers: modifiers) do + metadata = [ + file: state.file, + line: meta[:line], + sigil: List.to_atom([name]), + modifiers: modifiers + ] + + case callback.(hd(entries), metadata) do binary when is_binary(binary) -> [binary] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/elixir/lib/code/normalizer.ex new/elixir-1.13.3/lib/elixir/lib/code/normalizer.ex --- old/elixir-1.13.2/lib/elixir/lib/code/normalizer.ex 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/elixir/lib/code/normalizer.ex 2022-02-09 16:26:17.000000000 +0100 @@ -251,12 +251,16 @@ if is_atom(literal) and Code.Identifier.classify(literal) == :alias and is_nil(meta[:delimiter]) do - "Elixir." <> segments = Atom.to_string(literal) - segments = - segments - |> String.split(".") - |> Enum.map(&String.to_atom/1) + case Atom.to_string(literal) do + "Elixir" -> + [:"Elixir"] + + "Elixir." <> segments -> + segments + |> String.split(".") + |> Enum.map(&String.to_atom/1) + end {:__aliases__, meta, segments} else diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/elixir/lib/map.ex new/elixir-1.13.3/lib/elixir/lib/map.ex --- old/elixir-1.13.2/lib/elixir/lib/map.ex 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/elixir/lib/map.ex 2022-02-09 16:26:17.000000000 +0100 @@ -214,7 +214,24 @@ """ @spec new(Enumerable.t(), (term -> {key, value})) :: map - def new(enumerable, transform) when is_function(transform, 1) do + def new(enumerable, transform) + def new(%_{} = enumerable, transform), do: new_from_enum(enumerable, transform) + def new(%{} = map, transform), do: new_from_map(map, transform) + def new(enumerable, transform), do: new_from_enum(enumerable, transform) + + defp new_from_map(map, transform) when is_function(transform, 1) do + iter = :maps.iterator(map) + next = :maps.next(iter) + :maps.from_list(do_map(next, transform)) + end + + defp do_map(:none, _fun), do: [] + + defp do_map({key, value, iter}, transform) do + [transform.({key, value}) | do_map(:maps.next(iter), transform)] + end + + defp new_from_enum(enumerable, transform) when is_function(transform, 1) do enumerable |> Enum.map(transform) |> :maps.from_list() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/elixir/lib/module/types/pattern.ex new/elixir-1.13.3/lib/elixir/lib/module/types/pattern.ex --- old/elixir-1.13.2/lib/elixir/lib/module/types/pattern.ex 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/elixir/lib/module/types/pattern.ex 2022-02-09 16:26:17.000000000 +0100 @@ -403,10 +403,8 @@ # bar, {:ok, baz} # bar, {:ok, bat} - expanded_args = - args - |> Enum.map(&flatten_union(&1, context)) - |> cartesian_product() + flatten_args = Enum.map(args, &flatten_union(&1, context)) + cartesian_args = cartesian_product(flatten_args) # Remove clauses that do not match the expected type # Ignore type variables in parameters by changing them to dynamic @@ -425,11 +423,11 @@ # the type contexts from unifying argument and parameter to # infer type variables in arguments result = - flat_map_ok(expanded_args, fn expanded_args -> + flat_map_ok(cartesian_args, fn cartesian_args -> result = Enum.flat_map(clauses, fn {params, return} -> result = - map_ok(Enum.zip(expanded_args, params), fn {arg, param} -> + map_ok(Enum.zip(cartesian_args, params), fn {arg, param} -> case unify(arg, param, stack, context) do {:ok, _type, context} -> {:ok, context} {:error, reason} -> {:error, reason} @@ -453,7 +451,13 @@ {:ok, returns_contexts} -> {success_returns, contexts} = Enum.unzip(returns_contexts) contexts = Enum.concat(contexts) - indexes = Enum.uniq(Enum.flat_map(args, &collect_var_indexes_from_type/1)) + + indexes = + for types <- flatten_args, + type <- types, + index <- collect_var_indexes_from_type(type), + do: index, + uniq: true # Build unions from collected type contexts to unify with # type variables from arguments diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/elixir/lib/string.ex new/elixir-1.13.3/lib/elixir/lib/string.ex --- old/elixir-1.13.2/lib/elixir/lib/string.ex 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/elixir/lib/string.ex 2022-02-09 16:26:17.000000000 +0100 @@ -2723,12 +2723,16 @@ graphemes_and_length: 1, reverse_characters_to_binary: 1} - defp byte_size_remaining_at(binary, 0) do - byte_size(binary) + defp byte_size_unicode(binary) when is_binary(binary), do: byte_size(binary) + defp byte_size_unicode([head]), do: byte_size_unicode(head) + defp byte_size_unicode([head | tail]), do: byte_size_unicode(head) + byte_size_unicode(tail) + + defp byte_size_remaining_at(unicode, 0) do + byte_size_unicode(unicode) end - defp byte_size_remaining_at(binary, n) do - case :unicode_util.gc(binary) do + defp byte_size_remaining_at(unicode, n) do + case :unicode_util.gc(unicode) do [_] -> 0 [_ | rest] -> byte_size_remaining_at(rest, n - 1) [] -> 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/elixir/src/elixir.erl new/elixir-1.13.3/lib/elixir/src/elixir.erl --- old/elixir-1.13.2/lib/elixir/src/elixir.erl 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/elixir/src/elixir.erl 2022-02-09 16:26:17.000000000 +0100 @@ -254,7 +254,7 @@ eval_forms(Tree, Binding, Opts) when is_list(Opts) -> eval_forms(Tree, Binding, env_for_eval(Opts)); eval_forms(Tree, RawBinding, OrigE) -> - {Vars, Binding} = normalize_binding(RawBinding, [], [], 0), + {Vars, Binding} = normalize_binding(RawBinding, #{}, [], 0), E = elixir_env:with_vars(OrigE, Vars), {_, S} = elixir_env:env_to_erl(E), {Erl, NewErlS, NewExS, NewE} = quoted_to_erl(Tree, E, S), @@ -275,12 +275,19 @@ {Value, elixir_erl_var:dump_binding(NewBinding, NewExS, NewErlS), NewE} end. -normalize_binding([{Key, Value} | Binding], Vars, Acc, I) when is_atom(Key) -> - normalize_binding(Binding, [{{Key, nil}, I} | Vars], [{{Key, nil}, Value} | Acc], I + 1); -normalize_binding([{Pair, Value} | Binding], Vars, Acc, I) -> - normalize_binding(Binding, [{Pair, I} | Vars], [{Pair, Value} | Acc], I + 1); -normalize_binding([], Vars, Acc, _I) -> - {maps:from_list(Vars), Acc}. +normalize_binding([Binding | NextBindings], VarsMap, Normalized, Counter) -> + {Pair, Value} = normalize_pair(Binding), + case VarsMap of + #{Pair := _} -> + normalize_binding(NextBindings, VarsMap, [{Pair, Value} | Normalized], Counter); + #{} -> + normalize_binding(NextBindings, VarsMap#{Pair => Counter}, [{Pair, Value} | Normalized], Counter + 1) + end; +normalize_binding([], VarsMap, Normalized, _Counter) -> + {VarsMap, Normalized}. + +normalize_pair({Key, Value}) when is_atom(Key) -> {{Key, nil}, Value}; +normalize_pair({Pair, Value}) -> {Pair, Value}. recur_eval([Expr | Exprs], Binding, Env) -> {value, Value, NewBinding} = diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/elixir/src/elixir_erl.erl new/elixir-1.13.3/lib/elixir/src/elixir_erl.erl --- old/elixir-1.13.2/lib/elixir/src/elixir_erl.erl 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/elixir/src/elixir_erl.erl 2022-02-09 16:26:17.000000000 +0100 @@ -552,7 +552,9 @@ <<"%", ('Elixir.Kernel':inspect(Module))/binary, "{}">>; signature_to_binary(_, Name, Signature) -> - 'Elixir.Macro':to_string({Name, [{closing, []}], Signature}). + Quoted = {Name, [{closing, []}], Signature}, + Doc = 'Elixir.Inspect.Algebra':format('Elixir.Code':quoted_to_algebra(Quoted), infinity), + 'Elixir.IO':iodata_to_binary(Doc). checker_chunk(#{definitions := Definitions, deprecated := Deprecated, is_behaviour := IsBehaviour}) -> DeprecatedMap = maps:from_list(Deprecated), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/elixir/test/elixir/code_formatter/general_test.exs new/elixir-1.13.3/lib/elixir/test/elixir/code_formatter/general_test.exs --- old/elixir-1.13.2/lib/elixir/test/elixir/code_formatter/general_test.exs 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/elixir/test/elixir/code_formatter/general_test.exs 2022-02-09 16:26:17.000000000 +0100 @@ -126,7 +126,7 @@ """ formatter = fn content, opts -> - assert opts == [sigil: :W, modifiers: []] + assert opts == [file: nil, line: 1, sigil: :W, modifiers: []] content |> String.split(~r/ +/) |> Enum.join(" ") end @@ -141,7 +141,7 @@ """ formatter = fn content, opts -> - assert opts == [sigil: :W, modifiers: 'abc'] + assert opts == [file: nil, line: 1, sigil: :W, modifiers: 'abc'] content |> String.split(~r/ +/) |> Enum.join(" ") end @@ -162,7 +162,7 @@ """ formatter = fn content, opts -> - assert opts == [sigil: :W, modifiers: []] + assert opts == [file: nil, line: 1, sigil: :W, modifiers: []] content |> String.split(~r/ +/) |> Enum.join(" ") end @@ -189,7 +189,7 @@ """ formatter = fn content, opts -> - assert opts == [sigil: :W, modifiers: 'abc'] + assert opts == [file: nil, line: 2, sigil: :W, modifiers: 'abc'] content |> String.split(~r/ +/) |> Enum.join("\n") end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/elixir/test/elixir/code_normalizer/formatted_ast_test.exs new/elixir-1.13.3/lib/elixir/test/elixir/code_normalizer/formatted_ast_test.exs --- old/elixir-1.13.2/lib/elixir/test/elixir/code_normalizer/formatted_ast_test.exs 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/elixir/test/elixir/code_normalizer/formatted_ast_test.exs 2022-02-09 16:26:17.000000000 +0100 @@ -115,6 +115,7 @@ test "does not reformat aliases" do assert_same ~S[:"Elixir.String"] + assert_same ~S[:"Elixir"] end test "quoted operators" do diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/elixir/test/elixir/code_normalizer/quoted_ast_test.exs new/elixir-1.13.3/lib/elixir/test/elixir/code_normalizer/quoted_ast_test.exs --- old/elixir-1.13.2/lib/elixir/test/elixir/code_normalizer/quoted_ast_test.exs 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/elixir/test/elixir/code_normalizer/quoted_ast_test.exs 2022-02-09 16:26:17.000000000 +0100 @@ -620,6 +620,7 @@ assert quoted_to_string({:__block__, [], [:"a\nb\tc"]}, escape: false) == ~s/:"a\nb\tc"/ assert quoted_to_string({:__block__, [], [:"a\nb\tc"]}) == ~S/:"a\nb\tc"/ + assert quoted_to_string(quote(do: :"Elixir")) == "Elixir" assert quoted_to_string(quote(do: :"Elixir.Foo")) == "Foo" assert quoted_to_string(quote(do: :"Elixir.Foo.Bar")) == "Foo.Bar" assert quoted_to_string(quote(do: :"Elixir.foobar")) == ~S/:"Elixir.foobar"/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/elixir/test/elixir/code_test.exs new/elixir-1.13.3/lib/elixir/test/elixir/code_test.exs --- old/elixir-1.13.2/lib/elixir/test/elixir/code_test.exs 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/elixir/test/elixir/code_test.exs 2022-02-09 16:26:17.000000000 +0100 @@ -52,6 +52,9 @@ # The order of which values win is not guaranteed, but it should evaluate successfully. assert Code.eval_string("b = String.Chars.to_string(a)", a: 0, a: 1) == {"1", [{:b, "1"}, {:a, 1}]} + + assert Code.eval_string("b = String.Chars.to_string(a)", a: 0, a: 1, c: 2) == + {"1", [{:c, 2}, {:b, "1"}, {:a, 1}]} end test "with many options" do diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/elixir/test/elixir/kernel/docs_test.exs new/elixir-1.13.3/lib/elixir/test/elixir/kernel/docs_test.exs --- old/elixir-1.13.2/lib/elixir/test/elixir/kernel/docs_test.exs 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/elixir/test/elixir/kernel/docs_test.exs 2022-02-09 16:26:17.000000000 +0100 @@ -119,6 +119,14 @@ def two_good_names(first, :ok), do: first def two_good_names(second, :error), do: second + + def really_long_signature( + really_long_var_named_one, + really_long_var_named_two, + really_long_var_named_three + ) do + {really_long_var_named_one, really_long_var_named_two, really_long_var_named_three} + end end ) @@ -128,6 +136,7 @@ assert [ arg_names, only_underscore, + really_long_signature, two_good_names, with_defaults, with_map_and_default, @@ -141,6 +150,12 @@ # only_underscore/1 assert {{:only_underscore, 1}, ["only_underscore(_)"]} = only_underscore + # really_long_signature/3 + assert {{:really_long_signature, 3}, + [ + "really_long_signature(really_long_var_named_one, really_long_var_named_two, really_long_var_named_three)" + ]} = really_long_signature + # two_good_names/2 assert {{:two_good_names, 2}, ["two_good_names(first, atom)"]} = two_good_names diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/elixir/test/elixir/kernel/quote_test.exs new/elixir-1.13.3/lib/elixir/test/elixir/kernel/quote_test.exs --- old/elixir-1.13.2/lib/elixir/test/elixir/kernel/quote_test.exs 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/elixir/test/elixir/kernel/quote_test.exs 2022-02-09 16:26:17.000000000 +0100 @@ -521,6 +521,9 @@ assert {:__aliases__, [alias: false], [:Foo, :Bar]} = quote(do: Foo.Bar) assert {:__aliases__, [alias: false], [:Dict, :Bar]} = quote(do: Dict.Bar) assert {:__aliases__, [alias: Dict.Bar], [:SuperDict, :Bar]} = quote(do: SuperDict.Bar) + + # Edge-case + assert {:__aliases__, _, [Elixir]} = quote(do: Elixir) end test "expand aliases" do diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/elixir/test/elixir/macro_test.exs new/elixir-1.13.3/lib/elixir/test/elixir/macro_test.exs --- old/elixir-1.13.2/lib/elixir/test/elixir/macro_test.exs 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/elixir/test/elixir/macro_test.exs 2022-02-09 16:26:17.000000000 +0100 @@ -326,6 +326,8 @@ end test "aliases call" do + assert macro_to_string(quote(do: Elixir)) == "Elixir" + assert macro_to_string(quote(do: Foo)) == "Foo" assert macro_to_string(quote(do: Foo.Bar.baz(1, 2, 3))) == "Foo.Bar.baz(1, 2, 3)" assert macro_to_string(quote(do: Foo.Bar.baz([1, 2, 3]))) == "Foo.Bar.baz([1, 2, 3])" assert macro_to_string(quote(do: Foo.bar(<<>>, []))) == "Foo.bar(<<>>, [])" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/elixir/test/elixir/module/types/types_test.exs new/elixir-1.13.3/lib/elixir/test/elixir/module/types/types_test.exs --- old/elixir-1.13.2/lib/elixir/test/elixir/module/types/types_test.exs 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/elixir/test/elixir/module/types/types_test.exs 2022-02-09 16:26:17.000000000 +0100 @@ -687,5 +687,18 @@ end ) == :none end + + test "no-recursion on guards with map fields" do + assert warning( + [assigns], + ( + variable_enum = assigns.variable_enum + + case true do + _ when variable_enum != nil -> assigns.variable_enum + end + ) + ) == :none + end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/elixir/test/elixir/string_test.exs new/elixir-1.13.3/lib/elixir/test/elixir/string_test.exs --- old/elixir-1.13.2/lib/elixir/test/elixir/string_test.exs 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/elixir/test/elixir/string_test.exs 2022-02-09 16:26:17.000000000 +0100 @@ -131,6 +131,11 @@ end end + test "split_at/2 with invalid guard" do + assert String.split_at(<<?a, 195, 10, ?a>>, 2) == {<<?a, 195>>, <<10, ?a>>} + assert String.split_at(<<107, 205, 135, 184>>, 1) == {<<107, 205, 135>>, <<184>>} + end + test "upcase/1" do assert String.upcase("123 abcd 456 efg hij ( %$#) kl mnop @ qrst = -_ uvwxyz") == "123 ABCD 456 EFG HIJ ( %$#) KL MNOP @ QRST = -_ UVWXYZ" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/mix/lib/mix/compilers/elixir.ex new/elixir-1.13.3/lib/mix/lib/mix/compilers/elixir.ex --- old/elixir-1.13.2/lib/mix/lib/mix/compilers/elixir.ex 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/mix/lib/mix/compilers/elixir.ex 2022-02-09 16:26:17.000000000 +0100 @@ -2,6 +2,7 @@ @moduledoc false @manifest_vsn 13 + @checkpoint_vsn 2 import Record @@ -102,7 +103,7 @@ {false, stale, old_lock, old_config} end - {stale_local_mods, stale_local_exports, all_local_exports} = + {stale_modules, stale_exports, all_local_exports} = stale_local_deps(manifest, stale, modified, all_local_exports) prev_paths = for source(source: source) <- all_sources, do: source @@ -120,8 +121,8 @@ all_modules, all_sources, removed, - stale_local_mods, - Map.merge(stale_local_exports, removed_modules), + Map.merge(stale_modules, removed_modules), + Map.merge(stale_exports, removed_modules), dest ) end @@ -180,7 +181,7 @@ delete_compiler_info() end else - # We need to return ok if deps_changed? or stale_local_mods changed, + # We need to return ok if deps_changed? or stale_modules changed, # even if no code was compiled, because we need to propagate the changed # status to compile.protocols. This will be the case whenever: # @@ -193,7 +194,7 @@ # will only compute the diff with current protocols. In fact, there is no # need to reconsolidate if an Erlang file changes and it doesn't trigger # any other change, but the diff check should be reasonably fast anyway. - status = if removed != [] or deps_changed? or stale_local_mods != %{}, do: :ok, else: :noop + status = if removed != [] or deps_changed? or stale_modules != %{}, do: :ok, else: :noop # If nothing changed but there is one more recent mtime, bump the manifest if status != :noop or Enum.any?(Map.values(sources_stats), &(elem(&1, 0) > modified)) do @@ -283,8 +284,8 @@ all_modules, all_sources, removed, - stale_local_mods, - stale_local_exports, + stale_modules, + stale_exports, dest ) do # TODO: Use :maps.from_keys/2 on Erlang/OTP 24+ @@ -294,13 +295,17 @@ into: %{}, do: {module, []} - {checkpoint_stale, checkpoint_modules} = parse_checkpoint(manifest) + {checkpoint_stale_modules, checkpoint_stale_exports, checkpoint_modules} = + parse_checkpoint(manifest) + modules_to_recompile = Map.merge(checkpoint_modules, modules_to_recompile) - stale_local_mods = Map.merge(checkpoint_stale, stale_local_mods) + stale_modules = Map.merge(checkpoint_stale_modules, stale_modules) + stale_exports = Map.merge(checkpoint_stale_exports, stale_exports) - if map_size(stale_local_mods) != map_size(checkpoint_stale) or + if map_size(stale_modules) != map_size(checkpoint_stale_modules) or + map_size(stale_exports) != map_size(checkpoint_stale_exports) or map_size(modules_to_recompile) != map_size(checkpoint_modules) do - write_checkpoint(manifest, stale_local_mods, modules_to_recompile) + write_checkpoint(manifest, stale_modules, stale_exports, modules_to_recompile) end sources_stats = @@ -332,8 +337,8 @@ all_modules, all_sources, removed ++ changed, - stale_local_mods, - stale_local_exports, + stale_modules, + stale_exports, dest ) @@ -654,16 +659,16 @@ # files that have changed. Then it recursively figures out # all the files that changed (via the module dependencies) and # return the non-changed entries and the removed sources. - defp update_stale_entries(modules, _sources, [], stale_mods, stale_exports, _compile_path) - when stale_mods == %{} and stale_exports == %{} do + defp update_stale_entries(modules, _sources, [], stale_modules, stale_exports, _compile_path) + when stale_modules == %{} and stale_exports == %{} do {modules, %{}, []} end - defp update_stale_entries(modules, sources, changed, stale_mods, stale_exports, compile_path) do + defp update_stale_entries(modules, sources, changed, stale_modules, stale_exports, compile_path) do # TODO: Use :maps.from_keys/2 on Erlang/OTP 24+ changed = Enum.into(changed, %{}, &{&1, []}) reducer = &remove_stale_entry(&1, &2, sources, stale_exports, compile_path) - remove_stale_entries(modules, %{}, changed, stale_mods, reducer) + remove_stale_entries(modules, %{}, changed, stale_modules, reducer) end defp remove_stale_entries(modules, exports, old_changed, old_stale, reducer) do @@ -720,6 +725,8 @@ defp stale_local_deps(manifest, stale_modules, modified, old_exports) do base = Path.basename(manifest) + # The stale modules so far will become both stale_modules and stale_exports, + # as any export from a dependency needs to be recompiled. # TODO: Use :maps.from_keys/2 on Erlang/OTP 24+ stale_modules = for module <- stale_modules, do: {module, []}, into: %{} @@ -727,7 +734,7 @@ not scm.fetchable?, manifest = Path.join([opts[:build], ".mix", base]), Mix.Utils.last_modified(manifest) > modified, - reduce: {stale_modules, %{}, old_exports} do + reduce: {stale_modules, stale_modules, old_exports} do {modules, exports, new_exports} -> {_manifest_modules, dep_sources} = read_manifest(manifest) @@ -1017,19 +1024,19 @@ (manifest <> ".checkpoint") |> File.read!() |> :erlang.binary_to_term() rescue _ -> - {%{}, %{}} + {%{}, %{}, %{}} else - {@manifest_vsn, stale, recompile_modules} -> - {stale, recompile_modules} + {@checkpoint_vsn, stale_modules, stale_exports, recompile_modules} -> + {stale_modules, stale_exports, recompile_modules} _ -> - {%{}, %{}} + {%{}, %{}, %{}} end end - defp write_checkpoint(manifest, stale, recompile_modules) do + defp write_checkpoint(manifest, stale_modules, stale_exports, recompile_modules) do File.mkdir_p!(Path.dirname(manifest)) - term = {@manifest_vsn, stale, recompile_modules} + term = {@checkpoint_vsn, stale_modules, stale_exports, recompile_modules} checkpoint_data = :erlang.term_to_binary(term, [:compressed]) File.write!(manifest <> ".checkpoint", checkpoint_data) end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/mix/lib/mix/tasks/format.ex new/elixir-1.13.3/lib/mix/lib/mix/tasks/format.ex --- old/elixir-1.13.2/lib/mix/lib/mix/tasks/format.ex 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/mix/lib/mix/tasks/format.ex 2022-02-09 16:26:17.000000000 +0100 @@ -104,11 +104,11 @@ The `opts` passed to `format/2` contains all the formatting options and either: - * `:sigil` (atom) - the sigil being formatted, e.g. `:M`. + * `:sigil` (atom) - the sigil being formatted, e.g. `:M`. - * `:modifiers` (charlist) - list of sigil modifiers. + * `:modifiers` (charlist) - list of sigil modifiers. - * `:extension` (string) - the extension of the file being formatted, e.g. `".md"`. + * `:extension` (string) - the extension of the file being formatted, e.g. `".md"`. Now any application can use your formatter as follows: @@ -288,7 +288,15 @@ end end - formatter_opts = Keyword.put(formatter_opts, :plugins, plugins) + sigils = + for plugin <- plugins, + sigil <- find_sigils_from_plugins(plugin, formatter_opts), + do: {sigil, &plugin.format(&1, &2 ++ formatter_opts)} + + formatter_opts = + formatter_opts + |> Keyword.put(:plugins, plugins) + |> Keyword.put(:sigils, sigils) if deps == [] and subs == [] do {{formatter_opts, []}, sources} @@ -496,7 +504,7 @@ cond do plugin = find_plugin_for_extension(formatter_opts, ext) -> - &plugin.format(&1, [extension: ext] ++ formatter_opts) + &plugin.format(&1, [extension: ext, file: file] ++ formatter_opts) ext in ~w(.ex .exs) -> &elixir_format(&1, [file: file] ++ formatter_opts) @@ -537,12 +545,7 @@ defp stdin_or_wildcard(path), do: path |> Path.expand() |> Path.wildcard(match_dot: true) defp elixir_format(content, formatter_opts) do - sigils = - for plugin <- Keyword.fetch!(formatter_opts, :plugins), - sigil <- find_sigils_from_plugins(plugin, formatter_opts), - do: {sigil, &plugin.format(&1, &2 ++ formatter_opts)} - - IO.iodata_to_binary([Code.format_string!(content, [sigils: sigils] ++ formatter_opts), ?\n]) + IO.iodata_to_binary([Code.format_string!(content, formatter_opts), ?\n]) end defp find_sigils_from_plugins(plugin, formatter_opts) do diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/mix/lib/mix/tasks/test.coverage.ex new/elixir-1.13.3/lib/mix/lib/mix/tasks/test.coverage.ex --- old/elixir-1.13.2/lib/mix/lib/mix/tasks/test.coverage.ex 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/mix/lib/mix/tasks/test.coverage.ex 2022-02-09 16:26:17.000000000 +0100 @@ -350,7 +350,7 @@ Mix.shell().info("-----------|--------------------------") results |> Enum.sort() |> Enum.each(&display(&1, threshold)) Mix.shell().info("-----------|--------------------------") - display({totals, "Total"}, opts) + display({totals, "Total"}, threshold) Mix.shell().info("") end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/mix/test/mix/tasks/compile.elixir_test.exs new/elixir-1.13.3/lib/mix/test/mix/tasks/compile.elixir_test.exs --- old/elixir-1.13.2/lib/mix/test/mix/tasks/compile.elixir_test.exs 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/mix/test/mix/tasks/compile.elixir_test.exs 2022-02-09 16:26:17.000000000 +0100 @@ -182,6 +182,11 @@ Process.put({MixTest.Case.Sample, :application}, extra_applications: [:logger]) File.mkdir_p!("config") + File.write!("config/config.exs", """ + import Config + config :logger, :level, :debug + """) + File.write!("lib/a.ex", """ defmodule A do _ = Logger.metadata() @@ -234,6 +239,12 @@ refute_received {:mix_shell, :info, ["Compiled lib/b.ex"]} assert File.stat!("_build/dev/lib/sample/.mix/compile.elixir").mtime > @old_time + # No-op does not recompile + File.touch!("_build/dev/lib/sample/.mix/compile.elixir", @old_time) + assert recompile.() == {:ok, []} + refute_received {:mix_shell, :info, ["Compiled lib/a.ex"]} + refute_received {:mix_shell, :info, ["Compiled lib/b.ex"]} + # Changing self fully recompiles File.write!("config/config.exs", """ import Config @@ -263,6 +274,76 @@ Application.delete_env(:sample, :foo, persistent: true) end + test "recompiles files when config changes export dependencies" do + in_fixture("no_mixfile", fn -> + Mix.Project.push(MixTest.Case.Sample) + Process.put({MixTest.Case.Sample, :application}, extra_applications: [:ex_unit]) + File.mkdir_p!("config") + + File.write!("lib/a.ex", """ + defmodule A do + def test_struct do + %ExUnit.Test{} + end + end + """) + + assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []} + assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]} + assert_received {:mix_shell, :info, ["Compiled lib/b.ex"]} + + recompile = fn -> + Mix.ProjectStack.pop() + Mix.Project.push(MixTest.Case.Sample) + Mix.Tasks.Loadconfig.load_compile("config/config.exs") + Mix.Tasks.Compile.Elixir.run(["--verbose"]) + end + + # Adding config recompiles + File.write!("config/config.exs", """ + import Config + config :ex_unit, :some, :config + """) + + File.touch!("_build/dev/lib/sample/.mix/compile.elixir", @old_time) + assert recompile.() == {:ok, []} + assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]} + refute_received {:mix_shell, :info, ["Compiled lib/b.ex"]} + assert File.stat!("_build/dev/lib/sample/.mix/compile.elixir").mtime > @old_time + + # Changing config recompiles + File.write!("config/config.exs", """ + import Config + config :ex_unit, :some, :another + """) + + File.touch!("_build/dev/lib/sample/.mix/compile.elixir", @old_time) + assert recompile.() == {:ok, []} + assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]} + refute_received {:mix_shell, :info, ["Compiled lib/b.ex"]} + assert File.stat!("_build/dev/lib/sample/.mix/compile.elixir").mtime > @old_time + + # Removing config recompiles + File.write!("config/config.exs", """ + import Config + """) + + File.touch!("_build/dev/lib/sample/.mix/compile.elixir", @old_time) + assert recompile.() == {:ok, []} + assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]} + refute_received {:mix_shell, :info, ["Compiled lib/b.ex"]} + assert File.stat!("_build/dev/lib/sample/.mix/compile.elixir").mtime > @old_time + + # No-op does not recompile + File.touch!("_build/dev/lib/sample/.mix/compile.elixir", @old_time) + assert recompile.() == {:ok, []} + refute_received {:mix_shell, :info, ["Compiled lib/a.ex"]} + refute_received {:mix_shell, :info, ["Compiled lib/b.ex"]} + end) + after + Application.delete_env(:ex_unit, :some, persistent: true) + end + test "recompiles files when config changes with crashes" do in_fixture("no_mixfile", fn -> Mix.Project.push(MixTest.Case.Sample) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/elixir-1.13.2/lib/mix/test/mix/tasks/format_test.exs new/elixir-1.13.3/lib/mix/test/mix/tasks/format_test.exs --- old/elixir-1.13.2/lib/mix/test/mix/tasks/format_test.exs 2022-01-13 10:51:17.000000000 +0100 +++ new/elixir-1.13.3/lib/mix/test/mix/tasks/format_test.exs 2022-02-09 16:26:17.000000000 +0100 @@ -206,6 +206,8 @@ assert opts[:from_formatter_exs] == :yes assert opts[:sigil] == :W assert opts[:modifiers] == 'abc' + assert opts[:line] == 2 + assert opts[:file] =~ ~r/\/a\.ex$/ contents |> String.split(~r/\s/) |> Enum.join("\n") end end @@ -247,12 +249,15 @@ def features(opts) do assert opts[:from_formatter_exs] == :yes - [extensions: ~w(.w)] + [extensions: ~w(.w), sigils: [:W]] end def format(contents, opts) do assert opts[:from_formatter_exs] == :yes assert opts[:extension] == ".w" + assert opts[:file] =~ ~r/\/a\.w$/ + assert [W: sigil_fun] = opts[:sigils] + assert is_function(sigil_fun, 2) contents |> String.split(~r/\s/) |> Enum.join("\n") end end
