Merge branch 'main' of github.com:roc-lang/roc into fix_benchmarks

This commit is contained in:
Anton-4 2024-01-13 19:47:20 +01:00
commit 6a6345eb01
No known key found for this signature in database
GPG key ID: 0971D718C0A9B937
130 changed files with 7235 additions and 9783 deletions

View file

@ -53,6 +53,10 @@ jobs:
latestTag=$(git describe --tags $(git rev-list --tags --max-count=1)) latestTag=$(git describe --tags $(git rev-list --tags --max-count=1))
git checkout $latestTag git checkout $latestTag
# temp issue with new string interpolation syntax
# TODO undo when 0.7.2 or 0.8.0 is released
- run: sed -i 's/\$//g' basic-cli/examples/tcp-client.roc
- name: Run all tests with latest roc nightly and latest basic-cli release - name: Run all tests with latest roc nightly and latest basic-cli release
run: | run: |
sed -i 's/x86_64/arm64/g' ./ci/test_latest_release.sh sed -i 's/x86_64/arm64/g' ./ci/test_latest_release.sh

30
.gitignore vendored
View file

@ -1,3 +1,27 @@
### Do not modify these first three ignore rules. Needed to ignore files with no extension ###
# Ignore all files including binary files that have no extension
*
# Unignore all files with extensions
!*.*
# Unignore all directories
!*/
# Specifically keep these files with no extension
!Earthfile
!AUTHORS
!LICENSE*
!LEGAL*
!Dockerfile
# .reuse/dep5 see https://reuse.software/
!dep5
# NotARocFile is used for formatter test
!NotARocFile
# also includes keeping one exe benchmark file
!dynhost_benchmarks*
### Add specific file extensions and directories below ###
# Ignore the following directories and file extensions
target target
generated-docs generated-docs
zig-cache zig-cache
@ -63,10 +87,12 @@ result
# Only keep Cargo.lock dependencies for the main compiler. # Only keep Cargo.lock dependencies for the main compiler.
# Examples and test only crates should be fine to be unlocked. # Examples and test only crates should be fine to be unlocked.
# This remove unneccessary lock file versioning. # This remove unnecessary lock file versioning.
# It also ensures the compiler can always pull in 1 version of things and doesn't get restricted by sub lockfiles. # It also ensures the compiler can always pull in 1 version of things and doesn't get restricted by sub lockfiles.
/**/Cargo.lock /**/Cargo.lock
!/Cargo.lock !/Cargo.lock
!/examples/static-site-gen/platform/Cargo.lock
# static-site-gen exception is because of https://github.com/tkaitchuck/aHash/issues/195
# snapshot tests temp file # snapshot tests temp file
*.pending-snap *.pending-snap
@ -82,3 +108,5 @@ www/dist
www/content/examples www/content/examples
www/examples-main.zip www/examples-main.zip
www/examples-main www/examples-main
examples/static-site-gen/**/*.html

136
Cargo.lock generated
View file

@ -19,13 +19,14 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]] [[package]]
name = "ahash" name = "ahash"
version = "0.8.3" version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"once_cell", "once_cell",
"version_check", "version_check",
"zerocopy",
] ]
[[package]] [[package]]
@ -61,6 +62,12 @@ dependencies = [
"alloc-no-stdlib", "alloc-no-stdlib",
] ]
[[package]]
name = "allocator-api2"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]] [[package]]
name = "android-tzdata" name = "android-tzdata"
version = "0.1.1" version = "0.1.1"
@ -124,13 +131,6 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "arena-pool"
version = "0.0.1"
dependencies = [
"roc_error_macros",
]
[[package]] [[package]]
name = "arrayref" name = "arrayref"
version = "0.3.7" version = "0.3.7"
@ -209,7 +209,7 @@ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"miniz_oxide", "miniz_oxide",
"object 0.32.1", "object",
"rustc-demangle", "rustc-demangle",
] ]
@ -707,7 +707,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"hashbrown 0.14.1", "hashbrown 0.14.3",
"lock_api", "lock_api",
"once_cell", "once_cell",
"parking_lot_core", "parking_lot_core",
@ -722,6 +722,17 @@ dependencies = [
"powerfmt", "powerfmt",
] ]
[[package]]
name = "derive_more"
version = "0.99.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]] [[package]]
name = "diff" name = "diff"
version = "0.1.13" version = "0.1.13"
@ -827,6 +838,12 @@ dependencies = [
"regex", "regex",
] ]
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.5" version = "0.3.5"
@ -1041,7 +1058,7 @@ dependencies = [
"futures-sink", "futures-sink",
"futures-util", "futures-util",
"http", "http",
"indexmap", "indexmap 1.9.3",
"slab", "slab",
"tokio", "tokio",
"tokio-util", "tokio-util",
@ -1062,20 +1079,14 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.13.2" version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
dependencies = [ dependencies = [
"ahash", "ahash",
"bumpalo", "allocator-api2",
] ]
[[package]]
name = "hashbrown"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.4.1" version = "0.4.1"
@ -1258,6 +1269,16 @@ dependencies = [
"hashbrown 0.12.3", "hashbrown 0.12.3",
] ]
[[package]]
name = "indexmap"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
dependencies = [
"equivalent",
"hashbrown 0.14.3",
]
[[package]] [[package]]
name = "indoc" name = "indoc"
version = "1.0.9" version = "1.0.9"
@ -1636,24 +1657,16 @@ dependencies = [
[[package]] [[package]]
name = "object" name = "object"
version = "0.30.4" version = "0.32.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"flate2", "flate2",
"hashbrown 0.13.2", "hashbrown 0.14.3",
"indexmap", "indexmap 2.1.0",
"memchr",
]
[[package]]
name = "object"
version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
dependencies = [
"memchr", "memchr",
"ruzstd",
] ]
[[package]] [[package]]
@ -2152,9 +2165,9 @@ dependencies = [
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.11.22" version = "0.11.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41"
dependencies = [ dependencies = [
"base64 0.21.4", "base64 0.21.4",
"bytes", "bytes",
@ -2396,7 +2409,7 @@ dependencies = [
"bitvec", "bitvec",
"bumpalo", "bumpalo",
"fnv", "fnv",
"hashbrown 0.13.2", "hashbrown 0.14.3",
"im", "im",
"im-rc", "im-rc",
"smallvec", "smallvec",
@ -2526,7 +2539,7 @@ version = "0.0.1"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"capstone", "capstone",
"object 0.30.4", "object",
"packed_struct", "packed_struct",
"roc_builtins", "roc_builtins",
"roc_can", "roc_can",
@ -2591,7 +2604,7 @@ dependencies = [
"cli_utils", "cli_utils",
"dircpy", "dircpy",
"fnv", "fnv",
"indexmap", "indexmap 2.1.0",
"indoc", "indoc",
"libc", "libc",
"libloading", "libloading",
@ -2682,7 +2695,7 @@ dependencies = [
"libc", "libc",
"mach_object", "mach_object",
"memmap2", "memmap2",
"object 0.30.4", "object",
"roc_collections", "roc_collections",
"roc_error_macros", "roc_error_macros",
"roc_load", "roc_load",
@ -2785,7 +2798,7 @@ dependencies = [
"arrayvec 0.7.4", "arrayvec 0.7.4",
"bitvec", "bitvec",
"bumpalo", "bumpalo",
"hashbrown 0.13.2", "hashbrown 0.14.3",
"parking_lot", "parking_lot",
"roc_builtins", "roc_builtins",
"roc_can", "roc_can",
@ -3282,6 +3295,17 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "ruzstd"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d"
dependencies = [
"byteorder",
"derive_more",
"twox-hash",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.15" version = "1.0.15"
@ -4135,6 +4159,16 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
name = "twox-hash"
version = "1.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
dependencies = [
"cfg-if",
"static_assertions",
]
[[package]] [[package]]
name = "typed-arena" name = "typed-arena"
version = "2.0.2" version = "2.0.2"
@ -4683,3 +4717,23 @@ name = "yansi"
version = "0.5.1" version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
[[package]]
name = "zerocopy"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
]

View file

@ -101,11 +101,11 @@ fnv = "1.0.7"
fs_extra = "1.3.0" fs_extra = "1.3.0"
futures = "0.3.26" futures = "0.3.26"
glyph_brush = "0.7.7" glyph_brush = "0.7.7"
hashbrown = { version = "0.13.2", features = ["bumpalo"] } hashbrown = { version = "0.14.3" }
iced-x86 = { version = "1.18.0", default-features = false, features = ["std", "decoder", "op_code_info", "instr_info"] } iced-x86 = { version = "1.18.0", default-features = false, features = ["std", "decoder", "op_code_info", "instr_info"] }
im = "15.1.0" im = "15.1.0"
im-rc = "15.1.0" im-rc = "15.1.0"
indexmap = "1.9.2" indexmap = "2.1.0"
indoc = "1.0.9" indoc = "1.0.9"
insta = "1.28.0" insta = "1.28.0"
js-sys = "0.3.61" js-sys = "0.3.61"
@ -120,7 +120,7 @@ maplit = "1.0.2"
memmap2 = "0.5.10" memmap2 = "0.5.10"
mimalloc = { version = "0.1.34", default-features = false } mimalloc = { version = "0.1.34", default-features = false }
nonempty = "0.8.1" nonempty = "0.8.1"
object = { version = "0.30.3", features = ["read", "write"] } object = { version = "0.32.2", features = ["read", "write"] }
packed_struct = "0.10.1" packed_struct = "0.10.1"
page_size = "0.5.0" page_size = "0.5.0"
palette = "0.6.1" palette = "0.6.1"
@ -139,7 +139,7 @@ quote = "1.0.23"
rand = "0.8.5" rand = "0.8.5"
regex = "1.7.1" regex = "1.7.1"
remove_dir_all = "0.8.1" remove_dir_all = "0.8.1"
reqwest = { version = "0.11.20", default-features = false, features = ["blocking", "rustls-tls"] } # default-features=false removes libopenssl as a dependency on Linux, which might not be available! reqwest = { version = "0.11.23", default-features = false, features = ["blocking", "rustls-tls"] } # default-features=false removes libopenssl as a dependency on Linux, which might not be available!
rlimit = "0.9.1" rlimit = "0.9.1"
rustyline = { git = "https://github.com/roc-lang/rustyline", rev = "e74333c" } rustyline = { git = "https://github.com/roc-lang/rustyline", rev = "e74333c" }
rustyline-derive = { git = "https://github.com/roc-lang/rustyline", rev = "e74333c" } rustyline-derive = { git = "https://github.com/roc-lang/rustyline", rev = "e74333c" }

View file

@ -465,7 +465,6 @@ pub fn test(matches: &ArgMatches, triple: Triple) -> io::Result<i32> {
let arena = &arena; let arena = &arena;
let target = &triple; let target = &triple;
let opt_level = opt_level;
let target_info = TargetInfo::from(target); let target_info = TargetInfo::from(target);
// TODO may need to determine this dynamically based on dev builds. // TODO may need to determine this dynamically based on dev builds.
let function_kind = FunctionKind::LambdaSet; let function_kind = FunctionKind::LambdaSet;

View file

@ -145,7 +145,7 @@ fn main() -> io::Result<()> {
let triple = target.to_triple(); let triple = target.to_triple();
let function_kind = FunctionKind::LambdaSet; let function_kind = FunctionKind::LambdaSet;
let (platform_path, stub_lib, stub_dll_symbols) = roc_linker::generate_stub_lib( let (platform_path, stub_lib, stub_dll_symbols) = roc_linker::generate_stub_lib(
&input_path, input_path,
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()), RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
&triple, &triple,
function_kind, function_kind,

View file

@ -1,11 +0,0 @@
app
*.o
*.dSYM
dynhost
libapp.so
metadata
preprocessedhost
packages-test
multi-dep-str/multi-dep-str
multi-dep-thunk/multi-dep-thunk

View file

@ -1 +0,0 @@
Main

View file

@ -1 +0,0 @@
Main

View file

@ -1,17 +0,0 @@
*.dSYM
libhost.a
libapp.so
dynhost
preprocessedhost
metadata
expects/expects
benchmarks/rbtree-ck
benchmarks/rbtree-insert
benchmarks/test-astar
benchmarks/test-base64
benchmarks/NQueens
benchmarks/cFold
benchmarks/nQueens
benchmarks/quicksortApp
benchmarks/rBTreeCk

View file

@ -1,2 +0,0 @@
fibonacci
quicksort

View file

@ -1,12 +0,0 @@
cfold
closure
deriv
issue2279
nqueens
quicksortapp
RBTreeCk
RBTreeDel
RBTreeInsert
TestAStar
TestBase64
*.wasm

View file

@ -1,12 +0,0 @@
[package]
name = "arena-pool"
description = "An implementation of an arena allocator designed for the compiler's workloads."
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
version.workspace = true
[dependencies]
roc_error_macros = { path = "../../error_macros" }

View file

@ -1,2 +0,0 @@
//! An implementation of an [arena allocator](https://mgravell.github.io/Pipelines.Sockets.Unofficial/docs/arenas.html) designed for the compiler's workloads.
pub mod pool;

View file

@ -1,397 +0,0 @@
use roc_error_macros::internal_error;
use std::marker::PhantomPinned;
use std::ptr::{copy_nonoverlapping, NonNull};
pub struct ArenaRef<T> {
ptr: NonNull<T>,
_pin: PhantomPinned,
}
impl<T> ArenaRef<T> {
pub fn get<'a, A: AsArena<T>>(&'a self, arena: &A) -> &'a T {
arena.verify_ownership(self.ptr);
// SAFETY: we know this pointer is safe to follow because it will only
// get deallocated once the pool where it was created gets deallocated
// (along with all of the Arenas it detached), and we just verified that
// this ArenaRef's ID matches a pool which has not yet been deallocated.
unsafe { self.ptr.as_ref() }
}
pub fn get_mut<'a, A: AsArena<T>>(&'a mut self, arena: &A) -> &'a mut T {
arena.verify_ownership(self.ptr);
// SAFETY: we know this pointer is safe to follow because it will only
// get deallocated once the pool where it was created gets deallocated
// (along with all of the Arenas it detached), and we just verified that
// this ArenaRef's ID matches a pool which has not yet been deallocated.
unsafe { self.ptr.as_mut() }
}
}
/// Like a Vec, except the capacity you give it initially is its maximum
/// capacity forever. If you ever exceed it, it'll panic!
pub struct ArenaVec<T> {
buffer_ptr: NonNull<T>,
len: usize,
capacity: usize,
_pin: PhantomPinned,
}
impl<T> ArenaVec<T> {
pub fn new_in(arena: &mut Arena<T>) -> Self {
// We can't start with a NonNull::dangling pointer because when we go
// to push elements into this, they'll try to verify the dangling
// pointer resides in the arena it was given, which will likely panic.
//
// Instead, we'll take a pointer inside the array but never use it
// other than for verification, because our capacity is 0.
Self::with_capacity_in(0, arena)
}
pub fn with_capacity_in(capacity: usize, arena: &mut Arena<T>) -> Self {
let ptr = arena.alloc_vec(capacity);
Self {
buffer_ptr: unsafe { NonNull::new_unchecked(ptr) },
capacity,
len: 0,
_pin: PhantomPinned,
}
}
pub fn push(&mut self, val: T, arena: &mut Arena<T>) {
// Verify that this is the arena where we originally got our buffer,
// and is therefore safe to read and to write to. (If we have sufficient
// capacity, we'll write to it, and otherwise we'll read from it when
// copying our buffer over to the new reserved block.)
arena.verify_ownership(self.buffer_ptr);
if self.len <= self.capacity {
// We're all set!
//
// This empty branch is just here for branch prediction,
// since this should be the most common case in practice.
} else {
// Double our capacity and reserve a new block.
self.capacity *= 2;
let ptr = arena.alloc_vec(self.capacity);
// SAFETY: the existing buffer must have at least self.len elements,
// as must the new one, so copying that many between them is safe.
unsafe {
// Copy all elements from the current buffer into the new one
copy_nonoverlapping(self.buffer_ptr.as_ptr(), ptr, self.len);
}
self.buffer_ptr = unsafe { NonNull::new_unchecked(ptr) };
}
// Store the element in the appropriate memory address.
let elem_ptr = unsafe { &mut *self.buffer_ptr.as_ptr().add(self.len) };
*elem_ptr = val;
self.len += 1;
}
pub fn get<'a>(&'a self, index: usize, arena: &Arena<T>) -> Option<&'a T> {
arena.verify_ownership(self.buffer_ptr);
if index < self.len {
// SAFETY: we know this pointer is safe to follow because we've
// done a bounds check, and because we know it will only get
// deallocated once the pool where it was created gets deallocated
// (along with all of the Arenas it detached), and we just verified that
// this ArenaRef's ID matches a pool which has not yet been deallocated.
Some(unsafe { &*self.buffer_ptr.as_ptr().add(index) })
} else {
None
}
}
pub fn get_mut<'a>(&'a mut self, index: usize, arena: &Arena<T>) -> Option<&'a mut T> {
arena.verify_ownership(self.buffer_ptr);
if index < self.len {
// SAFETY: we know this pointer is safe to follow because we've
// done a bounds check, and because we know it will only get
// deallocated once the pool where it was created gets deallocated
// (along with all of the Arenas it detached), and we just verified that
// this ArenaRef's ID matches a pool which has not yet been deallocated.
Some(unsafe { &mut *self.buffer_ptr.as_ptr().add(index) })
} else {
None
}
}
}
#[derive(PartialEq, Eq)]
pub struct ArenaPool<T> {
first_chunk: Vec<T>,
extra_chunks: Vec<Vec<T>>,
num_leased: usize,
default_chunk_capacity: usize,
}
impl<T> ArenaPool<T> {
const DEFAULT_CHUNK_SIZE: usize = 1024;
/// Be careful! Both of these arguments are of type usize.
///
/// The first is the number of elements that will be in each arena.
/// The second is the number of arenas.
///
/// This returns a new Pool, and also an iterator of Arenas. These Arenas can
/// be given to different threads, where they can be used to allocate
/// ArenaRef and ArenaVec values which can then be dereferenced by the Arena
/// that created them, or by this pool once those Arenas have been
/// reabsorbed back into it.
///
/// (A word of warning: if you try to use this pool to dereference ArenaRec
/// and ArenaVec values which were allocated by arenas that have *not* yet
/// been reabsorbed, it may work some of the time and panic other times,
/// depending on whether the arena needed to allocate extra chunks beyond
/// its initial chunk. tl;dr - doing that may panic, so don't try it!)
///
/// Before this pool gets dropped, you must call reabsorb() on every
/// arena that has been leased - otherwise, you'll get a panic when this
/// gets dropped! The memory safety of the system depends on all arenas
/// having been reabsorbed before the pool gets deallocated, which is why
/// the pool's Drop implementation enforces it.
pub fn new(num_arenas: usize, elems_per_arena: usize) -> (ArenaPool<T>, ArenaIter<T>) {
Self::with_chunk_size(num_arenas, elems_per_arena, Self::DEFAULT_CHUNK_SIZE)
}
/// Like `new`, except you can also specify the chunk size that each
/// arena will use to allocate its extra chunks if it runs out of space
/// in its main buffer.
///
/// Things will run fastest if that main buffer never runs out, though!
pub fn with_chunk_size(
num_arenas: usize,
elems_per_arena: usize,
chunk_size: usize,
) -> (ArenaPool<T>, ArenaIter<T>) {
let mut first_chunk = Vec::with_capacity(elems_per_arena * num_arenas);
let iter = ArenaIter {
ptr: first_chunk.as_mut_ptr(),
quantity_remaining: num_arenas,
first_chunk_capacity: elems_per_arena,
};
let pool = Self {
first_chunk,
extra_chunks: Vec::new(),
num_leased: num_arenas,
default_chunk_capacity: chunk_size,
};
(pool, iter)
}
/// Return an arena to the pool. (This would have been called "return" but
/// that's a reserved keyword.)
pub fn reabsorb(&mut self, arena: Arena<T>) {
// Ensure we're reabsorbing an arena that was
// actually leased by this pool in the first place!
verify_ownership(
self.first_chunk.as_ptr(),
self.first_chunk.capacity(),
&self.extra_chunks,
arena.first_chunk_ptr,
);
// Add the arena's extra chunks to our own, so their memory remains live
// after the arena gets dropped. This is important, because at this
// point their pointers can still potentially be dereferenced!
self.extra_chunks.extend(arena.extra_chunks);
self.num_leased -= 1;
}
}
impl<T> Drop for ArenaPool<T> {
fn drop(&mut self) {
// When an ArenaPool gets dropped, it must not have any leased
// arenas remaining. If it does, there will be outstanding IDs which
// could be used with those non-reabsorbed Arenas to read freed memory!
// This would be a use-after-free; we panic rather than permit that.
assert_eq!(self.num_leased, 0);
}
}
pub struct ArenaIter<T> {
ptr: *mut T,
quantity_remaining: usize,
first_chunk_capacity: usize,
}
// Implement `Iterator` for `Fibonacci`.
// The `Iterator` trait only requires a method to be defined for the `next` element.
impl<T> Iterator for ArenaIter<T> {
type Item = Arena<T>;
// Here, we define the sequence using `.curr` and `.next`.
// The return type is `Option<T>`:
// * When the `Iterator` is finished, `None` is returned.
// * Otherwise, the next value is wrapped in `Some` and returned.
fn next(&mut self) -> Option<Arena<T>> {
if self.quantity_remaining != 0 {
let first_chunk_ptr = self.ptr;
self.ptr = unsafe { self.ptr.add(self.first_chunk_capacity) };
self.quantity_remaining -= 1;
Some(Arena {
first_chunk_ptr,
first_chunk_len: 0,
first_chunk_cap: self.first_chunk_capacity,
extra_chunks: Vec::new(),
})
} else {
None
}
}
}
#[derive(PartialEq, Eq)]
pub struct Arena<T> {
first_chunk_ptr: *mut T,
first_chunk_len: usize,
first_chunk_cap: usize,
extra_chunks: Vec<Vec<T>>,
}
impl<T> Arena<T> {
pub fn alloc(&mut self, val: T) -> ArenaRef<T> {
let ptr: *mut T = if self.first_chunk_len < self.first_chunk_cap {
// We have enough room in the first chunk for 1 allocation.
self.first_chunk_len += 1;
// Return a pointer to the next available slot.
unsafe { self.first_chunk_ptr.add(self.first_chunk_len) }
} else {
// We ran out of space in the first chunk, so we turn to extra chunks.
// First, ensure that we have an extra chunk with enough space in it.
match self.extra_chunks.last() {
Some(chunk) => {
if chunk.len() >= chunk.capacity() {
// We've run out of space in our last chunk. Create a new one!
self.extra_chunks
.push(Vec::with_capacity(self.first_chunk_cap));
}
}
None => {
// We've never had extra chunks until now. Create the first one!
self.extra_chunks
.push(Vec::with_capacity(self.first_chunk_cap));
}
}
let chunk = self.extra_chunks.last_mut().unwrap();
let index = chunk.len();
chunk.push(val);
// Get a pointer to a memory address within our particular chunk.
&mut chunk[index]
};
ArenaRef {
ptr: unsafe { NonNull::new_unchecked(ptr) },
_pin: PhantomPinned,
}
}
fn alloc_vec(&mut self, num_elems: usize) -> *mut T {
if self.first_chunk_len + num_elems <= self.first_chunk_cap {
// We have enough room in the first chunk for this vec.
self.first_chunk_len += num_elems;
// Return a pointer to the next available element.
unsafe { self.first_chunk_ptr.add(self.first_chunk_len) }
} else {
let new_chunk_cap = self.first_chunk_cap.max(num_elems);
// We ran out of space in the first chunk, so we turn to extra chunks.
// First, ensure that we have an extra chunk with enough space in it.
match self.extra_chunks.last() {
Some(chunk) => {
if chunk.len() + num_elems >= chunk.capacity() {
// We don't have enough space in our last chunk.
// Create a new one!
self.extra_chunks.push(Vec::with_capacity(new_chunk_cap));
}
}
None => {
// We've never had extra chunks until now. Create the first one!
self.extra_chunks.push(Vec::with_capacity(new_chunk_cap));
}
}
let chunk = self.extra_chunks.last_mut().unwrap();
let index = chunk.len();
// Get a pointer to a memory address within our particular chunk.
&mut chunk[index]
}
}
}
pub trait AsArena<T> {
fn verify_ownership(&self, ptr: NonNull<T>);
}
impl<T> AsArena<T> for ArenaPool<T> {
fn verify_ownership(&self, ptr: NonNull<T>) {
verify_ownership(
self.first_chunk.as_ptr(),
self.first_chunk.capacity(),
&self.extra_chunks,
ptr.as_ptr(),
);
}
}
impl<T> AsArena<T> for Arena<T> {
fn verify_ownership(&self, ptr: NonNull<T>) {
verify_ownership(
self.first_chunk_ptr,
self.first_chunk_cap,
&self.extra_chunks,
ptr.as_ptr(),
);
}
}
fn verify_ownership<T>(
first_chunk_ptr: *const T,
first_chunk_cap: usize,
extra_chunks: &[Vec<T>],
ptr: *const T,
) {
let addr = ptr as usize;
let start_addr = first_chunk_ptr as usize;
let end_addr = start_addr + first_chunk_cap;
if start_addr <= addr && addr < end_addr {
// This is within our first chunk's address space, so it's verified!
} else {
// This wasn't within our first chunk's address space, so we need
// to see if we can find it in one of our extra_chunks.
for chunk in extra_chunks {
let start_addr = chunk.as_ptr() as usize;
let end_addr = start_addr + chunk.capacity();
if start_addr <= addr && addr < end_addr {
// Found it! No need to loop anymore; verification passed.
return;
}
}
// The address wasn't within any of our chunks' bounds.
// Panic to avoid use-after-free errors!
internal_error!("Pointer ownership verification failed.");
}
}

View file

@ -1,17 +0,0 @@
// #[macro_use]
// extern crate pretty_assertions;
extern crate arena_pool;
#[cfg(test)]
mod test_arena_pool {
use arena_pool::pool::{ArenaIter, ArenaPool};
#[test]
fn empty_pool() {
// Neither of these does anything, but they
// at least shouldn't panic or anything.
let _: (ArenaPool<()>, ArenaIter<()>) = ArenaPool::new(0, 0);
let _: (ArenaPool<()>, ArenaIter<()>) = ArenaPool::with_chunk_size(0, 0, 0);
}
}

View file

@ -802,7 +802,7 @@ fn build_loaded_file<'a>(
platform_main_roc.with_file_name(roc_linker::preprocessed_host_filename(target).unwrap()) platform_main_roc.with_file_name(roc_linker::preprocessed_host_filename(target).unwrap())
}; };
let mut output_exe_path = match out_path { let output_exe_path = match out_path {
Some(path) => { Some(path) => {
// true iff the path ends with a directory separator, // true iff the path ends with a directory separator,
// e.g. '/' on UNIX, '/' or '\\' on Windows // e.g. '/' on UNIX, '/' or '\\' on Windows
@ -830,12 +830,22 @@ fn build_loaded_file<'a>(
if ends_with_sep { if ends_with_sep {
let filename = app_module_path.file_name().unwrap_or_default(); let filename = app_module_path.file_name().unwrap_or_default();
with_executable_extension(&path.join(filename), operating_system) with_output_extension(
&path.join(filename),
operating_system,
linking_strategy,
link_type,
)
} else { } else {
path.to_path_buf() path.to_path_buf()
} }
} }
None => with_executable_extension(&app_module_path, operating_system), None => with_output_extension(
&app_module_path,
operating_system,
linking_strategy,
link_type,
),
}; };
// We don't need to spawn a rebuild thread when using a prebuilt host. // We don't need to spawn a rebuild thread when using a prebuilt host.
@ -994,7 +1004,6 @@ fn build_loaded_file<'a>(
} }
(LinkingStrategy::Additive, _) | (LinkingStrategy::Legacy, LinkType::None) => { (LinkingStrategy::Additive, _) | (LinkingStrategy::Legacy, LinkType::None) => {
// Just copy the object file to the output folder. // Just copy the object file to the output folder.
output_exe_path.set_extension(operating_system.object_file_ext());
std::fs::write(&output_exe_path, &*roc_app_bytes).unwrap(); std::fs::write(&output_exe_path, &*roc_app_bytes).unwrap();
} }
(LinkingStrategy::Legacy, _) => { (LinkingStrategy::Legacy, _) => {
@ -1324,6 +1333,17 @@ pub fn build_str_test<'a>(
) )
} }
fn with_executable_extension(path: &Path, os: OperatingSystem) -> PathBuf { fn with_output_extension(
path.with_extension(os.executable_file_ext().unwrap_or_default()) path: &Path,
os: OperatingSystem,
linking_strategy: LinkingStrategy,
link_type: LinkType,
) -> PathBuf {
match (linking_strategy, link_type) {
(LinkingStrategy::Additive, _) | (LinkingStrategy::Legacy, LinkType::None) => {
// Additive linking and no linking both output the object file type.
path.with_extension(os.object_file_ext())
}
_ => path.with_extension(os.executable_file_ext().unwrap_or_default()),
}
} }

View file

@ -1 +0,0 @@
builtins.ll

View file

@ -1,5 +0,0 @@
zig-out
zig-cache
src/zig-cache
benchmark/zig-cache
dec

View file

