Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

Fix bit arrays with `unit` and `bytes` options

author
Gears
committer
Louis Pilfold
date (May 6, 2026, 4:45 PM +0100) commit fa6cc0ee parent a73e9974 change-id mrsrylnu
+223 -8
+4
CHANGELOG.md
··· 218 218 build directory was manually deleted. The compiler now automatically rebuilds 219 219 the project when this configuration changes. 220 220 ([daniellionel01](https://github.com/daniellionel01)) 221 + 222 + - Fixed a bug where using the `bytes` and `unit` options together on a bit array 223 + segment could generate incorrect code on the JavaScript target. 224 + ([Surya Rose](https://github.com/GearsDatapacks))
+14 -8
compiler-core/src/ast.rs
··· 3661 3661 }) 3662 3662 } 3663 3663 3664 + /// Returns the unit of `size` in the bit array segment. The `unit` option 3665 + /// overrides the `bytes` option, so if a segment has both, the unit is what 3666 + /// is specified in `unit`, not 8. 3664 3667 pub fn unit(&self) -> u8 { 3665 - self.options 3666 - .iter() 3667 - .find_map(|option| match option { 3668 - BitArrayOption::Unit { value, .. } => Some(*value), 3669 - BitArrayOption::Bytes { .. } => Some(8), 3668 + let mut has_bytes_option = false; 3669 + 3670 + for option in self.options.iter() { 3671 + match option { 3672 + BitArrayOption::Unit { value, .. } => return *value, 3673 + BitArrayOption::Bytes { .. } => has_bytes_option = true, 3670 3674 BitArrayOption::Int { .. } 3671 3675 | BitArrayOption::Float { .. } 3672 3676 | BitArrayOption::Bits { .. } ··· 3681 3685 | BitArrayOption::Big { .. } 3682 3686 | BitArrayOption::Little { .. } 3683 3687 | BitArrayOption::Native { .. } 3684 - | BitArrayOption::Size { .. } => None, 3685 - }) 3686 - .unwrap_or(1) 3688 + | BitArrayOption::Size { .. } => {} 3689 + } 3690 + } 3691 + 3692 + if has_bytes_option { 8 } else { 1 } 3687 3693 } 3688 3694 3689 3695 pub(crate) fn has_bits_option(&self) -> bool {
+25
compiler-core/src/erlang/tests/bit_arrays.rs
··· 526 526 "# 527 527 ) 528 528 } 529 + 530 + // https://github.com/gleam-lang/gleam/issues/5208 531 + #[test] 532 + fn unit_option_ignores_bytes() { 533 + assert_erl!( 534 + " 535 + pub fn main() { 536 + let assert <<x:unit(2)-bytes-size(3)>> = <<1:6>> 537 + x 538 + } 539 + " 540 + ); 541 + } 542 + 543 + #[test] 544 + fn unit_option_ignores_bytes_regardless_of_order() { 545 + assert_erl!( 546 + " 547 + pub fn main() { 548 + let assert <<x:bytes-unit(2)-size(3)>> = <<1:6>> 549 + x 550 + } 551 + " 552 + ); 553 + }
+37
compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unit_option_ignores_bytes.snap
··· 1 + --- 2 + source: compiler-core/src/erlang/tests/bit_arrays.rs 3 + expression: "\npub fn main() {\n let assert <<x:unit(2)-bytes-size(3)>> = <<1:6>>\n x\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub fn main() { 8 + let assert <<x:unit(2)-bytes-size(3)>> = <<1:6>> 9 + x 10 + } 11 + 12 + 13 + ----- COMPILED ERLANG 14 + -module(my@mod). 15 + -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). 16 + -define(FILEPATH, "project/test/my/mod.gleam"). 17 + -export([main/0]). 18 + 19 + -file("project/test/my/mod.gleam", 2). 20 + -spec main() -> bitstring(). 21 + main() -> 22 + X@1 = case <<1:6>> of 23 + <<X:3/binary-unit:2>> -> X; 24 + _assert_fail -> 25 + erlang:error(#{gleam_error => let_assert, 26 + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, 27 + file => <<?FILEPATH/utf8>>, 28 + module => <<"my/mod"/utf8>>, 29 + function => <<"main"/utf8>>, 30 + line => 3, 31 + value => _assert_fail, 32 + start => 19, 33 + 'end' => 67, 34 + pattern_start => 30, 35 + pattern_end => 57}) 36 + end, 37 + X@1.
+37
compiler-core/src/erlang/tests/snapshots/gleam_core__erlang__tests__bit_arrays__unit_option_ignores_bytes_regardless_of_order.snap
··· 1 + --- 2 + source: compiler-core/src/erlang/tests/bit_arrays.rs 3 + expression: "\npub fn main() {\n let assert <<x:bytes-unit(2)-size(3)>> = <<1:6>>\n x\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub fn main() { 8 + let assert <<x:bytes-unit(2)-size(3)>> = <<1:6>> 9 + x 10 + } 11 + 12 + 13 + ----- COMPILED ERLANG 14 + -module(my@mod). 15 + -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). 16 + -define(FILEPATH, "project/test/my/mod.gleam"). 17 + -export([main/0]). 18 + 19 + -file("project/test/my/mod.gleam", 2). 20 + -spec main() -> bitstring(). 21 + main() -> 22 + X@1 = case <<1:6>> of 23 + <<X:3/binary-unit:2>> -> X; 24 + _assert_fail -> 25 + erlang:error(#{gleam_error => let_assert, 26 + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, 27 + file => <<?FILEPATH/utf8>>, 28 + module => <<"my/mod"/utf8>>, 29 + function => <<"main"/utf8>>, 30 + line => 3, 31 + value => _assert_fail, 32 + start => 19, 33 + 'end' => 67, 34 + pattern_start => 30, 35 + pattern_end => 57}) 36 + end, 37 + X@1.
+25
compiler-core/src/javascript/tests/bit_arrays.rs
··· 2819 2819 "# 2820 2820 ); 2821 2821 } 2822 + 2823 + // https://github.com/gleam-lang/gleam/issues/5208 2824 + #[test] 2825 + fn unit_option_ignores_bytes() { 2826 + assert_js!( 2827 + " 2828 + pub fn main() { 2829 + let assert <<x:unit(2)-bytes-size(3)>> = <<1:6>> 2830 + x 2831 + } 2832 + " 2833 + ); 2834 + } 2835 + 2836 + #[test] 2837 + fn unit_option_ignores_bytes_regardless_of_order() { 2838 + assert_js!( 2839 + " 2840 + pub fn main() { 2841 + let assert <<x:bytes-unit(2)-size(3)>> = <<1:6>> 2842 + x 2843 + } 2844 + " 2845 + ); 2846 + }
+35
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__unit_option_ignores_bytes.snap
··· 1 + --- 2 + source: compiler-core/src/javascript/tests/bit_arrays.rs 3 + expression: "\npub fn main() {\n let assert <<x:unit(2)-bytes-size(3)>> = <<1:6>>\n x\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub fn main() { 8 + let assert <<x:unit(2)-bytes-size(3)>> = <<1:6>> 9 + x 10 + } 11 + 12 + 13 + ----- COMPILED JAVASCRIPT 14 + import { makeError, toBitArray, bitArraySlice, sizedInt } from "../gleam.mjs"; 15 + 16 + const FILEPATH = "src/module.gleam"; 17 + 18 + export function main() { 19 + let $ = toBitArray([sizedInt(1, 6, true)]); 20 + let x; 21 + if ($.bitSize === 6) { 22 + x = bitArraySlice($, 0, 6); 23 + } else { 24 + throw makeError( 25 + "let_assert", 26 + FILEPATH, 27 + "my/mod", 28 + 3, 29 + "main", 30 + "Pattern match failed, no pattern matched the value.", 31 + { value: $, start: 19, end: 67, pattern_start: 30, pattern_end: 57 } 32 + ) 33 + } 34 + return x; 35 + }
+35
compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__unit_option_ignores_bytes_regardless_of_order.snap
··· 1 + --- 2 + source: compiler-core/src/javascript/tests/bit_arrays.rs 3 + expression: "\npub fn main() {\n let assert <<x:bytes-unit(2)-size(3)>> = <<1:6>>\n x\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub fn main() { 8 + let assert <<x:bytes-unit(2)-size(3)>> = <<1:6>> 9 + x 10 + } 11 + 12 + 13 + ----- COMPILED JAVASCRIPT 14 + import { makeError, toBitArray, bitArraySlice, sizedInt } from "../gleam.mjs"; 15 + 16 + const FILEPATH = "src/module.gleam"; 17 + 18 + export function main() { 19 + let $ = toBitArray([sizedInt(1, 6, true)]); 20 + let x; 21 + if ($.bitSize === 6) { 22 + x = bitArraySlice($, 0, 6); 23 + } else { 24 + throw makeError( 25 + "let_assert", 26 + FILEPATH, 27 + "my/mod", 28 + 3, 29 + "main", 30 + "Pattern match failed, no pattern matched the value.", 31 + { value: $, start: 19, end: 67, pattern_start: 30, pattern_end: 57 } 32 + ) 33 + } 34 + return x; 35 + }
+11
test/language/test/language/bit_array_match_test.gleam
··· 139 139 let assert <<a, b:size(a), c:size(b)>> = <<2, 3:2, 7:3>> 140 140 assert a + b + c == 12 141 141 } 142 + 143 + // https://github.com/gleam-lang/gleam/issues/5208 144 + pub fn unit_ignores_bytes_option() { 145 + let assert <<x:unit(2)-bytes-size(3)>> = <<1:6>> 146 + assert x == <<1:6>> 147 + } 148 + 149 + pub fn unit_ignores_bytes_option_regardless_of_order() { 150 + let assert <<x:bytes-unit(2)-size(3)>> = <<1:6>> 151 + assert x == <<1:6>> 152 + }