Skip to content

Commit c001cbd

Browse files
committed
Start v1.20
1 parent 577c803 commit c001cbd

File tree

7 files changed

+20
-292
lines changed

7 files changed

+20
-292
lines changed

CHANGELOG.md

Lines changed: 5 additions & 279 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
SPDX-FileCopyrightText: 2012 Plataformatec
55
-->
66

7-
# Changelog for Elixir v1.19
7+
# Changelog for Elixir v1.20
88

99
## Type system improvements
1010

11-
### More type inference
11+
### Full type inference
1212

1313
Elixir now performs inference of whole functions. The best way to show the new capabilities are with examples. Take the following code:
1414

@@ -30,294 +30,20 @@ end
3030

3131
Even though the `+` operator works with both integers and floats, Elixir infers that `a` and `b` must be both integers, as the result of `+` is given to a function that expects an integer. The inferred type information is then used during type checking to find possible typing errors.
3232

33-
### Type checking of protocol dispatch and implementations
34-
35-
This release also adds type checking when dispatching and implementing protocols.
36-
37-
For example, string interpolation in Elixir uses the `String.Chars` protocol. If you pass a value that does not implement said protocol, Elixir will now emit a warning accordingly.
38-
39-
Here is an example passing a range, which cannot be converted into a string, to an interpolation:
40-
41-
```elixir
42-
defmodule Example do
43-
def my_code(first..last//step = range) do
44-
"hello #{range}"
45-
end
46-
end
47-
```
48-
49-
the above emits the following warnings:
50-
51-
```
52-
warning: incompatible value given to string interpolation:
53-
54-
data
55-
56-
it has type:
57-
58-
%Range{first: term(), last: term(), step: term()}
59-
60-
but expected a type that implements the String.Chars protocol, it must be one of:
61-
62-
dynamic(
63-
%Date{} or %DateTime{} or %NaiveDateTime{} or %Time{} or %URI{} or %Version{} or
64-
%Version.Requirement{}
65-
) or atom() or binary() or float() or integer() or list(term())
66-
```
67-
68-
Warnings are also emitted if you pass a data type that does not implement the `Enumerable` protocol as a generator to for-comprehensions:
69-
70-
```elixir
71-
defmodule Example do
72-
def my_code(%Date{} = date) do
73-
for(x <- date, do: x)
74-
end
75-
end
76-
```
77-
78-
will emit:
79-
80-
```
81-
warning: incompatible value given to for-comprehension:
82-
83-
x <- date
84-
85-
it has type:
86-
87-
%Date{year: term(), month: term(), day: term(), calendar: term()}
88-
89-
but expected a type that implements the Enumerable protocol, it must be one of:
90-
91-
dynamic(
92-
%Date.Range{} or %File.Stream{} or %GenEvent.Stream{} or %HashDict{} or %HashSet{} or
93-
%IO.Stream{} or %MapSet{} or %Range{} or %Stream{}
94-
) or fun() or list(term()) or non_struct_map()
95-
```
96-
97-
### Type checking and inference of anonymous functions
98-
99-
Elixir v1.19 can now type infer and type check anonymous functions. Here is a trivial example:
100-
101-
```elixir
102-
defmodule Example do
103-
def run do
104-
fun = fn %{} -> :map end
105-
fun.("hello")
106-
end
107-
end
108-
```
109-
110-
The example above has an obvious typing violation, as the anonymous function expects a map but a string is given. With Elixir v1.19, the following warning is now printed:
111-
112-
```
113-
warning: incompatible types given on function application:
114-
115-
fun.("hello")
116-
117-
given types:
118-
119-
binary()
120-
121-
but function has type:
122-
123-
(dynamic(map()) -> :map)
124-
125-
typing violation found at:
126-
127-
6 │ fun.("hello")
128-
│ ~
129-
130-
└─ mod.exs:6:8: Example.run/0
131-
```
132-
133-
Function captures, such as `&String.to_integer/1`, will also propagate the type as of Elixir v1.19, arising more opportunity for Elixir's type system to catch bugs in our programs.
134-
13533
### Acknowledgements
13634

