Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
327063cc84 | ||
|
|
795d0a9583 | ||
|
|
1150ebad03 | ||
|
|
18feec4cd8 | ||
|
|
7d5920206b | ||
|
|
a694447601 | ||
|
|
19ae388dda | ||
|
|
6b5edea5f1 | ||
|
|
b736c23af9 | ||
|
|
63f0000ace | ||
|
|
5e8b187d08 | ||
|
|
aea1a47b8d | ||
|
|
eeba8e992d | ||
|
|
dd42dd8620 | ||
|
|
ed1ddfd338 | ||
|
|
d17df054e2 |
@@ -78,6 +78,27 @@ Another [ExDoc](https://github.com/elixir-lang/ex_doc) feature we have incorpora
|
||||
|
||||
Finally, we have started enriching our documentation with [Mermaid.js](https://mermaid.js.org/) diagrams. You can find examples in the [GenServer](https://hexdocs.pm/elixir/main/GenServer.html) and [Supervisor](https://hexdocs.pm/elixir/main/Supervisor.html) docs.
|
||||
|
||||
## v1.16.3 (2024-05-21)
|
||||
|
||||
### 1. Bug fixes
|
||||
|
||||
#### Elixir
|
||||
|
||||
* [bin/elixir] Properly handle the `--dbg` flag in Elixir's CLI
|
||||
* [Code.Formatter] Add brackets around keyword lists when formatting the left-hand side of `when`
|
||||
* [Kernel] Only infer size in pinned variable in binary strings when needed
|
||||
* [System] Add a note that arguments are unsafe when invoking .bat/.com scripts on Windows via `System.cmd/3`
|
||||
* [Port] Add a note that arguments are unsafe when invoking .bat/.com scripts on Windows
|
||||
* [URI] Ensure `:undefined` fields are properly converted to `nil` when invoking Erlang's API
|
||||
|
||||
#### Logger
|
||||
|
||||
* [Logger] Ensure translators are persisted across logger restarts
|
||||
|
||||
#### Mix
|
||||
|
||||
* [mix compile] Ensure compile paths are accessible during compilation
|
||||
|
||||
## v1.16.2 (2024-03-10)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
ELIXIR_VERSION=1.16.2
|
||||
ELIXIR_VERSION=1.16.3
|
||||
|
||||
if [ $# -eq 0 ] || { [ $# -eq 1 ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; }; then
|
||||
cat <<USAGE >&2
|
||||
@@ -112,10 +112,10 @@ while [ $I -le $LENGTH ]; do
|
||||
C=1
|
||||
MODE="iex"
|
||||
;;
|
||||
-v|--no-halt|--dbg)
|
||||
-v|--no-halt)
|
||||
C=1
|
||||
;;
|
||||
-e|-r|-pr|-pa|-pz|--eval|--remsh|--dot-iex)
|
||||
-e|-r|-pr|-pa|-pz|--eval|--remsh|--dot-iex|--dbg)
|
||||
C=2
|
||||
;;
|
||||
--rpc-eval)
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
@if defined ELIXIR_CLI_ECHO (@echo on) else (@echo off)
|
||||
|
||||
set ELIXIR_VERSION=1.16.2
|
||||
set ELIXIR_VERSION=1.16.3
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
if ""%1""=="""" if ""%2""=="""" goto documentation
|
||||
|
||||
@@ -1959,6 +1959,14 @@ defmodule Code.Formatter do
|
||||
# fn a, b, c when d -> e end
|
||||
defp clause_args_to_algebra([{:when, meta, args}], state) do
|
||||
{args, right} = split_last(args)
|
||||
|
||||
# If there are any keywords, wrap them in lists
|
||||
args =
|
||||
Enum.map(args, fn
|
||||
[_ | _] = keyword -> {:__block__, [], [keyword]}
|
||||
other -> other
|
||||
end)
|
||||
|
||||
left = {{:special, :clause_args}, meta, [args]}
|
||||
binary_op_to_algebra(:when, "when", meta, left, right, :no_parens_arg, state)
|
||||
end
|
||||
|
||||
@@ -79,6 +79,27 @@ defmodule Port do
|
||||
are for advanced usage within the VM. Also consider using `System.cmd/3`
|
||||
if all you want is to execute a program and retrieve its return value.
|
||||
|
||||
> #### Windows argument splitting and untrusted arguments {: .warning}
|
||||
>
|
||||
> On Unix systems, arguments are passed to a new operating system
|
||||
> process as an array of strings but on Windows it is up to the child
|
||||
> process to parse them and some Windows programs may apply their own
|
||||
> rules, which are inconsistent with the standard C runtime `argv` parsing
|
||||
>
|
||||
> This is particularly troublesome when invoking `.bat` or `.com` files
|
||||
> as these run implicitly through `cmd.exe`, whose argument parsing is
|
||||
> vulnerable to malicious input and can be used to run arbitrary shell
|
||||
> commands.
|
||||
>
|
||||
> Therefore, if you are running on Windows and you execute batch
|
||||
> files or `.com` applications, you must not pass untrusted input as
|
||||
> arguments to the program. You may avoid accidentally executing them
|
||||
> by explicitly passing the extension of the program you want to run,
|
||||
> such as `.exe`, and double check the program is indeed not a batch
|
||||
> file or `.com` application.
|
||||
>
|
||||
> This affects both `spawn` and `spawn_executable`.
|
||||
|
||||
### spawn
|
||||
|
||||
The `:spawn` tuple receives a binary that is going to be executed as a
|
||||
|
||||
@@ -1005,6 +1005,25 @@ defmodule System do
|
||||
`Port` module describes this problem and possible solutions under
|
||||
the "Zombie processes" section.
|
||||
|
||||
> #### Windows argument splitting and untrusted arguments {: .warning}
|
||||
>
|
||||
> On Unix systems, arguments are passed to a new operating system
|
||||
> process as an array of strings but on Windows it is up to the child
|
||||
> process to parse them and some Windows programs may apply their own
|
||||
> rules, which are inconsistent with the standard C runtime `argv` parsing
|
||||
>
|
||||
> This is particularly troublesome when invoking `.bat` or `.com` files
|
||||
> as these run implicitly through `cmd.exe`, whose argument parsing is
|
||||
> vulnerable to malicious input and can be used to run arbitrary shell
|
||||
> commands.
|
||||
>
|
||||
> Therefore, if you are running on Windows and you execute batch
|
||||
> files or `.com` applications, you must not pass untrusted input as
|
||||
> arguments to the program. You may avoid accidentally executing them
|
||||
> by explicitly passing the extension of the program you want to run,
|
||||
> such as `.exe`, and double check the program is indeed not a batch
|
||||
> file or `.com` application.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> System.cmd("echo", ["hello"])
|
||||
|
||||
@@ -656,16 +656,16 @@ defmodule URI do
|
||||
scheme = String.downcase(scheme, :ascii)
|
||||
|
||||
case map do
|
||||
%{port: port} when port != :undefined ->
|
||||
%{port: port} when is_integer(port) ->
|
||||
%{uri | scheme: scheme}
|
||||
|
||||
%{} ->
|
||||
case default_port(scheme) do
|
||||
nil -> %{uri | scheme: scheme}
|
||||
port -> %{uri | scheme: scheme, port: port}
|
||||
end
|
||||
%{uri | scheme: scheme, port: default_port(scheme)}
|
||||
end
|
||||
|
||||
%{port: :undefined} ->
|
||||
%{uri | port: nil}
|
||||
|
||||
%{} ->
|
||||
uri
|
||||
end
|
||||
|
||||
@@ -707,11 +707,11 @@ fruits = ["apple", "banana", "grape", "orange", "pear"]
|
||||
iex> Enum.slide(fruits, 2, 0)
|
||||
["grape", "apple", "banana", "orange", "pear"]
|
||||
iex> Enum.slide(fruits, 2, 4)
|
||||
["apple", "banana", "orange", "pear", "grape", ]
|
||||
["apple", "banana", "orange", "pear", "grape"]
|
||||
iex> Enum.slide(fruits, 1..3, 0)
|
||||
["banana", "grape", "orange", "apple", "pear"]
|
||||
iex> Enum.slide(fruits, 1..3, 4)
|
||||
["banana", "pear", "grape", "orange", "apple"]
|
||||
["apple", "pear", "banana", "grape", "orange"]
|
||||
```
|
||||
|
||||
## Reversing
|
||||
|
||||
@@ -227,7 +227,7 @@ Elixir also supports string interpolation:
|
||||
```elixir
|
||||
iex> string = "world"
|
||||
iex> "hello #{string}!"
|
||||
"hello world"
|
||||
"hello world!"
|
||||
```
|
||||
|
||||
String concatenation requires both sides to be strings but interpolation supports any data type that may be converted to a string:
|
||||
|
||||
@@ -223,7 +223,7 @@ It is important that a macro is defined before its usage. Failing to define a ma
|
||||
|
||||
```elixir
|
||||
iex> defmodule Sample do
|
||||
...> def four, do: two + two
|
||||
...> def four, do: two() + two()
|
||||
...> defmacrop two, do: 2
|
||||
...> end
|
||||
** (CompileError) iex:2: function two/0 undefined
|
||||
|
||||
@@ -36,9 +36,9 @@ expand(BitstrMeta, Fun, [{'::', Meta, [Left, Right]} | T], Acc, S, E, Alignment,
|
||||
MatchOrRequireSize = RequireSize or is_match_size(T, EL),
|
||||
EType = expr_type(ELeft),
|
||||
ExpectSize = case ELeft of
|
||||
_ when not MatchOrRequireSize -> optional;
|
||||
{'^', _, [{_, _, _}]} -> {infer, ELeft};
|
||||
_ when MatchOrRequireSize -> required;
|
||||
_ -> optional
|
||||
_ -> required
|
||||
end,
|
||||
{ERight, EAlignment, SS, ES} = expand_specs(EType, Meta, Right, SL, OriginalS, EL, ExpectSize),
|
||||
|
||||
|
||||
@@ -296,6 +296,28 @@ defmodule Code.Formatter.GeneralTest do
|
||||
assert_same code, @short_length
|
||||
end
|
||||
|
||||
test "keeps parens if argument includes keyword list" do
|
||||
assert_same """
|
||||
fn [] when is_integer(x) ->
|
||||
x + 42
|
||||
end
|
||||
"""
|
||||
|
||||
bad = """
|
||||
fn (input: x) when is_integer(x) ->
|
||||
x + 42
|
||||
end
|
||||
"""
|
||||
|
||||
good = """
|
||||
fn [input: x] when is_integer(x) ->
|
||||
x + 42
|
||||
end
|
||||
"""
|
||||
|
||||
assert_format bad, good
|
||||
end
|
||||
|
||||
test "with a single clause, followed by a newline, and can fit in one line" do
|
||||
assert_same """
|
||||
fn
|
||||
|
||||
@@ -255,6 +255,12 @@ defmodule Kernel.BinaryTest do
|
||||
assert <<1::size((^foo).bar)>> = <<1::5>>
|
||||
end
|
||||
|
||||
test "bitsyntax size with pinned integer" do
|
||||
a = 1
|
||||
b = <<2, 3>>
|
||||
assert <<^a, ^b::binary>> = <<1, 2, 3>>
|
||||
end
|
||||
|
||||
test "automatic size computation of matched bitsyntax variable" do
|
||||
var = "foo"
|
||||
<<^var::binary, rest::binary>> = "foobar"
|
||||
|
||||
@@ -277,6 +277,32 @@ defmodule URITest do
|
||||
test "preserves an empty query" do
|
||||
assert URI.new!("http://foo.com/?").query == ""
|
||||
end
|
||||
|
||||
test "without scheme, undefined port after host translates to nil" do
|
||||
assert URI.new!("//https://www.example.com") ==
|
||||
%URI{
|
||||
scheme: nil,
|
||||
userinfo: nil,
|
||||
host: "https",
|
||||
port: nil,
|
||||
path: "//www.example.com",
|
||||
query: nil,
|
||||
fragment: nil
|
||||
}
|
||||
end
|
||||
|
||||
test "with scheme, undefined port after host translates to nil" do
|
||||
assert URI.new!("myscheme://myhost:/path/info") ==
|
||||
%URI{
|
||||
scheme: "myscheme",
|
||||
userinfo: nil,
|
||||
host: "myhost",
|
||||
port: nil,
|
||||
path: "/path/info",
|
||||
query: nil,
|
||||
fragment: nil
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
test "http://http://http://@http://http://?http://#http://" do
|
||||
|
||||
@@ -216,7 +216,14 @@ defmodule ExUnit.CaptureIOTest do
|
||||
end)
|
||||
|
||||
capture_io("\"a", fn ->
|
||||
assert :io.scan_erl_form(~c">") == {:error, {1, :erl_scan, {:string, 34, ~c"a"}}, 1}
|
||||
error =
|
||||
if System.otp_release() >= "27" do
|
||||
{1, :erl_scan, {:unterminated, :string, ~c"a"}}
|
||||
else
|
||||
{1, :erl_scan, {:string, 34, ~c"a"}}
|
||||
end
|
||||
|
||||
assert :io.scan_erl_form(~c">") == {:error, error, 1}
|
||||
assert :io.scan_erl_form(~c">") == {:eof, 1}
|
||||
end)
|
||||
|
||||
|
||||
@@ -332,17 +332,26 @@ defmodule IEx.HelpersTest do
|
||||
assert help =~ "Welcome to Interactive Elixir"
|
||||
end
|
||||
|
||||
@tag :erlang_doc
|
||||
test "prints Erlang module documentation" do
|
||||
captured = capture_io(fn -> h(:timer) end)
|
||||
assert captured =~ "This module provides useful functions related to time."
|
||||
end
|
||||
|
||||
@tag :erlang_doc
|
||||
test "prints Erlang module function specs" do
|
||||
captured = capture_io(fn -> h(:timer.sleep() / 1) end)
|
||||
assert captured =~ ":timer.sleep/1"
|
||||
assert captured =~ "-spec sleep(Time) -> ok when Time :: timeout()."
|
||||
|
||||
# TODO Fix for OTP 27 once specs are available
|
||||
if System.otp_release() < "27" do
|
||||
assert captured =~ "-spec sleep(Time) -> ok when Time :: timeout()."
|
||||
else
|
||||
assert captured =~ "sleep(Time)"
|
||||
end
|
||||
end
|
||||
|
||||
@tag :erlang_doc
|
||||
test "handles non-existing Erlang module function" do
|
||||
captured = capture_io(fn -> h(:timer.baz() / 1) end)
|
||||
assert captured =~ "No documentation for :timer.baz was found"
|
||||
@@ -1008,23 +1017,47 @@ defmodule IEx.HelpersTest do
|
||||
cleanup_modules([TypeSample])
|
||||
end
|
||||
|
||||
test "prints all types in erlang module" do
|
||||
@tag :erlang_doc
|
||||
test "prints all types in Erlang module" do
|
||||
captured = capture_io(fn -> t(:queue) end)
|
||||
assert captured =~ "-type queue() :: queue(_)"
|
||||
assert captured =~ "-opaque queue(Item)"
|
||||
|
||||
# TODO Fix for OTP 27 once specs are available
|
||||
if System.otp_release() < "27" do
|
||||
assert captured =~ "-type queue() :: queue(_)"
|
||||
assert captured =~ "-opaque queue(Item)"
|
||||
else
|
||||
assert captured =~ "queue()"
|
||||
assert captured =~ "queue(Item)"
|
||||
end
|
||||
end
|
||||
|
||||
test "prints single type from erlang module" do
|
||||
@tag :erlang_doc
|
||||
test "prints single type from Erlang module" do
|
||||
captured = capture_io(fn -> t(:erlang.iovec()) end)
|
||||
assert captured =~ "-type iovec() :: [binary()]"
|
||||
|
||||
# TODO Fix for OTP 27 once specs are available
|
||||
if System.otp_release() < "27" do
|
||||
assert captured =~ "-type iovec() :: [binary()]"
|
||||
else
|
||||
assert captured =~ "iovec()"
|
||||
end
|
||||
|
||||
assert captured =~ "A list of binaries."
|
||||
|
||||
captured = capture_io(fn -> t(:erlang.iovec() / 0) end)
|
||||
assert captured =~ "-type iovec() :: [binary()]"
|
||||
|
||||
# TODO Fix for OTP 27 once specs are available
|
||||
if System.otp_release() < "27" do
|
||||
assert captured =~ "-type iovec() :: [binary()]"
|
||||
else
|
||||
assert captured =~ "iovec()"
|
||||
end
|
||||
|
||||
assert captured =~ "A list of binaries."
|
||||
end
|
||||
|
||||
test "handles non-existing types from erlang module" do
|
||||
@tag :erlang_doc
|
||||
test "handles non-existing types from Erlang module" do
|
||||
captured = capture_io(fn -> t(:erlang.foo()) end)
|
||||
assert captured =~ "No type information for :erlang.foo was found or :erlang.foo is private"
|
||||
|
||||
|
||||
@@ -7,11 +7,19 @@ IEx.configure(colors: [enabled: false])
|
||||
{line_exclude, line_include} =
|
||||
if line = System.get_env("LINE"), do: {[:test], [line: line]}, else: {[], []}
|
||||
|
||||
erlang_doc_exclude =
|
||||
if match?({:docs_v1, _, _, _, %{}, _, _}, Code.fetch_docs(:array)) do
|
||||
[]
|
||||
else
|
||||
IO.puts("Erlang/OTP compiled without docs, some tests are excluded...")
|
||||
[:erlang_doc]
|
||||
end
|
||||
|
||||
ExUnit.start(
|
||||
assert_receive_timeout: assert_timeout,
|
||||
trace: !!System.get_env("TRACE"),
|
||||
include: line_include,
|
||||
exclude: line_exclude
|
||||
exclude: line_exclude ++ erlang_doc_exclude
|
||||
)
|
||||
|
||||
defmodule IEx.Case do
|
||||
|
||||
@@ -867,9 +867,12 @@ defmodule Logger do
|
||||
|
||||
defp update_translators(updater) do
|
||||
:elixir_config.serial(fn ->
|
||||
translators = updater.(Application.fetch_env!(:logger, :translators))
|
||||
Application.put_env(:logger, :translators, translators)
|
||||
|
||||
with %{filters: filters} <- :logger.get_primary_config(),
|
||||
{{_, {fun, config}}, filters} <- List.keytake(filters, :logger_translator, 0) do
|
||||
config = update_in(config.translators, updater)
|
||||
config = %{config | translators: translators}
|
||||
:ok = :logger.set_primary_config(:filters, filters ++ [logger_translator: {fun, config}])
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -58,7 +58,9 @@ defmodule Logger.Backends.HandlerTest do
|
||||
end
|
||||
|
||||
test "add_translator/1 and remove_translator/1 for logger formats" do
|
||||
refute {CustomTranslator, :t} in Application.fetch_env!(:logger, :translators)
|
||||
assert Logger.add_translator({CustomTranslator, :t})
|
||||
assert {CustomTranslator, :t} in Application.fetch_env!(:logger, :translators)
|
||||
|
||||
assert capture_log(fn ->
|
||||
:logger.info(~c"hello: ~p", [:ok])
|
||||
|
||||
@@ -43,7 +43,11 @@ defmodule Mix.Tasks.Compile.All do
|
||||
Code.delete_paths(current_paths -- loaded_paths)
|
||||
end
|
||||
|
||||
Code.prepend_paths(loaded_paths -- current_paths, cache: true)
|
||||
# Add the current compilation path. compile.elixir and compile.erlang
|
||||
# will also add this path, but only if they run, so we always add it
|
||||
# here too. Furthermore, we don't cache it as we may still write to it.
|
||||
compile_path = to_charlist(Mix.Project.compile_path())
|
||||
Code.prepend_paths([compile_path | loaded_paths -- current_paths], cache: true)
|
||||
|
||||
result =
|
||||
if "--no-compile" in args do
|
||||
@@ -64,12 +68,6 @@ defmodule Mix.Tasks.Compile.All do
|
||||
Mix.AppLoader.write_cache(app_cache, Map.new(loaded_modules))
|
||||
end
|
||||
|
||||
# Add the current compilation path. compile.elixir and compile.erlang
|
||||
# will also add this path, but only if they run, so we always add it
|
||||
# here too. Furthermore, we don't cache it as we may still write to it.
|
||||
compile_path = to_charlist(Mix.Project.compile_path())
|
||||
_ = Code.prepend_path(compile_path)
|
||||
|
||||
unless "--no-app-loading" in args do
|
||||
app = config[:app]
|
||||
|
||||
|
||||
@@ -19,6 +19,14 @@ defmodule Mix.Tasks.Compile.ElixirTest do
|
||||
|
||||
in_fixture("no_mixfile", fn ->
|
||||
Mix.Project.push(MixTest.Case.Sample)
|
||||
|
||||
File.write!("lib/a.ex", """
|
||||
defmodule A, do: :ok
|
||||
|
||||
# Also make sure that we access the ebin directory during compilation
|
||||
true = to_charlist(Mix.Project.compile_path()) in :code.get_path()
|
||||
""")
|
||||
|
||||
Mix.Tasks.Compile.Elixir.run(["--verbose"])
|
||||
|
||||
assert File.regular?("_build/shared/lib/sample/ebin/Elixir.A.beam")
|
||||
@@ -32,6 +40,14 @@ defmodule Mix.Tasks.Compile.ElixirTest do
|
||||
test "compiles a project with per environment build" do
|
||||
in_fixture("no_mixfile", fn ->
|
||||
Mix.Project.push(MixTest.Case.Sample)
|
||||
|
||||
File.write!("lib/a.ex", """
|
||||
defmodule A, do: :ok
|
||||
|
||||
# Also make sure that we access the ebin directory during compilation
|
||||
true = to_charlist(Mix.Project.compile_path()) in :code.get_path()
|
||||
""")
|
||||
|
||||
Mix.Tasks.Compile.Elixir.run(["--verbose"])
|
||||
|
||||
assert File.regular?("_build/dev/lib/sample/ebin/Elixir.A.beam")
|
||||
@@ -772,7 +788,7 @@ defmodule Mix.Tasks.Compile.ElixirTest do
|
||||
end)
|
||||
end
|
||||
|
||||
test "compiles mtime changed files if content changed but not length" do
|
||||
test "recompiles mtime changed files if content changed but not length" do
|
||||
in_fixture("no_mixfile", fn ->
|
||||
Mix.Project.push(MixTest.Case.Sample)
|
||||
assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
|
||||
@@ -872,7 +888,7 @@ defmodule Mix.Tasks.Compile.ElixirTest do
|
||||
end)
|
||||
end
|
||||
|
||||
test "compiles size changed files" do
|
||||
test "recompiles size changed files" do
|
||||
in_fixture("no_mixfile", fn ->
|
||||
Mix.Project.push(MixTest.Case.Sample)
|
||||
past = @old_time
|
||||
@@ -894,7 +910,7 @@ defmodule Mix.Tasks.Compile.ElixirTest do
|
||||
end)
|
||||
end
|
||||
|
||||
test "compiles dependent changed modules" do
|
||||
test "recompiles dependent changed modules" do
|
||||
in_fixture("no_mixfile", fn ->
|
||||
Mix.Project.push(MixTest.Case.Sample)
|
||||
File.write!("lib/a.ex", "defmodule A, do: B.module_info()")
|
||||
@@ -914,7 +930,7 @@ defmodule Mix.Tasks.Compile.ElixirTest do
|
||||
end)
|
||||
end
|
||||
|
||||
test "compiles dependent changed modules without beam files" do
|
||||
test "recompiles dependent changed modules without beam files" do
|
||||
in_fixture("no_mixfile", fn ->
|
||||
Mix.Project.push(MixTest.Case.Sample)
|
||||
|
||||
@@ -943,7 +959,7 @@ defmodule Mix.Tasks.Compile.ElixirTest do
|
||||
Code.put_compiler_option(:ignore_module_conflict, false)
|
||||
end
|
||||
|
||||
test "compiles dependent changed modules even on removal" do
|
||||
test "recompiles dependent changed modules even on removal" do
|
||||
in_fixture("no_mixfile", fn ->
|
||||
Mix.Project.push(MixTest.Case.Sample)
|
||||
File.write!("lib/a.ex", "defmodule A, do: B.module_info()")
|
||||
@@ -964,7 +980,7 @@ defmodule Mix.Tasks.Compile.ElixirTest do
|
||||
end)
|
||||
end
|
||||
|
||||
test "compiles dependent changed on conflict" do
|
||||
test "recompiles dependent changed on conflict" do
|
||||
in_fixture("no_mixfile", fn ->
|
||||
Mix.Project.push(MixTest.Case.Sample)
|
||||
|
||||
@@ -991,7 +1007,7 @@ defmodule Mix.Tasks.Compile.ElixirTest do
|
||||
end)
|
||||
end
|
||||
|
||||
test "compiles dependent changed external resources" do
|
||||
test "recompiles dependent changed external resources" do
|
||||
in_fixture("no_mixfile", fn ->
|
||||
Mix.Project.push(MixTest.Case.Sample)
|
||||
tmp = tmp_path("c.eex")
|
||||
|
||||
Reference in New Issue
Block a user