Fork of daniellemaywood.uk/gleam — Wasm codegen work
22 kB
762 lines
1# Changelog
2
3## Unreleased
4
5### Compiler
6
7- The compiler now applies an optimisation known as "interference based pruning"
8 when compiling bit array pattern matching where matches are performed at the
9 start of bit arrays.
10 This optimisation drastically reduces compile times, memory usage and the
11 compiled code size, removing many redundant checks.
12 It is particularly important for network protocol applications where it is
13 typical to match on some fixed patterns at the start of the bitarray.
14 For example:
15
16 ```gleam
17 pub fn parser_headers(headers: BitArray, bytes: Int) -> Headers {
18 case headers {
19 <<"CONTENT_LENGTH" as header, 0, value:size(bytes), 0, rest:bytes>>
20 | <<"QUERY_STRING" as header, 0, value:size(bytes), 0, rest:bytes>>
21 | <<"REQUEST_URI" as header, 0, value:size(bytes), 0, rest:bytes>>
22 // ...
23 | <<"REDIRECT_STATUS" as header, 0, value:size(bytes), 0, rest:bytes>>
24 | <<"SCRIPT_NAME" as header, 0, value:size(bytes), 0, rest:bytes>>
25 -> [#(header, value), ..parse_headers(rest)]
26 }
27 }
28 ```
29
30 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
31
32- The compiler now raises a warning for unreachable branches that are matching
33 on bit array segments that could never match. Consider this example:
34
35 ```gleam
36 pub fn get_payload(packet: BitArray) -> Result(BitArray, Nil) {
37 case packet {
38 <<200, payload:bytes>> -> Ok(payload)
39 <<404, _:bits>> -> Error(Nil)
40 _ -> Ok(packet)
41 }
42 }
43 ```
44
45 There's a subtle bug here. The second branch can never match since it's
46 impossible for the first byte of the bit array to have the value `404`.
47 The new error explains this nicely:
48
49 ```text
50 warning: Unreachable pattern
51 ┌─ /src.gleam:4:5
52 │
53 4 │ <<404, _:bits>> -> Error(Nil)
54 │ ^^^^^^^^^^^^^^^
55 │ │
56 │ A 1 byte unsigned integer will never match this value
57
58 This pattern cannot be reached as it contains segments that will never
59 match.
60
61 Hint: It can be safely removed.
62 ```
63
64 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
65
66- The compiler now emits a better error message for private types marked as
67 opaque. For example, the following piece of code:
68
69 ```gleam
70 opaque type Wibble {
71 Wobble
72 }
73 ```
74
75 Would result in the following error:
76
77 ```
78 error: Private opaque type
79 ┌─ /src/one/two.gleam:2:1
80 │
81 2 │ opaque type Wibble {
82 │ ^^^^^^ You can safely remove this.
83
84 Only a public type can be opaque.
85 ```
86
87 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
88
89- The parsing of opaque private types is now fault tolerant: having a private
90 opaque type in a module no longer stops the compiler from highlighting other
91 errors.
92 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
93
94- The compiler now emits a single warning for multiple negations in a row, while
95 previously it would emit multiple comments highlighting increasingly longer
96 spans.
97 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
98
99- Redundant `_ as x` patterns are now deprecated in favour of `x`.
100 ([eutampieri](https://github.com/eutampieri))
101
102- The compiler will now raise warning for inefficient use of `list.length()`
103 when trying to check is list empty via `0 < list.length(list)` or
104 `list.length(list) > 0` as well as in other cases. For example, the following
105 code:
106
107 ```gleam
108 import gleam/list
109
110 pub fn main() {
111 let numbers = [1, 46]
112 let _ = 0 < list.length(numbers)
113 let _ = list.length(numbers) > 0
114 }
115 ```
116
117 Would result in following warnings:
118
119 ```
120 warning: Inefficient use of `list.length`
121 ┌─ /data/data/com.termux/files/home/test_gleam/src/test_gleam.gleam:5:13
122 │
123 5 │ let _ = 0 < list.length(numbers)
124 │ ^^^^^^^^^^^^^^^^^^^^^^^^
125
126 The `list.length` function has to iterate across the whole
127 list to calculate the length, which is wasteful if you only
128 need to know if the list is empty or not.
129
130 Hint: You can use `the_list != []` instead.
131
132 warning: Inefficient use of `list.length`
133 ┌─ /data/data/com.termux/files/home/test_gleam/src/test_gleam.gleam:6:13
134 │
135 6 │ let _ = list.length(numbers) > 0
136 │ ^^^^^^^^^^^^^^^^^^^^^^^^
137
138 The `list.length` function has to iterate across the whole
139 list to calculate the length, which is wasteful if you only
140 need to know if the list is empty or not.
141
142 Hint: You can use `the_list != []` instead.
143 ```
144
145 ([Andrey Kozhev](https://github.com/ankddev))
146
147- The compiler now provides an improved error message for when trying to define
148 a constant inside a function. For example, the following code:
149
150 ```gleam
151 pub fn deep_thought() {
152 const the_answer = 42
153 the_answer
154 }
155 ```
156
157 Will produce this error message:
158
159 ```txt
160 error: Syntax error
161 ┌─ /src/file.gleam:2:3
162 │
163 3 │ const the_answer = 43
164 │ ^^^^^ Constants are not allowed inside functions
165
166 All variables are immutable in Gleam, so constants inside functions are not
167 necessary.
168 Hint: Either move this into the global scope or use `let` binding instead.
169 ```
170
171 ([Surya Rose](https://github.com/GearsDatapacks))
172
173- The code generated for blocks on the JavaScript target has been improved and
174 is now smaller in certain cases.
175 ([Surya Rose](https://github.com/GearsDatapacks))
176
177- Writing a type name followed by `()` now emits an error during analysis
178 rather than parsing, so it no longer stops the compiler from reporting errors
179 further in the code.
180 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
181
182- The compiler now shows a specific syntax error when trying to use an
183 angle-bracket syntax for generic types or function definitions:
184
185 ```txt
186 error: Syntax error
187 ┌─ /src/parse/error.gleam:2:12
188 │
189 2 │ type Either<a, b> {
190 │ ^ I was expecting `(` here.
191
192 Type parameters use lowercase names and are surrounded by parentheses.
193
194 type Either(a, b) {
195
196 See: https://tour.gleam.run/data-types/generic-custom-types/
197 ```
198
199 ([Aaron Christiansen](https://github.com/AaronC81))
200
201- Fault tolerance for analysis of labeled fields in constructor patterns has
202 been improved.
203 ([sobolevn](https://github.com/sobolevn))
204
205- Compiler now adds a hint when `#`-styled comments are used. This code:
206
207 ```gleam
208 fn some() {
209 let a = 1
210 # let b = 2
211 }
212 ```
213
214 Now produces:
215
216 ```txt
217 error: Syntax error
218 ┌─ /src/main.gleam:3:5
219 │
220 3 │ # let b = 2
221 │ ^^^ I was not expecting this
222
223 Found the keyword `let`, expected one of:
224 - `(`
225 Hint: Maybe you meant to create a comment?
226 Comments in Gleam start with `//`, not `#`
227 ```
228
229 ([sobolevn](https://github.com/sobolevn))
230
231- The `erlang.application_start_argument` parameter has been added to
232 `gleam.toml`. This is a string containing an Erlang term that will be written
233 into the package's Erlang `.app` file if `erlang.application_start_module`
234 has been set, replacing the default argument of `[]`.
235 ([Louis Pilfold](https://github.com/lpil))
236
237- Generated code for the JavaScript target now includes a public API which can
238 be used for FFI interacting with Gleam custom types. For example, if you have
239 this Gleam code:
240
241 ```gleam
242 pub type Person {
243 Teacher(name: String, subject: String)
244 Student(name: String, age: Int)
245 }
246 ```
247
248 You can use the new API to use the `Person` type in FFI code:
249
250 ```javascript
251 import * from "./person.mjs";
252
253 // Constructing custom types
254 let teacher = Person$Teacher("Joe Armstrong", "Computer Science");
255 let student = Person$Student("Louis Pilfold", 17);
256
257 let randomPerson = Math.random() > 0.5 ? teacher : student;
258
259 // Checking variants
260 let randomIsTeacher = Person$isTeacher(randomPerson);
261
262 // Getting fields
263 let studentAge = Person$Student$age(student);
264
265 // The `name` field is shared so can be accessed from either variant
266 let personNAme = Person$name(randomPerson);
267 ```
268
269 ([Surya Rose](https://github.com/GearsDatapacks))
270
271### Build tool
272
273- New projects are generated using OTP28 on GitHub Actions.
274 ([Louis Pilfold](https://github.com/lpil))
275
276- The build tool now has a new `hex owner transfer` subcommand to transfer
277 ownership of existing packages.
278 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
279
280- `gleam add` now adds `dependencies` and `dev-dependencies` as tables instead
281 of inline tables if they are missing.
282 ([Andrey Kozhev](https://github.com/ankddev))
283
284- After dependency resolution the build tool will now print all packages added
285 and removed, and any versions changed.
286 ([Louis Pilfold](https://github.com/lpil))
287
288- `gleam publish` now blocks publishing packages that contain the default main
289 function to prevent accidental publishing of unmodified template code.
290 ([Joohoon Cha](https://github.com/jcha0713))
291
292- When generating documentation, the build tool will now print the names of
293 public type aliases instead of internal type names when annotating functions
294 and types. For example, for the following code:
295
296 ```gleam
297 import my_package/internal
298
299 pub type ExternalAlias = internal.InternalRepresentation
300
301 pub fn do_thing() -> ExternalAlias { ... }
302 ```
303
304 This is what the build tool used to generate:
305
306 ```gleam
307 pub fn do_thing() -> @internal InternalRepresentation
308 ```
309
310 Whereas now it will not use the internal name, and instead produce:
311
312 ```gleam
313 pub fn do_thing() -> ExternalAlias
314 ```
315
316 ([Surya Rose](https://github.com/GearsDatapacks))
317
318- Support has been added for using Tangled as a repository.
319 ([Naomi Roberts](https://github.com/naomieow))
320
321### Language server
322
323- The language server now offers a code action to remove all the unreachable
324 branches in a case expression. For example:
325
326 ```gleam
327 pub fn main() {
328 case find_user() {
329 Ok(user) -> todo
330 Ok(Admin) -> todo
331 // ^^^^^^^^^ This branch is unreachable
332 Ok(User) -> todo
333 // ^^^^^^^^ This branch is unreachable
334 Error(_) -> todo
335 }
336 }
337 ```
338
339 Hovering over one of the unreachable branches and triggering the code action
340 would remove all the unreachable branches:
341
342 ```gleam
343 pub fn main() {
344 case find_user() {
345 Ok(user) -> todo
346
347 Error(_) -> todo
348 }
349 }
350 ```
351
352 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
353
354- The "pattern match on variable" can now be triggered on lists. For example:
355
356 ```gleam
357 pub fn is_empty(list: List(a)) -> Bool {
358 // ^^^^ Triggering the action over here
359 }
360 ```
361
362 Triggering the action over the `list` argument would result in the following
363 code:
364
365 ```gleam
366 pub fn is_empty(list: List(a)) -> Bool {
367 case list {
368 [] -> todo
369 [first, ..rest] -> todo
370 }
371 }
372 ```
373
374 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
375
376- The "pattern match on variable" code action can now be triggered on variables
377 introduced by other patterns. For example:
378
379 ```gleam
380 pub fn main() {
381 let User(name:, role:) = find_user("lucy")
382 // ^^^^ Triggering the action over
383 }
384 ```
385
386 Triggering the action over another variable like `role` would result in the
387 following code:
388
389 ```gleam
390 pub fn main() {
391 let User(name:, role:) = find_user("lucy")
392 case role {
393 Admin -> todo
394 Member -> todo
395 }
396 }
397 ```
398
399 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
400
401- The "pattern match on variable" code action can now be triggered on variables
402 in case expressions. For example:
403
404 ```gleam
405 pub fn main() {
406 case find_user() {
407 Ok(user) -> todo
408 Error(_) -> todo
409 }
410 }
411 ```
412
413 Triggering the action over the `user` variable would result in the following
414 code:
415
416 ```gleam
417 pub fn main() {
418 case find_user() {
419 Ok(Admin) -> todo
420 Ok(Member) -> todo
421 Error(_) -> todo
422 }
423 }
424 ```
425
426 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
427
428- The language server now offers a quick fix to remove `opaque` from a private
429 type:
430
431 ```gleam
432 opaque type Wibble {
433 // ^^^ This is an error!
434 Wobble
435 }
436 ```
437
438 If you hover over the type and trigger the quick fix, the language server will
439 automatically remove the `opaque` keyword:
440
441 ```gleam
442 type Wibble {
443 Wobble
444 }
445 ```
446
447 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
448
449- The language server now offers a code action to add the omitted labels in a
450 call. For example:
451
452 ```gleam
453 pub type User {
454 User(first_name: String, last_name: String, likes: List(String))
455 }
456
457 pub fn main() {
458 let first_name = "Giacomo"
459 User(first_name, "Cavalieri", ["gleam"])
460 //^^^^ Triggering the code action over here
461 }
462 ```
463
464 Triggering the code action over the `User` constructor will result in the
465 following code:
466
467 ```gleam
468 pub type User {
469 User(first_name: String, last_name: String, likes: List(String))
470 }
471
472 pub fn main() {
473 let first_name = "Giacomo"
474 User(first_name:, last_name: "Cavalieri", likes: ["gleam"])
475 }
476 ```
477
478- The "inline variable" code action is now only suggested when hovering over the
479 relevant variable.
480 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
481
482- When hovering over a record field in a record access expression, the language
483 sever will now show the documentation for that field, if present.
484 ([Surya Rose](https://github.com/GearsDatapacks))
485
486- Renaming a variable from a label shorthand (`name:`) no longer includes the
487 colon in the rename dialog (`name:` -> `name`)
488 ([fruno](https://github.com/frunobulax-the-poodle))
489
490- The language server now offers a code action to collapse nested case
491 expressions. Take this example:
492
493 ```gleam
494 case user {
495 User(role: Admin, name:) ->
496 // Here the only thing we're doing is pattern matching on the
497 // `name` variable we've just defined in the outer pattern.
498 case name {
499 "Joe" -> "Hello, Joe!"
500 _ -> "Hello, stranger"
501 }
502
503 _ -> "You're not an admin!"
504 }
505 ```
506
507 We could simplify this case expression and reduce nesting like so:
508
509 ```gleam
510 case user {
511 User(role: Admin, name: "Joe") -> "Hello, Joe!"
512 User(role: Admin, name: _) -> "Hello, stranger"
513 _ -> "You're not an admin!"
514 }
515 ```
516
517 Now, if you hover over that pattern, the language server will offer the
518 "collapse nested case" action that will simplify your code like shown in the
519 example above.
520
521 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
522
523- The "Generate function" code action now allows generating function in other
524 modules. For example, given the following code:
525
526 ```gleam
527 // maths.gleam
528 pub fn add(a: Int, b: Int) -> Int { a + b }
529
530 // main.gleam
531 import maths
532
533 pub fn main() -> Int {
534 echo maths.add(1, 2)
535 echo maths.subtract(from: 2, subtract: 1)
536 // ^ Trigger the "Generate function" code action here
537 }
538 ```
539
540 The language sever will edit the `maths.gleam` file:
541
542 ```gleam
543 pub fn add(a: Int, b: Int) -> Int { a + b }
544
545 pub fn subtract(from from: Int, subtract subtract: Int) -> Int {
546 todo
547 }
548 ```
549
550 ([Surya Rose](https://github.com/GearsDatapacks))
551
552- The "Add type annotations" and "Generate function" code actions now ignore
553 type variables defined in other functions, improving the generated code.
554 For example:
555
556 ```gleam
557 fn something(a: a, b: b, c: c) -> d { todo }
558
559 fn pair(a, b) { #(a, b) }
560 ```
561
562 Previously, when triggering the "Add type annotations" code action on the
563 `pair` function, the language server would have generated:
564
565 ```gleam
566 fn pair(a: e, b: f) -> #(e, f) { #(a, b) }
567 ```
568
569 However in 1.13, it will now generate:
570
571 ```gleam
572 fn pair(a: a, b: b) -> #(a, b) { #(a, b) }
573 ```
574
575 ([Surya Rose](https://github.com/GearsDatapacks))
576
577- You can now go to definition, rename, etc. from alternative patterns!
578
579 ```gleam
580 case wibble {
581 Wibble | Wobble -> 0
582 // ^- Previously you could not trigger actions from here
583 }
584
585 ```
586
587 ([fruno](https://github.com/fruno-bulax))
588
589- When showing types of values on hover, or adding type annotations, the language
590 server will now prefer public type aliases to internal types. For example, if
591 the "Add type annotations" code action was triggered on the following code:
592
593 ```gleam
594 import lustre/html
595 import lustre/element
596 import lustre/attribute
597
598 pub fn make_link(attribute, element) {
599 html.a([attribute], [elements])
600 }
601 ```
602
603 Previously, the following code would have been generated:
604
605 ```gleam
606 pub fn make_link(
607 attribute: vattr.Attribute,
608 element: vdom.Element(a)
609 ) -> vdom.Element(a) {
610 html.a([attribute], [elements])
611 }
612 ```
613
614 Which references internal types which should not be imported by the user.
615 However, now the language server will produce the following:
616
617 ```gleam
618 pub fn make_link(
619 attribute: attribute.Attribute,
620 element: element.Element(a)
621 ) -> element.Element(a) {
622 html.a([attribute], [elements])
623 }
624 ```
625
626 ([Surya Rose](https://github.com/GearsDatapacks))
627
628- The language server now offers the `convert to case` code action only if a
629 single `let assert` expression is selected.
630 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
631
632### Formatter
633
634- The formatter now removes needless multiple negations that are safe to remove.
635 For example, this snippet of code:
636
637 ```gleam
638 pub fn useless_negations() {
639 let lucky_number = --11
640 let lucy_is_a_star = !!!False
641 }
642 ```
643
644 Is rewritten as:
645
646 ```gleam
647 pub fn useless_negations() {
648 let lucky_number = 11
649 let lucy_is_a_star = !False
650 }
651 ```
652
653 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
654
655- Redundant `_ as x` patterns are rewritten to `x`.
656 ([eutampieri](https://github.com/eutampieri))
657
658- The formatter no longer removes blocks from case clause guards.
659 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
660
661### Bug fixes
662
663- Fixed a bug where literals using `\u{XXXX}` syntax in bit array pattern
664 segments were not translated to Erlang's `\x{XXXX}` syntax correctly.
665 ([Benjamin Peinhardt](https://github.com/bcpeinhardt))
666
667- Fixed a bug where `echo` could crash on JavaScript if the module contains
668 record variants with the same name as some built-in JavaScript objects.
669 ([Louis Pilfold](https://github.com/lpil))
670
671- Fixed a bug where the compiler would highlight an entire double negation
672 expression as safe to remove, instead of just highlighting the double
673 negation.
674 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
675
676- Fixed a bug where the compiler would crash if there was an invalid version
677 requirement in a project's `gleam.toml`.
678 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
679
680- Fixed a bug where the compiler would suggest a discouraged project name as an
681 alternative to the reserved `gleam` name.
682 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
683
684- Fixed a bug where Forgejo source URLs in the HTML documentation could be
685 incorrectly structured.
686 ([Louis Pilfold](https://github.com/lpil))
687
688- The compiler now emits an error when a module in the `src` directory imports
689 a dev dependency, while previously it would incorrectly let these
690 dependencies to be imported.
691 ([Surya Rose](https://github.com/GearsDatapacks))
692
693- Erroneous extra fields in `gleam.toml` dependency specifications will no
694 longer be siltently ignored. An error is now returned highlighting the
695 problem instead.
696 ([Louis Pilfold](https://github.com/lpil))
697
698- Fixed a bug where renaming a constant which is referenced in another module
699 inside a guard would generate invalid code.
700 ([Surya Rose](https://github.com/GearsDatapacks))
701
702- Fixed a bug where `echo .. as ..` message will be omitted in browser target.
703 ([Andrey Kozhev](https://github.com/ankddev))
704
705- Fixed a bug where renaming a variable used in a record update would produce
706 invalid code in certain situations.
707 ([Surya Rose](https://github.com/GearsDatapacks))
708
709- Fixed a bug where adding `echo` to the subject of a `case` expression would
710 prevent variant inference from working correctly.
711 ([Surya Rose](https://github.com/GearsDatapacks))
712
713- Fixed a bug where the compiler would suggest to use a discarded value defined
714 in a different function.
715 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
716
717- Fixed a bug where the formatter would format a panic message adding more
718 nesting than necessary.
719 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
720
721- Fixed a bug where the language server wouldn't offer the "unqualify" code
722 action if used on a type alias.
723 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
724
725- Fixed a bug where the language server would fail to rename an external
726 function with no body.
727 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
728
729- Fixed a bug where the compiler allowed to write a guard with an empty clause.
730 ([Tristan-Mihai Radulescu](https://github.com/Courtcircuits))
731
732- Fixed a bug where switching from a hex dependency to a git dependency would
733 result in an error from the compiler.
734 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
735
736- Fixed a bug where the compiler would reference a redeclared variable in a let
737 assert message, instead of the original variable, on the Erlang target.
738 ([Danielle Maywood](https://github.com/DanielleMaywood))
739
740- Fixed a bug where the compiler would report an imported module as unused if it
741 were used by private functions only.
742 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
743
744- Fixed a bug where the "Extract variable" code action would shadow existing
745 variables, constants and function names.
746 ([Matias Carlander](https://github.com/matiascr))
747
748- Fixed a bug where the language server would not fill in the missing labels of
749 a pattern correctly, generating invalid code.
750 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
751
752- Fixed a bug where invalid code was being generated when using the "Extract
753 variable" code action inside an anonymous function.
754 ([Matias Carlander](https://github.com/matiascr))
755
756- Fixed a bug where running `gleam update` would not properly update git
757 dependencies unless `gleam clean` was run first.
758 ([Surya Rose](https://github.com/GearsDatapacks))
759
760- Fixed a bug where the compiler would produce wrong JavaScript code for binary
761 pattern matching expressions using literal strings and byte segments.
762 ([Giacomo Cavalieri](https://github.com/giacomocavalieri))