gleam-lang / gleam

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

Pattern aliases for strings produce bad Erlang #2733

Closed rchog closed 3 months ago

rchog commented 4 months ago

I was delighted to learn that the pattern aliases described here are also supported for strings, however, I ran into this problem when trying to run my code with Erlang as the target. I pared it way down to this minimal example - it's nonsense, but it seems clear where the problem is:

import gleam/io
import gleam/string

fn reproduce_bug(data) {
  case data {
    "" -> ""
    "(" as paren <> rest -> paren <> reproduce_bug(rest)
    s -> s <> reproduce_bug(string.drop_left(s, 1))
  }
}

pub fn main() {
  io.println(reproduce_bug("abcde(fgh)ijkl"))
}

..which produces the following when run with gleam run:

[ bug ]$ gleam run
Downloading packages
 Downloaded 2 packages in 0.00s
  Compiling gleam_stdlib
  Compiling gleeunit
  Compiling bug
/home/r/projects/gleam/bug/build/dev/erlang/bug/_gleam_artefacts/bug.erl:12:20: syntax error before: '='
%   12|         <<"("/utf8 = Paren, Rest/binary>> ->
%     |                    ^

/home/r/projects/gleam/bug/build/dev/erlang/bug/_gleam_artefacts/bug.erl:6:2: spec for undefined function reproduce_bug/1
%    6| -spec reproduce_bug(binary()) -> binary().
%     |  ^

/home/r/projects/gleam/bug/build/dev/erlang/bug/_gleam_artefacts/bug.erl:21:22: function reproduce_bug/1 undefined
%   21|     gleam@io:println(reproduce_bug(<<"abcde(fgh)ijkl"/utf8>>)).
%     |                      ^

error: Shell command failure

There was a problem when running the shell command `escript`.

It runs as expected with gleam run -t js. My Gleam version is 1.0.0, installed from here. I'll add the generated Erlang for good measure:

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

-export([main/0]).

-spec reproduce_bug(binary()) -> binary().
reproduce_bug(Data) ->
    case Data of
        <<""/utf8>> ->
            <<""/utf8>>;

        <<"("/utf8 = Paren, Rest/binary>> ->
            <<Paren/binary, (reproduce_bug(Rest))/binary>>;

        S ->
            <<S/binary, (reproduce_bug(gleam@string:drop_left(S, 1)))/binary>>
    end.

-spec main() -> nil.
main() ->
    gleam@io:println(reproduce_bug(<<"abcde(fgh)ijkl"/utf8>>)).
lpil commented 4 months ago

Thank you

Fri3dNstuff commented 4 months ago

I looked at the bug a little further, and managed to produce an even smaller minimal example:

case "" {
  "" as a <> _ -> Nil
  _ -> Nil
}

error (edited for brevity):

bug.erl:30:19: syntax error before: '='
%   30|         <<""/utf8 = A, _/binary>> ->
%     |                   ^

generated Erlang:

case <<""/utf8>> of
    <<""/utf8 = A, _/binary>> ->
        nil;

    _ ->
        nil
end,

it seems like pattern aliases and string prefixes do not play nicely together. should pattern aliases be available for string prefixes in the first place? their value is a known constant.

wgancar commented 3 months ago

Since this got merged https://github.com/gleam-lang/gleam/pull/2782 I think we can close this issue. WDYT @lpil ?

lpil commented 3 months ago

Thank you!