Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 3 additions & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ oxc_sourcemap = "3"

#
allocator-api2 = "0.2.21"
assert-unchecked = "0.1.2"
base64 = "0.22.1"
bitflags = "2.8.0"
bpaf = "0.9.16"
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_allocator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ workspace = true
doctest = false

[dependencies]
oxc_data_structures = { workspace = true, features = ["assert_unchecked"] }
oxc_estree = { workspace = true, optional = true }

allocator-api2 = { workspace = true }
assert-unchecked = { workspace = true }
bumpalo = { workspace = true, features = ["allocator-api2", "collections"] }
hashbrown = { workspace = true, default-features = false, features = ["inline-more", "allocator-api2"] }
rustc-hash = { workspace = true }
Expand Down
3 changes: 2 additions & 1 deletion crates/oxc_allocator/src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ use std::{
ptr,
};

use assert_unchecked::assert_unchecked;
use bumpalo::collections::String as BumpaloString;
pub use simdutf8::basic::Utf8Error;
use simdutf8::basic::from_utf8;

use oxc_data_structures::assert_unchecked;

use crate::{Allocator, Vec};

/// Arena String.
Expand Down
9 changes: 5 additions & 4 deletions crates/oxc_data_structures/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,17 @@ workspace = true

[lib]
test = true
# Doctests must be enabled for this crate as they are used to run compilation failure tests
doctest = true

[dependencies]
assert-unchecked = { workspace = true, optional = true }
ropey = { workspace = true, optional = true }

[features]
default = []
all = ["code_buffer", "inline_string", "rope", "stack"]
code_buffer = ["dep:assert-unchecked"]
all = ["assert_unchecked", "code_buffer", "inline_string", "rope", "stack"]
assert_unchecked = []
code_buffer = ["assert_unchecked"]
inline_string = []
rope = ["dep:ropey"]
stack = ["dep:assert-unchecked"]
stack = ["assert_unchecked"]
102 changes: 102 additions & 0 deletions crates/oxc_data_structures/src/assert_unchecked.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//! `assert_unchecked!` macro.

/// Macro that makes a soundness promise to the compiler that this condition always holds.
///
/// This is wrapper around [`std::hint::assert_unchecked`] which performs a standard safe `assert!`
/// in debug builds, and accepts a format string for the error in that case.
///
/// See documentation for [`std::hint::assert_unchecked`] for further details.
///
/// This macro can be used in const context.
///
/// # SAFETY
/// It is undefined behaviour if the condition evaluates to `false`.
///
/// # Examples
/// ```
/// // Requires `assert_unchecked` feature
/// use oxc_data_structures::assert_unchecked;
///
/// /// Read first byte from a `&[u8]`, without bounds checks.
/// ///
/// /// # SAFETY
/// /// Caller must ensure `slice` is not empty.
/// unsafe fn first_unchecked(slice: &[u8]) -> u8 {
/// // SAFETY: Caller guarantees `slice` is not empty
/// unsafe {
/// assert_unchecked!(!slice.is_empty(), "Oh no. Slice is empty.");
/// }
/// // Compiler elides the bounds check here. https://godbolt.org/z/xaGK8GzbG
/// slice[0]
/// }
/// ```
#[macro_export]
macro_rules! assert_unchecked {
($cond:expr) => (assert_unchecked!($cond,));
($cond:expr, $($arg:tt)*) => ({
#[cfg(debug_assertions)]
{
const unsafe fn __needs_unsafe() {}
__needs_unsafe();
assert!($cond, $($arg)*);
}
#[cfg(not(debug_assertions))]
{
std::hint::assert_unchecked($cond);
}
})
}

/**
Doctest to ensure macro cannot be used without `unsafe {}`.
```compile_fail
use oxc_data_structures::assert_unchecked;
assert_unchecked!(true);
```
*/
const _MACRO_CANNOT_BE_USED_WITHOUT_UNSAFE: () = ();

#[cfg(test)]
#[expect(clippy::undocumented_unsafe_blocks)]
mod test {
mod pass {
use crate::assert_unchecked;

#[test]
fn plain() {
unsafe { assert_unchecked!(0 == 0) };
}

#[test]
fn string_literal() {
unsafe { assert_unchecked!(0 == 0, "String literal") };
}

#[test]
fn fmt_string() {
unsafe { assert_unchecked!(0 == 0, "Format str {} {:?}", 123, 456) };
}
}

// Cannot test failing assertions in release mode as it'd be undefined behavior!
#[cfg(debug_assertions)]
mod fail {
#[test]
#[should_panic(expected = "assertion failed: 0 == 1")]
fn plain() {
unsafe { assert_unchecked!(0 == 1) };
}

#[test]
#[should_panic(expected = "String literal")]
fn string_literal() {
unsafe { assert_unchecked!(0 == 1, "String literal") };
}

#[test]
#[should_panic(expected = "Format str: 123 456")]
fn fmt_string() {
unsafe { assert_unchecked!(0 == 1, "Format str: {} {:?}", 123, 456) };
}
}
}
2 changes: 1 addition & 1 deletion crates/oxc_data_structures/src/code_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use std::iter;

