changelog/v1.13.md
Fixed a bug where the "Extract function" code action would not properly
extract a use expression.
(Giacomo Cavalieri)
Fixed a bug where the "Extract function" code action would generate a function with the wrong type when used on a use expression. (Giacomo Cavalieri)
Fixed a bug where the error message for inexhaustive patterns could show incorrect extra patterns in addition to the correct missing patterns. (Adi Salimgereyev)
Fixed a bug where triggering the "Generate function" code action to generate a function in a different module could cause the generated function to appear in the middle of an existing function, resulting in invalid code. (Surya Rose)
Fixed a bug where the "turn into pipe" code action would not trigger inside the final step of a pipeline. (Giacomo Cavalieri)
Fixed a bug where the "pattern match on variable" code action would crash when used on a variable followed by a case expression. (Giacomo Cavalieri)
The compiler now applies an optimisation known as "interference based pruning" when compiling bit array pattern matching where matches are performed at the start of bit arrays. This optimisation drastically reduces compile times, memory usage and the compiled code size, removing many redundant checks. It is particularly important for network protocol applications where it is typical to match on some fixed patterns at the start of the bitarray. For example:
pub fn parser_headers(headers: BitArray, bytes: Int) -> Headers {
case headers {
<<"CONTENT_LENGTH" as header, 0, value:size(bytes), 0, rest:bytes>>
| <<"QUERY_STRING" as header, 0, value:size(bytes), 0, rest:bytes>>
| <<"REQUEST_URI" as header, 0, value:size(bytes), 0, rest:bytes>>
// ...
| <<"REDIRECT_STATUS" as header, 0, value:size(bytes), 0, rest:bytes>>
| <<"SCRIPT_NAME" as header, 0, value:size(bytes), 0, rest:bytes>>
-> [#(header, value), ..parse_headers(rest)]
}
}
The compiler now raises a warning for unreachable clauses that are matching on bit array segments that could never match. Consider this example:
pub fn get_payload(packet: BitArray) -> Result(BitArray, Nil) {
case packet {
<<200, payload:bytes>> -> Ok(payload)
<<404, _:bits>> -> Error(Nil)
_ -> Ok(packet)
}
}
There's a subtle bug here. The second clause can never match since it's
impossible for the first byte of the bit array to have the value 404.
The new error explains this nicely:
warning: Unreachable pattern
┌─ /src.gleam:4:5
│
4 │ <<404, _:bits>> -> Error(Nil)
│ ^^^^^^^^^^^^^^^
│ │
│ A 1 byte unsigned integer will never match this value
This pattern cannot be reached as it contains segments that will never
match.
Hint: It can be safely removed.
The compiler now raises a warning when a function's argument is only passed along in a recursive call but not actually used for anything. For example:
import gleam/io
pub fn greet(x, times) {
case times {
0 -> Nil
_ -> {
io.println("Hello, Joe!")
greet(x, times - 1)
}
}
}
In this piece of code the x argument is actually never used, and the
compiler will raise the following warning:
warning: Unused function argument
┌─ /Users/giacomocavalieri/Desktop/prova/src/prova.gleam:3:14
│
3 │ pub fn greet(x, times) {
│ ^ This argument is unused
This argument is passed to the function when recursing, but it's never used
for anything.
The compiler now emits a better error message for private types marked as opaque. For example, the following piece of code:
opaque type Wibble {
Wobble
}
Would result in the following error:
error: Private opaque type
┌─ /src/one/two.gleam:2:1
│
2 │ opaque type Wibble {
│ ^^^^^^ You can safely remove this.
Only a public type can be opaque.
The parsing of opaque private types is now fault tolerant: having a private opaque type in a module no longer stops the compiler from highlighting other errors. (Giacomo Cavalieri)
The compiler now emits a single warning for multiple negations in a row, while previously it would emit multiple comments highlighting increasingly longer spans. (Giacomo Cavalieri)
Redundant _ as x patterns are now deprecated in favour of x.
(eutampieri)
The compiler will now raise warning for inefficient use of list.length()
when trying to check is list empty via 0 < list.length(list) or
list.length(list) > 0 as well as in other cases. For example, the following
code:
import gleam/list
pub fn main() {
let numbers = [1, 46]
let _ = 0 < list.length(numbers)
let _ = list.length(numbers) > 0
}
Would result in following warnings:
warning: Inefficient use of `list.length`
┌─ /data/data/com.termux/files/home/test_gleam/src/test_gleam.gleam:5:13
│
5 │ let _ = 0 < list.length(numbers)
│ ^^^^^^^^^^^^^^^^^^^^^^^^
The `list.length` function has to iterate across the whole
list to calculate the length, which is wasteful if you only
need to know if the list is empty or not.
Hint: You can use `the_list != []` instead.
warning: Inefficient use of `list.length`
┌─ /data/data/com.termux/files/home/test_gleam/src/test_gleam.gleam:6:13
│
6 │ let _ = list.length(numbers) > 0
│ ^^^^^^^^^^^^^^^^^^^^^^^^
The `list.length` function has to iterate across the whole
list to calculate the length, which is wasteful if you only
need to know if the list is empty or not.
Hint: You can use `the_list != []` instead.
The compiler now provides an improved error message for when trying to define a constant inside a function. For example, the following code:
pub fn deep_thought() -> Int {
const the_answer = 42
the_answer
}
Will produce this error message:
error: Syntax error
┌─ /src/file.gleam:2:3
│
3 │ const the_answer = 43
│ ^^^^^ Constants are not allowed inside functions
All variables are immutable in Gleam, so constants inside functions are not
necessary.
Hint: Either move this into the global scope or use `let` binding instead.
The code generated for blocks on the JavaScript target has been improved and is now smaller in certain cases. (Surya Rose)
Writing a type name followed by () now emits an error during analysis
rather than parsing, so it no longer stops the compiler from reporting errors
further in the code.
(Giacomo Cavalieri)
The compiler now shows a specific syntax error when trying to use an angle-bracket syntax for generic types or function definitions:
error: Syntax error
┌─ /src/parse/error.gleam:2:12
│
2 │ type Either<a, b> {
│ ^ I was expecting `(` here.
Type parameters use lowercase names and are surrounded by parentheses.
type Either(a, b) {
See: https://tour.gleam.run/data-types/generic-custom-types/
Fault tolerance for analysis of labeled fields in variant patterns has been improved. (sobolevn)
Compiler now adds a hint when #-styled comments are used. This code:
fn some() {
let a = 1
# let b = 2
}
Now produces:
error: Syntax error
┌─ /src/main.gleam:3:5
│
3 │ # let b = 2
│ ^^^ I was not expecting this
Found the keyword `let`, expected one of:
- `(`
Hint: Maybe you meant to create a comment?
Comments in Gleam start with `//`, not `#`
(sobolevn)
The erlang.application_start_argument parameter has been added to
gleam.toml. This is a string containing an Erlang term that will be written
into the package's Erlang .app file if erlang.application_start_module
has been set, replacing the default argument of [].
(Louis Pilfold)
Generated code for the JavaScript target now includes a public API which can be used for FFI interacting with Gleam custom types. For example, if you have this Gleam code:
pub type Person {
Teacher(name: String, subject: String)
Student(name: String, age: Int)
}
You can use the new API to use the Person type in FFI code:
import {...} from "./person.mjs";
// Constructing custom types
let teacher = Person$Teacher("Joe Armstrong", "Computer Science");
let student = Person$Student("Louis Pilfold");
let randomPerson = Math.random() > 0.5 ? teacher : student;
// Checking variants
let randomIsTeacher = Person$isTeacher(randomPerson);
// Getting fields
let teacherSubject = Person$Teacher$subject(teacher);
// The `name` field is shared so can be accessed from either variant
let personName = Person$name(randomPerson);
New projects are generated using OTP28 on GitHub Actions. (Louis Pilfold)
The build tool now has a new hex owner transfer subcommand to transfer
ownership of existing packages.
(Giacomo Cavalieri)
gleam add now adds dependencies and dev_dependencies as tables instead
of inline tables if they are missing.
(Andrey Kozhev)
After dependency resolution the build tool will now print all packages added and removed, and any versions changed. (Louis Pilfold)
gleam publish now blocks publishing packages that contain the default main
function to prevent accidental publishing of unmodified template code.
(Joohoon Cha)
When generating documentation, the build tool will now print the names of public type aliases instead of internal type names when annotating functions and types. For example, for the following code:
import my_package/internal
pub type ExternalAlias = internal.InternalRepresentation
pub fn do_thing() -> ExternalAlias { ... }
This is what the build tool used to generate:
pub fn do_thing() -> @internal InternalRepresentation
Whereas now it will not use the internal name, and instead produce:
pub fn do_thing() -> ExternalAlias
Support has been added for using Tangled as a repository. (Naomi Roberts)
The language server now offers a code action to remove all the unreachable clauses in a case expression. For example:
pub fn main() {
case find_user() {
Ok(user) -> todo
Ok(Admin) -> todo
// ^^^^^^^^^ This clause is unreachable
Ok(User) -> todo
// ^^^^^^^^ This clause is unreachable
Error(_) -> todo
}
}
Hovering over one of the unreachable clauses and triggering the code action would remove all the unreachable clauses:
pub fn main() {
case find_user() {
Ok(user) -> todo
Error(_) -> todo
}
}
The "pattern match on variable" can now be triggered on lists. For example:
pub fn is_empty(list: List(a)) -> Bool {
// ^^^^ Triggering the action here
}
Triggering the action on the list argument would result in the following
code:
pub fn is_empty(list: List(a)) -> Bool {
case list {
[] -> todo
[first, ..rest] -> todo
}
}
The "pattern match on variable" code action can now be triggered on variables introduced by other patterns. For example:
pub fn main() {
let User(name:, role:) = find_user("lucy")
// ^^^^ Triggering the action here
}
Triggering the action on another variable like role would result in the
following code:
pub fn main() {
let User(name:, role:) = find_user("lucy")
case role {
Admin -> todo
Member -> todo
}
}
The "pattern match on variable" code action can now be triggered on variables in case expressions. For example:
pub fn main() {
case find_user() {
Ok(user) -> todo
Error(_) -> todo
}
}
Triggering the action on the user variable would result in the following
code:
pub fn main() {
case find_user() {
Ok(Admin) -> todo
Ok(Member) -> todo
Error(_) -> todo
}
}
The language server now offers a quick fix to remove opaque from a private
type:
opaque type Wibble {
// ^^^ This is an error!
Wobble
}
If you hover over the type and trigger the quick fix, the language server will
automatically remove the opaque keyword:
type Wibble {
Wobble
}
The language server now offers a code action to add the omitted labels in a call. For example:
pub type User {
User(first_name: String, last_name: String, likes: List(String))
}
pub fn main() {
let first_name = "Giacomo"
User(first_name, "Cavalieri", ["gleam"])
//^^^^ Triggering the code action here
}
Triggering the code action on the User constructor will result in the
following code:
pub type User {
User(first_name: String, last_name: String, likes: List(String))
}
pub fn main() {
let first_name = "Giacomo"
User(first_name:, last_name: "Cavalieri", likes: ["gleam"])
}
The "inline variable" code action is now only suggested when hovering over the relevant variable. (Giacomo Cavalieri)
When hovering over a record field in a record access expression, the language sever will now show the documentation for that field, if present. (Surya Rose)
Renaming a variable from a label shorthand (name:) no longer includes the
colon in the rename dialog (name: -> name)
(fruno)
The language server now offers a code action to collapse nested case expressions. Take this example:
case user {
User(role: Admin, name:) ->
// Here the only thing we're doing is pattern matching on the
// `name` variable we've just defined in the outer pattern.
case name {
"Joe" -> "Hello, Joe!"
_ -> "Hello, stranger"
}
_ -> "You're not an admin!"
}
We could simplify this case expression and reduce nesting like so:
case user {
User(role: Admin, name: "Joe") -> "Hello, Joe!"
User(role: Admin, name: _) -> "Hello, stranger"
_ -> "You're not an admin!"
}
Now, if you hover over that pattern, the language server will offer the "collapse nested case" action that will simplify your code like shown in the example above.
The "Generate function" code action now allows generating function in other modules. For example, given the following code:
// maths.gleam
pub fn add(a: Int, b: Int) -> Int { a + b }
// main.gleam
import maths
pub fn main() -> Int {
echo maths.add(1, 2)
echo maths.subtract(from: 2, subtract: 1)
// ^ Trigger the "Generate function" code action here
}
The language sever will edit the maths.gleam file:
pub fn add(a: Int, b: Int) -> Int { a + b }
pub fn subtract(from from: Int, subtract subtract: Int) -> Int {
todo
}
The "Add type annotations" and "Generate function" code actions now ignore type variables defined in other functions, improving the generated code. For example:
fn something(a: a, b: b, c: c) -> d { todo }
fn pair(a, b) { #(a, b) }
Previously, when triggering the "Add type annotations" code action on the
pair function, the language server would have generated:
fn pair(a: e, b: f) -> #(e, f) { #(a, b) }
However in 1.13, it will now generate:
fn pair(a: a, b: b) -> #(a, b) { #(a, b) }
You can now go to definition, rename, etc. from alternative patterns!
case wibble {
Wibble | Wobble -> 0
// ^- Previously you could not trigger actions from here
}
(fruno)
When showing types of values on hover, or adding type annotations, the language server will now prefer public type aliases to internal types. For example, if the "Add type annotations" code action was triggered on the following code:
import lustre/html
import lustre/element
import lustre/attribute
pub fn make_link(attribute, element) {
html.a([attribute], [elements])
}
Previously, the following code would have been generated:
pub fn make_link(
attribute: vattr.Attribute,
element: vdom.Element(a)
) -> vdom.Element(a) {
html.a([attribute], [elements])
}
Which references internal types which should not be imported by the user. However, now the language server will produce the following:
pub fn make_link(
attribute: attribute.Attribute,
element: element.Element(a)
) -> element.Element(a) {
html.a([attribute], [elements])
}
The language server now offers the convert to case code action only if a
single let assert expression is selected.
(Giacomo Cavalieri)
The language server now offers an "Extract function" code action to extract a selected piece of code into a separate function. For example:
const head_byte_count = 256
pub fn get_head_of_file() {
let assert Ok(contents) = read_file()
case contents {
//^ Select from here
<<head:bytes-size(head_byte_count), _:bits>> -> Ok(head)
_ -> Error(Nil)
}
//^ Until here
}
Would become:
const head_byte_count = 256
pub fn get_head_of_file() {
let assert Ok(contents) = read_file()
function(contents)
}
fn function(contents: BitArray) -> Result(BitArray, Nil) {
case contents {
<<head:bytes-size(head_byte_count), _:bits>> -> Ok(head)
_ -> Error(Nil)
}
}
You can then use language server renaming to choose an appropriate name for the new function.
The formatter now removes needless multiple negations that are safe to remove. For example, this snippet of code:
pub fn useless_negations() {
let lucky_number = --11
let lucy_is_a_star = !!!False
}
Is rewritten as:
pub fn useless_negations() {
let lucky_number = 11
let lucy_is_a_star = !False
}
Redundant _ as x patterns are rewritten to x.
(eutampieri)
The formatter no longer removes blocks from case clause guards. (Giacomo Cavalieri)
The formatter now properly formats tuple return annotation with comments. (Andrey Kozhev)
Fixed a bug where literals using \u{XXXX} syntax in bit array pattern
segments were not translated to Erlang's \x{XXXX} syntax correctly.
(Benjamin Peinhardt)
Fixed a bug where echo could crash on JavaScript if the module contains
record variants with the same name as some built-in JavaScript objects.
(Louis Pilfold)
Fixed a bug where the compiler would highlight an entire double negation expression as safe to remove, instead of just highlighting the double negation. (Giacomo Cavalieri)
Fixed a bug where the compiler would crash if there was an invalid version
requirement in a project's gleam.toml.
(Giacomo Cavalieri)
Fixed a bug where the compiler would suggest a discouraged project name as an
alternative to the reserved gleam name.
(Giacomo Cavalieri)
Fixed a bug where Forgejo source URLs in the HTML documentation could be incorrectly structured. (Louis Pilfold)
The compiler now emits an error when a module in the src directory imports
a dev dependency, while previously it would incorrectly let these
dependencies to be imported.
(Surya Rose)
Erroneous extra fields in gleam.toml dependency specifications will no
longer be siltently ignored. An error is now returned highlighting the
problem instead.
(Louis Pilfold)
Fixed a bug where renaming a constant which is referenced in another module inside a guard would generate invalid code. (Surya Rose)
Fixed a bug where echo .. as .. message will be omitted in browser target.
(Andrey Kozhev)
Fixed a bug where renaming a variable used in a record update would produce invalid code in certain situations. (Surya Rose)
Fixed a bug where adding echo to the subject of a case expression would
prevent variant inference from working correctly.
(Surya Rose)
Fixed a bug where the compiler would suggest to use a discarded value defined in a different function. (Giacomo Cavalieri)
Fixed a bug where the formatter would format a panic message adding more nesting than necessary. (Giacomo Cavalieri)
Fixed a bug where the language server wouldn't offer the "unqualify" code action if used on a type alias. (Giacomo Cavalieri)
Fixed a bug where the language server would fail to rename an external function with no body. (Giacomo Cavalieri)
Fixed a bug where the compiler allowed to write a guard with an empty clause. (Tristan-Mihai Radulescu)
Fixed a bug where switching from a hex dependency to a git dependency would result in an error from the compiler. (Giacomo Cavalieri)
Fixed a bug where the compiler would reference a redeclared variable in a let assert message, instead of the original variable, on the Erlang target. (Danielle Maywood)
Fixed a bug where the compiler would report an imported module as unused if it were used by private functions only. (Giacomo Cavalieri)
Fixed a bug where the "Extract variable" code action would shadow existing variables, constants and function names. (Matias Carlander)
Fixed a bug where the language server would not fill in the missing labels of a pattern correctly, generating invalid code. (Giacomo Cavalieri)
Fixed a bug where invalid code was being generated when using the "Extract variable" code action inside an anonymous function. (Matias Carlander)
Fixed a bug where running gleam update would not properly update git
dependencies unless gleam clean was run first.
(Surya Rose)
Fixed a bug where the compiler would produce wrong JavaScript code for binary pattern matching expressions using literal strings and byte segments. (Giacomo Cavalieri)
Fixed a bug where the build tool would crash when trying to add transitive dependency. (Andrey Kozhev)