File elixir-1.11.4-git.patch of Package elixir

diff --git a/.github/workflows/builds.hex.pm.yml b/.github/workflows/builds.hex.pm.yml
new file mode 100644
index 000000000..f263f5a7c
--- /dev/null
+++ b/.github/workflows/builds.hex.pm.yml
@@ -0,0 +1,87 @@
+name: builds.hex.pm
+
+on:
+  push:
+    branches:
+      - main
+      - v*.*
+    tags:
+      - v*
+
+env:
+  ELIXIR_OPTS: "--warnings-as-errors"
+  ERLC_OPTS: "warnings_as_errors"
+  LANG: C.UTF-8
+
+concurrency: builds_txt
+
+jobs:
+  release_pre_built:
+    strategy:
+      fail-fast: true
+      max-parallel: 1
+      matrix:
+        include:
+          - otp: 23
+            otp_version: '23.3'
+            build_docs: build_docs
+    runs-on: ubuntu-20.04
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          fetch-depth: 50
+      - name: Get tags
+        run: git fetch --tags origin
+      - uses: ./.github/workflows/release_pre_built
+        with:
+          otp_version: ${{ matrix.otp_version }}
+          otp: ${{ matrix.otp }}
+          build_docs: ${{ matrix.build_docs }}
+      - name: Utils.sh
+        run: |
+          cat << 'EOF' > utils.sh
+          function purge_key() {
+            curl \
+                -X POST \
+                -H "Fastly-Key: ${FASTLY_KEY}" \
+                -H "Accept: application/json" \
+                -H "Content-Length: 0" \
+                "https://api.fastly.com/service/$1/purge/$2"
+          }
+          function purge() {
+            purge_key ${FASTLY_REPO_SERVICE_ID} $1
+            purge_key ${FASTLY_BUILDS_SERVICE_ID} $1
+            sleep 2
+            purge_key ${FASTLY_REPO_SERVICE_ID} $1
+            purge_key ${FASTLY_BUILDS_SERVICE_ID} $1
+            sleep 2
+            purge_key ${FASTLY_REPO_SERVICE_ID} $1
+            purge_key ${FASTLY_BUILDS_SERVICE_ID} $1
+          }
+          EOF
+          chmod +x utils.sh
+      - name: Upload Docs to S3
+        if: ${{ matrix.build_docs }}
+        env:
+          AWS_ACCESS_KEY_ID: ${{ secrets.HEX_AWS_ACCESS_KEY_ID }}
+          AWS_SECRET_ACCESS_KEY: ${{ secrets.HEX_AWS_SECRET_ACCESS_KEY }}
+          AWS_REGION: ${{ secrets.HEX_AWS_REGION }}
+          AWS_S3_BUCKET: ${{ secrets.HEX_AWS_S3_BUCKET }}
+          FASTLY_REPO_SERVICE_ID: ${{ secrets.HEX_FASTLY_REPO_SERVICE_ID }}
+          FASTLY_BUILDS_SERVICE_ID: ${{ secrets.HEX_FASTLY_BUILDS_SERVICE_ID }}
+          FASTLY_KEY: ${{ secrets.HEX_FASTLY_KEY }}
+        run: |
+          source utils.sh
+          version=$(echo ${{ github.ref_name }} | sed -e 's/^v//g')
+          for f in doc/*; do
+              if [ -d "$f" ]; then
+                  app=`echo $f | sed s/"doc\/"//`
+                  tarball="${app}-${version}.tar.gz"
+                  surrogate_key="docs/${app}-${version}"
+                  tar -czf "${tarball}" -C "doc/${app}" .
+                  aws s3 cp "${tarball}" "s3://${{ env.AWS_S3_BUCKET }}/docs/${tarball}" \
+                      --cache-control "public,max-age=3600" \
+                      --metadata "{\"surrogate-key\":\"${surrogate_key}\",\"surrogate-control\":\"public,max-age=604800\"}"
+                  purge "${surrogate_key}"
+              fi
+          done
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f43a9ff62..a4bc8dbeb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -15,7 +15,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        otp_release: ['OTP-23.0', 'OTP-22.3', 'OTP-22.0', 'OTP-21.3.8', 'OTP-21.0']
+        otp_release: ['OTP-24.0', 'OTP-23.0', 'OTP-22.3', 'OTP-22.0', 'OTP-21.3.8', 'OTP-21.0']
         development: [false]
         include:
           - otp_release: master
diff --git a/.github/workflows/release_pre_built/action.yml b/.github/workflows/release_pre_built/action.yml
new file mode 100644
index 000000000..e8d063014
--- /dev/null
+++ b/.github/workflows/release_pre_built/action.yml
@@ -0,0 +1,51 @@
+name: "Release pre built"
+description: "Builds elixir release, ExDoc and generates docs"
+inputs:
+  otp:
+    description: "The major OTP version"
+  otp_version:
+    description: "The exact OTP version (major.minor[.patch])"
+  build_docs:
+    description: "If docs have to be built or not"
+runs:
+  using: "composite"
+  steps:
+    - uses: erlef/setup-beam@v1
+      with:
+        otp-version: ${{ inputs.otp_version }}
+        version-type: strict
+    - name: Build Elixir Release
+      shell: bash
+      run: |
+        make Precompiled.zip
+        mv Precompiled.zip elixir-otp-${{ inputs.otp }}.zip
+        shasum -a 1 elixir-otp-${{ inputs.otp }}.zip > elixir-otp-${{ inputs.otp }}.zip.sha1sum
+        shasum -a 256 elixir-otp-${{ inputs.otp }}.zip > elixir-otp-${{ inputs.otp }}.zip.sha256sum
+        echo "$PWD/bin" >> $GITHUB_PATH
+    - name: Get latest stable ExDoc version
+      if: ${{ inputs.build_docs }}
+      shell: bash
+      run: |
+        EX_DOC_LATEST_STABLE_VERSION=$(curl -s https://hex.pm/api/packages/ex_doc | jq --raw-output '.latest_stable_version')
+        echo "EX_DOC_LATEST_STABLE_VERSION=${EX_DOC_LATEST_STABLE_VERSION}" >> $GITHUB_ENV
+    - uses: actions/checkout@v3
+      if: ${{ inputs.build_docs }}
+      with:
+        repository: elixir-lang/ex_doc
+        ref: v${{ env.EX_DOC_LATEST_STABLE_VERSION }}
+        path: ex_doc
+    - name: Build ex_doc
+      if: ${{ inputs.build_docs }}
+      shell: bash
+      run: |
+        mv ex_doc ../ex_doc
+        cd ../ex_doc
+        ../elixir/bin/mix do local.rebar --force, local.hex --force, deps.get, compile
+        cd ../elixir
+    - name: Build Docs
+      if: ${{ inputs.build_docs }}
+      shell: bash
+      run: |
+        make Docs.zip
+        shasum -a 1 Docs.zip > Docs.zip.sha1sum
+        shasum -a 256 Docs.zip > Docs.zip.sha256sum
diff --git a/Makefile b/Makefile
index 68c44f8b9..93a565c19 100644
--- a/Makefile
+++ b/Makefile
@@ -178,40 +178,48 @@ clean_residual_files:
 
 LOGO_PATH = $(shell test -f ../docs/logo.png && echo "--logo ../docs/logo.png")
 SOURCE_REF = $(shell tag="$(call GIT_TAG)" revision="$(call GIT_REVISION)"; echo "$${tag:-$$revision}")
+
 DOCS_FORMAT = html
-COMPILE_DOCS = bin/elixir ../ex_doc/bin/ex_doc "$(1)" "$(VERSION)" "lib/$(2)/ebin" --main "$(3)" --source-url "https://github.com/elixir-lang/elixir" --source-ref "$(call SOURCE_REF)" $(call LOGO_PATH) --output doc/$(2) --canonical "https://hexdocs.pm/$(2)/$(CANONICAL)" --homepage-url "https://elixir-lang.org/docs.html" --formatter "$(DOCS_FORMAT)" $(4)
+DOCS_COMPILE = CANONICAL=$(CANONICAL) bin/elixir ../ex_doc/bin/ex_doc "$(1)" "$(VERSION)" "lib/$(2)/ebin" --main "$(3)" --source-url "https://github.com/elixir-lang/elixir" --source-ref "$(call SOURCE_REF)" $(call LOGO_PATH) --output doc/$(2) --canonical "https://hexdocs.pm/$(2)/$(CANONICAL)" --homepage-url "https://elixir-lang.org/docs.html" --formatter "$(DOCS_FORMAT)" $(4)
+DOCS_CONFIG = bin/elixir lib/elixir/scripts/docs_config.exs "$(1)"
 
 docs: compile ../ex_doc/bin/ex_doc docs_elixir docs_eex docs_mix docs_iex docs_ex_unit docs_logger
 
 docs_elixir: compile ../ex_doc/bin/ex_doc
 	@ echo "==> ex_doc (elixir)"
 	$(Q) rm -rf doc/elixir
-	$(call COMPILE_DOCS,Elixir,elixir,Kernel,--config "lib/elixir/docs.exs")
+	$(call DOCS_COMPILE,Elixir,elixir,Kernel,--config "lib/elixir/scripts/elixir_docs.exs")
+	$(call DOCS_CONFIG,elixir)
 
 docs_eex: compile ../ex_doc/bin/ex_doc
 	@ echo "==> ex_doc (eex)"
 	$(Q) rm -rf doc/eex
-	$(call COMPILE_DOCS,EEx,eex,EEx)
+	$(call DOCS_COMPILE,EEx,eex,EEx,--config "lib/elixir/scripts/mix_docs.exs")
+	$(call DOCS_CONFIG,eex)
 
 docs_mix: compile ../ex_doc/bin/ex_doc
 	@ echo "==> ex_doc (mix)"
 	$(Q) rm -rf doc/mix
-	$(call COMPILE_DOCS,Mix,mix,Mix)
+	$(call DOCS_COMPILE,Mix,mix,Mix,--config "lib/elixir/scripts/mix_docs.exs")
+	$(call DOCS_CONFIG,mix)
 
 docs_iex: compile ../ex_doc/bin/ex_doc
 	@ echo "==> ex_doc (iex)"
 	$(Q) rm -rf doc/iex
-	$(call COMPILE_DOCS,IEx,iex,IEx)
+	$(call DOCS_COMPILE,IEx,iex,IEx,--config "lib/elixir/scripts/mix_docs.exs")
+	$(call DOCS_CONFIG,iex)
 
 docs_ex_unit: compile ../ex_doc/bin/ex_doc
 	@ echo "==> ex_doc (ex_unit)"
 	$(Q) rm -rf doc/ex_unit
-	$(call COMPILE_DOCS,ExUnit,ex_unit,ExUnit)
+	$(call DOCS_COMPILE,ExUnit,ex_unit,ExUnit,--config "lib/elixir/scripts/mix_docs.exs")
+	$(call DOCS_CONFIG,ex_unit)
 
 docs_logger: compile ../ex_doc/bin/ex_doc
 	@ echo "==> ex_doc (logger)"
 	$(Q) rm -rf doc/logger
-	$(call COMPILE_DOCS,Logger,logger,Logger)
+	$(call DOCS_COMPILE,Logger,logger,Logger,--config "lib/elixir/scripts/mix_docs.exs")
+	$(call DOCS_CONFIG,logger)
 
 ../ex_doc/bin/ex_doc:
 	@ echo "ex_doc is not found in ../ex_doc as expected. See README for more information."
@@ -220,23 +228,23 @@ docs_logger: compile ../ex_doc/bin/ex_doc
 #==> Zip tasks
 
 Docs.zip: docs
-	rm -f Docs-v$(VERSION).zip
-	zip -9 -r Docs-v$(VERSION).zip CHANGELOG.md doc NOTICE LICENSE README.md
-	@ echo "Docs file created $(CURDIR)/Docs-v$(VERSION).zip"
+	rm -f Docs.zip
+	zip -9 -r Docs.zip CHANGELOG.md doc NOTICE LICENSE README.md
+	@ echo "Docs file created $(CURDIR)/Docs.zip"
 
 Precompiled.zip: build_man compile
-	rm -f Precompiled-v$(VERSION).zip
-	zip -9 -r Precompiled-v$(VERSION).zip bin CHANGELOG.md lib/*/ebin lib/*/lib LICENSE man NOTICE README.md VERSION
-	@ echo "Precompiled file created $(CURDIR)/Precompiled-v$(VERSION).zip"
+	rm -f Precompiled.zip
+	zip -9 -r Precompiled.zip bin CHANGELOG.md lib/*/ebin lib/*/lib LICENSE man NOTICE README.md VERSION
+	@ echo "Precompiled file created $(CURDIR)/Precompiled.zip"
 
 zips: Precompiled.zip Docs.zip
 	@ echo ""
 	@ echo "### Checksums"
 	@ echo ""
-	@ shasum -a 1 < Precompiled-v$(VERSION).zip | sed -e "s/-//" | xargs echo "  * Precompiled.zip SHA1:"
-	@ shasum -a 512 < Precompiled-v$(VERSION).zip | sed -e "s/-//" | xargs echo "  * Precompiled.zip SHA512:"
-	@ shasum -a 1 < Docs-v$(VERSION).zip | sed -e "s/-//" | xargs echo "  * Docs.zip SHA1:"
-	@ shasum -a 512 < Docs-v$(VERSION).zip | sed -e "s/-//" | xargs echo "  * Docs.zip SHA512:"
+	@ shasum -a 1 < Precompiled.zip | sed -e "s/-//" | xargs echo "  * Precompiled.zip SHA1:"
+	@ shasum -a 512 < Precompiled.zip | sed -e "s/-//" | xargs echo "  * Precompiled.zip SHA512:"
+	@ shasum -a 1 < Docs.zip | sed -e "s/-//" | xargs echo "  * Docs.zip SHA1:"
+	@ shasum -a 512 < Docs.zip | sed -e "s/-//" | xargs echo "  * Docs.zip SHA512:"
 	@ echo ""
 
 #==> Test tasks
diff --git a/lib/elixir/scripts/docs_config.exs b/lib/elixir/scripts/docs_config.exs
new file mode 100644
index 000000000..e24101732
--- /dev/null
+++ b/lib/elixir/scripts/docs_config.exs
@@ -0,0 +1,19 @@
+# Generate docs_config.js for version chooser in ExDoc
+[app] = System.argv()
+
+{text_tags, 0} = System.cmd("git", ["tag"])
+skipped = Version.parse!("1.0.3")
+
+list_contents =
+  text_tags
+  |> String.split()
+  |> Enum.map(fn "v" <> rest -> Version.parse!(rest) end)
+  |> Enum.filter(&(Version.compare(&1, skipped) == :gt))
+  |> Enum.sort({:desc, Version})
+  |> Enum.map_intersperse(", ", fn version ->
+    version_string = to_string(version)
+    ~s[{"version":"v#{version_string}", "url":"https://hexdocs.pm/#{app}/#{version_string}"}]
+  end)
+
+File.mkdir_p!("doc/#{app}")
+File.write!("doc/#{app}/docs_config.js", ["var versionNodes = [", list_contents, "];\n"])
diff --git a/lib/elixir/docs.exs b/lib/elixir/scripts/elixir_docs.exs
similarity index 100%
rename from lib/elixir/docs.exs
rename to lib/elixir/scripts/elixir_docs.exs
diff --git a/lib/elixir/scripts/mix_docs.exs b/lib/elixir/scripts/mix_docs.exs
new file mode 100644
index 000000000..a5b76f55e
--- /dev/null
+++ b/lib/elixir/scripts/mix_docs.exs
@@ -0,0 +1,12 @@
+canonical = System.fetch_env!("CANONICAL")
+
+[
+  deps: [
+    eex: "https://hexdocs.pm/eex/#{canonical}",
+    elixir: "https://hexdocs.pm/elixir/#{canonical}",
+    ex_unit: "https://hexdocs.pm/ex_unit/#{canonical}",
+    iex: "https://hexdocs.pm/iex/#{canonical}",
+    logger: "https://hexdocs.pm/logger/#{canonical}",
+    mix: "https://hexdocs.pm/mix/#{canonical}"
+  ]
+]
diff --git a/lib/elixir/src/elixir_erl_compiler.erl b/lib/elixir/src/elixir_erl_compiler.erl
index 7010b59fd..e0aa05114 100644
--- a/lib/elixir/src/elixir_erl_compiler.erl
+++ b/lib/elixir/src/elixir_erl_compiler.erl
@@ -94,6 +94,8 @@ handle_file_warning(true, _File, {_Line, sys_core_fold, {nomatch_shadow, _}}) ->
 
 %% Those we implement ourselves
 handle_file_warning(_, _File, {_Line, v3_core, {map_key_repeated, _}}) -> ok;
+handle_file_warning(_, _File, {_Line, sys_core_fold, {ignored, useless_building}}) -> ok;
+%% TODO: remove when we require Erlang/OTP 24
 handle_file_warning(_, _File, {_Line, sys_core_fold, useless_building}) -> ok;
 
 %% Ignore all linting errors (only come up on parse transforms)
@@ -112,11 +114,11 @@ handle_file_error(File, {Line, Module, Desc}) ->
   elixir_errors:compile_error([{line, Line}], File, Message).
 
 %% Mention the capture operator in make_fun
-custom_format(sys_core_fold, {no_effect, {erlang, make_fun, 3}}) ->
+custom_format(sys_core_fold, {ignored, {no_effect, {erlang, make_fun, 3}}}) ->
   "the result of the capture operator & (:erlang.make_fun/3) is never used";
 
 %% Make no_effect clauses pretty
-custom_format(sys_core_fold, {no_effect, {erlang, F, A}}) ->
+custom_format(sys_core_fold, {ignored, {no_effect, {erlang, F, A}}}) ->
   {Fmt, Args} = case erl_internal:comp_op(F, A) of
     true -> {"use of operator ~ts has no effect", [elixir_utils:erlang_comparison_op_to_elixir(F)]};
     false ->
@@ -127,12 +129,20 @@ custom_format(sys_core_fold, {no_effect, {erlang, F, A}}) ->
   end,
   io_lib:format(Fmt, Args);
 
-%% Rewrite nomatch_guard to be more generic it can happen inside if, unless, and the like
-custom_format(sys_core_fold, nomatch_guard) ->
+%% Rewrite nomatch to be more generic, it can happen inside if, unless, and the like
+custom_format(sys_core_fold, {nomatch, X}) when X == guard; X == no_clause ->
   "this check/guard will always yield the same result";
 
+custom_format(sys_core_fold, {nomatch, {shadow, Line, {ErlName, ErlArity}}}) ->
+  {Name, Arity} = elixir_utils:erl_fa_to_elixir_fa(ErlName, ErlArity),
+
+  io_lib:format(
+    "this clause for ~ts/~B cannot match because a previous clause at line ~B always matches",
+    [Name, Arity, Line]
+  );
+
 %% Handle literal eval failures
-custom_format(sys_core_fold, {eval_failure, {Mod, Name, Arity}, Error}) ->
+custom_format(sys_core_fold, {failed, {eval_failure, {Mod, Name, Arity}, Error}}) ->
   #{'__struct__' := Struct} = 'Elixir.Exception':normalize(error, Error),
   {ExMod, ExName, ExArgs} = elixir_rewrite:erl_to_ex(Mod, Name, lists:duplicate(Arity, nil)),
   Call = 'Elixir.Exception':format_mfa(ExMod, ExName, length(ExArgs)),
@@ -143,18 +153,16 @@ custom_format(sys_core_fold, {eval_failure, {Mod, Name, Arity}, Error}) ->
   ["the call to ", Trimmed, " will fail with ", elixir_aliases:inspect(Struct)];
 
 %% TODO: remove when we require OTP 24
+custom_format(sys_core_fold, {nomatch_shadow, Line, FA}) ->
+  custom_format(sys_core_fold, {nomatch, {shadow, Line, FA}});
+custom_format(sys_core_fold, nomatch_guard) ->
+  custom_format(sys_core_fold, {nomatch, guard});
+custom_format(sys_core_fold, {no_effect, X}) ->
+  custom_format(sys_core_fold, {ignored, {no_effect, X}});
 custom_format(sys_core_fold, {eval_failure, Error}) ->
   #{'__struct__' := Struct} = 'Elixir.Exception':normalize(error, Error),
   ["this expression will fail with ", elixir_aliases:inspect(Struct)];
 
-custom_format(sys_core_fold, {nomatch_shadow,Line,{ErlName,ErlArity}}) ->
-  {Name, Arity} = elixir_utils:erl_fa_to_elixir_fa(ErlName, ErlArity),
-
-  io_lib:format(
-    "this clause for ~ts/~B cannot match because a previous clause at line ~B always matches",
-    [Name, Arity, Line]
-  );
-
 custom_format([], Desc) ->
   io_lib:format("~p", [Desc]);
 
diff --git a/lib/elixir/test/elixir/exception_test.exs b/lib/elixir/test/elixir/exception_test.exs
index df9d46bbc..ae08d5185 100644
--- a/lib/elixir/test/elixir/exception_test.exs
+++ b/lib/elixir/test/elixir/exception_test.exs
@@ -446,11 +446,12 @@ test "annotates undefined function error with suggestions" do
                    * min/1
              """
 
-      assert blame_message(:erlang, & &1.gt_cookie()) == """
-             function :erlang.gt_cookie/0 is undefined or private. Did you mean one of:
+      assert blame_message(:erlang, & &1.hal()) == """
+             function :erlang.hal/0 is undefined or private. Did you mean one of:
 
-                   * get_cookie/0
-                   * set_cookie/2
+                   * halt/0
+                   * halt/1
+                   * halt/2
              """
     end
 
diff --git a/lib/elixir/test/elixir/kernel/warning_test.exs b/lib/elixir/test/elixir/kernel/warning_test.exs
index 15a984a54..37334ff65 100644
--- a/lib/elixir/test/elixir/kernel/warning_test.exs
+++ b/lib/elixir/test/elixir/kernel/warning_test.exs
@@ -1154,31 +1154,6 @@ def foo(x), do: :ok
     purge(Sample)
   end
 
-  test "with and do clauses emit errors, else clauses do not" do
-    assert capture_err(fn ->
-             Code.compile_string("""
-             with {:first, int} when is_integer(int) <- {:second, Integer.gcd(2, 4)} do
-               int
-             end
-             """)
-           end) =~ "this clause cannot match"
-
-    assert capture_err(fn ->
-             Code.compile_string("""
-             with {:first, int1} when is_integer(int1) <- {:first, Integer.gcd(2, 4)},
-                  {:second, int2} when is_integer(int2) <- {:second, Integer.gcd(2, 4)} do
-               {:ok, int1 + int2}
-             else
-               {:first, nil} -> {:error, "first number is not integer"}
-               {:second, nil} -> {:error, "second number is not integer"}
-             end
-             """)
-           end) == ""
-  after
-    purge(Sample1)
-    purge(Sample2)
-  end
-
   test "warning on code point escape" do
     assert capture_err(fn ->
              Code.eval_string("? ")
diff --git a/lib/logger/lib/logger/translator.ex b/lib/logger/lib/logger/translator.ex
index d1d7e62f1..8afd79436 100644
--- a/lib/logger/lib/logger/translator.ex
+++ b/lib/logger/lib/logger/translator.ex
@@ -357,15 +357,22 @@ defp child_info(_min_level, _child) do
     []
   end
 
-  defp child_debug(:debug, restart_type: restart, shutdown: shutdown, child_type: type) do
-    ["\nRestart: ", inspect(restart), "\nShutdown: ", inspect(shutdown)] ++
-      ["\nType: ", inspect(type)]
+  defp child_debug(:debug, opts) do
+    for {key, value} <- opts do
+      child_debug_key(key, value)
+    end
   end
 
   defp child_debug(_min_level, _child) do
     []
   end
 
+  defp child_debug_key(:restart_type, value), do: ["\nRestart: " | inspect(value)]
+  defp child_debug_key(:shutdown, value), do: ["\nShutdown: " | inspect(value)]
+  defp child_debug_key(:child_type, value), do: ["\nType: " | inspect(value)]
+  defp child_debug_key(:significant, value), do: if(value, do: "\nSignificant: true", else: [])
+  defp child_debug_key(_, _), do: []
+
   defp report_crash(min_level, [[{:initial_call, initial_call} | crashed], linked]) do
     mfa = initial_call_to_mfa(initial_call)
     report_crash(min_level, crashed, [{:initial_call, mfa}], linked)
diff --git a/lib/mix/lib/mix/task.ex b/lib/mix/lib/mix/task.ex
index af3db782d..11fc24bfd 100644
--- a/lib/mix/lib/mix/task.ex
+++ b/lib/mix/lib/mix/task.ex
@@ -387,15 +387,16 @@ defp run_task(proj, task, args) do
         Mix.ProjectStack.on_recursing_root(fn -> run(task, args) end)
 
       Mix.TasksServer.run({:task, task, proj}) ->
-        if Mix.debug?(), do: output_task_debug_info(task, args, proj)
         run_requirements(module)
 
-        try do
-          module.run(args)
-        rescue
-          e in OptionParser.ParseError ->
-            Mix.raise("Could not invoke task #{inspect(task)}: " <> Exception.message(e))
-        end
+        with_debug(task, args, proj, fn ->
+          try do
+            module.run(args)
+          rescue
+            e in OptionParser.ParseError ->
+              Mix.raise("Could not invoke task #{inspect(task)}: " <> Exception.message(e))
+          end
+        end)
 
       true ->
         :noop
@@ -409,8 +410,16 @@ defp run_requirements(module) do
     end)
   end
 
-  defp output_task_debug_info(task, args, proj) do
-    Mix.shell().info("** Running mix " <> task_to_string(task, args) <> project_to_string(proj))
+  defp with_debug(task, args, proj, fun) do
+    if Mix.debug?() do
+      shell = Mix.shell()
+      shell.info(["-> Running mix ", task_to_string(task, args), project_to_string(proj)])
+      {time, res} = :timer.tc(fun)
+      shell.info(["<- Ran mix ", task, " in ", Integer.to_string(div(time, 1000)), "ms"])
+      res
+    else
+      fun.()
+    end
   end
 
   defp project_to_string(nil), do: ""
diff --git a/lib/mix/test/mix/cli_test.exs b/lib/mix/test/mix/cli_test.exs
index 45857359e..80a2a5b9a 100644
--- a/lib/mix/test/mix/cli_test.exs
+++ b/lib/mix/test/mix/cli_test.exs
@@ -60,11 +60,11 @@ def run(_) do
       assert contents =~ "This won't appear"
 
       contents = mix(~w[my_hello], [{"MIX_DEBUG", "1"}])
-      assert contents =~ "** Running mix my_hello (inside MyProject)"
+      assert contents =~ "-> Running mix my_hello (inside MyProject)"
       assert contents =~ "** (Mix.Error) oops"
 
       contents = mix(~w[my_hello], [{"MIX_DEBUG", "0"}])
-      refute contents =~ "** Running mix my_hello (inside MyProject)"
+      refute contents =~ "-> Running mix my_hello (inside MyProject)"
       refute contents =~ "** (Mix.Error) oops"
     end)
   end
diff --git a/lib/mix/test/mix/task_test.exs b/lib/mix/test/mix/task_test.exs
index ad59c32aa..5e11e9527 100644
--- a/lib/mix/test/mix/task_test.exs
+++ b/lib/mix/test/mix/task_test.exs
@@ -59,7 +59,8 @@ test "run/2 outputs task debug info if Mix.debug? is true" do
     Mix.shell(Mix.Shell.IO)
     Mix.debug(true)
 
-    assert ExUnit.CaptureIO.capture_io(fn -> Mix.Task.run("hello") end) =~ "** Running mix hello"
+    assert ExUnit.CaptureIO.capture_io(fn -> Mix.Task.run("hello") end) =~
+             ~r"-> Running mix hello\n<- Ran mix hello in \d+ms"
   after
     Mix.shell(Mix.Shell.Process)
     Mix.debug(false)
openSUSE Build Service is sponsored by