Skip to content

Commit

Permalink
Port Gleam 1.3 JS fixes to Nix (#13)
Browse files Browse the repository at this point in the history
* implement compile-time bit array alignment check

* fix record constructors in constants using non-aliased names

* fix unnecessary gleam.nix writes

* add test for cases with a single clause matching a variable

This generated a bug in JS before, but seems like Nix isn't affected
  • Loading branch information
PgBiel authored Jul 28, 2024
1 parent 7f4b171 commit 31840e2
Show file tree
Hide file tree
Showing 17 changed files with 259 additions and 10 deletions.
8 changes: 7 additions & 1 deletion compiler-core/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,13 @@ impl<'a> Nix<'a> {
"builtins.import {}\n",
nix::syntax::path(self.prelude_location.as_str())
);
writer.write(&self.output_directory.join("gleam.nix"), &rexport)?;
let prelude_path = &self.output_directory.join("gleam.nix");

// This check skips unnecessary `gleam.nix` writes which confuse
// watchers
if !writer.exists(prelude_path) {
writer.write(prelude_path, &rexport)?;
}

Ok(())
}
Expand Down
31 changes: 28 additions & 3 deletions compiler-core/src/nix/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,20 @@ impl Generator<'_> {

// Sized ints
[BitArrayOption::Size { value: size, .. }] => {
let size_int = match *size.clone() {
TypedExpr::Int {
location: _,
typ: _,
value,
} => value.parse().unwrap_or(0),
_ => 0,
};
if size_int > 0 && size_int % 8 != 0 {
return Err(Error::Unsupported {
feature: "Non byte aligned array".into(),
location: segment.location,
});
}
self.tracker.sized_integer_segment_used = true;
let size = self.wrap_child_expression(size)?;
Ok(docvec![
Expand Down Expand Up @@ -1285,10 +1299,11 @@ pub(crate) fn constant_expression<'a>(
Constant::Record { typ, .. } if typ.is_nil() => Ok("null".to_doc()),

Constant::Record {
tag,
typ,
args,
module,
name,
tag,
typ,
..
} => {
if typ.is_result() {
Expand All @@ -1303,7 +1318,7 @@ pub(crate) fn constant_expression<'a>(
.map(|arg| wrap_child_constant_expression(tracker, &arg.value))
.try_collect()?;

Ok(construct_record(module.as_deref(), tag, field_values))
Ok(construct_record(module.as_deref(), name, field_values))
}

Constant::BitArray { segments, .. } => {
Expand Down Expand Up @@ -1579,6 +1594,16 @@ fn constant_bit_array<'a>(

// Sized ints
[BitArrayOption::Size { value: size, .. }] => {
let size_int = match *size.clone() {
Constant::Int { location: _, value } => value.parse().unwrap_or(0),
_ => 0,
};
if size_int > 0 && size_int % 8 != 0 {
return Err(Error::Unsupported {
feature: "Non byte aligned array".into(),
location: segment.location,
});
}
tracker.sized_integer_segment_used = true;
let size = wrap_child_constant_expr_fun(tracker, size)?;
Ok(docvec![
Expand Down
1 change: 1 addition & 0 deletions compiler-core/src/nix/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod blocks;
mod bools;
mod case;
mod case_clause_guards;
mod consts;
mod custom_types;
mod externals;
mod functions;
Expand Down
56 changes: 54 additions & 2 deletions compiler-core/src/nix/tests/bit_arrays.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ fn sized() {
assert_nix!(
r#"
fn go() {
<<256:4>>
<<256:64>>
}
"#,
);
Expand All @@ -71,7 +71,7 @@ fn explicit_sized() {
assert_nix!(
r#"
fn go() {
<<256:size(4)>>
<<256:size(64)>>
}
"#,
);
Expand Down Expand Up @@ -245,3 +245,55 @@ fn as_module_const() {
"#
)
}

#[test]
fn negative_size() {
assert_nix!(
r#"
fn go() {
<<1:size(-1)>>
}
"#,
);
}

// https://github.com/gleam-lang/gleam/issues/1591
#[test]
fn not_byte_aligned() {
assert_nix!(
r#"
fn thing() {
4
}
fn go() {
<<256:4>>
}
"#,
);
}

#[test]
fn not_byte_aligned_explicit_sized() {
assert_nix!(
r#"
fn go() {
<<256:size(4)>>
}
"#,
);
}

// This test would ideally also result in go() being deleted like the previous tests
// but we can not know for sure what the value of a variable is going to be
// so right now go() is not deleted.
#[test]
fn not_byte_aligned_variable() {
assert_nix!(
r#"
fn go() {
let x = 4
<<256:size(x)>>
}
"#,
);
}
34 changes: 34 additions & 0 deletions compiler-core/src/nix/tests/case.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,37 @@ pub fn main() {
"#
)
}

// https://github.com/gleam-lang/gleam/issues/3379
#[test]
fn single_clause_variables() {
assert_nix!(
r#"
pub fn main() {
let text = "first defined"
case "defined again" {
text -> Nil
}
let text = "a third time"
Nil
}
"#
)
}

// https://github.com/gleam-lang/gleam/issues/3379
#[test]
fn single_clause_variables_assigned() {
assert_nix!(
r#"
pub fn main() {
let text = "first defined"
let other = case "defined again" {
text -> Nil
}
let text = "a third time"
Nil
}
"#
)
}
35 changes: 35 additions & 0 deletions compiler-core/src/nix/tests/consts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use crate::assert_nix;

#[test]
fn custom_type_constructor_imported_and_aliased() {
assert_nix!(
("package", "other_module", "pub type T { A }"),
r#"import other_module.{A as B}
pub const local = B
"#,
);
}

#[test]
fn imported_aliased_ok() {
assert_nix!(
r#"import gleam.{Ok as Y}
pub type X {
Ok
}
pub const y = Y
"#,
);
}

#[test]
fn imported_ok() {
assert_nix!(
r#"import gleam
pub type X {
Ok
}
pub const y = gleam.Ok
"#,
);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
source: compiler-core/src/nix/tests/bit_arrays.rs
expression: "\nfn go() {\n <<256:size(4)>>\n}\n"
expression: "\nfn go() {\n <<256:size(64)>>\n}\n"
---
let
inherit (builtins.import ./../gleam.nix) toBitArray sizedInt;

go = { }: toBitArray [ (sizedInt 256 4) ];
go = { }: toBitArray [ (sizedInt 256 64) ];
in
{ }
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
source: compiler-core/src/nix/tests/bit_arrays.rs
expression: "\nfn go() {\n <<1:size(-1)>>\n}\n"
---
let
inherit (builtins.import ./../gleam.nix) toBitArray sizedInt;

go = { }: toBitArray [ (sizedInt 1 (-1)) ];
in
{ }
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
source: compiler-core/src/nix/tests/bit_arrays.rs
expression: "\nfn thing() {\n 4\n}\nfn go() {\n <<256:4>>\n}\n"
---
let inherit (builtins.import ./../gleam.nix) toBitArray; thing = { }: 4; in { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
source: compiler-core/src/nix/tests/bit_arrays.rs
expression: "\nfn go() {\n <<256:size(4)>>\n}\n"
---
let inherit (builtins.import ./../gleam.nix) toBitArray; in { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
source: compiler-core/src/nix/tests/bit_arrays.rs
expression: "\nfn go() {\n let x = 4\n <<256:size(x)>>\n}\n"
---
let
inherit (builtins.import ./../gleam.nix) toBitArray sizedInt;

go = { }: let x = 4; in toBitArray [ (sizedInt 256 x) ];
in
{ }
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
source: compiler-core/src/nix/tests/bit_arrays.rs
expression: "\nfn go() {\n <<256:4>>\n}\n"
expression: "\nfn go() {\n <<256:64>>\n}\n"
---
let
inherit (builtins.import ./../gleam.nix) toBitArray sizedInt;

go = { }: toBitArray [ (sizedInt 256 4) ];
go = { }: toBitArray [ (sizedInt 256 64) ];
in
{ }
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
source: compiler-core/src/nix/tests/case.rs
expression: "\npub fn main() {\n let text = \"first defined\"\n case \"defined again\" {\n text -> Nil\n }\n let text = \"a third time\"\n Nil\n}\n"
---
let
main =
{ }:
let
text = "first defined";
_' = let _pat' = "defined again"; in let text'1 = _pat'; in null;
text'1 = "a third time";
in
builtins.seq _' null;
in
{ inherit main; }
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
source: compiler-core/src/nix/tests/case.rs
expression: "\npub fn main() {\n let text = \"first defined\"\n let other = case \"defined again\" {\n text -> Nil\n }\n let text = \"a third time\"\n Nil\n}\n"
---
let
main =
{ }:
let
text = "first defined";
other = let _pat' = "defined again"; in let text'1 = _pat'; in null;
text'1 = "a third time";
in
null;
in
{ inherit main; }
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
source: compiler-core/src/nix/tests/consts.rs
expression: "import other_module.{A as B}\npub const local = B\n"
---
let
other_module' = builtins.import ./../../package/other_module.nix;
B = (builtins.import ./../../package/other_module.nix).A;

local = B;
in
{ inherit local; }
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
source: compiler-core/src/nix/tests/consts.rs
expression: "import gleam.{Ok as Y}\npub type X {\n Ok\n}\npub const y = Y\n"
---
let
gleam' = builtins.import ./../gleam.nix;
Y = (builtins.import ./../gleam.nix).Ok;

Ok = { __gleamTag = "Ok"; };

y = Y;
in
{ inherit Ok y; }
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
source: compiler-core/src/nix/tests/consts.rs
expression: "import gleam\npub type X {\n Ok\n}\npub const y = gleam.Ok\n"
---
let
gleam' = builtins.import ./../gleam.nix;

Ok = { __gleamTag = "Ok"; };

y = gleam'.Ok;
in
{ inherit Ok y; }

0 comments on commit 31840e2

Please sign in to comment.