Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,7 @@
- Fixed a bug where renaming would not work properly if there was an error in
target file.
([Surya Rose](https://github.com/GearsDatapacks))

- Fixed a bug where referencing a constant record inside a case branch matching
on that constant would generate invalid code on the Erlang target.
([Igor Castejón](https://github.com/IgorCastejon))
90 changes: 90 additions & 0 deletions compiler-core/src/erlang/tests/case.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,93 @@ pub fn main(x) {
"#,
);
}

#[test]
fn local_variable_as_case_subject_with_type_refinement_allows_field_access_inside_branch() {
assert_erl!(
r#"
pub type User {
User(name: String, age: Int)
Guest
}

pub fn main() {
let user = User("Gleam", 42)

case user {
User(..) -> user.name
Guest -> "Guest"
}
}
"#
);
}

#[test]
fn local_variable_as_case_subject_shadows_const() {
assert_erl!(
r#"
pub type Wibble {
Wibble
Wobble(int: Int)
}

const wibble = Wibble

pub fn main() {
echo wibble
// This 'wibble' shadows the const
let wibble = Wobble(42)
case wibble {
// This matches the local variable, not the const
Wobble(_) -> wibble
}
}
"#
)
}

// https://github.com/gleam-lang/gleam/issues/5261
#[test]
fn case_with_record_const_as_subject_with_record_constructor_clause_and_referencing_same_const_inside_clause_consequence()
{
assert_erl!(
r#"
pub type Wibble {
Wibble
Wobble(int: Int)
}

const wibble = Wibble

pub fn main() {
case wibble {
Wobble(_) -> wibble
wobble -> wibble
}
}
"#
);
}

// https://github.com/gleam-lang/gleam/issues/5261
#[test]
fn const_as_case_subject_with_type_refinement_allows_field_access_inside_branch() {
assert_erl!(
r#"
pub type Wibble {
Wibble
Wobble(int: Int)
}

const wibble = Wobble(42)

pub fn main() {
case wibble {
Wibble -> 24
Wobble(_) -> wibble.int
}
}
"#
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
source: compiler-core/src/erlang/tests/case.rs
expression: "\npub type Wibble {\n Wibble\n Wobble(int: Int)\n}\n\nconst wibble = Wibble\n\npub fn main() {\n case wibble {\n Wobble(_) -> wibble\n wobble -> wibble\n }\n}\n"
---
----- SOURCE CODE

pub type Wibble {
Wibble
Wobble(int: Int)
}

const wibble = Wibble

pub fn main() {
case wibble {
Wobble(_) -> wibble
wobble -> wibble
}
}


----- COMPILED ERLANG
-module(my@mod).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "project/test/my/mod.gleam").
-export([main/0]).
-export_type([wibble/0]).

-type wibble() :: wibble | {wobble, integer()}.

-file("project/test/my/mod.gleam", 9).
-spec main() -> wibble().
main() ->
case wibble of
{wobble, _} ->
wibble;

Wobble ->
wibble
end.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
source: compiler-core/src/erlang/tests/case.rs
expression: "\npub type Wibble {\n Wibble\n Wobble(int: Int)\n}\n\nconst wibble = Wobble(42)\n\npub fn main() {\n case wibble {\n Wibble -> 24\n Wobble(_) -> wibble.int\n }\n}\n"
---
----- SOURCE CODE

pub type Wibble {
Wibble
Wobble(int: Int)
}

const wibble = Wobble(42)

pub fn main() {
case wibble {
Wibble -> 24
Wobble(_) -> wibble.int
}
}


----- COMPILED ERLANG
-module(my@mod).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "project/test/my/mod.gleam").
-export([main/0]).
-export_type([wibble/0]).

-type wibble() :: wibble | {wobble, integer()}.

-file("project/test/my/mod.gleam", 9).
-spec main() -> integer().
main() ->
case {wobble, 42} of
wibble ->
24;

{wobble, _} ->
erlang:element(2, {wobble, 42})
end.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
source: compiler-core/src/erlang/tests/case.rs
expression: "\npub type Wibble {\n Wibble\n Wobble(int: Int)\n}\n\nconst wibble = Wibble\n\npub fn main() {\n echo wibble\n // This 'wibble' shadows the const\n let wibble = Wobble(42)\n case wibble {\n // This matches the local variable, not the const\n Wobble(_) -> wibble\n }\n}\n"
---
----- SOURCE CODE

pub type Wibble {
Wibble
Wobble(int: Int)
}

const wibble = Wibble

pub fn main() {
echo wibble
// This 'wibble' shadows the const
let wibble = Wobble(42)
case wibble {
// This matches the local variable, not the const
Wobble(_) -> wibble
}
}


----- COMPILED ERLANG
-module(my@mod).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "project/test/my/mod.gleam").
-export([main/0]).
-export_type([wibble/0]).

-type wibble() :: wibble | {wobble, integer()}.

-file("project/test/my/mod.gleam", 9).
-spec main() -> wibble().
main() ->
echo(wibble, nil, 10),
Wibble = {wobble, 42},
case Wibble of
{wobble, _} ->
Wibble
end.

% ...omitted code from `templates/echo.erl`...
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
source: compiler-core/src/erlang/tests/case.rs
expression: "\npub type User {\n User(name: String, age: Int)\n Guest\n}\n\npub fn main() {\n let user = User(\"Gleam\", 42)\n \n case user {\n User(..) -> user.name\n Guest -> \"Guest\"\n }\n}\n"
---
----- SOURCE CODE

pub type User {
User(name: String, age: Int)
Guest
}

pub fn main() {
let user = User("Gleam", 42)

case user {
User(..) -> user.name
Guest -> "Guest"
}
}


----- COMPILED ERLANG
-module(my@mod).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "project/test/my/mod.gleam").
-export([main/0]).
-export_type([user/0]).

-type user() :: {user, binary(), integer()} | guest.

-file("project/test/my/mod.gleam", 7).
-spec main() -> binary().
main() ->
User = {user, <<"Gleam"/utf8>>, 42},
case User of
{user, _, _} ->
erlang:element(2, User);

guest ->
<<"Guest"/utf8>>
end.
90 changes: 90 additions & 0 deletions compiler-core/src/javascript/tests/case.rs
Original file line number Diff line number Diff line change
Expand Up @@ -887,3 +887,93 @@ pub fn main() {
"#
)
}

