Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package elixir for openSUSE:Factory checked 
in at 2026-01-12 10:22:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/elixir (Old)
 and      /work/SRC/openSUSE:Factory/.elixir.new.1928 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "elixir"

Mon Jan 12 10:22:32 2026 rev:46 rq:1326507 version:1.19.5

Changes:
--------
--- /work/SRC/openSUSE:Factory/elixir/elixir.changes    2025-11-28 
16:56:41.391778608 +0100
+++ /work/SRC/openSUSE:Factory/.elixir.new.1928/elixir.changes  2026-01-12 
10:31:36.066890244 +0100
@@ -1,0 +2,6 @@
+Sat Jan 10 12:09:22 UTC 2026 - Alessio Biancalana <[email protected]>
+
+- Upgrade to Elixir 1.19.5:
+  * Changelog available at https://hexdocs.pm/elixir/1.19.5/changelog.html
+
+-------------------------------------------------------------------

Old:
----
  elixir-1.19.4-doc.zip
  elixir-1.19.4.tar.gz

New:
----
  elixir-1.19.5-doc.zip
  elixir-1.19.5.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ elixir.spec ++++++
--- /var/tmp/diff_new_pack.7kcy4C/_old  2026-01-12 10:31:37.542950807 +0100
+++ /var/tmp/diff_new_pack.7kcy4C/_new  2026-01-12 10:31:37.546950971 +0100
@@ -18,7 +18,7 @@
 
 %define elixirdir %{_prefix}/lib/elixir
 Name:           elixir
-Version:        1.19.4
+Version:        1.19.5
 Release:        0
 Summary:        Functional meta-programming aware language built atop Erlang
 License:        Apache-2.0

++++++ _scmsync.obsinfo ++++++
--- /var/tmp/diff_new_pack.7kcy4C/_old  2026-01-12 10:31:37.646955075 +0100
+++ /var/tmp/diff_new_pack.7kcy4C/_new  2026-01-12 10:31:37.670956059 +0100
@@ -1,6 +1,6 @@
-mtime: 1764319463
-commit: a85fc128d402651f852787b6a2f57d17c2aff5586354e645033c644cea34e928
+mtime: 1768047012
+commit: fea2558efa407bd98399d116b8a6e9c095b1680b39f3c99b4111394c886f0241
 url: https://src.opensuse.org/erlang/elixir.git
-revision: a85fc128d402651f852787b6a2f57d17c2aff5586354e645033c644cea34e928
+revision: fea2558efa407bd98399d116b8a6e9c095b1680b39f3c99b4111394c886f0241
 projectscmsync: https://src.opensuse.org/erlang/_ObsPrj.git
 

++++++ build.specials.obscpio ++++++

++++++ build.specials.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/.gitignore new/.gitignore
--- old/.gitignore      1970-01-01 01:00:00.000000000 +0100
+++ new/.gitignore      2026-01-10 13:12:46.000000000 +0100
@@ -0,0 +1 @@
+.osc

++++++ elixir-1.19.4-doc.zip -> elixir-1.19.5-doc.zip ++++++
++++ 93186 lines of diff (skipped)