use assert_unchecked::assert_unchecked;
use crate::assert_unchecked;

/// A string builder for constructing source code.
///
Expand Down
6 changes: 6 additions & 0 deletions crates/oxc_data_structures/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@

#![warn(missing_docs)]

#[cfg(feature = "assert_unchecked")]
mod assert_unchecked;

#[cfg(feature = "code_buffer")]
pub mod code_buffer;

#[cfg(feature = "inline_string")]
pub mod inline_string;

#[cfg(feature = "rope")]
pub mod rope;

#[cfg(feature = "stack")]
pub mod stack;
2 changes: 1 addition & 1 deletion crates/oxc_data_structures/src/stack/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::{
slice,
};

use assert_unchecked::assert_unchecked;
use crate::assert_unchecked;

use super::StackCapacity;

Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ doctest = false
[dependencies]
oxc_allocator = { workspace = true }
oxc_ast = { workspace = true }
oxc_data_structures = { workspace = true, features = ["assert_unchecked"] }
oxc_diagnostics = { workspace = true }
oxc_ecmascript = { workspace = true }
oxc_regular_expression = { workspace = true }
oxc_span = { workspace = true }
oxc_syntax = { workspace = true }

assert-unchecked = { workspace = true }
bitflags = { workspace = true }
cow-utils = { workspace = true }
num-bigint = { workspace = true }
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_parser/src/lexer/byte_handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ macro_rules! byte_handler {
/// fn SPS(lexer: &mut Lexer) {
/// // SAFETY: This macro is only used for ASCII characters
/// unsafe {
/// use assert_unchecked::assert_unchecked;
/// use oxc_data_structures::assert_unchecked;
/// assert_unchecked!(!lexer.source.is_eof());
/// assert_unchecked!(lexer.source.peek_byte_unchecked() < 128);
/// }
Expand All @@ -125,7 +125,7 @@ macro_rules! ascii_byte_handler {
byte_handler!($id($lex) {
// SAFETY: This macro is only used for ASCII characters
unsafe {
use assert_unchecked::assert_unchecked;
use oxc_data_structures::assert_unchecked;
assert_unchecked!(!$lex.source.is_eof());
assert_unchecked!($lex.source.peek_byte_unchecked() < 128);
}
Expand Down
3 changes: 1 addition & 2 deletions crates/oxc_semantic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,13 @@ oxc_allocator = { workspace = true }
oxc_ast = { workspace = true }
oxc_ast_visit = { workspace = true }
oxc_cfg = { workspace = true }
oxc_data_structures = { workspace = true, features = ["stack"] }
oxc_data_structures = { workspace = true, features = ["assert_unchecked", "stack"] }
oxc_diagnostics = { workspace = true }
oxc_ecmascript = { workspace = true }
oxc_index = { workspace = true }
oxc_span = { workspace = true }
oxc_syntax = { workspace = true }

assert-unchecked = { workspace = true }
itertools = { workspace = true }
phf = { workspace = true, features = ["macros"] }
rustc-hash = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_semantic/src/unresolved_stack.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use assert_unchecked::assert_unchecked;
use rustc_hash::FxHashMap;

use oxc_data_structures::assert_unchecked;
use oxc_span::Atom;
use oxc_syntax::reference::ReferenceId;

Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_syntax/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ doctest = false
[dependencies]
oxc_allocator = { workspace = true }
oxc_ast_macros = { workspace = true }
oxc_data_structures = { workspace = true, features = ["assert_unchecked"] }
oxc_estree = { workspace = true }
oxc_index = { workspace = true }
oxc_span = { workspace = true }

assert-unchecked = { workspace = true }
bitflags = { workspace = true }
cow-utils = { workspace = true }
nonmax = { workspace = true }
Expand Down
4 changes: 3 additions & 1 deletion crates/oxc_syntax/src/identifier.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#![expect(missing_docs)] // fixme
use assert_unchecked::assert_unchecked;

use unicode_id_start::{is_id_continue_unicode, is_id_start_unicode};

use oxc_data_structures::assert_unchecked;

pub const EOF: char = '\0';

// 11.1 Unicode Format-Control Characters
Expand Down
Loading