diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 83a95ca0a9..08e2334d99 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 || 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 - - - 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 +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 \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 49e194a7fd..81662fe873 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`. +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 🚀. @@ -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`. diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index 9dbea0188a..8f156e950d 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -115,14 +115,14 @@ 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 stderr:\n{}\nstdout:\n{}", - compile_out.stderr, - compile_out.stdout + "\n___________\nRoc command failed with status {:?}:\n\n {:?}\n___________\n", + compile_out.status, + compile_out ); compile_out @@ -252,10 +252,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 @@ -409,6 +406,7 @@ mod cli_run { #[test] #[serial(cli_platform)] + #[cfg_attr(windows, ignore)] fn hello_world() { test_roc_app_slim( "examples", @@ -425,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( @@ -441,6 +440,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", @@ -452,6 +452,7 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] fn platform_switching_zig() { test_roc_app_slim( "examples/platform-switching", @@ -485,11 +486,16 @@ 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) } #[test] + #[cfg_attr(windows, ignore)] fn fibonacci() { test_roc_app_slim( "crates/cli_testing_examples/algorithms", @@ -517,6 +523,7 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] fn quicksort() { test_roc_app_slim( "crates/cli_testing_examples/algorithms", @@ -551,6 +558,7 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] fn interactive_effects() { test_roc_app( "examples/cli", @@ -566,6 +574,7 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] // tea = The Elm Architecture fn terminal_ui_tea() { test_roc_app( @@ -582,6 +591,7 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] fn false_interpreter() { test_roc_app( "examples/cli/false-interpreter", @@ -590,7 +600,7 @@ mod cli_run { &[], &[Arg::ExamplePath("examples/hello.false")], &[], - "Hello, World!\n", + &("Hello, World!".to_string() + LINE_ENDING), false, true, ) @@ -602,6 +612,7 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] fn static_site_gen() { test_roc_app( "examples/static-site-gen", @@ -618,6 +629,7 @@ mod cli_run { #[test] #[serial(cli_platform)] + #[cfg_attr(windows, ignore)] fn with_env_vars() { test_roc_app( "examples/cli", @@ -639,6 +651,7 @@ mod cli_run { } #[test] + #[cfg_attr(windows, ignore)] fn parse_movies_csv() { test_roc_app_slim( "examples/parser", @@ -856,16 +869,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", @@ -877,11 +893,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", @@ -907,11 +925,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", @@ -923,11 +943,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) } @@ -946,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"), @@ -962,6 +985,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"), @@ -978,6 +1002,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"), @@ -994,6 +1019,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"), diff --git a/crates/cli_utils/src/helpers.rs b/crates/cli_utils/src/helpers.rs index 093bc58491..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,6 +19,7 @@ use tempfile::NamedTempFile; #[derive(Debug)] pub struct Out { + pub cmd_str: OsString, // command with all its arguments, for easy debugging pub stdout: String, pub stderr: String, pub status: ExitStatus, @@ -157,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()) @@ -165,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}",) }); { @@ -176,17 +177,18 @@ 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 { + 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, @@ -209,6 +211,8 @@ pub fn run_cmd<'a, I: IntoIterator, E: IntoIterator, E: IntoIterator>( cmd.arg(arg); } + let cmd_str = pretty_command_string(&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, @@ -439,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 +} 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/build/src/link.rs b/crates/compiler/build/src/link.rs index ca83ce3a15..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", @@ -1370,7 +1377,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; @@ -1378,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/crates/compiler/builtins/build.rs b/crates/compiler/builtins/build.rs index e0541ba925..9f59176547 100644 --- a/crates/compiler/builtins/build.rs +++ b/crates/compiler/builtins/build.rs @@ -222,8 +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 { - panic!("{} failed: {}", command_str, error_str); + panic!("{} failed with:\n\n {}\n", command_str, error_str); } } }, 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/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/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..690aff9a60 100644 --- a/crates/compiler/fmt/src/lib.rs +++ b/crates/compiler/fmt/src/lib.rs @@ -13,6 +13,11 @@ 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 +104,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; } @@ -109,7 +116,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() } } @@ -183,14 +190,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/compiler/fmt/tests/test_fmt.rs b/crates/compiler/fmt/tests/test_fmt.rs index 4bc00be14c..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; @@ -16,11 +18,14 @@ 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, check_formatting: impl Fn(&str), check_stability: bool) { let arena = Bump::new(); let input = input.trim(); - let expected = expected.trim(); match roc_parse::test_helpers::parse_expr_with(&arena, input) { Ok(actual) => { @@ -32,12 +37,15 @@ mod test_fmt { let output = buf.as_str(); - 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!( - "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 +68,34 @@ 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 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, check_formatting(expected), true); + } + fn expr_formats_same(input: &str) { - expr_formats_to(input, input); + expr_formats(input, check_formatting(input), true); } fn fmt_module_and_defs<'a>( @@ -5825,4 +5846,78 @@ 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::>() + } + + 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 let Some(prefix) = file.strip_suffix(".expr.roc") { + println!("formatting {}", file); + 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, + // so we'll have to pre-pend that for this test. + } + } + } } 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); diff --git a/crates/compiler/load/build.rs b/crates/compiler/load/build.rs index 4d69184bc7..7b2a2cf129 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/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/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_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/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..82d35a635f 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") { @@ -162,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, @@ -339,7 +345,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 +353,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 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/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, diff --git a/crates/compiler/solve/tests/solve_expr.rs b/crates/compiler/solve/tests/solve_expr.rs index 3ca24cbe93..8981ed3adc 100644 --- a/crates/compiler/solve/tests/solve_expr.rs +++ b/crates/compiler/solve/tests/solve_expr.rs @@ -8197,4 +8197,65 @@ 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", + ) + } + + #[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" + ) + } + + #[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", + ); + } } diff --git a/crates/compiler/types/src/num.rs b/crates/compiler/types/src/num.rs index 88ba52e37f..5a85e0a1bb 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. @@ -121,6 +123,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)] @@ -281,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)] diff --git a/crates/compiler/types/src/subs.rs b/crates/compiler/types/src/subs.rs index 50784290ec..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, @@ -1951,7 +1953,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 +3201,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 +3227,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,51 +3238,45 @@ 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, _, _) => { - 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]; - short_circuit_help(subs, root_var, &new_seen, var)?; + 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, seen, *real_var); + } } Ok(()) @@ -3272,16 +3287,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 } } @@ -3289,7 +3303,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() { @@ -3306,7 +3320,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 @@ -3323,7 +3337,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) { 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/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/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/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 ]) } } diff --git a/crates/reporting/src/report.rs b/crates/reporting/src/report.rs index 50ca390a12..80ddfc7c33 100644 --- a/crates/reporting/src/report.rs +++ b/crates/reporting/src/report.rs @@ -275,7 +275,7 @@ pub const ANSI_STYLE_CODES: StyleCodes = StyleCodes { macro_rules! html_color { ($name: expr) => { - concat!("") + concat!("") }; } @@ -287,8 +287,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/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. "### ); diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index 27c76dcdcf..a8ffb2adeb 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -107,15 +107,8 @@ 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 +131,20 @@ pub fn get_lib_path() -> Option { None } -// get the Path of the root of the repository +#[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) -> PathBuf { + let path_str = path_buf.display().to_string(); + + 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/platform-switching/c-platform/host.c b/examples/platform-switching/c-platform/host.c index 9583f0e4c0..0dd679cdf1 100644 --- a/examples/platform-switching/c-platform/host.c +++ b/examples/platform-switching/c-platform/host.c @@ -7,9 +7,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); } 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() +} 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" +] diff --git a/www/build.sh b/www/build.sh index 73aeafe104..38ab96db1f 100755 --- a/www/build.sh +++ b/www/build.sh @@ -56,7 +56,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 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 @@ - + 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