diff --git a/compiler-core/src/codegen.rs b/compiler-core/src/codegen.rs index acdf668fe..d392786c3 100644 --- a/compiler-core/src/codegen.rs +++ b/compiler-core/src/codegen.rs @@ -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(()) } diff --git a/compiler-core/src/nix/expression.rs b/compiler-core/src/nix/expression.rs index bc1dc3757..d697c7172 100644 --- a/compiler-core/src/nix/expression.rs +++ b/compiler-core/src/nix/expression.rs @@ -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![ @@ -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() { @@ -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, .. } => { @@ -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![ diff --git a/compiler-core/src/nix/tests.rs b/compiler-core/src/nix/tests.rs index 9f7103694..4ee07a603 100644 --- a/compiler-core/src/nix/tests.rs +++ b/compiler-core/src/nix/tests.rs @@ -17,6 +17,7 @@ mod blocks; mod bools; mod case; mod case_clause_guards; +mod consts; mod custom_types; mod externals; mod functions; diff --git a/compiler-core/src/nix/tests/bit_arrays.rs b/compiler-core/src/nix/tests/bit_arrays.rs index 4a215c242..5dcf635a7 100644 --- a/compiler-core/src/nix/tests/bit_arrays.rs +++ b/compiler-core/src/nix/tests/bit_arrays.rs @@ -60,7 +60,7 @@ fn sized() { assert_nix!( r#" fn go() { - <<256:4>> + <<256:64>> } "#, ); @@ -71,7 +71,7 @@ fn explicit_sized() { assert_nix!( r#" fn go() { - <<256:size(4)>> + <<256:size(64)>> } "#, ); @@ -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)>> +} +"#, + ); +} diff --git a/compiler-core/src/nix/tests/case.rs b/compiler-core/src/nix/tests/case.rs index dc2417daa..b439bea60 100644 --- a/compiler-core/src/nix/tests/case.rs +++ b/compiler-core/src/nix/tests/case.rs @@ -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 +} +"# + ) +} diff --git a/compiler-core/src/nix/tests/consts.rs b/compiler-core/src/nix/tests/consts.rs new file mode 100644 index 000000000..ccbf9c50c --- /dev/null +++ b/compiler-core/src/nix/tests/consts.rs @@ -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 +"#, + ); +} diff --git a/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__explicit_sized.snap b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__explicit_sized.snap index 787c3180b..127a46d66 100644 --- a/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__explicit_sized.snap +++ b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__explicit_sized.snap @@ -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 { } diff --git a/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__negative_size.snap b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__negative_size.snap new file mode 100644 index 000000000..f18e9608a --- /dev/null +++ b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__negative_size.snap @@ -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 +{ } diff --git a/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__not_byte_aligned.snap b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__not_byte_aligned.snap new file mode 100644 index 000000000..cb6a065ec --- /dev/null +++ b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__not_byte_aligned.snap @@ -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 { } diff --git a/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__not_byte_aligned_explicit_sized.snap b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__not_byte_aligned_explicit_sized.snap new file mode 100644 index 000000000..e32a47bdc --- /dev/null +++ b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__not_byte_aligned_explicit_sized.snap @@ -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 { } diff --git a/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__not_byte_aligned_variable.snap b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__not_byte_aligned_variable.snap new file mode 100644 index 000000000..e55a8fde4 --- /dev/null +++ b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__not_byte_aligned_variable.snap @@ -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 +{ } diff --git a/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__sized.snap b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__sized.snap index 4ed73ade8..e4dcd5528 100644 --- a/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__sized.snap +++ b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__bit_arrays__sized.snap @@ -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 { } diff --git a/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__case__single_clause_variables.snap b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__case__single_clause_variables.snap new file mode 100644 index 000000000..f8c827766 --- /dev/null +++ b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__case__single_clause_variables.snap @@ -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; } diff --git a/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__case__single_clause_variables_assigned.snap b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__case__single_clause_variables_assigned.snap new file mode 100644 index 000000000..42e654d13 --- /dev/null +++ b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__case__single_clause_variables_assigned.snap @@ -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; } diff --git a/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__consts__custom_type_constructor_imported_and_aliased.snap b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__consts__custom_type_constructor_imported_and_aliased.snap new file mode 100644 index 000000000..7f7fb92c0 --- /dev/null +++ b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__consts__custom_type_constructor_imported_and_aliased.snap @@ -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; } diff --git a/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__consts__imported_aliased_ok.snap b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__consts__imported_aliased_ok.snap new file mode 100644 index 000000000..27fc73fe2 --- /dev/null +++ b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__consts__imported_aliased_ok.snap @@ -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; } diff --git a/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__consts__imported_ok.snap b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__consts__imported_ok.snap new file mode 100644 index 000000000..cb68a78e0 --- /dev/null +++ b/compiler-core/src/nix/tests/snapshots/glistix_core__nix__tests__consts__imported_ok.snap @@ -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; }