gleam-lang / gleam

⭐️ A friendly language for building type-safe, scalable systems!
https://gleam.run
Apache License 2.0
17.42k stars 723 forks source link

Fatal compiler bug when compiling BitArray pattern to Erlang #3375

Open DanielleMaywood opened 2 months ago

DanielleMaywood commented 2 months ago

When pattern matching on BitArrays and using the as pattern, it causes a fatal compile error when compiling to Erlang.

pub fn main() {
  let assert <<65 as a, _rest:bytes>> = <<65>>
}

Gleam: 1.3.0 OS: macOS 15.0

When running gleam build, the following error occurs

  Compiling erlang_pattern_repro

warning: Unused variable
  ┌─ /Users/danielle/Repositories/Playground/gleam/erlang_pattern_repro/src/erlang_pattern_repro.gleam:2:22
  │
2 │   let assert <<65 as a, _rest:bytes>> = <<65>>
  │                      ^ This variable is never used

Hint: You can ignore it with an underscore: `_a`.
error: Fatal compiler bug!

This is a bug in the Gleam compiler, sorry!

Please report this crash to https://github.com/gleam-lang/gleam/issues/new
and include this error message with your report.

Panic: compiler-core/src/erlang/pattern.rs:206
        Pattern segment match not recognised
Gleam version: 1.3.0
Operating system: macos

If you can also share your code and say what file you were editing or any
steps to reproduce the crash that would be a great help.

You may also want to try again with the `GLEAM_LOG=trace` environment
variable set.
lpil commented 2 months ago

Thank you. Does this break any of your projects?

DanielleMaywood commented 2 months ago

It does not break any of my projects, no. I discovered this when experimenting.

Acepie commented 2 months ago

FYI looks like this is the same issue as https://github.com/gleam-lang/gleam/issues/3251 as for actually solving this, my erlang isn't great but as far as I understand from reading docs/looking online, erlang doesn't allow assignments in bitarray matches right? So we can't produce something like the below because the assignment is a syntax error. I assume we can't make this a regular compilation error since that gleam code is valid when compiled to javascript? In Javascript we make this work by doing the assignment inside the block so I guess we could try to do the same thing for this case? lmk if this sounds reasonable or if I'm totally off the mark

-module(test_gleam).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).

-export([main/0]).

-spec main() -> bitstring().
main() ->
    _assert_subject = <<65>>,
    <<65 = A, _/binary>> = case _assert_subject of
        <<65, _/binary>> -> _assert_subject;
        _assert_fail ->
            erlang:error(#{gleam_error => let_assert,
                        message => <<"Assertion pattern match failed"/utf8>>,
                        value => _assert_fail,
                        module => <<"test_gleam"/utf8>>,
                        function => <<"main"/utf8>>,
                        line => 2})
    end.
lpil commented 1 month ago

Bit array patterns are so tricky! Lots of weird restrictions I didn't realise.

We could remove the 65 = and push a guard of A =:= 65 perhaps? Seems like it could get a bit complicated.

Shall we close the other issue and track this one here? Seeing as it has more context?