#[test]
fn local_variable_as_case_subject_with_type_refinement_allows_field_access_inside_branch() {
assert_js!(
r#"
pub type User {
User(name: String, age: Int)
Guest
}

pub fn main() {
let user = User("Gleam", 42)

case user {
User(..) -> user.name
Guest -> "Guest"
}
}
"#
);
}

#[test]
fn local_variable_as_case_subject_shadows_const() {
assert_js!(
r#"
pub type Wibble {
Wibble
Wobble(int: Int)
}

const wibble = Wibble

pub fn main() {
echo wibble
// This 'wibble' shadows the const
let wibble = Wobble(42)
case wibble {
// This matches the local variable, not the const
Wobble(_) -> wibble
}
}
"#
)
}

// https://github.com/gleam-lang/gleam/issues/5261
#[test]
fn case_with_record_const_as_subject_with_record_constructor_clause_and_referencing_same_const_inside_clause_consequence()
{
assert_js!(
r#"
pub type Wibble {
Wibble
Wobble(int: Int)
}

const wibble = Wibble

pub fn main() {
case wibble {
Wobble(_) -> wibble
wobble -> wibble
}
}
"#
);
}

// https://github.com/gleam-lang/gleam/issues/5261
#[test]
fn const_as_case_subject_with_type_refinement_allows_field_access_inside_branch() {
assert_js!(
r#"
pub type Wibble {
Wibble
Wobble(int: Int)
}

const wibble = Wobble(42)

pub fn main() {
case wibble {
Wibble -> 24
Wobble(_) -> wibble.int
}
}
"#
)
}
Loading