@ -264,6 +264,9 @@ comptime {
if (builtin.target.cpu.arch == .aarch64) { if (builtin.target.cpu.arch == .aarch64) {
@export(__roc_force_setjmp, .{ .name = "__roc_force_setjmp", .linkage = .Weak }); @export(__roc_force_setjmp, .{ .name = "__roc_force_setjmp", .linkage = .Weak });
@export(__roc_force_longjmp, .{ .name = "__roc_force_longjmp", .linkage = .Weak }); @export(__roc_force_longjmp, .{ .name = "__roc_force_longjmp", .linkage = .Weak });
} else if (builtin.os.tag == .windows) {
@export(__roc_force_setjmp_windows, .{ .name = "__roc_force_setjmp", .linkage = .Weak });
@export(__roc_force_longjmp_windows, .{ .name = "__roc_force_longjmp", .linkage = .Weak });
} }
} }
@ -279,14 +282,103 @@ pub extern fn _longjmp([*c]c_int, c_int) noreturn;
pub extern fn sigsetjmp([*c]c_int, c_int) c_int; pub extern fn sigsetjmp([*c]c_int, c_int) c_int;
pub extern fn siglongjmp([*c]c_int, c_int) noreturn; pub extern fn siglongjmp([*c]c_int, c_int) noreturn;
pub extern fn longjmperror() void; pub extern fn longjmperror() void;
// Zig won't expose the externs (and hence link correctly) unless we force them to be used. // Zig won't expose the externs (and hence link correctly) unless we force them to be used.
fn __roc_force_setjmp(it: [*c]c_int) callconv(.C) c_int { fn __roc_force_setjmp(it: [*c]c_int) callconv(.C) c_int {
return setjmp(it); return setjmp(it);
} }
fn __roc_force_longjmp(a0: [*c]c_int, a1: c_int) callconv(.C) noreturn { fn __roc_force_longjmp(a0: [*c]c_int, a1: c_int) callconv(.C) noreturn {
longjmp(a0, a1); longjmp(a0, a1);
} }
pub extern fn windows_setjmp([*c]c_int) c_int;
pub extern fn windows_longjmp([*c]c_int, c_int) noreturn;
fn __roc_force_setjmp_windows(it: [*c]c_int) callconv(.C) c_int {
return windows_setjmp(it);
}
fn __roc_force_longjmp_windows(a0: [*c]c_int, a1: c_int) callconv(.C) noreturn {
windows_longjmp(a0, a1);
}
comptime {
if (builtin.os.tag == .windows) {
asm (
\\.global windows_longjmp;
\\windows_longjmp:
\\ movq 0x00(%rcx), %rdx
\\ movq 0x08(%rcx), %rbx
\\ # note 0x10 is not used yet!
\\ movq 0x18(%rcx), %rbp
\\ movq 0x20(%rcx), %rsi
\\ movq 0x28(%rcx), %rdi
\\ movq 0x30(%rcx), %r12
\\ movq 0x38(%rcx), %r13
\\ movq 0x40(%rcx), %r14
\\ movq 0x48(%rcx), %r15
\\
\\ # restore stack pointer
\\ movq 0x10(%rcx), %rsp
\\
\\ # load jmp address
\\ movq 0x50(%rcx), %r8
\\
\\ # set up return value
\\ movq %rbx, %rax
\\
\\ movdqu 0x60(%rcx), %xmm6
\\ movdqu 0x70(%rcx), %xmm7
\\ movdqu 0x80(%rcx), %xmm8
\\ movdqu 0x90(%rcx), %xmm9
\\ movdqu 0xa0(%rcx), %xmm10
\\ movdqu 0xb0(%rcx), %xmm11
\\ movdqu 0xc0(%rcx), %xmm12
\\ movdqu 0xd0(%rcx), %xmm13
\\ movdqu 0xe0(%rcx), %xmm14
\\ movdqu 0xf0(%rcx), %xmm15
\\
\\ jmp *%r8
\\
\\.global windows_setjmp;
\\windows_setjmp:
\\ movq %rdx, 0x00(%rcx)
\\ movq %rbx, 0x08(%rcx)
\\ # note 0x10 is not used yet!
\\ movq %rbp, 0x18(%rcx)
\\ movq %rsi, 0x20(%rcx)
\\ movq %rdi, 0x28(%rcx)
\\ movq %r12, 0x30(%rcx)
\\ movq %r13, 0x38(%rcx)
\\ movq %r14, 0x40(%rcx)
\\ movq %r15, 0x48(%rcx)
\\
\\ # the stack location right after the windows_setjmp call
\\ leaq 0x08(%rsp), %r8
\\ movq %r8, 0x10(%rcx)
\\
\\ movq (%rsp), %r8
\\ movq %r8, 0x50(%rcx)
\\
\\ movdqu %xmm6, 0x60(%rcx)
\\ movdqu %xmm7, 0x70(%rcx)
\\ movdqu %xmm8, 0x80(%rcx)
\\ movdqu %xmm9, 0x90(%rcx)
\\ movdqu %xmm10, 0xa0(%rcx)
\\ movdqu %xmm11, 0xb0(%rcx)
\\ movdqu %xmm12, 0xc0(%rcx)
\\ movdqu %xmm13, 0xd0(%rcx)
\\ movdqu %xmm14, 0xe0(%rcx)
\\ movdqu %xmm15, 0xf0(%rcx)
\\
\\ xorl %eax, %eax
\\ ret
\\
);
}
}
// Export helpers - Must be run inside a comptime // Export helpers - Must be run inside a comptime
fn exportBuiltinFn(comptime func: anytype, comptime func_name: []const u8) void { fn exportBuiltinFn(comptime func: anytype, comptime func_name: []const u8) void {
@export(func, .{ .name = "roc_builtins." ++ func_name, .linkage = .Strong }); @export(func, .{ .name = "roc_builtins." ++ func_name, .linkage = .Strong });

View file

@ -445,6 +445,9 @@ pub const NOTIFY_PARENT_EXPECT: &str = "roc_builtins.utils.notify_parent_expect"
pub const UTILS_LONGJMP: &str = "longjmp"; pub const UTILS_LONGJMP: &str = "longjmp";
pub const UTILS_SETJMP: &str = "setjmp"; pub const UTILS_SETJMP: &str = "setjmp";
pub const UTILS_WINDOWS_SETJMP: &str = "windows_setjmp";
pub const UTILS_WINDOWS_LONGJMP: &str = "windows_longjmp";
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct IntToIntrinsicName { pub struct IntToIntrinsicName {
pub options: [IntrinsicName; 10], pub options: [IntrinsicName; 10],

View file

@ -1112,7 +1112,7 @@ fn deep_copy_type_vars<C: CopyEnv>(
} }
for uls_index in unspecialized { for uls_index in unspecialized {
let Uls(var, _, _) = env.source()[uls_index]; let Uls(var, _, _) = env.source()[uls_index];
descend_var!(var); let _ignored = descend_var!(var);
} }
let new_ambient_function = descend_var!(ambient_function); let new_ambient_function = descend_var!(ambient_function);

View file

@ -74,14 +74,25 @@ fn print_declarations_help<'a>(
f.intersperse(defs, f.hardline().append(f.hardline())) f.intersperse(defs, f.hardline().append(f.hardline()))
} }
fn always_true() -> bool {
true
}
macro_rules! maybe_paren { macro_rules! maybe_paren {
($paren_if_above:expr, $my_prec:expr, $doc:expr) => { ($paren_if_above:expr, $my_prec:expr, $doc:expr) => {
maybe_paren!($paren_if_above, $my_prec, || true, $doc) maybe_paren!($paren_if_above, $my_prec, always_true, $doc)
}; };
($paren_if_above:expr, $my_prec:expr, $extra_cond:expr, $doc:expr) => { ($paren_if_above:expr, $my_prec:expr, $extra_cond:expr, $doc:expr) => {
if $my_prec > $paren_if_above && $extra_cond() { 'blk: {
$doc.parens().group() if $my_prec > $paren_if_above {
} else { #[allow(clippy::redundant_closure_call)]
let extra_cond = $extra_cond();
if extra_cond {
break 'blk $doc.parens().group();
}
}
$doc $doc
} }
}; };

View file

@ -2423,7 +2423,9 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
| ast::StrSegment::Plaintext(_) => true, | ast::StrSegment::Plaintext(_) => true,
// Disallow nested interpolation. Alternatively, we could allow it but require // Disallow nested interpolation. Alternatively, we could allow it but require
// a comment above it apologizing to the next person who has to read the code. // a comment above it apologizing to the next person who has to read the code.
ast::StrSegment::Interpolated(_) => false, ast::StrSegment::Interpolated(_) | ast::StrSegment::DeprecatedInterpolated(_) => {
false
}
}) })
} }
ast::Expr::Record(fields) => fields.iter().all(|loc_field| match loc_field.value { ast::Expr::Record(fields) => fields.iter().all(|loc_field| match loc_field.value {
@ -2550,7 +2552,7 @@ fn flatten_str_lines<'a>(
); );
} }
}, },
Interpolated(loc_expr) => { Interpolated(loc_expr) | DeprecatedInterpolated(loc_expr) => {
if is_valid_interpolation(loc_expr.value) { if is_valid_interpolation(loc_expr.value) {
// Interpolations desugar to Str.concat calls // Interpolations desugar to Str.concat calls
output.references.insert_call(Symbol::STR_CONCAT); output.references.insert_call(Symbol::STR_CONCAT);

View file

@ -634,6 +634,22 @@ fn desugar_str_segments<'a>(
StrSegment::Plaintext(_) | StrSegment::Unicode(_) | StrSegment::EscapedChar(_) => { StrSegment::Plaintext(_) | StrSegment::Unicode(_) | StrSegment::EscapedChar(_) => {
*segment *segment
} }
StrSegment::DeprecatedInterpolated(loc_expr) => {
let loc_desugared = desugar_expr(
arena,
arena.alloc(Loc {
region: loc_expr.region,
value: *loc_expr.value,
}),
src,
line_info,
module_path,
);
StrSegment::DeprecatedInterpolated(Loc {
region: loc_desugared.region,
value: arena.alloc(loc_desugared.value),
})
}
StrSegment::Interpolated(loc_expr) => { StrSegment::Interpolated(loc_expr) => {
let loc_desugared = desugar_expr( let loc_desugared = desugar_expr(
arena, arena,

View file

@ -1071,7 +1071,7 @@ fn flatten_str_lines(lines: &[&[StrSegment<'_>]]) -> Pattern {
Unicode(loc_digits) => { Unicode(loc_digits) => {
todo!("parse unicode digits {:?}", loc_digits); todo!("parse unicode digits {:?}", loc_digits);
} }
Interpolated(loc_expr) => { Interpolated(loc_expr) | DeprecatedInterpolated(loc_expr) => {
return Pattern::UnsupportedPattern(loc_expr.region); return Pattern::UnsupportedPattern(loc_expr.region);
} }
EscapedChar(escaped) => buf.push(escaped.unescape()), EscapedChar(escaped) => buf.push(escaped.unescape()),

View file

@ -280,12 +280,12 @@ mod test_can {
#[test] #[test]
fn correct_annotated_body() { fn correct_annotated_body() {
let src = indoc!( let src = indoc!(
r#" r"
f : Num.Int * -> Num.Int * f : Num.Int * -> Num.Int *
f = \ a -> a f = \ a -> a
f f
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -296,12 +296,12 @@ mod test_can {
#[test] #[test]
fn correct_annotated_body_with_comments() { fn correct_annotated_body_with_comments() {
let src = indoc!( let src = indoc!(
r#" r"
f : Num.Int * -> Num.Int * # comment f : Num.Int * -> Num.Int * # comment
f = \ a -> a f = \ a -> a
f f
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -312,12 +312,12 @@ mod test_can {
#[test] #[test]
fn name_mismatch_annotated_body() { fn name_mismatch_annotated_body() {
let src = indoc!( let src = indoc!(
r#" r"
f : Num.Int * -> Num.Int * f : Num.Int * -> Num.Int *
g = \ a -> a g = \ a -> a
g g
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -340,12 +340,12 @@ mod test_can {
#[test] #[test]
fn name_mismatch_annotated_body_with_comment() { fn name_mismatch_annotated_body_with_comment() {
let src = indoc!( let src = indoc!(
r#" r"
f : Num.Int * -> Num.Int * # comment f : Num.Int * -> Num.Int * # comment
g = \ a -> a g = \ a -> a
g g
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -368,13 +368,13 @@ mod test_can {
#[test] #[test]
fn separated_annotated_body() { fn separated_annotated_body() {
let src = indoc!( let src = indoc!(
r#" r"
f : Num.Int * -> Num.Int * f : Num.Int * -> Num.Int *
f = \ a -> a f = \ a -> a
f 42 f 42
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -389,13 +389,13 @@ mod test_can {
#[test] #[test]
fn separated_annotated_body_with_comment() { fn separated_annotated_body_with_comment() {
let src = indoc!( let src = indoc!(
r#" r"
f : Num.Int * -> Num.Int * f : Num.Int * -> Num.Int *
# comment # comment
f = \ a -> a f = \ a -> a
f 42 f 42
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -410,13 +410,13 @@ mod test_can {
#[test] #[test]
fn shadowed_annotation() { fn shadowed_annotation() {
let src = indoc!( let src = indoc!(
r#" r"
f : Num.Int * -> Num.Int * f : Num.Int * -> Num.Int *
f : Num.Int * -> Num.Int * f : Num.Int * -> Num.Int *
f f
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -432,7 +432,7 @@ mod test_can {
#[test] #[test]
fn correct_nested_unannotated_body() { fn correct_nested_unannotated_body() {
let src = indoc!( let src = indoc!(
r#" r"
f : Num.Int * f : Num.Int *
f = f =
g = 42 g = 42
@ -440,7 +440,7 @@ mod test_can {
g + 1 g + 1
f f
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -451,7 +451,7 @@ mod test_can {
#[test] #[test]
fn correct_nested_annotated_body() { fn correct_nested_annotated_body() {
let src = indoc!( let src = indoc!(
r#" r"
f : Num.Int * f : Num.Int *
f = f =
g : Num.Int * g : Num.Int *
@ -460,7 +460,7 @@ mod test_can {
g + 1 g + 1
f f
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -471,7 +471,7 @@ mod test_can {
#[test] #[test]
fn correct_nested_body_annotated_multiple_lines() { fn correct_nested_body_annotated_multiple_lines() {
let src = indoc!( let src = indoc!(
r#" r"
f : Num.Int * f : Num.Int *
f = f =
g : Num.Int * g : Num.Int *
@ -482,7 +482,7 @@ mod test_can {
g + h + z g + h + z
f f
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -493,7 +493,7 @@ mod test_can {
#[test] #[test]
fn correct_nested_body_unannotated_multiple_lines() { fn correct_nested_body_unannotated_multiple_lines() {
let src = indoc!( let src = indoc!(
r#" r"
f : Num.Int * f : Num.Int *
f = f =
g = 42 g = 42
@ -503,7 +503,7 @@ mod test_can {
g + h + z g + h + z
f f
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -513,7 +513,7 @@ mod test_can {
#[test] #[test]
fn correct_double_nested_body() { fn correct_double_nested_body() {
let src = indoc!( let src = indoc!(
r#" r"
f : Num.Int * f : Num.Int *
f = f =
g = g =
@ -523,7 +523,7 @@ mod test_can {
f f
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -534,13 +534,13 @@ mod test_can {
#[test] #[test]
fn annotation_followed_with_unrelated_affectation() { fn annotation_followed_with_unrelated_affectation() {
let src = indoc!( let src = indoc!(
r#" r"
F : Str F : Str
x = 1 x = 1
x x
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -554,7 +554,7 @@ mod test_can {
#[test] #[test]
fn two_annotations_followed_with_unrelated_affectation() { fn two_annotations_followed_with_unrelated_affectation() {
let src = indoc!( let src = indoc!(
r#" r"
G : Str G : Str
F : {} F : {}
@ -562,7 +562,7 @@ mod test_can {
x = 1 x = 1
x x
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -581,11 +581,11 @@ mod test_can {
// // it only exists in the closure's arguments. // // it only exists in the closure's arguments.
// let arena = Bump::new(); // let arena = Bump::new();
// let src = indoc!( // let src = indoc!(
// r#" // r"
// func = \arg -> arg // func = \arg -> arg
// func 2 // func 2
// "# // "
// ); // );
// let (_actual, output, problems, _var_store, _vars, _constraint) = // let (_actual, output, problems, _var_store, _vars, _constraint) =
// can_expr_with(&arena, test_home(), src); // can_expr_with(&arena, test_home(), src);
@ -608,13 +608,13 @@ mod test_can {
// fn call_by_pointer_for_fn_args() { // fn call_by_pointer_for_fn_args() {
// // This function will get passed in as a pointer. // // This function will get passed in as a pointer.
// let src = indoc!( // let src = indoc!(
// r#" // r"
// apply = \f, x -> f x // apply = \f, x -> f x
// identity = \a -> a // identity = \a -> a
// apply identity 5 // apply identity 5
// "# // "
// ); // );
// let arena = Bump::new(); // let arena = Bump::new();
// let (_actual, output, problems, _var_store, _vars, _constraint) = // let (_actual, output, problems, _var_store, _vars, _constraint) =
@ -637,9 +637,9 @@ mod test_can {
#[test] #[test]
fn incorrect_optional_value() { fn incorrect_optional_value() {
let src = indoc!( let src = indoc!(
r#" r"
{ x ? 42 } { x ? 42 }
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { let CanExprOut {
@ -911,7 +911,7 @@ mod test_can {
#[test] #[test]
fn recognize_tail_calls() { fn recognize_tail_calls() {
let src = indoc!( let src = indoc!(
r#" r"
g = \x -> g = \x ->
when x is when x is
0 -> 0 0 -> 0
@ -936,7 +936,7 @@ mod test_can {
{ x: p, y: h } { x: p, y: h }
) )
) )
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { let CanExprOut {
@ -963,7 +963,7 @@ mod test_can {
// #[test] // #[test]
// fn reproduce_incorrect_unused_defs() { // fn reproduce_incorrect_unused_defs() {
// let src = indoc!( // let src = indoc!(
// r#" // r"
// g = \x -> // g = \x ->
// when x is // when x is
// 0 -> 0 // 0 -> 0
@ -983,7 +983,7 @@ mod test_can {
// # variables must be (indirectly) referenced in the body for analysis to work // # variables must be (indirectly) referenced in the body for analysis to work
// # { x: p, y: h } // # { x: p, y: h }
// g // g
// "# // "
// ); // );
// let arena = Bump::new(); // let arena = Bump::new();
// let CanExprOut { // let CanExprOut {
@ -1012,14 +1012,14 @@ mod test_can {
#[test] #[test]
fn when_tail_call() { fn when_tail_call() {
let src = indoc!( let src = indoc!(
r#" r"
g = \x -> g = \x ->
when x is when x is
0 -> 0 0 -> 0
_ -> g (x + 1) _ -> g (x + 1)
g 0 g 0
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { let CanExprOut {
@ -1034,11 +1034,11 @@ mod test_can {
#[test] #[test]
fn immediate_tail_call() { fn immediate_tail_call() {
let src = indoc!( let src = indoc!(
r#" r"
f = \x -> f x f = \x -> f x
f 0 f 0
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { let CanExprOut {
@ -1055,13 +1055,13 @@ mod test_can {
#[test] #[test]
fn when_condition_is_no_tail_call() { fn when_condition_is_no_tail_call() {
let src = indoc!( let src = indoc!(
r#" r"
q = \x -> q = \x ->
when q x is when q x is
_ -> 0 _ -> 0
q 0 q 0
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { let CanExprOut {
@ -1076,7 +1076,7 @@ mod test_can {
#[test] #[test]
fn good_mutual_recursion() { fn good_mutual_recursion() {
let src = indoc!( let src = indoc!(
r#" r"
q = \x -> q = \x ->
when x is when x is
0 -> 0 0 -> 0
@ -1088,7 +1088,7 @@ mod test_can {
_ -> q (x - 1) _ -> q (x - 1)
q p q p
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { let CanExprOut {
@ -1107,11 +1107,11 @@ mod test_can {
#[test] #[test]
fn valid_self_recursion() { fn valid_self_recursion() {
let src = indoc!( let src = indoc!(
r#" r"
boom = \_ -> boom {} boom = \_ -> boom {}
boom boom
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { let CanExprOut {
@ -1128,13 +1128,13 @@ mod test_can {
#[test] #[test]
fn invalid_mutual_recursion() { fn invalid_mutual_recursion() {
let src = indoc!( let src = indoc!(
r#" r"
x = y x = y
y = z y = z
z = x z = x
x x
"# "
); );
let home = test_home(); let home = test_home();
let arena = Bump::new(); let arena = Bump::new();
@ -1176,11 +1176,11 @@ mod test_can {
#[test] #[test]
fn dict() { fn dict() {
let src = indoc!( let src = indoc!(
r#" r"
x = Dict.empty {} x = Dict.empty {}
Dict.len x Dict.len x
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -1191,7 +1191,7 @@ mod test_can {
#[test] #[test]
fn unused_def_regression() { fn unused_def_regression() {
let src = indoc!( let src = indoc!(
r#" r"
Booly : [Yes, No, Maybe] Booly : [Yes, No, Maybe]
y : Booly y : Booly
@ -1205,7 +1205,7 @@ mod test_can {
x = [y] x = [y]
x x
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -1216,14 +1216,14 @@ mod test_can {
#[test] #[test]
fn optional_field_not_unused() { fn optional_field_not_unused() {
let src = indoc!( let src = indoc!(
r#" r"
fallbackZ = 3 fallbackZ = 3
fn = \{ x, y, z ? fallbackZ } -> fn = \{ x, y, z ? fallbackZ } ->
{ x, y, z } { x, y, z }
fn { x: 0, y: 1 } fn { x: 0, y: 1 }
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -1234,12 +1234,12 @@ mod test_can {
#[test] #[test]
fn issue_2534() { fn issue_2534() {
let src = indoc!( let src = indoc!(
r#" r"
x = { a: 1 } x = { a: 1 }
{ {
x & a: 2 x & a: 2
} }
"# "
); );
let arena = Bump::new(); let arena = Bump::new();
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src); let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
@ -1252,13 +1252,13 @@ mod test_can {
// // "local" should be used, because the closure used it. // // "local" should be used, because the closure used it.
// // However, "unused" should be unused. // // However, "unused" should be unused.
// let (_, output, problems, _) = can_expr(indoc!( // let (_, output, problems, _) = can_expr(indoc!(
// r#" // r"
// local = 5 // local = 5
// unused = 6 // unused = 6
// func = \arg -> arg + local // func = \arg -> arg + local
// 3 + func 2 // 3 + func 2
// "# // "
// )); // ));
// assert_eq!( // assert_eq!(
@ -1283,13 +1283,13 @@ mod test_can {
//fn unused_closure() { //fn unused_closure() {
// // "unused" should be unused because it's in func, which is unused. // // "unused" should be unused because it's in func, which is unused.
// let (_, output, problems, _) = can_expr(indoc!( // let (_, output, problems, _) = can_expr(indoc!(
// r#" // r"
// local = 5 // local = 5
// unused = 6 // unused = 6
// func = \arg -> arg + unused // func = \arg -> arg + unused
// local // local
// "# // "
// )); // ));
// assert_eq!( // assert_eq!(
@ -1316,9 +1316,9 @@ mod test_can {
// #[test] // #[test]
// fn basic_unrecognized_constant() { // fn basic_unrecognized_constant() {
// let (expr, output, problems, _) = can_expr(indoc!( // let (expr, output, problems, _) = can_expr(indoc!(
// r#" // r"
// x // x
// "# // "
// )); // ));
// assert_eq!( // assert_eq!(
@ -1342,12 +1342,12 @@ mod test_can {
//#[test] //#[test]
//fn complex_unrecognized_constant() { //fn complex_unrecognized_constant() {
// let (_, output, problems, _) = can_expr(indoc!( // let (_, output, problems, _) = can_expr(indoc!(
// r#" // r"
// a = 5 // a = 5
// b = 6 // b = 6
// a + b * z // a + b * z
// "# // "
// )); // ));
// assert_eq!( // assert_eq!(
@ -1375,13 +1375,13 @@ mod test_can {
// // This should report that both a and b are unused, since the return expr never references them. // // This should report that both a and b are unused, since the return expr never references them.
// // It should not report them as circular, since we haven't solved the halting problem here. // // It should not report them as circular, since we haven't solved the halting problem here.
// let (_, output, problems, _) = can_expr(indoc!( // let (_, output, problems, _) = can_expr(indoc!(
// r#" // r"
// a = \arg -> if arg > 0 then b 7 else 0 // a = \arg -> if arg > 0 then b 7 else 0
// b = \arg -> if arg > 0 then a (arg - 1) else 0 // b = \arg -> if arg > 0 then a (arg - 1) else 0
// c = 5 // c = 5
// c // c
// "# // "
// )); // ));
// assert_eq!(problems, vec![unused("a"), unused("b")]); // assert_eq!(problems, vec![unused("a"), unused("b")]);
@ -1400,7 +1400,7 @@ mod test_can {
//#[test] //#[test]
//fn can_fibonacci() { //fn can_fibonacci() {
// let (_, output, problems, _) = can_expr(indoc!( // let (_, output, problems, _) = can_expr(indoc!(
// r#" // r"
// fibonacci = \num -> // fibonacci = \num ->
// if num < 2 then // if num < 2 then
// num // num
@ -1408,7 +1408,7 @@ mod test_can {
// fibonacci (num - 1) + fibonacci (num - 2) // fibonacci (num - 1) + fibonacci (num - 2)
// fibonacci 9 // fibonacci 9
// "# // "
// )); // ));
// assert_eq!(problems, vec![]); // assert_eq!(problems, vec![]);
@ -1430,7 +1430,7 @@ mod test_can {
// // is considered a tail call, even though it only // // is considered a tail call, even though it only
// // calls itself from one branch! // // calls itself from one branch!
// let (_, output, problems, _) = can_expr(indoc!( // let (_, output, problems, _) = can_expr(indoc!(
// r#" // r"
// factorial = \num -> // factorial = \num ->
// factorialHelp num 0 // factorialHelp num 0
@ -1441,7 +1441,7 @@ mod test_can {
// factorialHelp (num - 1) (total * num) // factorialHelp (num - 1) (total * num)
// factorial 9 // factorial 9
// "# // "
// )); // ));
// assert_eq!(problems, vec![]); // assert_eq!(problems, vec![]);
@ -1462,12 +1462,12 @@ mod test_can {
// // This should report that neither a nor b are unused, // // This should report that neither a nor b are unused,
// // since if you never call a function but do return it, that's okay! // // since if you never call a function but do return it, that's okay!
// let (_, output, problems, _) = can_expr(indoc!( // let (_, output, problems, _) = can_expr(indoc!(
// r#" // r"
// a = \_ -> 42 // a = \_ -> 42
// b = a // b = a
// b // b
// "# // "
// )); // ));
// assert_eq!(problems, Vec::new()); // assert_eq!(problems, Vec::new());
@ -1488,14 +1488,14 @@ mod test_can {
//#[test] //#[test]
//fn reorder_assignments() { //fn reorder_assignments() {
// let (expr, output, problems, _) = can_expr(indoc!( // let (expr, output, problems, _) = can_expr(indoc!(
// r#" // r"
// increment = \arg -> arg + 1 // increment = \arg -> arg + 1
// z = (increment 2) + y // z = (increment 2) + y
// y = x + 1 // y = x + 1
// x = 9 // x = 9
// z * 3 // z * 3
// "# // "
// )); // ));
// assert_eq!(problems, vec![]); // assert_eq!(problems, vec![]);
@ -1526,7 +1526,7 @@ mod test_can {
//#[test] //#[test]
//fn reorder_closed_over_assignments() { //fn reorder_closed_over_assignments() {
// let (expr, output, problems, _) = can_expr(indoc!( // let (expr, output, problems, _) = can_expr(indoc!(
// r#" // r"
// z = func1 x // z = func1 x
// x = 9 // x = 9
// y = func2 3 // y = func2 3
@ -1534,7 +1534,7 @@ mod test_can {
// func2 = \arg -> arg + x // func2 = \arg -> arg + x
// z // z
// "# // "
// )); // ));
// assert_eq!(problems, vec![]); // assert_eq!(problems, vec![]);
@ -1628,14 +1628,14 @@ mod test_can {
//#[test] //#[test]
//fn circular_assignment() { //fn circular_assignment() {
// let (_, _, problems, _) = can_expr(indoc!( // let (_, _, problems, _) = can_expr(indoc!(
// r#" // r"
// c = d + 3 // c = d + 3
// b = 2 + c // b = 2 + c
// d = a + 7 // d = a + 7
// a = b + 1 // a = b + 1
// 2 + d // 2 + d
// "# // "
// )); // ));
// assert_eq!( // assert_eq!(
@ -1655,9 +1655,9 @@ mod test_can {
// // There was a bug where this reported UnusedArgument("val") // // There was a bug where this reported UnusedArgument("val")
// // since it was used only in the returned function only. // // since it was used only in the returned function only.
// let (_, _, problems, _) = can_expr(indoc!( // let (_, _, problems, _) = can_expr(indoc!(
// r#" // r"
// \val -> \_ -> val // \val -> \_ -> val
// "# // "
// )); // ));
// assert_eq!(problems, vec![]); // assert_eq!(problems, vec![]);
@ -1828,10 +1828,10 @@ mod test_can {
// // This should NOT be string interpolation, because of the \\ // // This should NOT be string interpolation, because of the \\
// indoc!( // indoc!(
// r#" // r#"
// "abcd\\(efg)hij" // "abcd\$(efg)hij"
// "# // "#
// ), // ),
// Str(r#"abcd\(efg)hij"#.into()), // Str(r"abcd\(efg)hij".into()),
// ); // );
// } // }
@ -1848,7 +1848,7 @@ mod test_can {
// #[test] // #[test]
// fn string_with_special_escapes() { // fn string_with_special_escapes() {
// expect_parsed_str(r#"x\x"#, r#""x\\x""#); // expect_parsed_str(r"x\x", r#""x\\x""#);
// expect_parsed_str(r#"x"x"#, r#""x\"x""#); // expect_parsed_str(r#"x"x"#, r#""x\"x""#);
// expect_parsed_str("x\tx", r#""x\tx""#); // expect_parsed_str("x\tx", r#""x\tx""#);
// expect_parsed_str("x\rx", r#""x\rx""#); // expect_parsed_str("x\rx", r#""x\rx""#);

View file

@ -1,17 +0,0 @@
/node_modules
/.pnp
.pnp.js
/coverage
/build
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View file

@ -30,9 +30,6 @@ pub type SendMap<K, V> = im::hashmap::HashMap<K, V, BuildHasher>;
pub type SendSet<K> = im::hashset::HashSet<K, BuildHasher>; pub type SendSet<K> = im::hashset::HashSet<K, BuildHasher>;
// pub type BumpMap<'a, K, V> = hashbrown::HashMap<K, V, BuildHasher, hashbrown::BumpWrapper<'a>>;
// pub type BumpSet<'a, K> = hashbrown::HashSet<K, BuildHasher, hashbrown::BumpWrapper<'a>>;
pub type BumpMap<K, V> = hashbrown::HashMap<K, V, BuildHasher>; pub type BumpMap<K, V> = hashbrown::HashMap<K, V, BuildHasher>;
pub type BumpSet<K> = hashbrown::HashSet<K, BuildHasher>; pub type BumpSet<K> = hashbrown::HashSet<K, BuildHasher>;
@ -46,32 +43,20 @@ pub trait BumpMapDefault<'a> {
impl<'a, K, V> BumpMapDefault<'a> for BumpMap<K, V> { impl<'a, K, V> BumpMapDefault<'a> for BumpMap<K, V> {
fn new_in(_arena: &'a bumpalo::Bump) -> Self { fn new_in(_arena: &'a bumpalo::Bump) -> Self {
// hashbrown::HashMap::with_hasher_in(default_hasher(), hashbrown::BumpWrapper(arena))
hashbrown::HashMap::with_hasher(default_hasher()) hashbrown::HashMap::with_hasher(default_hasher())
} }
fn with_capacity_in(capacity: usize, _arena: &'a bumpalo::Bump) -> Self { fn with_capacity_in(capacity: usize, _arena: &'a bumpalo::Bump) -> Self {
// hashbrown::HashMap::with_capacity_and_hasher_in(
// capacity,
// default_hasher(),
// hashbrown::BumpWrapper(arena),
// )
hashbrown::HashMap::with_capacity_and_hasher(capacity, default_hasher()) hashbrown::HashMap::with_capacity_and_hasher(capacity, default_hasher())
} }
} }
impl<'a, K> BumpMapDefault<'a> for BumpSet<K> { impl<'a, K> BumpMapDefault<'a> for BumpSet<K> {
fn new_in(_arena: &'a bumpalo::Bump) -> Self { fn new_in(_arena: &'a bumpalo::Bump) -> Self {
// hashbrown::HashSet::with_hasher_in(default_hasher(), hashbrown::BumpWrapper(arena))
hashbrown::HashSet::with_hasher(default_hasher()) hashbrown::HashSet::with_hasher(default_hasher())
} }
fn with_capacity_in(capacity: usize, _arena: &'a bumpalo::Bump) -> Self { fn with_capacity_in(capacity: usize, _arena: &'a bumpalo::Bump) -> Self {
// hashbrown::HashSet::with_capacity_and_hasher_in(
// capacity,
// default_hasher(),
// hashbrown::BumpWrapper(arena),
// )
hashbrown::HashSet::with_capacity_and_hasher(capacity, default_hasher()) hashbrown::HashSet::with_capacity_and_hasher(capacity, default_hasher())
} }
} }

View file

@ -400,7 +400,7 @@ fn hash_newtype_tag_union(
let hasher_var = synth_var(env.subs, Content::FlexAbleVar(None, Subs::AB_HASHER)); let hasher_var = synth_var(env.subs, Content::FlexAbleVar(None, Subs::AB_HASHER));
// A // A
let tag_name = tag_name; // let tag_name = tag_name;
// t1 .. tn // t1 .. tn
let payload_vars = payload_variables; let payload_vars = payload_variables;
// x11 .. x1n // x11 .. x1n

View file

@ -612,9 +612,20 @@ fn format_str_segment(seg: &StrSegment, buf: &mut Buf, indent: u16) {
buf.push('\\'); buf.push('\\');
buf.push(escaped.to_parsed_char()); buf.push(escaped.to_parsed_char());
} }
Interpolated(loc_expr) => { DeprecatedInterpolated(loc_expr) => {
buf.push_str("\\("); buf.push_str("\\(");
// e.g. (name) in "Hi, \(name)!" // e.g. (name) in "Hi, $(name)!"
loc_expr.value.format_with_options(
buf,
Parens::NotNeeded, // We already printed parens!
Newlines::No, // Interpolations can never have newlines
indent,
);
buf.push(')');
}
Interpolated(loc_expr) => {
buf.push_str("$(");
// e.g. (name) in "Hi, $(name)!"
loc_expr.value.format_with_options( loc_expr.value.format_with_options(
buf, buf,
Parens::NotNeeded, // We already printed parens! Parens::NotNeeded, // We already printed parens!

View file

@ -656,6 +656,9 @@ impl<'a> RemoveSpaces<'a> for StrSegment<'a> {
StrSegment::Unicode(t) => StrSegment::Unicode(t.remove_spaces(arena)), StrSegment::Unicode(t) => StrSegment::Unicode(t.remove_spaces(arena)),
StrSegment::EscapedChar(c) => StrSegment::EscapedChar(c), StrSegment::EscapedChar(c) => StrSegment::EscapedChar(c),
StrSegment::Interpolated(t) => StrSegment::Interpolated(t.remove_spaces(arena)), StrSegment::Interpolated(t) => StrSegment::Interpolated(t.remove_spaces(arena)),
StrSegment::DeprecatedInterpolated(t) => {
StrSegment::DeprecatedInterpolated(t.remove_spaces(arena))
}
} }
} }
} }

View file

@ -1266,6 +1266,7 @@ impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
) { ) {
add_reg64_reg64_reg64(buf, dst, src1, src2); add_reg64_reg64_reg64(buf, dst, src1, src2);
} }
#[inline(always)] #[inline(always)]
fn add_freg32_freg32_freg32( fn add_freg32_freg32_freg32(
buf: &mut Vec<'_, u8>, buf: &mut Vec<'_, u8>,
@ -1285,6 +1286,25 @@ impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
fadd_freg_freg_freg(buf, FloatWidth::F64, dst, src1, src2); fadd_freg_freg_freg(buf, FloatWidth::F64, dst, src1, src2);
} }
#[inline(always)]
fn sub_freg32_freg32_freg32(
buf: &mut Vec<'_, u8>,
dst: AArch64FloatReg,
src1: AArch64FloatReg,
src2: AArch64FloatReg,
) {
fsub_freg_freg_freg(buf, FloatWidth::F32, dst, src1, src2);
}
#[inline(always)]
fn sub_freg64_freg64_freg64(
buf: &mut Vec<'_, u8>,
dst: AArch64FloatReg,
src1: AArch64FloatReg,
src2: AArch64FloatReg,
) {
fsub_freg_freg_freg(buf, FloatWidth::F64, dst, src1, src2);
}
#[inline(always)] #[inline(always)]
fn call(buf: &mut Vec<'_, u8>, relocs: &mut Vec<'_, Relocation>, fn_name: String) { fn call(buf: &mut Vec<'_, u8>, relocs: &mut Vec<'_, Relocation>, fn_name: String) {
let inst = 0b1001_0100_0000_0000_0000_0000_0000_0000u32; let inst = 0b1001_0100_0000_0000_0000_0000_0000_0000u32;
@ -3894,6 +3914,27 @@ fn fadd_freg_freg_freg(
buf.extend(inst.bytes()); buf.extend(inst.bytes());
} }
/// `FSUB Sd/Dd, Sn/Dn, Sm/Dm` -> Sub Sn/Dn and Sm/Dm and place the result into Sd/Dd.
#[inline(always)]
fn fsub_freg_freg_freg(
buf: &mut Vec<'_, u8>,
ftype: FloatWidth,
dst: AArch64FloatReg,
src1: AArch64FloatReg,
src2: AArch64FloatReg,
) {
let inst =
FloatingPointDataProcessingTwoSource::new(FloatingPointDataProcessingTwoSourceParams {
opcode: 0b0011,
ptype: ftype,
rd: dst,
rn: src1,
rm: src2,
});
buf.extend(inst.bytes());
}
/// `FCMP Sn/Dn, Sm/Dm` -> Compare Sn/Dn and Sm/Dm, setting condition flags. /// `FCMP Sn/Dn, Sm/Dm` -> Compare Sn/Dn and Sm/Dm, setting condition flags.
#[inline(always)] #[inline(always)]
fn fcmp_freg_freg( fn fcmp_freg_freg(

View file

@ -166,6 +166,13 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
); );
fn add_reg64_reg64_imm32(buf: &mut Vec<'_, u8>, dst: GeneralReg, src1: GeneralReg, imm32: i32); fn add_reg64_reg64_imm32(buf: &mut Vec<'_, u8>, dst: GeneralReg, src1: GeneralReg, imm32: i32);
fn add_reg64_reg64_reg64(
buf: &mut Vec<'_, u8>,
dst: GeneralReg,
src1: GeneralReg,
src2: GeneralReg,
);
fn add_freg32_freg32_freg32( fn add_freg32_freg32_freg32(
buf: &mut Vec<'_, u8>, buf: &mut Vec<'_, u8>,
dst: FloatReg, dst: FloatReg,
@ -178,12 +185,6 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
src1: FloatReg, src1: FloatReg,
src2: FloatReg, src2: FloatReg,
); );
fn add_reg64_reg64_reg64(
buf: &mut Vec<'_, u8>,
dst: GeneralReg,
src1: GeneralReg,
src2: GeneralReg,
);
fn and_reg64_reg64_reg64( fn and_reg64_reg64_reg64(
buf: &mut Vec<'_, u8>, buf: &mut Vec<'_, u8>,
@ -629,6 +630,19 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
ASM: Assembler<GeneralReg, FloatReg>, ASM: Assembler<GeneralReg, FloatReg>,
CC: CallConv<GeneralReg, FloatReg, ASM>; CC: CallConv<GeneralReg, FloatReg, ASM>;
fn sub_freg32_freg32_freg32(
buf: &mut Vec<'_, u8>,
dst: FloatReg,
src1: FloatReg,
src2: FloatReg,
);
fn sub_freg64_freg64_freg64(
buf: &mut Vec<'_, u8>,
dst: FloatReg,
src1: FloatReg,
src2: FloatReg,
);
fn sub_reg64_reg64_imm32(buf: &mut Vec<'_, u8>, dst: GeneralReg, src1: GeneralReg, imm32: i32); fn sub_reg64_reg64_imm32(buf: &mut Vec<'_, u8>, dst: GeneralReg, src1: GeneralReg, imm32: i32);
fn sub_reg64_reg64_reg64( fn sub_reg64_reg64_reg64(
buf: &mut Vec<'_, u8>, buf: &mut Vec<'_, u8>,
@ -1308,16 +1322,14 @@ impl<
fn build_num_add(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &InLayout<'a>) { fn build_num_add(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &InLayout<'a>) {
match self.layout_interner.get_repr(*layout) { match self.layout_interner.get_repr(*layout) {
LayoutRepr::Builtin(Builtin::Int(quadword_and_smaller!())) => { LayoutRepr::Builtin(Builtin::Int(int_width)) => self.build_fn_call(
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst); dst,
let src1_reg = self bitcode::NUM_ADD_OR_PANIC_INT[int_width].to_string(),
.storage_manager &[*src1, *src2],
.load_to_general_reg(&mut self.buf, src1); &[*layout, *layout],
let src2_reg = self layout,
.storage_manager ),
.load_to_general_reg(&mut self.buf, src2);
ASM::add_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
}
LayoutRepr::Builtin(Builtin::Float(FloatWidth::F64)) => { LayoutRepr::Builtin(Builtin::Float(FloatWidth::F64)) => {
let dst_reg = self.storage_manager.claim_float_reg(&mut self.buf, dst); let dst_reg = self.storage_manager.claim_float_reg(&mut self.buf, dst);
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1); let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
@ -1330,16 +1342,60 @@ impl<
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2); let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
ASM::add_freg32_freg32_freg32(&mut self.buf, dst_reg, src1_reg, src2_reg); ASM::add_freg32_freg32_freg32(&mut self.buf, dst_reg, src1_reg, src2_reg);
} }
LayoutRepr::Builtin(Builtin::Decimal) => {
self.build_fn_call( LayoutRepr::DEC => self.build_fn_call(
dst, dst,
bitcode::DEC_ADD_OR_PANIC.to_string(), bitcode::DEC_ADD_OR_PANIC.to_string(),
&[*src1, *src2], &[*src1, *src2],
&[Layout::DEC, Layout::DEC], &[Layout::DEC, Layout::DEC],
&Layout::DEC, &Layout::DEC,
); ),
other => unreachable!("NumAdd for layout {other:?}"),
} }
x => todo!("NumAdd: layout, {:?}", x), }
fn build_num_add_wrap(
&mut self,
dst: &Symbol,
src1: &Symbol,
src2: &Symbol,
layout: &InLayout<'a>,
) {
match self.layout_interner.get_repr(*layout) {
LayoutRepr::Builtin(Builtin::Int(quadword_and_smaller!())) => {
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src1);
let src2_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src2);
ASM::add_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
}
LayoutRepr::Builtin(Builtin::Float(FloatWidth::F64)) => {
let dst_reg = self.storage_manager.claim_float_reg(&mut self.buf, dst);
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
ASM::add_freg64_freg64_freg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
}
LayoutRepr::Builtin(Builtin::Float(FloatWidth::F32)) => {
let dst_reg = self.storage_manager.claim_float_reg(&mut self.buf, dst);
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
ASM::add_freg32_freg32_freg32(&mut self.buf, dst_reg, src1_reg, src2_reg);
}
LayoutRepr::DEC => self.build_fn_call(
dst,
bitcode::DEC_ADD_SATURATED.to_string(),
&[*src1, *src2],
&[Layout::DEC, Layout::DEC],
&Layout::DEC,
),
other => unreachable!("NumAddWrap for layout {other:?}"),
} }
} }
@ -1424,9 +1480,38 @@ impl<
} }
fn build_num_mul(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &InLayout<'a>) { fn build_num_mul(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &InLayout<'a>) {
// for the time being, `num_mul` is implemented as wrapping multiplication. In roc, the normal match self.layout_interner.get_repr(*layout) {
// `mul` should panic on overflow, but we just don't do that yet LayoutRepr::Builtin(Builtin::Int(int_width)) => self.build_fn_call(
self.build_num_mul_wrap(dst, src1, src2, layout) dst,
bitcode::NUM_MUL_OR_PANIC_INT[int_width].to_string(),
&[*src1, *src2],
&[*layout, *layout],
layout,
),
LayoutRepr::Builtin(Builtin::Float(FloatWidth::F64)) => {
let dst_reg = self.storage_manager.claim_float_reg(&mut self.buf, dst);
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
ASM::mul_freg64_freg64_freg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
}
LayoutRepr::Builtin(Builtin::Float(FloatWidth::F32)) => {
let dst_reg = self.storage_manager.claim_float_reg(&mut self.buf, dst);
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
ASM::mul_freg32_freg32_freg32(&mut self.buf, dst_reg, src1_reg, src2_reg);
}
LayoutRepr::DEC => self.build_fn_call(
dst,
bitcode::DEC_MUL_OR_PANIC.to_string(),
&[*src1, *src2],
&[Layout::DEC, Layout::DEC],
&Layout::DEC,
),
other => unreachable!("NumMul for layout {other:?}"),
}
} }
fn build_num_mul_wrap( fn build_num_mul_wrap(
@ -1609,6 +1694,15 @@ impl<
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2); let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
ASM::div_freg32_freg32_freg32(&mut self.buf, dst_reg, src1_reg, src2_reg); ASM::div_freg32_freg32_freg32(&mut self.buf, dst_reg, src1_reg, src2_reg);
} }
LayoutRepr::Builtin(Builtin::Decimal) => {
self.build_fn_call(
dst,
bitcode::DEC_DIV.to_string(),
&[*src1, *src2],
&[*layout, *layout],
layout,
);
}
x => todo!("NumDiv: layout, {:?}", x), x => todo!("NumDiv: layout, {:?}", x),
} }
} }
@ -1688,9 +1782,38 @@ impl<
} }
fn build_num_sub(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &InLayout<'a>) { fn build_num_sub(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &InLayout<'a>) {
// for the time being, `num_sub` is implemented as wrapping subtraction. In roc, the normal match self.layout_interner.get_repr(*layout) {
// `sub` should panic on overflow, but we just don't do that yet LayoutRepr::Builtin(Builtin::Int(int_width)) => self.build_fn_call(
self.build_num_sub_wrap(dst, src1, src2, layout) dst,
bitcode::NUM_SUB_OR_PANIC_INT[int_width].to_string(),
&[*src1, *src2],
&[*layout, *layout],
layout,
),
LayoutRepr::Builtin(Builtin::Float(FloatWidth::F64)) => {
let dst_reg = self.storage_manager.claim_float_reg(&mut self.buf, dst);
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
ASM::sub_freg64_freg64_freg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
}
LayoutRepr::Builtin(Builtin::Float(FloatWidth::F32)) => {
let dst_reg = self.storage_manager.claim_float_reg(&mut self.buf, dst);
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
ASM::sub_freg32_freg32_freg32(&mut self.buf, dst_reg, src1_reg, src2_reg);
}
LayoutRepr::DEC => self.build_fn_call(
dst,
bitcode::DEC_SUB_OR_PANIC.to_string(),
&[*src1, *src2],
&[Layout::DEC, Layout::DEC],
&Layout::DEC,
),
other => unreachable!("NumMul for layout {other:?}"),
}
} }
fn build_num_sub_wrap( fn build_num_sub_wrap(

View file

@ -523,12 +523,12 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
use X86_64GeneralReg::*; use X86_64GeneralReg::*;
type ASM = X86_64Assembler; type ASM = X86_64Assembler;
// move the first argument to roc_panic (a *RocStr) into r8 // move the first argument to roc_panic (a *const RocStr) into r8
ASM::add_reg64_reg64_imm32(buf, R8, RSP, 8); ASM::mov_reg64_reg64(buf, R8, RDI);
// move the crash tag into the second return register. We add 1 to it because the 0 value // move the crash tag into the second return register. We add 1 to it because the 0 value
// is already used for "no crash occurred" // is already used for "no crash occurred"
ASM::add_reg64_reg64_imm32(buf, RDX, RDI, 1); ASM::add_reg64_reg64_imm32(buf, RDX, RSI, 1);
// the setlongjmp_buffer // the setlongjmp_buffer
ASM::data_pointer(buf, relocs, String::from("setlongjmp_buffer"), RDI); ASM::data_pointer(buf, relocs, String::from("setlongjmp_buffer"), RDI);
@ -2004,6 +2004,39 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
} }
} }
#[inline(always)]
fn sub_freg32_freg32_freg32(
buf: &mut Vec<'_, u8>,
dst: X86_64FloatReg,
src1: X86_64FloatReg,
src2: X86_64FloatReg,
) {
if dst == src1 {
subss_freg32_freg32(buf, dst, src2);
} else if dst == src2 {
subss_freg32_freg32(buf, dst, src1);
} else {
movss_freg32_freg32(buf, dst, src1);
subss_freg32_freg32(buf, dst, src2);
}
}
#[inline(always)]
fn sub_freg64_freg64_freg64(
buf: &mut Vec<'_, u8>,
dst: X86_64FloatReg,
src1: X86_64FloatReg,
src2: X86_64FloatReg,
) {
if dst == src1 {
subsd_freg64_freg64(buf, dst, src2);
} else if dst == src2 {
subsd_freg64_freg64(buf, dst, src1);
} else {
movsd_freg64_freg64(buf, dst, src1);
subsd_freg64_freg64(buf, dst, src2);
}
}
#[inline(always)] #[inline(always)]
fn call(buf: &mut Vec<'_, u8>, relocs: &mut Vec<'_, Relocation>, fn_name: String) { fn call(buf: &mut Vec<'_, u8>, relocs: &mut Vec<'_, Relocation>, fn_name: String) {
buf.extend([0xE8, 0x00, 0x00, 0x00, 0x00]); buf.extend([0xE8, 0x00, 0x00, 0x00, 0x00]);
@ -3052,124 +3085,78 @@ fn sar_reg64_reg64(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg) {
buf.extend([rex, 0xD3, 0xC0 | (7 << 3) | dst_mod]); buf.extend([rex, 0xD3, 0xC0 | (7 << 3) | dst_mod]);
} }
/// `ADDSD xmm1,xmm2/m64` -> Add the low double-precision floating-point value from xmm2/mem to xmm1 and store the result in xmm1. fn double_binary_operation(
#[inline(always)] buf: &mut Vec<'_, u8>,
fn addsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) { dst: X86_64FloatReg,
src: X86_64FloatReg,
float_width: FloatWidth,
op_code2: u8,
) {
let op_code1 = match float_width {
FloatWidth::F32 => 0xF3,
FloatWidth::F64 => 0xF2,
};
let dst_high = dst as u8 > 7; let dst_high = dst as u8 > 7;
let dst_mod = dst as u8 % 8; let dst_mod = dst as u8 % 8;
let src_high = src as u8 > 7; let src_high = src as u8 > 7;
let src_mod = src as u8 % 8; let src_mod = src as u8 % 8;
if dst_high || src_high { if dst_high || src_high {
buf.extend([ buf.extend([
0xF2, op_code1,
0x40 | ((dst_high as u8) << 2) | (src_high as u8), 0x40 | ((dst_high as u8) << 2) | (src_high as u8),
0x0F, 0x0F,
0x58, op_code2,
0xC0 | (dst_mod << 3) | (src_mod), 0xC0 | (dst_mod << 3) | (src_mod),
]) ])
} else { } else {
buf.extend([0xF2, 0x0F, 0x58, 0xC0 | (dst_mod << 3) | (src_mod)]) buf.extend([op_code1, 0x0F, op_code2, 0xC0 | (dst_mod << 3) | (src_mod)])
} }
} }
/// `ADDSD xmm1,xmm2/m64` -> Add the low double-precision floating-point value from xmm2/mem to xmm1 and store the result in xmm1.
#[inline(always)]
fn addsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
double_binary_operation(buf, dst, src, FloatWidth::F64, 0x58)
}
/// `ADDSS xmm1,xmm2/m64` -> Add the low single-precision floating-point value from xmm2/mem to xmm1 and store the result in xmm1. /// `ADDSS xmm1,xmm2/m64` -> Add the low single-precision floating-point value from xmm2/mem to xmm1 and store the result in xmm1.
#[inline(always)] #[inline(always)]
fn addss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) { fn addss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
let dst_high = dst as u8 > 7; double_binary_operation(buf, dst, src, FloatWidth::F32, 0x58)
let dst_mod = dst as u8 % 8; }
let src_high = src as u8 > 7;
let src_mod = src as u8 % 8; /// `SUBSD xmm1,xmm2/m64` -> Sub the low double-precision floating-point value from xmm2/mem to xmm1 and store the result in xmm1.
if dst_high || src_high { #[inline(always)]
buf.extend([ fn subsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
0xF3, double_binary_operation(buf, dst, src, FloatWidth::F64, 0x5C)
0x40 | ((dst_high as u8) << 2) | (src_high as u8), }
0x0F,
0x58, /// `SUBSS xmm1,xmm2/m64` -> Sub the low single-precision floating-point value from xmm2/mem to xmm1 and store the result in xmm1.
0xC0 | (dst_mod << 3) | (src_mod), #[inline(always)]
]) fn subss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
} else { double_binary_operation(buf, dst, src, FloatWidth::F32, 0x5C)
buf.extend([0xF3, 0x0F, 0x58, 0xC0 | (dst_mod << 3) | (src_mod)])
}
} }
/// `MULSD xmm1,xmm2/m64` -> Multiply the low double-precision floating-point value from xmm2/mem to xmm1 and store the result in xmm1.
#[inline(always)] #[inline(always)]
fn mulsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) { fn mulsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
let dst_high = dst as u8 > 7; double_binary_operation(buf, dst, src, FloatWidth::F64, 0x59)
let dst_mod = dst as u8 % 8;
let src_high = src as u8 > 7;
let src_mod = src as u8 % 8;
if dst_high || src_high {
buf.extend([
0xF2,
0x40 | ((dst_high as u8) << 2) | (src_high as u8),
0x0F,
0x59,
0xC0 | (dst_mod << 3) | (src_mod),
])
} else {
buf.extend([0xF2, 0x0F, 0x59, 0xC0 | (dst_mod << 3) | (src_mod)])
} }
#[inline(always)]
fn mulss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
double_binary_operation(buf, dst, src, FloatWidth::F32, 0x59)
} }
/// `DIVSS xmm1,xmm2/m64` -> Divide the low single-precision floating-point value from xmm2/mem to xmm1 and store the result in xmm1. /// `DIVSS xmm1,xmm2/m64` -> Divide the low single-precision floating-point value from xmm2/mem to xmm1 and store the result in xmm1.
#[inline(always)] #[inline(always)]
fn divss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) { fn divss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
let dst_high = dst as u8 > 7; double_binary_operation(buf, dst, src, FloatWidth::F32, 0x5E)
let dst_mod = dst as u8 % 8;
let src_high = src as u8 > 7;
let src_mod = src as u8 % 8;
if dst_high || src_high {
buf.extend([
0xF3,
0x40 | ((dst_high as u8) << 2) | (src_high as u8),
0x0F,
0x5E,
0xC0 | (dst_mod << 3) | (src_mod),
])
} else {
buf.extend([0xF3, 0x0F, 0x5E, 0xC0 | (dst_mod << 3) | (src_mod)])
}
} }
/// `DIVSD xmm1,xmm2/m64` -> Divide the low double-precision floating-point value from xmm2/mem to xmm1 and store the result in xmm1. /// `DIVSD xmm1,xmm2/m64` -> Divide the low double-precision floating-point value from xmm2/mem to xmm1 and store the result in xmm1.
#[inline(always)] #[inline(always)]
fn divsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) { fn divsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
let dst_high = dst as u8 > 7; double_binary_operation(buf, dst, src, FloatWidth::F64, 0x5E)
let dst_mod = dst as u8 % 8;
let src_high = src as u8 > 7;
let src_mod = src as u8 % 8;
if dst_high || src_high {
buf.extend([
0xF2,
0x40 | ((dst_high as u8) << 2) | (src_high as u8),
0x0F,
0x5E,
0xC0 | (dst_mod << 3) | (src_mod),
])
} else {
buf.extend([0xF2, 0x0F, 0x5E, 0xC0 | (dst_mod << 3) | (src_mod)])
}
}
/// `ADDSS xmm1,xmm2/m64` -> Add the low single-precision floating-point value from xmm2/mem to xmm1 and store the result in xmm1.
#[inline(always)]
fn mulss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
let dst_high = dst as u8 > 7;
let dst_mod = dst as u8 % 8;
let src_high = src as u8 > 7;
let src_mod = src as u8 % 8;
if dst_high || src_high {
buf.extend([
0xF3,
0x40 | ((dst_high as u8) << 2) | (src_high as u8),
0x0F,
0x59,
0xC0 | (dst_mod << 3) | (src_mod),
])
} else {
buf.extend([0xF3, 0x0F, 0x59, 0xC0 | (dst_mod << 3) | (src_mod)])
}
} }
#[inline(always)] #[inline(always)]

View file

@ -668,14 +668,22 @@ trait Backend<'a> {
&Literal::Int((crash_tag as u128).to_ne_bytes()), &Literal::Int((crash_tag as u128).to_ne_bytes()),
); );
// this function gets a RocStr, but the roc_panic defined by a platform expects a `*RocStr`.
// we store the value in a global variable and then use a pointer to this global
let panic_msg_ptr = self.debug_symbol("panic_msg_ptr");
let ignored = self.debug_symbol("ignored");
self.build_data_pointer(&panic_msg_ptr, "panic_msg".to_string());
self.load_literal_symbols(&[msg]);
self.build_ptr_store(ignored, panic_msg_ptr, msg, Layout::STR);
// Now that the arguments are needed, load them if they are literals. // Now that the arguments are needed, load them if they are literals.
let arguments = &[msg, error_message]; let arguments = &[panic_msg_ptr, error_message];
self.load_literal_symbols(arguments); self.load_literal_symbols(arguments);
self.build_fn_call( self.build_fn_call(
&Symbol::DEV_TMP2, &Symbol::DEV_TMP2,
String::from("roc_panic"), String::from("roc_panic"),
arguments, arguments,
&[Layout::STR, Layout::U32], &[Layout::U64, Layout::U32],
&Layout::UNIT, &Layout::UNIT,
); );
@ -1002,7 +1010,7 @@ trait Backend<'a> {
arg_layouts[0], *ret_layout, arg_layouts[0], *ret_layout,
"NumAdd: expected to have the same argument and return layout" "NumAdd: expected to have the same argument and return layout"
); );
self.build_num_add(sym, &args[0], &args[1], ret_layout) self.build_num_add_wrap(sym, &args[0], &args[1], ret_layout)
} }
LowLevel::NumAddChecked => { LowLevel::NumAddChecked => {
self.build_num_add_checked(sym, &args[0], &args[1], &arg_layouts[0], ret_layout) self.build_num_add_checked(sym, &args[0], &args[1], &arg_layouts[0], ret_layout)
@ -1072,13 +1080,84 @@ trait Backend<'a> {
); );
self.build_num_neg(sym, &args[0], ret_layout) self.build_num_neg(sym, &args[0], ret_layout)
} }
LowLevel::NumPowInt => self.build_fn_call( LowLevel::NumPowInt => {
let repr = self.interner().get_repr(arg_layouts[0]);
let LayoutRepr::Builtin(Builtin::Int(int_width)) = repr else {
unreachable!("invalid layout for NumPowInt")
};
self.build_fn_call(
sym, sym,
bitcode::NUM_POW_INT[IntWidth::I64].to_string(), bitcode::NUM_POW_INT[int_width].to_string(),
args,
arg_layouts,
ret_layout,
)
}
LowLevel::NumPow => {
let intrinsic = match self.interner().get_repr(arg_layouts[0]) {
LayoutRepr::Builtin(Builtin::Float(float_width)) => {
&bitcode::NUM_POW[float_width]
}
LayoutRepr::DEC => todo!("exponentiation for decimals"),
_ => unreachable!("invalid layout for NumPow"),
};
self.build_fn_call(sym, intrinsic.to_string(), args, arg_layouts, ret_layout)
}
LowLevel::NumFloor => {
let repr = self.interner().get_repr(*ret_layout);
let LayoutRepr::Builtin(Builtin::Int(int_width)) = repr else {
unreachable!("invalid return layout for NumFloor")
};
match arg_layouts[0] {
Layout::F32 => self.build_fn_call(
sym,
bitcode::NUM_FLOOR_F32[int_width].to_string(),
args, args,
arg_layouts, arg_layouts,
ret_layout, ret_layout,
), ),
Layout::F64 => self.build_fn_call(
sym,
bitcode::NUM_FLOOR_F64[int_width].to_string(),
args,
arg_layouts,
ret_layout,
),
Layout::DEC => todo!("NumFloor for decimals"),
_ => unreachable!("invalid layout for NumFloor"),
}
}
LowLevel::NumCeiling => {
let repr = self.interner().get_repr(*ret_layout);
let LayoutRepr::Builtin(Builtin::Int(int_width)) = repr else {
unreachable!("invalid return layout for NumCeiling")
};
match arg_layouts[0] {
Layout::F32 => self.build_fn_call(
sym,
bitcode::NUM_CEILING_F32[int_width].to_string(),
args,
arg_layouts,
ret_layout,
),
Layout::F64 => self.build_fn_call(
sym,
bitcode::NUM_CEILING_F64[int_width].to_string(),
args,
arg_layouts,
ret_layout,
),
Layout::DEC => todo!("NumCeiling for decimals"),
_ => unreachable!("invalid layout for NumCeiling"),
}
}
LowLevel::NumSub => { LowLevel::NumSub => {
debug_assert_eq!( debug_assert_eq!(
2, 2,
@ -1385,6 +1464,36 @@ trait Backend<'a> {
self.build_num_sqrt(*sym, args[0], float_width); self.build_num_sqrt(*sym, args[0], float_width);
} }
LowLevel::NumSin => {
let intrinsic = match arg_layouts[0] {
Layout::F64 => &bitcode::NUM_SIN[FloatWidth::F64],
Layout::F32 => &bitcode::NUM_SIN[FloatWidth::F32],
Layout::DEC => bitcode::DEC_SIN,
_ => unreachable!("invalid layout for sin"),
};
self.build_fn_call(sym, intrinsic.to_string(), args, arg_layouts, ret_layout)
}
LowLevel::NumCos => {
let intrinsic = match arg_layouts[0] {
Layout::F64 => &bitcode::NUM_COS[FloatWidth::F64],
Layout::F32 => &bitcode::NUM_COS[FloatWidth::F32],
Layout::DEC => bitcode::DEC_COS,
_ => unreachable!("invalid layout for cos"),
};
self.build_fn_call(sym, intrinsic.to_string(), args, arg_layouts, ret_layout)
}
LowLevel::NumTan => {
let intrinsic = match arg_layouts[0] {
Layout::F64 => &bitcode::NUM_TAN[FloatWidth::F64],
Layout::F32 => &bitcode::NUM_TAN[FloatWidth::F32],
Layout::DEC => bitcode::DEC_TAN,
_ => unreachable!("invalid layout for tan"),
};
self.build_fn_call(sym, intrinsic.to_string(), args, arg_layouts, ret_layout)
}
LowLevel::NumRound => self.build_fn_call( LowLevel::NumRound => self.build_fn_call(
sym, sym,
bitcode::NUM_ROUND_F64[IntWidth::I64].to_string(), bitcode::NUM_ROUND_F64[IntWidth::I64].to_string(),
@ -1962,12 +2071,15 @@ trait Backend<'a> {
"NumIsZero: expected to have return layout of type Bool" "NumIsZero: expected to have return layout of type Bool"
); );
let literal = match self.interner().get_repr(arg_layouts[0]) {
LayoutRepr::Builtin(Builtin::Int(_)) => Literal::Int(0i128.to_ne_bytes()),
LayoutRepr::Builtin(Builtin::Float(_)) => Literal::Float(0.0),
LayoutRepr::DEC => Literal::Decimal([0; 16]),
_ => unreachable!("invalid layout for sin"),
};
self.load_literal_symbols(args); self.load_literal_symbols(args);
self.load_literal( self.load_literal(&Symbol::DEV_TMP, &arg_layouts[0], &literal);
&Symbol::DEV_TMP,
&arg_layouts[0],
&Literal::Int(0i128.to_ne_bytes()),
);
self.build_eq(sym, &args[0], &Symbol::DEV_TMP, &arg_layouts[0]); self.build_eq(sym, &args[0], &Symbol::DEV_TMP, &arg_layouts[0]);
self.free_symbol(&Symbol::DEV_TMP) self.free_symbol(&Symbol::DEV_TMP)
} }
@ -2086,6 +2198,14 @@ trait Backend<'a> {
return_layout: &InLayout<'a>, return_layout: &InLayout<'a>,
); );
fn build_num_add_wrap(
&mut self,
dst: &Symbol,
src1: &Symbol,
src2: &Symbol,
layout: &InLayout<'a>,
);
/// build_num_sub_checked stores the sum of src1 and src2 into dst. /// build_num_sub_checked stores the sum of src1 and src2 into dst.
fn build_num_sub_checked( fn build_num_sub_checked(
&mut self, &mut self,

View file

@ -159,6 +159,30 @@ fn define_setlongjmp_buffer(output: &mut Object) -> SymbolId {
symbol_id symbol_id
} }
// needed to implement Crash when setjmp/longjmp is used
fn define_panic_msg(output: &mut Object) -> SymbolId {
let bss_section = output.section_id(StandardSection::Data);
// 3 words for a RocStr
const SIZE: usize = 3 * core::mem::size_of::<u64>();
let symbol = Symbol {
name: b"panic_msg".to_vec(),
value: 0,
size: SIZE as u64,
kind: SymbolKind::Data,
scope: SymbolScope::Linkage,
weak: false,
section: SymbolSection::Section(bss_section),
flags: SymbolFlags::None,
};
let symbol_id = output.add_symbol(symbol);
output.add_symbol_data(symbol_id, bss_section, &[0x00; SIZE], 8);
symbol_id
}
fn generate_setjmp<'a, B: Backend<'a>>(backend: &mut B, output: &mut Object) { fn generate_setjmp<'a, B: Backend<'a>>(backend: &mut B, output: &mut Object) {
let text_section = output.section_id(StandardSection::Text); let text_section = output.section_id(StandardSection::Text);
let proc_symbol = Symbol { let proc_symbol = Symbol {
@ -334,7 +358,7 @@ fn generate_wrapper<'a, B: Backend<'a>>(
let (proc_data, offset) = backend.build_wrapped_jmp(); let (proc_data, offset) = backend.build_wrapped_jmp();
let proc_offset = output.add_symbol_data(proc_id, text_section, proc_data, 16); let proc_offset = output.add_symbol_data(proc_id, text_section, proc_data, 16);
let name = wraps.as_str().as_bytes(); let name = wraps.as_bytes();
// If the symbol is an undefined zig builtin, we need to add it here. // If the symbol is an undefined zig builtin, we need to add it here.
let symbol = Symbol { let symbol = Symbol {
name: name.to_vec(), name: name.to_vec(),
@ -422,6 +446,7 @@ fn build_object<'a, B: Backend<'a>>(
*/ */
if backend.env().mode.generate_roc_panic() { if backend.env().mode.generate_roc_panic() {
define_panic_msg(&mut output);
define_setlongjmp_buffer(&mut output); define_setlongjmp_buffer(&mut output);
generate_roc_panic(&mut backend, &mut output); generate_roc_panic(&mut backend, &mut output);

View file

@ -949,6 +949,12 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
} }
pub fn new_debug_info(module: &Module<'ctx>) -> (DebugInfoBuilder<'ctx>, DICompileUnit<'ctx>) { pub fn new_debug_info(module: &Module<'ctx>) -> (DebugInfoBuilder<'ctx>, DICompileUnit<'ctx>) {
let debug_metadata_version = module.get_context().i32_type().const_int(3, false);
module.add_basic_value_flag(
"Debug Info Version",
inkwell::module::FlagBehavior::Warning,
debug_metadata_version,
);
module.create_debug_info_builder( module.create_debug_info_builder(
true, true,
/* language */ inkwell::debug_info::DWARFSourceLanguage::C, /* language */ inkwell::debug_info::DWARFSourceLanguage::C,
@ -4104,7 +4110,6 @@ fn const_i128<'ctx>(env: &Env<'_, 'ctx, '_>, value: i128) -> IntValue<'ctx> {
fn const_u128<'ctx>(env: &Env<'_, 'ctx, '_>, value: u128) -> IntValue<'ctx> { fn const_u128<'ctx>(env: &Env<'_, 'ctx, '_>, value: u128) -> IntValue<'ctx> {
// truncate the lower 64 bits // truncate the lower 64 bits
let value = value;
let a = value as u64; let a = value as u64;
// get the upper 64 bits // get the upper 64 bits
@ -5067,6 +5072,11 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx>(
} }
pub fn get_sjlj_buffer<'ctx>(env: &Env<'_, 'ctx, '_>) -> PointerValue<'ctx> { pub fn get_sjlj_buffer<'ctx>(env: &Env<'_, 'ctx, '_>) -> PointerValue<'ctx> {
let word_type = match env.target_info.ptr_width() {
PtrWidth::Bytes4 => env.context.i32_type(),
PtrWidth::Bytes8 => env.context.i64_type(),
};
// The size of jump_buf is target-dependent. // The size of jump_buf is target-dependent.
// - AArch64 needs 3 machine-sized words // - AArch64 needs 3 machine-sized words
// - LLVM says the following about the SJLJ intrinsic: // - LLVM says the following about the SJLJ intrinsic:
@ -5078,11 +5088,15 @@ pub fn get_sjlj_buffer<'ctx>(env: &Env<'_, 'ctx, '_>) -> PointerValue<'ctx> {
// The following three words are available for use in a target-specific manner. // The following three words are available for use in a target-specific manner.
// //
// So, let's create a 5-word buffer. // So, let's create a 5-word buffer.
let word_type = match env.target_info.ptr_width() { let size = if env.target_info.operating_system == roc_target::OperatingSystem::Windows {
PtrWidth::Bytes4 => env.context.i32_type(), // Due to https://github.com/llvm/llvm-project/issues/72908
PtrWidth::Bytes8 => env.context.i64_type(), // on windows, we store the register contents into this buffer directly!
30
} else {
5
}; };
let type_ = word_type.array_type(5);
let type_ = word_type.array_type(size);
let global = match env.module.get_global("roc_sjlj_buffer") { let global = match env.module.get_global("roc_sjlj_buffer") {
Some(global) => global, Some(global) => global,
@ -5100,9 +5114,12 @@ pub fn get_sjlj_buffer<'ctx>(env: &Env<'_, 'ctx, '_>) -> PointerValue<'ctx> {
pub fn build_setjmp_call<'ctx>(env: &Env<'_, 'ctx, '_>) -> BasicValueEnum<'ctx> { pub fn build_setjmp_call<'ctx>(env: &Env<'_, 'ctx, '_>) -> BasicValueEnum<'ctx> {
let jmp_buf = get_sjlj_buffer(env); let jmp_buf = get_sjlj_buffer(env);
if cfg!(target_arch = "aarch64") { if env.target_info.architecture == roc_target::Architecture::Aarch64 {
// Due to https://github.com/roc-lang/roc/issues/2965, we use a setjmp we linked in from Zig // Due to https://github.com/roc-lang/roc/issues/2965, we use a setjmp we linked in from Zig
call_bitcode_fn(env, &[jmp_buf.into()], bitcode::UTILS_SETJMP) call_bitcode_fn(env, &[jmp_buf.into()], bitcode::UTILS_SETJMP)
} else if env.target_info.operating_system == roc_target::OperatingSystem::Windows {
// Due to https://github.com/llvm/llvm-project/issues/72908, we use a setjmp defined as asm in Zig
call_bitcode_fn(env, &[jmp_buf.into()], bitcode::UTILS_WINDOWS_SETJMP)
} else { } else {
// Anywhere else, use the LLVM intrinsic. // Anywhere else, use the LLVM intrinsic.
// https://llvm.org/docs/ExceptionHandling.html#llvm-eh-sjlj-setjmp // https://llvm.org/docs/ExceptionHandling.html#llvm-eh-sjlj-setjmp

View file

@ -315,11 +315,18 @@ pub fn add_sjlj_roc_panic(env: &Env<'_, '_, '_>) {
pub fn build_longjmp_call(env: &Env) { pub fn build_longjmp_call(env: &Env) {
let jmp_buf = get_sjlj_buffer(env); let jmp_buf = get_sjlj_buffer(env);
if cfg!(target_arch = "aarch64") { if env.target_info.architecture == roc_target::Architecture::Aarch64 {
// Call the Zig-linked longjmp: `void longjmp(i32*, i32)` // Due to https://github.com/roc-lang/roc/issues/2965, we use a setjmp we linked in from Zig
let tag = env.context.i32_type().const_int(1, false); let tag = env.context.i32_type().const_int(1, false);
let _call = let _call =
call_void_bitcode_fn(env, &[jmp_buf.into(), tag.into()], bitcode::UTILS_LONGJMP); call_void_bitcode_fn(env, &[jmp_buf.into(), tag.into()], bitcode::UTILS_LONGJMP);
} else if env.target_info.operating_system == roc_target::OperatingSystem::Windows {
let tag = env.context.i32_type().const_int(1, false);
let _call = call_void_bitcode_fn(
env,
&[jmp_buf.into(), tag.into()],
bitcode::UTILS_WINDOWS_LONGJMP,
);
} else { } else {
// Call the LLVM-intrinsic longjmp: `void @llvm.eh.sjlj.longjmp(i8* %setjmp_buf)` // Call the LLVM-intrinsic longjmp: `void @llvm.eh.sjlj.longjmp(i8* %setjmp_buf)`
let jmp_buf_i8p = env.builder.new_build_pointer_cast( let jmp_buf_i8p = env.builder.new_build_pointer_cast(

View file

@ -1853,6 +1853,11 @@ fn build_float_binop<'ctx>(
let bd = env.builder; let bd = env.builder;
let float_type = match float_width {
FloatWidth::F32 => env.context.f32_type(),
FloatWidth::F64 => env.context.f64_type(),
};
match op { match op {
NumAdd => bd.new_build_float_add(lhs, rhs, "add_float").into(), NumAdd => bd.new_build_float_add(lhs, rhs, "add_float").into(),
NumAddChecked => { NumAddChecked => {
@ -1865,10 +1870,8 @@ fn build_float_binop<'ctx>(
.into_int_value(); .into_int_value();
let is_infinite = bd.new_build_not(is_finite, "negate"); let is_infinite = bd.new_build_not(is_finite, "negate");
let struct_type = context.struct_type( let struct_type =
&[context.f64_type().into(), context.bool_type().into()], context.struct_type(&[float_type.into(), context.bool_type().into()], false);
false,
);
let struct_value = { let struct_value = {
let v1 = struct_type.const_zero(); let v1 = struct_type.const_zero();
@ -1894,10 +1897,8 @@ fn build_float_binop<'ctx>(
.into_int_value(); .into_int_value();
let is_infinite = bd.new_build_not(is_finite, "negate"); let is_infinite = bd.new_build_not(is_finite, "negate");
let struct_type = context.struct_type( let struct_type =
&[context.f64_type().into(), context.bool_type().into()], context.struct_type(&[float_type.into(), context.bool_type().into()], false);
false,
);
let struct_value = { let struct_value = {
let v1 = struct_type.const_zero(); let v1 = struct_type.const_zero();
@ -1924,10 +1925,8 @@ fn build_float_binop<'ctx>(
.into_int_value(); .into_int_value();
let is_infinite = bd.new_build_not(is_finite, "negate"); let is_infinite = bd.new_build_not(is_finite, "negate");
let struct_type = context.struct_type( let struct_type =
&[context.f64_type().into(), context.bool_type().into()], context.struct_type(&[float_type.into(), context.bool_type().into()], false);
false,
);
let struct_value = { let struct_value = {
let v1 = struct_type.const_zero(); let v1 = struct_type.const_zero();

View file

@ -1295,14 +1295,24 @@ fn build_rec_union_recursive_decrement<'a, 'ctx>(
_ => tag_id, _ => tag_id,
}; };
let block = env.context.append_basic_block(parent, "tag_id_decrement");
env.builder.position_at_end(block);
// if none of the fields are or contain anything refcounted, just move on // if none of the fields are or contain anything refcounted, just move on
if fields_need_no_refcounting(layout_interner, field_layouts) { if fields_need_no_refcounting(layout_interner, field_layouts) {
continue; // Still make sure to decrement the refcount of the union as a whole.
if let DecOrReuse::Dec = decrement_or_reuse {
let union_layout = LayoutRepr::Union(union_layout);
refcount_ptr.modify(call_mode, union_layout, env, layout_interner);
} }
let block = env.context.append_basic_block(parent, "tag_id_decrement"); // this function returns void
builder.new_build_return(None);
env.builder.position_at_end(block); cases.push((tag_id_int_type.const_int(tag_id as u64, false), block));
continue;
}
let fields_struct = LayoutRepr::struct_(field_layouts); let fields_struct = LayoutRepr::struct_(field_layouts);
let wrapper_type = basic_type_from_layout(env, layout_interner, fields_struct); let wrapper_type = basic_type_from_layout(env, layout_interner, fields_struct);
@ -1370,13 +1380,10 @@ fn build_rec_union_recursive_decrement<'a, 'ctx>(
// and store them on the stack, then modify (and potentially free) the current cell, then // and store them on the stack, then modify (and potentially free) the current cell, then
// actually inc/dec the fields. // actually inc/dec the fields.
match decrement_or_reuse { if let DecOrReuse::Dec = decrement_or_reuse {
DecOrReuse::Reuse => {}
DecOrReuse::Dec => {
let union_layout = LayoutRepr::Union(union_layout); let union_layout = LayoutRepr::Union(union_layout);
refcount_ptr.modify(call_mode, union_layout, env, layout_interner); refcount_ptr.modify(call_mode, union_layout, env, layout_interner);
} }
}
for (field, field_layout) in deferred_nonrec { for (field, field_layout) in deferred_nonrec {
modify_refcount_layout_help( modify_refcount_layout_help(

View file

@ -1,4 +0,0 @@
*.wasm
*.wat
/notes.md
/tmp

File diff suppressed because it is too large Load diff

View file

@ -1 +0,0 @@
/tmp

View file

@ -325,7 +325,7 @@ fn import_transitive_alias() {
( (
"RBTree", "RBTree",
indoc!( indoc!(
r#" r"
interface RBTree exposes [RedBlackTree, empty] imports [] interface RBTree exposes [RedBlackTree, empty] imports []
# The color of a node. Leaves are considered Black. # The color of a node. Leaves are considered Black.
@ -337,18 +337,18 @@ fn import_transitive_alias() {
empty : RedBlackTree k v empty : RedBlackTree k v
empty = empty =
Empty Empty
"# "
), ),
), ),
( (
"Other", "Other",
indoc!( indoc!(
r#" r"
interface Other exposes [empty] imports [RBTree] interface Other exposes [empty] imports [RBTree]
empty : RBTree.RedBlackTree I64 I64 empty : RBTree.RedBlackTree I64 I64
empty = RBTree.empty empty = RBTree.empty
"# "
), ),
), ),
]; ];
@ -628,11 +628,11 @@ fn parse_problem() {
let modules = vec![( let modules = vec![(
"Main", "Main",
indoc!( indoc!(
r#" r"
interface Main exposes [main] imports [] interface Main exposes [main] imports []
main = [ main = [
"# "
), ),
)]; )];
@ -820,23 +820,23 @@ fn opaque_wrapped_unwrapped_outside_defining_module() {
( (
"Age", "Age",
indoc!( indoc!(
r#" r"
interface Age exposes [Age] imports [] interface Age exposes [Age] imports []
Age := U32 Age := U32
"# "
), ),
), ),
( (
"Main", "Main",
indoc!( indoc!(
r#" r"
interface Main exposes [twenty, readAge] imports [Age.{ Age }] interface Main exposes [twenty, readAge] imports [Age.{ Age }]
twenty = @Age 20 twenty = @Age 20
readAge = \@Age n -> n readAge = \@Age n -> n
"# "
), ),
), ),
]; ];
@ -846,7 +846,7 @@ fn opaque_wrapped_unwrapped_outside_defining_module() {
assert_eq!( assert_eq!(
err, err,
indoc!( indoc!(
r#" r"
OPAQUE TYPE DECLARED OUTSIDE SCOPE ...rapped_outside_defining_module/Main OPAQUE TYPE DECLARED OUTSIDE SCOPE ...rapped_outside_defining_module/Main
The unwrapped opaque type Age referenced here: The unwrapped opaque type Age referenced here:
@ -883,7 +883,7 @@ fn opaque_wrapped_unwrapped_outside_defining_module() {
^^^^^^^^^^^ ^^^^^^^^^^^
Since Age isn't used, you don't need to import it. Since Age isn't used, you don't need to import it.
"# "
), ),
"\n{}", "\n{}",
err err
@ -993,11 +993,11 @@ fn module_doesnt_match_file_path() {
let modules = vec![( let modules = vec![(
"Age", "Age",
indoc!( indoc!(
r#" r"
interface NotAge exposes [Age] imports [] interface NotAge exposes [Age] imports []
Age := U32 Age := U32
"# "
), ),
)]; )];
@ -1005,7 +1005,7 @@ fn module_doesnt_match_file_path() {
assert_eq!( assert_eq!(
err, err,
indoc!( indoc!(
r#" r"
WEIRD MODULE NAME tmp/module_doesnt_match_file_path/Age WEIRD MODULE NAME tmp/module_doesnt_match_file_path/Age
This module name does not correspond with the file path it is defined This module name does not correspond with the file path it is defined
@ -1016,7 +1016,7 @@ fn module_doesnt_match_file_path() {
Module names must correspond with the file paths they are defined in. Module names must correspond with the file paths they are defined in.
For example, I expect to see BigNum defined in BigNum.roc, or Math.Sin For example, I expect to see BigNum defined in BigNum.roc, or Math.Sin
defined in Math/Sin.roc."# defined in Math/Sin.roc."
), ),
"\n{}", "\n{}",
err err
@ -1028,9 +1028,9 @@ fn module_cyclic_import_itself() {
let modules = vec![( let modules = vec![(
"Age", "Age",
indoc!( indoc!(
r#" r"
interface Age exposes [] imports [Age] interface Age exposes [] imports [Age]
"# "
), ),
)]; )];
@ -1038,7 +1038,7 @@ fn module_cyclic_import_itself() {
assert_eq!( assert_eq!(
err, err,
indoc!( indoc!(
r#" r"
IMPORT CYCLE tmp/module_cyclic_import_itself/Age IMPORT CYCLE tmp/module_cyclic_import_itself/Age
I can't compile Age because it depends on itself through the following I can't compile Age because it depends on itself through the following
@ -1052,7 +1052,7 @@ fn module_cyclic_import_itself() {
Cyclic dependencies are not allowed in Roc! Can you restructure a Cyclic dependencies are not allowed in Roc! Can you restructure a
module in this import chain so that it doesn't have to depend on module in this import chain so that it doesn't have to depend on
itself?"# itself?"
), ),
"\n{}", "\n{}",
err err
@ -1065,17 +1065,17 @@ fn module_cyclic_import_transitive() {
( (
"Age", "Age",
indoc!( indoc!(
r#" r"
interface Age exposes [] imports [Person] interface Age exposes [] imports [Person]
"# "
), ),
), ),
( (
"Person", "Person",
indoc!( indoc!(
r#" r"
interface Person exposes [] imports [Age] interface Person exposes [] imports [Age]
"# "
), ),
), ),
]; ];
@ -1084,7 +1084,7 @@ fn module_cyclic_import_transitive() {
assert_eq!( assert_eq!(
err, err,
indoc!( indoc!(
r#" r"
IMPORT CYCLE tmp/module_cyclic_import_transitive/Age.roc IMPORT CYCLE tmp/module_cyclic_import_transitive/Age.roc
I can't compile Age because it depends on itself through the following I can't compile Age because it depends on itself through the following
@ -1100,7 +1100,7 @@ fn module_cyclic_import_transitive() {
Cyclic dependencies are not allowed in Roc! Can you restructure a Cyclic dependencies are not allowed in Roc! Can you restructure a
module in this import chain so that it doesn't have to depend on module in this import chain so that it doesn't have to depend on
itself?"# itself?"
), ),
"\n{}", "\n{}",
err err
@ -1113,17 +1113,17 @@ fn nested_module_has_incorrect_name() {
( (
"Dep/Foo.roc", "Dep/Foo.roc",
indoc!( indoc!(
r#" r"
interface Foo exposes [] imports [] interface Foo exposes [] imports []
"# "
), ),
), ),
( (
"I.roc", "I.roc",
indoc!( indoc!(
r#" r"
interface I exposes [] imports [Dep.Foo] interface I exposes [] imports [Dep.Foo]
"# "
), ),
), ),
]; ];
@ -1132,7 +1132,7 @@ fn nested_module_has_incorrect_name() {
assert_eq!( assert_eq!(
err, err,
indoc!( indoc!(
r#" r"
INCORRECT MODULE NAME tmp/nested_module_has_incorrect_name/Dep/Foo.roc INCORRECT MODULE NAME tmp/nested_module_has_incorrect_name/Dep/Foo.roc
This module has a different name than I expected: This module has a different name than I expected:
@ -1142,7 +1142,7 @@ fn nested_module_has_incorrect_name() {
Based on the nesting and use of this module, I expect it to have name Based on the nesting and use of this module, I expect it to have name
Dep.Foo"# Dep.Foo"
), ),
"\n{}", "\n{}",
err err

View file

@ -1047,7 +1047,7 @@ fn insert_refcount_operations_binding<'a>(
closure_env_layout: _, closure_env_layout: _,
/// update mode of the higher order lowlevel itself // update mode of the higher order lowlevel itself
update_mode: _, update_mode: _,
passed_function, passed_function,

View file

@ -3085,7 +3085,9 @@ fn specialize_host_specializations<'a>(
let from_app = offset_variable(from_app); let from_app = offset_variable(from_app);
let index = specialize_external_help(env, procs, layout_cache, lambda_name, from_app); let index = specialize_external_help(env, procs, layout_cache, lambda_name, from_app);
let Some(from_platform) = opt_from_platform else { continue }; let Some(from_platform) = opt_from_platform else {
continue;
};
// now run the lambda set numbering scheme // now run the lambda set numbering scheme
let hels = find_lambda_sets(env.arena, env.subs, from_platform); let hels = find_lambda_sets(env.arena, env.subs, from_platform);
@ -3146,7 +3148,9 @@ fn specialize_host_specializations<'a>(
}; };
let in_progress = &mut procs.specialized.procedures[index.0]; let in_progress = &mut procs.specialized.procedures[index.0];
let InProgressProc::Done(proc) = in_progress else { unreachable!() }; let InProgressProc::Done(proc) = in_progress else {
unreachable!()
};
procs.host_exposed_lambda_sets.push((proc.name, key, hels)); procs.host_exposed_lambda_sets.push((proc.name, key, hels));
} }

View file

@ -442,7 +442,7 @@ pub trait LayoutInterner<'a>: Sized {
pub struct InLayout<'a>(usize, std::marker::PhantomData<&'a ()>); pub struct InLayout<'a>(usize, std::marker::PhantomData<&'a ()>);
impl<'a> Clone for InLayout<'a> { impl<'a> Clone for InLayout<'a> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self(self.0, Default::default()) *self
} }
} }

View file

@ -122,7 +122,8 @@ pub enum StrSegment<'a> {
Plaintext(&'a str), // e.g. "foo" Plaintext(&'a str), // e.g. "foo"
Unicode(Loc<&'a str>), // e.g. "00A0" in "\u(00A0)" Unicode(Loc<&'a str>), // e.g. "00A0" in "\u(00A0)"
EscapedChar(EscapedChar), // e.g. '\n' in "Hello!\n" EscapedChar(EscapedChar), // e.g. '\n' in "Hello!\n"
Interpolated(Loc<&'a Expr<'a>>), // e.g. (name) in "Hi, \(name)!" Interpolated(Loc<&'a Expr<'a>>),
DeprecatedInterpolated(Loc<&'a Expr<'a>>), // The old "$(...)" syntax - will be removed someday
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
@ -141,6 +142,7 @@ pub enum EscapedChar {
SingleQuote, // \' SingleQuote, // \'
Backslash, // \\ Backslash, // \\
CarriageReturn, // \r CarriageReturn, // \r
Dollar, // \$
} }
impl EscapedChar { impl EscapedChar {
@ -155,6 +157,7 @@ impl EscapedChar {
CarriageReturn => 'r', CarriageReturn => 'r',
Tab => 't', Tab => 't',
Newline => 'n', Newline => 'n',
Dollar => '$',
} }
} }
@ -168,6 +171,7 @@ impl EscapedChar {
CarriageReturn => '\r', CarriageReturn => '\r',
Tab => '\t', Tab => '\t',
Newline => '\n', Newline => '\n',
Dollar => '$',
} }
} }
} }
@ -213,6 +217,7 @@ impl<'a> TryFrom<StrSegment<'a>> for SingleQuoteSegment<'a> {
StrSegment::Unicode(s) => Ok(SingleQuoteSegment::Unicode(s)), StrSegment::Unicode(s) => Ok(SingleQuoteSegment::Unicode(s)),
StrSegment::EscapedChar(s) => Ok(SingleQuoteSegment::EscapedChar(s)), StrSegment::EscapedChar(s) => Ok(SingleQuoteSegment::EscapedChar(s)),
StrSegment::Interpolated(_) => Err(ESingleQuote::InterpolationNotAllowed), StrSegment::Interpolated(_) => Err(ESingleQuote::InterpolationNotAllowed),
StrSegment::DeprecatedInterpolated(_) => Err(ESingleQuote::InterpolationNotAllowed),
} }
} }
} }
@ -1587,7 +1592,9 @@ impl<'a> Malformed for StrSegment<'a> {
fn is_malformed(&self) -> bool { fn is_malformed(&self) -> bool {
match self { match self {
StrSegment::Plaintext(_) | StrSegment::Unicode(_) | StrSegment::EscapedChar(_) => false, StrSegment::Plaintext(_) | StrSegment::Unicode(_) | StrSegment::EscapedChar(_) => false,
StrSegment::Interpolated(expr) => expr.is_malformed(), StrSegment::Interpolated(expr) | StrSegment::DeprecatedInterpolated(expr) => {
expr.is_malformed()
}
} }
} }
} }

View file

@ -82,7 +82,7 @@ impl<'a> Src64<'a> {
} }
// Safety: we got capacity by rounding up to the nearest 64B // Safety: we got capacity by rounding up to the nearest 64B
let dest = unsafe { allocate_chunks(arena, capacity)? }.as_ptr() as *mut u8; let dest = unsafe { allocate_chunks(arena, capacity)? }.as_ptr();
// Safety: `dest` has a length of `capacity`, which has been rounded up to a multiple of 64. // Safety: `dest` has a length of `capacity`, which has been rounded up to a multiple of 64.
unsafe { unsafe {
@ -264,8 +264,7 @@ impl<'a> Src64<'a> {
// Safety: bytes_ptr came from an allocation of `capacity` bytes, it's had // Safety: bytes_ptr came from an allocation of `capacity` bytes, it's had
// newlines filled at the end, and `file_size` bytes written over the rest. // newlines filled at the end, and `file_size` bytes written over the rest.
let bytes = let bytes = unsafe { core::slice::from_raw_parts_mut(buf.as_ptr(), capacity) };
unsafe { core::slice::from_raw_parts_mut(buf.as_ptr() as *mut u8, capacity) };
Ok(Self { bytes }) Ok(Self { bytes })
} }

View file

@ -349,6 +349,68 @@ pub fn parse_str_like_literal<'a>() -> impl Parser<'a, StrLikeLiteral<'a>, EStri
return Err((MadeProgress, EString::EndlessSingleLine(start_state.pos()))); return Err((MadeProgress, EString::EndlessSingleLine(start_state.pos())));
} }
} }
b'$' => {
// This is for the byte we're about to parse.
segment_parsed_bytes += 1;
// iff the '$' is followed by '(', this is string interpolation.
if let Some(b'(') = bytes.next() {
// We're about to begin string interpolation!
//
// End the previous segment so we can begin a new one.
// Retroactively end it right before the `$` char we parsed.
// (We can't use end_segment! here because it ends it right after
// the just-parsed character, which here would be '(' rather than '$')
// Don't push anything if the string would be empty.
if segment_parsed_bytes > 2 {
// exclude the 2 chars we just parsed, namely '$' and '('
let string_bytes = &state.bytes()[0..(segment_parsed_bytes - 2)];
match std::str::from_utf8(string_bytes) {
Ok(string) => {
state.advance_mut(string.len());
segments.push(StrSegment::Plaintext(string));
}
Err(_) => {
return Err((
MadeProgress,
EString::Space(BadInputError::BadUtf8, state.pos()),
));
}
}
}
// Advance past the `$(`
state.advance_mut(2);
let original_byte_count = state.bytes().len();
// Parse an arbitrary expression, followed by ')'
let (_progress, loc_expr, new_state) = skip_second!(
specialize_ref(
EString::Format,
loc(allocated(reset_min_indent(expr::expr_help())))
),
word1(b')', EString::FormatEnd)
)
.parse(arena, state, min_indent)?;
// Advance the iterator past the expr we just parsed.
for _ in 0..(original_byte_count - new_state.bytes().len()) {
bytes.next();
}
segments.push(StrSegment::Interpolated(loc_expr));
// Reset the segment
segment_parsed_bytes = 0;
state = new_state;
}
// If the '$' wasn't followed by '(', then this wasn't interpolation,
// and we don't need to do anything special.
}
b'\\' => { b'\\' => {
// We're about to begin an escaped segment of some sort! // We're about to begin an escaped segment of some sort!
// //
@ -386,7 +448,7 @@ pub fn parse_str_like_literal<'a>() -> impl Parser<'a, StrLikeLiteral<'a>, EStri
bytes.next(); bytes.next();
} }
segments.push(StrSegment::Interpolated(loc_expr)); segments.push(StrSegment::DeprecatedInterpolated(loc_expr));
// Reset the segment // Reset the segment
segment_parsed_bytes = 0; segment_parsed_bytes = 0;
@ -437,6 +499,9 @@ pub fn parse_str_like_literal<'a>() -> impl Parser<'a, StrLikeLiteral<'a>, EStri
Some(b'n') => { Some(b'n') => {
escaped_char!(EscapedChar::Newline); escaped_char!(EscapedChar::Newline);
} }
Some(b'$') => {
escaped_char!(EscapedChar::Dollar);
}
_ => { _ => {
// Invalid escape! A backslash must be followed // Invalid escape! A backslash must be followed
// by either an open paren or else one of the // by either an open paren or else one of the

View file

@ -158,9 +158,20 @@ mod test_parse {
// INTERPOLATION // INTERPOLATION
#[test]
fn escaped_interpolation() {
assert_segments(r#""Hi, \$(name)!""#, |arena| {
bumpalo::vec![in arena;
Plaintext("Hi, "),
EscapedChar(EscapedChar::Dollar),
Plaintext("(name)!"),
]
});
}
#[test] #[test]
fn string_with_interpolation_in_middle() { fn string_with_interpolation_in_middle() {
assert_segments(r#""Hi, \(name)!""#, |arena| { assert_segments(r#""Hi, $(name)!""#, |arena| {
let expr = arena.alloc(Var { let expr = arena.alloc(Var {
module_name: "", module_name: "",
ident: "name", ident: "name",
@ -176,7 +187,7 @@ mod test_parse {
#[test] #[test]
fn string_with_interpolation_in_front() { fn string_with_interpolation_in_front() {
assert_segments(r#""\(name), hi!""#, |arena| { assert_segments(r#""$(name), hi!""#, |arena| {
let expr = arena.alloc(Var { let expr = arena.alloc(Var {
module_name: "", module_name: "",
ident: "name", ident: "name",
@ -191,7 +202,7 @@ mod test_parse {
#[test] #[test]
fn string_with_interpolation_in_back() { fn string_with_interpolation_in_back() {
assert_segments(r#""Hello \(name)""#, |arena| { assert_segments(r#""Hello $(name)""#, |arena| {
let expr = arena.alloc(Var { let expr = arena.alloc(Var {
module_name: "", module_name: "",
ident: "name", ident: "name",
@ -206,7 +217,7 @@ mod test_parse {
#[test] #[test]
fn string_with_multiple_interpolations() { fn string_with_multiple_interpolations() {
assert_segments(r#""Hi, \(name)! How is \(project) going?""#, |arena| { assert_segments(r#""Hi, $(name)! How is $(project) going?""#, |arena| {
let expr1 = arena.alloc(Var { let expr1 = arena.alloc(Var {
module_name: "", module_name: "",
ident: "name", ident: "name",
@ -227,6 +238,32 @@ mod test_parse {
}); });
} }
#[test]
fn string_with_non_interpolation_dollar_signs() {
assert_segments(
r#""$a Hi, $(name)! $b How is $(project) going? $c""#,
|arena| {
let expr1 = arena.alloc(Var {
module_name: "",
ident: "name",
});
let expr2 = arena.alloc(Var {
module_name: "",
ident: "project",
});
bumpalo::vec![in arena;
Plaintext("$a Hi, "),
Interpolated(Loc::new(10, 14, expr1)),
Plaintext("! $b How is "),
Interpolated(Loc::new(29, 36, expr2)),
Plaintext(" going? $c")
]
},
);
}
#[test] #[test]
fn empty_source_file() { fn empty_source_file() {
assert_parsing_fails("", SyntaxError::Eof(Region::zero())); assert_parsing_fails("", SyntaxError::Eof(Region::zero()));
@ -272,11 +309,11 @@ mod test_parse {
let arena = Bump::new(); let arena = Bump::new();
let src = indoc!( let src = indoc!(
r#" r"
foo = \list -> foo = \list ->
isTest = \_ -> 5 isTest = \_ -> 5
List.map list isTest List.map list isTest
"# "
); );
let actual = module_defs() let actual = module_defs()
.parse(&arena, State::new(src.as_bytes()), 0) .parse(&arena, State::new(src.as_bytes()), 0)
@ -295,12 +332,12 @@ mod test_parse {
// highlights a problem with the else branch demanding a newline after its expression // highlights a problem with the else branch demanding a newline after its expression
let src = indoc!( let src = indoc!(
r#" r"
main = main =
v = \y -> if x then y else z v = \y -> if x then y else z
1 1
"# "
); );
let state = State::new(src.as_bytes()); let state = State::new(src.as_bytes());

View file

@ -540,6 +540,7 @@ pub(crate) fn type_to_var_help(
) )
.expect("extension var could not be seen as a tag union"); .expect("extension var could not be seen as a tag union");
#[allow(clippy::never_loop)]
for _ in it { for _ in it {
unreachable!("we assert that the ext var is empty; otherwise we'd already know it was a tag union!"); unreachable!("we assert that the ext var is empty; otherwise we'd already know it was a tag union!");
} }

File diff suppressed because it is too large Load diff

View file

@ -1 +0,0 @@
/build

View file

@ -542,7 +542,7 @@ mod encode_immediate {
_ -> "<bad>" _ -> "<bad>"
"# "#
), $num, stringify!($typ)), ), $num, stringify!($typ)),
RocStr::from(format!(r#"{}"#, $num).as_str()), RocStr::from(format!(r"{}", $num).as_str()),
RocStr RocStr
) )
} }
@ -1011,7 +1011,7 @@ fn decode_derive_decoder_for_opaque() {
_ -> "FAIL" _ -> "FAIL"
"# "#
), ),
RocStr::from(r#"Hello, World!"#), RocStr::from(r"Hello, World!"),
RocStr RocStr
) )
} }
@ -1458,7 +1458,7 @@ mod hash {
use indoc::indoc; use indoc::indoc;
const TEST_HASHER: &str = indoc!( const TEST_HASHER: &str = indoc!(
r#" r"
THasher := List U8 implements [Hasher { THasher := List U8 implements [Hasher {
addBytes: tAddBytes, addBytes: tAddBytes,
addU8: tAddU8, addU8: tAddU8,
@ -1507,7 +1507,7 @@ mod hash {
tComplete = \@THasher _ -> Num.maxU64 tComplete = \@THasher _ -> Num.maxU64
tRead = \@THasher bytes -> bytes tRead = \@THasher bytes -> bytes
"# "
); );
fn build_test(input: &str) -> String { fn build_test(input: &str) -> String {
@ -1668,7 +1668,7 @@ mod hash {
#[test] #[test]
fn list_u8() { fn list_u8() {
assert_evals_to!( assert_evals_to!(
&build_test(r#"[15u8, 23u8, 37u8]"#), &build_test(r"[15u8, 23u8, 37u8]"),
RocList::from_slice(&[15, 23, 37]), RocList::from_slice(&[15, 23, 37]),
RocList<u8> RocList<u8>
) )
@ -1700,7 +1700,7 @@ mod hash {
#[test] #[test]
fn empty_record() { fn empty_record() {
assert_evals_to!( assert_evals_to!(
&build_test(r#"{}"#), &build_test(r"{}"),
RocList::from_slice(&[] as &[u8]), RocList::from_slice(&[] as &[u8]),
RocList<u8> RocList<u8>
) )
@ -1728,7 +1728,7 @@ mod hash {
fn record_of_list_of_records() { fn record_of_list_of_records() {
assert_evals_to!( assert_evals_to!(
&build_test( &build_test(
r#"{ a: [ { b: 15u8 }, { b: 23u8 } ], b: [ { c: 45u8 }, { c: 73u8 } ] }"# r"{ a: [ { b: 15u8 }, { b: 23u8 } ], b: [ { c: 45u8 }, { c: 73u8 } ] }"
), ),
RocList::from_slice(&[15, 23, 45, 73]), RocList::from_slice(&[15, 23, 45, 73]),
RocList<u8> RocList<u8>
@ -1757,7 +1757,7 @@ mod hash {
fn tuple_of_list_of_tuples() { fn tuple_of_list_of_tuples() {
assert_evals_to!( assert_evals_to!(
&build_test( &build_test(
r#"( [ ( 15u8, 32u8 ), ( 23u8, 41u8 ) ], [ (45u8, 63u8), (58u8, 73u8) ] )"# r"( [ ( 15u8, 32u8 ), ( 23u8, 41u8 ) ], [ (45u8, 63u8), (58u8, 73u8) ] )"
), ),
RocList::from_slice(&[15, 32, 23, 41, 45, 63, 58, 73]), RocList::from_slice(&[15, 32, 23, 41, 45, 63, 58, 73]),
RocList<u8> RocList<u8>
@ -2152,7 +2152,7 @@ fn issue_4772_weakened_monomorphic_destructure() {
with_larger_debug_stack(|| { with_larger_debug_stack(|| {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r###" r#"
app "test" app "test"
imports [TotallyNotJson] imports [TotallyNotJson]
provides [main] to "./platform" provides [main] to "./platform"
@ -2173,7 +2173,7 @@ fn issue_4772_weakened_monomorphic_destructure() {
main = main =
getNumber |> Result.map .val |> Result.withDefault 0 getNumber |> Result.map .val |> Result.withDefault 0
"### "#
), ),
1234i64, 1234i64,
i64 i64
@ -2302,7 +2302,7 @@ mod inspect {
main = Inspect.toStr (@Op {}) main = Inspect.toStr (@Op {})
"# "#
), ),
RocStr::from(r#"<opaque>"#), RocStr::from(r"<opaque>"),
RocStr RocStr
); );
} }
@ -2322,7 +2322,7 @@ mod inspect {
main = late (@Op {}) main = late (@Op {})
"# "#
), ),
RocStr::from(r#"<opaque>"#), RocStr::from(r"<opaque>"),
RocStr RocStr
); );
} }

View file

@ -19,11 +19,11 @@ use roc_std::{RocList, RocResult, RocStr};
fn def_closure_in_parens() { fn def_closure_in_parens() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
id = (\x -> x) id = (\x -> x)
id 42u32 id 42u32
"# "
), ),
42, 42,
u32 u32
@ -35,11 +35,11 @@ fn def_closure_in_parens() {
fn def_closure_in_multiple_parens() { fn def_closure_in_multiple_parens() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
id = (((\x -> x))) id = (((\x -> x)))
id 42u32 id 42u32
"# "
), ),
42, 42,
u32 u32

View file

@ -20,9 +20,9 @@ use roc_std::{RocList, RocStr};
fn dict_empty_len() { fn dict_empty_len() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Dict.len (Dict.empty {}) Dict.len (Dict.empty {})
"# "
), ),
0, 0,
usize usize
@ -34,11 +34,11 @@ fn dict_empty_len() {
fn dict_insert_empty() { fn dict_insert_empty() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Dict.empty {} Dict.empty {}
|> Dict.insert 42 32 |> Dict.insert 42 32
|> Dict.len |> Dict.len
"# "
), ),
1, 1,
usize usize
@ -50,12 +50,12 @@ fn dict_insert_empty() {
fn dict_empty_contains() { fn dict_empty_contains() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
empty : Dict.Dict I64 F64 empty : Dict.Dict I64 F64
empty = Dict.empty {} empty = Dict.empty {}
Dict.contains empty 42 Dict.contains empty 42
"# "
), ),
false, false,
bool bool
@ -67,12 +67,12 @@ fn dict_empty_contains() {
fn dict_nonempty_contains() { fn dict_nonempty_contains() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
empty : Dict.Dict I64 F64 empty : Dict.Dict I64 F64
empty = Dict.insert (Dict.empty {}) 42 1.23 empty = Dict.insert (Dict.empty {}) 42 1.23
Dict.contains empty 42 Dict.contains empty 42
"# "
), ),
true, true,
bool bool
@ -85,14 +85,14 @@ fn dict_nonempty_contains() {
fn dict_empty_remove() { fn dict_empty_remove() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
empty : Dict.Dict I64 F64 empty : Dict.Dict I64 F64
empty = Dict.empty {} empty = Dict.empty {}
empty empty
|> Dict.remove 42 |> Dict.remove 42
|> Dict.len |> Dict.len
"# "
), ),
0, 0,
i64 i64
@ -104,7 +104,7 @@ fn dict_empty_remove() {
fn dict_nonempty_remove() { fn dict_nonempty_remove() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
empty : Dict.Dict I64 F64 empty : Dict.Dict I64 F64
empty = Dict.insert (Dict.empty {}) 42 1.23 empty = Dict.insert (Dict.empty {}) 42 1.23
@ -112,7 +112,7 @@ fn dict_nonempty_remove() {
|> Dict.remove 42 |> Dict.remove 42
|> Dict.len |> Dict.len
|> Num.toI64 |> Num.toI64
"# "
), ),
0, 0,
i64 i64
@ -124,7 +124,7 @@ fn dict_nonempty_remove() {
fn dict_nonempty_get() { fn dict_nonempty_get() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
empty : Dict.Dict I64 F64 empty : Dict.Dict I64 F64
empty = Dict.insert (Dict.empty {}) 42 1.23 empty = Dict.insert (Dict.empty {}) 42 1.23
@ -137,7 +137,7 @@ fn dict_nonempty_get() {
|> Dict.insert 42 1.23f64 |> Dict.insert 42 1.23f64
|> Dict.get 42 |> Dict.get 42
|> withDefault 0 |> withDefault 0
"# "
), ),
1.23, 1.23,
f64 f64
@ -145,7 +145,7 @@ fn dict_nonempty_get() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
withDefault = \x, def -> withDefault = \x, def ->
when x is when x is
Ok v -> v Ok v -> v
@ -155,7 +155,7 @@ fn dict_nonempty_get() {
|> Dict.insert 42 1.23f64 |> Dict.insert 42 1.23f64
|> Dict.get 43 |> Dict.get 43
|> withDefault 0 |> withDefault 0
"# "
), ),
0.0, 0.0,
f64 f64
@ -167,7 +167,7 @@ fn dict_nonempty_get() {
fn keys() { fn keys() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
myDict : Dict.Dict I64 I64 myDict : Dict.Dict I64 I64
myDict = myDict =
Dict.empty {} Dict.empty {}
@ -177,7 +177,7 @@ fn keys() {
Dict.keys myDict Dict.keys myDict
"# "
), ),
RocList::from_slice(&[0, 1, 2]), RocList::from_slice(&[0, 1, 2]),
RocList<i64> RocList<i64>
@ -189,7 +189,7 @@ fn keys() {
fn values() { fn values() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
myDict : Dict.Dict I64 I64 myDict : Dict.Dict I64 I64
myDict = myDict =
Dict.empty {} Dict.empty {}
@ -199,7 +199,7 @@ fn values() {
Dict.values myDict Dict.values myDict
"# "
), ),
RocList::from_slice(&[100, 200, 300]), RocList::from_slice(&[100, 200, 300]),
RocList<i64> RocList<i64>
@ -211,14 +211,14 @@ fn values() {
fn from_list_with_fold_simple() { fn from_list_with_fold_simple() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
myDict : Dict.Dict I64 I64 myDict : Dict.Dict I64 I64
myDict = myDict =
[1,2,3] [1,2,3]
|> List.walk (Dict.empty {}) (\accum, value -> Dict.insert accum value value) |> List.walk (Dict.empty {}) (\accum, value -> Dict.insert accum value value)
Dict.values myDict Dict.values myDict
"# "
), ),
RocList::from_slice(&[1, 2, 3]), RocList::from_slice(&[1, 2, 3]),
RocList<i64> RocList<i64>
@ -230,7 +230,7 @@ fn from_list_with_fold_simple() {
fn from_list_with_fold_reallocates() { fn from_list_with_fold_reallocates() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
range : I64, I64, List I64-> List I64 range : I64, I64, List I64-> List I64
range = \low, high, accum -> range = \low, high, accum ->
if low < high then if low < high then
@ -245,7 +245,7 @@ fn from_list_with_fold_reallocates() {
|> List.walk (Dict.empty {}) (\accum, value -> Dict.insert accum value value) |> List.walk (Dict.empty {}) (\accum, value -> Dict.insert accum value value)
Dict.values myDict Dict.values myDict
"# "
), ),
RocList::from_slice(&[ RocList::from_slice(&[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
@ -329,7 +329,7 @@ fn big_str_values() {
fn unit_values() { fn unit_values() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
myDict : Dict.Dict I64 {} myDict : Dict.Dict I64 {}
myDict = myDict =
Dict.empty {} Dict.empty {}
@ -339,7 +339,7 @@ fn unit_values() {
|> Dict.insert 3 {} |> Dict.insert 3 {}
Num.toI64 (Dict.len myDict) Num.toI64 (Dict.len myDict)
"# "
), ),
4, 4,
i64 i64
@ -351,13 +351,13 @@ fn unit_values() {
fn single() { fn single() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
myDict : Dict.Dict I64 {} myDict : Dict.Dict I64 {}
myDict = myDict =
Dict.single 12345 {} Dict.single 12345 {}
Num.toI64 (Dict.len myDict) Num.toI64 (Dict.len myDict)
"# "
), ),
1, 1,
i64 i64
@ -369,14 +369,14 @@ fn single() {
fn insert_all() { fn insert_all() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
myDict : Dict I64 {} myDict : Dict I64 {}
myDict = myDict =
Dict.insertAll (Dict.single 0 {}) (Dict.single 1 {}) Dict.insertAll (Dict.single 0 {}) (Dict.single 1 {})
Dict.len myDict Dict.len myDict
|> Num.toI64 |> Num.toI64
"# "
), ),
2, 2,
i64 i64
@ -388,14 +388,14 @@ fn insert_all() {
fn insert_all_prefer_second() { fn insert_all_prefer_second() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
myDict : Dict.Dict I64 I64 myDict : Dict.Dict I64 I64
myDict = myDict =
(Dict.single 0 100) (Dict.single 0 100)
|> Dict.insertAll (Dict.single 0 200) |> Dict.insertAll (Dict.single 0 200)
Dict.values myDict Dict.values myDict
"# "
), ),
RocList::from_slice(&[200]), RocList::from_slice(&[200]),
RocList<i64> RocList<i64>
@ -407,7 +407,7 @@ fn insert_all_prefer_second() {
fn keep_shared() { fn keep_shared() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
dict1 : Dict.Dict I64 {} dict1 : Dict.Dict I64 {}
dict1 = dict1 =
Dict.empty {} Dict.empty {}
@ -427,7 +427,7 @@ fn keep_shared() {
Dict.keepShared dict1 dict2 Dict.keepShared dict1 dict2
|> Dict.len |> Dict.len
|> Num.toI64 |> Num.toI64
"# "
), ),
2, 2,
i64 i64
@ -439,7 +439,7 @@ fn keep_shared() {
fn keep_shared_value_must_match() { fn keep_shared_value_must_match() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
dict1 : Dict.Dict I64 I64 dict1 : Dict.Dict I64 I64
dict1 = dict1 =
Dict.empty {} Dict.empty {}
@ -458,7 +458,7 @@ fn keep_shared_value_must_match() {
Dict.keepShared dict1 dict2 Dict.keepShared dict1 dict2
|> Dict.values |> Dict.values
"# "
), ),
RocList::from_slice(&[2]), RocList::from_slice(&[2]),
RocList<i64> RocList<i64>
@ -470,7 +470,7 @@ fn keep_shared_value_must_match() {
fn remove_all() { fn remove_all() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
dict1 : Dict.Dict I64 {} dict1 : Dict.Dict I64 {}
dict1 = dict1 =
Dict.empty {} Dict.empty {}
@ -490,7 +490,7 @@ fn remove_all() {
Dict.removeAll dict1 dict2 Dict.removeAll dict1 dict2
|> Dict.len |> Dict.len
|> Num.toI64 |> Num.toI64
"# "
), ),
3, 3,
i64 i64
@ -502,7 +502,7 @@ fn remove_all() {
fn remove_all_prefer_first() { fn remove_all_prefer_first() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
dict1 : Dict.Dict I64 I64 dict1 : Dict.Dict I64 I64
dict1 = dict1 =
Dict.empty {} Dict.empty {}
@ -521,7 +521,7 @@ fn remove_all_prefer_first() {
Dict.removeAll dict1 dict2 Dict.removeAll dict1 dict2
|> Dict.values |> Dict.values
"# "
), ),
RocList::from_slice(&[1, 5, 3]), RocList::from_slice(&[1, 5, 3]),
RocList<i64> RocList<i64>
@ -533,7 +533,7 @@ fn remove_all_prefer_first() {
fn walk_sum_keys() { fn walk_sum_keys() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
dict1 : Dict.Dict I64 I64 dict1 : Dict.Dict I64 I64
dict1 = dict1 =
Dict.empty {} Dict.empty {}
@ -544,7 +544,7 @@ fn walk_sum_keys() {
|> Dict.insert 5 5 |> Dict.insert 5 5
Dict.walk dict1 0 \k, _, a -> k + a Dict.walk dict1 0 \k, _, a -> k + a
"# "
), ),
15, 15,
i64 i64

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -28,11 +28,11 @@ fn basic_float() {
fn branch_first_float() { fn branch_first_float() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when 1.23f64 is when 1.23f64 is
1.23 -> 12 1.23 -> 12
_ -> 34 _ -> 34
"# "
), ),
12, 12,
i64 i64
@ -44,11 +44,11 @@ fn branch_first_float() {
fn branch_second_float() { fn branch_second_float() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when 2.34 is when 2.34 is
1.23 -> 63 1.23 -> 63
_ -> 48 _ -> 48
"# "
), ),
48, 48,
i64 i64
@ -60,12 +60,12 @@ fn branch_second_float() {
fn branch_third_float() { fn branch_third_float() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when 10.0 is when 10.0 is
1.0 -> 63 1.0 -> 63
2.0 -> 48 2.0 -> 48
_ -> 112 _ -> 112
"# "
), ),
112, 112,
i64 i64
@ -77,11 +77,11 @@ fn branch_third_float() {
fn branch_first_int() { fn branch_first_int() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when 1 is when 1 is
1 -> 12 1 -> 12
_ -> 34 _ -> 34
"# "
), ),
12, 12,
i64 i64
@ -93,11 +93,11 @@ fn branch_first_int() {
fn branch_second_int() { fn branch_second_int() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when 2 is when 2 is
1 -> 63 1 -> 63
_ -> 48 _ -> 48
"# "
), ),
48, 48,
i64 i64
@ -109,12 +109,12 @@ fn branch_second_int() {
fn branch_third_int() { fn branch_third_int() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when 10 is when 10 is
1 -> 63 1 -> 63
2 -> 48 2 -> 48
_ -> 112 _ -> 112
"# "
), ),
112, 112,
i64 i64
@ -126,11 +126,11 @@ fn branch_third_int() {
fn branch_store_variable() { fn branch_store_variable() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when 0 is when 0 is
1 -> 12 1 -> 12
a -> a a -> a
"# "
), ),
0, 0,
i64 i64
@ -142,13 +142,13 @@ fn branch_store_variable() {
fn when_one_element_tag() { fn when_one_element_tag() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x : [Pair (Int a) (Int a)] x : [Pair (Int a) (Int a)]
x = Pair 0x2 0x3 x = Pair 0x2 0x3
when x is when x is
Pair l r -> l + r Pair l r -> l + r
"# "
), ),
5, 5,
i64 i64
@ -160,14 +160,14 @@ fn when_one_element_tag() {
fn when_two_element_tag_first() { fn when_two_element_tag_first() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x : [A (Int a), B (Int a)] x : [A (Int a), B (Int a)]
x = A 0x2 x = A 0x2
when x is when x is
A v -> v A v -> v
B v -> v B v -> v
"# "
), ),
2, 2,
i64 i64
@ -179,14 +179,14 @@ fn when_two_element_tag_first() {
fn when_two_element_tag_second() { fn when_two_element_tag_second() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x : [A (Int a), B (Int a)] x : [A (Int a), B (Int a)]
x = B 0x3 x = B 0x3
when x is when x is
A v -> v A v -> v
B v -> v B v -> v
"# "
), ),
3, 3,
i64 i64
@ -198,10 +198,10 @@ fn when_two_element_tag_second() {
fn gen_when_one_branch() { fn gen_when_one_branch() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when 1.23 is when 1.23 is
_ -> 23 _ -> 23
"# "
), ),
23, 23,
i64 i64
@ -213,7 +213,7 @@ fn gen_when_one_branch() {
fn gen_large_when_int() { fn gen_large_when_int() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
foo = \num -> foo = \num ->
when num is when num is
0 -> 200 0 -> 200
@ -224,7 +224,7 @@ fn gen_large_when_int() {
_ -> 1000 _ -> 1000
foo -3 foo -3
"# "
), ),
111, 111,
i64 i64
@ -236,7 +236,7 @@ fn gen_large_when_int() {
fn gen_large_when_float() { fn gen_large_when_float() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
foo = \num -> foo = \num ->
when num is when num is
0.5f64 -> 200.1 0.5f64 -> 200.1
@ -247,7 +247,7 @@ fn gen_large_when_float() {
_ -> 1000.6f64 _ -> 1000.6f64
foo -3.6 foo -3.6
"# "
), ),
111.2, 111.2,
f64 f64
@ -259,11 +259,11 @@ fn gen_large_when_float() {
fn or_pattern() { fn or_pattern() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when 2 is when 2 is
1 | 2 -> 42 1 | 2 -> 42
_ -> 1 _ -> 1
"# "
), ),
42, 42,
i64 i64
@ -275,11 +275,11 @@ fn or_pattern() {
fn apply_identity() { fn apply_identity() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
identity = \a -> a identity = \a -> a
identity 5 identity 5
"# "
), ),
5, 5,
i64 i64
@ -291,12 +291,12 @@ fn apply_identity() {
fn apply_unnamed_identity() { fn apply_unnamed_identity() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
wrapper = \{} -> wrapper = \{} ->
(\a -> a) 5 (\a -> a) 5
wrapper {} wrapper {}
"# "
), ),
5, 5,
i64 i64
@ -308,7 +308,7 @@ fn apply_unnamed_identity() {
fn return_unnamed_fn() { fn return_unnamed_fn() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
wrapper = \{} -> wrapper = \{} ->
alwaysFloatIdentity : Int * -> (Frac a -> Frac a) alwaysFloatIdentity : Int * -> (Frac a -> Frac a)
alwaysFloatIdentity = \_ -> alwaysFloatIdentity = \_ ->
@ -317,7 +317,7 @@ fn return_unnamed_fn() {
(alwaysFloatIdentity 2) 1.23f64 (alwaysFloatIdentity 2) 1.23f64
wrapper {} wrapper {}
"# "
), ),
1.23, 1.23,
f64 f64
@ -329,7 +329,7 @@ fn return_unnamed_fn() {
fn gen_when_fn() { fn gen_when_fn() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
limitedNegate = \num -> limitedNegate = \num ->
when num is when num is
1 -> -1 1 -> -1
@ -337,7 +337,7 @@ fn gen_when_fn() {
_ -> num _ -> num
limitedNegate 1 limitedNegate 1
"# "
), ),
-1, -1,
i64 i64
@ -349,11 +349,11 @@ fn gen_when_fn() {
fn gen_basic_def() { fn gen_basic_def() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
answer = 42 answer = 42
answer answer
"# "
), ),
42, 42,
i64 i64
@ -361,11 +361,11 @@ fn gen_basic_def() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
float = 1.23f64 float = 1.23f64
float float
"# "
), ),
1.23, 1.23,
f64 f64
@ -377,13 +377,13 @@ fn gen_basic_def() {
fn gen_multiple_defs() { fn gen_multiple_defs() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
answer = 42 answer = 42
float = 1.23f64 float = 1.23f64
if float > 3 then answer else answer if float > 3 then answer else answer
"# "
), ),
42, 42,
i64 i64
@ -391,13 +391,13 @@ fn gen_multiple_defs() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
answer = 42 answer = 42
float = 1.23f64 float = 1.23f64
if answer > 3 then float else float if answer > 3 then float else float
"# "
), ),
1.23, 1.23,
f64 f64
@ -411,7 +411,7 @@ fn gen_multiple_defs() {
// fn gen_chained_defs() { // fn gen_chained_defs() {
// assert_evals_to!( // assert_evals_to!(
// indoc!( // indoc!(
// r#" // r"
// x = i1 // x = i1
// i3 = i2 // i3 = i2
// i1 = 1337 // i1 = 1337
@ -419,7 +419,7 @@ fn gen_multiple_defs() {
// y = 12.4 // y = 12.4
// //
// i3 // i3
// "# // "
// ), // ),
// 1337, // 1337,
// i64 // i64
@ -431,7 +431,7 @@ fn gen_multiple_defs() {
// fn gen_nested_defs_old() { // fn gen_nested_defs_old() {
// assert_evals_to!( // assert_evals_to!(
// indoc!( // indoc!(
// r#" // r"
// x = 5 // x = 5
// //
// answer = // answer =
@ -461,7 +461,7 @@ fn gen_multiple_defs() {
// y = 12.4 // y = 12.4
// //
// answer // answer
// "# // "
// ), // ),
// 1337, // 1337,
// i64 // i64
@ -473,7 +473,7 @@ fn gen_multiple_defs() {
// fn let_x_in_x() { // fn let_x_in_x() {
// assert_evals_to!( // assert_evals_to!(
// indoc!( // indoc!(
// r#" // r"
// x = 5 // x = 5
// //
// answer = // answer =
@ -484,7 +484,7 @@ fn gen_multiple_defs() {
// nested // nested
// //
// answer // answer
// "# // "
// ), // ),
// 1337, // 1337,
// i64 // i64
@ -496,7 +496,7 @@ fn gen_multiple_defs() {
fn factorial() { fn factorial() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
factorial = \n, accum -> factorial = \n, accum ->
when n is when n is
0 -> 0 ->
@ -506,7 +506,7 @@ fn factorial() {
factorial (n - 1) (n * accum) factorial (n - 1) (n * accum)
factorial 10 1 factorial 10 1
"# "
), ),
3628800, 3628800,
i64 i64
@ -518,7 +518,7 @@ fn factorial() {
fn peano1() { fn peano1() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Peano : [S Peano, Z] Peano : [S Peano, Z]
three : Peano three : Peano
@ -527,7 +527,7 @@ fn peano1() {
when three is when three is
Z -> 2 Z -> 2
S _ -> 1 S _ -> 1
"# "
), ),
1, 1,
i64 i64
@ -539,7 +539,7 @@ fn peano1() {
fn peano2() { fn peano2() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Peano : [S Peano, Z] Peano : [S Peano, Z]
three : Peano three : Peano
@ -549,7 +549,7 @@ fn peano2() {
S (S _) -> 1 S (S _) -> 1
S (_) -> 0 S (_) -> 0
Z -> 0 Z -> 0
"# "
), ),
1, 1,
i64 i64
@ -833,7 +833,7 @@ fn linked_list_map() {
fn when_nested_maybe() { fn when_nested_maybe() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Maybe a : [Nothing, Just a] Maybe a : [Nothing, Just a]
x : Maybe (Maybe (Int a)) x : Maybe (Maybe (Int a))
@ -842,7 +842,7 @@ fn when_nested_maybe() {
when x is when x is
Just (Just v) -> v + 0x1 Just (Just v) -> v + 0x1
_ -> 0x1 _ -> 0x1
"# "
), ),
42, 42,
i64 i64
@ -850,7 +850,7 @@ fn when_nested_maybe() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Maybe a : [Nothing, Just a] Maybe a : [Nothing, Just a]
x : Maybe (Maybe (Int *)) x : Maybe (Maybe (Int *))
@ -860,7 +860,7 @@ fn when_nested_maybe() {
Just (Just v) -> v + 0x1 Just (Just v) -> v + 0x1
Just Nothing -> 0x2 Just Nothing -> 0x2
Nothing -> 0x1 Nothing -> 0x1
"# "
), ),
2, 2,
i64 i64
@ -868,7 +868,7 @@ fn when_nested_maybe() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Maybe a : [Nothing, Just a] Maybe a : [Nothing, Just a]
x : Maybe (Maybe (Int *)) x : Maybe (Maybe (Int *))
@ -878,7 +878,7 @@ fn when_nested_maybe() {
Just (Just v) -> v + 0x1 Just (Just v) -> v + 0x1
Just Nothing -> 0x2 Just Nothing -> 0x2
Nothing -> 0x1 Nothing -> 0x1
"# "
), ),
1, 1,
i64 i64
@ -890,7 +890,7 @@ fn when_nested_maybe() {
fn when_peano() { fn when_peano() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Peano : [S Peano, Z] Peano : [S Peano, Z]
three : Peano three : Peano
@ -900,7 +900,7 @@ fn when_peano() {
S (S _) -> 1 S (S _) -> 1
S (_) -> 2 S (_) -> 2
Z -> 3 Z -> 3
"# "
), ),
1, 1,
i64 i64
@ -908,7 +908,7 @@ fn when_peano() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Peano : [S Peano, Z] Peano : [S Peano, Z]
three : Peano three : Peano
@ -918,7 +918,7 @@ fn when_peano() {
S (S _) -> 1 S (S _) -> 1
S (_) -> 2 S (_) -> 2
Z -> 3 Z -> 3
"# "
), ),
2, 2,
i64 i64
@ -926,7 +926,7 @@ fn when_peano() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Peano : [S Peano, Z] Peano : [S Peano, Z]
three : Peano three : Peano
@ -936,7 +936,7 @@ fn when_peano() {
S (S _) -> 1 S (S _) -> 1
S (_) -> 2 S (_) -> 2
Z -> 3 Z -> 3
"# "
), ),
3, 3,
i64 i64
@ -955,7 +955,7 @@ fn when_peano() {
fn overflow_frees_list() { fn overflow_frees_list() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
myList = [1,2,3] myList = [1,2,3]
# integer overflow; must use the list so it is defined before the overflow # integer overflow; must use the list so it is defined before the overflow
@ -967,7 +967,7 @@ fn overflow_frees_list() {
index = Num.intCast n index = Num.intCast n
List.get myList index List.get myList index
"# "
), ),
(3, 0), (3, 0),
(i64, i8) (i64, i8)
@ -980,12 +980,12 @@ fn overflow_frees_list() {
fn undefined_variable() { fn undefined_variable() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
if Bool.true then if Bool.true then
x + z x + z
else else
y + z y + z
"# "
), ),
3, 3,
i64 i64
@ -1016,12 +1016,12 @@ fn a_crash() {
fn annotation_without_body() { fn annotation_without_body() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
foo : Int * foo : Int *
foo foo
"# "
), ),
3, 3,
i64 i64
@ -2022,11 +2022,11 @@ fn hof_conditional() {
// exposed issue with the if condition being just a symbol // exposed issue with the if condition being just a symbol
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
passTrue = \f -> f Bool.true passTrue = \f -> f Bool.true
passTrue (\trueVal -> if trueVal then Bool.false else Bool.true) passTrue (\trueVal -> if trueVal then Bool.false else Bool.true)
"# "
), ),
0, 0,
u8 u8
@ -2041,12 +2041,12 @@ fn hof_conditional() {
fn pattern_shadowing() { fn pattern_shadowing() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x = 4 x = 4
when 4 is when 4 is
x -> x x -> x
"# "
), ),
0, 0,
i64 i64
@ -2060,11 +2060,11 @@ fn pattern_shadowing() {
fn unsupported_pattern_str_interp() { fn unsupported_pattern_str_interp() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ x: 4 } = { x : 4 } { x: 4 } = { x : 4 }
x x
"# "
), ),
0, 0,
i64 i64
@ -2120,14 +2120,14 @@ fn case_or_pattern() {
// it is currently duplicated // it is currently duplicated
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x : [Red, Green, Blue] x : [Red, Green, Blue]
x = Red x = Red
when x is when x is
Red | Green -> 0 Red | Green -> 0
Blue -> 1 Blue -> 1
"# "
), ),
0, 0,
i64 i64
@ -2517,11 +2517,11 @@ fn backpassing_result() {
fn function_malformed_pattern() { fn function_malformed_pattern() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x = 3 x = 3
(\x -> x) 42 (\x -> x) 42
"# "
), ),
3, 3,
i64 i64
@ -2534,12 +2534,12 @@ fn function_malformed_pattern() {
fn call_invalid_layout() { fn call_invalid_layout() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
f : I64 -> I64 f : I64 -> I64
f = \x -> x f = \x -> x
f {} f {}
"# "
), ),
3, 3,
i64, i64,
@ -3261,12 +3261,12 @@ fn polymophic_expression_captured_inside_closure() {
fn issue_2322() { fn issue_2322() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
double = \x -> x * 2 double = \x -> x * 2
doubleBind = \x -> (\_ -> double x) doubleBind = \x -> (\_ -> double x)
doubleThree = doubleBind 3 doubleThree = doubleBind 3
doubleThree {} doubleThree {}
"# "
), ),
6, 6,
i64 i64
@ -3312,14 +3312,14 @@ fn box_and_unbox_big_string() {
fn box_and_unbox_nonrecursive_tag() { fn box_and_unbox_nonrecursive_tag() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
result : Result U64 U64 result : Result U64 U64
result = Ok 42 result = Ok 42
result result
|> Box.box |> Box.box
|> Box.unbox |> Box.unbox
"# "
), ),
roc_std::RocResult::ok(42), roc_std::RocResult::ok(42),
roc_std::RocResult<u64, u64> roc_std::RocResult<u64, u64>
@ -3409,9 +3409,9 @@ fn box_and_unbox_f32() {
fn box_and_unbox_record_2_u64() { fn box_and_unbox_record_2_u64() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Box.unbox (Box.box { a: 15u64, b: 27u64 }) Box.unbox (Box.box { a: 15u64, b: 27u64 })
"# "
), ),
(15, 27), (15, 27),
(u64, u64) (u64, u64)
@ -3423,9 +3423,9 @@ fn box_and_unbox_record_2_u64() {
fn box_and_unbox_record_3_u64() { fn box_and_unbox_record_3_u64() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Box.unbox (Box.box { a: 15u64, b: 27u64, c: 34u64 }) Box.unbox (Box.box { a: 15u64, b: 27u64, c: 34u64 })
"# "
), ),
(15, 27, 34), (15, 27, 34),
(u64, u64, u64) (u64, u64, u64)
@ -3437,9 +3437,9 @@ fn box_and_unbox_record_3_u64() {
fn box_and_unbox_record_2_u8() { fn box_and_unbox_record_2_u8() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Box.unbox (Box.box { a: 15u8, b: 27u8 }) Box.unbox (Box.box { a: 15u8, b: 27u8 })
"# "
), ),
(15, 27), (15, 27),
(u8, u8) (u8, u8)
@ -3451,9 +3451,9 @@ fn box_and_unbox_record_2_u8() {
fn box_and_unbox_record_3_u8() { fn box_and_unbox_record_3_u8() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Box.unbox (Box.box { a: 15u8, b: 27u8, c: 34u8 }) Box.unbox (Box.box { a: 15u8, b: 27u8, c: 34u8 })
"# "
), ),
(15, 27, 34), (15, 27, 34),
(u8, u8, u8) (u8, u8, u8)
@ -3465,12 +3465,12 @@ fn box_and_unbox_record_3_u8() {
fn box_and_unbox_tag_union() { fn box_and_unbox_tag_union() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
v : [A U8, B U8] # usually stack allocated v : [A U8, B U8] # usually stack allocated
v = B 27u8 v = B 27u8
Box.unbox (Box.box v) Box.unbox (Box.box v)
"# "
), ),
(27, 1), (27, 1),
(u8, u8) (u8, u8)
@ -3534,7 +3534,7 @@ fn issue_2894() {
fn polymorphic_def_used_in_closure() { fn polymorphic_def_used_in_closure() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
a : I64 -> _ a : I64 -> _
a = \g -> a = \g ->
f = { r: g, h: 32 } f = { r: g, h: 32 }
@ -3543,7 +3543,7 @@ fn polymorphic_def_used_in_closure() {
h1 = (\{} -> f.h) {} h1 = (\{} -> f.h) {}
h1 h1
a 1 a 1
"# "
), ),
32, 32,
u64 u64
@ -3555,13 +3555,13 @@ fn polymorphic_def_used_in_closure() {
fn polymorphic_lambda_set_usage() { fn polymorphic_lambda_set_usage() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
id1 = \x -> x id1 = \x -> x
id2 = \y -> y id2 = \y -> y
id = if Bool.true then id1 else id2 id = if Bool.true then id1 else id2
id 9u8 id 9u8
"# "
), ),
9, 9,
u8 u8
@ -3573,7 +3573,7 @@ fn polymorphic_lambda_set_usage() {
fn polymorphic_lambda_set_multiple_specializations() { fn polymorphic_lambda_set_multiple_specializations() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
id1 = \x -> x id1 = \x -> x
id2 = \y -> y id2 = \y -> y
id = \z -> id = \z ->
@ -3581,7 +3581,7 @@ fn polymorphic_lambda_set_multiple_specializations() {
f z f z
(id 9u8) + Num.toU8 (id 16u16) (id 9u8) + Num.toU8 (id 16u16)
"# "
), ),
25, 25,
u8 u8
@ -3642,14 +3642,14 @@ fn mutual_recursion_top_level_defs() {
fn polymorphic_lambda_captures_polymorphic_value() { fn polymorphic_lambda_captures_polymorphic_value() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x = 2 x = 2
f1 = \_ -> x f1 = \_ -> x
f = if Bool.true then f1 else f1 f = if Bool.true then f1 else f1
f {} f {}
"# "
), ),
2, 2,
u64 u64
@ -3661,7 +3661,7 @@ fn polymorphic_lambda_captures_polymorphic_value() {
fn lambda_capture_niche_u64_vs_u8_capture() { fn lambda_capture_niche_u64_vs_u8_capture() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
capture : _ -> ({} -> Str) capture : _ -> ({} -> Str)
capture = \val -> capture = \val ->
\{} -> \{} ->
@ -3677,7 +3677,7 @@ fn lambda_capture_niche_u64_vs_u8_capture() {
capture 18u8 capture 18u8
fun {} fun {}
"# "
), ),
RocStr::from("123"), RocStr::from("123"),
RocStr RocStr
@ -3789,14 +3789,14 @@ fn lambda_capture_niches_have_captured_function_in_closure() {
fn recursive_call_capturing_function() { fn recursive_call_capturing_function() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
a = \b -> a = \b ->
c = \d -> c = \d ->
if d == 7 then d else c (d + b) if d == 7 then d else c (d + b)
c 1 c 1
a 6 a 6
"# "
), ),
7, 7,
i64 i64
@ -3808,13 +3808,13 @@ fn recursive_call_capturing_function() {
fn shared_pattern_variable_in_when_branches() { fn shared_pattern_variable_in_when_branches() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
f = \t -> f = \t ->
when t is when t is
A x | B x -> x A x | B x -> x
{a: f (A 15u8), b: (B 31u8)} {a: f (A 15u8), b: (B 31u8)}
"# "
), ),
(15u8, 31u8), (15u8, 31u8),
(u8, u8) (u8, u8)
@ -3826,12 +3826,12 @@ fn shared_pattern_variable_in_when_branches() {
fn symbol_not_bound_in_all_patterns_runs_when_no_bound_symbol_used() { fn symbol_not_bound_in_all_patterns_runs_when_no_bound_symbol_used() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
f = \t -> when t is f = \t -> when t is
A x | B y -> 31u8 A x | B y -> 31u8
{a: f (A 15u8), b: f (B 15u8)} {a: f (A 15u8), b: f (B 15u8)}
"# "
), ),
(31u8, 31u8), (31u8, 31u8),
(u8, u8), (u8, u8),
@ -3845,10 +3845,10 @@ fn symbol_not_bound_in_all_patterns_runs_when_no_bound_symbol_used() {
fn symbol_not_bound_in_all_patterns_runs_when_bound_pattern_reached() { fn symbol_not_bound_in_all_patterns_runs_when_bound_pattern_reached() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when A 15u8 is when A 15u8 is
A x | B y -> x A x | B y -> x
"# "
), ),
15u8, 15u8,
u8, u8,
@ -3865,10 +3865,10 @@ fn symbol_not_bound_in_all_patterns_runs_when_bound_pattern_reached() {
fn runtime_error_when_degenerate_pattern_reached() { fn runtime_error_when_degenerate_pattern_reached() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when B 15u8 is when B 15u8 is
A x | B y -> x + 5u8 A x | B y -> x + 5u8
"# "
), ),
15u8, 15u8,
u8, u8,
@ -4399,7 +4399,7 @@ fn pattern_as_of_symbol() {
fn function_specialization_information_in_lambda_set_thunk() { fn function_specialization_information_in_lambda_set_thunk() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r###" r#"
app "test" provides [main] to "./platform" app "test" provides [main] to "./platform"
andThen = \{} -> andThen = \{} ->
@ -4409,7 +4409,7 @@ fn function_specialization_information_in_lambda_set_thunk() {
between = andThen {} between = andThen {}
main = between \{} -> between \{} -> 10u8 main = between \{} -> between \{} -> 10u8
"### "#
), ),
30, 30,
u8 u8
@ -4421,7 +4421,7 @@ fn function_specialization_information_in_lambda_set_thunk() {
fn function_specialization_information_in_lambda_set_thunk_independent_defs() { fn function_specialization_information_in_lambda_set_thunk_independent_defs() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r###" r#"
app "test" provides [main] to "./platform" app "test" provides [main] to "./platform"
andThen = \{} -> andThen = \{} ->
@ -4433,7 +4433,7 @@ fn function_specialization_information_in_lambda_set_thunk_independent_defs() {
between2 = andThen {} between2 = andThen {}
main = between1 \{} -> between2 \{} -> 10u8 main = between1 \{} -> between2 \{} -> 10u8
"### "#
), ),
30, 30,
u8 u8
@ -4526,7 +4526,7 @@ fn layout_cache_structure_with_multiple_recursive_structures() {
fn reset_recursive_type_wraps_in_named_type() { fn reset_recursive_type_wraps_in_named_type() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r###" r#"
app "test" provides [main] to "./platform" app "test" provides [main] to "./platform"
main : Str main : Str
@ -4553,7 +4553,7 @@ fn reset_recursive_type_wraps_in_named_type() {
strX = f x strX = f x
strXs = printLinkedList xs f strXs = printLinkedList xs f
"Cons \(strX) (\(strXs))" "Cons \(strX) (\(strXs))"
"### "#
), ),
RocStr::from("Cons 2 (Cons 3 (Cons 4 (Nil)))"), RocStr::from("Cons 2 (Cons 3 (Cons 4 (Nil)))"),
RocStr RocStr
@ -4619,12 +4619,12 @@ fn many_arguments() {
// exhausts all argument registers on x86 and aarch // exhausts all argument registers on x86 and aarch
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
fun = \a,b,c,d, e,f,g,h, i -> fun = \a,b,c,d, e,f,g,h, i ->
(a + b + c + d) + (e + f + g + h) + i (a + b + c + d) + (e + f + g + h) + i
fun 0i64 1 2 3 4 5 6 7 8 fun 0i64 1 2 3 4 5 6 7 8
"# "
), ),
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8, 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8,
i64 i64
@ -4636,9 +4636,9 @@ fn many_arguments() {
fn multiple_uses_of_bool_true_record() { fn multiple_uses_of_bool_true_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
(Bool.true, Bool.true).0 (Bool.true, Bool.true).0
"# "
), ),
true, true,
bool bool
@ -4650,14 +4650,14 @@ fn multiple_uses_of_bool_true_record() {
fn multiple_uses_of_bool_true_tag_union() { fn multiple_uses_of_bool_true_tag_union() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x : [ One Bool Bool, Empty ] x : [ One Bool Bool, Empty ]
x = One Bool.true Bool.true x = One Bool.true Bool.true
when x is when x is
One a _ -> a One a _ -> a
Empty -> Bool.false Empty -> Bool.false
"# "
), ),
true, true,
bool bool

View file

@ -18,9 +18,9 @@ use roc_std::{RocList, RocStr};
fn basic_record() { fn basic_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ y: 17, x: 15, z: 19 }.x { y: 17, x: 15, z: 19 }.x
"# "
), ),
15, 15,
i64 i64
@ -28,9 +28,9 @@ fn basic_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ x: 15, y: 17, z: 19 }.y { x: 15, y: 17, z: 19 }.y
"# "
), ),
17, 17,
i64 i64
@ -38,9 +38,9 @@ fn basic_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ x: 15, y: 17, z: 19 }.z { x: 15, y: 17, z: 19 }.z
"# "
), ),
19, 19,
i64 i64
@ -52,11 +52,11 @@ fn basic_record() {
fn f64_record() { fn f64_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
rec = { y: 17.2f64, x: 15.1f64, z: 19.3f64 } rec = { y: 17.2f64, x: 15.1f64, z: 19.3f64 }
rec.x rec.x
"# "
), ),
15.1, 15.1,
f64 f64
@ -64,11 +64,11 @@ fn f64_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
rec = { y: 17.2f64, x: 15.1f64, z: 19.3f64 } rec = { y: 17.2f64, x: 15.1f64, z: 19.3f64 }
rec.y rec.y
"# "
), ),
17.2, 17.2,
f64 f64
@ -76,11 +76,11 @@ fn f64_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
rec = { y: 17.2f64, x: 15.1f64, z: 19.3f64 } rec = { y: 17.2f64, x: 15.1f64, z: 19.3f64 }
rec.z rec.z
"# "
), ),
19.3, 19.3,
f64 f64
@ -93,14 +93,14 @@ fn pass_bool_record() {
// found a bug there the register to use was not incremented correctly // found a bug there the register to use was not incremented correctly
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
true : Bool true : Bool
true = Bool.true true = Bool.true
f = \_, x -> x f = \_, x -> x
f { x: true, y: true } 23 f { x: true, y: true } 23
"# "
), ),
23, 23,
i64 i64
@ -124,11 +124,11 @@ fn fn_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
rec = { x: 15, y: 17, z: 19 } rec = { x: 15, y: 17, z: 19 }
rec.z + rec.x rec.z + rec.x
"# "
), ),
34, 34,
i64 i64
@ -140,11 +140,11 @@ fn fn_record() {
fn def_record() { fn def_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
rec = { y: 17, x: 15, z: 19 } rec = { y: 17, x: 15, z: 19 }
rec.x rec.x
"# "
), ),
15, 15,
i64 i64
@ -152,11 +152,11 @@ fn def_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
rec = { x: 15, y: 17, z: 19 } rec = { x: 15, y: 17, z: 19 }
rec.y rec.y
"# "
), ),
17, 17,
i64 i64
@ -164,11 +164,11 @@ fn def_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
rec = { x: 15, y: 17, z: 19 } rec = { x: 15, y: 17, z: 19 }
rec.z rec.z
"# "
), ),
19, 19,
i64 i64
@ -180,10 +180,10 @@ fn def_record() {
fn when_on_record() { fn when_on_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when { x: 0x2 } is when { x: 0x2 } is
{ x } -> x + 3 { x } -> x + 3
"# "
), ),
5, 5,
i64 i64
@ -195,10 +195,10 @@ fn when_on_record() {
fn when_record_with_guard_pattern() { fn when_record_with_guard_pattern() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when { x: 0x2, y: 1.23 } is when { x: 0x2, y: 1.23 } is
{ x: var } -> var + 3 { x: var } -> var + 3
"# "
), ),
5, 5,
i64 i64
@ -210,11 +210,11 @@ fn when_record_with_guard_pattern() {
fn let_with_record_pattern() { fn let_with_record_pattern() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ x } = { x: 0x2, y: 1.23 } { x } = { x: 0x2, y: 1.23 }
x x
"# "
), ),
2, 2,
i64 i64
@ -226,11 +226,11 @@ fn let_with_record_pattern() {
fn record_guard_pattern() { fn record_guard_pattern() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when { x: 0x2, y: 1.23 } is when { x: 0x2, y: 1.23 } is
{ x: 0x4 } -> 5 { x: 0x4 } -> 5
{ x } -> x + 3 { x } -> x + 3
"# "
), ),
5, 5,
i64 i64
@ -242,11 +242,11 @@ fn record_guard_pattern() {
fn twice_record_access() { fn twice_record_access() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x = {a: 0x2, b: 0x3 } x = {a: 0x2, b: 0x3 }
x.a + x.b x.a + x.b
"# "
), ),
5, 5,
i64 i64
@ -257,11 +257,11 @@ fn twice_record_access() {
fn empty_record() { fn empty_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
v = {} v = {}
v v
"# "
), ),
(), (),
() ()
@ -272,9 +272,9 @@ fn empty_record() {
fn i64_record2_literal() { fn i64_record2_literal() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ x: 3, y: 5 } { x: 3, y: 5 }
"# "
), ),
(3, 5), (3, 5),
(i64, i64) (i64, i64)
@ -286,9 +286,9 @@ fn i64_record2_literal() {
// fn i64_record3_literal() { // fn i64_record3_literal() {
// assert_evals_to!( // assert_evals_to!(
// indoc!( // indoc!(
// r#" // r"
// { x: 3, y: 5, z: 17 } // { x: 3, y: 5, z: 17 }
// "# // "
// ), // ),
// (3, 5, 17), // (3, 5, 17),
// (i64, i64, i64) // (i64, i64, i64)
@ -299,9 +299,9 @@ fn i64_record2_literal() {
fn f64_record2_literal() { fn f64_record2_literal() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ x: 3.1f64, y: 5.1f64 } { x: 3.1f64, y: 5.1f64 }
"# "
), ),
(3.1, 5.1), (3.1, 5.1),
(f64, f64) (f64, f64)
@ -313,9 +313,9 @@ fn f64_record2_literal() {
// fn f64_record3_literal() { // fn f64_record3_literal() {
// assert_evals_to!( // assert_evals_to!(
// indoc!( // indoc!(
// r#" // r"
// { x: 3.1, y: 5.1, z: 17.1 } // { x: 3.1, y: 5.1, z: 17.1 }
// "# // "
// ), // ),
// (3.1, 5.1, 17.1), // (3.1, 5.1, 17.1),
// (f64, f64, f64) // (f64, f64, f64)
@ -327,12 +327,12 @@ fn f64_record2_literal() {
// fn bool_record4_literal() { // fn bool_record4_literal() {
// assert_evals_to!( // assert_evals_to!(
// indoc!( // indoc!(
// r#" // r"
// record : { a : Bool, b : Bool, c : Bool, d : Bool } // record : { a : Bool, b : Bool, c : Bool, d : Bool }
// record = { a: Bool.true, b: Bool.true, c : Bool.true, d : Bool } // record = { a: Bool.true, b: Bool.true, c : Bool.true, d : Bool }
// record // record
// "# // "
// ), // ),
// (true, false, false, true), // (true, false, false, true),
// (bool, bool, bool, bool) // (bool, bool, bool, bool)
@ -343,9 +343,9 @@ fn f64_record2_literal() {
fn i64_record1_literal() { fn i64_record1_literal() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ a: 3 } { a: 3 }
"# "
), ),
3, 3,
i64 i64
@ -357,9 +357,9 @@ fn i64_record1_literal() {
// fn i64_record9_literal() { // fn i64_record9_literal() {
// assert_evals_to!( // assert_evals_to!(
// indoc!( // indoc!(
// r#" // r"
// { a: 3, b: 5, c: 17, d: 1, e: 9, f: 12, g: 13, h: 14, i: 15 } // { a: 3, b: 5, c: 17, d: 1, e: 9, f: 12, g: 13, h: 14, i: 15 }
// "# // "
// ), // ),
// (3, 5, 17, 1, 9, 12, 13, 14, 15), // (3, 5, 17, 1, 9, 12, 13, 14, 15),
// (i64, i64, i64, i64, i64, i64, i64, i64, i64) // (i64, i64, i64, i64, i64, i64, i64, i64, i64)
@ -371,9 +371,9 @@ fn i64_record1_literal() {
// fn f64_record3_literal() { // fn f64_record3_literal() {
// assert_evals_to!( // assert_evals_to!(
// indoc!( // indoc!(
// r#" // r"
// { x: 3.1, y: 5.1, z: 17.1 } // { x: 3.1, y: 5.1, z: 17.1 }
// "# // "
// ), // ),
// (3.1, 5.1, 17.1), // (3.1, 5.1, 17.1),
// (f64, f64, f64) // (f64, f64, f64)
@ -384,12 +384,12 @@ fn i64_record1_literal() {
fn bool_literal() { fn bool_literal() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x : Bool x : Bool
x = Bool.true x = Bool.true
x x
"# "
), ),
true, true,
bool bool
@ -401,12 +401,12 @@ fn bool_literal() {
fn return_record() { fn return_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x = 4 x = 4
y = 3 y = 3
{ x, y } { x, y }
"# "
), ),
(4, 3), (4, 3),
(i64, i64) (i64, i64)
@ -446,7 +446,7 @@ fn optional_field_when_use_default() {
fn optional_field_when_use_default_nested() { fn optional_field_when_use_default_nested() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
f = \r -> f = \r ->
when r is when r is
{ x: Blue, y ? 3 } -> y { x: Blue, y ? 3 } -> y
@ -458,7 +458,7 @@ fn optional_field_when_use_default_nested() {
d = f { x: Red } d = f { x: Red }
a * b * c * d a * b * c * d
"# "
), ),
3 * 5 * 7 * 11, 3 * 5 * 7 * 11,
i64 i64
@ -491,13 +491,13 @@ fn optional_field_destructure_module() {
fn optional_field_destructure_expr() { fn optional_field_destructure_expr() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
fn = \r -> fn = \r ->
{ x ? 10, y } = r { x ? 10, y } = r
x + y x + y
fn { x: 4, y: 9 } fn { x: 4, y: 9 }
"# "
), ),
13, 13,
i64 i64
@ -551,13 +551,13 @@ fn optional_field_let_no_use_default() {
fn optional_field_let_no_use_default_nested() { fn optional_field_let_no_use_default_nested() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
f = \r -> f = \r ->
{ x ? 10, y } = r { x ? 10, y } = r
x + y x + y
f { y: 9, x: 4 } f { y: 9, x: 4 }
"# "
), ),
13, 13,
i64 i64
@ -569,12 +569,12 @@ fn optional_field_let_no_use_default_nested() {
fn optional_field_function_use_default() { fn optional_field_function_use_default() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
f = \{ x ? 10, y } -> x + y f = \{ x ? 10, y } -> x + y
f { y: 9 } f { y: 9 }
"# "
), ),
19, 19,
i64 i64
@ -605,12 +605,12 @@ fn optional_field_function_no_use_default() {
fn optional_field_function_no_use_default_nested() { fn optional_field_function_no_use_default_nested() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
f = \{ x ? 10, y } -> x + y f = \{ x ? 10, y } -> x + y
f { x: 4, y: 9 } f { x: 4, y: 9 }
"# "
), ),
13, 13,
i64 i64
@ -622,10 +622,10 @@ fn optional_field_function_no_use_default_nested() {
fn optional_field_singleton_record() { fn optional_field_singleton_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when { x : 4 } is when { x : 4 } is
{ x ? 3 } -> x { x ? 3 } -> x
"# "
), ),
4, 4,
i64 i64
@ -637,10 +637,10 @@ fn optional_field_singleton_record() {
fn optional_field_empty_record() { fn optional_field_empty_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when { } is when { } is
{ x ? 3 } -> x { x ? 3 } -> x
"# "
), ),
3, 3,
i64 i64
@ -652,9 +652,9 @@ fn optional_field_empty_record() {
fn return_record_2() { fn return_record_2() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ x: 3, y: 5 } { x: 3, y: 5 }
"# "
), ),
[3, 5], [3, 5],
[i64; 2] [i64; 2]
@ -666,9 +666,9 @@ fn return_record_2() {
fn return_record_3() { fn return_record_3() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ x: 3, y: 5, z: 4 } { x: 3, y: 5, z: 4 }
"# "
), ),
(3, 5, 4), (3, 5, 4),
(i64, i64, i64) (i64, i64, i64)
@ -680,9 +680,9 @@ fn return_record_3() {
fn return_record_4() { fn return_record_4() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ a: 3, b: 5, c: 4, d: 2 } { a: 3, b: 5, c: 4, d: 2 }
"# "
), ),
[3, 5, 4, 2], [3, 5, 4, 2],
[i64; 4] [i64; 4]
@ -694,9 +694,9 @@ fn return_record_4() {
fn return_record_5() { fn return_record_5() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ a: 3, b: 5, c: 4, d: 2, e: 1 } { a: 3, b: 5, c: 4, d: 2, e: 1 }
"# "
), ),
[3, 5, 4, 2, 1], [3, 5, 4, 2, 1],
[i64; 5] [i64; 5]
@ -708,9 +708,9 @@ fn return_record_5() {
fn return_record_6() { fn return_record_6() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ a: 3, b: 5, c: 4, d: 2, e: 1, f: 7 } { a: 3, b: 5, c: 4, d: 2, e: 1, f: 7 }
"# "
), ),
[3, 5, 4, 2, 1, 7], [3, 5, 4, 2, 1, 7],
[i64; 6] [i64; 6]
@ -722,9 +722,9 @@ fn return_record_6() {
fn return_record_7() { fn return_record_7() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ a: 3, b: 5, c: 4, d: 2, e: 1, f: 7, g: 8 } { a: 3, b: 5, c: 4, d: 2, e: 1, f: 7, g: 8 }
"# "
), ),
[3, 5, 4, 2, 1, 7, 8], [3, 5, 4, 2, 1, 7, 8],
[i64; 7] [i64; 7]
@ -736,9 +736,9 @@ fn return_record_7() {
fn return_record_float_int() { fn return_record_float_int() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ a: 1.23f64, b: 0x1 } { a: 1.23f64, b: 0x1 }
"# "
), ),
(1.23, 0x1), (1.23, 0x1),
(f64, i64) (f64, i64)
@ -750,9 +750,9 @@ fn return_record_float_int() {
fn return_record_int_float() { fn return_record_int_float() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ a: 0x1, b: 1.23f64 } { a: 0x1, b: 1.23f64 }
"# "
), ),
(0x1, 1.23), (0x1, 1.23),
(i64, f64) (i64, f64)
@ -764,9 +764,9 @@ fn return_record_int_float() {
fn return_record_float_float() { fn return_record_float_float() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ a: 2.46f64, b: 1.23f64 } { a: 2.46f64, b: 1.23f64 }
"# "
), ),
(2.46, 1.23), (2.46, 1.23),
(f64, f64) (f64, f64)
@ -778,9 +778,9 @@ fn return_record_float_float() {
fn return_record_float_float_float() { fn return_record_float_float_float() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ a: 2.46f64, b: 1.23f64, c: 0.1f64 } { a: 2.46f64, b: 1.23f64, c: 0.1f64 }
"# "
), ),
(2.46, 1.23, 0.1), (2.46, 1.23, 0.1),
(f64, f64, f64) (f64, f64, f64)
@ -792,9 +792,9 @@ fn return_record_float_float_float() {
fn return_nested_record() { fn return_nested_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
{ flag: 0x0, payload: { a: 2.46f64, b: 1.23f64, c: 0.1f64 } } { flag: 0x0, payload: { a: 2.46f64, b: 1.23f64, c: 0.1f64 } }
"# "
), ),
(0x0, (2.46, 1.23, 0.1)), (0x0, (2.46, 1.23, 0.1)),
(i64, (f64, f64, f64)) (i64, (f64, f64, f64))
@ -806,13 +806,13 @@ fn return_nested_record() {
fn nested_record_load() { fn nested_record_load() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x = { a : { b : 0x5 } } x = { a : { b : 0x5 } }
y = x.a y = x.a
y.b y.b
"# "
), ),
5, 5,
i64 i64
@ -844,9 +844,9 @@ fn accessor_multi_element_record() {
fn accessor_single_element_record() { fn accessor_single_element_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
.foo { foo: 4 } .foo { foo: 4 }
"# "
), ),
4, 4,
i64 i64
@ -858,11 +858,11 @@ fn accessor_single_element_record() {
fn update_record() { fn update_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
rec = { foo: 42, bar: 2.46f64 } rec = { foo: 42, bar: 2.46f64 }
{ rec & foo: rec.foo + 1 } { rec & foo: rec.foo + 1 }
"# "
), ),
(2.46, 43), (2.46, 43),
(f64, i64) (f64, i64)
@ -874,11 +874,11 @@ fn update_record() {
fn update_single_element_record() { fn update_single_element_record() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
rec = { foo: 42} rec = { foo: 42}
{ rec & foo: rec.foo + 1 } { rec & foo: rec.foo + 1 }
"# "
), ),
43, 43,
i64 i64
@ -927,14 +927,14 @@ fn alignment_in_record() {
fn blue_and_present() { fn blue_and_present() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
f = \r -> f = \r ->
when r is when r is
{ x: Blue, y ? 3 } -> y { x: Blue, y ? 3 } -> y
{ x: Red, y ? 5 } -> y { x: Red, y ? 5 } -> y
f { x: Blue, y: 7 } f { x: Blue, y: 7 }
"# "
), ),
7, 7,
i64 i64
@ -946,14 +946,14 @@ fn blue_and_present() {
fn blue_and_absent() { fn blue_and_absent() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
f = \r -> f = \r ->
when r is when r is
{ x: Blue, y ? 3 } -> y { x: Blue, y ? 3 } -> y
{ x: Red, y ? 5 } -> y { x: Red, y ? 5 } -> y
f { x: Blue } f { x: Blue }
"# "
), ),
3, 3,
i64 i64
@ -965,7 +965,7 @@ fn blue_and_absent() {
fn update_the_only_field() { fn update_the_only_field() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Model : { foo : I64 } Model : { foo : I64 }
model : Model model : Model
@ -977,7 +977,7 @@ fn update_the_only_field() {
newModel = { model & foo } newModel = { model & foo }
newModel.foo newModel.foo
"# "
), ),
4, 4,
i64 i64
@ -990,7 +990,7 @@ fn update_the_only_field() {
fn both_have_unique_fields() { fn both_have_unique_fields() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
a = { x: 42, y: 43 } a = { x: 42, y: 43 }
b = { x: 42, z: 44 } b = { x: 42, z: 44 }
@ -998,7 +998,7 @@ fn both_have_unique_fields() {
f = \{ x: x1}, { x: x2 } -> x1 + x2 f = \{ x: x1}, { x: x2 } -> x1 + x2
f a b f a b
"# "
), ),
84, 84,
i64 i64

View file

@ -17,12 +17,12 @@ use roc_std::{RocResult, RocStr};
fn with_default_ok() { fn with_default_ok() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
result : Result I64 {} result : Result I64 {}
result = Ok 12345 result = Ok 12345
Result.withDefault result 0 Result.withDefault result 0
"# "
), ),
12345, 12345,
i64 i64
@ -34,12 +34,12 @@ fn with_default_ok() {
fn with_default_err() { fn with_default_err() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
result : Result I64 {} result : Result I64 {}
result = Err {} result = Err {}
Result.withDefault result 0 Result.withDefault result 0
"# "
), ),
0, 0,
i64 i64
@ -51,14 +51,14 @@ fn with_default_err() {
fn result_map() { fn result_map() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
result : Result I64 {} result : Result I64 {}
result = Ok 2 result = Ok 2
result result
|> Result.map (\x -> x + 1) |> Result.map (\x -> x + 1)
|> Result.withDefault 0 |> Result.withDefault 0
"# "
), ),
3, 3,
i64 i64
@ -66,14 +66,14 @@ fn result_map() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
result : Result I64 {} result : Result I64 {}
result = Err {} result = Err {}
result result
|> Result.map (\x -> x + 1) |> Result.map (\x -> x + 1)
|> Result.withDefault 0 |> Result.withDefault 0
"# "
), ),
0, 0,
i64 i64
@ -85,14 +85,14 @@ fn result_map() {
fn result_map_err() { fn result_map_err() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
result : Result {} I64 result : Result {} I64
result = Err 2 result = Err 2
when Result.mapErr result (\x -> x + 1) is when Result.mapErr result (\x -> x + 1) is
Err n -> n Err n -> n
Ok _ -> 0 Ok _ -> 0
"# "
), ),
3, 3,
i64 i64
@ -100,14 +100,14 @@ fn result_map_err() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
result : Result {} I64 result : Result {} I64
result = Ok {} result = Ok {}
when Result.mapErr result (\x -> x + 1) is when Result.mapErr result (\x -> x + 1) is
Err n -> n Err n -> n
Ok _ -> 0 Ok _ -> 0
"# "
), ),
0, 0,
i64 i64
@ -119,10 +119,10 @@ fn result_map_err() {
fn err_type_var() { fn err_type_var() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Result.map (Ok 3) (\x -> x + 1) Result.map (Ok 3) (\x -> x + 1)
|> Result.withDefault -1 |> Result.withDefault -1
"# "
), ),
4, 4,
i64 i64
@ -134,13 +134,13 @@ fn err_type_var() {
fn err_type_var_annotation() { fn err_type_var_annotation() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
ok : Result I64 * ok : Result I64 *
ok = Ok 3 ok = Ok 3
Result.map ok (\x -> x + 1) Result.map ok (\x -> x + 1)
|> Result.withDefault -1 |> Result.withDefault -1
"# "
), ),
4, 4,
i64 i64
@ -152,13 +152,13 @@ fn err_type_var_annotation() {
fn err_empty_tag_union() { fn err_empty_tag_union() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
ok : Result I64 [] ok : Result I64 []
ok = Ok 3 ok = Ok 3
Result.map ok (\x -> x + 1) Result.map ok (\x -> x + 1)
|> Result.withDefault -1 |> Result.withDefault -1
"# "
), ),
4, 4,
i64 i64
@ -170,12 +170,12 @@ fn err_empty_tag_union() {
fn is_ok() { fn is_ok() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
result : Result I64 {} result : Result I64 {}
result = Ok 2 result = Ok 2
Result.isOk result Result.isOk result
"# "
), ),
true, true,
bool bool
@ -183,12 +183,12 @@ fn is_ok() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
result : Result I64 {} result : Result I64 {}
result = Err {} result = Err {}
Result.isOk result Result.isOk result
"# "
), ),
false, false,
bool bool
@ -200,12 +200,12 @@ fn is_ok() {
fn is_err() { fn is_err() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
result : Result I64 {} result : Result I64 {}
result = Ok 2 result = Ok 2
Result.isErr result Result.isErr result
"# "
), ),
false, false,
bool bool
@ -213,12 +213,12 @@ fn is_err() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
result : Result I64 {} result : Result I64 {}
result = Err {} result = Err {}
Result.isErr result Result.isErr result
"# "
), ),
true, true,
bool bool
@ -230,12 +230,12 @@ fn is_err() {
fn roc_result_ok_i64() { fn roc_result_ok_i64() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
result : Result I64 {} result : Result I64 {}
result = Ok 42 result = Ok 42
result result
"# "
), ),
RocResult::ok(42), RocResult::ok(42),
RocResult<i64, ()> RocResult<i64, ()>
@ -250,12 +250,12 @@ fn roc_result_ok_f64() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
result : Result F64 {} result : Result F64 {}
result = Ok 42.0 result = Ok 42.0
result result
"# "
), ),
RocResult::ok(42.0), RocResult::ok(42.0),
RocResult<f64, ()> RocResult<f64, ()>

View file

@ -20,9 +20,9 @@ use roc_std::RocList;
fn empty_len() { fn empty_len() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Set.len (Set.empty {}) Set.len (Set.empty {})
"# "
), ),
0, 0,
usize usize
@ -34,9 +34,9 @@ fn empty_len() {
fn single_len() { fn single_len() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Set.len (Set.single 42) Set.len (Set.single 42)
"# "
), ),
1, 1,
usize usize
@ -48,9 +48,9 @@ fn single_len() {
fn single_to_list() { fn single_to_list() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Set.toList (Set.single 42) Set.toList (Set.single 42)
"# "
), ),
RocList::from_slice(&[42]), RocList::from_slice(&[42]),
RocList<i64> RocList<i64>
@ -58,9 +58,9 @@ fn single_to_list() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Set.toList (Set.single 1) Set.toList (Set.single 1)
"# "
), ),
RocList::from_slice(&[1]), RocList::from_slice(&[1]),
RocList<i64> RocList<i64>
@ -72,13 +72,13 @@ fn single_to_list() {
fn insert() { fn insert() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Set.empty {} Set.empty {}
|> Set.insert 0 |> Set.insert 0
|> Set.insert 1 |> Set.insert 1
|> Set.insert 2 |> Set.insert 2
|> Set.toList |> Set.toList
"# "
), ),
RocList::from_slice(&[0, 1, 2]), RocList::from_slice(&[0, 1, 2]),
RocList<i64> RocList<i64>
@ -90,14 +90,14 @@ fn insert() {
fn remove() { fn remove() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Set.empty {} Set.empty {}
|> Set.insert 0 |> Set.insert 0
|> Set.insert 1 |> Set.insert 1
|> Set.remove 1 |> Set.remove 1
|> Set.remove 2 |> Set.remove 2
|> Set.toList |> Set.toList
"# "
), ),
RocList::from_slice(&[0]), RocList::from_slice(&[0]),
RocList<i64> RocList<i64>
@ -109,7 +109,7 @@ fn remove() {
fn union() { fn union() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
set1 : Set.Set I64 set1 : Set.Set I64
set1 = Set.fromList [1,2] set1 = Set.fromList [1,2]
@ -118,7 +118,7 @@ fn union() {
Set.union set1 set2 Set.union set1 set2
|> Set.toList |> Set.toList
"# "
), ),
RocList::from_slice(&[1, 3, 4, 2]), RocList::from_slice(&[1, 3, 4, 2]),
RocList<i64> RocList<i64>
@ -130,7 +130,7 @@ fn union() {
fn difference() { fn difference() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
set1 : Set.Set I64 set1 : Set.Set I64
set1 = Set.fromList [1,2] set1 = Set.fromList [1,2]
@ -139,7 +139,7 @@ fn difference() {
Set.difference set1 set2 Set.difference set1 set2
|> Set.toList |> Set.toList
"# "
), ),
RocList::from_slice(&[2]), RocList::from_slice(&[2]),
RocList<i64> RocList<i64>
@ -151,7 +151,7 @@ fn difference() {
fn intersection() { fn intersection() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
set1 : Set.Set I64 set1 : Set.Set I64
set1 = Set.fromList [1,2] set1 = Set.fromList [1,2]
@ -160,7 +160,7 @@ fn intersection() {
Set.intersection set1 set2 Set.intersection set1 set2
|> Set.toList |> Set.toList
"# "
), ),
RocList::from_slice(&[1]), RocList::from_slice(&[1]),
RocList<i64> RocList<i64>
@ -172,9 +172,9 @@ fn intersection() {
fn walk_sum() { fn walk_sum() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Set.walk (Set.fromList [1,2,3]) 0 (\x, y -> x + y) Set.walk (Set.fromList [1,2,3]) 0 (\x, y -> x + y)
"# "
), ),
6, 6,
i64 i64
@ -186,9 +186,9 @@ fn walk_sum() {
fn contains() { fn contains() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Set.contains (Set.fromList [1,3,4]) 4 Set.contains (Set.fromList [1,3,4]) 4
"# "
), ),
true, true,
bool bool
@ -196,9 +196,9 @@ fn contains() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Set.contains (Set.fromList [1,3,4]) 2 Set.contains (Set.fromList [1,3,4]) 2
"# "
), ),
false, false,
bool bool
@ -210,11 +210,11 @@ fn contains() {
fn from_list() { fn from_list() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
[1,2,2,3,1,4] [1,2,2,3,1,4]
|> Set.fromList |> Set.fromList
|> Set.toList |> Set.toList
"# "
), ),
RocList::from_slice(&[1, 2, 3, 4]), RocList::from_slice(&[1, 2, 3, 4]),
RocList<i64> RocList<i64>
@ -222,14 +222,14 @@ fn from_list() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
empty : List I64 empty : List I64
empty = [] empty = []
empty empty
|> Set.fromList |> Set.fromList
|> Set.toList |> Set.toList
"# "
), ),
RocList::<i64>::default(), RocList::<i64>::default(),
RocList<i64> RocList<i64>
@ -242,11 +242,11 @@ fn from_list() {
fn from_list_void() { fn from_list_void() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
[] []
|> Set.fromList |> Set.fromList
|> Set.toList |> Set.toList
"# "
), ),
RocList::<i64>::default(), RocList::<i64>::default(),
RocList<i64> RocList<i64>
@ -258,9 +258,9 @@ fn from_list_void() {
fn to_list_empty() { fn to_list_empty() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Set.toList (Set.empty {}) Set.toList (Set.empty {})
"# "
), ),
RocList::<std::convert::Infallible>::default(), RocList::<std::convert::Infallible>::default(),
RocList<std::convert::Infallible> RocList<std::convert::Infallible>

View file

@ -39,14 +39,14 @@ fn width_and_alignment_u8_u8() {
fn applied_tag_nothing() { fn applied_tag_nothing() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Maybe a : [Just a, Nothing] Maybe a : [Just a, Nothing]
x : Maybe I64 x : Maybe I64
x = Nothing x = Nothing
x x
"# "
), ),
1, 1,
(i64, u8), (i64, u8),
@ -59,14 +59,14 @@ fn applied_tag_nothing() {
fn applied_tag_just() { fn applied_tag_just() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Maybe a : [Just a, Nothing] Maybe a : [Just a, Nothing]
y : Maybe I64 y : Maybe I64
y = Just 0x4 y = Just 0x4
y y
"# "
), ),
(0x4, 0), (0x4, 0),
(i64, u8) (i64, u8)
@ -78,7 +78,7 @@ fn applied_tag_just() {
fn applied_tag_just_enum() { fn applied_tag_just_enum() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Fruit : [Orange, Apple, Banana] Fruit : [Orange, Apple, Banana]
Maybe a : [Just a, Nothing] Maybe a : [Just a, Nothing]
@ -89,7 +89,7 @@ fn applied_tag_just_enum() {
y = Just orange y = Just orange
y y
"# "
), ),
(2, 0), (2, 0),
(u8, u8) (u8, u8)
@ -101,12 +101,12 @@ fn applied_tag_just_enum() {
fn true_is_true() { fn true_is_true() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
bool : Bool bool : Bool
bool = Bool.true bool = Bool.true
bool bool
"# "
), ),
true, true,
bool bool
@ -118,12 +118,12 @@ fn true_is_true() {
fn false_is_false() { fn false_is_false() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
bool : Bool bool : Bool
bool = Bool.false bool = Bool.false
bool bool
"# "
), ),
false, false,
bool bool
@ -135,7 +135,7 @@ fn false_is_false() {
fn basic_enum() { fn basic_enum() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Fruit : [Apple, Orange, Banana] Fruit : [Apple, Orange, Banana]
apple : Fruit apple : Fruit
@ -145,7 +145,7 @@ fn basic_enum() {
orange = Orange orange = Orange
apple == orange apple == orange
"# "
), ),
false, false,
bool bool
@ -157,7 +157,7 @@ fn basic_enum() {
fn even_odd() { fn even_odd() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
even = \n -> even = \n ->
when n is when n is
0 -> Bool.true 0 -> Bool.true
@ -171,7 +171,7 @@ fn even_odd() {
_ -> even (n - 1) _ -> even (n - 1)
odd 5 && even 42 odd 5 && even 42
"# "
), ),
true, true,
bool bool
@ -183,9 +183,9 @@ fn even_odd() {
fn gen_literal_true() { fn gen_literal_true() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
if Bool.true then -1 else 1 if Bool.true then -1 else 1
"# "
), ),
-1, -1,
i64 i64
@ -197,9 +197,9 @@ fn gen_literal_true() {
fn gen_if_float() { fn gen_if_float() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
if Bool.true then -1.0 else 1.0f64 if Bool.true then -1.0 else 1.0f64
"# "
), ),
-1.0, -1.0,
f64 f64
@ -210,14 +210,14 @@ fn gen_if_float() {
fn when_on_nothing() { fn when_on_nothing() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x : [Nothing, Just I64] x : [Nothing, Just I64]
x = Nothing x = Nothing
when x is when x is
Nothing -> 0x2 Nothing -> 0x2
Just _ -> 0x1 Just _ -> 0x1
"# "
), ),
2, 2,
i64 i64
@ -229,14 +229,14 @@ fn when_on_nothing() {
fn when_on_just() { fn when_on_just() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x : [Nothing, Just I64] x : [Nothing, Just I64]
x = Just 41 x = Just 41
when x is when x is
Just v -> v + 0x1 Just v -> v + 0x1
Nothing -> 0x1 Nothing -> 0x1
"# "
), ),
42, 42,
i64 i64
@ -248,14 +248,14 @@ fn when_on_just() {
fn when_on_result() { fn when_on_result() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x : Result I64 I64 x : Result I64 I64
x = Err 41 x = Err 41
when x is when x is
Err v -> v + 1 Err v -> v + 1
Ok _ -> 1 Ok _ -> 1
"# "
), ),
42, 42,
i64 i64
@ -267,7 +267,7 @@ fn when_on_result() {
fn when_on_these() { fn when_on_these() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
These a b : [This a, That b, These a b] These a b : [This a, That b, These a b]
x : These I64 I64 x : These I64 I64
@ -277,7 +277,7 @@ fn when_on_these() {
These a b -> a + b These a b -> a + b
That v -> v That v -> v
This v -> v This v -> v
"# "
), ),
5, 5,
i64 i64
@ -290,11 +290,11 @@ fn match_on_two_values() {
// this will produce a Chain internally // this will produce a Chain internally
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when Pair 2 3 is when Pair 2 3 is
Pair 4 3 -> 9 Pair 4 3 -> 9
Pair a b -> a + b Pair a b -> a + b
"# "
), ),
5, 5,
i64 i64
@ -306,12 +306,12 @@ fn match_on_two_values() {
fn pair_with_underscore() { fn pair_with_underscore() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when Pair 2 3 is when Pair 2 3 is
Pair 4 _ -> 1 Pair 4 _ -> 1
Pair 3 _ -> 2 Pair 3 _ -> 2
Pair a b -> a + b Pair a b -> a + b
"# "
), ),
5, 5,
i64 i64
@ -324,7 +324,7 @@ fn result_with_underscore() {
// This test revealed an issue with hashing Test values // This test revealed an issue with hashing Test values
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x : Result I64 I64 x : Result I64 I64
x = Ok 2 x = Ok 2
@ -332,7 +332,7 @@ fn result_with_underscore() {
Ok 3 -> 1 Ok 3 -> 1
Ok _ -> 2 Ok _ -> 2
Err _ -> 3 Err _ -> 3
"# "
), ),
2, 2,
i64 i64
@ -369,7 +369,7 @@ fn maybe_is_just_not_nested() {
fn maybe_is_just_nested() { fn maybe_is_just_nested() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Maybe a : [Just a, Nothing] Maybe a : [Just a, Nothing]
isJust : Maybe a -> Bool isJust : Maybe a -> Bool
@ -379,7 +379,7 @@ fn maybe_is_just_nested() {
Just _ -> Bool.true Just _ -> Bool.true
isJust (Just 42) isJust (Just 42)
"# "
), ),
true, true,
bool bool
@ -391,7 +391,7 @@ fn maybe_is_just_nested() {
fn nested_pattern_match() { fn nested_pattern_match() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Maybe a : [Nothing, Just a] Maybe a : [Nothing, Just a]
x : Maybe (Maybe I64) x : Maybe (Maybe I64)
@ -400,7 +400,7 @@ fn nested_pattern_match() {
when x is when x is
Just (Just v) -> v + 0x1 Just (Just v) -> v + 0x1
_ -> 0x1 _ -> 0x1
"# "
), ),
42, 42,
i64 i64
@ -428,11 +428,11 @@ fn if_guard_vanilla() {
fn when_on_single_value_tag() { fn when_on_single_value_tag() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when Identity 0 is when Identity 0 is
Identity 0 -> 6 Identity 0 -> 6
Identity s -> s Identity s -> s
"# "
), ),
6, 6,
i64 i64
@ -444,7 +444,7 @@ fn when_on_single_value_tag() {
fn if_guard_multiple() { fn if_guard_multiple() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
f = \n -> f = \n ->
when Identity n 0 is when Identity n 0 is
Identity x _ if x == 0 -> x + 0 Identity x _ if x == 0 -> x + 0
@ -453,7 +453,7 @@ fn if_guard_multiple() {
Identity x _ -> x - x Identity x _ -> x - x
{ a: f 0, b: f 1, c: f 2, d: f 4 } { a: f 0, b: f 1, c: f 2, d: f 4 }
"# "
), ),
[0, 1, 2, 0], [0, 1, 2, 0],
[i64; 4] [i64; 4]
@ -465,13 +465,13 @@ fn if_guard_multiple() {
fn if_guard_constructor_switch() { fn if_guard_constructor_switch() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when Identity 32 0 is when Identity 32 0 is
Identity 41 _ -> 0 Identity 41 _ -> 0
Identity s 0 if s == 32 -> 3 Identity s 0 if s == 32 -> 3
# Identity s 0 -> s # Identity s 0 -> s
Identity z _ -> z Identity z _ -> z
"# "
), ),
3, 3,
i64 i64
@ -509,12 +509,12 @@ fn if_guard_constructor_switch() {
fn if_guard_constructor_chain() { fn if_guard_constructor_chain() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when Identity 43 0 is when Identity 43 0 is
Identity 42 _ if 3 == 3 -> 43 Identity 42 _ if 3 == 3 -> 43
# Identity 42 _ -> 1 # Identity 42 _ -> 1
Identity z _ -> z Identity z _ -> z
"# "
), ),
43, 43,
i64 i64
@ -526,14 +526,14 @@ fn if_guard_constructor_chain() {
fn if_guard_pattern_false() { fn if_guard_pattern_false() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
wrapper = \{} -> wrapper = \{} ->
when 2 is when 2 is
2 if Bool.false -> 0 2 if Bool.false -> 0
_ -> 42 _ -> 42
wrapper {} wrapper {}
"# "
), ),
42, 42,
i64 i64
@ -545,14 +545,14 @@ fn if_guard_pattern_false() {
fn if_guard_switch() { fn if_guard_switch() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
wrapper = \{} -> wrapper = \{} ->
when 2 is when 2 is
2 | 3 if Bool.false -> 0 2 | 3 if Bool.false -> 0
_ -> 42 _ -> 42
wrapper {} wrapper {}
"# "
), ),
42, 42,
i64 i64
@ -564,14 +564,14 @@ fn if_guard_switch() {
fn if_guard_pattern_true() { fn if_guard_pattern_true() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
wrapper = \{} -> wrapper = \{} ->
when 2 is when 2 is
2 if Bool.true -> 42 2 if Bool.true -> 42
_ -> 0 _ -> 0
wrapper {} wrapper {}
"# "
), ),
42, 42,
i64 i64
@ -583,14 +583,14 @@ fn if_guard_pattern_true() {
fn if_guard_exhaustiveness() { fn if_guard_exhaustiveness() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
wrapper = \{} -> wrapper = \{} ->
when 2 is when 2 is
_ if Bool.false -> 0 _ if Bool.false -> 0
_ -> 42 _ -> 42
wrapper {} wrapper {}
"# "
), ),
42, 42,
i64 i64
@ -602,7 +602,7 @@ fn if_guard_exhaustiveness() {
fn when_on_enum() { fn when_on_enum() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Fruit : [Apple, Orange, Banana] Fruit : [Apple, Orange, Banana]
apple : Fruit apple : Fruit
@ -612,7 +612,7 @@ fn when_on_enum() {
Apple -> 1 Apple -> 1
Banana -> 2 Banana -> 2
Orange -> 3 Orange -> 3
"# "
), ),
1, 1,
i64 i64
@ -624,14 +624,14 @@ fn when_on_enum() {
fn pattern_matching_unit() { fn pattern_matching_unit() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Unit : [Unit] Unit : [Unit]
f : Unit -> I64 f : Unit -> I64
f = \Unit -> 42 f = \Unit -> 42
f Unit f Unit
"# "
), ),
42, 42,
i64 i64
@ -639,7 +639,7 @@ fn pattern_matching_unit() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Unit : [Unit] Unit : [Unit]
x : Unit x : Unit
@ -647,7 +647,7 @@ fn pattern_matching_unit() {
when x is when x is
Unit -> 42 Unit -> 42
"# "
), ),
42, 42,
i64 i64
@ -655,12 +655,12 @@ fn pattern_matching_unit() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
f : {} -> I64 f : {} -> I64
f = \{} -> 42 f = \{} -> 42
f {} f {}
"# "
), ),
42, 42,
i64 i64
@ -668,10 +668,10 @@ fn pattern_matching_unit() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when {} is when {} is
{} -> 42 {} -> 42
"# "
), ),
42, 42,
i64 i64
@ -683,12 +683,12 @@ fn pattern_matching_unit() {
fn one_element_tag() { fn one_element_tag() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x : [Pair I64] x : [Pair I64]
x = Pair 2 x = Pair 2
x x
"# "
), ),
2, 2,
i64 i64
@ -721,14 +721,14 @@ fn nested_tag_union() {
fn unit_type() { fn unit_type() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Unit : [Unit] Unit : [Unit]
v : Unit v : Unit
v = Unit v = Unit
v v
"# "
), ),
(), (),
() ()
@ -740,12 +740,12 @@ fn unit_type() {
fn join_point_if() { fn join_point_if() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x = x =
if Bool.true then 1 else 2 if Bool.true then 1 else 2
x x
"# "
), ),
1, 1,
i64 i64
@ -757,7 +757,7 @@ fn join_point_if() {
fn join_point_when() { fn join_point_when() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
wrapper = \{} -> wrapper = \{} ->
x : [Red, White, Blue] x : [Red, White, Blue]
x = Blue x = Blue
@ -771,7 +771,7 @@ fn join_point_when() {
y y
wrapper {} wrapper {}
"# "
), ),
3.1, 3.1,
f64 f64
@ -783,7 +783,7 @@ fn join_point_when() {
fn join_point_with_cond_expr() { fn join_point_with_cond_expr() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
wrapper = \{} -> wrapper = \{} ->
y = y =
when 1 + 2 is when 1 + 2 is
@ -794,7 +794,7 @@ fn join_point_with_cond_expr() {
y y
wrapper {} wrapper {}
"# "
), ),
3, 3,
i64 i64
@ -802,7 +802,7 @@ fn join_point_with_cond_expr() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
y = y =
if 1 + 2 > 0 then if 1 + 2 > 0 then
3 3
@ -810,7 +810,7 @@ fn join_point_with_cond_expr() {
0 0
y y
"# "
), ),
3, 3,
i64 i64
@ -1135,12 +1135,12 @@ fn applied_tag_function_pair() {
fn tag_must_be_its_own_type() { fn tag_must_be_its_own_type() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
z : [A, B, C] z : [A, B, C]
z = Z z = Z
z z
"# "
), ),
1, 1,
i64 i64
@ -1171,12 +1171,12 @@ fn recursive_tag_union_into_flat_tag_union() {
fn monomorphized_tag() { fn monomorphized_tag() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
b = \{} -> Bar b = \{} -> Bar
f : [Foo, Bar], [Bar, Baz] -> U8 f : [Foo, Bar], [Bar, Baz] -> U8
f = \_, _ -> 18 f = \_, _ -> 18
f (b {}) (b {}) f (b {}) (b {})
"# "
), ),
18, 18,
u8 u8
@ -1391,7 +1391,7 @@ fn issue_2445() {
fn issue_2458() { fn issue_2458() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
Foo a : [Blah (Bar a), Nothing {}] Foo a : [Blah (Bar a), Nothing {}]
Bar a : Foo a Bar a : Foo a
@ -1401,7 +1401,7 @@ fn issue_2458() {
when v is when v is
Blah (Blah (Nothing {})) -> 15 Blah (Blah (Nothing {})) -> 15
_ -> 25 _ -> 25
"# "
), ),
15, 15,
u8 u8
@ -1471,11 +1471,11 @@ fn issue_1162() {
fn polymorphic_tag() { fn polymorphic_tag() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x : [Y U8] x : [Y U8]
x = Y 3 x = Y 3
x x
"# "
), ),
3, // Y is a newtype, it gets unwrapped 3, // Y is a newtype, it gets unwrapped
u8 u8
@ -1487,11 +1487,11 @@ fn polymorphic_tag() {
fn issue_2725_alias_polymorphic_lambda() { fn issue_2725_alias_polymorphic_lambda() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
wrap = \value -> Tag value wrap = \value -> Tag value
wrapIt = wrap wrapIt = wrap
wrapIt 42 wrapIt 42
"# "
), ),
42, // Tag is a newtype, it gets unwrapped 42, // Tag is a newtype, it gets unwrapped
i64 i64
@ -1717,7 +1717,7 @@ fn instantiate_annotated_as_recursive_alias_multiple_polymorphic_expr() {
fn issue_3560_nested_tag_constructor_is_newtype() { fn issue_3560_nested_tag_constructor_is_newtype() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
f : _ -> u8 f : _ -> u8
f = \t -> f = \t ->
when t is when t is
@ -1725,7 +1725,7 @@ fn issue_3560_nested_tag_constructor_is_newtype() {
Wrapper (AlternatePayload it) -> it Wrapper (AlternatePayload it) -> it
{a: f (Wrapper (Payload 15u8)), b: f(Wrapper (AlternatePayload 31u8))} {a: f (Wrapper (Payload 15u8)), b: f(Wrapper (AlternatePayload 31u8))}
"# "
), ),
(15, 31), (15, 31),
(u8, u8) (u8, u8)
@ -1737,7 +1737,7 @@ fn issue_3560_nested_tag_constructor_is_newtype() {
fn issue_3560_nested_tag_constructor_is_record_newtype() { fn issue_3560_nested_tag_constructor_is_record_newtype() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
f : _ -> u8 f : _ -> u8
f = \t -> f = \t ->
when t is when t is
@ -1745,7 +1745,7 @@ fn issue_3560_nested_tag_constructor_is_record_newtype() {
{wrapper: (AlternatePayload it)} -> it {wrapper: (AlternatePayload it)} -> it
{a: f {wrapper: (Payload 15u8)}, b: f {wrapper: (AlternatePayload 31u8)}} {a: f {wrapper: (Payload 15u8)}, b: f {wrapper: (AlternatePayload 31u8)}}
"# "
), ),
(15, 31), (15, 31),
(u8, u8) (u8, u8)
@ -1791,7 +1791,7 @@ fn alignment_i128() {
fn error_type_in_tag_union_payload() { fn error_type_in_tag_union_payload() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
f : ([] -> Bool) -> Bool f : ([] -> Bool) -> Bool
f = \fun -> f = \fun ->
if Bool.true then if Bool.true then
@ -1800,7 +1800,7 @@ fn error_type_in_tag_union_payload() {
Bool.false Bool.false
f (\x -> x) f (\x -> x)
"# "
), ),
0, 0,
u8, u8,
@ -1864,7 +1864,7 @@ fn issue_3653_recursion_pointer_in_naked_opaque_localized() {
fn issue_2165_recursive_tag_destructure() { fn issue_2165_recursive_tag_destructure() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
SomeTag : [ Ctor { rec : List SomeTag } ] SomeTag : [ Ctor { rec : List SomeTag } ]
x : SomeTag x : SomeTag
@ -1872,7 +1872,7 @@ fn issue_2165_recursive_tag_destructure() {
when x is when x is
Ctor { rec } -> Num.toStr (List.len rec) Ctor { rec } -> Num.toStr (List.len rec)
"# "
), ),
RocStr::from("0"), RocStr::from("0"),
RocStr RocStr
@ -2183,7 +2183,7 @@ fn issue_5162_recast_nested_nullable_unwrapped_layout() {
with_larger_debug_stack(|| { with_larger_debug_stack(|| {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r###" r#"
app "test" provides [main] to "./platform" app "test" provides [main] to "./platform"
Concept : [ Concept : [
@ -2197,7 +2197,7 @@ fn issue_5162_recast_nested_nullable_unwrapped_layout() {
main = main =
when Dict.single bottom 0 is when Dict.single bottom 0 is
_ -> Bool.true _ -> Bool.true
"### "#
), ),
true, true,
bool bool
@ -2210,7 +2210,7 @@ fn issue_5162_recast_nested_nullable_unwrapped_layout() {
fn nullable_wrapped_eq_issue_5434() { fn nullable_wrapped_eq_issue_5434() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r###" r#"
app "test" provides [main] to "./platform" app "test" provides [main] to "./platform"
Value : [ Value : [
@ -2229,7 +2229,7 @@ fn nullable_wrapped_eq_issue_5434() {
Bool.true Bool.true
else else
Bool.false Bool.false
"### "#
), ),
false, false,
bool bool
@ -2241,7 +2241,7 @@ fn nullable_wrapped_eq_issue_5434() {
fn recursive_tag_id_in_allocation_basic() { fn recursive_tag_id_in_allocation_basic() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r###" r#"
app "test" provides [main] to "./platform" app "test" provides [main] to "./platform"
Value : [ Value : [
@ -2270,7 +2270,7 @@ fn recursive_tag_id_in_allocation_basic() {
G _ -> "G" G _ -> "G"
H _ -> "H" H _ -> "H"
I _ -> "I" I _ -> "I"
"### "#
), ),
RocStr::from("H"), RocStr::from("H"),
RocStr RocStr
@ -2282,7 +2282,7 @@ fn recursive_tag_id_in_allocation_basic() {
fn recursive_tag_id_in_allocation_eq() { fn recursive_tag_id_in_allocation_eq() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r###" r#"
app "test" provides [main] to "./platform" app "test" provides [main] to "./platform"
Value : [ Value : [
@ -2304,7 +2304,7 @@ fn recursive_tag_id_in_allocation_eq() {
y = H 42 y = H 42
main = (x == x) && (x != y) && (y == y) main = (x == x) && (x != y) && (y == y)
"### "#
), ),
true, true,
bool bool

View file

@ -18,9 +18,9 @@ use roc_std::RocStr;
fn basic_tuple() { fn basic_tuple() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
( 15, 17, 19 ).0 ( 15, 17, 19 ).0
"# "
), ),
15, 15,
i64 i64
@ -28,9 +28,9 @@ fn basic_tuple() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
( 15, 17, 19 ).1 ( 15, 17, 19 ).1
"# "
), ),
17, 17,
i64 i64
@ -38,9 +38,9 @@ fn basic_tuple() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
( 15, 17, 19 ).2 ( 15, 17, 19 ).2
"# "
), ),
19, 19,
i64 i64
@ -52,11 +52,11 @@ fn basic_tuple() {
fn f64_tuple() { fn f64_tuple() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
tup = (17.2f64, 15.1f64, 19.3f64) tup = (17.2f64, 15.1f64, 19.3f64)
tup.0 tup.0
"# "
), ),
17.2, 17.2,
f64 f64
@ -64,11 +64,11 @@ fn f64_tuple() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
tup = (17.2f64, 15.1f64, 19.3f64) tup = (17.2f64, 15.1f64, 19.3f64)
tup.1 tup.1
"# "
), ),
15.1, 15.1,
f64 f64
@ -76,11 +76,11 @@ fn f64_tuple() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
tup = (17.2f64, 15.1f64, 19.3f64) tup = (17.2f64, 15.1f64, 19.3f64)
tup.2 tup.2
"# "
), ),
19.3, 19.3,
f64 f64
@ -104,11 +104,11 @@ fn fn_tuple() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
rec = (15, 17, 19) rec = (15, 17, 19)
rec.2 + rec.0 rec.2 + rec.0
"# "
), ),
34, 34,
i64 i64
@ -120,11 +120,11 @@ fn fn_tuple() {
fn int_tuple() { fn int_tuple() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
rec = (15, 17, 19) rec = (15, 17, 19)
rec.0 rec.0
"# "
), ),
15, 15,
i64 i64
@ -132,11 +132,11 @@ fn int_tuple() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
rec = (15, 17, 19) rec = (15, 17, 19)
rec.1 rec.1
"# "
), ),
17, 17,
i64 i64
@ -144,11 +144,11 @@ fn int_tuple() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
rec = (15, 17, 19) rec = (15, 17, 19)
rec.2 rec.2
"# "
), ),
19, 19,
i64 i64
@ -160,10 +160,10 @@ fn int_tuple() {
fn when_on_tuple() { fn when_on_tuple() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when (0x2, 0x3) is when (0x2, 0x3) is
(x, y) -> x + y (x, y) -> x + y
"# "
), ),
5, 5,
i64 i64
@ -175,10 +175,10 @@ fn when_on_tuple() {
fn when_tuple_with_guard_pattern() { fn when_tuple_with_guard_pattern() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when (0x2, 1.23) is when (0x2, 1.23) is
(var, _) -> var + 3 (var, _) -> var + 3
"# "
), ),
5, 5,
i64 i64
@ -190,11 +190,11 @@ fn when_tuple_with_guard_pattern() {
fn let_with_tuple_pattern() { fn let_with_tuple_pattern() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
(x, _ ) = (0x2, 1.23) (x, _ ) = (0x2, 1.23)
x x
"# "
), ),
2, 2,
i64 i64
@ -202,11 +202,11 @@ fn let_with_tuple_pattern() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
(_, y) = (0x2, 0x3) (_, y) = (0x2, 0x3)
y y
"# "
), ),
3, 3,
i64 i64
@ -218,11 +218,11 @@ fn let_with_tuple_pattern() {
fn tuple_guard_pattern() { fn tuple_guard_pattern() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when (0x2, 1.23) is when (0x2, 1.23) is
(0x4, _) -> 5 (0x4, _) -> 5
(x, _) -> x + 4 (x, _) -> x + 4
"# "
), ),
6, 6,
i64 i64
@ -230,11 +230,11 @@ fn tuple_guard_pattern() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
when (0x2, 0x3) is when (0x2, 0x3) is
(_, 0x4) -> 5 (_, 0x4) -> 5
(_, x) -> x + 4 (_, x) -> x + 4
"# "
), ),
7, 7,
i64 i64
@ -246,11 +246,11 @@ fn tuple_guard_pattern() {
fn twice_tuple_access() { fn twice_tuple_access() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x = (0x2, 0x3) x = (0x2, 0x3)
x.0 + x.1 x.0 + x.1
"# "
), ),
5, 5,
i64 i64
@ -262,9 +262,9 @@ fn twice_tuple_access() {
fn i64_tuple2_literal() { fn i64_tuple2_literal() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
(3, 5) (3, 5)
"# "
), ),
(3, 5), (3, 5),
(i64, i64) (i64, i64)
@ -276,9 +276,9 @@ fn i64_tuple2_literal() {
fn i64_tuple3_literal() { fn i64_tuple3_literal() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
(3, 5, 17) (3, 5, 17)
"# "
), ),
(3, 5, 17), (3, 5, 17),
(i64, i64, i64) (i64, i64, i64)
@ -290,9 +290,9 @@ fn i64_tuple3_literal() {
fn f64_tuple2_literal() { fn f64_tuple2_literal() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
(3.1f64, 5.1f64) (3.1f64, 5.1f64)
"# "
), ),
(3.1, 5.1), (3.1, 5.1),
(f64, f64) (f64, f64)
@ -304,12 +304,12 @@ fn f64_tuple2_literal() {
fn bool_tuple4_literal() { fn bool_tuple4_literal() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
tuple : (Bool, Bool, Bool, Bool) tuple : (Bool, Bool, Bool, Bool)
tuple = (Bool.true, Bool.false, Bool.false, Bool.true) tuple = (Bool.true, Bool.false, Bool.false, Bool.true)
tuple tuple
"# "
), ),
(true, false, false, true), (true, false, false, true),
(bool, bool, bool, bool) (bool, bool, bool, bool)
@ -323,9 +323,9 @@ fn bool_tuple4_literal() {
fn i64_tuple9_literal() { fn i64_tuple9_literal() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
( 3, 5, 17, 1, 9, 12, 13, 14, 15 ) ( 3, 5, 17, 1, 9, 12, 13, 14, 15 )
"# "
), ),
[3, 5, 17, 1, 9, 12, 13, 14, 15], [3, 5, 17, 1, 9, 12, 13, 14, 15],
[i64; 9] [i64; 9]
@ -337,12 +337,12 @@ fn i64_tuple9_literal() {
fn return_tuple() { fn return_tuple() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x = 4 x = 4
y = 3 y = 3
(x, y) (x, y)
"# "
), ),
(4, 3), (4, 3),
(i64, i64) (i64, i64)
@ -354,9 +354,9 @@ fn return_tuple() {
fn return_tuple_2() { fn return_tuple_2() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
(3, 5) (3, 5)
"# "
), ),
[3, 5], [3, 5],
[i64; 2] [i64; 2]
@ -368,9 +368,9 @@ fn return_tuple_2() {
fn return_tuple_3() { fn return_tuple_3() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
( 3, 5, 4 ) ( 3, 5, 4 )
"# "
), ),
(3, 5, 4), (3, 5, 4),
(i64, i64, i64) (i64, i64, i64)
@ -382,9 +382,9 @@ fn return_tuple_3() {
fn return_tuple_4() { fn return_tuple_4() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
( 3, 5, 4, 2 ) ( 3, 5, 4, 2 )
"# "
), ),
[3, 5, 4, 2], [3, 5, 4, 2],
[i64; 4] [i64; 4]
@ -398,9 +398,9 @@ fn return_tuple_4() {
fn return_tuple_5() { fn return_tuple_5() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
( 3, 5, 4, 2, 1 ) ( 3, 5, 4, 2, 1 )
"# "
), ),
[3, 5, 4, 2, 1], [3, 5, 4, 2, 1],
[i64; 5] [i64; 5]
@ -414,9 +414,9 @@ fn return_tuple_5() {
fn return_tuple_6() { fn return_tuple_6() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
( 3, 5, 4, 2, 1, 7 ) ( 3, 5, 4, 2, 1, 7 )
"# "
), ),
[3, 5, 4, 2, 1, 7], [3, 5, 4, 2, 1, 7],
[i64; 6] [i64; 6]
@ -430,9 +430,9 @@ fn return_tuple_6() {
fn return_tuple_7() { fn return_tuple_7() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
( 3, 5, 4, 2, 1, 7, 8 ) ( 3, 5, 4, 2, 1, 7, 8 )
"# "
), ),
[3, 5, 4, 2, 1, 7, 8], [3, 5, 4, 2, 1, 7, 8],
[i64; 7] [i64; 7]
@ -444,9 +444,9 @@ fn return_tuple_7() {
fn return_tuple_float_int() { fn return_tuple_float_int() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
(1.23f64, 0x1) (1.23f64, 0x1)
"# "
), ),
(1.23, 0x1), (1.23, 0x1),
(f64, i64) (f64, i64)
@ -458,9 +458,9 @@ fn return_tuple_float_int() {
fn return_tuple_int_float() { fn return_tuple_int_float() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
( 0x1, 1.23f64 ) ( 0x1, 1.23f64 )
"# "
), ),
(0x1, 1.23), (0x1, 1.23),
(i64, f64) (i64, f64)
@ -472,9 +472,9 @@ fn return_tuple_int_float() {
fn return_tuple_float_float() { fn return_tuple_float_float() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
( 2.46f64, 1.23f64 ) ( 2.46f64, 1.23f64 )
"# "
), ),
(2.46, 1.23), (2.46, 1.23),
(f64, f64) (f64, f64)
@ -486,9 +486,9 @@ fn return_tuple_float_float() {
fn return_tuple_float_float_float() { fn return_tuple_float_float_float() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
( 2.46f64, 1.23f64, 0.1f64 ) ( 2.46f64, 1.23f64, 0.1f64 )
"# "
), ),
(2.46, 1.23, 0.1), (2.46, 1.23, 0.1),
(f64, f64, f64) (f64, f64, f64)
@ -500,9 +500,9 @@ fn return_tuple_float_float_float() {
fn return_nested_tuple() { fn return_nested_tuple() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
(0x0, (2.46f64, 1.23f64, 0.1f64)) (0x0, (2.46f64, 1.23f64, 0.1f64))
"# "
), ),
(0x0, (2.46, 1.23, 0.1)), (0x0, (2.46, 1.23, 0.1)),
(i64, (f64, f64, f64)) (i64, (f64, f64, f64))
@ -514,13 +514,13 @@ fn return_nested_tuple() {
fn nested_tuple_load() { fn nested_tuple_load() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
x = (0, (0x2, 0x5, 0x6)) x = (0, (0x2, 0x5, 0x6))
y = x.1 y = x.1
y.2 y.2
"# "
), ),
6, 6,
i64 i64
@ -572,7 +572,7 @@ fn alignment_in_tuple() {
fn tuple_length_polymorphism() { fn tuple_length_polymorphism() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r"
a = (42, 43) a = (42, 43)
b = (1, 2, 44) b = (1, 2, 44)
@ -580,7 +580,7 @@ fn tuple_length_polymorphism() {
f = \(x1, x2), (x3, x4) -> x1 + x2 + x3 + x4 f = \(x1, x2), (x3, x4) -> x1 + x2 + x3 + x4
f a b f a b
"# "
), ),
88, 88,
i64 i64

File diff suppressed because it is too large Load diff

View file

@ -1,3 +0,0 @@
target
corpus
artifacts

File diff suppressed because it is too large Load diff

View file

@ -731,7 +731,7 @@ mod test_snapshots {
#[test] #[test]
fn string_with_interpolation_in_middle() { fn string_with_interpolation_in_middle() {
assert_segments(r#""Hi, \(name)!""#, |arena| { assert_segments(r#""Hi, $(name)!""#, |arena| {
let expr = arena.alloc(Var { let expr = arena.alloc(Var {
module_name: "", module_name: "",
ident: "name", ident: "name",
@ -747,7 +747,7 @@ mod test_snapshots {
#[test] #[test]
fn string_with_interpolation_in_front() { fn string_with_interpolation_in_front() {
assert_segments(r#""\(name), hi!""#, |arena| { assert_segments(r#""$(name), hi!""#, |arena| {
let expr = arena.alloc(Var { let expr = arena.alloc(Var {
module_name: "", module_name: "",
ident: "name", ident: "name",
@ -762,7 +762,7 @@ mod test_snapshots {
#[test] #[test]
fn string_with_interpolation_in_back() { fn string_with_interpolation_in_back() {
assert_segments(r#""Hello \(name)""#, |arena| { assert_segments(r#""Hello $(name)""#, |arena| {
let expr = arena.alloc(Var { let expr = arena.alloc(Var {
module_name: "", module_name: "",
ident: "name", ident: "name",
@ -777,7 +777,7 @@ mod test_snapshots {
#[test] #[test]
fn string_with_multiple_interpolations() { fn string_with_multiple_interpolations() {
assert_segments(r#""Hi, \(name)! How is \(project) going?""#, |arena| { assert_segments(r#""Hi, $(name)! How is $(project) going?""#, |arena| {
let expr1 = arena.alloc(Var { let expr1 = arena.alloc(Var {
module_name: "", module_name: "",
ident: "name", ident: "name",

View file

@ -566,10 +566,7 @@ impl<T> Copy for SubsIndex<T> {}
impl<T> Clone for SubsIndex<T> { impl<T> Clone for SubsIndex<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { *self
index: self.index,
_marker: self._marker,
}
} }
} }
@ -577,11 +574,7 @@ impl<T> Copy for SubsSlice<T> {}
impl<T> Clone for SubsSlice<T> { impl<T> Clone for SubsSlice<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { *self
start: self.start,
length: self.length,
_marker: self._marker,
}
} }
} }

View file

@ -1300,17 +1300,21 @@ mod debug_types {
Arg, Arg,
} }
fn always_true() -> bool {
true
}
macro_rules! maybe_paren { macro_rules! maybe_paren {
($paren_if_above:expr, $my_prec:expr, $doc:expr) => { ($paren_if_above:expr, $my_prec:expr, $doc:expr) => {
maybe_paren!($paren_if_above, $my_prec, || true, $doc) maybe_paren!($paren_if_above, $my_prec, always_true, $doc)
}; };
($paren_if_above:expr, $my_prec:expr, $extra_cond:expr, $doc:expr) => { ($paren_if_above:expr, $my_prec:expr, $extra_cond:expr, $doc:expr) => {{
if $my_prec > $paren_if_above && $extra_cond() { if $my_prec > $paren_if_above && $extra_cond() {
$doc.parens().group() $doc.parens().group()
} else { } else {
$doc $doc
} }
}; }};
} }
fn typ<'a>( fn typ<'a>(

View file

@ -1 +0,0 @@
/build

View file

@ -1,3 +0,0 @@
*.so
*.dylib
*.dll

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,12 +0,0 @@
Cargo.lock
Cargo.toml
build.rs
host.c
test_glue
roc_externs.rs
main.rs
app
dynhost
libapp.so
metadata
preprocessedhost

View file

@ -37,7 +37,7 @@ macro_rules! tokens {
} }
impl Token { impl Token {
pub const LEGEND: &[SemanticTokenType] = &[ pub const LEGEND: &'static [SemanticTokenType] = &[
$(SemanticTokenType::new($lsp_token)),* $(SemanticTokenType::new($lsp_token)),*
]; ];
} }

View file

@ -438,11 +438,19 @@ impl<R: Read> Read for ProgressReporter<R> {
self.read += size; self.read += size;
if let Some(total) = self.total { if let Some(total) = self.total {
let total = total as f32 / 1_000_000.0;
let read = self.read as f32 / 1_000_000.0;
if total < 1.0 {
eprint!( eprint!(
"\u{001b}[2K\u{001b}[G[{:.1} / {:.1} MB]", "\u{001b}[2K\u{001b}[G[{:.1} / {:.1} KB]",
self.read as f32 / 1_000_000.0, // Convert MB to KB
total as f32 / 1_000_000.0, read * 1000.0,
total * 1000.0,
); );
} else {
eprint!("\u{001b}[2K\u{001b}[G[{:.1} / {:.1} MB]", read, total,);
}
} else { } else {
eprint!( eprint!(
"\u{001b}[2K\u{001b}[G[{:.1} MB]", "\u{001b}[2K\u{001b}[G[{:.1} MB]",

View file

@ -18,7 +18,7 @@ macro_rules! deref_number {
impl ReplAppMemory for ExpectMemory { impl ReplAppMemory for ExpectMemory {
fn deref_bool(&self, addr: usize) -> bool { fn deref_bool(&self, addr: usize) -> bool {
let ptr = unsafe { self.start.add(addr) } as *const u8; let ptr = unsafe { self.start.add(addr) };
let value = unsafe { std::ptr::read_unaligned(ptr) }; let value = unsafe { std::ptr::read_unaligned(ptr) };
// bool values should only ever be 0 or 1 // bool values should only ever be 0 or 1

View file

@ -238,12 +238,12 @@ mod test {
"# "#
), ),
indoc!( indoc!(
r#" r"
This expectation failed: This expectation failed:
5 expect 1 == 2 5 expect 1 == 2
^^^^^^^^^^^^^ ^^^^^^^^^^^^^
"# "
), ),
); );
} }
@ -265,7 +265,7 @@ mod test {
"# "#
), ),
indoc!( indoc!(
r#" r"
This expectation failed: This expectation failed:
5> expect 5> expect
@ -281,7 +281,7 @@ mod test {
b : Num * b : Num *
b = 2 b = 2
"# "
), ),
); );
} }
@ -380,7 +380,7 @@ mod test {
"# "#
), ),
indoc!( indoc!(
r#" r"
This expectation failed: This expectation failed:
5> expect 5> expect
@ -397,7 +397,7 @@ mod test {
expected : Result I64 [OutOfBounds] expected : Result I64 [OutOfBounds]
expected = Ok 42 expected = Ok 42
"# "
), ),
); );
} }
@ -463,7 +463,7 @@ mod test {
"# "#
), ),
indoc!( indoc!(
r#" r"
This expectation failed: This expectation failed:
5> expect 5> expect
@ -485,7 +485,7 @@ mod test {
y : U8, y : U8,
} }
vec2 = { x: 4, y: 8 } vec2 = { x: 4, y: 8 }
"# "
), ),
); );
} }
@ -965,22 +965,22 @@ mod test {
fn issue_i4389() { fn issue_i4389() {
run_expect_test( run_expect_test(
indoc!( indoc!(
r#" r"
interface Test exposes [] imports [] interface Test exposes [] imports []
expect expect
totalCount = \{} -> 1u8 totalCount = \{} -> 1u8
totalCount {} == 96u8 totalCount {} == 96u8
"# "
), ),
indoc!( indoc!(
r#" r"
This expectation failed: This expectation failed:
3> expect 3> expect
4> totalCount = \{} -> 1u8 4> totalCount = \{} -> 1u8
5> totalCount {} == 96u8 5> totalCount {} == 96u8
"# "
), ),
); );
} }
@ -989,7 +989,7 @@ mod test {
fn adjacent_lists() { fn adjacent_lists() {
run_expect_test( run_expect_test(
indoc!( indoc!(
r#" r"
interface Test exposes [] imports [] interface Test exposes [] imports []
expect expect
@ -1007,10 +1007,10 @@ mod test {
x: [115, 116, 117], x: [115, 116, 117],
} }
actual == expected actual == expected
"# "
), ),
indoc!( indoc!(
r#" r"
This expectation failed: This expectation failed:
3> expect 3> expect
@ -1044,7 +1044,7 @@ mod test {
x : List (Int Unsigned8), x : List (Int Unsigned8),
} }
expected = { body: [42, 43, 44], headers: [15, 16, 17], x: [115, 116, 117] } expected = { body: [42, 43, 44], headers: [15, 16, 17], x: [115, 116, 117] }
"# "
), ),
); );
} }
@ -1113,7 +1113,7 @@ mod test {
fn tag_payloads_of_different_size() { fn tag_payloads_of_different_size() {
run_expect_test( run_expect_test(
indoc!( indoc!(
r#" r"
interface Test exposes [] imports [] interface Test exposes [] imports []
actual : [Leftover (List U8), TooShort] actual : [Leftover (List U8), TooShort]
@ -1124,10 +1124,10 @@ mod test {
expected = TooShort expected = TooShort
actual == expected actual == expected
"# "
), ),
indoc!( indoc!(
r#" r"
This expectation failed: This expectation failed:
6> expect 6> expect
@ -1143,7 +1143,7 @@ mod test {
TooShort, TooShort,
] ]
expected = TooShort expected = TooShort
"# "
), ),
); );
} }
@ -1220,7 +1220,7 @@ mod test {
fn match_on_opaque_number_type() { fn match_on_opaque_number_type() {
run_expect_test( run_expect_test(
indoc!( indoc!(
r#" r"
interface Test exposes [] imports [] interface Test exposes [] imports []
hexToByte : U8, U8 -> U8 hexToByte : U8, U8 -> U8
@ -1231,10 +1231,10 @@ mod test {
actual = hexToByte 7 4 actual = hexToByte 7 4
expected = 't' expected = 't'
actual == expected actual == expected
"# "
), ),
indoc!( indoc!(
r#" r"
This expectation failed: This expectation failed:
7> expect 7> expect
@ -1249,7 +1249,7 @@ mod test {
expected : Int Unsigned8 expected : Int Unsigned8
expected = 116 expected = 116
"# "
), ),
); );
} }

View file

@ -124,11 +124,11 @@ fn bool_basic_equality() {
fn bool_true() { fn bool_true() {
expect_success( expect_success(
indoc!( indoc!(
r#" r"
Bool.true Bool.true
"# "
), ),
r#"Bool.true : Bool"#, r"Bool.true : Bool",
); );
} }
@ -136,11 +136,11 @@ fn bool_true() {
fn bool_false() { fn bool_false() {
expect_success( expect_success(
indoc!( indoc!(
r#" r"
Bool.false Bool.false
"# "
), ),
r#"Bool.false : Bool"#, r"Bool.false : Bool",
); );
} }
@ -315,24 +315,24 @@ fn nested_string_list() {
#[test] #[test]
fn nested_num_list() { fn nested_num_list() {
expect_success( expect_success(
r#"[[[4, 3, 2], [1, 0]], [[]], []]"#, r"[[[4, 3, 2], [1, 0]], [[]], []]",
r#"[[[4, 3, 2], [1, 0]], [[]], []] : List (List (List (Num *)))"#, r"[[[4, 3, 2], [1, 0]], [[]], []] : List (List (List (Num *)))",
); );
} }
#[test] #[test]
fn nested_int_list() { fn nested_int_list() {
expect_success( expect_success(
r#"[[[4, 3, 2], [1, 0x0]], [[]], []]"#, r"[[[4, 3, 2], [1, 0x0]], [[]], []]",
r#"[[[4, 3, 2], [1, 0]], [[]], []] : List (List (List (Int *)))"#, r"[[[4, 3, 2], [1, 0]], [[]], []] : List (List (List (Int *)))",
); );
} }
#[test] #[test]
fn nested_float_list() { fn nested_float_list() {
expect_success( expect_success(
r#"[[[4, 3, 2], [1, 0.0]], [[]], []]"#, r"[[[4, 3, 2], [1, 0.0]], [[]], []]",
r#"[[[4, 3, 2], [1, 0]], [[]], []] : List (List (List (Frac *)))"#, r"[[[4, 3, 2], [1, 0]], [[]], []] : List (List (List (Frac *)))",
); );
} }
@ -641,7 +641,7 @@ fn too_few_args() {
expect_failure( expect_failure(
"Num.add 2", "Num.add 2",
indoc!( indoc!(
r#" r"
TOO FEW ARGS TOO FEW ARGS
The add function expects 2 arguments, but it got only 1: The add function expects 2 arguments, but it got only 1:
@ -651,7 +651,7 @@ fn too_few_args() {
Roc does not allow functions to be partially applied. Use a closure to Roc does not allow functions to be partially applied. Use a closure to
make partial application explicit. make partial application explicit.
"# "
), ),
); );
} }
@ -970,7 +970,7 @@ fn large_nullable_wrapped_tag_union() {
fn issue_2300() { fn issue_2300() {
expect_success( expect_success(
r#"\Email str -> str == """#, r#"\Email str -> str == """#,
r#"<function> : [Email Str] -> Bool"#, r"<function> : [Email Str] -> Bool",
) )
} }
@ -978,8 +978,8 @@ fn issue_2300() {
#[test] #[test]
fn function_in_list() { fn function_in_list() {
expect_success( expect_success(
r#"[\x -> x + 1, \s -> s * 2]"#, r"[\x -> x + 1, \s -> s * 2]",
r#"[<function>, <function>] : List (Num a -> Num a)"#, r"[<function>, <function>] : List (Num a -> Num a)",
) )
} }
@ -987,8 +987,8 @@ fn function_in_list() {
#[test] #[test]
fn function_in_record() { fn function_in_record() {
expect_success( expect_success(
r#"{ n: 1, adder: \x -> x + 1 }"#, r"{ n: 1, adder: \x -> x + 1 }",
r#"{ adder: <function>, n: 1 } : { adder : Num a -> Num a, n : Num * }"#, r"{ adder: <function>, n: 1 } : { adder : Num a -> Num a, n : Num * }",
) )
} }
@ -996,8 +996,8 @@ fn function_in_record() {
#[test] #[test]
fn function_in_unwrapped_record() { fn function_in_unwrapped_record() {
expect_success( expect_success(
r#"{ adder: \x -> x + 1 }"#, r"{ adder: \x -> x + 1 }",
r#"{ adder: <function> } : { adder : Num a -> Num a }"#, r"{ adder: <function> } : { adder : Num a -> Num a }",
) )
} }
@ -1005,16 +1005,16 @@ fn function_in_unwrapped_record() {
#[test] #[test]
fn function_in_tag() { fn function_in_tag() {
expect_success( expect_success(
r#"Adder (\x -> x + 1)"#, r"Adder (\x -> x + 1)",
r#"Adder <function> : [Adder (Num a -> Num a)]"#, r"Adder <function> : [Adder (Num a -> Num a)]",
) )
} }
#[test] #[test]
fn newtype_of_record_of_tag_of_record_of_tag() { fn newtype_of_record_of_tag_of_record_of_tag() {
expect_success( expect_success(
r#"A {b: C {d: 1}}"#, r"A {b: C {d: 1}}",
r#"A { b: C { d: 1 } } : [A { b : [C { d : Num * }] }]"#, r"A { b: C { d: 1 } } : [A { b : [C { d : Num * }] }]",
) )
} }
@ -1022,11 +1022,11 @@ fn newtype_of_record_of_tag_of_record_of_tag() {
fn print_u8s() { fn print_u8s() {
expect_success( expect_success(
indoc!( indoc!(
r#" r"
x : U8 x : U8
x = 129 x = 129
x x
"# "
), ),
"129 : U8", "129 : U8",
) )
@ -1062,17 +1062,17 @@ fn parse_problem() {
fn issue_2343_complete_mono_with_shadowed_vars() { fn issue_2343_complete_mono_with_shadowed_vars() {
expect_failure( expect_failure(
indoc!( indoc!(
r#" r"
b = False b = False
f = \b -> f = \b ->
when b is when b is
True -> 5 True -> 5
False -> 15 False -> 15
f b f b
"# "
), ),
indoc!( indoc!(
r#" r"
DUPLICATE NAME DUPLICATE NAME
The b name is first defined here: The b name is first defined here:
@ -1087,7 +1087,7 @@ fn issue_2343_complete_mono_with_shadowed_vars() {
Since these variables have the same name, it's easy to use the wrong Since these variables have the same name, it's easy to use the wrong
one by accident. Give one of them a new name. one by accident. Give one of them a new name.
"# "
), ),
); );
} }
@ -1126,12 +1126,12 @@ fn tag_with_type_behind_alias() {
fn issue_2588_record_with_function_and_nonfunction() { fn issue_2588_record_with_function_and_nonfunction() {
expect_success( expect_success(
indoc!( indoc!(
r#" r"
x = 1 x = 1
f = \n -> n * 2 f = \n -> n * 2
{ y: f x, f }"# { y: f x, f }"
), ),
r#"{ f: <function>, y: 2 } : { f : Num a -> Num a, y : Num * }"#, r"{ f: <function>, y: 2 } : { f : Num a -> Num a, y : Num * }",
) )
} }
@ -1139,10 +1139,10 @@ fn issue_2588_record_with_function_and_nonfunction() {
fn opaque_apply() { fn opaque_apply() {
expect_success( expect_success(
indoc!( indoc!(
r#" r"
Age := U32 Age := U32
@Age 23"# @Age 23"
), ),
"@Age 23 : Age", "@Age 23 : Age",
) )
@ -1165,14 +1165,14 @@ fn opaque_apply_polymorphic() {
fn opaque_pattern_and_call() { fn opaque_pattern_and_call() {
expect_success( expect_success(
indoc!( indoc!(
r#" r"
F t u := [Package t u] F t u := [Package t u]
f = \@F (Package A {}) -> @F (Package {} A) f = \@F (Package A {}) -> @F (Package {} A)
f (@F (Package A {}))"# f (@F (Package A {}))"
), ),
r#"@F (Package {} A) : F {} [A]"#, r"@F (Package {} A) : F {} [A]",
) )
} }
@ -1180,10 +1180,10 @@ fn opaque_pattern_and_call() {
fn dec_in_repl() { fn dec_in_repl() {
expect_success( expect_success(
indoc!( indoc!(
r#" r"
x: Dec x: Dec
x=1.23 x=1.23
x"# x"
), ),
"1.23 : Dec", "1.23 : Dec",
) )
@ -1193,12 +1193,12 @@ fn dec_in_repl() {
fn print_i8_issue_2710() { fn print_i8_issue_2710() {
expect_success( expect_success(
indoc!( indoc!(
r#" r"
a : I8 a : I8
a = -1 a = -1
a"# a"
), ),
r#"-1 : I8"#, r"-1 : I8",
) )
} }
@ -1243,11 +1243,11 @@ fn issue_2582_specialize_result_value() {
fn issue_2818() { fn issue_2818() {
expect_success( expect_success(
indoc!( indoc!(
r#" r"
f : {} -> List Str f : {} -> List Str
f = \_ -> f = \_ ->
x = [] x = []
x"# x"
), ),
r"<function> : {} -> List Str", r"<function> : {} -> List Str",
) )
@ -1257,7 +1257,7 @@ fn issue_2818() {
fn issue_2810_recursive_layout_inside_nonrecursive() { fn issue_2810_recursive_layout_inside_nonrecursive() {
expect_success( expect_success(
indoc!( indoc!(
r#" r"
Command : [Command Tool] Command : [Command Tool]
Job : [Job Command] Job : [Job Command]
@ -1266,7 +1266,7 @@ fn issue_2810_recursive_layout_inside_nonrecursive() {
a : Job a : Job
a = Job (Command (FromJob (Job (Command SystemTool)))) a = Job (Command (FromJob (Job (Command SystemTool))))
a"# a"
), ),
"Job (Command (FromJob (Job (Command SystemTool)))) : Job", "Job (Command (FromJob (Job (Command SystemTool)))) : Job",
) )
@ -1276,12 +1276,12 @@ fn issue_2810_recursive_layout_inside_nonrecursive() {
fn render_nullable_unwrapped_passing_through_alias() { fn render_nullable_unwrapped_passing_through_alias() {
expect_success( expect_success(
indoc!( indoc!(
r#" r"
Deep : [L DeepList] Deep : [L DeepList]
DeepList : [Nil, Cons Deep] DeepList : [Nil, Cons Deep]
v : DeepList v : DeepList
v = (Cons (L (Cons (L (Cons (L Nil)))))) v = (Cons (L (Cons (L (Cons (L Nil))))))
v"# v"
), ),
"Cons (L (Cons (L (Cons (L Nil))))) : DeepList", "Cons (L (Cons (L (Cons (L Nil))))) : DeepList",
) )
@ -1291,9 +1291,9 @@ fn render_nullable_unwrapped_passing_through_alias() {
fn opaque_wrap_function() { fn opaque_wrap_function() {
expect_success( expect_success(
indoc!( indoc!(
r#" r"
A a := a A a := a
List.map [1u8, 2u8, 3u8] @A"# List.map [1u8, 2u8, 3u8] @A"
), ),
"[@A 1, @A 2, @A 3] : List (A U8)", "[@A 1, @A 2, @A 3] : List (A U8)",
); );
@ -1305,10 +1305,10 @@ fn opaque_wrap_function() {
fn dict_get_single() { fn dict_get_single() {
expect_success( expect_success(
indoc!( indoc!(
r#" r"
Dict.single 0 {a: 1, c: 2} |> Dict.get 0"# Dict.single 0 {a: 1, c: 2} |> Dict.get 0"
), ),
r#"Ok { a: 1, c: 2 } : Result { a : Num *, c : Num * } [KeyNotFound]"#, r"Ok { a: 1, c: 2 } : Result { a : Num *, c : Num * } [KeyNotFound]",
) )
} }
@ -1319,7 +1319,7 @@ fn record_of_poly_function() {
r#" r#"
{ a: \_ -> "a" }"# { a: \_ -> "a" }"#
), ),
r#"{ a: <function> } : { a : * -> Str }"#, r"{ a: <function> } : { a : * -> Str }",
); );
} }
@ -1338,18 +1338,18 @@ fn record_of_poly_function_and_string() {
fn newtype_by_void_is_wrapped() { fn newtype_by_void_is_wrapped() {
expect_success( expect_success(
indoc!( indoc!(
r#" r"
Result.try (Err 42) (\x -> Err (x+1))"# Result.try (Err 42) (\x -> Err (x+1))"
), ),
r#"Err 42 : Result b (Num *)"#, r"Err 42 : Result b (Num *)",
); );
expect_success( expect_success(
indoc!( indoc!(
r#" r"
Result.try (Ok 42) (\x -> Ok (x+1))"# Result.try (Ok 42) (\x -> Ok (x+1))"
), ),
r#"Ok 43 : Result (Num *) err"#, r"Ok 43 : Result (Num *) err",
); );
} }
@ -1357,11 +1357,11 @@ fn newtype_by_void_is_wrapped() {
fn enum_tag_union_in_list() { fn enum_tag_union_in_list() {
expect_success( expect_success(
indoc!( indoc!(
r#" r"
[E, F, G, H] [E, F, G, H]
"# "
), ),
r#"[E, F, G, H] : List [E, F, G, H]"#, r"[E, F, G, H] : List [E, F, G, H]",
); );
} }
@ -1373,7 +1373,7 @@ fn str_to_dec() {
Str.toDec "1234.1234" Str.toDec "1234.1234"
"# "#
), ),
r#"Ok 1234.1234 : Result Dec [InvalidNumStr]"#, r"Ok 1234.1234 : Result Dec [InvalidNumStr]",
); );
} }
@ -1405,7 +1405,7 @@ fn nested_tuple() {
fn ordered_tag_union_memory_layout() { fn ordered_tag_union_memory_layout() {
expect_success( expect_success(
indoc!( indoc!(
r#" r"
Loc : { line: U32, column: U32 } Loc : { line: U32, column: U32 }
Node : [ A Loc, Height U8 Loc ] Node : [ A Loc, Height U8 Loc ]
@ -1413,9 +1413,9 @@ fn ordered_tag_union_memory_layout() {
x : Node x : Node
x = Height 1 { line: 2, column: 3 } x = Height 1 { line: 2, column: 3 }
x x
"# "
), ),
r#"Height 1 { column: 3, line: 2 } : Node"#, r"Height 1 { column: 3, line: 2 } : Node",
); );
} }

View file

@ -1,5 +0,0 @@
# wasm-pack
/pkg
# shell script output
/build

View file

@ -9,7 +9,7 @@
# We use this two-step process because Netlify times out if we try to build the Web REPL there. # We use this two-step process because Netlify times out if we try to build the Web REPL there.
# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
set -euxo pipefail set -exo pipefail
if ! which wasm-pack if ! which wasm-pack
then then
@ -23,9 +23,22 @@ cd $SCRIPT_RELATIVE_DIR
mkdir -p build mkdir -p build
rm -rf build/* rm -rf build/*
# c++abi is not needed for wasm-pack and causes an error, see #6303 for more info
REMOVE_STR="-C link-arg=-lc++abi"
( # start subshell to limit scope of export RUSTFLAGS
# Check if RUSTFLAGS contains the string to be removed
if [[ $RUSTFLAGS == *"$REMOVE_STR"* ]]; then
# Remove the string
RUSTFLAGS=$(echo "$RUSTFLAGS" | sed "s/$REMOVE_STR//g")
export RUSTFLAGS
fi
# We want a release build, but with debug info (to get stack traces for Wasm backend panics) # We want a release build, but with debug info (to get stack traces for Wasm backend panics)
# This configuration is called `--profiling` # This configuration is called `--profiling`
wasm-pack build --profiling --target web -- --features console_error_panic_hook wasm-pack build --profiling --target web -- --features console_error_panic_hook
)
cp -v pkg/roc_repl_wasm.js build cp -v pkg/roc_repl_wasm.js build
# To disable optimizations while debugging, do `export REPL_DEBUG=1` before running the script # To disable optimizations while debugging, do `export REPL_DEBUG=1` before running the script

View file

@ -1 +0,0 @@
/tmp

View file

@ -2,6 +2,7 @@ use std::path::PathBuf;
use roc_collections::MutMap; use roc_collections::MutMap;
use roc_module::symbol::{Interns, ModuleId}; use roc_module::symbol::{Interns, ModuleId};
use roc_problem::can::Problem;
use roc_region::all::LineInfo; use roc_region::all::LineInfo;
use roc_solve_problem::TypeError; use roc_solve_problem::TypeError;
@ -87,29 +88,6 @@ pub fn report_problems(
// Report parsing and canonicalization problems // Report parsing and canonicalization problems
let alloc = RocDocAllocator::new(&src_lines, *home, interns); let alloc = RocDocAllocator::new(&src_lines, *home, interns);
let problems = can_problems.remove(home).unwrap_or_default();
for problem in problems.into_iter() {
let report = can_problem(&alloc, &lines, module_path.clone(), problem);
let severity = report.severity;
let mut buf = String::new();
report.render_color_terminal(&mut buf, &alloc, &palette);
match severity {
Warning => {
warnings.push(buf);
}
RuntimeError => {
errors.push(buf);
}
Fatal => {
fatally_errored = true;
errors.push(buf);
}
}
}
let problems = type_problems.remove(home).unwrap_or_default(); let problems = type_problems.remove(home).unwrap_or_default();
for problem in problems { for problem in problems {
@ -133,6 +111,43 @@ pub fn report_problems(
} }
} }
} }
// Shadowing errors often cause cryptic type errors. To make it easy to spot the root cause,
// we print the shadowing errors last.
let problems = can_problems.remove(home).unwrap_or_default();
let (shadowing_errs, mut ordered): (Vec<Problem>, Vec<Problem>) =
problems.into_iter().partition(|p| {
matches!(
p,
Problem::Shadowing {
original_region: _,
shadow: _,
kind: _,
}
)
});
ordered.extend(shadowing_errs);
for problem in ordered.into_iter() {
let report = can_problem(&alloc, &lines, module_path.clone(), problem);
let severity = report.severity;
let mut buf = String::new();
report.render_color_terminal(&mut buf, &alloc, &palette);
match severity {
Warning => {
warnings.push(buf);
}
RuntimeError => {
errors.push(buf);
}
Fatal => {
fatally_errored = true;
errors.push(buf);
}
}
}
} }
debug_assert!(can_problems.is_empty() && type_problems.is_empty(), "After reporting problems, there were {:?} can_problems and {:?} type_problems that could not be reported because they did not have corresponding entries in `sources`.", can_problems.len(), type_problems.len()); debug_assert!(can_problems.is_empty() && type_problems.is_empty(), "After reporting problems, there were {:?} can_problems and {:?} type_problems that could not be reported because they did not have corresponding entries in `sources`.", can_problems.len(), type_problems.len());

View file

@ -711,9 +711,9 @@ fn to_expr_report<'b>(
let thing = match annotation_source { let thing = match annotation_source {
TypedIfBranch { TypedIfBranch {
index, index,
num_branches, num_branches: 2,
.. ..
} if num_branches == 2 => alloc.concat([ } => alloc.concat([
alloc.keyword(if index == HumanIndex::FIRST { alloc.keyword(if index == HumanIndex::FIRST {
"then" "then"
} else { } else {

View file

@ -1,2 +0,0 @@
*.o
*.a

View file

@ -495,7 +495,7 @@ impl PartialEq for I128 {
impl PartialOrd for I128 { impl PartialOrd for I128 {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
i128::from(*self).partial_cmp(&i128::from(*other)) Some(self.cmp(other))
} }
} }
@ -547,7 +547,7 @@ impl PartialEq for U128 {
impl PartialOrd for U128 { impl PartialOrd for U128 {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
u128::from(*self).partial_cmp(&u128::from(*other)) Some(self.cmp(other))
} }
} }

View file

@ -48,7 +48,7 @@ impl<T> RocBox<T> {
/// ///
/// The box must be unique in order to leak it safely /// The box must be unique in order to leak it safely
pub unsafe fn leak(self) -> *mut T { pub unsafe fn leak(self) -> *mut T {
let ptr = self.contents.as_ptr() as *mut T; let ptr = self.contents.as_ptr();
core::mem::forget(self); core::mem::forget(self);
ptr ptr
} }
@ -59,7 +59,7 @@ impl<T> RocBox<T> {
} }
pub fn into_inner(self) -> T { pub fn into_inner(self) -> T {
unsafe { ptr::read(self.contents.as_ptr() as *mut T) } unsafe { ptr::read(self.contents.as_ptr()) }
} }
fn storage(&self) -> &Cell<Storage> { fn storage(&self) -> &Cell<Storage> {

View file

@ -388,7 +388,6 @@ impl RocStr {
// The backing list was not unique, so we can't mutate it in-place. // The backing list was not unique, so we can't mutate it in-place.
// ask for `len + 1` to store the original string and the terminator // ask for `len + 1` to store the original string and the terminator
with_stack_bytes(len + 1, |alloc_ptr: *mut u8| { with_stack_bytes(len + 1, |alloc_ptr: *mut u8| {
let alloc_ptr = alloc_ptr as *mut u8;
let elem_ptr = big_string.ptr_to_first_elem() as *mut u8; let elem_ptr = big_string.ptr_to_first_elem() as *mut u8;
// memcpy the bytes into the stack allocation // memcpy the bytes into the stack allocation
@ -406,7 +405,7 @@ impl RocStr {
// Even if the small string is at capacity, there will be room to write // Even if the small string is at capacity, there will be room to write
// a terminator in the byte that's used to store the length. // a terminator in the byte that's used to store the length.
terminate(bytes.as_mut_ptr() as *mut u8, small_str.len()) terminate(bytes.as_mut_ptr(), small_str.len())
} }
} }
} }
@ -716,7 +715,7 @@ impl Eq for RocStr {}
impl PartialOrd for RocStr { impl PartialOrd for RocStr {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
self.as_str().partial_cmp(other.as_str()) Some(self.cmp(other))
} }
} }

View file

@ -149,7 +149,7 @@ fn run_with_valgrind(binary_path: &std::path::Path) {
let memory_errors = extract_valgrind_errors(&raw_xml).unwrap_or_else(|err| { let memory_errors = extract_valgrind_errors(&raw_xml).unwrap_or_else(|err| {
panic!( panic!(
indoc!( indoc!(
r#" r"
failed to parse the `valgrind` xml output: failed to parse the `valgrind` xml output:
Error was: Error was:
@ -167,7 +167,7 @@ fn run_with_valgrind(binary_path: &std::path::Path) {
valgrind stderr was: valgrind stderr was:
{} {}
"# "
), ),
err, raw_xml, valgrind_out.stdout, valgrind_out.stderr err, raw_xml, valgrind_out.stdout, valgrind_out.stderr
); );
@ -214,7 +214,7 @@ fn list_concat_consumes_first_argument() {
#[test] #[test]
fn list_concat_consumes_second_argument() { fn list_concat_consumes_second_argument() {
valgrind_test(indoc!( valgrind_test(indoc!(
r#" r"
( (
a : List U8 a : List U8
a = [] a = []
@ -223,7 +223,7 @@ fn list_concat_consumes_second_argument() {
|> List.len |> List.len
|> Num.toStr |> Num.toStr
) )
"# "
)); ));
} }
@ -273,7 +273,7 @@ fn str_concat_first_argument_not_unique() {
#[test] #[test]
fn list_concat_empty_list_zero_sized_type() { fn list_concat_empty_list_zero_sized_type() {
valgrind_test(indoc!( valgrind_test(indoc!(
r#" r"
( (
a = List.reserve [] 11 a = List.reserve [] 11
b = [] b = []
@ -281,7 +281,7 @@ fn list_concat_empty_list_zero_sized_type() {
|> List.len |> List.len
|> Num.toStr |> Num.toStr
) )
"# "
)); ));
} }
@ -316,7 +316,7 @@ fn str_trim_start_capacity() {
#[test] #[test]
fn str_concat_later_referencing_empty_list_with_capacity() { fn str_concat_later_referencing_empty_list_with_capacity() {
valgrind_test(indoc!( valgrind_test(indoc!(
r#" r"
( (
a : List U8 a : List U8
a = List.withCapacity 1 a = List.withCapacity 1
@ -326,7 +326,7 @@ fn str_concat_later_referencing_empty_list_with_capacity() {
|> Num.addWrap (List.len a) |> Num.addWrap (List.len a)
|> Num.toStr |> Num.toStr
) )
"# "
)); ));
} }
@ -504,7 +504,7 @@ fn tree_rebalance() {
#[test] #[test]
fn lowlevel_list_calls() { fn lowlevel_list_calls() {
valgrind_test(indoc!( valgrind_test(indoc!(
r#" r"
( (
a = List.map [1,1,1,1,1] (\x -> x + 0) a = List.map [1,1,1,1,1] (\x -> x + 0)
b = List.map2 a [1,1,1,1,1] (\x, y -> x + y) b = List.map2 a [1,1,1,1,1] (\x, y -> x + y)
@ -514,7 +514,7 @@ fn lowlevel_list_calls() {
Num.toStr (List.len e) Num.toStr (List.len e)
) )
"# "
)); ));
} }
@ -550,3 +550,29 @@ fn joinpoint_nullpointer() {
"# "#
)); ));
} }
#[test]
fn freeing_boxes() {
valgrind_test(indoc!(
r#"
(
# Without refcounted field
a : I32
a = 7
|> Box.box
|> Box.unbox
# With refcounted field
b : Str
b =
"Testing123. This will definitely be a large string that is on the heap."
|> Box.box
|> Box.unbox
a
|> Num.toStr
|> Str.concat b
)
"#
));
}

View file

@ -1,2 +0,0 @@
dynhost
libapp.so

View file

@ -1,2 +0,0 @@
/target
Cargo.lock

View file

@ -1,6 +1,8 @@
mod frame; mod frame;
mod instance; mod instance;
#[cfg(test)]
mod tests; mod tests;
mod value_store; mod value_store;
pub mod wasi; pub mod wasi;

View file

@ -90,6 +90,7 @@ macro_rules! section_impl {
let mut bytes = Vec::<u8>::with_capacity_in(range.len() * 2, arena); let mut bytes = Vec::<u8>::with_capacity_in(range.len() * 2, arena);
*cursor = range.end; *cursor = range.end;
bytes.extend_from_slice(&module_bytes[range]); bytes.extend_from_slice(&module_bytes[range]);
#[allow(clippy::redundant_closure_call)]
Ok($from_count_and_bytes(count, bytes)) Ok($from_count_and_bytes(count, bytes))
} }
} }

18
examples/.gitignore vendored
View file

@ -1,18 +0,0 @@
*.dSYM
libhost.a
libapp.so
dynhost
*.rm
*.rh
helloWorld
helloWorldNoURL
inspect-gui
inspect-logging
swiftui
parser/examples/example
gui/hello-gui
gui/breakout/breakout
gui/breakout/hello-gui
webserver/echo
webserver/http

View file

@ -1,13 +0,0 @@
args
countdown
echo
effects
file
form
tui
http-get
file-io
env
ingested-file
ingested-file-bytes
out.txt

View file

@ -1 +0,0 @@
false

Some files were not shown because too many files have changed in this diff Show more