mirror of
https://github.com/roc-lang/roc.git
synced 2024-11-13 09:49:11 +03:00
Merge branch 'main' of github.com:roc-lang/roc into wasm_module_crate
This commit is contained in:
commit
c16d425936
107
.github/workflows/windows.yml
vendored
107
.github/workflows/windows.yml
vendored
@ -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
|
@ -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`.
|
||||
|
@ -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"),
|
||||
|
@ -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<Item = &'a str>, E: IntoIterator<Item = (&'a
|
||||
cmd.env(env, val);
|
||||
}
|
||||
|
||||
let cmd_str = pretty_command_string(&cmd);
|
||||
|
||||
let mut child = cmd
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
@ -231,6 +235,7 @@ pub fn run_cmd<'a, I: IntoIterator<Item = &'a str>, E: IntoIterator<Item = (&'a
|
||||
.unwrap_or_else(|_| panic!("failed to execute cmd `{}` in CLI test", cmd_name));
|
||||
|
||||
Out {
|
||||
cmd_str,
|
||||
stdout: String::from_utf8(output.stdout).unwrap(),
|
||||
stderr: String::from_utf8(output.stderr).unwrap(),
|
||||
status: output.status,
|
||||
@ -274,6 +279,8 @@ pub fn run_with_valgrind<'a, I: IntoIterator<Item = &'a str>>(
|
||||
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<Item = &'a str>>(
|
||||
|
||||
(
|
||||
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
|
||||
}
|
||||
|
@ -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)?;
|
||||
|
@ -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<String> {
|
||||
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 {}",
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -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<FlatHash> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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>(
|
||||
<T as ExtractSpaces<'a>>::Item: Formattable,
|
||||
{
|
||||
let start = match braces {
|
||||
Braces::Round => '(',
|
||||
Braces::Curly => '{',
|
||||
Braces::Square => '[',
|
||||
};
|
||||
|
||||
let end = match braces {
|
||||
Braces::Round => ')',
|
||||
Braces::Curly => '}',
|
||||
Braces::Square => ']',
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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>(
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<String> {
|
||||
std::fs::read_dir(dir)
|
||||
.unwrap()
|
||||
.map(|f| f.unwrap().file_name().to_str().unwrap().to_string())
|
||||
.collect::<std::vec::Vec<_>>()
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 = {
|
||||
|
@ -2276,33 +2276,12 @@ impl<'a> Layout<'a> {
|
||||
env: &mut Env<'a, '_>,
|
||||
range: NumericRange,
|
||||
) -> Cacheable<LayoutResult<'a>> {
|
||||
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,
|
||||
)))
|
||||
}
|
||||
|
@ -0,0 +1,4 @@
|
||||
Hash has
|
||||
hash : a -> U64
|
||||
|
||||
1
|
@ -0,0 +1,5 @@
|
||||
Hash has
|
||||
hash : a -> U64
|
||||
hash2 : a -> U64
|
||||
|
||||
1
|
@ -0,0 +1,3 @@
|
||||
Hash has hash : a -> U64 | a has Hash
|
||||
|
||||
1
|
@ -0,0 +1,5 @@
|
||||
Ab1 has ab1 : a -> {} | a has Ab1
|
||||
|
||||
Ab2 has ab2 : a -> {} | a has Ab2
|
||||
|
||||
1
|
@ -0,0 +1 @@
|
||||
1 + 2
|
@ -0,0 +1,4 @@
|
||||
{ x, y } : Foo
|
||||
{ x, y } = { x: "foo", y: 3.14 }
|
||||
|
||||
x
|
@ -0,0 +1,4 @@
|
||||
UserId x : [UserId I64]
|
||||
(UserId x) = UserId 42
|
||||
|
||||
x
|
@ -0,0 +1,4 @@
|
||||
(x, y) : Foo
|
||||
(x, y) = ("foo", 3.14)
|
||||
|
||||
x
|
@ -0,0 +1 @@
|
||||
whee 12 34
|
@ -0,0 +1 @@
|
||||
-whee 12 foo
|
@ -0,0 +1 @@
|
||||
!whee 12 foo
|
@ -0,0 +1,9 @@
|
||||
## first line of docs
|
||||
## second line
|
||||
## third line
|
||||
## fourth line
|
||||
##
|
||||
## sixth line after doc new line
|
||||
x = 5
|
||||
|
||||
42
|
@ -0,0 +1,3 @@
|
||||
12
|
||||
* # test!
|
||||
92
|
@ -0,0 +1,2 @@
|
||||
3 # test!
|
||||
+ 4
|
@ -0,0 +1,2 @@
|
||||
[ # comment
|
||||
]
|
@ -0,0 +1,2 @@
|
||||
3 # 2 × 2
|
||||
+ 4
|
@ -0,0 +1,3 @@
|
||||
(Email str) = Email "blah@example.com"
|
||||
|
||||
str
|
@ -0,0 +1 @@
|
||||
""
|
@ -0,0 +1 @@
|
||||
x == y
|
@ -0,0 +1,4 @@
|
||||
expect
|
||||
1 == 1
|
||||
|
||||
4
|
@ -0,0 +1,3 @@
|
||||
iffy = 5
|
||||
|
||||
42
|
@ -0,0 +1,2 @@
|
||||
\x ->
|
||||
1
|
@ -0,0 +1,10 @@
|
||||
my_list = [
|
||||
0,
|
||||
[
|
||||
a,
|
||||
b,
|
||||
],
|
||||
1,
|
||||
]
|
||||
|
||||
42
|
@ -0,0 +1,6 @@
|
||||
my_list = [
|
||||
0,
|
||||
1,
|
||||
]
|
||||
|
||||
42
|
@ -0,0 +1,6 @@
|
||||
my_list = [
|
||||
0,
|
||||
1,
|
||||
]
|
||||
|
||||
42
|
@ -0,0 +1,9 @@
|
||||
when [] is
|
||||
[] -> {}
|
||||
[..] -> {}
|
||||
[_, .., _, ..] -> {}
|
||||
[a, b, c, d] -> {}
|
||||
[a, b, ..] -> {}
|
||||
[.., c, d] -> {}
|
||||
[[A], [..], [a]] -> {}
|
||||
[[[], []], [[], x]] -> {}
|
@ -0,0 +1,3 @@
|
||||
when x is
|
||||
bar.and -> 1
|
||||
_ -> 4
|
@ -0,0 +1,3 @@
|
||||
when x is
|
||||
Foo.and -> 1
|
||||
_ -> 4
|
@ -0,0 +1 @@
|
||||
-12 - 5
|
@ -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
|
@ -0,0 +1,3 @@
|
||||
x, y <- List.map2 [] []
|
||||
|
||||
x + y
|
@ -0,0 +1 @@
|
||||
"foo"
|
@ -0,0 +1,13 @@
|
||||
a = "Hello,\n\nWorld!"
|
||||
b =
|
||||
"""
|
||||
Hello,\n\nWorld!
|
||||
"""
|
||||
c =
|
||||
"""
|
||||
Hello,
|
||||
|
||||
World!
|
||||
"""
|
||||
|
||||
42
|
@ -0,0 +1,11 @@
|
||||
(
|
||||
# before 1
|
||||
1,
|
||||
# after 1
|
||||
# before 2
|
||||
2,
|
||||
# after 2
|
||||
# before 3
|
||||
3,
|
||||
# after 3
|
||||
)
|
@ -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",
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
@ -0,0 +1,13 @@
|
||||
(
|
||||
#before 1
|
||||
1
|
||||
#after 1
|
||||
,
|
||||
#before 2
|
||||
2
|
||||
#after 2
|
||||
,
|
||||
#before 3
|
||||
3
|
||||
# after 3
|
||||
)
|
@ -0,0 +1,5 @@
|
||||
f :
|
||||
# comment
|
||||
{}
|
||||
|
||||
42
|
@ -0,0 +1 @@
|
||||
31 * 42 + 534
|
@ -0,0 +1,6 @@
|
||||
if t1 then
|
||||
1
|
||||
else if t2 then
|
||||
2
|
||||
else
|
||||
3
|
@ -0,0 +1,4 @@
|
||||
x =
|
||||
5
|
||||
|
||||
42
|
@ -0,0 +1,3 @@
|
||||
3
|
||||
*
|
||||
4
|
@ -0,0 +1,3 @@
|
||||
3
|
||||
-
|
||||
4
|
@ -0,0 +1,5 @@
|
||||
x =
|
||||
1
|
||||
< 2
|
||||
|
||||
42
|
@ -0,0 +1,3 @@
|
||||
[
|
||||
1,
|
||||
]
|
@ -0,0 +1,7 @@
|
||||
# ######
|
||||
# ## not docs!
|
||||
# #still not docs
|
||||
# #####
|
||||
x = 5
|
||||
|
||||
42
|
@ -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,
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
# leading comment
|
||||
x <- \y -> y
|
||||
|
||||
x
|
@ -0,0 +1 @@
|
||||
"x"
|
@ -0,0 +1,4 @@
|
||||
# leading comment
|
||||
x = 5
|
||||
|
||||
42
|
@ -0,0 +1 @@
|
||||
1 - 2
|
@ -0,0 +1 @@
|
||||
1 + 2
|
@ -0,0 +1,4 @@
|
||||
# leading comment
|
||||
x = 5
|
||||
|
||||
42
|
@ -0,0 +1,3 @@
|
||||
(@Thunk it) = id (@A {})
|
||||
|
||||
it {}
|
@ -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
|
@ -0,0 +1 @@
|
||||
@Age
|
@ -0,0 +1 @@
|
||||
@Age m n
|
@ -0,0 +1,2 @@
|
||||
when n is
|
||||
@Age -> 1
|
@ -0,0 +1,2 @@
|
||||
when n is
|
||||
@Add n m -> n + m
|
@ -0,0 +1,4 @@
|
||||
3
|
||||
+
|
||||
|
||||
4
|
@ -0,0 +1,8 @@
|
||||
x = foo
|
||||
(
|
||||
baz {
|
||||
bar: blah,
|
||||
}
|
||||
)
|
||||
|
||||
x
|
@ -0,0 +1,7 @@
|
||||
a = [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
]
|
||||
|
||||
a
|
@ -0,0 +1,5 @@
|
||||
x = foo {
|
||||
bar: blah,
|
||||
}
|
||||
|
||||
x
|
@ -0,0 +1 @@
|
||||
whee
|
@ -0,0 +1,3 @@
|
||||
Blah a b : Foo.Bar.Baz x y
|
||||
|
||||
42
|
@ -0,0 +1,3 @@
|
||||
foo : Foo.Bar.Baz x y as Blah a b
|
||||
|
||||
42
|
@ -0,0 +1,2 @@
|
||||
when Delmin (Del rx) 0 is
|
||||
Delmin (Del ry) _ -> Node Black 0 Bool.false ry
|
@ -0,0 +1 @@
|
||||
1 * if Bool.true then 1 else 1
|
@ -0,0 +1,5 @@
|
||||
1
|
||||
+
|
||||
when Foo is
|
||||
Foo -> 2
|
||||
Bar -> 3
|
@ -0,0 +1,5 @@
|
||||
# leading comment
|
||||
{ x, y } = 5
|
||||
y = 6
|
||||
|
||||
42
|
@ -0,0 +1,8 @@
|
||||
f : {
|
||||
getLine : Effect Str,
|
||||
putLine : Str -> Effect Int,
|
||||
text : Str,
|
||||
value : Int *,
|
||||
}
|
||||
|
||||
42
|
@ -0,0 +1,3 @@
|
||||
x : { init : {} -> Model, update : Model, Str -> Model, view : Model -> Str }
|
||||
|
||||
42
|
@ -0,0 +1 @@
|
||||
{ x: if Bool.true then 1 else 2, y: 3 }
|
@ -0,0 +1 @@
|
||||
x - y
|
@ -0,0 +1 @@
|
||||
[1]
|
@ -0,0 +1 @@
|
||||
[]
|
@ -0,0 +1 @@
|
||||
1 - 2
|
@ -0,0 +1 @@
|
||||
10 * 11
|
@ -0,0 +1,5 @@
|
||||
# leading comment
|
||||
x <- \y -> y
|
||||
z <- {}
|
||||
|
||||
x
|
@ -0,0 +1,3 @@
|
||||
when x is
|
||||
"" -> 1
|
||||
"mise" -> 2
|
@ -0,0 +1,5 @@
|
||||
# leading comment
|
||||
x = 5
|
||||
y = 6
|
||||
|
||||
42
|
@ -0,0 +1,3 @@
|
||||
doStuff : UserId -> Task Str _
|
||||
|
||||
42
|
@ -0,0 +1 @@
|
||||
whee 12 -foo
|
@ -0,0 +1 @@
|
||||
-(whee 12 foo)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user