From 1d1b09520ca0a288f417c24a8d328d6682faaafc Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Fri, 6 Sep 2024 08:53:10 +1000 Subject: [PATCH 01/17] add heap as a new crate --- Cargo.lock | 23 +++- Cargo.toml | 1 + crates/roc_std_heap/Cargo.toml | 13 ++ crates/roc_std_heap/src/lib.rs | 239 +++++++++++++++++++++++++++++++++ 4 files changed, 273 insertions(+), 3 deletions(-) create mode 100644 crates/roc_std_heap/Cargo.toml create mode 100644 crates/roc_std_heap/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index f4299c78b84..1925825b62f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1399,9 +1399,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libloading" @@ -1540,6 +1540,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memmap2" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.6.5" @@ -2705,7 +2714,7 @@ dependencies = [ "indoc", "libc", "mach_object", - "memmap2", + "memmap2 0.5.10", "object", "roc_collections", "roc_error_macros", @@ -3133,6 +3142,14 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "roc_std_heap" +version = "0.0.1" +dependencies = [ + "memmap2 0.9.4", + "roc_std", +] + [[package]] name = "roc_target" version = "0.0.1" diff --git a/Cargo.toml b/Cargo.toml index a02dc7b7de2..6dafb57e8e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ members = [ "crates/wasm_module", "crates/wasm_interp", "crates/language_server", + "crates/roc_std_heap", ] exclude = [ diff --git a/crates/roc_std_heap/Cargo.toml b/crates/roc_std_heap/Cargo.toml new file mode 100644 index 00000000000..885643722c4 --- /dev/null +++ b/crates/roc_std_heap/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "roc_std_heap" +description = "Rust representations of a Roc threadsafe version of the refcounted heap that can avoid a wrapping Mutex and RefCell" + +authors = ["The Roc Contributors"] +edition = "2021" +license = "UPL-1.0" +repository = "https://github.com/roc-lang/roc" +version = "0.0.1" + +[dependencies] +roc_std = { path = "../roc_std" } +memmap2 = "=0.9.4" diff --git a/crates/roc_std_heap/src/lib.rs b/crates/roc_std_heap/src/lib.rs new file mode 100644 index 00000000000..eaab3065b8f --- /dev/null +++ b/crates/roc_std_heap/src/lib.rs @@ -0,0 +1,239 @@ +//! This heap module attempts to make simple single type heaps. +//! These are used for allocating and deallocating resources beyond the scope of roc. +//! +//! For example, roc can not free file resources. +//! Instead, they will be tracked and reference counted in a side heap. +//! When freed, the underlying resource can be released. +//! +//! To make checking resource types quick, all heaps allocate to a single mmap. +//! Then a simple range check on a pointer can confirm is a pointer is into a specific heap. + +use memmap2::MmapMut; +use roc_std::RocBox; +use std::{ + cell::UnsafeCell, + ffi::c_void, + io::{Error, ErrorKind, Result}, + marker::PhantomData, + mem, ptr, + sync::Mutex, +}; + +const REFCOUNT_ONE: usize = isize::MIN as usize; + +/// ThreadSafeRefcountedResourceHeap is a threadsafe version of the refcounted heap that can avoid a wrapping Mutex and RefCell. +/// This is very important for dealloc performance. +/// No lock is needed to check if a pointer is in range of the underlying mmap. +/// This leads to a solid perf bump over the naive lock everywhere solution. +/// Otherwise, alloc and dealloc, always use a mutex, but are much rarer to be called. +/// If perf becomes a problem once basic-cli has threading, we should consider sharding the heap by thread. +pub struct ThreadSafeRefcountedResourceHeap { + heap: UnsafeCell>, + guard: Mutex<()>, +} + +impl ThreadSafeRefcountedResourceHeap { + pub fn new(max_elements: usize) -> Result> { + RefcountedResourceHeap::new(max_elements).map(|heap| ThreadSafeRefcountedResourceHeap { + heap: UnsafeCell::new(heap), + guard: Mutex::new(()), + }) + } + + pub fn alloc_for(self: &Self, data: T) -> Result> { + let _g = self.guard.lock().unwrap(); + unsafe { &mut *self.heap.get() }.alloc_for(data) + } + + pub fn dealloc(self: &Self, ptr: *const U) { + let _g = self.guard.lock().unwrap(); + unsafe { &mut *self.heap.get() }.dealloc(ptr) + } + + // This is safe to call at any time with no lock! + pub fn in_range(self: &Self, ptr: *const U) -> bool { + unsafe { &*self.heap.get() }.in_range(ptr) + } + + pub fn box_to_resource<'a>(data: RocBox<()>) -> &'a mut T { + RefcountedResourceHeap::box_to_resource(data) + } +} + +unsafe impl Sync for ThreadSafeRefcountedResourceHeap {} +unsafe impl Send for ThreadSafeRefcountedResourceHeap {} + +#[repr(C)] +struct Refcounted(usize, T); + +/// HeapOfRefcounted is a wrapper around Heap for data that roc stores with a refcount. +/// It will return a pointer to right after the refcount (what a `Box {}` would expect in Roc). +pub struct RefcountedResourceHeap(Heap>); + +impl RefcountedResourceHeap { + pub fn new(max_elements: usize) -> Result> { + Heap::new(max_elements).map(|heap| RefcountedResourceHeap(heap)) + } + + pub fn alloc_for(self: &mut Self, data: T) -> Result> { + self.0.alloc().map(|alloc_ptr| { + unsafe { std::ptr::write(alloc_ptr, Refcounted(REFCOUNT_ONE, data)) }; + let box_ptr = alloc_ptr as usize + mem::size_of::(); + unsafe { std::mem::transmute(box_ptr) } + }) + } + + pub fn dealloc(self: &mut Self, ptr: *const U) { + self.0.dealloc(ptr as _); + } + + pub fn in_range(self: &Self, ptr: *const U) -> bool { + self.0.in_range(ptr as _) + } + + pub fn box_to_resource<'a>(data: RocBox<()>) -> &'a mut T { + let box_ptr: usize = unsafe { std::mem::transmute(data) }; + + let alloc_ptr = (box_ptr - mem::size_of::()) as *mut Refcounted; + let alloc: &mut Refcounted = unsafe { &mut *alloc_ptr }; + &mut alloc.1 + } +} + +/// The Heap is one mmap of data that can be interpreted multiple ways. +/// +/// It can be view as list of unions between `T` and `usize`. +/// In the case of a `T`, it is an allocated element. +/// In the case of a `usize`, it is part of the freed list. +/// The value of the `usize` is the next free node. +/// +/// Note: If we ever need better multithreaded performance, +/// we could shard the heap and lock individual shards. +pub struct Heap { + data: MmapMut, + elements: usize, + max_elements: usize, + free_list: *const c_void, + phantom: PhantomData, +} + +unsafe impl Send for Heap {} + +impl Heap { + pub fn new(max_elements: usize) -> Result> { + debug_assert!(max_elements > 0); + + let max_bytes = max_elements * Self::node_size(); + Ok(Self { + data: MmapMut::map_anon(max_bytes)?, + elements: 0, + max_elements, + free_list: ptr::null(), + phantom: PhantomData::default(), + }) + } + + pub fn alloc(self: &mut Self) -> Result<*mut T> { + if self.free_list != ptr::null() { + // Open slot on the free list. + let root = self.free_list as *const *const c_void; + let next = unsafe { *root }; + self.free_list = next; + + // Convert root into a `*mut T` for use. + return Ok(root as *mut T); + } + + // If has available memory allocate at end. + if self.elements < self.max_elements { + let offset = self.elements * Self::node_size(); + let elem_ptr = unsafe { self.data.as_mut_ptr().offset(offset as isize) }; + self.elements += 1; + return Ok(elem_ptr as *mut T); + } + + return Err(Error::from(ErrorKind::OutOfMemory)); + } + + pub fn dealloc(self: &mut Self, elem_ptr: *mut T) { + debug_assert!(self.in_range(elem_ptr)); + + // Just push the freed value to the start of the free list. + let old_root = self.free_list; + self.free_list = elem_ptr as *const c_void; + unsafe { *(self.free_list as *mut *const c_void) = old_root }; + + unsafe { + // Free the underlying resource. + std::ptr::drop_in_place(elem_ptr); + } + } + + pub fn in_range(self: &Self, elem_ptr: *mut T) -> bool { + let start = self.data.as_ptr(); + let offset = self.elements * Self::node_size(); + let end = unsafe { start.offset(offset as isize) }; + (start as usize) <= (elem_ptr as usize) && (elem_ptr as usize) < (end as usize) + } + + const fn node_size() -> usize { + let a = mem::size_of::(); + let b = mem::size_of::(); + if a > b { + a + } else { + b + } + } +} + +#[cfg(test)] +mod test { + use std::u128; + + use super::*; + + #[test] + fn alloc_to_limit() { + let limit = 4; + let mut heap = Heap::::new(limit).unwrap(); + let mut ptrs = vec![]; + loop { + match heap.alloc() { + Ok(ptr) => ptrs.push(ptr), + Err(_) => break, + } + } + + assert_eq!(ptrs.len(), limit); + for ptr in ptrs { + assert!(heap.in_range(ptr)); + } + } + + #[test] + fn reuse_freed_elems() { + let limit = 4; + let mut heap = Heap::::new(limit).unwrap(); + let a = heap.alloc().unwrap(); + let b = heap.alloc().unwrap(); + let c = heap.alloc().unwrap(); + let d = heap.alloc().unwrap(); + + heap.dealloc(c); + assert_eq!(c, heap.alloc().unwrap()); + + assert!(heap.alloc().is_err()); + + heap.dealloc(d); + heap.dealloc(a); + heap.dealloc(b); + + // These should be reused in reverse order. + assert_eq!(b, heap.alloc().unwrap()); + assert_eq!(a, heap.alloc().unwrap()); + assert_eq!(d, heap.alloc().unwrap()); + + assert!(heap.alloc().is_err()); + } +} From f21654a78ebd2a289e30dedac18546d63a24f129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Geron?= Date: Wed, 11 Sep 2024 15:32:30 +1200 Subject: [PATCH 02/17] Add a test case for List.dropAt at an index located in the middle of the list --- crates/compiler/test_gen/src/gen_list.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/compiler/test_gen/src/gen_list.rs b/crates/compiler/test_gen/src/gen_list.rs index 401ddc5711a..4d2c42a070b 100644 --- a/crates/compiler/test_gen/src/gen_list.rs +++ b/crates/compiler/test_gen/src/gen_list.rs @@ -547,6 +547,11 @@ fn list_drop_at() { RocList::from_slice(&[2, 3]), RocList ); + assert_evals_to!( + "List.dropAt [1, 2, 3] 1", + RocList::from_slice(&[1, 3]), + RocList + ); assert_evals_to!( "List.dropAt [0, 0, 0] 3", RocList::from_slice(&[0, 0, 0]), From a7eae239f037cfe724cf74f7c559fed9dd87bfde Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 16 Sep 2024 16:47:20 -0700 Subject: [PATCH 03/17] Avoid explicit tag padding Explicit padding changes the c-abi when passed to/returned from functions. This is leading to incorrect loading of types like `Task U64 {}`. --- crates/compiler/gen_llvm/src/llvm/convert.rs | 12 ------------ crates/glue/src/RustGlue.roc | 20 -------------------- 2 files changed, 32 deletions(-) diff --git a/crates/compiler/gen_llvm/src/llvm/convert.rs b/crates/compiler/gen_llvm/src/llvm/convert.rs index 73eb20f3440..257f6613634 100644 --- a/crates/compiler/gen_llvm/src/llvm/convert.rs +++ b/crates/compiler/gen_llvm/src/llvm/convert.rs @@ -315,17 +315,6 @@ impl<'ctx> RocUnion<'ctx> { .as_basic_type_enum(); let struct_type = if let Some(tag_type) = tag_type { - let tag_width = match tag_type { - TagType::I8 => 1, - TagType::I16 => 2, - }; - - let tag_padding = round_up_to_alignment(tag_width, data_align) - tag_width; - let tag_padding_type = context - .i8_type() - .array_type(tag_padding) - .as_basic_type_enum(); - context.struct_type( &[ alignment_array_type, @@ -334,7 +323,6 @@ impl<'ctx> RocUnion<'ctx> { TagType::I8 => context.i8_type().into(), TagType::I16 => context.i16_type().into(), }, - tag_padding_type, ], false, ) diff --git a/crates/glue/src/RustGlue.roc b/crates/glue/src/RustGlue.roc index 61402a838db..0531aaa6029 100644 --- a/crates/glue/src/RustGlue.roc +++ b/crates/glue/src/RustGlue.roc @@ -1288,7 +1288,6 @@ generateRecursiveTagUnion = \buf, types, id, tagUnionName, tags, discriminantSiz union $(unionName) { """ |> \b -> List.walk tags b (generateUnionField types) - |> generateTagUnionSizer types id tags |> Str.concat "}\n\n" |> generateRocRefcounted types unionType escapedName @@ -1337,25 +1336,6 @@ writeTagImpls = \buf, tags, discriminantName, indents, f -> |> writeIndents indents |> Str.concat "}\n" -generateTagUnionSizer : Str, Types, TypeId, _ -> Str -generateTagUnionSizer = \buf, types, id, tags -> - if List.len tags > 1 then - # When there's a discriminant (so, multiple tags) and there is - # no alignment padding after the largest variant, - # the compiler will make extra room for the discriminant. - # We need that to be reflected in the overall size of the enum, - # so add an extra variant with the appropriate size. - # - # (Do this even if theoretically shouldn't be necessary, since - # there's no runtime cost and it more explicitly syncs the - # union's size with what we think it should be.) - size = getSizeRoundedToAlignment types id - sizeStr = Num.toStr size - - Str.concat buf "$(indent)_sizer: [u8; $(sizeStr)],\n" - else - buf - generateDiscriminant = \buf, types, name, tags, size -> if size > 0 then enumType = From 4e3ec97d7ae85f8253eec39b522532ddff38dd96 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Mon, 16 Sep 2024 17:10:49 -0700 Subject: [PATCH 04/17] generate array of alignment type to enforce tag data alignment --- crates/compiler/gen_llvm/src/llvm/convert.rs | 28 +++++--------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/crates/compiler/gen_llvm/src/llvm/convert.rs b/crates/compiler/gen_llvm/src/llvm/convert.rs index 257f6613634..079d5c2b794 100644 --- a/crates/compiler/gen_llvm/src/llvm/convert.rs +++ b/crates/compiler/gen_llvm/src/llvm/convert.rs @@ -282,16 +282,9 @@ pub(crate) struct RocUnion<'ctx> { tag_type: Option, } -fn is_multiple_of(big: u32, small: u32) -> bool { - match small { - 0 => true, // 0 is a multiple of all n, because n * 0 = 0 - n => big % n == 0, - } -} - impl<'ctx> RocUnion<'ctx> { - pub const TAG_ID_INDEX: u32 = 2; - pub const TAG_DATA_INDEX: u32 = 1; + pub const TAG_ID_INDEX: u32 = 1; + pub const TAG_DATA_INDEX: u32 = 0; fn new( context: &'ctx Context, @@ -301,23 +294,14 @@ impl<'ctx> RocUnion<'ctx> { ) -> Self { let bytes = round_up_to_alignment(data_width, data_align); - let byte_array_type = if is_multiple_of(bytes, 8) && is_multiple_of(data_align, 8) { - context - .i64_type() - .array_type(bytes / 8) - .as_basic_type_enum() - } else { - context.i8_type().array_type(bytes).as_basic_type_enum() - }; - - let alignment_array_type = alignment_type(context, data_align) - .array_type(0) + let align_type = alignment_type(context, data_align); + let byte_array_type = align_type + .array_type(bytes / data_align) .as_basic_type_enum(); let struct_type = if let Some(tag_type) = tag_type { context.struct_type( &[ - alignment_array_type, byte_array_type, match tag_type { TagType::I8 => context.i8_type().into(), @@ -327,7 +311,7 @@ impl<'ctx> RocUnion<'ctx> { false, ) } else { - context.struct_type(&[alignment_array_type, byte_array_type], false) + context.struct_type(&[byte_array_type], false) }; Self { From 515e2e3e3aa3a9e7b46186035b5f2ad9e2407734 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 17 Sep 2024 13:19:53 -0700 Subject: [PATCH 05/17] clippy --- crates/roc_std_heap/src/lib.rs | 64 +++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/crates/roc_std_heap/src/lib.rs b/crates/roc_std_heap/src/lib.rs index eaab3065b8f..018840071bd 100644 --- a/crates/roc_std_heap/src/lib.rs +++ b/crates/roc_std_heap/src/lib.rs @@ -40,18 +40,21 @@ impl ThreadSafeRefcountedResourceHeap { }) } - pub fn alloc_for(self: &Self, data: T) -> Result> { + pub fn alloc_for(&self, data: T) -> Result> { let _g = self.guard.lock().unwrap(); unsafe { &mut *self.heap.get() }.alloc_for(data) } - pub fn dealloc(self: &Self, ptr: *const U) { + /// # Safety + /// + /// This function will drop the pointed to data. It must be initialized. + pub unsafe fn dealloc(&self, ptr: *const U) { let _g = self.guard.lock().unwrap(); - unsafe { &mut *self.heap.get() }.dealloc(ptr) + (*self.heap.get()).dealloc(ptr) } // This is safe to call at any time with no lock! - pub fn in_range(self: &Self, ptr: *const U) -> bool { + pub fn in_range(&self, ptr: *const U) -> bool { unsafe { &*self.heap.get() }.in_range(ptr) } @@ -75,7 +78,7 @@ impl RefcountedResourceHeap { Heap::new(max_elements).map(|heap| RefcountedResourceHeap(heap)) } - pub fn alloc_for(self: &mut Self, data: T) -> Result> { + pub fn alloc_for(&mut self, data: T) -> Result> { self.0.alloc().map(|alloc_ptr| { unsafe { std::ptr::write(alloc_ptr, Refcounted(REFCOUNT_ONE, data)) }; let box_ptr = alloc_ptr as usize + mem::size_of::(); @@ -83,11 +86,14 @@ impl RefcountedResourceHeap { }) } - pub fn dealloc(self: &mut Self, ptr: *const U) { + /// # Safety + /// + /// This function will drop the pointed to data. It must be initialized. + pub unsafe fn dealloc(&mut self, ptr: *const U) { self.0.dealloc(ptr as _); } - pub fn in_range(self: &Self, ptr: *const U) -> bool { + pub fn in_range(&self, ptr: *const U) -> bool { self.0.in_range(ptr as _) } @@ -129,12 +135,12 @@ impl Heap { elements: 0, max_elements, free_list: ptr::null(), - phantom: PhantomData::default(), + phantom: PhantomData, }) } - pub fn alloc(self: &mut Self) -> Result<*mut T> { - if self.free_list != ptr::null() { + pub fn alloc(&mut self) -> Result<*mut T> { + if self.free_list.is_null() { // Open slot on the free list. let root = self.free_list as *const *const c_void; let next = unsafe { *root }; @@ -147,32 +153,33 @@ impl Heap { // If has available memory allocate at end. if self.elements < self.max_elements { let offset = self.elements * Self::node_size(); - let elem_ptr = unsafe { self.data.as_mut_ptr().offset(offset as isize) }; + let elem_ptr = unsafe { self.data.as_mut_ptr().add(offset) }; self.elements += 1; return Ok(elem_ptr as *mut T); } - return Err(Error::from(ErrorKind::OutOfMemory)); + Err(Error::from(ErrorKind::OutOfMemory)) } - pub fn dealloc(self: &mut Self, elem_ptr: *mut T) { + /// # Safety + /// + /// This function will drop the pointed to data. It must be initialized. + pub unsafe fn dealloc(&mut self, elem_ptr: *mut T) { debug_assert!(self.in_range(elem_ptr)); // Just push the freed value to the start of the free list. let old_root = self.free_list; self.free_list = elem_ptr as *const c_void; - unsafe { *(self.free_list as *mut *const c_void) = old_root }; + *(self.free_list as *mut *const c_void) = old_root; - unsafe { - // Free the underlying resource. - std::ptr::drop_in_place(elem_ptr); - } + // Free the underlying resource. + std::ptr::drop_in_place(elem_ptr); } - pub fn in_range(self: &Self, elem_ptr: *mut T) -> bool { + pub fn in_range(&self, elem_ptr: *mut T) -> bool { let start = self.data.as_ptr(); let offset = self.elements * Self::node_size(); - let end = unsafe { start.offset(offset as isize) }; + let end = unsafe { start.add(offset) }; (start as usize) <= (elem_ptr as usize) && (elem_ptr as usize) < (end as usize) } @@ -198,11 +205,8 @@ mod test { let limit = 4; let mut heap = Heap::::new(limit).unwrap(); let mut ptrs = vec![]; - loop { - match heap.alloc() { - Ok(ptr) => ptrs.push(ptr), - Err(_) => break, - } + while let Ok(ptr) = heap.alloc() { + ptrs.push(ptr); } assert_eq!(ptrs.len(), limit); @@ -220,14 +224,16 @@ mod test { let c = heap.alloc().unwrap(); let d = heap.alloc().unwrap(); - heap.dealloc(c); + unsafe { heap.dealloc(c) }; assert_eq!(c, heap.alloc().unwrap()); assert!(heap.alloc().is_err()); - heap.dealloc(d); - heap.dealloc(a); - heap.dealloc(b); + unsafe { + heap.dealloc(d); + heap.dealloc(a); + heap.dealloc(b); + } // These should be reused in reverse order. assert_eq!(b, heap.alloc().unwrap()); From dc538ef788c5c1068c33244f6a68f3208f010a57 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 17 Sep 2024 13:27:39 -0700 Subject: [PATCH 06/17] add function from basic-webserver impl --- crates/roc_std_heap/src/lib.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/crates/roc_std_heap/src/lib.rs b/crates/roc_std_heap/src/lib.rs index 018840071bd..19a4da65003 100644 --- a/crates/roc_std_heap/src/lib.rs +++ b/crates/roc_std_heap/src/lib.rs @@ -61,6 +61,15 @@ impl ThreadSafeRefcountedResourceHeap { pub fn box_to_resource<'a>(data: RocBox<()>) -> &'a mut T { RefcountedResourceHeap::box_to_resource(data) } + + pub fn box_to_refcount<'a>(data: &RocBox<()>) -> &'a mut usize { + RefcountedResourceHeap::::box_to_refcount(data) + } + + pub fn promote_all_to_constant(self: &Self) { + let _g = self.guard.lock().unwrap(); + unsafe { &mut *self.heap.get() }.promote_all_to_constant(); + } } unsafe impl Sync for ThreadSafeRefcountedResourceHeap {} @@ -104,6 +113,26 @@ impl RefcountedResourceHeap { let alloc: &mut Refcounted = unsafe { &mut *alloc_ptr }; &mut alloc.1 } + + pub fn box_to_refcount<'a>(data: &RocBox<()>) -> &'a mut usize { + let box_ptr: &usize = unsafe { std::mem::transmute(data) }; + + let rc_ptr = (*box_ptr - mem::size_of::()) as *mut usize; + unsafe { &mut *rc_ptr } + } + + /// Promotes all live references to constants. + /// Does this my walking all allocations and setting the refcount to zero (constant). + /// It will also end up walking freed elements, but their bytes are uninitialized and don't matter. + /// This is great for calling after an init function where all lived data is guarenteed to live until the server finishes running. + pub fn promote_all_to_constant(self: &mut Self) { + for i in 0..self.0.elements { + let offset = i * Heap::>::node_size(); + let elem_ptr = unsafe { self.0.data.as_mut_ptr().offset(offset as isize) }; + let rc_ptr = elem_ptr as *mut usize; + unsafe { *rc_ptr = 0 }; + } + } } /// The Heap is one mmap of data that can be interpreted multiple ways. From 8305affe2577bb8cdd584771436e68aef4f15020 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 17 Sep 2024 13:28:28 -0700 Subject: [PATCH 07/17] more clippy --- crates/roc_std_heap/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/roc_std_heap/src/lib.rs b/crates/roc_std_heap/src/lib.rs index 19a4da65003..a77d46b41c9 100644 --- a/crates/roc_std_heap/src/lib.rs +++ b/crates/roc_std_heap/src/lib.rs @@ -66,7 +66,7 @@ impl ThreadSafeRefcountedResourceHeap { RefcountedResourceHeap::::box_to_refcount(data) } - pub fn promote_all_to_constant(self: &Self) { + pub fn promote_all_to_constant(&self) { let _g = self.guard.lock().unwrap(); unsafe { &mut *self.heap.get() }.promote_all_to_constant(); } @@ -125,10 +125,10 @@ impl RefcountedResourceHeap { /// Does this my walking all allocations and setting the refcount to zero (constant). /// It will also end up walking freed elements, but their bytes are uninitialized and don't matter. /// This is great for calling after an init function where all lived data is guarenteed to live until the server finishes running. - pub fn promote_all_to_constant(self: &mut Self) { + pub fn promote_all_to_constant(&mut self) { for i in 0..self.0.elements { let offset = i * Heap::>::node_size(); - let elem_ptr = unsafe { self.0.data.as_mut_ptr().offset(offset as isize) }; + let elem_ptr = unsafe { self.0.data.as_mut_ptr().add(offset) }; let rc_ptr = elem_ptr as *mut usize; unsafe { *rc_ptr = 0 }; } From ad7be994ce4288393ee5096d1db7dfaf8aee8442 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 17 Sep 2024 13:33:33 -0700 Subject: [PATCH 08/17] minor cleanup --- crates/roc_std_heap/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/roc_std_heap/src/lib.rs b/crates/roc_std_heap/src/lib.rs index a77d46b41c9..9a9dc152cf5 100644 --- a/crates/roc_std_heap/src/lib.rs +++ b/crates/roc_std_heap/src/lib.rs @@ -20,6 +20,7 @@ use std::{ }; const REFCOUNT_ONE: usize = isize::MIN as usize; +const REFCOUNT_CONSTANT: usize = 0; /// ThreadSafeRefcountedResourceHeap is a threadsafe version of the refcounted heap that can avoid a wrapping Mutex and RefCell. /// This is very important for dealloc performance. @@ -130,7 +131,7 @@ impl RefcountedResourceHeap { let offset = i * Heap::>::node_size(); let elem_ptr = unsafe { self.0.data.as_mut_ptr().add(offset) }; let rc_ptr = elem_ptr as *mut usize; - unsafe { *rc_ptr = 0 }; + unsafe { *rc_ptr = REFCOUNT_CONSTANT }; } } } From 3e423ce41813322320060a02ab376f664efeabc3 Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 17 Sep 2024 13:37:11 -0700 Subject: [PATCH 09/17] typo --- crates/roc_std_heap/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/roc_std_heap/src/lib.rs b/crates/roc_std_heap/src/lib.rs index 9a9dc152cf5..0dc8af1a0b5 100644 --- a/crates/roc_std_heap/src/lib.rs +++ b/crates/roc_std_heap/src/lib.rs @@ -125,7 +125,7 @@ impl RefcountedResourceHeap { /// Promotes all live references to constants. /// Does this my walking all allocations and setting the refcount to zero (constant). /// It will also end up walking freed elements, but their bytes are uninitialized and don't matter. - /// This is great for calling after an init function where all lived data is guarenteed to live until the server finishes running. + /// This is great for calling after an init function where all lived data is guaranteed to live until the server finishes running. pub fn promote_all_to_constant(&mut self) { for i in 0..self.0.elements { let offset = i * Heap::>::node_size(); From 7989ee763c307bd4f7031ab9eb1c22e8fac7d7dd Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Tue, 17 Sep 2024 14:20:36 -0700 Subject: [PATCH 10/17] fix null check (accidentally inverted conditional) --- crates/roc_std_heap/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/roc_std_heap/src/lib.rs b/crates/roc_std_heap/src/lib.rs index 0dc8af1a0b5..1af5dcc8997 100644 --- a/crates/roc_std_heap/src/lib.rs +++ b/crates/roc_std_heap/src/lib.rs @@ -170,7 +170,7 @@ impl Heap { } pub fn alloc(&mut self) -> Result<*mut T> { - if self.free_list.is_null() { + if !self.free_list.is_null() { // Open slot on the free list. let root = self.free_list as *const *const c_void; let next = unsafe { *root }; From 033d87034c01e76c1a0798b301bd7b91816f6f4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Geron?= Date: Wed, 11 Sep 2024 15:32:30 +1200 Subject: [PATCH 11/17] Add a test case for List.dropAt at an index located in the middle of the list --- crates/compiler/test_gen/src/gen_list.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/compiler/test_gen/src/gen_list.rs b/crates/compiler/test_gen/src/gen_list.rs index 401ddc5711a..4d2c42a070b 100644 --- a/crates/compiler/test_gen/src/gen_list.rs +++ b/crates/compiler/test_gen/src/gen_list.rs @@ -547,6 +547,11 @@ fn list_drop_at() { RocList::from_slice(&[2, 3]), RocList ); + assert_evals_to!( + "List.dropAt [1, 2, 3] 1", + RocList::from_slice(&[1, 3]), + RocList + ); assert_evals_to!( "List.dropAt [0, 0, 0] 3", RocList::from_slice(&[0, 0, 0]), From c10b25cf6e8a69b4c95ce9eeeb2ce29cda6ec85f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Geron?= Date: Thu, 19 Sep 2024 10:43:05 +1200 Subject: [PATCH 12/17] Fixes #7065 in List.dropAt, author: @bhansconnect --- crates/compiler/builtins/bitcode/src/list.zig | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/crates/compiler/builtins/bitcode/src/list.zig b/crates/compiler/builtins/bitcode/src/list.zig index e89b39c5611..c95e6e8063e 100644 --- a/crates/compiler/builtins/bitcode/src/list.zig +++ b/crates/compiler/builtins/bitcode/src/list.zig @@ -618,6 +618,16 @@ pub fn listDropAt( ) callconv(.C) RocList { const size = list.len(); const size_u64 = @as(u64, @intCast(size)); + + // NOTE + // we need to return an empty list explicitly, + // because we rely on the pointer field being null if the list is empty + // which also requires duplicating the utils.decref call to spend the RC token + if (size <= 1) { + list.decref(alignment, element_width, elements_refcounted, dec); + return RocList.empty(); + } + // If droping the first or last element, return a seamless slice. // For simplicity, do this by calling listSublist. // In the future, we can test if it is faster to manually inline the important parts here. @@ -638,25 +648,16 @@ pub fn listDropAt( // were >= than `size`, and we know `size` fits in usize. const drop_index: usize = @intCast(drop_index_u64); - if (elements_refcounted) { - const element = source_ptr + drop_index * element_width; - dec(element); - } - - // NOTE - // we need to return an empty list explicitly, - // because we rely on the pointer field being null if the list is empty - // which also requires duplicating the utils.decref call to spend the RC token - if (size < 2) { - list.decref(alignment, element_width, elements_refcounted, dec); - return RocList.empty(); - } - if (list.isUnique()) { - var i = drop_index; - const copy_target = source_ptr; + if (elements_refcounted) { + const element = source_ptr + drop_index * element_width; + dec(element); + } + + const copy_target = source_ptr + (drop_index * element_width); const copy_source = copy_target + element_width; - std.mem.copyForwards(u8, copy_target[i..size], copy_source[i..size]); + const copy_size = (size - drop_index - 1) * element_width; + std.mem.copyForwards(u8, copy_target[0..copy_size], copy_source[0..copy_size]); var new_list = list; From a9594fa75dcf862fd49d2affc81de718fcc499b8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 04:16:02 +0000 Subject: [PATCH 13/17] Bump serve-static and express in /crates/compiler/checkmate/www Bumps [serve-static](https://github.com/expressjs/serve-static) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together. Updates `serve-static` from 1.15.0 to 1.16.2 - [Release notes](https://github.com/expressjs/serve-static/releases) - [Changelog](https://github.com/expressjs/serve-static/blob/v1.16.2/HISTORY.md) - [Commits](https://github.com/expressjs/serve-static/compare/v1.15.0...v1.16.2) Updates `express` from 4.19.2 to 4.21.0 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.0) --- updated-dependencies: - dependency-name: serve-static dependency-type: indirect - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../compiler/checkmate/www/package-lock.json | 237 +++++++++++++----- 1 file changed, 168 insertions(+), 69 deletions(-) diff --git a/crates/compiler/checkmate/www/package-lock.json b/crates/compiler/checkmate/www/package-lock.json index 0f9ae79b541..b933542cb82 100644 --- a/crates/compiler/checkmate/www/package-lock.json +++ b/crates/compiler/checkmate/www/package-lock.json @@ -5917,9 +5917,9 @@ "dev": true }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "dependencies": { "bytes": "3.1.2", @@ -5930,7 +5930,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -6091,13 +6091,19 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7249,6 +7255,23 @@ "node": ">= 10" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -7597,9 +7620,9 @@ } }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "engines": { "node": ">= 0.8" @@ -7704,6 +7727,27 @@ "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", "dev": true }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", @@ -8646,37 +8690,37 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "dev": true, "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -8883,13 +8927,13 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -9249,10 +9293,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { "version": "1.1.5", @@ -9300,15 +9347,19 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9590,12 +9641,12 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.1" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9640,6 +9691,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -13153,10 +13216,13 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -13538,10 +13604,13 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -13889,9 +13958,9 @@ "dev": true }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", "dev": true }, "node_modules/path-type": { @@ -15501,12 +15570,12 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -16560,9 +16629,9 @@ "dev": true }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "dependencies": { "debug": "2.6.9", @@ -16598,6 +16667,15 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -16692,20 +16770,37 @@ } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -16743,14 +16838,18 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" From 584a6c2bd27470e94700ea94c8b1d0a1770eae1c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 04:16:05 +0000 Subject: [PATCH 14/17] Bump body-parser and express in /crates/compiler/checkmate/www Bumps [body-parser](https://github.com/expressjs/body-parser) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together. Updates `body-parser` from 1.20.2 to 1.20.3 - [Release notes](https://github.com/expressjs/body-parser/releases) - [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md) - [Commits](https://github.com/expressjs/body-parser/compare/1.20.2...1.20.3) Updates `express` from 4.19.2 to 4.21.0 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.0) --- updated-dependencies: - dependency-name: body-parser dependency-type: indirect - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../compiler/checkmate/www/package-lock.json | 237 +++++++++++++----- 1 file changed, 168 insertions(+), 69 deletions(-) diff --git a/crates/compiler/checkmate/www/package-lock.json b/crates/compiler/checkmate/www/package-lock.json index 0f9ae79b541..b933542cb82 100644 --- a/crates/compiler/checkmate/www/package-lock.json +++ b/crates/compiler/checkmate/www/package-lock.json @@ -5917,9 +5917,9 @@ "dev": true }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "dependencies": { "bytes": "3.1.2", @@ -5930,7 +5930,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -6091,13 +6091,19 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7249,6 +7255,23 @@ "node": ">= 10" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -7597,9 +7620,9 @@ } }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "engines": { "node": ">= 0.8" @@ -7704,6 +7727,27 @@ "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", "dev": true }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", @@ -8646,37 +8690,37 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "dev": true, "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -8883,13 +8927,13 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -9249,10 +9293,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { "version": "1.1.5", @@ -9300,15 +9347,19 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9590,12 +9641,12 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.1" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9640,6 +9691,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -13153,10 +13216,13 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -13538,10 +13604,13 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -13889,9 +13958,9 @@ "dev": true }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", "dev": true }, "node_modules/path-type": { @@ -15501,12 +15570,12 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -16560,9 +16629,9 @@ "dev": true }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "dependencies": { "debug": "2.6.9", @@ -16598,6 +16667,15 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -16692,20 +16770,37 @@ } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -16743,14 +16838,18 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" From 3eadc03e28a9e05f5e284c598e86f9a9827d4270 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Fri, 20 Sep 2024 16:19:56 -0300 Subject: [PATCH 15/17] Add failing test for multiline params --- crates/cli/tests/cli_run.rs | 19 +++++++++++++++++++ .../tests/module_params/MultilineParams.roc | 8 ++++++++ .../tests/module_params/multiline_params.roc | 11 +++++++++++ crates/compiler/can/src/pattern.rs | 5 ++++- 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 crates/cli/tests/module_params/MultilineParams.roc create mode 100644 crates/cli/tests/module_params/multiline_params.roc diff --git a/crates/cli/tests/cli_run.rs b/crates/cli/tests/cli_run.rs index 1544a888873..a27aa457ab0 100644 --- a/crates/cli/tests/cli_run.rs +++ b/crates/cli/tests/cli_run.rs @@ -922,6 +922,25 @@ mod cli_run { ); } + #[test] + #[cfg_attr(windows, ignore)] + fn module_params_multiline_pattern() { + test_roc_app( + "crates/cli/tests/module_params", + "multiline_params.roc", + &[], + &[], + &[], + indoc!( + r#" + hi + "# + ), + UseValgrind::No, + TestCliCommands::Dev, + ); + } + #[test] #[cfg_attr(windows, ignore)] fn transitive_expects() { diff --git a/crates/cli/tests/module_params/MultilineParams.roc b/crates/cli/tests/module_params/MultilineParams.roc new file mode 100644 index 00000000000..631b88473be --- /dev/null +++ b/crates/cli/tests/module_params/MultilineParams.roc @@ -0,0 +1,8 @@ +module { + sendHttpReq, + getEnvVar +} -> [hi] + +hi : Str +hi = + "hi" diff --git a/crates/cli/tests/module_params/multiline_params.roc b/crates/cli/tests/module_params/multiline_params.roc new file mode 100644 index 00000000000..531721c9258 --- /dev/null +++ b/crates/cli/tests/module_params/multiline_params.roc @@ -0,0 +1,11 @@ +app [main] { + pf: platform "../fixtures/multi-dep-str/platform/main.roc", +} + +import MultilineParams { + sendHttpReq: \_ -> crash "todo", + getEnvVar: \_ -> crash "todo", +} + +main = + MultilineParams.hi \ No newline at end of file diff --git a/crates/compiler/can/src/pattern.rs b/crates/compiler/can/src/pattern.rs index ddd6efda308..ffd097e3ae8 100644 --- a/crates/compiler/can/src/pattern.rs +++ b/crates/compiler/can/src/pattern.rs @@ -914,7 +914,10 @@ pub fn canonicalize_record_destructs<'a>( } }; } - _ => unreachable!("Any other pattern should have given a parse error"), + _ => unreachable!( + "Any other pattern should have given a parse error: {:?}", + loc_pattern.value + ), } } From 3f9e957c9cba8fa5e2b6c15b6926dedabd8434c4 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Fri, 20 Sep 2024 16:30:59 -0300 Subject: [PATCH 16/17] Extract record destructure desugaring into its own fn --- crates/compiler/can/src/desugar.rs | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/crates/compiler/can/src/desugar.rs b/crates/compiler/can/src/desugar.rs index 3f4872366e4..65599c21783 100644 --- a/crates/compiler/can/src/desugar.rs +++ b/crates/compiler/can/src/desugar.rs @@ -1226,17 +1226,7 @@ fn desugar_pattern<'a>(env: &mut Env<'a>, scope: &mut Scope, pattern: Pattern<'a Apply(tag, desugared_arg_patterns.into_bump_slice()) } RecordDestructure(field_patterns) => { - let mut allocated = Vec::with_capacity_in(field_patterns.len(), env.arena); - for field_pattern in field_patterns.iter() { - let value = desugar_pattern(env, scope, field_pattern.value); - allocated.push(Loc { - value, - region: field_pattern.region, - }); - } - let field_patterns = field_patterns.replace_items(allocated.into_bump_slice()); - - RecordDestructure(field_patterns) + RecordDestructure(desugar_record_destructures(env, scope, field_patterns)) } RequiredField(name, field_pattern) => { RequiredField(name, desugar_loc_pattern(env, scope, field_pattern)) @@ -1274,6 +1264,23 @@ fn desugar_pattern<'a>(env: &mut Env<'a>, scope: &mut Scope, pattern: Pattern<'a } } +pub fn desugar_record_destructures<'a>( + env: &mut Env<'a>, + scope: &mut Scope, + field_patterns: Collection<'a, Loc>>, +) -> Collection<'a, Loc>> { + let mut allocated = Vec::with_capacity_in(field_patterns.len(), env.arena); + for field_pattern in field_patterns.iter() { + let value = desugar_pattern(env, scope, field_pattern.value); + allocated.push(Loc { + value, + region: field_pattern.region, + }); + } + + field_patterns.replace_items(allocated.into_bump_slice()) +} + /// Desugars a `dbg expr` expression into a statement block that prints and returns the /// value produced by `expr`. Essentially: /// ( From 5054c9990edb08982eb99a7aea4e8525d36bf6e3 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Fri, 20 Sep 2024 16:35:18 -0300 Subject: [PATCH 17/17] Desugar module param patterns before canonicalizing --- crates/compiler/can/src/module.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/compiler/can/src/module.rs b/crates/compiler/can/src/module.rs index 14dc2f827b8..3a45b6ba912 100644 --- a/crates/compiler/can/src/module.rs +++ b/crates/compiler/can/src/module.rs @@ -3,6 +3,7 @@ use std::path::Path; use crate::abilities::{AbilitiesStore, ImplKey, PendingAbilitiesStore, ResolvedImpl}; use crate::annotation::{canonicalize_annotation, AnnotationFor}; use crate::def::{canonicalize_defs, report_unused_imports, Def}; +use crate::desugar::desugar_record_destructures; use crate::env::Env; use crate::expr::{ ClosureData, DbgLookup, Declarations, ExpectLookup, Expr, Output, PendingDerives, @@ -326,13 +327,16 @@ pub fn canonicalize_module_defs<'a>( before_arrow: _, after_arrow: _, }| { + let desugared_patterns = + desugar_record_destructures(&mut env, &mut scope, pattern.value); + let (destructs, _) = canonicalize_record_destructs( &mut env, var_store, &mut scope, &mut output, PatternType::ModuleParams, - &pattern.value, + &desugared_patterns, pattern.region, PermitShadows(false), );