13735
The type system was made possible thanks to a partnership between [CNRS](https://www.cnrs.fr/) and [Remote](https://remote.com/). The development work is currently sponsored by [Fresha](https://www.fresha.com/), [Starfish*](https://starfish.team/), and [Dashbit](https://dashbit.co/).
13836

139-
## Faster compile times in large projects
140-
141-
This release includes two compiler improvements that can lead up to 4x faster builds in large codebases.
142-
143-
While Elixir has always compiled the given files in project or a dependency in parallel, the compiler would sometimes be unable to use all of the machine resources efficiently. This release addresses two common limitations, delivering performance improvements that scale with codebase size and available CPU cores.
144-
145-
### Code loading bottlenecks
146-
147-
Prior to this release, Elixir would load modules as soon as they were defined. However, because the Erlang part of code loading happens within a single process (the code server), this would make it a bottleneck, reducing the amount of parallelization, especially on large projects.
148-
149-
This release makes it so modules are loaded lazily. This reduces the pressure on the code server, making compilation up to 2x faster for large projects, and also reduces the overall amount of work done during compilation.
150-
151-
Implementation wise, [the parallel compiler already acts as a mechanism to resolve modules during compilation](https://elixir-lang.org/blog/2012/04/24/a-peek-inside-elixir-s-parallel-compiler/), so we built on that. By making sure the compiler controls both module compilation and module loading, it can also better guarantee deterministic builds.
152-
153-
The only potential regression in this approach happens if you have a module, which is used at compile time and defines an `@on_load` callback (typically used for [NIFs](https://www.erlang.org/doc/system/nif.html)) that invokes another modules within the same project. For example:
154-
155-
```elixir
156-
defmodule MyLib.SomeModule do
157-
@on_load :init
158-
159-
def init do
160-
MyLib.AnotherModule.do_something()
161-
end
162-
163-
def something_else do
164-
...
165-
end
166-
end
167-
168-
MyLib.SomeModule.something_else()
169-
```
170-
171-
The reason this fails is because `@on_load` callbacks are invoked within the code server and therefore they have limited ability to load additional modules. It is generally advisable to limit invocation of external modules during `@on_load` callbacks but, in case it is strictly necessary, you can set `@compile {:autoload, true}` in the invoked module to address this issue in a forward and backwards compatible manner.
172-
173-
### Parallel compilation of dependencies
174-
175-
This release introduces a variable called `MIX_OS_DEPS_COMPILE_PARTITION_COUNT`, which instructs `mix deps.compile` to compile dependencies in parallel.
176-
177-
While fetching dependencies and compiling individual Elixir dependencies already happened in parallel, there were pathological cases where performance would be left on the table, such as compiling dependencies with native code or dependencies where one or two large file would take over most of the compilation time.
178-
179-
By setting `MIX_OS_DEPS_COMPILE_PARTITION_COUNT` to a number greater than 1, Mix will now compile multiple dependencies at the same time, using separate OS processes. Empirical testing shows that setting it to half of the number of cores on your machine is enough to maximize resource usage. The exact speed up will depend on the number of dependencies and the number of machine cores, although some reports mention up to 4x faster compilation times. If you plan to enable it on CI or build servers, keep in mind it will most likely have a direct impact on memory usage too.
180-
181-
## Improved pretty printing algorithm
182-
183-
Elixir v1.19 ships with a new pretty printing implementation that tracks limits as a whole, instead of per depth. Previous versions would track limits per depth. For example, if you had a list of lists of 4 elements and a limit of 5, it would be pretty printed as follows:
184-
185-
```elixir
186-
[
187-
[1, 2, 3],
188-
[1, 2, ...],
189-
[1, ...],
190-
[...],
191-
...
192-
]
193-
```
194-
195-
This allows for more information to be shown at different nesting levels, which is useful for complex data structures. But it led to some pathological cases where the `limit` option had little effect on actually filtering the amount of data shown. The new implementation decouples the limit handling from depth, decreasing it as it goes. Therefore, the list above with the same limit in Elixir v1.19 is now printed as:
196-
197-
```elixir
198-
[
199-
[1, 2, 3],
200-
...
201-
]
202-
```
203-
204-
The outer list is the first element, the first nested list is the second, followed by three numbers, reaching the limit. This gives developers more precise control over pretty printing.
205-
206-
Given this may reduce the amount of data printed by default, the default limit has also been increased from 50 to 100. We may further increase it in upcoming releases based on community feedback.
207-
208-
## OpenChain certification
209-
210-
Elixir v1.19 is also our first release following OpenChain compliance, [as previously announced](https://elixir-lang.org/blog/2025/02/26/elixir-openchain-certification/). In a nutshell:
211-
212-
* Elixir releases now include a Source SBoM in CycloneDX 1.6 or later and SPDX 2.3 or later formats.
213-
* Each release is attested along with the Source SBoM.
214-
215-
These additions offer greater transparency into the components and licenses of each release, supporting more rigorous supply chain requirements.
216-
217-
This work was performed by Jonatan Männchen and sponsored by the Erlang Ecosystem Foundation.
218-
219-
## v1.19.0-dev
37+
## v1.20.0-dev
22038

22139
### 1. Enhancements
22240

223-
#### Elixir
224-
225-
* [Access] Add `Access.values/0` for traversing maps and keyword lists values
226-
* [Base] Add functions to verify if an encoding is valid, such as `valid16?`, `valid64?`, and so forth
227-
* [Calendar] Support 2-arity options for `Calendar.strftime/3` which receives the whole data type
228-
* [Code] Add `:migrate_call_parens_on_pipe` formatter option
229-
* [Code] Add `:indentation` option to `Code.string_to_quoted/2`
230-
* [Code.Fragment] Preserve more block content around cursor in `container_cursor_to_quoted`
231-
* [Code.Fragment] Add `:block_keyword_or_binary_operator` to `Code.Fragment` for more precise suggestions after operators and closing terminators
232-
* [Code.Fragment] Add `Code.Fragment.lines/1`
233-
* [Enum] Provide more information on `Enum.OutOfBoundsError`
234-
* [Inspect] Allow `optional: :all` when deriving Inspect
235-
* [Inspect.Algebra] Add optimistic/pessimistic groups as a simplified implementation of `next_break_fits`
236-
* [IO.ANSI] Add ANSI codes to turn off conceal and crossed_out
237-
* [Kernel] Allow controlling which applications are used during inference
238-
* [Kernel] Support `min/2` and `max/2` as guards
239-
* [Kernel.ParallelCompiler] Add `each_long_verification_threshold` which invokes a callback when type checking a module takes too long
240-
* [Kernel.ParallelCompiler] Include lines in `== Compilation error in file ... ==` slogans
241-
* [Macro] Print debugging results from `Macro.dbg/3` as they happen, instead of once at the end
242-
* [Module] Do not automatically load modules after their compilation, guaranteeing a more consistent compile time experience and drastically improving compilation times
243-
* [Protocol] Type checking of protocols dispatch and implementations
244-
* [Regex] Add `Regex.to_embed/2` which returns an embeddable representation of regex in another regex
245-
* [String] Add `String.count/2` to count occurrences of a pattern
246-
247-
#### ExUnit
248-
249-
* [ExUnit.CaptureLog] Parallelize log dispatch when multiple processes are capturing log
250-
* [ExUnit.Case] Add `:test_group` to the test context
251-
* [ExUnit.Doctest] Support ellipsis in doctest exceptions to match the remaining of the exception
252-
* [ExUnit.Doctest] Add `:inspect_opts` option for doctest
253-
254-
#### IEx
255-
256-
* [IEx] Support multi-line prompts (due to this feature, `:continuation_prompt` and `:alive_continuation_prompt` are no longer supported as IEx configuration)
257-
* [IEx.Autocomplete] Functions annotated with `@doc group: "Name"` metadata will appear within their own groups in autocompletion
258-
259-
#### Mix
260-
261-
* [mix] Add support for `MIX_PROFILE_FLAGS` to configure `MIX_PROFILE`
262-
* [mix compile] Debug the compiler and type checker PID when `MIX_DEBUG=1` and compilation/verification thresholds are met
263-
* [mix compile] Add `Mix.Tasks.Compiler.reenable/1`
264-
* [mix deps.compile] Support `MIX_OS_DEPS_COMPILE_PARTITION_COUNT` for compiling deps concurrently across multiple operating system processes
265-
* [mix help] Add `mix help Mod`, `mix help :mod`, `mix help Mod.fun` and `mix help Mod.fun/arity`
266-
* [mix test] Allow to distinguish the exit status between warnings as errors and test failures
267-
* [mix xref graph] Add support for `--format json`
268-
* [mix xref graph] Emit a warning if `--source` is part of a cycle
269-
* [M ix.Task.Compiler] Add `Mix.Task.Compiler.run/2`
270-
27141
### 2. Bug fixes
27242

273-
#### Elixir
274-
275-
* [DateTime] Do not truncate microseconds regardless of precision in `DateTime.diff/3`
276-
* [File] Properly handle permissions errors cascading from parent in `File.mkdir_p/1`
277-
* [Kernel] `not_a_map.key` now raises `BadMapError` for consistency with other map operations
278-
* [Regex] Fix `Regex.split/2` returning too many results when the chunk being split on was empty (which can happen when using features such as `/K`)
279-
* [Stream] Ensure `Stream.transform/5` respects suspend command when its inner stream halts
280-
* [URI] Several fixes to `URI.merge/2` related to trailing slashes, trailing dots, and hostless base URIs
281-
282-
#### Mix
283-
284-
* [mix cmd] Preserve argument quoting in subcommands
285-
* [mix format] Ensure the formatter does not go over the specified limit in certain corner cases
286-
* [mix release] Fix `RELEASE_SYS_CONFIG` for Windows 11
287-
* [mix test] Preserve files with no longer filter on `mix test`
288-
* [mix xref graph] Provide more consistent output by considering strong connected components only when computing graphs
289-
29043
### 3. Soft deprecations (no warnings emitted)
29144

292-
#### Elixir
293-
294-
* [Inspect.Algebra] `next_break_fits` is deprecated in favor of `optimistic`/`pessimistic` groups
295-
* [Node] `Node.start/2-3` is deprecated in favor of `Node.start/2` with a keyword list
296-
297-
#### Mix
298-
299-
* [mix compile] `--no-protocol-consolidation` is deprecated in favor of `--no-consolidate-protocols` for consistency with `mix.exs` configuration
300-
* [mix compile.protocols] Protocol consolidation is now part of `compile.elixir` and has no effect
301-
30245
### 4. Hard deprecations
30346

304-
#### Elixir
305-
306-
* [Code] The `on_undefined_variable: :warn` is deprecated. Relying on undefined variables becoming function calls will not be supported in the future
307-
* [File] Passing a callback as third argument to `File.cp/3` is deprecated, pass it as a `on_conflict: callback` option instead
308-
* [File] Passing a callback as third argument to `File.cp_r/3` is deprecated, pass it as a `on_conflict: callback` option instead
309-
* [Kernel] The struct update syntax, such as `%URI{uri | path: "/foo/bar"}` is deprecated in favor of pattern matching on the struct when the variable is defined and then using the map update syntax `%{uri | path: "/foo/bar"}`. Thanks to the type system, pattern matching on structs can find more errors, more reliably
310-
* [Kernel.ParallelCompiler] Passing `return_diagnostics: true` as an option is required on `compile`, `compile_to_path` and `require`
311-
312-
#### Logger
313-
314-
* [Logger] The `:backends` configuration is deprecated, either set the `:default_handler` to false or start backends in your application start callback
315-
316-
#### Mix
317-
318-
* [mix] The `:default_task`, `:preferred_cli_env`, and `:preferred_cli_target` configuration inside `def project` in your `mix.exs` has been deprecated in favor of `:default_task`, `:preferred_envs` and `:preferred_targets` inside the `def cli` function
319-
* [mix do] Using commas as task separator in `mix do` (such as `mix do foo, bar`) is deprecated, use `+` instead (as in `mix do foo + bar`)
320-
321-
## v1.18
47+
## v1.19
32248

323-
The CHANGELOG for v1.18 releases can be found [in the v1.18 branch](https://github.com/elixir-lang/elixir/blob/v1.18/CHANGELOG.md).
49+
The CHANGELOG for v1.19 releases can be found [in the v1.19 branch](https://github.com/elixir-lang/elixir/blob/v1.19/CHANGELOG.md).

RELEASE.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88

99
## Shipping a new version
1010

11-
1. Update version in /VERSION, bin/elixir, bin/elixir.bat, and bin/elixir.ps1
11+
1. Update version in /VERSION, bin/elixir, and bin/elixir.bat
1212

1313
2. Ensure /CHANGELOG.md is updated, versioned and add the current date
14+
1415
- If this release addresses any publicly known security vulnerabilities with
1516
assigned CVEs, add a "Security" section to `CHANGELOG.md`. For example:
1617
```md
@@ -34,15 +35,15 @@
3435

3536
### In the new branch
3637

37-
1. Comment the `CANONICAL=` in /Makefile
38+
1. Comment out `CANONICAL := main/` in /Makefile
3839

3940
2. Update tables in /SECURITY.md and "Compatibility and Deprecations"
4041

4142
3. Commit "Branch out vMAJOR.MINOR"
4243

4344
### Back in main
4445

45-
1. Bump /VERSION file, bin/elixir, bin/elixir.bat, and bin/elixir.ps1
46+
1. Bump /VERSION file, bin/elixir, and bin/elixir.bat
4647

4748
2. Start new /CHANGELOG.md
4849

SECURITY.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ Elixir applies bug fixes only to the latest minor branch. Security patches are a
1212

1313
Elixir version | Support
1414
:------------- | :-----------------------------
15-
1.19 | Development
16-
1.18 | Bug fixes and security patches
15+
1.20 | Development
16+
1.19 | Bug fixes and security patches
17+
1.18 | Security patches only
1718
1.17 | Security patches only
1819
1.16 | Security patches only
1920
1.15 | Security patches only
20-
1.14 | Security patches only
2121

2222
## Announcements
2323

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.19.0-dev
1+
1.20.0-dev

bin/elixir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
set -e
88

9-
ELIXIR_VERSION=1.19.0-dev
9+
ELIXIR_VERSION=1.20.0-dev
1010

1111
if [ $# -eq 0 ] || { [ $# -eq 1 ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; }; then
1212
cat <<USAGE >&2

bin/elixir.bat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
:: SPDX-FileCopyrightText: 2021 The Elixir Team
55
:: SPDX-FileCopyrightText: 2012 Plataformatec
66

7-
set ELIXIR_VERSION=1.19.0-dev
7+
set ELIXIR_VERSION=1.20.0-dev
88

99
if ""%1""=="""" if ""%2""=="""" goto documentation
1010
if /I ""%1""==""--help"" if ""%2""=="""" goto documentation

0 commit comments

Comments
 (0)