From e2891257baeb4d7a30c4988fc335759c9e52c631 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Fri, 11 Nov 2022 12:24:19 -0500 Subject: [PATCH 01/32] Don't use a style attribute for the builtins tip This doesn't work because of our content-security policy! --- crates/docs/src/static/styles.css | 6 ++++++ www/build.sh | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/docs/src/static/styles.css b/crates/docs/src/static/styles.css index dc1f934e93..3c73586699 100644 --- a/crates/docs/src/static/styles.css +++ b/crates/docs/src/static/styles.css @@ -468,6 +468,12 @@ pre { line-height: 15px; } +.builtins-tip { + padding: 1em; + font-style: italic; + line-height: 1.3em; +} + @media (prefers-color-scheme: dark) { :root { --body-bg-color: var(--purple-8); diff --git a/www/build.sh b/www/build.sh index f8cd18e5d8..2a54114a88 100755 --- a/www/build.sh +++ b/www/build.sh @@ -40,7 +40,7 @@ mv generated-docs/*.* www/build # move all the .js, .css, etc. files to build/ mv generated-docs/ www/build/builtins # move all the folders to build/builtins/ # Manually add this tip to all the builtin docs. -find www/build/builtins -type f -name 'index.html' -exec sed -i 's!!
Tip: Some names differ from other languages.
!' {} \; +find www/build/builtins -type f -name 'index.html' -exec sed -i 's!!
Tip: Some names differ from other languages.
!' {} \; echo 'Generating CLI example platform docs...' # Change ROC_DOCS_ROOT_DIR=builtins so that links will be generated relative to From 1478cfc3ad22f50cfa319e5bd980f78e4bae4c19 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Fri, 11 Nov 2022 12:24:43 -0500 Subject: [PATCH 02/32] Don't use style attributes for web repl colors This doesn't work because of our content-security policy! --- crates/reporting/src/report.rs | 6 +++--- www/public/repl/repl.css | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/crates/reporting/src/report.rs b/crates/reporting/src/report.rs index c3acf99fad..b85a631367 100644 --- a/crates/reporting/src/report.rs +++ b/crates/reporting/src/report.rs @@ -273,7 +273,7 @@ pub const ANSI_STYLE_CODES: StyleCodes = StyleCodes { macro_rules! html_color { ($name: expr) => { - concat!("") + concat!("") }; } @@ -285,8 +285,8 @@ pub const HTML_STYLE_CODES: StyleCodes = StyleCodes { magenta: html_color!("magenta"), cyan: html_color!("cyan"), white: html_color!("white"), - bold: "", - underline: "", + bold: "", + underline: "", reset: "", color_reset: "", }; diff --git a/www/public/repl/repl.css b/www/public/repl/repl.css index bbf6d1a6f6..cee0b97bf9 100644 --- a/www/public/repl/repl.css +++ b/www/public/repl/repl.css @@ -75,3 +75,31 @@ section.source textarea { padding: 8px; margin-bottom: 16px; } + +.color-red { + color: red; +} +.color-green { + color: green; +} +.color-yellow { + color: yellow; +} +.color-blue { + color: blue; +} +.color-magenta { + color: magenta; +} +.color-cyan { + color: cyan; +} +.color-white { + color: white; +} +.bold { + font-weight: bold; +} +.underline { + text-decoration: underline; +} \ No newline at end of file From b6df9fe0dc8110727f82e8baa5b18c49c1c10661 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 12 Nov 2022 14:11:00 +0100 Subject: [PATCH 03/32] display the command nicely --- crates/compiler/build/src/link.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/compiler/build/src/link.rs b/crates/compiler/build/src/link.rs index ca83ce3a15..ca9ddeb9d3 100644 --- a/crates/compiler/build/src/link.rs +++ b/crates/compiler/build/src/link.rs @@ -1370,7 +1370,15 @@ pub fn preprocess_host_wasm32(host_input_path: &Path, preprocessed_host_path: &P } fn run_build_command(mut command: Command, file_to_build: &str, flaky_fail_counter: usize) { - let cmd_str = format!("{:?}", &command); + let mut command_string = std::ffi::OsString::new(); + command_string.push(command.get_program()); + + for arg in command.get_args() { + command_string.push(" "); + command_string.push(arg); + } + + let cmd_str = command_string.to_str().unwrap(); let cmd_output = command.output().unwrap(); let max_flaky_fail_count = 10; From abbc2d2acdbfab10bc58cb90e1e37c189cd56f09 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 12 Nov 2022 14:23:57 +0100 Subject: [PATCH 04/32] ignore ruby platform on windows --- crates/cli/tests/cli_run.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index 58f6e770f0..a7ce2fdd8f 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -480,6 +480,10 @@ mod cli_run { } #[test] + #[cfg_attr( + windows, + ignore = "this platform is broken, and `roc run --lib` is missing on windows" + )] fn ruby_interop() { test_roc_app_slim("examples/ruby-interop", "main.roc", "libhello", "", true) } From 2318ffe31d74c63bdb5b9241ea41695d1bf34576 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 12 Nov 2022 14:38:26 +0100 Subject: [PATCH 05/32] don't include header files that don't exist on windows --- crates/cli/tests/cli_run.rs | 7 ++----- examples/platform-switching/c-platform/host.c | 4 ++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index a7ce2fdd8f..28e129b85e 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -247,10 +247,7 @@ mod cli_run { ), }; - // strip out any carriage return characters to make the output on windows match unix - let stdout = out.stdout.replace('\r', ""); - - if !stdout.ends_with(expected_ending) { + if !&out.stdout.ends_with(expected_ending) { panic!( "expected output to end with {:?} but instead got {:#?} - stderr was: {:#?}", expected_ending, out.stdout, out.stderr @@ -589,7 +586,7 @@ mod cli_run { &[], &[Arg::ExamplePath("examples/hello.false")], &[], - "Hello, World!\n", + &("Hello, World!".to_string() + LINE_ENDING), false, true, ) diff --git a/examples/platform-switching/c-platform/host.c b/examples/platform-switching/c-platform/host.c index 8c403ba0fb..1b466cfa38 100644 --- a/examples/platform-switching/c-platform/host.c +++ b/examples/platform-switching/c-platform/host.c @@ -4,9 +4,13 @@ #include #include #include + +#ifdef _WIN32 +#else #include // shm_open #include // for mmap #include // for kill +#endif void* roc_alloc(size_t size, unsigned int alignment) { return malloc(size); } From 39b10f0dc8e51da0c91758702099c15271029f72 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Sat, 12 Nov 2022 14:58:16 +0100 Subject: [PATCH 06/32] do roc_cli tests Signed-off-by: Anton-4 <17049058+Anton-4@users.noreply.github.com> --- .github/workflows/windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 83a95ca0a9..2666083695 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -46,7 +46,7 @@ jobs: # Why are these tests not build with previous command? => fingerprint error. Use `CARGO_LOG=cargo::core::compiler::fingerprint=info` to investigate - name: Build specific tests without running. Twice for zig lld-link error. - run: cargo test --locked --release --no-run -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker || cargo test --locked --release --no-run -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker + run: cargo test --locked --release --no-run -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker -p roc_cli || cargo test --locked --release --no-run -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker -p roc_cli - name: Actually run the tests. - run: cargo test --locked --release -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker + run: cargo test --locked --release -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker -p roc_cli From 1efd7260de15f2b0a6ab3b3a4c5394068018c14c Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Fri, 11 Nov 2022 15:56:50 -0500 Subject: [PATCH 07/32] Add fmt test to make sure formatting works for all parser test cases --- crates/compiler/fmt/src/collection.rs | 3 ++ crates/compiler/fmt/src/def.rs | 2 +- crates/compiler/fmt/src/expr.rs | 24 +++++++---- crates/compiler/fmt/src/lib.rs | 2 +- crates/compiler/fmt/tests/test_fmt.rs | 62 +++++++++++++++++++++------ 5 files changed, 70 insertions(+), 23 deletions(-) diff --git a/crates/compiler/fmt/src/collection.rs b/crates/compiler/fmt/src/collection.rs index 772bf460cb..80798788ce 100644 --- a/crates/compiler/fmt/src/collection.rs +++ b/crates/compiler/fmt/src/collection.rs @@ -8,6 +8,7 @@ use crate::{ #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub enum Braces { + Round, Square, Curly, } @@ -22,11 +23,13 @@ pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable>( >::Item: Formattable, { let start = match braces { + Braces::Round => '(', Braces::Curly => '{', Braces::Square => '[', }; let end = match braces { + Braces::Round => ')', Braces::Curly => '}', Braces::Square => ']', }; diff --git a/crates/compiler/fmt/src/def.rs b/crates/compiler/fmt/src/def.rs index 94bfae58e1..d93c932f19 100644 --- a/crates/compiler/fmt/src/def.rs +++ b/crates/compiler/fmt/src/def.rs @@ -134,7 +134,7 @@ impl<'a> Formattable for TypeDef<'a> { if !self.is_multiline() { debug_assert_eq!(members.len(), 1); - buf.push_str(" "); + buf.spaces(1); members[0].format_with_options( buf, Parens::NotNeeded, diff --git a/crates/compiler/fmt/src/expr.rs b/crates/compiler/fmt/src/expr.rs index db6d46617c..75c8201f8e 100644 --- a/crates/compiler/fmt/src/expr.rs +++ b/crates/compiler/fmt/src/expr.rs @@ -326,9 +326,6 @@ impl<'a> Formattable for Expr<'a> { Record(fields) => { fmt_record(buf, None, *fields, indent); } - Tuple(_fields) => { - todo!("format tuple"); - } RecordUpdate { update, fields } => { fmt_record(buf, Some(*update), *fields, indent); } @@ -386,6 +383,7 @@ impl<'a> Formattable for Expr<'a> { fmt_if(buf, branches, final_else, self.is_multiline(), indent); } When(loc_condition, branches) => fmt_when(buf, loc_condition, branches, indent), + Tuple(items) => fmt_collection(buf, indent, Braces::Round, *items, Newlines::No), List(items) => fmt_collection(buf, indent, Braces::Square, *items, Newlines::No), BinOps(lefts, right) => fmt_binops(buf, lefts, right, false, parens, indent), UnaryOp(sub_expr, unary_op) => { @@ -421,7 +419,10 @@ impl<'a> Formattable for Expr<'a> { buf.push('.'); buf.push_str(key); } - MalformedIdent(_, _) => {} + MalformedIdent(str, _) => { + buf.indent(indent); + buf.push_str(str) + } MalformedClosure => {} PrecedenceConflict { .. } => {} } @@ -505,10 +506,10 @@ fn push_op(buf: &mut Buf, op: BinOp) { pub fn fmt_str_literal<'buf>(buf: &mut Buf<'buf>, literal: StrLiteral, indent: u16) { use roc_parse::ast::StrLiteral::*; - buf.indent(indent); - buf.push('"'); match literal { PlainLine(string) => { + buf.indent(indent); + buf.push('"'); // When a PlainLine contains '\n' or '"', format as a block string if string.contains('"') || string.contains('\n') { buf.push_str("\"\""); @@ -523,15 +524,21 @@ pub fn fmt_str_literal<'buf>(buf: &mut Buf<'buf>, literal: StrLiteral, indent: u } else { buf.push_str_allow_spaces(string); }; + buf.push('"'); } Line(segments) => { + buf.indent(indent); + buf.push('"'); for seg in segments.iter() { format_str_segment(seg, buf, 0) } + buf.push('"'); } Block(lines) => { // Block strings will always be formatted with """ on new lines - buf.push_str("\"\""); + buf.ensure_ends_with_newline(); + buf.indent(indent); + buf.push_str("\"\"\""); buf.newline(); for segments in lines.iter() { @@ -543,10 +550,9 @@ pub fn fmt_str_literal<'buf>(buf: &mut Buf<'buf>, literal: StrLiteral, indent: u buf.newline(); } buf.indent(indent); - buf.push_str("\"\""); + buf.push_str("\"\"\""); } } - buf.push('"'); } fn fmt_binops<'a, 'buf>( diff --git a/crates/compiler/fmt/src/lib.rs b/crates/compiler/fmt/src/lib.rs index 29b438de4b..cd175e53c5 100644 --- a/crates/compiler/fmt/src/lib.rs +++ b/crates/compiler/fmt/src/lib.rs @@ -109,7 +109,7 @@ impl<'a> Buf<'a> { if self.spaces_to_flush > 0 { self.flush_spaces(); self.newline(); - } else if !self.text.ends_with('\n') { + } else if !self.text.ends_with('\n') && !self.text.is_empty() { self.newline() } } diff --git a/crates/compiler/fmt/tests/test_fmt.rs b/crates/compiler/fmt/tests/test_fmt.rs index 4bc00be14c..828c22c4f5 100644 --- a/crates/compiler/fmt/tests/test_fmt.rs +++ b/crates/compiler/fmt/tests/test_fmt.rs @@ -16,11 +16,15 @@ mod test_fmt { use roc_parse::state::State; use roc_test_utils::{assert_multiline_str_eq, workspace_root}; - // Not intended to be used directly in tests; please use expr_formats_to or expr_formats_same - fn expr_formats_to(input: &str, expected: &str) { + /// Check that the given input is formatted to the given output. + /// If the expected output is `None`, then this only checks that the input + /// parses without error, formats without error, and + /// (optionally, based on the value of `check_stability`) re-parses to + /// the same AST as the original. + fn expr_formats(input: &str, expected: Option<&str>, check_stability: bool) { let arena = Bump::new(); let input = input.trim(); - let expected = expected.trim(); + let expected = expected.map(|e| e.trim()); match roc_parse::test_helpers::parse_expr_with(&arena, input) { Ok(actual) => { @@ -32,12 +36,17 @@ mod test_fmt { let output = buf.as_str(); - assert_multiline_str_eq!(expected, output); + if let Some(expected) = expected { + assert_multiline_str_eq!(expected, output); + } let reparsed_ast = roc_parse::test_helpers::parse_expr_with(&arena, output).unwrap_or_else(|err| { panic!( - "After formatting, the source code no longer parsed!\n\nParse error was: {:?}\n\nThe code that failed to parse:\n\n{}\n\n", - err, output + "After formatting, the source code no longer parsed!\n\n\ + Parse error was: {:?}\n\n\ + The code that failed to parse:\n\n{}\n\n\ + The original ast was:\n\n{:#?}\n\n", + err, output, actual ); }); @@ -60,21 +69,27 @@ mod test_fmt { } // Now verify that the resultant formatting is _stable_ - i.e. that it doesn't change again if re-formatted - let mut reformatted_buf = Buf::new_in(&arena); - reparsed_ast.format_with_options(&mut reformatted_buf, Parens::NotNeeded, Newlines::Yes, 0); + if check_stability { + let mut reformatted_buf = Buf::new_in(&arena); + reparsed_ast.format_with_options(&mut reformatted_buf, Parens::NotNeeded, Newlines::Yes, 0); - if output != reformatted_buf.as_str() { - eprintln!("Formatting bug; formatting is not stable. Reformatting the formatted code changed it again, as follows:\n\n"); + if output != reformatted_buf.as_str() { + eprintln!("Formatting bug; formatting is not stable. Reformatting the formatted code changed it again, as follows:\n\n"); - assert_multiline_str_eq!(output, reformatted_buf.as_str()); + assert_multiline_str_eq!(output, reformatted_buf.as_str()); + } } } Err(error) => panic!("Unexpected parse failure when parsing this for formatting:\n\n{}\n\nParse error was:\n\n{:?}\n\n", input, error) }; } + fn expr_formats_to(input: &str, expected: &str) { + expr_formats(input, Some(expected), true); + } + fn expr_formats_same(input: &str) { - expr_formats_to(input, input); + expr_formats(input, Some(input), true); } fn fmt_module_and_defs<'a>( @@ -5825,4 +5840,27 @@ mod test_fmt { // "# // )); // } + + #[test] + fn parse_test_snapshots_format_without_error() { + fn list(dir: &std::path::Path) -> std::vec::Vec { + std::fs::read_dir(dir) + .unwrap() + .map(|f| f.unwrap().file_name().to_str().unwrap().to_string()) + .collect::>() + } + + let base = std::path::PathBuf::from("../parse/tests/snapshots/pass"); + for file in list(&base) { + if file.ends_with(".expr.roc") { + println!("formatting {}", file); + let contents = std::fs::read_to_string(base.join(file)).unwrap(); + expr_formats(&contents, None, false); + } else if file.ends_with(".module.roc") { + // TODO: re-format module defs and ensure they're correct. + // Note that these tests don't have an actual module header, + // so we'll have to pre-pend that for this test. + } + } + } } From 29230921e6a3ab48557c519fc6ac8905694d589d Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Mon, 14 Nov 2022 19:37:25 +0100 Subject: [PATCH 08/32] windows fixes --- .github/workflows/windows.yml | 107 +++++++++++++++--------------- crates/compiler/build/src/link.rs | 75 ++++++++++++--------- rust-toolchain.toml | 27 +++++--- 3 files changed, 114 insertions(+), 95 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 2666083695..e1fca24c70 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -1,52 +1,55 @@ -on: [pull_request] - -name: Test windows build - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -env: - RUST_BACKTRACE: 1 - -jobs: - windows-cargo-build: - name: windows-cargo-build - runs-on: windows-2022 - env: - LLVM_SYS_130_PREFIX: C:\LLVM-13.0.1-win64 - - timeout-minutes: 150 - steps: - - uses: actions/checkout@v2 - - - run: Add-Content -Path "$env:GITHUB_ENV" -Value "GITHUB_RUNNER_CPU=$((Get-CimInstance Win32_Processor).Name)" - - - uses: Swatinem/rust-cache@v2 - with: - shared-key: "rust-cache-windows-${{env.GITHUB_RUNNER_CPU}}" - - - name: download and install zig - run: | - curl.exe --output "C:\zig-windows-x86_64-0.9.1.zip" --url https://ziglang.org/download/0.9.1/zig-windows-x86_64-0.9.1.zip - cd C:\ - 7z x zig-windows-x86_64-0.9.1.zip - Add-Content $env:GITHUB_PATH "C:\zig-windows-x86_64-0.9.1\" - - - name: zig version - run: zig version - - - name: set up llvm 13 - run: | - curl.exe -L -O https://github.com/roc-lang/llvm-package-windows/releases/download/v13.0.1/LLVM-13.0.1-win64.7z - 7z x LLVM-13.0.1-win64.7z -oC:\LLVM-13.0.1-win64 - - - name: Build tests --release without running. Twice for zig lld-link error. - run: cargo test --locked --release --no-run || cargo test --locked --release --no-run - - # Why are these tests not build with previous command? => fingerprint error. Use `CARGO_LOG=cargo::core::compiler::fingerprint=info` to investigate - - name: Build specific tests without running. Twice for zig lld-link error. - run: cargo test --locked --release --no-run -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker -p roc_cli || cargo test --locked --release --no-run -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker -p roc_cli - - - name: Actually run the tests. - run: cargo test --locked --release -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker -p roc_cli +on: [pull_request] + +name: Test windows build + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + RUST_BACKTRACE: 1 + +jobs: + windows-cargo-build: + name: windows-cargo-build + runs-on: windows-2022 + env: + LLVM_SYS_130_PREFIX: C:\LLVM-13.0.1-win64 + + timeout-minutes: 150 + steps: + - uses: actions/checkout@v2 + + - run: Add-Content -Path "$env:GITHUB_ENV" -Value "GITHUB_RUNNER_CPU=$((Get-CimInstance Win32_Processor).Name)" + + - uses: Swatinem/rust-cache@v2 + with: + shared-key: "rust-cache-windows-${{env.GITHUB_RUNNER_CPU}}" + + - name: download and install zig + run: | + curl.exe --output "C:\zig-windows-x86_64-0.9.1.zip" --url https://ziglang.org/download/0.9.1/zig-windows-x86_64-0.9.1.zip + cd C:\ + 7z x zig-windows-x86_64-0.9.1.zip + Add-Content $env:GITHUB_PATH "C:\zig-windows-x86_64-0.9.1\" + + - name: zig version + run: zig version + + - name: install rust nightly 1.64 + run: rustup install nightly-2022-08-06 + + - name: set up llvm 13 + run: | + curl.exe -L -O https://github.com/roc-lang/llvm-package-windows/releases/download/v13.0.1/LLVM-13.0.1-win64.7z + 7z x LLVM-13.0.1-win64.7z -oC:\LLVM-13.0.1-win64 + + - name: Build tests --release without running. Twice for zig lld-link error. + run: cargo test --locked --release --no-run || cargo test --locked --release --no-run + + # Why are these tests not build with previous command? => fingerprint error. Use `CARGO_LOG=cargo::core::compiler::fingerprint=info` to investigate + - name: Build specific tests without running. Twice for zig lld-link error. + run: cargo test --locked --release --no-run -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker -p roc_cli || cargo test --locked --release --no-run -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker -p roc_cli + + - name: Actually run the tests. + run: cargo test --locked --release -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker -p roc_cli diff --git a/crates/compiler/build/src/link.rs b/crates/compiler/build/src/link.rs index ca9ddeb9d3..f682091075 100644 --- a/crates/compiler/build/src/link.rs +++ b/crates/compiler/build/src/link.rs @@ -186,11 +186,15 @@ pub fn build_zig_host_native( opt_level: OptLevel, shared_lib_path: Option<&Path>, ) -> Command { + // to prevent `clang failed with stderr: zig: error: unable to make temporary file: No such file or directory` + let env_userprofile = env::var("USERPROFILE").unwrap_or_else(|_| "".to_string()); + let mut zig_cmd = zig(); zig_cmd .env_clear() .env("PATH", env_path) - .env("HOME", env_home); + .env("HOME", env_home) + .env("USERPROFILE", env_userprofile); if let Some(shared_lib_path) = shared_lib_path { zig_cmd.args(&[ @@ -419,7 +423,7 @@ pub fn build_c_host_native( dest, sources[0], find_zig_str_path().to_str().unwrap(), - "x86_64-windows-gnu", + get_target_str(target), opt_level, Some(shared_lib_path), ); @@ -578,23 +582,16 @@ pub fn rebuild_host( shared_lib_path, ) } - Architecture::X86_64 => { - let target = match target.operating_system { - OperatingSystem::Windows => "x86_64-windows-gnu", - _ => "native", - }; - - build_zig_host_native( - &env_path, - &env_home, - host_dest.to_str().unwrap(), - zig_host_src.to_str().unwrap(), - zig_str_path.to_str().unwrap(), - target, - opt_level, - shared_lib_path, - ) - } + Architecture::X86_64 => build_zig_host_native( + &env_path, + &env_home, + host_dest.to_str().unwrap(), + zig_host_src.to_str().unwrap(), + zig_str_path.to_str().unwrap(), + get_target_str(target), + opt_level, + shared_lib_path, + ), Architecture::X86_32(_) => build_zig_host_native( &env_path, &env_home, @@ -636,7 +633,7 @@ pub fn rebuild_host( // on windows, we need the nightly toolchain so we can use `-Z export-executable-symbols` // using `+nightly` only works when running cargo through rustup let mut cmd = rustup(); - cmd.args(["run", "nightly", "cargo"]); + cmd.args(["run", "nightly-2022-08-06", "cargo"]); cmd } else { @@ -807,6 +804,16 @@ pub fn rebuild_host( host_dest } +fn get_target_str(target: &Triple) -> &str { + if target.operating_system == OperatingSystem::Windows + && target.environment == target_lexicon::Environment::Gnu + { + "x86_64-windows-gnu" + } else { + "native" + } +} + fn nix_path_opt() -> Option { env::var_os("NIX_GLIBC_PATH").map(|path| path.into_string().unwrap()) } @@ -1227,7 +1234,7 @@ fn link_wasm32( } fn link_windows( - _target: &Triple, + target: &Triple, output_path: PathBuf, input_paths: &[&str], link_type: LinkType, @@ -1263,7 +1270,7 @@ fn link_windows( .args(input_paths) .args([ "-target", - "x86_64-windows-gnu", + get_target_str(target), "--subsystem", "console", "-lc", @@ -1386,24 +1393,26 @@ fn run_build_command(mut command: Command, file_to_build: &str, flaky_fail_count match std::str::from_utf8(&cmd_output.stderr) { Ok(stderr) => { // flaky error seen on macos 12 apple silicon, related to https://github.com/ziglang/zig/issues/9711 - if stderr.contains("unable to save cached ZIR code") && flaky_fail_counter < max_flaky_fail_count { - run_build_command(command, file_to_build, flaky_fail_counter + 1) + if stderr.contains("unable to save cached ZIR code") { + if flaky_fail_counter < max_flaky_fail_count { + run_build_command(command, file_to_build, flaky_fail_counter + 1) + } else { + internal_error!( + "Error:\n Failed to rebuild {} {} times, this is not a flaky failure:\n The executed command was:\n {}\n stderr of that command:\n {}", + file_to_build, + max_flaky_fail_count, + cmd_str, + stderr + ) + } } else { internal_error!( - "Error:\n Failed to rebuild {} {} times, this is not a flaky failure:\n The executed command was:\n {}\n stderr of that command:\n {}", + "Error:\n Failed to rebuild {}:\n The executed command was:\n {}\n stderr of that command:\n {}", file_to_build, - max_flaky_fail_count, cmd_str, stderr ) } - - internal_error!( - "Error:\n Failed to rebuild {}:\n The executed command was:\n {}\n stderr of that command:\n {}", - file_to_build, - cmd_str, - stderr - ) }, Err(utf8_err) => internal_error!( "Error:\n Failed to rebuild {}:\n The executed command was:\n {}\n stderr of that command could not be parsed as valid utf8:\n {}", diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 1924978fb6..90a1165f87 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,10 +1,17 @@ -[toolchain] -channel = "1.64.0" # when changing this, update the date below with the last nightly with matching version using the link below -# https://github.com/oxalica/rust-overlay/tree/master/manifests/nightly/2022 -# channel = "nightly-2022-08-06" # 1.64 nightly to be able to use unstable features -profile = "default" -components = [ - # for usages of rust-analyzer or similar tools inside `nix develop` - "rust-src" -] -targets = [ "x86_64-unknown-linux-gnu" ] +[toolchain] +# How to update version: +# - update `channel = "RUST_VERSION"` +# - to update the nightly version: +# - Find the latest nightly release that matches RUST_VERSION here: https://github.com/oxalica/rust-overlay/tree/master/manifests/nightly/2022 +# - update `channel = "nightly-OLD_DATE"` below +# - update nightly-OLD_DATE in .github/workflows/windows.yml +# - update nightly-OLD_DATE in crates/compiler/build/src/link.rs + +channel = "1.64.0" # check ^^^ when changing this +# +# channel = "nightly-2022-08-06" # 1.64 nightly to be able to use unstable features +profile = "default" +components = [ + # for usages of rust-analyzer or similar tools inside `nix develop` + "rust-src" +] From 5aa29c4e8be4c7d7a4f6c4c56c6891dd662ea698 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 15 Nov 2022 22:02:11 +0100 Subject: [PATCH 09/32] morphic + reset/reuse --- crates/compiler/alias_analysis/src/lib.rs | 29 +++++++++++++++++++--- crates/compiler/gen_llvm/src/llvm/build.rs | 17 +++++++++++-- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/crates/compiler/alias_analysis/src/lib.rs b/crates/compiler/alias_analysis/src/lib.rs index 01d9287320..d3f91bb538 100644 --- a/crates/compiler/alias_analysis/src/lib.rs +++ b/crates/compiler/alias_analysis/src/lib.rs @@ -1543,11 +1543,32 @@ fn expr_spec<'a>( } _ => unreachable!("empty array does not have a list layout"), }, - Reset { symbol, .. } => { - let type_id = layout_spec(env, builder, interner, layout, &WhenRecursive::Unreachable)?; - let value_id = env.symbols[symbol]; + Reset { + symbol, + update_mode, + } => { + let tag_value_id = env.symbols[symbol]; - builder.add_unknown_with(block, &[value_id], type_id) + let union_layout = match layout { + Layout::Union(ul) => ul, + _ => unreachable!(), + }; + + let type_name_bytes = recursive_tag_union_name_bytes(union_layout).as_bytes(); + let type_name = TypeName(&type_name_bytes); + + // unwrap the named wrapper + let union_id = builder.add_unwrap_named(block, MOD_APP, type_name, tag_value_id)?; + + let heap_cell = builder.add_get_tuple_field(block, union_id, TAG_CELL_INDEX)?; + let union_data = builder.add_get_tuple_field(block, union_id, TAG_DATA_INDEX)?; + + let mode = update_mode.to_bytes(); + let update_mode_var = UpdateModeVar(&mode); + + let _unit = builder.add_update(block, update_mode_var, heap_cell)?; + + with_new_heap_cell(builder, block, union_data) } RuntimeErrorFunction(_) => { let type_id = layout_spec(env, builder, interner, layout, &WhenRecursive::Unreachable)?; diff --git a/crates/compiler/gen_llvm/src/llvm/build.rs b/crates/compiler/gen_llvm/src/llvm/build.rs index 5335c0dbb3..bb2b0ec22d 100644 --- a/crates/compiler/gen_llvm/src/llvm/build.rs +++ b/crates/compiler/gen_llvm/src/llvm/build.rs @@ -1053,7 +1053,16 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( load_roc_value(env, *layout, value.into_pointer_value(), "load_boxed_value") } - Reset { symbol, .. } => { + Reset { + symbol, + update_mode, + } => { + let bytes = update_mode.to_bytes(); + let update_var = UpdateModeVar(&bytes); + let update_mode = func_spec_solutions + .update_mode(update_var) + .unwrap_or(UpdateMode::Immutable); + let (tag_ptr, layout) = load_symbol_and_layout(scope, symbol); let tag_ptr = tag_ptr.into_pointer_value(); @@ -1070,7 +1079,11 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( let refcount_ptr = PointerToRefcount::from_ptr_to_data(env, tag_pointer_clear_tag_id(env, tag_ptr)); - let is_unique = refcount_ptr.is_1(env); + + let is_unique = match update_mode { + UpdateMode::InPlace => env.context.bool_type().const_int(1, false), + UpdateMode::Immutable => refcount_ptr.is_1(env), + }; env.builder .build_conditional_branch(is_unique, then_block, else_block); From ce160f28a2ddef67adf531e462bde8aabe392556 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Tue, 15 Nov 2022 16:21:00 -0600 Subject: [PATCH 10/32] Chase under aliases during occurs checking Closes #4368 --- crates/compiler/solve/tests/solve_expr.rs | 23 +++++++++++++++++++++++ crates/compiler/types/src/subs.rs | 8 ++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/crates/compiler/solve/tests/solve_expr.rs b/crates/compiler/solve/tests/solve_expr.rs index 3ca24cbe93..74e72ff688 100644 --- a/crates/compiler/solve/tests/solve_expr.rs +++ b/crates/compiler/solve/tests/solve_expr.rs @@ -8197,4 +8197,27 @@ mod solve_expr { "### ); } + + #[test] + fn fix_recursion_under_alias_issue_4368() { + infer_eq_without_problem( + indoc!( + r#" + app "test" provides [doIt] to "./platform" + + Effect : [ + DoIt {} ({} -> Effect), + ] + + Task := ({} -> Effect) -> Effect + + doIt : {} -> Task + doIt = \{} -> + @Task \toNext -> + DoIt {} \{} -> (toNext {}) + "# + ), + "{} -> Task", + ) + } } diff --git a/crates/compiler/types/src/subs.rs b/crates/compiler/types/src/subs.rs index 50784290ec..381011123c 100644 --- a/crates/compiler/types/src/subs.rs +++ b/crates/compiler/types/src/subs.rs @@ -3255,13 +3255,17 @@ fn occurs( EmptyRecord | EmptyTagUnion => Ok(()), } } - Alias(_, args, _, _) => { + Alias(_, args, real_var, _) => { let mut new_seen = seen.to_owned(); new_seen.push(root_var); for var_index in args.into_iter() { let var = subs[var_index]; - short_circuit_help(subs, root_var, &new_seen, var)?; + if short_circuit_help(subs, root_var, &new_seen, var).is_err() { + // Pay the cost and figure out what the actual recursion point is + + return short_circuit_help(subs, root_var, &new_seen, *real_var); + } } Ok(()) From 2d57aa2170ae34b5a3642e077bd6727097e7cf2f Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Tue, 15 Nov 2022 17:33:18 -0600 Subject: [PATCH 11/32] Use thread-local buffer for occurs check seen variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This materially improves performance for programs that are recursion-heavy (as most Roc programs will likely be). ``` $ hyperfine '/tmp/roc-old check examples/cli/cli-platform/Arg.roc' '/tmp/roc-new check examples/cli/cli-platform/Arg.roc' --warmup 10 Benchmark 1: /tmp/roc-old check examples/cli/cli-platform/Arg.roc Time (mean ± σ): 53.8 ms ± 1.3 ms [User: 87.3 ms, System: 10.8 ms] Range (min … max): 52.2 ms … 60.4 ms 51 runs Benchmark 2: /tmp/roc-new check examples/cli/cli-platform/Arg.roc Time (mean ± σ): 45.0 ms ± 1.6 ms [User: 59.4 ms, System: 11.3 ms] Range (min … max): 42.6 ms … 49.8 ms 60 runs Summary '/tmp/roc-new check examples/cli/cli-platform/Arg.roc' ran 1.20 ± 0.05 times faster than '/tmp/roc-old check examples/cli/cli-platform/Arg.roc' ``` The time spent in `occurs` during checking for `Arg` drops from 50% to 23%. --- crates/compiler/types/src/subs.rs | 116 ++++++++++++++++-------------- 1 file changed, 62 insertions(+), 54 deletions(-) diff --git a/crates/compiler/types/src/subs.rs b/crates/compiler/types/src/subs.rs index 381011123c..2d9848cc8e 100644 --- a/crates/compiler/types/src/subs.rs +++ b/crates/compiler/types/src/subs.rs @@ -1951,7 +1951,10 @@ impl Subs { /// This ignores [Content::RecursionVar]s that occur recursively, because those are /// already priced in and expected to occur. pub fn occurs(&self, var: Variable) -> Result<(), (Variable, Vec)> { - occurs(self, &[], var) + let mut scratchpad = take_occurs_scratchpad(); + let result = occurs(self, &mut scratchpad, var); + put_occurs_scratchpad(scratchpad); + result } pub fn mark_tag_union_recursive( @@ -3196,9 +3199,24 @@ fn is_empty_record(subs: &Subs, mut var: Variable) -> bool { } } +std::thread_local! { + static SCRATCHPAD_FOR_OCCURS: RefCell>> = RefCell::new(Some(Vec::with_capacity(1024))); +} + +fn take_occurs_scratchpad() -> Vec { + SCRATCHPAD_FOR_OCCURS.with(|f| f.take().unwrap()) +} + +fn put_occurs_scratchpad(mut scratchpad: Vec) { + SCRATCHPAD_FOR_OCCURS.with(|f| { + scratchpad.clear(); + f.replace(Some(scratchpad)); + }); +} + fn occurs( subs: &Subs, - seen: &[Variable], + seen: &mut Vec, input_var: Variable, ) -> Result<(), (Variable, Vec)> { use self::Content::*; @@ -3207,9 +3225,10 @@ fn occurs( let root_var = subs.get_root_key_without_compacting(input_var); if seen.contains(&root_var) { - Err((root_var, vec![])) + Err((root_var, Vec::with_capacity(0))) } else { - match subs.get_content_without_compacting(root_var) { + seen.push(root_var); + let result = (|| match subs.get_content_without_compacting(root_var) { FlexVar(_) | RigidVar(_) | FlexAbleVar(_, _) @@ -3217,54 +3236,44 @@ fn occurs( | RecursionVar { .. } | Error => Ok(()), - Structure(flat_type) => { - let mut new_seen = seen.to_owned(); - - new_seen.push(root_var); - - match flat_type { - Apply(_, args) => { - short_circuit(subs, root_var, &new_seen, subs.get_subs_slice(*args).iter()) - } - Func(arg_vars, closure_var, ret_var) => { - let it = once(ret_var) - .chain(once(closure_var)) - .chain(subs.get_subs_slice(*arg_vars).iter()); - short_circuit(subs, root_var, &new_seen, it) - } - Record(vars_by_field, ext_var) => { - let slice = - SubsSlice::new(vars_by_field.variables_start, vars_by_field.length); - let it = once(ext_var).chain(subs.get_subs_slice(slice).iter()); - short_circuit(subs, root_var, &new_seen, it) - } - TagUnion(tags, ext_var) => { - occurs_union(subs, root_var, &new_seen, tags)?; - - short_circuit_help(subs, root_var, &new_seen, *ext_var) - } - FunctionOrTagUnion(_, _, ext_var) => { - let it = once(ext_var); - short_circuit(subs, root_var, &new_seen, it) - } - RecursiveTagUnion(_, tags, ext_var) => { - occurs_union(subs, root_var, &new_seen, tags)?; - - short_circuit_help(subs, root_var, &new_seen, *ext_var) - } - EmptyRecord | EmptyTagUnion => Ok(()), + Structure(flat_type) => match flat_type { + Apply(_, args) => { + short_circuit(subs, root_var, seen, subs.get_subs_slice(*args).iter()) } - } - Alias(_, args, real_var, _) => { - let mut new_seen = seen.to_owned(); - new_seen.push(root_var); + Func(arg_vars, closure_var, ret_var) => { + let it = once(ret_var) + .chain(once(closure_var)) + .chain(subs.get_subs_slice(*arg_vars).iter()); + short_circuit(subs, root_var, seen, it) + } + Record(vars_by_field, ext_var) => { + let slice = SubsSlice::new(vars_by_field.variables_start, vars_by_field.length); + let it = once(ext_var).chain(subs.get_subs_slice(slice).iter()); + short_circuit(subs, root_var, seen, it) + } + TagUnion(tags, ext_var) => { + occurs_union(subs, root_var, seen, tags)?; + short_circuit_help(subs, root_var, seen, *ext_var) + } + FunctionOrTagUnion(_, _, ext_var) => { + let it = once(ext_var); + short_circuit(subs, root_var, seen, it) + } + RecursiveTagUnion(_, tags, ext_var) => { + occurs_union(subs, root_var, seen, tags)?; + + short_circuit_help(subs, root_var, seen, *ext_var) + } + EmptyRecord | EmptyTagUnion => Ok(()), + }, + Alias(_, args, real_var, _) => { for var_index in args.into_iter() { let var = subs[var_index]; - if short_circuit_help(subs, root_var, &new_seen, var).is_err() { + if short_circuit_help(subs, root_var, seen, var).is_err() { // Pay the cost and figure out what the actual recursion point is - return short_circuit_help(subs, root_var, &new_seen, *real_var); + return short_circuit_help(subs, root_var, seen, *real_var); } } @@ -3276,16 +3285,15 @@ fn occurs( unspecialized: _, ambient_function: _, }) => { - let mut new_seen = seen.to_owned(); - new_seen.push(root_var); - // unspecialized lambda vars excluded because they are not explicitly part of the // type (they only matter after being resolved). - occurs_union(subs, root_var, &new_seen, solved) + occurs_union(subs, root_var, seen, solved) } RangedNumber(_range_vars) => Ok(()), - } + })(); + seen.pop(); + result } } @@ -3293,7 +3301,7 @@ fn occurs( fn occurs_union( subs: &Subs, root_var: Variable, - seen: &[Variable], + seen: &mut Vec, tags: &UnionLabels, ) -> Result<(), (Variable, Vec)> { for slice_index in tags.variables() { @@ -3310,7 +3318,7 @@ fn occurs_union( fn short_circuit<'a, T>( subs: &Subs, root_key: Variable, - seen: &[Variable], + seen: &mut Vec, iter: T, ) -> Result<(), (Variable, Vec)> where @@ -3327,7 +3335,7 @@ where fn short_circuit_help( subs: &Subs, root_key: Variable, - seen: &[Variable], + seen: &mut Vec, var: Variable, ) -> Result<(), (Variable, Vec)> { if let Err((v, mut vec)) = occurs(subs, seen, var) { From d4bf9463272beb07f853bef441a4d14103338326 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Tue, 15 Nov 2022 17:42:41 -0500 Subject: [PATCH 12/32] Assert formatting for parse tests --- crates/compiler/fmt/tests/test_fmt.rs | 77 ++++++++++++++++--- ..._signature_is_multiline.expr.formatted.roc | 4 + .../ability_multi_line.expr.formatted.roc | 5 ++ .../ability_single_line.expr.formatted.roc | 3 + .../ability_two_in_a_row.expr.formatted.roc | 5 ++ .../pass/add_with_spaces.expr.formatted.roc | 1 + ...ated_record_destructure.expr.formatted.roc | 4 + ...notated_tag_destructure.expr.formatted.roc | 4 + ...tated_tuple_destructure.expr.formatted.roc | 4 + .../pass/apply_two_args.expr.formatted.roc | 1 + .../apply_unary_negation.expr.formatted.roc | 1 + .../pass/apply_unary_not.expr.formatted.roc | 1 + .../pass/basic_docs.expr.formatted.roc | 9 +++ .../pass/comment_after_op.expr.formatted.roc | 3 + .../pass/comment_before_op.expr.formatted.roc | 2 + ...mment_inside_empty_list.expr.formatted.roc | 2 + .../comment_with_non_ascii.expr.formatted.roc | 2 + ...tructure_tag_assignment.expr.formatted.roc | 3 + .../pass/empty_string.expr.formatted.roc | 1 + .../snapshots/pass/equals.expr.formatted.roc | 1 + .../snapshots/pass/expect.expr.formatted.roc | 4 + .../snapshots/pass/if_def.expr.formatted.roc | 3 + .../pass/lambda_indent.expr.formatted.roc | 2 + ...osing_indent_not_enough.expr.formatted.roc | 10 +++ ...ndent_no_trailing_comma.expr.formatted.roc | 6 ++ ...ent_with_trailing_comma.expr.formatted.roc | 6 ++ .../pass/list_patterns.expr.formatted.roc | 9 +++ ...ed_pattern_field_access.expr.formatted.roc | 3 + ...med_pattern_module_name.expr.formatted.roc | 3 + ...minus_twelve_minus_five.expr.formatted.roc | 1 + .../pass/mixed_docs.expr.formatted.roc | 7 ++ .../pass/multi_backpassing.expr.formatted.roc | 3 + .../pass/multi_char_string.expr.formatted.roc | 1 + .../pass/multiline_string.expr.formatted.roc | 13 ++++ ..._signature_with_comment.expr.formatted.roc | 5 ++ .../multiple_operators.expr.formatted.roc | 1 + .../pass/nested_if.expr.formatted.roc | 6 ++ .../newline_after_equals.expr.formatted.roc | 4 + .../pass/newline_after_mul.expr.formatted.roc | 3 + .../pass/newline_after_sub.expr.formatted.roc | 3 + ...spaces_before_less_than.expr.formatted.roc | 5 ++ .../newline_singleton_list.expr.formatted.roc | 3 + .../pass/not_docs.expr.formatted.roc | 7 ++ ...number_literal_suffixes.expr.formatted.roc | 37 +++++++++ .../pass/one_backpassing.expr.formatted.roc | 4 + .../pass/one_char_string.expr.formatted.roc | 1 + .../snapshots/pass/one_def.expr.formatted.roc | 4 + .../pass/one_minus_two.expr.formatted.roc | 1 + .../pass/one_plus_two.expr.formatted.roc | 1 + .../pass/one_spaced_def.expr.formatted.roc | 4 + ...ture_first_item_in_body.expr.formatted.roc | 3 + .../opaque_has_abilities.expr.formatted.roc | 24 ++++++ .../opaque_reference_expr.expr.formatted.roc | 1 + ...nce_expr_with_arguments.expr.formatted.roc | 1 + ...paque_reference_pattern.expr.formatted.roc | 2 + ..._pattern_with_arguments.expr.formatted.roc | 2 + .../pass/ops_with_newlines.expr.formatted.roc | 4 + ...tdented_app_with_record.expr.formatted.roc | 8 ++ .../pass/outdented_list.expr.formatted.roc | 7 ++ .../pass/outdented_record.expr.formatted.roc | 5 ++ .../pass/parenthetical_var.expr.formatted.roc | 1 + .../pass/parse_alias.expr.formatted.roc | 3 + .../pass/parse_as_ann.expr.formatted.roc | 3 + ...rn_with_space_in_parens.expr.formatted.roc | 2 + .../snapshots/pass/plus_if.expr.formatted.roc | 1 + .../pass/plus_when.expr.formatted.roc | 5 ++ .../record_destructure_def.expr.formatted.roc | 5 ++ .../record_func_type_decl.expr.formatted.roc | 8 ++ ...cord_type_with_function.expr.formatted.roc | 3 + .../pass/record_with_if.expr.formatted.roc | 1 + .../space_only_after_minus.expr.formatted.roc | 1 + .../spaced_singleton_list.expr.formatted.roc | 1 + ...paces_inside_empty_list.expr.formatted.roc | 1 + .../pass/sub_with_spaces.expr.formatted.roc | 1 + .../pass/ten_times_eleven.expr.formatted.roc | 1 + .../pass/two_backpassing.expr.formatted.roc | 5 ++ .../pass/two_branch_when.expr.formatted.roc | 3 + .../pass/two_spaced_def.expr.formatted.roc | 5 ++ ...pe_decl_with_underscore.expr.formatted.roc | 3 + .../unary_negation_arg.expr.formatted.roc | 1 + ...ry_negation_with_parens.expr.formatted.roc | 1 + .../unary_not_with_parens.expr.formatted.roc | 1 + .../underscore_backpassing.expr.formatted.roc | 4 + ...e_in_assignment_pattern.expr.formatted.roc | 7 ++ .../pass/var_minus_two.expr.formatted.roc | 1 + .../pass/when_if_guard.expr.formatted.roc | 9 +++ .../when_in_assignment.expr.formatted.roc | 4 + .../pass/when_in_function.expr.formatted.roc | 4 + ...ion_python_style_indent.expr.formatted.roc | 4 + .../pass/when_in_parens.expr.formatted.roc | 3 + ...when_in_parens_indented.expr.formatted.roc | 2 + ...th_alternative_patterns.expr.formatted.roc | 7 ++ ...th_function_application.expr.formatted.roc | 6 ++ ...n_with_negative_numbers.expr.formatted.roc | 3 + .../pass/when_with_numbers.expr.formatted.roc | 3 + .../pass/when_with_records.expr.formatted.roc | 3 + ...en_with_tuple_in_record.expr.formatted.roc | 3 + .../pass/when_with_tuples.expr.formatted.roc | 3 + .../where_clause_function.expr.formatted.roc | 3 + ...ultiple_bound_abilities.expr.formatted.roc | 7 ++ ...ere_clause_multiple_has.expr.formatted.roc | 3 + ...ple_has_across_newlines.expr.formatted.roc | 5 ++ ...ere_clause_non_function.expr.formatted.roc | 3 + ...where_clause_on_newline.expr.formatted.roc | 5 ++ crates/compiler/parse/tests/test_parse.rs | 9 ++- 105 files changed, 495 insertions(+), 12 deletions(-) create mode 100644 crates/compiler/parse/tests/snapshots/pass/ability_demand_signature_is_multiline.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/ability_multi_line.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/ability_single_line.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/ability_two_in_a_row.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/annotated_record_destructure.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/annotated_tag_destructure.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/annotated_tuple_destructure.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/apply_two_args.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/basic_docs.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/comment_after_op.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/comment_before_op.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/comment_inside_empty_list.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/destructure_tag_assignment.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/empty_string.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/equals.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/expect.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/if_def.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/lambda_indent.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/list_closing_indent_not_enough.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/list_closing_same_indent_no_trailing_comma.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/list_closing_same_indent_with_trailing_comma.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/list_patterns.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/mixed_docs.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/multi_char_string.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/multiline_string.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/multiple_operators.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/nested_if.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/not_docs.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/number_literal_suffixes.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/one_backpassing.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/one_char_string.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/one_def.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/one_minus_two.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/one_plus_two.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/opaque_destructure_first_item_in_body.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/opaque_has_abilities.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/opaque_reference_expr.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/opaque_reference_expr_with_arguments.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/opaque_reference_pattern.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/opaque_reference_pattern_with_arguments.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/outdented_app_with_record.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/outdented_list.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/outdented_record.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/parenthetical_var.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/parse_alias.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/plus_if.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/plus_when.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/record_func_type_decl.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/record_type_with_function.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/record_with_if.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/spaces_inside_empty_list.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/two_backpassing.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/two_branch_when.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/type_decl_with_underscore.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/underscore_in_assignment_pattern.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/var_minus_two.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/when_if_guard.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/when_in_assignment.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/when_in_function.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/when_in_function_python_style_indent.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/when_in_parens.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/when_with_records.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/when_with_tuple_in_record.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/when_with_tuples.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/where_clause_function.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/where_clause_multiple_bound_abilities.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/where_clause_multiple_has.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/where_clause_multiple_has_across_newlines.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/where_clause_non_function.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/where_clause_on_newline.expr.formatted.roc diff --git a/crates/compiler/fmt/tests/test_fmt.rs b/crates/compiler/fmt/tests/test_fmt.rs index 828c22c4f5..bc615c3a09 100644 --- a/crates/compiler/fmt/tests/test_fmt.rs +++ b/crates/compiler/fmt/tests/test_fmt.rs @@ -5,6 +5,8 @@ extern crate roc_fmt; #[cfg(test)] mod test_fmt { + use std::path::PathBuf; + use bumpalo::Bump; use roc_fmt::annotation::{Formattable, Newlines, Parens}; use roc_fmt::def::fmt_defs; @@ -21,10 +23,9 @@ mod test_fmt { /// parses without error, formats without error, and /// (optionally, based on the value of `check_stability`) re-parses to /// the same AST as the original. - fn expr_formats(input: &str, expected: Option<&str>, check_stability: bool) { + fn expr_formats(input: &str, check_formatting: impl Fn(&str), check_stability: bool) { let arena = Bump::new(); let input = input.trim(); - let expected = expected.map(|e| e.trim()); match roc_parse::test_helpers::parse_expr_with(&arena, input) { Ok(actual) => { @@ -36,9 +37,7 @@ mod test_fmt { let output = buf.as_str(); - if let Some(expected) = expected { - assert_multiline_str_eq!(expected, output); - } + check_formatting(output); let reparsed_ast = roc_parse::test_helpers::parse_expr_with(&arena, output).unwrap_or_else(|err| { panic!( @@ -84,12 +83,19 @@ mod test_fmt { }; } + fn check_formatting(expected: &'_ str) -> impl Fn(&str) + '_ { + let expected = expected.trim(); + move |output| { + assert_multiline_str_eq!(expected, output); + } + } + fn expr_formats_to(input: &str, expected: &str) { - expr_formats(input, Some(expected), true); + expr_formats(input, check_formatting(expected), true); } fn expr_formats_same(input: &str) { - expr_formats(input, Some(input), true); + expr_formats(input, check_formatting(input), true); } fn fmt_module_and_defs<'a>( @@ -5850,12 +5856,63 @@ mod test_fmt { .collect::>() } + fn check_saved_formatting(original: &'_ str, result_path: PathBuf) -> impl Fn(&str) + '_ { + move |actual_result: &str| { + if std::env::var("ROC_SNAPSHOT_TEST_OVERWRITE").is_ok() { + if original == actual_result { + std::fs::remove_file(&result_path) + .or_else(|e| { + if e.kind() == std::io::ErrorKind::NotFound { + Ok(()) + } else { + Err(e) + } + }) + .unwrap(); + } else { + std::fs::write(&result_path, actual_result).unwrap(); + } + } else if original == actual_result { + // We represent this expectation on the filesystem as the _absence_ of the .formatted.expr.roc file. + // This makes the directory a bit cleaner. + + assert!(!result_path.exists(), + "Expected no file at {}\n\ + This how we represent the expectation that the formatting of the input file should not change.\n\ + consider running the tests with:\n\ + `env ROC_SNAPSHOT_TEST_OVERWRITE=1 cargo test ...` (which will delete the file for you),\n\ + and commiting the delete.", + result_path.display()); + } else { + let expected_result = + std::fs::read_to_string(&result_path).unwrap_or_else(|e| { + panic!( + "Error opening test output file {}:\n\ + {:?} + Supposing the file is missing, consider running the tests with:\n\ + `env ROC_SNAPSHOT_TEST_OVERWRITE=1 cargo test ...`\n\ + and committing the file that creates.", + result_path.display(), + e + ); + }); + + assert_multiline_str_eq!(expected_result.as_str(), actual_result); + } + } + } + let base = std::path::PathBuf::from("../parse/tests/snapshots/pass"); for file in list(&base) { - if file.ends_with(".expr.roc") { + if let Some(prefix) = file.strip_suffix(".expr.roc") { println!("formatting {}", file); - let contents = std::fs::read_to_string(base.join(file)).unwrap(); - expr_formats(&contents, None, false); + let contents = std::fs::read_to_string(base.join(&file)).unwrap(); + let formatted_path = base.join(format!("{}.expr.formatted.roc", prefix)); + expr_formats( + &contents, + check_saved_formatting(&contents, formatted_path), + false, + ); } else if file.ends_with(".module.roc") { // TODO: re-format module defs and ensure they're correct. // Note that these tests don't have an actual module header, diff --git a/crates/compiler/parse/tests/snapshots/pass/ability_demand_signature_is_multiline.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/ability_demand_signature_is_multiline.expr.formatted.roc new file mode 100644 index 0000000000..e7679e58b7 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/ability_demand_signature_is_multiline.expr.formatted.roc @@ -0,0 +1,4 @@ +Hash has + hash : a -> U64 + +1 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/ability_multi_line.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/ability_multi_line.expr.formatted.roc new file mode 100644 index 0000000000..56efcb2abc --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/ability_multi_line.expr.formatted.roc @@ -0,0 +1,5 @@ +Hash has + hash : a -> U64 + hash2 : a -> U64 + +1 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/ability_single_line.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/ability_single_line.expr.formatted.roc new file mode 100644 index 0000000000..80bf875f2b --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/ability_single_line.expr.formatted.roc @@ -0,0 +1,3 @@ +Hash has hash : a -> U64 | a has Hash + +1 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/ability_two_in_a_row.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/ability_two_in_a_row.expr.formatted.roc new file mode 100644 index 0000000000..d27a926150 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/ability_two_in_a_row.expr.formatted.roc @@ -0,0 +1,5 @@ +Ab1 has ab1 : a -> {} | a has Ab1 + +Ab2 has ab2 : a -> {} | a has Ab2 + +1 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.formatted.roc new file mode 100644 index 0000000000..193df0b550 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/add_with_spaces.expr.formatted.roc @@ -0,0 +1 @@ +1 + 2 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/annotated_record_destructure.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/annotated_record_destructure.expr.formatted.roc new file mode 100644 index 0000000000..c90bbf19bb --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/annotated_record_destructure.expr.formatted.roc @@ -0,0 +1,4 @@ +{ x, y } : Foo +{ x, y } = { x: "foo", y: 3.14 } + +x \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/annotated_tag_destructure.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/annotated_tag_destructure.expr.formatted.roc new file mode 100644 index 0000000000..ffdce670b5 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/annotated_tag_destructure.expr.formatted.roc @@ -0,0 +1,4 @@ +UserId x : [UserId I64] +(UserId x) = UserId 42 + +x \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/annotated_tuple_destructure.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/annotated_tuple_destructure.expr.formatted.roc new file mode 100644 index 0000000000..d114e4c0dc --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/annotated_tuple_destructure.expr.formatted.roc @@ -0,0 +1,4 @@ +(x, y) : Foo +(x, y) = ("foo", 3.14) + +x \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/apply_two_args.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/apply_two_args.expr.formatted.roc new file mode 100644 index 0000000000..241d261c53 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/apply_two_args.expr.formatted.roc @@ -0,0 +1 @@ +whee 12 34 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.formatted.roc new file mode 100644 index 0000000000..13ce629143 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/apply_unary_negation.expr.formatted.roc @@ -0,0 +1 @@ +-whee 12 foo \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.formatted.roc new file mode 100644 index 0000000000..a843b0638a --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/apply_unary_not.expr.formatted.roc @@ -0,0 +1 @@ +!whee 12 foo \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/basic_docs.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/basic_docs.expr.formatted.roc new file mode 100644 index 0000000000..8ebd4435d4 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/basic_docs.expr.formatted.roc @@ -0,0 +1,9 @@ +## first line of docs +## second line +## third line +## fourth line +## +## sixth line after doc new line +x = 5 + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/comment_after_op.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/comment_after_op.expr.formatted.roc new file mode 100644 index 0000000000..a5c7d29182 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/comment_after_op.expr.formatted.roc @@ -0,0 +1,3 @@ +12 +* # test! +92 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/comment_before_op.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/comment_before_op.expr.formatted.roc new file mode 100644 index 0000000000..eced1199fd --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/comment_before_op.expr.formatted.roc @@ -0,0 +1,2 @@ +3 # test! ++ 4 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/comment_inside_empty_list.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/comment_inside_empty_list.expr.formatted.roc new file mode 100644 index 0000000000..5b7bb076a8 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/comment_inside_empty_list.expr.formatted.roc @@ -0,0 +1,2 @@ +[ # comment +] \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.formatted.roc new file mode 100644 index 0000000000..d030753107 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/comment_with_non_ascii.expr.formatted.roc @@ -0,0 +1,2 @@ +3 # 2 × 2 ++ 4 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/destructure_tag_assignment.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/destructure_tag_assignment.expr.formatted.roc new file mode 100644 index 0000000000..efe6270b22 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/destructure_tag_assignment.expr.formatted.roc @@ -0,0 +1,3 @@ +(Email str) = Email "blah@example.com" + +str \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/empty_string.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/empty_string.expr.formatted.roc new file mode 100644 index 0000000000..3cc762b550 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/empty_string.expr.formatted.roc @@ -0,0 +1 @@ +"" \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/equals.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/equals.expr.formatted.roc new file mode 100644 index 0000000000..616ee7099e --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/equals.expr.formatted.roc @@ -0,0 +1 @@ +x == y \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/expect.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/expect.expr.formatted.roc new file mode 100644 index 0000000000..d0ec1ce6d3 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/expect.expr.formatted.roc @@ -0,0 +1,4 @@ +expect + 1 == 1 + +4 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/if_def.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/if_def.expr.formatted.roc new file mode 100644 index 0000000000..a671b8d1f5 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/if_def.expr.formatted.roc @@ -0,0 +1,3 @@ +iffy = 5 + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/lambda_indent.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/lambda_indent.expr.formatted.roc new file mode 100644 index 0000000000..9872c7f5b5 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/lambda_indent.expr.formatted.roc @@ -0,0 +1,2 @@ +\x -> + 1 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/list_closing_indent_not_enough.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/list_closing_indent_not_enough.expr.formatted.roc new file mode 100644 index 0000000000..5ec761f8f7 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/list_closing_indent_not_enough.expr.formatted.roc @@ -0,0 +1,10 @@ +my_list = [ + 0, + [ + a, + b, + ], + 1, +] + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/list_closing_same_indent_no_trailing_comma.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/list_closing_same_indent_no_trailing_comma.expr.formatted.roc new file mode 100644 index 0000000000..feccfe0c43 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/list_closing_same_indent_no_trailing_comma.expr.formatted.roc @@ -0,0 +1,6 @@ +my_list = [ + 0, + 1, +] + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/list_closing_same_indent_with_trailing_comma.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/list_closing_same_indent_with_trailing_comma.expr.formatted.roc new file mode 100644 index 0000000000..feccfe0c43 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/list_closing_same_indent_with_trailing_comma.expr.formatted.roc @@ -0,0 +1,6 @@ +my_list = [ + 0, + 1, +] + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/list_patterns.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/list_patterns.expr.formatted.roc new file mode 100644 index 0000000000..1484b7d234 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/list_patterns.expr.formatted.roc @@ -0,0 +1,9 @@ +when [] is + [] -> {} + [..] -> {} + [_, .., _, ..] -> {} + [a, b, c, d] -> {} + [a, b, ..] -> {} + [.., c, d] -> {} + [[A], [..], [a]] -> {} + [[[], []], [[], x]] -> {} \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.formatted.roc new file mode 100644 index 0000000000..62430a7666 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/malformed_pattern_field_access.expr.formatted.roc @@ -0,0 +1,3 @@ +when x is + bar.and -> 1 + _ -> 4 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.formatted.roc new file mode 100644 index 0000000000..d7120ecf86 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/malformed_pattern_module_name.expr.formatted.roc @@ -0,0 +1,3 @@ +when x is + Foo.and -> 1 + _ -> 4 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.formatted.roc new file mode 100644 index 0000000000..a3515ef437 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/minus_twelve_minus_five.expr.formatted.roc @@ -0,0 +1 @@ +-12 - 5 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/mixed_docs.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/mixed_docs.expr.formatted.roc new file mode 100644 index 0000000000..31d9cebf6b --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/mixed_docs.expr.formatted.roc @@ -0,0 +1,7 @@ +# ## not docs! +## docs, but with a problem +## (namely that this is a mix of docs and regular comments) +# not docs +x = 5 + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.formatted.roc new file mode 100644 index 0000000000..d4c0fbdec3 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/multi_backpassing.expr.formatted.roc @@ -0,0 +1,3 @@ +x, y <- List.map2 [] [] + +x + y \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/multi_char_string.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/multi_char_string.expr.formatted.roc new file mode 100644 index 0000000000..7e9668e783 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/multi_char_string.expr.formatted.roc @@ -0,0 +1 @@ +"foo" \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/multiline_string.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/multiline_string.expr.formatted.roc new file mode 100644 index 0000000000..9cc6397716 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/multiline_string.expr.formatted.roc @@ -0,0 +1,13 @@ +a = "Hello,\n\nWorld!" +b = +""" +Hello,\n\nWorld! +""" +c = + """ + Hello, + + World! + """ + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.formatted.roc new file mode 100644 index 0000000000..32a25e94e7 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.formatted.roc @@ -0,0 +1,5 @@ +f : + # comment + {} + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/multiple_operators.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/multiple_operators.expr.formatted.roc new file mode 100644 index 0000000000..5207b489d4 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/multiple_operators.expr.formatted.roc @@ -0,0 +1 @@ +31 * 42 + 534 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/nested_if.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/nested_if.expr.formatted.roc new file mode 100644 index 0000000000..149b222a9b --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/nested_if.expr.formatted.roc @@ -0,0 +1,6 @@ +if t1 then + 1 +else if t2 then + 2 +else + 3 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.formatted.roc new file mode 100644 index 0000000000..efd7601492 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.formatted.roc @@ -0,0 +1,4 @@ +x = + 5 + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.formatted.roc new file mode 100644 index 0000000000..ab98a84e11 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/newline_after_mul.expr.formatted.roc @@ -0,0 +1,3 @@ +3 +* +4 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.formatted.roc new file mode 100644 index 0000000000..139822fd66 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/newline_after_sub.expr.formatted.roc @@ -0,0 +1,3 @@ +3 +- +4 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.formatted.roc new file mode 100644 index 0000000000..ad8aaba17b --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.formatted.roc @@ -0,0 +1,5 @@ +x = + 1 + < 2 + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.formatted.roc new file mode 100644 index 0000000000..978c1bb4e6 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/newline_singleton_list.expr.formatted.roc @@ -0,0 +1,3 @@ +[ + 1, +] \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/not_docs.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/not_docs.expr.formatted.roc new file mode 100644 index 0000000000..2e10556b31 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/not_docs.expr.formatted.roc @@ -0,0 +1,7 @@ +# ###### +# ## not docs! +# #still not docs +# ##### +x = 5 + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/number_literal_suffixes.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/number_literal_suffixes.expr.formatted.roc new file mode 100644 index 0000000000..8f3f678ccc --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/number_literal_suffixes.expr.formatted.roc @@ -0,0 +1,37 @@ +{ + u8: 123u8, + u16: 123u16, + u32: 123u32, + u64: 123u64, + u128: 123u128, + i8: 123i8, + i16: 123i16, + i32: 123i32, + i64: 123i64, + i128: 123i128, + nat: 123nat, + dec: 123dec, + u8Neg: -123u8, + u16Neg: -123u16, + u32Neg: -123u32, + u64Neg: -123u64, + u128Neg: -123u128, + i8Neg: -123i8, + i16Neg: -123i16, + i32Neg: -123i32, + i64Neg: -123i64, + i128Neg: -123i128, + natNeg: -123nat, + decNeg: -123dec, + u8Bin: 0b101u8, + u16Bin: 0b101u16, + u32Bin: 0b101u32, + u64Bin: 0b101u64, + u128Bin: 0b101u128, + i8Bin: 0b101i8, + i16Bin: 0b101i16, + i32Bin: 0b101i32, + i64Bin: 0b101i64, + i128Bin: 0b101i128, + natBin: 0b101nat, +} \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/one_backpassing.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/one_backpassing.expr.formatted.roc new file mode 100644 index 0000000000..4ec34629b4 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/one_backpassing.expr.formatted.roc @@ -0,0 +1,4 @@ +# leading comment +x <- \y -> y + +x \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/one_char_string.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/one_char_string.expr.formatted.roc new file mode 100644 index 0000000000..3403a0c7f4 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/one_char_string.expr.formatted.roc @@ -0,0 +1 @@ +"x" \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/one_def.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/one_def.expr.formatted.roc new file mode 100644 index 0000000000..577e02f273 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/one_def.expr.formatted.roc @@ -0,0 +1,4 @@ +# leading comment +x = 5 + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/one_minus_two.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/one_minus_two.expr.formatted.roc new file mode 100644 index 0000000000..7ec0a893ae --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/one_minus_two.expr.formatted.roc @@ -0,0 +1 @@ +1 - 2 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/one_plus_two.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/one_plus_two.expr.formatted.roc new file mode 100644 index 0000000000..193df0b550 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/one_plus_two.expr.formatted.roc @@ -0,0 +1 @@ +1 + 2 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.formatted.roc new file mode 100644 index 0000000000..577e02f273 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.formatted.roc @@ -0,0 +1,4 @@ +# leading comment +x = 5 + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/opaque_destructure_first_item_in_body.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/opaque_destructure_first_item_in_body.expr.formatted.roc new file mode 100644 index 0000000000..1a4eeb0397 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/opaque_destructure_first_item_in_body.expr.formatted.roc @@ -0,0 +1,3 @@ +(@Thunk it) = id (@A {}) + +it {} \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/opaque_has_abilities.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/opaque_has_abilities.expr.formatted.roc new file mode 100644 index 0000000000..783b9d8c17 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/opaque_has_abilities.expr.formatted.roc @@ -0,0 +1,24 @@ +A := U8 has [Eq, Hash] + +A := a | a has Other + has [Eq, Hash] + +A := a | a has Other + has [Eq, Hash] + +A := U8 has [Eq { eq }, Hash { hash }] + +A := U8 has [Eq { eq, eq1 }] + +A := U8 has [Eq { eq, eq1 }, Hash] + +A := U8 has [Hash, Eq { eq, eq1 }] + +A := U8 has [] + +A := a | a has Other + has [Eq { eq }, Hash { hash }] + +A := U8 has [Eq {}] + +0 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/opaque_reference_expr.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/opaque_reference_expr.expr.formatted.roc new file mode 100644 index 0000000000..320a3f5774 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/opaque_reference_expr.expr.formatted.roc @@ -0,0 +1 @@ +@Age \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/opaque_reference_expr_with_arguments.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/opaque_reference_expr_with_arguments.expr.formatted.roc new file mode 100644 index 0000000000..0aeddca9ea --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/opaque_reference_expr_with_arguments.expr.formatted.roc @@ -0,0 +1 @@ +@Age m n \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/opaque_reference_pattern.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/opaque_reference_pattern.expr.formatted.roc new file mode 100644 index 0000000000..04257122f4 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/opaque_reference_pattern.expr.formatted.roc @@ -0,0 +1,2 @@ +when n is + @Age -> 1 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/opaque_reference_pattern_with_arguments.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/opaque_reference_pattern_with_arguments.expr.formatted.roc new file mode 100644 index 0000000000..62d5615f4e --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/opaque_reference_pattern_with_arguments.expr.formatted.roc @@ -0,0 +1,2 @@ +when n is + @Add n m -> n + m \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.formatted.roc new file mode 100644 index 0000000000..fd7e5086f3 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/ops_with_newlines.expr.formatted.roc @@ -0,0 +1,4 @@ +3 ++ + +4 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/outdented_app_with_record.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/outdented_app_with_record.expr.formatted.roc new file mode 100644 index 0000000000..bfd042f3ff --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/outdented_app_with_record.expr.formatted.roc @@ -0,0 +1,8 @@ +x = foo + ( + baz { + bar: blah, + } + ) + +x \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/outdented_list.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/outdented_list.expr.formatted.roc new file mode 100644 index 0000000000..dc7455f580 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/outdented_list.expr.formatted.roc @@ -0,0 +1,7 @@ +a = [ + 1, + 2, + 3, +] + +a \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/outdented_record.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/outdented_record.expr.formatted.roc new file mode 100644 index 0000000000..4354449034 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/outdented_record.expr.formatted.roc @@ -0,0 +1,5 @@ +x = foo { + bar: blah, +} + +x \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/parenthetical_var.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/parenthetical_var.expr.formatted.roc new file mode 100644 index 0000000000..53871cf18c --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/parenthetical_var.expr.formatted.roc @@ -0,0 +1 @@ +whee \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/parse_alias.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/parse_alias.expr.formatted.roc new file mode 100644 index 0000000000..d5b68ad051 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/parse_alias.expr.formatted.roc @@ -0,0 +1,3 @@ +Blah a b : Foo.Bar.Baz x y + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.formatted.roc new file mode 100644 index 0000000000..c24a0d5326 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.formatted.roc @@ -0,0 +1,3 @@ +foo : Foo.Bar.Baz x y as Blah a b + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.formatted.roc new file mode 100644 index 0000000000..4cccf77d54 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/pattern_with_space_in_parens.expr.formatted.roc @@ -0,0 +1,2 @@ +when Delmin (Del rx) 0 is + Delmin (Del ry) _ -> Node Black 0 Bool.false ry \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/plus_if.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/plus_if.expr.formatted.roc new file mode 100644 index 0000000000..047cd4eb6a --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/plus_if.expr.formatted.roc @@ -0,0 +1 @@ +1 * if Bool.true then 1 else 1 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/plus_when.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/plus_when.expr.formatted.roc new file mode 100644 index 0000000000..01feac8a69 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/plus_when.expr.formatted.roc @@ -0,0 +1,5 @@ +1 ++ +when Foo is + Foo -> 2 + Bar -> 3 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.formatted.roc new file mode 100644 index 0000000000..4c8ea1d6f4 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.formatted.roc @@ -0,0 +1,5 @@ +# leading comment +{ x, y } = 5 +y = 6 + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/record_func_type_decl.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/record_func_type_decl.expr.formatted.roc new file mode 100644 index 0000000000..7fbcc132ad --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/record_func_type_decl.expr.formatted.roc @@ -0,0 +1,8 @@ +f : { + getLine : Effect Str, + putLine : Str -> Effect Int, + text : Str, + value : Int *, +} + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/record_type_with_function.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/record_type_with_function.expr.formatted.roc new file mode 100644 index 0000000000..0f373a1046 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/record_type_with_function.expr.formatted.roc @@ -0,0 +1,3 @@ +x : { init : {} -> Model, update : Model, Str -> Model, view : Model -> Str } + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/record_with_if.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/record_with_if.expr.formatted.roc new file mode 100644 index 0000000000..74c194cb9f --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/record_with_if.expr.formatted.roc @@ -0,0 +1 @@ +{ x: if Bool.true then 1 else 2, y: 3 } \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.formatted.roc new file mode 100644 index 0000000000..2285ac28f0 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/space_only_after_minus.expr.formatted.roc @@ -0,0 +1 @@ +x - y \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.formatted.roc new file mode 100644 index 0000000000..bace2a0be1 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/spaced_singleton_list.expr.formatted.roc @@ -0,0 +1 @@ +[1] \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/spaces_inside_empty_list.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/spaces_inside_empty_list.expr.formatted.roc new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/spaces_inside_empty_list.expr.formatted.roc @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.formatted.roc new file mode 100644 index 0000000000..7ec0a893ae --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/sub_with_spaces.expr.formatted.roc @@ -0,0 +1 @@ +1 - 2 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.formatted.roc new file mode 100644 index 0000000000..f05fe00b0a --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/ten_times_eleven.expr.formatted.roc @@ -0,0 +1 @@ +10 * 11 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/two_backpassing.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/two_backpassing.expr.formatted.roc new file mode 100644 index 0000000000..89c3bc7993 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/two_backpassing.expr.formatted.roc @@ -0,0 +1,5 @@ +# leading comment +x <- \y -> y +z <- {} + +x \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/two_branch_when.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/two_branch_when.expr.formatted.roc new file mode 100644 index 0000000000..adedea2ab1 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/two_branch_when.expr.formatted.roc @@ -0,0 +1,3 @@ +when x is + "" -> 1 + "mise" -> 2 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.formatted.roc new file mode 100644 index 0000000000..9d573d1810 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.formatted.roc @@ -0,0 +1,5 @@ +# leading comment +x = 5 +y = 6 + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/type_decl_with_underscore.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/type_decl_with_underscore.expr.formatted.roc new file mode 100644 index 0000000000..75cfbf2e56 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/type_decl_with_underscore.expr.formatted.roc @@ -0,0 +1,3 @@ +doStuff : UserId -> Task Str _ + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.formatted.roc new file mode 100644 index 0000000000..65777a7508 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/unary_negation_arg.expr.formatted.roc @@ -0,0 +1 @@ +whee 12 -foo \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.formatted.roc new file mode 100644 index 0000000000..19140cf8fe --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/unary_negation_with_parens.expr.formatted.roc @@ -0,0 +1 @@ +-(whee 12 foo) \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.formatted.roc new file mode 100644 index 0000000000..00c9ffa9c3 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/unary_not_with_parens.expr.formatted.roc @@ -0,0 +1 @@ +!(whee 12 foo) \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.formatted.roc new file mode 100644 index 0000000000..85986c6c48 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/underscore_backpassing.expr.formatted.roc @@ -0,0 +1,4 @@ +# leading comment +_ <- \y -> y + +4 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/underscore_in_assignment_pattern.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/underscore_in_assignment_pattern.expr.formatted.roc new file mode 100644 index 0000000000..8840c025bb --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/underscore_in_assignment_pattern.expr.formatted.roc @@ -0,0 +1,7 @@ +(Pair x _) = Pair 0 1 +(Pair _ y) = Pair 0 1 +(Pair _ _) = Pair 0 1 +_ = Pair 0 1 +(Pair (Pair x _) (Pair _ y)) = Pair (Pair 0 1) (Pair 2 3) + +0 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/var_minus_two.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/var_minus_two.expr.formatted.roc new file mode 100644 index 0000000000..9b0ac03e68 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/var_minus_two.expr.formatted.roc @@ -0,0 +1 @@ +x - 2 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/when_if_guard.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/when_if_guard.expr.formatted.roc new file mode 100644 index 0000000000..a58ff1f7d1 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/when_if_guard.expr.formatted.roc @@ -0,0 +1,9 @@ +when x is + _ -> + 1 + + _ -> + 2 + + Ok -> + 3 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/when_in_assignment.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/when_in_assignment.expr.formatted.roc new file mode 100644 index 0000000000..ac116b5baf --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/when_in_assignment.expr.formatted.roc @@ -0,0 +1,4 @@ +x = when n is + 0 -> 0 + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/when_in_function.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/when_in_function.expr.formatted.roc new file mode 100644 index 0000000000..da1224efc4 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/when_in_function.expr.formatted.roc @@ -0,0 +1,4 @@ +func = \x -> when n is + 0 -> 0 + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/when_in_function_python_style_indent.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/when_in_function_python_style_indent.expr.formatted.roc new file mode 100644 index 0000000000..da1224efc4 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/when_in_function_python_style_indent.expr.formatted.roc @@ -0,0 +1,4 @@ +func = \x -> when n is + 0 -> 0 + +42 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/when_in_parens.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/when_in_parens.expr.formatted.roc new file mode 100644 index 0000000000..966d1fd427 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/when_in_parens.expr.formatted.roc @@ -0,0 +1,3 @@ +when x is + Ok -> + 3 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.formatted.roc new file mode 100644 index 0000000000..37cf62bc6b --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/when_in_parens_indented.expr.formatted.roc @@ -0,0 +1,2 @@ +when x is + Ok -> 3 diff --git a/crates/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.formatted.roc new file mode 100644 index 0000000000..197ae0ba07 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/when_with_alternative_patterns.expr.formatted.roc @@ -0,0 +1,7 @@ +when x is + "blah" | "blop" -> 1 + "foo" + | "bar" + | "baz" -> 2 + + "stuff" -> 4 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.formatted.roc new file mode 100644 index 0000000000..7b5f08d093 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/when_with_function_application.expr.formatted.roc @@ -0,0 +1,6 @@ +when x is + 1 -> + Num.neg + 2 + + _ -> 4 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.formatted.roc new file mode 100644 index 0000000000..072b3279c3 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/when_with_negative_numbers.expr.formatted.roc @@ -0,0 +1,3 @@ +when x is + 1 -> 2 + -3 -> 4 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.formatted.roc new file mode 100644 index 0000000000..6481e5741a --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/when_with_numbers.expr.formatted.roc @@ -0,0 +1,3 @@ +when x is + 1 -> 2 + 3 -> 4 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/when_with_records.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/when_with_records.expr.formatted.roc new file mode 100644 index 0000000000..9a8206358f --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/when_with_records.expr.formatted.roc @@ -0,0 +1,3 @@ +when x is + { y } -> 2 + { z, w } -> 4 \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/when_with_tuple_in_record.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/when_with_tuple_in_record.expr.formatted.roc new file mode 100644 index 0000000000..76cee263ea --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/when_with_tuple_in_record.expr.formatted.roc @@ -0,0 +1,3 @@ +when { foo: (1, 2) } is + { foo: (1, x) } -> x + { foo: (_, b) } -> 3 + b \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/when_with_tuples.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/when_with_tuples.expr.formatted.roc new file mode 100644 index 0000000000..fc3be23e29 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/when_with_tuples.expr.formatted.roc @@ -0,0 +1,3 @@ +when (1, 2) is + (1, x) -> x + (_, b) -> 3 + b \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/where_clause_function.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/where_clause_function.expr.formatted.roc new file mode 100644 index 0000000000..d140927f6c --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/where_clause_function.expr.formatted.roc @@ -0,0 +1,3 @@ +f : a -> (b -> c) | a has A + +f \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/where_clause_multiple_bound_abilities.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/where_clause_multiple_bound_abilities.expr.formatted.roc new file mode 100644 index 0000000000..a636368bfb --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/where_clause_multiple_bound_abilities.expr.formatted.roc @@ -0,0 +1,7 @@ +f : a -> b | a has Hash & Eq, b has Eq & Hash & Display + +f : + a + -> b | a has Hash & Eq, b has Hash & Display & Eq + +f \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/where_clause_multiple_has.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/where_clause_multiple_has.expr.formatted.roc new file mode 100644 index 0000000000..6763a21176 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/where_clause_multiple_has.expr.formatted.roc @@ -0,0 +1,3 @@ +f : a -> (b -> c) | a has A, b has Eq, c has Ord + +f \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/where_clause_multiple_has_across_newlines.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/where_clause_multiple_has_across_newlines.expr.formatted.roc new file mode 100644 index 0000000000..085b002fb0 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/where_clause_multiple_has_across_newlines.expr.formatted.roc @@ -0,0 +1,5 @@ +f : + a + -> (b -> c) | a has Hash, b has Eq, c has Ord + +f \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/where_clause_non_function.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/where_clause_non_function.expr.formatted.roc new file mode 100644 index 0000000000..6627a19f95 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/where_clause_non_function.expr.formatted.roc @@ -0,0 +1,3 @@ +f : a | a has A + +f \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/where_clause_on_newline.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/where_clause_on_newline.expr.formatted.roc new file mode 100644 index 0000000000..2556b5409b --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/where_clause_on_newline.expr.formatted.roc @@ -0,0 +1,5 @@ +f : + a + -> U64 | a has Hash + +f \ No newline at end of file diff --git a/crates/compiler/parse/tests/test_parse.rs b/crates/compiler/parse/tests/test_parse.rs index 18d92a043c..ac2af0df52 100644 --- a/crates/compiler/parse/tests/test_parse.rs +++ b/crates/compiler/parse/tests/test_parse.rs @@ -80,6 +80,11 @@ mod test_parse { assert!(res == "pass" || res == "fail", "a pass or fail filename was neither \"pass\" nor \"fail\", but rather: {:?}", res); let res_dir = base.join(&res); for file in list(&res_dir) { + if file.ends_with(".expr.formatted.roc") { + // These are written by fmt tests for verification. Ignore them! + continue; + } + let test = if let Some(test) = file.strip_suffix(".roc") { test } else if let Some(test) = file.strip_suffix(".result-ast") { @@ -339,7 +344,7 @@ mod test_parse { ) }; - if std::env::var("ROC_PARSER_SNAPSHOT_TEST_OVERWRITE").is_ok() { + if std::env::var("ROC_SNAPSHOT_TEST_OVERWRITE").is_ok() { std::fs::write(&result_path, actual_result).unwrap(); } else { let expected_result = std::fs::read_to_string(&result_path).unwrap_or_else(|e| { @@ -347,7 +352,7 @@ mod test_parse { "Error opening test output file {}:\n\ {:?} Supposing the file is missing, consider running the tests with:\n\ - `env ROC_PARSER_SNAPSHOT_TEST_OVERWRITE=1 cargo test ...`\n\ + `env ROC_SNAPSHOT_TEST_OVERWRITE=1 cargo test ...`\n\ and committing the file that creates.", result_path.display(), e From 36f0e9d4f55eb23b1cda5f80f599fbac07953938 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Tue, 15 Nov 2022 19:50:57 -0500 Subject: [PATCH 13/32] Add test for multiline tuple with comments --- ...ine_tuple_with_comments.expr.formatted.roc | 11 ++++ ...tiline_tuple_with_comments.expr.result-ast | 61 +++++++++++++++++++ .../multiline_tuple_with_comments.expr.roc | 13 ++++ crates/compiler/parse/tests/test_parse.rs | 1 + 4 files changed, 86 insertions(+) create mode 100644 crates/compiler/parse/tests/snapshots/pass/multiline_tuple_with_comments.expr.formatted.roc create mode 100644 crates/compiler/parse/tests/snapshots/pass/multiline_tuple_with_comments.expr.result-ast create mode 100644 crates/compiler/parse/tests/snapshots/pass/multiline_tuple_with_comments.expr.roc diff --git a/crates/compiler/parse/tests/snapshots/pass/multiline_tuple_with_comments.expr.formatted.roc b/crates/compiler/parse/tests/snapshots/pass/multiline_tuple_with_comments.expr.formatted.roc new file mode 100644 index 0000000000..936c7c5bca --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/multiline_tuple_with_comments.expr.formatted.roc @@ -0,0 +1,11 @@ +( + # before 1 + 1, + # after 1 + # before 2 + 2, + # after 2 + # before 3 + 3, + # after 3 +) \ No newline at end of file diff --git a/crates/compiler/parse/tests/snapshots/pass/multiline_tuple_with_comments.expr.result-ast b/crates/compiler/parse/tests/snapshots/pass/multiline_tuple_with_comments.expr.result-ast new file mode 100644 index 0000000000..995e618da0 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/multiline_tuple_with_comments.expr.result-ast @@ -0,0 +1,61 @@ +Tuple( + [ + @20-21 SpaceBefore( + SpaceAfter( + Num( + "1", + ), + [ + Newline, + LineComment( + "after 1", + ), + ], + ), + [ + Newline, + LineComment( + "before 1", + ), + ], + ), + @59-60 SpaceBefore( + SpaceAfter( + Num( + "2", + ), + [ + Newline, + LineComment( + "after 2", + ), + ], + ), + [ + Newline, + LineComment( + "before 2", + ), + ], + ), + @98-99 SpaceBefore( + SpaceAfter( + Num( + "3", + ), + [ + Newline, + LineComment( + " after 3", + ), + ], + ), + [ + Newline, + LineComment( + "before 3", + ), + ], + ), + ], +) diff --git a/crates/compiler/parse/tests/snapshots/pass/multiline_tuple_with_comments.expr.roc b/crates/compiler/parse/tests/snapshots/pass/multiline_tuple_with_comments.expr.roc new file mode 100644 index 0000000000..84dc40b291 --- /dev/null +++ b/crates/compiler/parse/tests/snapshots/pass/multiline_tuple_with_comments.expr.roc @@ -0,0 +1,13 @@ +( + #before 1 + 1 + #after 1 + , + #before 2 + 2 + #after 2 + , + #before 3 + 3 + # after 3 +) \ No newline at end of file diff --git a/crates/compiler/parse/tests/test_parse.rs b/crates/compiler/parse/tests/test_parse.rs index ac2af0df52..82d35a635f 100644 --- a/crates/compiler/parse/tests/test_parse.rs +++ b/crates/compiler/parse/tests/test_parse.rs @@ -167,6 +167,7 @@ mod test_parse { pass/equals_with_spaces.expr, pass/equals.expr, pass/expect_fx.module, + pass/multiline_tuple_with_comments.expr, pass/expect.expr, pass/float_with_underscores.expr, pass/full_app_header_trailing_commas.header, From e9d8d13b0297a99ca6588c17e527286297aebcc0 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 15 Nov 2022 17:09:16 +0100 Subject: [PATCH 14/32] windows fixes, error improvements --- crates/cli/tests/cli_run.rs | 4 +-- crates/cli_utils/src/helpers.rs | 8 ++++++ crates/compiler/builtins/build.rs | 6 +++- crates/compiler/fmt/src/lib.rs | 14 +++++++-- crates/utils/src/lib.rs | 21 ++++++++------ examples/static-site-gen/platform/src/lib.rs | 30 ++++++++++++++++---- 6 files changed, 64 insertions(+), 19 deletions(-) diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index 28e129b85e..87404409cd 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -115,10 +115,10 @@ mod cli_run { let is_reporting_runtime = stderr.starts_with("runtime: ") && stderr.ends_with("ms\n"); if !(stderr.is_empty() || is_reporting_runtime) { - panic!("`roc` command had unexpected stderr: {}", stderr); + panic!("\n___________\nThe roc command:\n\n {}\n\nhad unexpected stderr:\n\n {}\n___________\n", compile_out.cmd_str, stderr); } - assert!(compile_out.status.success(), "bad status {:?}", compile_out); + assert!(compile_out.status.success(), "\n___________\nRoc command failed with status {:?}:\n\n {:?}\n___________\n", compile_out.status, compile_out); compile_out } diff --git a/crates/cli_utils/src/helpers.rs b/crates/cli_utils/src/helpers.rs index 093bc58491..b0a2b34326 100644 --- a/crates/cli_utils/src/helpers.rs +++ b/crates/cli_utils/src/helpers.rs @@ -19,6 +19,7 @@ use tempfile::NamedTempFile; #[derive(Debug)] pub struct Out { + pub cmd_str: String, // command with all its arguments, for easy debugging pub stdout: String, pub stderr: String, pub status: ExitStatus, @@ -187,6 +188,7 @@ where }); Out { + cmd_str: roc_cmd_str, stdout: String::from_utf8(roc_cmd_output.stdout).unwrap(), stderr: String::from_utf8(roc_cmd_output.stderr).unwrap(), status: roc_cmd_output.status, @@ -205,6 +207,8 @@ pub fn run_cmd<'a, I: IntoIterator, E: IntoIterator, E: IntoIterator>( cmd.arg(arg); } + let cmd_str = format!("{:?}", cmd); + cmd.stdin(Stdio::piped()); cmd.stdout(Stdio::piped()); cmd.stderr(Stdio::piped()); @@ -303,6 +310,7 @@ pub fn run_with_valgrind<'a, I: IntoIterator>( ( Out { + cmd_str, stdout: String::from_utf8(output.stdout).unwrap(), stderr: String::from_utf8(output.stderr).unwrap(), status: output.status, diff --git a/crates/compiler/builtins/build.rs b/crates/compiler/builtins/build.rs index e0541ba925..9b6584ccf2 100644 --- a/crates/compiler/builtins/build.rs +++ b/crates/compiler/builtins/build.rs @@ -223,7 +223,11 @@ fn run_command(mut command: Command, flaky_fail_counter: usize) { run_command(command, flaky_fail_counter + 1) } } else { - panic!("{} failed: {}", command_str, error_str); + if error_str.contains("lld-link: error: failed to write the output file: Permission denied") { + panic!("{} failed with:\n\n {}\n\nWorkaround:\n\n Re-run the cargo command that triggered this build.", command_str, error_str); + } else { + panic!("{} failed with:\n\n {}\n", command_str, error_str); + } } } }, diff --git a/crates/compiler/fmt/src/lib.rs b/crates/compiler/fmt/src/lib.rs index 29b438de4b..562e95672b 100644 --- a/crates/compiler/fmt/src/lib.rs +++ b/crates/compiler/fmt/src/lib.rs @@ -13,6 +13,12 @@ pub mod spaces; use bumpalo::{collections::String, Bump}; use roc_parse::ast::Module; +#[cfg(windows)] +const NEWLINE: &str = "\r\n"; +#[cfg(not(windows))] +const NEWLINE: &str = "\n"; + + #[derive(Debug)] pub struct Ast<'a> { pub module: Module<'a>, @@ -99,7 +105,9 @@ impl<'a> Buf<'a> { pub fn newline(&mut self) { self.spaces_to_flush = 0; - self.text.push('\n'); + + self.text.push_str(NEWLINE); + self.beginning_of_line = true; } @@ -183,14 +191,14 @@ fn fmt_text_eof(text: &mut bumpalo::collections::String<'_>) { // There's some whitespace at the end of this file, but the first // whitespace char after the last non-whitespace char isn't a newline. // So replace that whitespace char (and everything after it) with a newline. - text.replace_range(last_whitespace_index.., "\n"); + text.replace_range(last_whitespace_index.., NEWLINE); } None => { debug_assert!(last_whitespace_index == text.len()); debug_assert!(!text.ends_with(char::is_whitespace)); // This doesn't end in whitespace at all, so add a newline. - text.push('\n'); + text.push_str(NEWLINE); } } } diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index 27c76dcdcf..5d31931b26 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -107,15 +107,9 @@ pub fn get_lib_path() -> Option { let exe_relative_str_path_opt = std::env::current_exe().ok(); if let Some(exe_relative_str_path) = exe_relative_str_path_opt { - // on windows, the current exe path is prefixed with `\\?\`, the "verbatim" prefix - // such a path does not works as an argument to `zig` and other command line tools, - // and there seems to be no good way to strip it. So we resort to some string manipulation - #[cfg(windows)] - let strip_windows_prefix = exe_relative_str_path.display().to_string(); #[cfg(windows)] - let exe_relative_str_path = - std::path::Path::new(strip_windows_prefix.trim_start_matches(r"\\?\")); + let exe_relative_str_path = strip_windows_prefix(&exe_relative_str_path); let mut curr_parent_opt = exe_relative_str_path.parent(); @@ -138,7 +132,18 @@ pub fn get_lib_path() -> Option { None } -// get the Path of the root of the repository +/// On windows, the path is prefixed with `\\?\`, the "verbatim" prefix. +/// Such a path does not works as an argument to `zig` and other command line tools, +/// and there seems to be no good way to strip it. So we resort to some string manipulation. +#[cfg(windows)] +pub fn strip_windows_prefix(path_buf: &PathBuf) -> std::path::PathBuf { + + let path_str = path_buf.display().to_string(); + + std::path::Path::new(path_str.trim_start_matches(r"\\?\")).to_path_buf() +} + +/// get the Path of the root of the repository pub fn root_dir() -> PathBuf { let mut path = env::current_exe().ok().unwrap(); diff --git a/examples/static-site-gen/platform/src/lib.rs b/examples/static-site-gen/platform/src/lib.rs index 5c5d11c088..3cffd8d458 100644 --- a/examples/static-site-gen/platform/src/lib.rs +++ b/examples/static-site-gen/platform/src/lib.rs @@ -113,17 +113,24 @@ pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut } fn run(input_dirname: &str, output_dirname: &str) -> Result<(), String> { - let input_dir = PathBuf::from(input_dirname) - .canonicalize() - .map_err(|e| format!("{}: {}", input_dirname, e))?; + + + let input_dir = + strip_windows_prefix( + PathBuf::from(input_dirname) + .canonicalize() + .map_err(|e| format!("{}: {}", input_dirname, e))? + ); let output_dir = { let dir = PathBuf::from(output_dirname); if !dir.exists() { fs::create_dir(&dir).unwrap(); } - dir.canonicalize() + strip_windows_prefix( + dir.canonicalize() .map_err(|e| format!("{}: {}", output_dirname, e))? + ) }; if !input_dir.exists() { @@ -150,7 +157,7 @@ fn run(input_dirname: &str, output_dirname: &str) -> Result<(), String> { num_successes += 1; } Err(e) => { - eprintln!("{}", e); + eprintln!("Failed to process file:\n\n ({:?})with error:\n\n {}", &input_file, e); num_errors += 1; } } @@ -169,6 +176,7 @@ fn run(input_dirname: &str, output_dirname: &str) -> Result<(), String> { } fn process_file(input_dir: &Path, output_dir: &Path, input_file: &Path) -> Result<(), String> { + match input_file.extension() { Some(s) if s.eq("md".into()) => {} _ => return Err("Only .md files are supported".into()), @@ -218,3 +226,15 @@ fn find_files(dir: &Path, file_paths: &mut Vec) -> std::io::Result<()> } Ok(()) } + +/// On windows, the path is prefixed with `\\?\`, the "verbatim" prefix. +/// Such a path does not works as an argument to `zig` and other command line tools, +/// and there seems to be no good way to strip it. So we resort to some string manipulation. +pub fn strip_windows_prefix(path_buf: PathBuf) -> std::path::PathBuf { + #[cfg(not(windows))] + return path_buf; + + let path_str = path_buf.display().to_string(); + + std::path::Path::new(path_str.trim_start_matches(r"\\?\")).to_path_buf() +} From b681949461dcacf06a19a580ff9114396ec9dd02 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 15 Nov 2022 17:38:24 +0100 Subject: [PATCH 15/32] clippy+fmt --- crates/cli/tests/cli_run.rs | 7 ++++++- crates/compiler/builtins/build.rs | 10 +++++----- crates/compiler/fmt/src/lib.rs | 1 - crates/compiler/load/build.rs | 1 + crates/utils/src/lib.rs | 6 ++---- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index 87404409cd..2646908f8f 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -118,7 +118,12 @@ mod cli_run { panic!("\n___________\nThe roc command:\n\n {}\n\nhad unexpected stderr:\n\n {}\n___________\n", compile_out.cmd_str, stderr); } - assert!(compile_out.status.success(), "\n___________\nRoc command failed with status {:?}:\n\n {:?}\n___________\n", compile_out.status, compile_out); + assert!( + compile_out.status.success(), + "\n___________\nRoc command failed with status {:?}:\n\n {:?}\n___________\n", + compile_out.status, + compile_out + ); compile_out } diff --git a/crates/compiler/builtins/build.rs b/crates/compiler/builtins/build.rs index 9b6584ccf2..9f59176547 100644 --- a/crates/compiler/builtins/build.rs +++ b/crates/compiler/builtins/build.rs @@ -222,12 +222,12 @@ fn run_command(mut command: Command, flaky_fail_counter: usize) { } else { run_command(command, flaky_fail_counter + 1) } + } else if error_str + .contains("lld-link: error: failed to write the output file: Permission denied") + { + panic!("{} failed with:\n\n {}\n\nWorkaround:\n\n Re-run the cargo command that triggered this build.\n\n", command_str, error_str); } else { - if error_str.contains("lld-link: error: failed to write the output file: Permission denied") { - panic!("{} failed with:\n\n {}\n\nWorkaround:\n\n Re-run the cargo command that triggered this build.", command_str, error_str); - } else { - panic!("{} failed with:\n\n {}\n", command_str, error_str); - } + panic!("{} failed with:\n\n {}\n", command_str, error_str); } } }, diff --git a/crates/compiler/fmt/src/lib.rs b/crates/compiler/fmt/src/lib.rs index 562e95672b..e4e0ea32b8 100644 --- a/crates/compiler/fmt/src/lib.rs +++ b/crates/compiler/fmt/src/lib.rs @@ -18,7 +18,6 @@ const NEWLINE: &str = "\r\n"; #[cfg(not(windows))] const NEWLINE: &str = "\n"; - #[derive(Debug)] pub struct Ast<'a> { pub module: Module<'a>, diff --git a/crates/compiler/load/build.rs b/crates/compiler/load/build.rs index e13232efc8..5fb6b7d0ac 100644 --- a/crates/compiler/load/build.rs +++ b/crates/compiler/load/build.rs @@ -4,6 +4,7 @@ use std::path::{Path, PathBuf}; use bumpalo::Bump; use roc_module::symbol::ModuleId; +#[cfg(not(windows))] const ROC_SKIP_SUBS_CACHE: &str = "ROC_SKIP_SUBS_CACHE"; const SKIP_SUBS_CACHE: bool = { diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index 5d31931b26..869442d6e3 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -3,7 +3,7 @@ use snafu::OptionExt; use std::{ collections::HashMap, env::{self, VarError}, - path::PathBuf, + path::{Path, PathBuf}, process::Command, slice::SliceIndex, }; @@ -107,7 +107,6 @@ pub fn get_lib_path() -> Option { let exe_relative_str_path_opt = std::env::current_exe().ok(); if let Some(exe_relative_str_path) = exe_relative_str_path_opt { - #[cfg(windows)] let exe_relative_str_path = strip_windows_prefix(&exe_relative_str_path); @@ -136,8 +135,7 @@ pub fn get_lib_path() -> Option { /// Such a path does not works as an argument to `zig` and other command line tools, /// and there seems to be no good way to strip it. So we resort to some string manipulation. #[cfg(windows)] -pub fn strip_windows_prefix(path_buf: &PathBuf) -> std::path::PathBuf { - +pub fn strip_windows_prefix(path_buf: &Path) -> std::path::PathBuf { let path_str = path_buf.display().to_string(); std::path::Path::new(path_str.trim_start_matches(r"\\?\")).to_path_buf() From 0517d8959ce8096749200149cb4616dbce3607e1 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 15 Nov 2022 20:22:24 +0100 Subject: [PATCH 16/32] clippy, run subset of cli_run tests --- .github/workflows/windows.yml | 5 ++++- crates/utils/src/lib.rs | 9 ++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index e1fca24c70..9e32eee197 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -52,4 +52,7 @@ jobs: run: cargo test --locked --release --no-run -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker -p roc_cli || cargo test --locked --release --no-run -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker -p roc_cli - name: Actually run the tests. - run: cargo test --locked --release -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker -p roc_cli + run: cargo test --locked --release -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker + + - name: Run roc_cli tests that work on CI + run: cargo test --locked --release -p roc_cli cli_run::fibonacci cli_run::format_check_good cli_run::format_check_reformatting_needed cli_run::platform_switching_zig cli_run::platform_switching_main diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index 869442d6e3..a8ffb2adeb 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -3,7 +3,7 @@ use snafu::OptionExt; use std::{ collections::HashMap, env::{self, VarError}, - path::{Path, PathBuf}, + path::PathBuf, process::Command, slice::SliceIndex, }; @@ -131,14 +131,17 @@ pub fn get_lib_path() -> Option { None } +#[cfg(windows)] +use std::path::Path; + /// On windows, the path is prefixed with `\\?\`, the "verbatim" prefix. /// Such a path does not works as an argument to `zig` and other command line tools, /// and there seems to be no good way to strip it. So we resort to some string manipulation. #[cfg(windows)] -pub fn strip_windows_prefix(path_buf: &Path) -> std::path::PathBuf { +pub fn strip_windows_prefix(path_buf: &Path) -> PathBuf { let path_str = path_buf.display().to_string(); - std::path::Path::new(path_str.trim_start_matches(r"\\?\")).to_path_buf() + Path::new(path_str.trim_start_matches(r"\\?\")).to_path_buf() } /// get the Path of the root of the repository From 6938ec62fcf95c50d635e1268e46ad2064aacf99 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 15 Nov 2022 20:08:02 +0100 Subject: [PATCH 17/32] display the command string in a prettier way --- crates/cli/tests/cli_run.rs | 2 +- crates/cli_utils/src/helpers.rs | 30 +++++++++++++++++++++--------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index 3cd3360a1a..511b33d509 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -115,7 +115,7 @@ mod cli_run { let is_reporting_runtime = stderr.starts_with("runtime: ") && stderr.ends_with("ms\n"); if !(stderr.is_empty() || is_reporting_runtime) { - panic!("\n___________\nThe roc command:\n\n {}\n\nhad unexpected stderr:\n\n {}\n___________\n", compile_out.cmd_str, stderr); + panic!("\n___________\nThe roc command:\n\n {:?}\n\nhad unexpected stderr:\n\n {}\n___________\n", compile_out.cmd_str, stderr); } assert!( diff --git a/crates/cli_utils/src/helpers.rs b/crates/cli_utils/src/helpers.rs index b0a2b34326..d866228838 100644 --- a/crates/cli_utils/src/helpers.rs +++ b/crates/cli_utils/src/helpers.rs @@ -9,7 +9,7 @@ use roc_utils::root_dir; use serde::Deserialize; use serde_xml_rs::from_str; use std::env; -use std::ffi::OsStr; +use std::ffi::{OsStr, OsString}; use std::io::Read; use std::io::Write; use std::path::Path; @@ -19,7 +19,7 @@ use tempfile::NamedTempFile; #[derive(Debug)] pub struct Out { - pub cmd_str: String, // command with all its arguments, for easy debugging + pub cmd_str: OsString, // command with all its arguments, for easy debugging pub stdout: String, pub stderr: String, pub status: ExitStatus, @@ -158,7 +158,7 @@ where roc_cmd.env(k, v); } - let roc_cmd_str = format!("{:?}", roc_cmd); + let roc_cmd_str = pretty_command_string(&roc_cmd); let mut roc_cmd_child = roc_cmd .stdin(Stdio::piped()) @@ -166,7 +166,7 @@ where .stderr(Stdio::piped()) .spawn() .unwrap_or_else(|err| { - panic!("Failed to execute command\n\n {roc_cmd_str}\n\nwith error:\n\n {err}",) + panic!("Failed to execute command\n\n {roc_cmd_str:?}\n\nwith error:\n\n {err}",) }); { @@ -177,14 +177,14 @@ where .write_all(stdin_str.as_bytes()) .unwrap_or_else(|err| { panic!( - "Failed to write to stdin for command\n\n {roc_cmd_str}\n\nwith error:\n\n {err}", + "Failed to write to stdin for command\n\n {roc_cmd_str:?}\n\nwith error:\n\n {err}", ) }); } } let roc_cmd_output = roc_cmd_child.wait_with_output().unwrap_or_else(|err| { - panic!("Failed to get output for command\n\n {roc_cmd_str}\n\nwith error:\n\n {err}",) + panic!("Failed to get output for command\n\n {roc_cmd_str:?}\n\nwith error:\n\n {err}",) }); Out { @@ -207,12 +207,12 @@ pub fn run_cmd<'a, I: IntoIterator, E: IntoIterator>( cmd.arg(arg); } - let cmd_str = format!("{:?}", cmd); + let cmd_str = pretty_command_string(&cmd); cmd.stdin(Stdio::piped()); cmd.stdout(Stdio::piped()); @@ -447,3 +447,15 @@ pub fn known_bad_file(file_name: &str) -> PathBuf { path } + +fn pretty_command_string(command: &Command) -> OsString { + let mut command_string = std::ffi::OsString::new(); + command_string.push(command.get_program()); + + for arg in command.get_args() { + command_string.push(" "); + command_string.push(arg); + } + + command_string +} From 37ad8a941aabeeab40cd821a57ab2d8432bd5f9a Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 16 Nov 2022 09:48:14 +0100 Subject: [PATCH 18/32] ignore some tests on windows --- .github/workflows/windows.yml | 5 +---- crates/cli/tests/cli_run.rs | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 9e32eee197..08e2334d99 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -52,7 +52,4 @@ jobs: run: cargo test --locked --release --no-run -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker -p roc_cli || cargo test --locked --release --no-run -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker -p roc_cli - name: Actually run the tests. - run: cargo test --locked --release -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker - - - name: Run roc_cli tests that work on CI - run: cargo test --locked --release -p roc_cli cli_run::fibonacci cli_run::format_check_good cli_run::format_check_reformatting_needed cli_run::platform_switching_zig cli_run::platform_switching_main + run: cargo test --locked --release -p roc_ident -p roc_region -p roc_collections -p roc_can -p roc_types -p roc_solve -p roc_mono -p roc_gen_dev -p roc_gen_wasm -p roc_serialize -p roc_editor -p roc_linker -p roc_cli \ No newline at end of file diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index 511b33d509..581de16199 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -406,6 +406,7 @@ mod cli_run { #[test] #[serial(cli_platform)] + #[cfg_attr(windows, ignore)] fn hello_world() { test_roc_app_slim( "examples", @@ -438,6 +439,7 @@ mod cli_run { // If we don't, a race condition leads to test flakiness. #[test] + #[cfg_attr(windows, ignore)] fn platform_switching_rust() { test_roc_app_slim( "examples/platform-switching", @@ -518,6 +520,7 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] fn quicksort() { test_roc_app_slim( "crates/cli_testing_examples/algorithms", @@ -552,6 +555,7 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] fn interactive_effects() { test_roc_app( "examples/cli", @@ -567,6 +571,7 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] // tea = The Elm Architecture fn terminal_ui_tea() { test_roc_app( @@ -583,6 +588,7 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] fn false_interpreter() { test_roc_app( "examples/cli/false-interpreter", @@ -603,6 +609,7 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] fn static_site_gen() { test_roc_app( "examples/static-site-gen", @@ -619,6 +626,7 @@ mod cli_run { #[test] #[serial(cli_platform)] + #[cfg_attr(windows, ignore)] fn with_env_vars() { test_roc_app( "examples/cli", @@ -640,6 +648,7 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] fn parse_movies_csv() { test_roc_app_slim( "examples/parser", @@ -857,16 +866,19 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] fn nqueens() { test_benchmark("NQueens.roc", "nqueens", &["6"], "4\n", true) } #[test] + #[cfg_attr(windows, ignore)] fn cfold() { test_benchmark("CFold.roc", "cfold", &["3"], "11 & 11\n", true) } #[test] + #[cfg_attr(windows, ignore)] fn deriv() { test_benchmark( "Deriv.roc", @@ -878,11 +890,13 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] fn rbtree_ck() { test_benchmark("RBTreeCk.roc", "rbtree-ck", &["100"], "10\n", true) } #[test] + #[cfg_attr(windows, ignore)] fn rbtree_insert() { test_benchmark( "RBTreeInsert.roc", @@ -908,11 +922,13 @@ mod cli_run { }*/ #[test] + #[cfg_attr(windows, ignore)] fn astar() { test_benchmark("TestAStar.roc", "test-astar", &[], "True\n", false) } #[test] + #[cfg_attr(windows, ignore)] fn base64() { test_benchmark( "TestBase64.roc", @@ -924,11 +940,13 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] fn closure() { test_benchmark("Closure.roc", "closure", &[], "", false) } #[test] + #[cfg_attr(windows, ignore)] fn issue2279() { test_benchmark("Issue2279.roc", "issue2279", &[], "Hello, world!\n", true) } @@ -963,6 +981,7 @@ mod cli_run { #[test] #[serial(multi_dep_str)] + #[cfg_attr(windows, ignore)] fn run_multi_dep_str_optimized() { check_output_with_stdin( &fixture_file("multi-dep-str", "Main.roc"), @@ -995,6 +1014,7 @@ mod cli_run { #[test] #[serial(multi_dep_thunk)] + #[cfg_attr(windows, ignore)] fn run_multi_dep_thunk_optimized() { check_output_with_stdin( &fixture_file("multi-dep-thunk", "Main.roc"), From 87042bc3e1767442ed510bf3597126d232e8366c Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 16 Nov 2022 12:05:11 +0100 Subject: [PATCH 19/32] ignore more tests --- crates/cli/tests/cli_run.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index 581de16199..81cd457878 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -423,6 +423,7 @@ mod cli_run { const LINE_ENDING: &str = "\n"; #[test] + #[cfg_attr(windows, ignore)] // uses C platform fn platform_switching_main() { test_roc_app_slim( @@ -451,6 +452,7 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] fn platform_switching_zig() { test_roc_app_slim( "examples/platform-switching", @@ -493,6 +495,7 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] fn fibonacci() { test_roc_app_slim( "crates/cli_testing_examples/algorithms", @@ -998,6 +1001,7 @@ mod cli_run { #[test] #[serial(multi_dep_thunk)] + #[cfg_attr(windows, ignore)] fn run_multi_dep_thunk_unoptimized() { check_output_with_stdin( &fixture_file("multi-dep-thunk", "Main.roc"), From fba1dc2b809408bdb9ae7f8b788b1e0c1f652333 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 16 Nov 2022 13:22:26 +0100 Subject: [PATCH 20/32] ignore one more test --- crates/cli/tests/cli_run.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index 81cd457878..8f156e950d 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -968,6 +968,7 @@ mod cli_run { #[test] #[serial(multi_dep_str)] + #[cfg_attr(windows, ignore)] fn run_multi_dep_str_unoptimized() { check_output_with_stdin( &fixture_file("multi-dep-str", "Main.roc"), From 16d321d5a14766091998db2a8543fa25f144edf7 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 16 Nov 2022 16:10:51 +0100 Subject: [PATCH 21/32] improve sign unsigned commits Signed-off-by: Anton-4 <17049058+Anton-4@users.noreply.github.com> --- CONTRIBUTING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 49e194a7fd..9559bbc5ba 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,7 +64,8 @@ This command will generate the documentation in the [`generated-docs`](generated ### Forgot to sign commits? -You can find which commits need to be signed by running `git log --show-signature`. +View your commits on github, those without the "Verified" badge still need to be signed. +If any of those is a merge commit follow [these steps](https://stackoverflow.com/a/9958215/4200103). If you have only one commit, running `git commit --amend --no-edit -S` would sign the latest commit 🚀. @@ -76,7 +77,7 @@ In case you have multiple commits, you can sign them in two ways: pick hash2 commit message 2 pick hash1 commit message 1 ``` - - After every commit you want to sign, add `exec git commit --amend --no-edit -S`. + - On a new line below a commit you want to sign, add `exec git commit --amend --no-edit -S`. Do this for all your unsigned commits 2. Or run git rebase recursively: - Find the oldest commit you want to sign, using the `git log --show-signature` command. - Run the command `git rebase --exec 'git commit --amend --no-edit -n -S' -i HASH` which would sign all commits up to commit `HASH`. From a807b5c4240ff7199c1f074c2e1f1b40beb90bd0 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 16 Nov 2022 16:13:38 +0100 Subject: [PATCH 22/32] improve wording Signed-off-by: Anton-4 <17049058+Anton-4@users.noreply.github.com> --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9559bbc5ba..055d9e64fc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,8 +64,8 @@ This command will generate the documentation in the [`generated-docs`](generated ### Forgot to sign commits? -View your commits on github, those without the "Verified" badge still need to be signed. -If any of those is a merge commit follow [these steps](https://stackoverflow.com/a/9958215/4200103). +You can view your commits on github, those without the "Verified" badge still need to be signed. +If any of those is a merge commit, follow [these steps](https://stackoverflow.com/a/9958215/4200103) instead of the ones below. If you have only one commit, running `git commit --amend --no-edit -S` would sign the latest commit 🚀. From 9b8dc6a83a8e92e0022afae940d0edf890fa2174 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 16 Nov 2022 16:15:12 +0100 Subject: [PATCH 23/32] typos Signed-off-by: Anton-4 <17049058+Anton-4@users.noreply.github.com> --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 055d9e64fc..81662fe873 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,7 +64,7 @@ This command will generate the documentation in the [`generated-docs`](generated ### Forgot to sign commits? -You can view your commits on github, those without the "Verified" badge still need to be signed. +You can view your commits on github, those without the "Verified" badge still need to be signed. If any of those is a merge commit, follow [these steps](https://stackoverflow.com/a/9958215/4200103) instead of the ones below. If you have only one commit, running `git commit --amend --no-edit -S` would sign the latest commit 🚀. @@ -77,7 +77,7 @@ In case you have multiple commits, you can sign them in two ways: pick hash2 commit message 2 pick hash1 commit message 1 ``` - - On a new line below a commit you want to sign, add `exec git commit --amend --no-edit -S`. Do this for all your unsigned commits + - On a new line below a commit you want to sign, add `exec git commit --amend --no-edit -S`. Do this for all your unsigned commits. 2. Or run git rebase recursively: - Find the oldest commit you want to sign, using the `git log --show-signature` command. - Run the command `git rebase --exec 'git commit --amend --no-edit -n -S' -i HASH` which would sign all commits up to commit `HASH`. From af81ceae3851f1d3a38f1a30a08c6db39f3779d9 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Wed, 16 Nov 2022 13:54:48 -0600 Subject: [PATCH 24/32] Add method to grab default compilation width of a number --- crates/compiler/mono/src/layout.rs | 27 +++------------------------ crates/compiler/types/src/num.rs | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/crates/compiler/mono/src/layout.rs b/crates/compiler/mono/src/layout.rs index 64e13f3bd2..872914c286 100644 --- a/crates/compiler/mono/src/layout.rs +++ b/crates/compiler/mono/src/layout.rs @@ -2276,33 +2276,12 @@ impl<'a> Layout<'a> { env: &mut Env<'a, '_>, range: NumericRange, ) -> Cacheable> { - use roc_types::num::IntLitWidth; - - // If we chose the default int layout then the real var might have been `Num *`, or - // similar. In this case fix-up width if we need to. Choose I64 if the range says - // that the number will fit, otherwise choose the next-largest number layout. - // // We don't pass the range down because `RangedNumber`s are somewhat rare, they only // appear due to number literals, so no need to increase parameter list sizes. - let num_layout = match range { - NumericRange::IntAtLeastSigned(w) | NumericRange::NumAtLeastSigned(w) => { - [IntLitWidth::I64, IntLitWidth::I128] - .iter() - .find(|candidate| candidate.is_superset(&w, true)) - .expect("if number doesn't fit, should have been a type error") - } - NumericRange::IntAtLeastEitherSign(w) | NumericRange::NumAtLeastEitherSign(w) => [ - IntLitWidth::I64, - IntLitWidth::U64, - IntLitWidth::I128, - IntLitWidth::U128, - ] - .iter() - .find(|candidate| candidate.is_superset(&w, false)) - .expect("if number doesn't fit, should have been a type error"), - }; + let num_layout = range.default_compilation_width(); + cacheable(Ok(Layout::int_literal_width_to_int( - *num_layout, + num_layout, env.target_info, ))) } diff --git a/crates/compiler/types/src/num.rs b/crates/compiler/types/src/num.rs index 88ba52e37f..cd4879b31c 100644 --- a/crates/compiler/types/src/num.rs +++ b/crates/compiler/types/src/num.rs @@ -121,6 +121,29 @@ impl NumericRange { } } } + + /// Chooses the int width to compile this ranged number into. + /// I64 is chosen if the range says that the number will fit, + /// otherwise the next-largest number layout is chosen. + pub fn default_compilation_width(&self) -> IntLitWidth { + *match self { + NumericRange::IntAtLeastSigned(w) | NumericRange::NumAtLeastSigned(w) => { + [IntLitWidth::I64, IntLitWidth::I128] + .iter() + .find(|candidate| candidate.is_superset(&w, true)) + .expect("if number doesn't fit, should have been a type error") + } + NumericRange::IntAtLeastEitherSign(w) | NumericRange::NumAtLeastEitherSign(w) => [ + IntLitWidth::I64, + IntLitWidth::U64, + IntLitWidth::I128, + IntLitWidth::U128, + ] + .iter() + .find(|candidate| candidate.is_superset(&w, false)) + .expect("if number doesn't fit, should have been a type error"), + } + } } #[derive(Clone, Copy, PartialEq, Eq, Debug)] From 330504131646b9dada8373bfd5d9e8cb289910b1 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Wed, 16 Nov 2022 13:55:15 -0600 Subject: [PATCH 25/32] Add Debug derives in lambda set compaction --- crates/compiler/derive_key/src/lib.rs | 2 +- crates/compiler/solve/src/specialize.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/compiler/derive_key/src/lib.rs b/crates/compiler/derive_key/src/lib.rs index a994a622e3..c9b6e3731f 100644 --- a/crates/compiler/derive_key/src/lib.rs +++ b/crates/compiler/derive_key/src/lib.rs @@ -71,7 +71,7 @@ pub enum Derived { } /// The builtin ability member to derive. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum DeriveBuiltin { ToEncoder, Decoder, diff --git a/crates/compiler/solve/src/specialize.rs b/crates/compiler/solve/src/specialize.rs index 49b39eb0d4..53db854639 100644 --- a/crates/compiler/solve/src/specialize.rs +++ b/crates/compiler/solve/src/specialize.rs @@ -605,6 +605,7 @@ enum SpecializationTypeKey { SingleLambdaSetImmediate(Symbol), } +#[derive(Debug)] enum SpecializeDecision { Specialize(SpecializationTypeKey), Drop, From 9c8a4ec027749c2ca276160366c4ac4d618f73d0 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Wed, 16 Nov 2022 13:57:03 -0600 Subject: [PATCH 26/32] Choose hash implementation for ranged number based on default width Closes #4416 --- crates/compiler/derive_key/src/hash.rs | 90 ++++++++++++++--------- crates/compiler/solve/tests/solve_expr.rs | 16 ++++ crates/compiler/types/src/num.rs | 21 ++++++ 3 files changed, 94 insertions(+), 33 deletions(-) diff --git a/crates/compiler/derive_key/src/hash.rs b/crates/compiler/derive_key/src/hash.rs index 94842e669f..7eec881038 100644 --- a/crates/compiler/derive_key/src/hash.rs +++ b/crates/compiler/derive_key/src/hash.rs @@ -105,42 +105,29 @@ impl FlatHash { // FlatType::Func(..) => Err(Underivable), }, - Content::Alias(sym, _, real_var, _) => match sym { - Symbol::NUM_U8 | Symbol::NUM_UNSIGNED8 => { - Ok(SingleLambdaSetImmediate(Symbol::HASH_ADD_U8)) - } - Symbol::NUM_U16 | Symbol::NUM_UNSIGNED16 => { - Ok(SingleLambdaSetImmediate(Symbol::HASH_ADD_U16)) - } - Symbol::NUM_U32 | Symbol::NUM_UNSIGNED32 => { - Ok(SingleLambdaSetImmediate(Symbol::HASH_ADD_U32)) - } - Symbol::NUM_U64 | Symbol::NUM_UNSIGNED64 => { - Ok(SingleLambdaSetImmediate(Symbol::HASH_ADD_U64)) - } - Symbol::NUM_U128 | Symbol::NUM_UNSIGNED128 => { - Ok(SingleLambdaSetImmediate(Symbol::HASH_ADD_U128)) - } - Symbol::NUM_I8 | Symbol::NUM_SIGNED8 => { - Ok(SingleLambdaSetImmediate(Symbol::HASH_HASH_I8)) - } - Symbol::NUM_I16 | Symbol::NUM_SIGNED16 => { - Ok(SingleLambdaSetImmediate(Symbol::HASH_HASH_I16)) - } - Symbol::NUM_I32 | Symbol::NUM_SIGNED32 => { - Ok(SingleLambdaSetImmediate(Symbol::HASH_HASH_I32)) - } - Symbol::NUM_I64 | Symbol::NUM_SIGNED64 => { - Ok(SingleLambdaSetImmediate(Symbol::HASH_HASH_I64)) - } - Symbol::NUM_I128 | Symbol::NUM_SIGNED128 => { - Ok(SingleLambdaSetImmediate(Symbol::HASH_HASH_I128)) - } + Content::Alias(sym, _, real_var, _) => match num_symbol_to_hash_lambda(sym) { + Some(lambda) => Ok(lambda), // NB: I believe it is okay to unwrap opaques here because derivers are only used // by the backend, and the backend treats opaques like structural aliases. - _ => Self::from_var(subs, real_var), + None => Self::from_var(subs, real_var), }, - Content::RangedNumber(_) => Err(Underivable), + Content::RangedNumber(range) => { + // Find the integer we're going to compile to, that'll tell us what lambda we + // should resolve to. + // + // Note that at this point, we don't need to update the underlying type variable. + // That's because + // + // - If the type variable always had a ground constructor after solving, we would + // have already refined the ranged number during obligation checking. + // + // - If the type variable was generalized, then this branch is only reached + // during monomorphization, at which point we always choose a default layout + // for ranged numbers, without concern for reification to a ground type. + let chosen_width = range.default_compilation_width(); + let lambda = num_symbol_to_hash_lambda(chosen_width.symbol()).unwrap(); + Ok(lambda) + } // Content::RecursionVar { structure, .. } => Self::from_var(subs, structure), // @@ -153,3 +140,40 @@ impl FlatHash { } } } + +const fn num_symbol_to_hash_lambda(symbol: Symbol) -> Option { + use FlatHash::*; + match symbol { + Symbol::NUM_U8 | Symbol::NUM_UNSIGNED8 => { + Some(SingleLambdaSetImmediate(Symbol::HASH_ADD_U8)) + } + Symbol::NUM_U16 | Symbol::NUM_UNSIGNED16 => { + Some(SingleLambdaSetImmediate(Symbol::HASH_ADD_U16)) + } + Symbol::NUM_U32 | Symbol::NUM_UNSIGNED32 => { + Some(SingleLambdaSetImmediate(Symbol::HASH_ADD_U32)) + } + Symbol::NUM_U64 | Symbol::NUM_UNSIGNED64 => { + Some(SingleLambdaSetImmediate(Symbol::HASH_ADD_U64)) + } + Symbol::NUM_U128 | Symbol::NUM_UNSIGNED128 => { + Some(SingleLambdaSetImmediate(Symbol::HASH_ADD_U128)) + } + Symbol::NUM_I8 | Symbol::NUM_SIGNED8 => { + Some(SingleLambdaSetImmediate(Symbol::HASH_HASH_I8)) + } + Symbol::NUM_I16 | Symbol::NUM_SIGNED16 => { + Some(SingleLambdaSetImmediate(Symbol::HASH_HASH_I16)) + } + Symbol::NUM_I32 | Symbol::NUM_SIGNED32 => { + Some(SingleLambdaSetImmediate(Symbol::HASH_HASH_I32)) + } + Symbol::NUM_I64 | Symbol::NUM_SIGNED64 => { + Some(SingleLambdaSetImmediate(Symbol::HASH_HASH_I64)) + } + Symbol::NUM_I128 | Symbol::NUM_SIGNED128 => { + Some(SingleLambdaSetImmediate(Symbol::HASH_HASH_I128)) + } + _ => None, + } +} diff --git a/crates/compiler/solve/tests/solve_expr.rs b/crates/compiler/solve/tests/solve_expr.rs index 74e72ff688..bac6ca4b2f 100644 --- a/crates/compiler/solve/tests/solve_expr.rs +++ b/crates/compiler/solve/tests/solve_expr.rs @@ -8220,4 +8220,20 @@ mod solve_expr { "{} -> Task", ) } + + #[test] + fn choose_ranged_num_for_hash() { + infer_queries!( + indoc!( + r#" + app "test" provides [main] to "./platform" + + main = + \h -> Hash.hash h 7 + # ^^^^^^^^^ + "# + ), + @"Hash#Hash.hash(1) : a, I64 -[[Hash.hashI64(12)]]-> a | a has Hasher" + ) + } } diff --git a/crates/compiler/types/src/num.rs b/crates/compiler/types/src/num.rs index cd4879b31c..1306db905f 100644 --- a/crates/compiler/types/src/num.rs +++ b/crates/compiler/types/src/num.rs @@ -1,3 +1,5 @@ +use roc_module::symbol::Symbol; + use crate::subs::Variable; /// A bound placed on a number because of its literal value. @@ -304,6 +306,25 @@ impl IntLitWidth { } } } + + pub const fn symbol(&self) -> Symbol { + match self { + IntLitWidth::U8 => Symbol::NUM_U8, + IntLitWidth::U16 => Symbol::NUM_U16, + IntLitWidth::U32 => Symbol::NUM_U32, + IntLitWidth::U64 => Symbol::NUM_U64, + IntLitWidth::U128 => Symbol::NUM_U128, + IntLitWidth::I8 => Symbol::NUM_I8, + IntLitWidth::I16 => Symbol::NUM_I16, + IntLitWidth::I32 => Symbol::NUM_I32, + IntLitWidth::I64 => Symbol::NUM_I64, + IntLitWidth::I128 => Symbol::NUM_I128, + IntLitWidth::Nat => Symbol::NUM_NAT, + IntLitWidth::F32 => Symbol::NUM_F32, + IntLitWidth::F64 => Symbol::NUM_F64, + IntLitWidth::Dec => Symbol::NUM_DEC, + } + } } #[derive(Clone, Copy, PartialEq, Eq, Debug)] From f7e03830584940d4250e6e2e78e52f9fd02a6f6b Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Wed, 16 Nov 2022 13:59:11 -0600 Subject: [PATCH 27/32] Drop dead reference --- crates/compiler/types/src/num.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/compiler/types/src/num.rs b/crates/compiler/types/src/num.rs index 1306db905f..5a85e0a1bb 100644 --- a/crates/compiler/types/src/num.rs +++ b/crates/compiler/types/src/num.rs @@ -132,7 +132,7 @@ impl NumericRange { NumericRange::IntAtLeastSigned(w) | NumericRange::NumAtLeastSigned(w) => { [IntLitWidth::I64, IntLitWidth::I128] .iter() - .find(|candidate| candidate.is_superset(&w, true)) + .find(|candidate| candidate.is_superset(w, true)) .expect("if number doesn't fit, should have been a type error") } NumericRange::IntAtLeastEitherSign(w) | NumericRange::NumAtLeastEitherSign(w) => [ @@ -142,7 +142,7 @@ impl NumericRange { IntLitWidth::U128, ] .iter() - .find(|candidate| candidate.is_superset(&w, false)) + .find(|candidate| candidate.is_superset(w, false)) .expect("if number doesn't fit, should have been a type error"), } } From 716c4cb8e48f7c5180bb70b3cb6fb9d34fc3d140 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Wed, 16 Nov 2022 17:09:31 -0600 Subject: [PATCH 28/32] Print rigid name in debug representation --- crates/compiler/types/src/subs.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/compiler/types/src/subs.rs b/crates/compiler/types/src/subs.rs index 2d9848cc8e..1eb3e8d797 100644 --- a/crates/compiler/types/src/subs.rs +++ b/crates/compiler/types/src/subs.rs @@ -798,8 +798,10 @@ fn subs_fmt_content(this: &Content, subs: &Subs, f: &mut fmt::Formatter) -> fmt: }; write!(f, "FlexAble({}, {:?})", name, subs.get_subs_slice(*symbols)) } - Content::RigidVar(name) => write!(f, "Rigid({:?})", name), - Content::RigidAbleVar(name, symbol) => write!(f, "RigidAble({:?}, {:?})", name, symbol), + Content::RigidVar(name) => write!(f, "Rigid({})", subs[*name].as_str()), + Content::RigidAbleVar(name, symbol) => { + write!(f, "RigidAble({}, {:?})", subs[*name].as_str(), symbol) + } Content::RecursionVar { structure, opt_name, From b43078440f2c6fe6bbadfddd0eca369788fcc30a Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Wed, 16 Nov 2022 17:09:47 -0600 Subject: [PATCH 29/32] Ensure ability-bound variables are registered in their generalization pool When we attempt to bind a type argument to an ability in an alias/opaque instantiation, we create a fresh flex var to represent satisfaction of the ability, and then unify the type argument with that flex var. Previously, we did not register this fresh var in the appropriate rank pool. Usually this is not a problem; however, our generalization algorithm is such that we skip adjusting the rank of redundant variables. Redundant variables are those that are in the same unification tree, but are not the root of the unification trees. This means that if such a flex able var becomes the root of a unification tree with the type argument, and the type argument is itself generalized, we will have missed generalization of the argument. The fix is simple - make sure to register the flex able var into the appropriate rank pool. Closes #4408 --- crates/compiler/solve/src/solve.rs | 11 ++++++----- crates/compiler/solve/tests/solve_expr.rs | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/crates/compiler/solve/src/solve.rs b/crates/compiler/solve/src/solve.rs index 29d4e1455f..d7396aee24 100644 --- a/crates/compiler/solve/src/solve.rs +++ b/crates/compiler/solve/src/solve.rs @@ -2960,12 +2960,13 @@ fn type_to_variable<'a>( _ => { let abilities_slice = SubsSlice::extend_new(&mut subs.symbol_names, abilities.sorted_iter().copied()); - let flex_ability = subs.fresh(Descriptor { - content: Content::FlexAbleVar(None, abilities_slice), + + let flex_ability = register( + subs, rank, - mark: Mark::NONE, - copy: OptVariable::NONE, - }); + pools, + Content::FlexAbleVar(None, abilities_slice), + ); let category = Category::OpaqueArg; match unify( diff --git a/crates/compiler/solve/tests/solve_expr.rs b/crates/compiler/solve/tests/solve_expr.rs index 74e72ff688..02cb37e347 100644 --- a/crates/compiler/solve/tests/solve_expr.rs +++ b/crates/compiler/solve/tests/solve_expr.rs @@ -8220,4 +8220,26 @@ mod solve_expr { "{} -> Task", ) } + + #[test] + fn generalize_inferred_opaque_variable_bound_to_ability_issue_4408() { + infer_eq_without_problem( + indoc!( + r#" + app "test" provides [top] to "./platform" + + MDict u := (List u) | u has Eq + + bot : MDict k -> MDict k + bot = \@MDict data -> + when {} is + {} -> @MDict data + + top : MDict v -> MDict v + top = \x -> bot x + "# + ), + "MDict v -> MDict v | v has Eq", + ); + } } From d3f4b60246364f283a7c20647f066c796ec73d2f Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 16 Nov 2022 20:17:27 -0500 Subject: [PATCH 30/32] Favicon night mode --- www/public/favicon.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/public/favicon.svg b/www/public/favicon.svg index e0cff74b57..97dc5a21af 100644 --- a/www/public/favicon.svg +++ b/www/public/favicon.svg @@ -1,4 +1,4 @@ - + From 2f54e46909a4cb886de5cc0191c658275737eec7 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 16 Nov 2022 23:10:53 -0500 Subject: [PATCH 31/32] Add a blank line after failed inline expectations --- crates/repl_expect/src/lib.rs | 13 +++++++------ crates/reporting/src/error/expect.rs | 2 ++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/crates/repl_expect/src/lib.rs b/crates/repl_expect/src/lib.rs index f0b458aa48..65fd94a124 100644 --- a/crates/repl_expect/src/lib.rs +++ b/crates/repl_expect/src/lib.rs @@ -182,7 +182,8 @@ mod test { // changes between test runs let p = actual.bytes().position(|c| c == b'\n').unwrap(); let (_, x) = actual.split_at(p); - let x = x.trim_start(); + let x = x.trim(); + let expected = expected.trim_end(); if x != expected { println!("{}", x); @@ -856,14 +857,14 @@ mod test { First Str U8, Next (List { item: Str, rest: NonEmpty }), ] - + expect nonEmpty = a = "abcdefgh" b = @NonEmpty (First "ijkl" 67u8) c = Next [{ item: a, rest: b }] @NonEmpty c - + when nonEmpty is _ -> Bool.false "# @@ -871,7 +872,7 @@ mod test { indoc!( r#" This expectation failed: - + 8│> expect 9│> nonEmpty = 10│> a = "abcdefgh" @@ -881,9 +882,9 @@ mod test { 14│> 15│> when nonEmpty is 16│> _ -> Bool.false - + When it failed, these variables had these values: - + nonEmpty : NonEmpty nonEmpty = @NonEmpty (Next [{ item: "abcdefgh", rest: @NonEmpty (First "ijkl" 67) }]) "# diff --git a/crates/reporting/src/error/expect.rs b/crates/reporting/src/error/expect.rs index aca95f1215..5bde85c412 100644 --- a/crates/reporting/src/error/expect.rs +++ b/crates/reporting/src/error/expect.rs @@ -94,11 +94,13 @@ impl<'a> Renderer<'a> { self.alloc .text("When it failed, these variables had these values:"), self.alloc.stack(it), + self.alloc.text(""), // Blank line at the end ]) } else { self.alloc.stack([ self.alloc.text("This expectation failed:"), self.alloc.region(line_col_region), + self.alloc.text(""), // Blank line at the end ]) } } From 6c4e2c873801dc48c3e1f73c6313d83313f7e771 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 16 Nov 2022 23:11:47 -0500 Subject: [PATCH 32/32] Revise wording on unnecessary wildcard warning My concern with the previous wording is that: - Beginners will be confused by "these are always open" - Users advanced enough to understand what that actually means won't benefit from seeing it in this warning message! --- crates/reporting/src/error/canonicalize.rs | 15 +++++++++++++-- crates/reporting/tests/test_reporting.rs | 13 +++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/crates/reporting/src/error/canonicalize.rs b/crates/reporting/src/error/canonicalize.rs index 3188c21738..b5b26e4125 100644 --- a/crates/reporting/src/error/canonicalize.rs +++ b/crates/reporting/src/error/canonicalize.rs @@ -1017,9 +1017,20 @@ pub fn can_problem<'b>( } Problem::UnnecessaryOutputWildcard { region } => { doc = alloc.stack([ - alloc.reflow("I see you annotated a wildcard in a place where it's not needed:"), + alloc.concat([ + alloc.reflow("This type annotation has a wildcard type variable ("), + alloc.keyword("*"), + alloc.reflow(") that isn't needed."), + ]), alloc.region(lines.convert_region(region)), - alloc.reflow("Tag unions that are constants, or the return values of functions, are always inferred to be open by default! You can remove this annotation safely."), + alloc.concat([ + alloc.reflow("Annotations for tag unions which are constants, or which are returned from functions, work the same way with or without a "), + alloc.keyword("*"), + alloc.reflow(" at the end. (The "), + alloc.keyword("*"), + alloc.reflow(" means something different when the tag union is an argument to a function, though!)"), + ]), + alloc.reflow("You can safely remove this to make the code more concise without changing what it means."), ]); title = "UNNECESSARY WILDCARD".to_string(); severity = Severity::Warning; diff --git a/crates/reporting/tests/test_reporting.rs b/crates/reporting/tests/test_reporting.rs index ab79c82024..56d0e73105 100644 --- a/crates/reporting/tests/test_reporting.rs +++ b/crates/reporting/tests/test_reporting.rs @@ -11772,14 +11772,19 @@ All branches in an `if` must have the same type! @r###" ── UNNECESSARY WILDCARD ────────────────────────────────── /code/proj/Main.roc ─ - I see you annotated a wildcard in a place where it's not needed: + This type annotation has a wildcard type variable (`*`) that isn't + needed. 4│ f : {} -> [A, B]* ^ - Tag unions that are constants, or the return values of functions, are - always inferred to be open by default! You can remove this annotation - safely. + Annotations for tag unions which are constants, or which are returned + from functions, work the same way with or without a `*` at the end. (The + `*` means something different when the tag union is an argument to a + function, though!) + + You can safely remove this to make the code more concise without + changing what it means. "### );