++++++ elixir-1.19.4.tar.gz -> elixir-1.19.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/CHANGELOG.md 
new/elixir-1.19.5/CHANGELOG.md
--- old/elixir-1.19.4/CHANGELOG.md      2025-11-27 16:50:26.000000000 +0100
+++ new/elixir-1.19.5/CHANGELOG.md      2026-01-09 11:57:56.000000000 +0100
@@ -234,6 +234,32 @@
 
 This work was performed by [Jonatan Männchen](https://maennchen.dev) and 
sponsored by the [Erlang Ecosystem Foundation](https://erlef.org).
 
+## v1.19.5 (2026-01-09)
+
+### 1. Enhancements
+
+#### Elixir
+
+  * [Protocol] Optimize protocol consolidation to no longer load structs
+
+### 2. Bug fixes
+
+#### Elixir
+
+  * [Kernel] Fix unnecessary recompilation when `dbg_callback` is modified at 
runtime
+  * [Kernel] Fix parser crash on missing parentheses on expression following 
operator `not in`
+  * [Kernel] Support fetching abstract code for modules compiled with Elixir 
v1.14 and earlier
+  * [Protocol] Ensure protocol consolidation no longer stores outdated struct 
types. As a consequence, protocols types only track struct names at the moment
+  * [Stream] Revert optimization which caused nested streams in 
`Stream.flat_map/2` to crash
+
+#### IEx
+
+  * [IEx] Fix usage of `#iex:break` as part of multi-line prompts
+
+#### Logger
+
+  * [Logger.Backends] Do not crash on invalid metadata
+
 ## v1.19.4 (2025-11-27)
 
 ### 1. Enhancements
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/VERSION new/elixir-1.19.5/VERSION
--- old/elixir-1.19.4/VERSION   2025-11-27 16:50:26.000000000 +0100
+++ new/elixir-1.19.5/VERSION   2026-01-09 11:57:56.000000000 +0100
@@ -1 +1 @@
-1.19.4
+1.19.5
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/bin/elixir new/elixir-1.19.5/bin/elixir
--- old/elixir-1.19.4/bin/elixir        2025-11-27 16:50:26.000000000 +0100
+++ new/elixir-1.19.5/bin/elixir        2026-01-09 11:57:56.000000000 +0100
@@ -6,7 +6,7 @@
 
 set -e
 
-ELIXIR_VERSION=1.19.4
+ELIXIR_VERSION=1.19.5
 
 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.19.4/bin/elixir.bat 
new/elixir-1.19.5/bin/elixir.bat
--- old/elixir-1.19.4/bin/elixir.bat    2025-11-27 16:50:26.000000000 +0100
+++ new/elixir-1.19.5/bin/elixir.bat    2026-01-09 11:57:56.000000000 +0100
@@ -4,7 +4,7 @@
 :: SPDX-FileCopyrightText: 2021 The Elixir Team
 :: SPDX-FileCopyrightText: 2012 Plataformatec
 
-set ELIXIR_VERSION=1.19.4
+set ELIXIR_VERSION=1.19.5
 
 if    ""%1""==""""                if ""%2""=="""" goto documentation
 if /I ""%1""==""--help""          if ""%2""=="""" goto documentation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/lib/elixir/lib/module/types/apply.ex 
new/elixir-1.19.5/lib/elixir/lib/module/types/apply.ex
--- old/elixir-1.19.4/lib/elixir/lib/module/types/apply.ex      2025-11-27 
16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/elixir/lib/module/types/apply.ex      2026-01-09 
11:57:56.000000000 +0100
@@ -1067,6 +1067,17 @@
                   """
               end
 
+            # The protocol has, at the moment, simplified clauses, so we build 
the complete one
+            clauses =
+              case mod.__protocol__(:impls) do
+                {:consolidated, mods} ->
+                  domain = mods |> Enum.map(&Module.Types.Of.impl/1) |> 
Enum.reduce(&union/2)
+                  [{[domain], dynamic()}]
+
+                _ ->
+                  clauses
+              end
+
             {"""
              but expected a type that implements the #{inspect(mod)} protocol.
              #{fix}\
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/lib/elixir/lib/module/types/of.ex 
new/elixir-1.19.5/lib/elixir/lib/module/types/of.ex
--- old/elixir-1.19.4/lib/elixir/lib/module/types/of.ex 2025-11-27 
16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/elixir/lib/module/types/of.ex 2026-01-09 
11:57:56.000000000 +0100
@@ -141,14 +141,25 @@
     {Any, term()}
   ]
 
+  @doc """
+  Currently, for protocol implementations, we only store
+  the open struct definition. This is because we don't want
+  to reconsolidate whenever the struct changes, but at the
+  moment we can't store references either. Ideally struct
+  types on protocol dispatches would be lazily resolved.
+  """
+  def impl(for, mode \\ :closed)
+
   for {for, type} <- impls do
-    def impl(unquote(for)), do: unquote(Macro.escape(type))
+    def impl(unquote(for), _mode), do: unquote(Macro.escape(type))
   end
 
-  def impl(struct) do
-    # Elixir did not strictly require the implementation to be available, so 
we need a fallback.
+  def impl(struct, mode) do
+    # Elixir did not strictly require the implementation to be available,
+    # so we need to deal with such cases accordingly.
     # TODO: Assume implementation is available on Elixir v2.0.
-    if info = Code.ensure_loaded?(struct) && struct.__info__(:struct) do
+    # A warning is emitted since v1.19+.
+    if info = mode == :closed && Code.ensure_loaded?(struct) && 
struct.__info__(:struct) do
       struct_type(struct, info)
     else
       open_map(__struct__: atom([struct]))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/lib/elixir/lib/protocol.ex 
new/elixir-1.19.5/lib/elixir/lib/protocol.ex
--- old/elixir-1.19.4/lib/elixir/lib/protocol.ex        2025-11-27 
16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/elixir/lib/protocol.ex        2026-01-09 
11:57:56.000000000 +0100
@@ -453,7 +453,7 @@
       true
 
   """
-  @spec extract_protocols([charlist | String.t()]) :: [atom]
+  @spec extract_protocols([charlist | String.t() | {charlist, [charlist]}]) :: 
[atom]
   def extract_protocols(paths) do
     extract_matching_by_attribute(paths, [?E, ?l, ?i, ?x, ?i, ?r, ?.], fn 
module, attributes ->
       case attributes[:__protocol__] do
@@ -482,7 +482,7 @@
       true
 
   """
-  @spec extract_impls(module, [charlist | String.t()]) :: [atom]
+  @spec extract_impls(module, [charlist | String.t() | {charlist, 
[charlist]}]) :: [atom]
   def extract_impls(protocol, paths) when is_atom(protocol) do
     prefix = Atom.to_charlist(protocol) ++ [?.]
 
@@ -496,17 +496,25 @@
 
   defp extract_matching_by_attribute(paths, prefix, callback) do
     for path <- paths,
-        # Do not use protocols as they may be consolidating
-        path = if(is_list(path), do: path, else: String.to_charlist(path)),
-        file <- list_dir(path),
+        {path, files} = list_dir(path),
+        file <- files,
         mod = extract_from_file(path, file, prefix, callback),
         do: mod
   end
 
+  # Do not use protocols as they may be consolidating
+  defp list_dir({path, files}) when is_list(path) and is_list(files) do
+    {path, files}
+  end
+
+  defp list_dir(path) when is_binary(path) do
+    list_dir(String.to_charlist(path))
+  end
+
   defp list_dir(path) when is_list(path) do
     case :file.list_dir(path) do
-      {:ok, files} -> files
-      _ -> []
+      {:ok, files} -> {path, files}
+      _ -> {path, []}
     end
   end
 
@@ -633,7 +641,7 @@
         checker =
           if checker do
             update_in(checker.exports, fn exports ->
-              signatures = new_signatures(definitions, protocol_funs, 
protocol, types)
+              signatures = new_signatures(definitions, protocol_funs, 
protocol, types, structs)
 
               for {fun, info} <- exports do
                 if sig = Map.get(signatures, fun) do
@@ -652,14 +660,13 @@
     end
   end
 
-  defp new_signatures(definitions, protocol_funs, protocol, types) do
+  defp new_signatures(definitions, protocol_funs, protocol, types, structs) do
     alias Module.Types.Descr
+    types_minus_any = List.delete(types, Any)
 
     clauses =
-      types
-      |> List.delete(Any)
-      |> Enum.map(fn impl ->
-        {[Module.Types.Of.impl(impl)], Descr.atom([__concat__(protocol, 
impl)])}
+      Enum.map(types_minus_any, fn impl ->
+        {[Module.Types.Of.impl(impl, :open)], Descr.atom([__concat__(protocol, 
impl)])}
       end)
 
     {domain, impl_for, impl_for!} =
@@ -674,10 +681,16 @@
           end
 
         _ ->
+          structs_domain =
+            case structs do
+              [] -> Descr.none()
+              _ -> Descr.open_map(__struct__: Descr.atom(structs))
+            end
+
           domain =
-            clauses
-            |> Enum.map(fn {[domain], _} -> domain end)
-            |> Enum.reduce(&Descr.union/2)
+            Enum.reduce(types_minus_any -- structs, structs_domain, fn impl, 
acc ->
+              Descr.union(Module.Types.Of.impl(impl, :open), acc)
+            end)
 
           not_domain = Descr.negation(domain)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/lib/elixir/lib/stream.ex 
new/elixir-1.19.5/lib/elixir/lib/stream.ex
--- old/elixir-1.19.4/lib/elixir/lib/stream.ex  2025-11-27 16:50:26.000000000 
+0100
+++ new/elixir-1.19.5/lib/elixir/lib/stream.ex  2026-01-09 11:57:56.000000000 
+0100
@@ -964,17 +964,13 @@
         after_fun.(user_acc)
         :erlang.raise(kind, reason, __STACKTRACE__)
     else
-      {:suspended, [val], next} ->
-        do_transform_user(val, user_acc, :cont, next, inner_acc, funs)
+      {:suspended, vals, next} ->
+        do_transform_user(:lists.reverse(vals), user_acc, :cont, next, 
inner_acc, funs)
 
-      {_, result} ->
+      {_, vals} ->
         # Do not attempt to call the resource again, it has either done or 
halted
         next = fn _ -> {:done, []} end
-
-        case result do
-          [val] -> do_transform_user(val, user_acc, :last, next, inner_acc, 
funs)
-          [] -> do_transform(user_acc, :last, next, inner_acc, funs)
-        end
+        do_transform_user(:lists.reverse(vals), user_acc, :last, next, 
inner_acc, funs)
     end
   end
 
@@ -989,7 +985,7 @@
           after_fun.(user_acc)
           :erlang.raise(kind, reason, __STACKTRACE__)
       else
-        result -> do_transform_result(result, :halt, next, inner_acc, funs)
+        result -> do_transform_result(result, [], :halt, next, inner_acc, funs)
       end
     else
       do_transform(user_acc, :halt, next, inner_acc, funs)
@@ -1002,7 +998,11 @@
     {:halted, elem(inner_acc, 1)}
   end
 
-  defp do_transform_user(val, user_acc, next_op, next, inner_acc, funs) do
+  defp do_transform_user([], user_acc, next_op, next, inner_acc, funs) do
+    do_transform(user_acc, next_op, next, inner_acc, funs)
+  end
+
+  defp do_transform_user([val | vals], user_acc, next_op, next, inner_acc, 
funs) do
     {user, _, _, _, after_fun} = funs
 
     try do
@@ -1013,20 +1013,20 @@
         after_fun.(user_acc)
         :erlang.raise(kind, reason, __STACKTRACE__)
     else
-      result -> do_transform_result(result, next_op, next, inner_acc, funs)
+      result -> do_transform_result(result, vals, next_op, next, inner_acc, 
funs)
     end
   end
 
-  defp do_transform_result(result, next_op, next, inner_acc, funs) do
+  defp do_transform_result(result, vals, next_op, next, inner_acc, funs) do
     {_, fun, inner, _, after_fun} = funs
 
     case result do
       {[], user_acc} ->
-        do_transform(user_acc, next_op, next, inner_acc, funs)
+        do_transform_user(vals, user_acc, next_op, next, inner_acc, funs)
 
       {list, user_acc} when is_list(list) ->
         reduce = &Enumerable.List.reduce(list, &1, fun)
-        do_transform_inner_list(user_acc, next_op, next, inner_acc, reduce, 
funs)
+        do_transform_inner_list(vals, user_acc, next_op, next, inner_acc, 
reduce, funs)
 
       {:halt, user_acc} ->
         next.({:halt, []})
@@ -1035,11 +1035,11 @@
 
       {other, user_acc} ->
         reduce = &Enumerable.reduce(other, &1, inner)
-        do_transform_inner_enum(user_acc, next_op, next, inner_acc, reduce, 
funs)
+        do_transform_inner_enum(vals, user_acc, next_op, next, inner_acc, 
reduce, funs)
     end
   end
 
-  defp do_transform_inner_list(user_acc, next_op, next, inner_acc, reduce, 
funs) do
+  defp do_transform_inner_list(vals, user_acc, next_op, next, inner_acc, 
reduce, funs) do
     {_, _, _, _, after_fun} = funs
 
     try do
@@ -1051,7 +1051,7 @@
         :erlang.raise(kind, reason, __STACKTRACE__)
     else
       {:done, acc} ->
-        do_transform(user_acc, next_op, next, {:cont, acc}, funs)
+        do_transform_user(vals, user_acc, next_op, next, {:cont, acc}, funs)
 
       {:halted, acc} ->
         next.({:halt, []})
@@ -1059,12 +1059,12 @@
         {:halted, acc}
 
       {:suspended, acc, continuation} ->
-        resume = &do_transform_inner_list(user_acc, next_op, next, &1, 
continuation, funs)
+        resume = &do_transform_inner_list(vals, user_acc, next_op, next, &1, 
continuation, funs)
         {:suspended, acc, resume}
     end
   end
 
-  defp do_transform_inner_enum(user_acc, next_op, next, {op, inner_acc}, 
reduce, funs) do
+  defp do_transform_inner_enum(vals, user_acc, next_op, next, {op, inner_acc}, 
reduce, funs) do
     {_, _, _, _, after_fun} = funs
 
     try do
@@ -1078,7 +1078,7 @@
       # The user wanted to cont/suspend but the stream halted,
       # so we continue with the user intention.
       {:halted, [inner_op | acc]} when op != :halt and inner_op != :halt ->
-        do_transform(user_acc, next_op, next, {inner_op, acc}, funs)
+        do_transform_user(vals, user_acc, next_op, next, {inner_op, acc}, funs)
 
       {:halted, [_ | acc]} ->
         next.({:halt, []})
@@ -1086,10 +1086,10 @@
         {:halted, acc}
 
       {:done, [_ | acc]} ->
-        do_transform(user_acc, next_op, next, {:cont, acc}, funs)
+        do_transform_user(vals, user_acc, next_op, next, {:cont, acc}, funs)
 
       {:suspended, [_ | acc], continuation} ->
-        resume = &do_transform_inner_enum(user_acc, next_op, next, &1, 
continuation, funs)
+        resume = &do_transform_inner_enum(vals, user_acc, next_op, next, &1, 
continuation, funs)
         {:suspended, acc, resume}
     end
   end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/lib/elixir/src/elixir.erl 
new/elixir-1.19.5/lib/elixir/src/elixir.erl
--- old/elixir-1.19.4/lib/elixir/src/elixir.erl 2025-11-27 16:50:26.000000000 
+0100
+++ new/elixir-1.19.5/lib/elixir/src/elixir.erl 2026-01-09 11:57:56.000000000 
+0100
@@ -64,6 +64,11 @@
       application:set_env(elixir, ansi_enabled, prim_tty:isatty(stdout) == 
true)
   end,
 
+  %% Store the initial dbg_callback value before any runtime modifications.
+  %% This allows Mix compiler to detect config changes vs runtime changes
+  %% (e.g., Kino wrapping dbg_callback at runtime should not trigger 
recompilation).
+  {ok, InitialDbgCallback} = application:get_env(elixir, dbg_callback),
+
   Tokenizer = case code:ensure_loaded('Elixir.String.Tokenizer') of
     {module, Mod} -> Mod;
     _ -> elixir_tokenizer
@@ -90,6 +95,7 @@
     {docs, true},
     {ignore_already_consolidated, false},
     {ignore_module_conflict, false},
+    {initial_dbg_callback, InitialDbgCallback},
     {infer_signatures, [elixir]},
     {on_undefined_variable, raise},
     {parser_options, [{columns, true}]},
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/lib/elixir/src/elixir_erl_pass.erl 
new/elixir-1.19.5/lib/elixir/src/elixir_erl_pass.erl
--- old/elixir-1.19.4/lib/elixir/src/elixir_erl_pass.erl        2025-11-27 
16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/elixir/src/elixir_erl_pass.erl        2026-01-09 
11:57:56.000000000 +0100
@@ -566,6 +566,11 @@
 extract_bit_type({unit, _, [Arg]}, Acc) ->
   [{unit, Arg} | Acc];
 extract_bit_type({Other, _, nil}, Acc) ->
+  [Other | Acc];
+%% TODO: Remove me on Elixir v2.0.
+%% Elixir v1.14 and earlier emitted an empty list
+%% and may still be processed via debug_info.
+extract_bit_type({Other, _, []}, Acc) ->
   [Other | Acc].
 
 %% Optimizations that are specific to Erlang and change
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/lib/elixir/src/elixir_erl_try.erl 
new/elixir-1.19.5/lib/elixir/src/elixir_erl_try.erl
--- old/elixir-1.19.4/lib/elixir/src/elixir_erl_try.erl 2025-11-27 
16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/elixir/src/elixir_erl_try.erl 2026-01-09 
11:57:56.000000000 +0100
@@ -27,8 +27,9 @@
   {Args, Guards} = elixir_utils:extract_splat_guards(Raw),
 
   Match =
+    %% TODO: Remove me on Elixir v2.0.
     %% Elixir v1.17 and earlier emitted single argument
-    %% and may still be processed via debug_info
+    %% and may still be processed via debug_info.
     case Args of
       [X] -> [throw, X];
       [X, Y] -> [X, Y]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/lib/elixir/src/elixir_parser.yrl 
new/elixir-1.19.5/lib/elixir/src/elixir_parser.yrl
--- old/elixir-1.19.4/lib/elixir/src/elixir_parser.yrl  2025-11-27 
16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/elixir/src/elixir_parser.yrl  2026-01-09 
11:57:56.000000000 +0100
@@ -1298,6 +1298,14 @@
   ok.
 
 %% TODO: Make this an error on v2.0
+warn_no_parens_after_do_op({{in_op, Location, Op, _InLocation}, _}) ->
+  {Line, _, _} = Location,
+
+  warn(
+    Line,
+    "missing parentheses on expression following operator \"" ++ 
atom_to_list(Op) ++ "\", "
+    "you must add parentheses to avoid ambiguities"
+  );
 warn_no_parens_after_do_op({{_Type, Location, Op}, _}) ->
   {Line, _, _} = Location,
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elixir-1.19.4/lib/elixir/test/elixir/kernel/warning_test.exs 
new/elixir-1.19.5/lib/elixir/test/elixir/kernel/warning_test.exs
--- old/elixir-1.19.4/lib/elixir/test/elixir/kernel/warning_test.exs    
2025-11-27 16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/elixir/test/elixir/kernel/warning_test.exs    
2026-01-09 11:57:56.000000000 +0100
@@ -1953,6 +1953,18 @@
     )
   end
 
+  test "do+end with not in operator without explicit parentheses" do
+    assert_warn_eval(
+      ["nofile:3\n", "missing parentheses on expression following operator 
\"not in\""],
+      """
+      quote do
+        case do
+        end not in no_parens 1, 2
+      end
+      """
+    )
+  end
+
   test "variable is being expanded to function call (on_undefined_variable: 
warn)" do
     capture_io(:stderr, fn ->
       Code.put_compiler_option(:on_undefined_variable, :warn)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elixir-1.19.4/lib/elixir/test/elixir/protocol/consolidation_test.exs 
new/elixir-1.19.5/lib/elixir/test/elixir/protocol/consolidation_test.exs
--- old/elixir-1.19.4/lib/elixir/test/elixir/protocol/consolidation_test.exs    
2025-11-27 16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/elixir/test/elixir/protocol/consolidation_test.exs    
2026-01-09 11:57:56.000000000 +0100
@@ -187,9 +187,11 @@
       assert domain == [term()]
 
       assert clauses == [
-               {[Of.impl(Map)], atom([WithAny.Map])},
-               {[Of.impl(ImplStruct)], 
atom([WithAny.Protocol.ConsolidationTest.ImplStruct])},
-               {[negation(union(Of.impl(ImplStruct), Of.impl(Map)))], 
atom([WithAny.Any])}
+               {[Of.impl(Map, :open)], atom([WithAny.Map])},
+               {[Of.impl(ImplStruct, :open)],
+                atom([WithAny.Protocol.ConsolidationTest.ImplStruct])},
+               {[negation(union(Of.impl(ImplStruct, :open), Of.impl(Map, 
:open)))],
+                atom([WithAny.Any])}
              ]
 
       assert %{{:ok, 2} => %{sig: {:strong, nil, clauses}}} = exports
@@ -256,18 +258,34 @@
       assert Inspect in protos
     end
 
+    test "protocols with expanded path" do
+      path = to_charlist(Application.app_dir(:elixir, "ebin"))
+      {:ok, mods} = :file.list_dir(path)
+      protos = Protocol.extract_protocols([{path, mods}])
+      assert Enumerable in protos
+      assert Inspect in protos
+    end
+
     test "implementations with charlist path" do
-      protos =
+      impls =
         Protocol.extract_impls(Enumerable, 
[to_charlist(Application.app_dir(:elixir, "ebin"))])
 
-      assert List in protos
-      assert Function in protos
+      assert List in impls
+      assert Function in impls
     end
 
     test "implementations with binary path" do
-      protos = Protocol.extract_impls(Enumerable, 
[Application.app_dir(:elixir, "ebin")])
-      assert List in protos
-      assert Function in protos
+      impls = Protocol.extract_impls(Enumerable, [Application.app_dir(:elixir, 
"ebin")])
+      assert List in impls
+      assert Function in impls
+    end
+
+    test "implementations with expanded path" do
+      path = to_charlist(Application.app_dir(:elixir, "ebin"))
+      {:ok, mods} = :file.list_dir(path)
+      impls = Protocol.extract_impls(Enumerable, [{path, mods}])
+      assert List in impls
+      assert Function in impls
     end
   end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/lib/elixir/test/elixir/regex_test.exs 
new/elixir-1.19.5/lib/elixir/test/elixir/regex_test.exs
--- old/elixir-1.19.4/lib/elixir/test/elixir/regex_test.exs     2025-11-27 
16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/elixir/test/elixir/regex_test.exs     2026-01-09 
11:57:56.000000000 +0100
@@ -127,7 +127,8 @@
   test "compile!/1" do
     assert %Regex{} = Regex.compile!("foo")
 
-    assert_raise Regex.CompileError, ~r/position 0$/, fn ->
+    # The exact position changed between Erlang/OTP 28.1 and 28.3
+    assert_raise Regex.CompileError, ~r/at position/, fn ->
       Regex.compile!("*foo")
     end
   end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/lib/elixir/test/elixir/stream_test.exs 
new/elixir-1.19.5/lib/elixir/test/elixir/stream_test.exs
--- old/elixir-1.19.4/lib/elixir/test/elixir/stream_test.exs    2025-11-27 
16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/elixir/test/elixir/stream_test.exs    2026-01-09 
11:57:56.000000000 +0100
@@ -183,6 +183,24 @@
     assert Stream.chunk_while([1, 2, 3, 4, 5], [], chunk_fun, after_fun) |> 
Enum.at(0) == [1]
   end
 
+  test "chunk_while/4 regression case with concat" do
+    result =
+      ["WrongHeader\nJohn Doe", "skipped"]
+      |> Stream.take(1)
+      |> Stream.chunk_while(
+        "",
+        fn element, acc ->
+          {acc, elements} = String.split(acc <> element, "\n") |> 
List.pop_at(-1)
+          {:cont, elements, acc}
+        end,
+        &{:cont, [&1], []}
+      )
+      |> Stream.concat()
+      |> Enum.to_list()
+
+    assert result == ["WrongHeader", "John Doe"]
+  end
+
   test "concat/1" do
     stream = Stream.concat([1..3, [], [4, 5, 6], [], 7..9])
     assert is_function(stream)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/lib/ex_unit/lib/ex_unit/callbacks.ex 
new/elixir-1.19.5/lib/ex_unit/lib/ex_unit/callbacks.ex
--- old/elixir-1.19.4/lib/ex_unit/lib/ex_unit/callbacks.ex      2025-11-27 
16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/ex_unit/lib/ex_unit/callbacks.ex      2026-01-09 
11:57:56.000000000 +0100
@@ -169,11 +169,7 @@
       end
   """
 
-  @type child_spec_overrides :: [
-          restart: :permanent | :transient | :temporary,
-          shutdown: :brutal_kill | timeout(),
-          type: :worker | :supervisor
-        ]
+  @type child_spec_overrides :: Supervisor.child_spec_overrides()
 
   @doc false
   def __register__(module) do
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/lib/iex/lib/iex/evaluator.ex 
new/elixir-1.19.5/lib/iex/lib/iex/evaluator.ex
--- old/elixir-1.19.4/lib/iex/lib/iex/evaluator.ex      2025-11-27 
16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/iex/lib/iex/evaluator.ex      2026-01-09 
11:57:56.000000000 +0100
@@ -71,61 +71,56 @@
 
   def parse(input, opts, []), do: parse(input, opts, {[], :other})
 
-  def parse(@break_trigger, opts, _parser_state) do
-    :elixir_errors.parse_error(
-      [line: opts[:line]],
-      opts[:file],
-      "incomplete expression",
-      "",
-      {~c"", Keyword.get(opts, :line, 1), Keyword.get(opts, :column, 1), 0}
-    )
-  end
-
   def parse(input, opts, {buffer, last_op}) do
     input = buffer ++ input
     file = Keyword.get(opts, :file, "nofile")
     line = Keyword.get(opts, :line, 1)
     column = Keyword.get(opts, :column, 1)
 
-    result =
-      with {:ok, tokens} <- :elixir.string_to_tokens(input, line, column, 
file, opts),
-           {:ok, adjusted_tokens, adjusted_op} <-
-             adjust_operator(tokens, line, column, file, opts, last_op),
-           {:ok, forms} <- :elixir.tokens_to_quoted(adjusted_tokens, file, 
opts) do
-        last_op =
-          case forms do
-            {:=, _, [_, _]} -> :match
-            _ -> :other
-          end
-
-        forms =
-          if adjusted_op != nil do
-            quote do
-              IEx.Evaluator.assert_no_error!()
-              unquote(forms)
+    if List.ends_with?(input, @break_trigger) do
+      triplet = {~c"", line, column, 0}
+      :elixir_errors.parse_error([line: line], file, "incomplete expression", 
"", triplet)
+    else
+      result =
+        with {:ok, tokens} <- :elixir.string_to_tokens(input, line, column, 
file, opts),
+             {:ok, adjusted_tokens, adjusted_op} <-
+               adjust_operator(tokens, line, column, file, opts, last_op),
+             {:ok, forms} <- :elixir.tokens_to_quoted(adjusted_tokens, file, 
opts) do
+          last_op =
+            case forms do
+              {:=, _, [_, _]} -> :match
+              _ -> :other
             end
-          else
-            forms
-          end
 
-        {:ok, forms, last_op}
-      end
+          forms =
+            if adjusted_op != nil do
+              quote do
+                IEx.Evaluator.assert_no_error!()
+                unquote(forms)
+              end
+            else
+              forms
+            end
+
+          {:ok, forms, last_op}
+        end
 
-    case result do
-      {:ok, forms, last_op} ->
-        {:ok, forms, {[], last_op}}
-
-      {:error, {_, _, ""}} ->
-        {:incomplete, {input, last_op}}
-
-      {:error, {location, error, token}} ->
-        :elixir_errors.parse_error(
-          location,
-          file,
-          error,
-          token,
-          {input, line, column, 0}
-        )
+      case result do
+        {:ok, forms, last_op} ->
+          {:ok, forms, {[], last_op}}
+
+        {:error, {_, _, ""}} ->
+          {:incomplete, {input, last_op}}
+
+        {:error, {location, error, token}} ->
+          :elixir_errors.parse_error(
+            location,
+            file,
+            error,
+            token,
+            {input, line, column, 0}
+          )
+      end
     end
   end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elixir-1.19.4/lib/logger/lib/logger/backends/handler.ex 
new/elixir-1.19.5/lib/logger/lib/logger/backends/handler.ex
--- old/elixir-1.19.4/lib/logger/lib/logger/backends/handler.ex 2025-11-27 
16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/logger/lib/logger/backends/handler.ex 2026-01-09 
11:57:56.000000000 +0100
@@ -47,7 +47,13 @@
         %{truncate: truncate, utc_log: utc_log?} = config
         level = erlang_level_to_elixir_level(erl_level)
         message = Logger.Formatter.format_event(event, truncate)
-        timestamp = Map.get_lazy(metadata, :time, fn -> 
:os.system_time(:microsecond) end)
+
+        timestamp =
+          case metadata do
+            %{time: time} when is_integer(time) and time >= 0 -> time
+            _ -> :os.system_time(:microsecond)
+          end
+
         date_time_ms = Logger.Formatter.system_time_to_date_time_ms(timestamp, 
utc_log?)
         metadata = [erl_level: erl_level] ++ 
erlang_metadata_to_elixir_metadata(metadata)
         event = {level, gl, {Logger, message, date_time_ms, metadata}}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elixir-1.19.4/lib/logger/test/logger/backends/handler_test.exs 
new/elixir-1.19.5/lib/logger/test/logger/backends/handler_test.exs
--- old/elixir-1.19.4/lib/logger/test/logger/backends/handler_test.exs  
2025-11-27 16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/logger/test/logger/backends/handler_test.exs  
2026-01-09 11:57:56.000000000 +0100
@@ -113,6 +113,12 @@
     Logger.configure_backend(Logger.Backends.Console, metadata: [])
   end
 
+  test "ignores invalid Erlang metadata" do
+    assert capture_log(fn -> :logger.info("ok", %{time: "bad"}) end) =~ "ok"
+  after
+    Logger.Backends.Internal.configure(Logger.Backends.Console, metadata: [])
+  end
+
   test "uses reporting callback with Elixir inspection" do
     assert capture_log(fn ->
              callback = fn %{hello: :world} -> {"~p~n", [:formatted]} end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/lib/mix/lib/mix/compilers/elixir.ex 
new/elixir-1.19.5/lib/mix/lib/mix/compilers/elixir.ex
--- old/elixir-1.19.4/lib/mix/lib/mix/compilers/elixir.ex       2025-11-27 
16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/mix/lib/mix/compilers/elixir.ex       2026-01-09 
11:57:56.000000000 +0100
@@ -287,7 +287,13 @@
   end
 
   defp deps_config_compile_env_apps(deps_config) do
-    if deps_config[:dbg] != Application.fetch_env!(:elixir, :dbg_callback) do
+    # Use initial_dbg_callback instead of dbg_callback to ignore runtime 
modifications.
+    # Tools like Kino modify dbg_callback at runtime to customize dbg/2 
behavior,
+    # but this should not trigger recompilation since the config hasn't 
actually changed.
+    # initial_dbg_callback is set when :elixir app starts, before any runtime 
modifications.
+    initial_dbg = :elixir_config.get(:initial_dbg_callback)
+
+    if deps_config[:dbg] != initial_dbg do
       [:elixir]
     else
       []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/elixir-1.19.4/lib/mix/lib/mix/compilers/protocol.ex 
new/elixir-1.19.5/lib/mix/lib/mix/compilers/protocol.ex
--- old/elixir-1.19.4/lib/mix/lib/mix/compilers/protocol.ex     2025-11-27 
16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/mix/lib/mix/compilers/protocol.ex     2026-01-09 
11:57:56.000000000 +0100
@@ -126,11 +126,16 @@
   end
 
   defp consolidation_paths do
-    filter_otp(:code.get_path(), :code.lib_dir())
-  end
+    otp = :code.lib_dir()
 
-  defp filter_otp(paths, otp) do
-    Enum.filter(paths, &(not :lists.prefix(otp, &1)))
+    # Pre-list the paths in each directory for performance
+    for path <- :code.get_path(), not :lists.prefix(otp, path) do
+      {path,
+       case :file.list_dir(path) do
+         {:ok, files} -> files
+         _ -> []
+       end}
+    end
   end
 
   defp consolidate([], _paths, output, _opts) do
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/elixir-1.19.4/lib/mix/test/mix/tasks/compile.elixir_test.exs 
new/elixir-1.19.5/lib/mix/test/mix/tasks/compile.elixir_test.exs
--- old/elixir-1.19.4/lib/mix/test/mix/tasks/compile.elixir_test.exs    
2025-11-27 16:50:26.000000000 +0100
+++ new/elixir-1.19.5/lib/mix/test/mix/tasks/compile.elixir_test.exs    
2026-01-09 11:57:56.000000000 +0100
@@ -278,9 +278,11 @@
       assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
       assert_received {:mix_shell, :info, ["Compiled lib/b.ex"]}
 
-      # Change the dbg_callback at runtime
+      # Simulate a config change by updating both dbg_callback and 
initial_dbg_callback.
+      # This represents the case where the user actually changed the config 
file.
       File.touch!("_build/dev/lib/sample/.mix/compile.elixir", @old_time)
       Application.put_env(:elixir, :dbg_callback, {__MODULE__, :dbg, []})
+      :elixir_config.put(:initial_dbg_callback, {__MODULE__, :dbg, []})
 
       assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
       assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
@@ -289,6 +291,35 @@
     end)
   after
     Application.put_env(:elixir, :dbg_callback, {Macro, :dbg, []})
+    :elixir_config.put(:initial_dbg_callback, {Macro, :dbg, []})
+  end
+
+  test "does not recompile when dbg_callback is modified at runtime but 
initial is unchanged" do
+    in_fixture("no_mixfile", fn ->
+      Mix.Project.push(MixTest.Case.Sample)
+
+      File.write!("lib/a.ex", """
+      defmodule A do
+        def a, do: dbg(:ok)
+      end
+      """)
+
+      assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
+      assert_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
+
+      # Simulate a tool like Kino modifying dbg_callback at runtime.
+      # Since initial_dbg_callback remains unchanged, this should NOT trigger 
recompilation.
+      original_dbg = Application.fetch_env!(:elixir, :dbg_callback)
+      :elixir_config.put(:initial_dbg_callback, original_dbg)
+      Application.put_env(:elixir, :dbg_callback, {SomeDebugTool, :dbg, 
[original_dbg]})
+
+      # Should NOT trigger recompilation since initial_dbg_callback is 
unchanged
+      assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:noop, []}
+      refute_received {:mix_shell, :info, ["Compiled lib/a.ex"]}
+    end)
+  after
+    Application.put_env(:elixir, :dbg_callback, {Macro, :dbg, []})
+    :elixir_config.put(:initial_dbg_callback, {Macro, :dbg, []})
   end
 
   test "recompiles files when config changes export dependencies" do

Reply via email to