treewide: enforce strict clippy check
This commit is contained in:
@@ -4,7 +4,9 @@ use std::marker::PhantomData;
|
||||
use std::mem::size_of;
|
||||
use std::ops::Deref;
|
||||
|
||||
use fix_bytecode::Continuation;
|
||||
use fix_lang::*;
|
||||
use fix_macros::unelide_lifetimes;
|
||||
use gc_arena::barrier::Unlock;
|
||||
use gc_arena::collect::Trace;
|
||||
use gc_arena::{Collect, Gc, GcRefLock, Mutation, RefLock};
|
||||
@@ -20,7 +22,10 @@ mod private {
|
||||
}
|
||||
|
||||
pub trait ValueVariant: private::Cealed {
|
||||
#[allow(private_bounds)]
|
||||
#[expect(
|
||||
private_bounds,
|
||||
reason = "Storable is a sealed implementation detail of the value system"
|
||||
)]
|
||||
type Ty<'gc>: Storable + 'gc;
|
||||
const TYPE: NixType;
|
||||
}
|
||||
@@ -52,6 +57,9 @@ macro_rules! define_value_types {
|
||||
}
|
||||
#[inline(always)]
|
||||
unsafe fn from_raw_box(raw: RawBox) -> Self {
|
||||
// SAFETY: the caller guarantees `raw` represents a valid
|
||||
// `Self` of this inline type, so it holds a `Value` (making
|
||||
// `value()` `Some`) whose payload decodes to this type.
|
||||
unsafe { <Self as RawStore>::from_val(raw.value().unwrap_unchecked()) }
|
||||
}
|
||||
}
|
||||
@@ -73,13 +81,17 @@ macro_rules! define_value_types {
|
||||
}
|
||||
#[inline(always)]
|
||||
unsafe fn from_raw_box(raw: RawBox) -> Self {
|
||||
// SAFETY: the caller guarantees `raw` represents a valid
|
||||
// `Self` of this GC type, so it holds a `Value` (making
|
||||
// `value()` `Some`) whose payload is the pointer originally
|
||||
// produced by `Gc::as_ptr` in `to_raw_box`.
|
||||
unsafe { Gc::from_ptr(<*mut $gtype as RawStore>::from_val(raw.value().unwrap_unchecked())) }
|
||||
}
|
||||
}
|
||||
impl private::Cealed for Gc<'_, $gtype> {}
|
||||
impl private::Cealed for $gtype {}
|
||||
impl ValueVariant for $gtype {
|
||||
type Ty<'gc> = Gc<'gc, fix_macros::unelide_lifetimes!('gc; $gtype)>;
|
||||
type Ty<'gc> = Gc<'gc, unelide_lifetimes!('gc; $gtype)>;
|
||||
const TYPE: NixType = $gty;
|
||||
}
|
||||
)*
|
||||
@@ -93,6 +105,7 @@ macro_rules! define_value_types {
|
||||
let mut mask_true: u8 = 0;
|
||||
let mut i = 0;
|
||||
while i < tags.len() {
|
||||
#[expect(clippy::indexing_slicing, reason = "loop condition guarantees `i < tags.len()`")]
|
||||
let (neg, val) = tags[i];
|
||||
let bit = 1 << val;
|
||||
if neg {
|
||||
@@ -106,12 +119,17 @@ macro_rules! define_value_types {
|
||||
}
|
||||
};
|
||||
|
||||
// SAFETY: `trace` visits every reachable `Gc` pointer: for each GC
|
||||
// tag it downcasts to the concrete `Gc` type and forwards `trace`,
|
||||
// while inline tags hold no GC pointers and need no tracing.
|
||||
unsafe impl<'gc> Collect<'gc> for Value<'gc> {
|
||||
const NEEDS_TRACE: bool = true;
|
||||
fn trace<T: Trace<'gc>>(&self, cc: &mut T) {
|
||||
let Some(tag) = self.raw.tag() else { return };
|
||||
match tag {
|
||||
$($gtag => unsafe {
|
||||
// SAFETY: `tag` matched `$gtag`, so `downcast` to the
|
||||
// corresponding GC type is guaranteed to be `Some`.
|
||||
self.downcast::<$gtype>().unwrap_unchecked().trace(cc)
|
||||
},)*
|
||||
$($itag => (),)*
|
||||
@@ -123,9 +141,13 @@ macro_rules! define_value_types {
|
||||
impl fmt::Debug for Value<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.tag() {
|
||||
// SAFETY: `tag()` is `None`, meaning the `RawBox` holds a
|
||||
// float, so `float()` is guaranteed to be `Some`.
|
||||
None => write!(f, "Float({:?})", unsafe {
|
||||
self.raw.float().unwrap_unchecked()
|
||||
}),
|
||||
// SAFETY: `tag()` matched `$itag`, so `downcast` to the
|
||||
// corresponding inline type is guaranteed to be `Some`.
|
||||
$(Some($itag) => write!(f, "{}({:?})", $iname, unsafe {
|
||||
self.downcast::<$itype>().unwrap_unchecked()
|
||||
}),)*
|
||||
@@ -171,6 +193,8 @@ impl Storable for f64 {
|
||||
}
|
||||
#[inline(always)]
|
||||
unsafe fn from_raw_box(raw: RawBox) -> Self {
|
||||
// SAFETY: the caller guarantees `raw` represents a valid `f64`, so
|
||||
// `float()` is guaranteed to be `Some`.
|
||||
unsafe { raw.float().copied().unwrap_unchecked() }
|
||||
}
|
||||
}
|
||||
@@ -180,6 +204,12 @@ impl ValueVariant for f64 {
|
||||
const TYPE: NixType = NixType::Float;
|
||||
}
|
||||
|
||||
impl<'gc, T: Storable + 'gc> From<T> for Value<'gc> {
|
||||
fn from(value: T) -> Self {
|
||||
Value::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// # Nix runtime value representation
|
||||
///
|
||||
/// NaN-boxed value fitting in 8 bytes.
|
||||
@@ -206,7 +236,10 @@ impl<'gc> Value<'gc> {
|
||||
|
||||
impl<'gc> Value<'gc> {
|
||||
#[inline]
|
||||
#[allow(private_bounds)]
|
||||
#[expect(
|
||||
private_bounds,
|
||||
reason = "Storable is a sealed implementation detail of the value system"
|
||||
)]
|
||||
pub fn new<T: Storable>(val: T) -> Self {
|
||||
Self {
|
||||
raw: val.to_raw_box(),
|
||||
@@ -230,7 +263,10 @@ impl<'gc> Value<'gc> {
|
||||
|
||||
#[inline]
|
||||
pub fn downcast<T: ValueVariant>(self) -> Option<T::Ty<'gc>> {
|
||||
self.is::<T>().then(|| unsafe { T::Ty::from_raw_box(self.raw) })
|
||||
self.is::<T>()
|
||||
// SAFETY: `is::<T>()` returned true, so `self.raw` represents a
|
||||
// valid `T::Ty`.
|
||||
.then(|| unsafe { T::Ty::from_raw_box(self.raw) })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -259,6 +295,10 @@ impl<'gc> Value<'gc> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[expect(
|
||||
clippy::unreachable,
|
||||
reason = "the preceding `if`/`else if` chain exhausts every registered value tag"
|
||||
)]
|
||||
pub fn ty(self) -> NixType {
|
||||
if self.is::<f64>() {
|
||||
NixType::Float
|
||||
@@ -316,7 +356,10 @@ impl<'gc> From<StaticValue> for Value<'gc> {
|
||||
|
||||
impl StaticValue {
|
||||
#[inline]
|
||||
#[allow(private_bounds)]
|
||||
#[expect(
|
||||
private_bounds,
|
||||
reason = "Storable is a sealed implementation detail of the value system"
|
||||
)]
|
||||
pub fn new<T: Storable + 'static>(val: T) -> Self {
|
||||
Self(Value::new(val))
|
||||
}
|
||||
@@ -429,6 +472,10 @@ impl<'gc> AttrSet<'gc> {
|
||||
Self { entries }
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::indexing_slicing,
|
||||
reason = "index comes from a successful `binary_search_by_key`, so it is a valid entry index"
|
||||
)]
|
||||
pub fn lookup(&self, key: StringId) -> Option<Value<'gc>> {
|
||||
self.entries
|
||||
.binary_search_by_key(&key, |(k, _)| *k)
|
||||
@@ -440,6 +487,10 @@ impl<'gc> AttrSet<'gc> {
|
||||
self.entries.binary_search_by_key(&key, |(k, _)| *k).is_ok()
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::indexing_slicing,
|
||||
reason = "`i`/`j` stay strictly below their lengths inside the loop, and the trailing slices use those in-bounds cursors as start indices"
|
||||
)]
|
||||
pub fn merge(&self, other: &Self, mc: &Mutation<'gc>) -> Gc<'gc, Self> {
|
||||
use std::cmp::Ordering::*;
|
||||
|
||||
@@ -500,6 +551,9 @@ impl<'gc> List<'gc> {
|
||||
impl<'gc> Unlock for List<'gc> {
|
||||
type Unlocked = RefCell<SmallVec<[Value<'gc>; 4]>>;
|
||||
unsafe fn unlock_unchecked(&self) -> &Self::Unlocked {
|
||||
// SAFETY: the caller upholds the `Unlock` contract (mutation happens
|
||||
// behind a write barrier); we forward that obligation to the inner
|
||||
// `RefLock`'s `unlock_unchecked`.
|
||||
unsafe { self.inner.unlock_unchecked() }
|
||||
}
|
||||
}
|
||||
@@ -539,6 +593,10 @@ impl<'gc> Env<'gc> {
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::indexing_slicing,
|
||||
reason = "`locals` was just created with `1 + n_locals` elements, so index 0 is always valid"
|
||||
)]
|
||||
pub fn with_arg(arg: Value<'gc>, n_locals: u32, prev: Gc<'gc, RefLock<Env<'gc>>>) -> Self {
|
||||
let mut locals = smallvec::smallvec![Value::default(); 1 + n_locals as usize];
|
||||
locals[0] = arg;
|
||||
@@ -576,6 +634,18 @@ pub struct PrimOp {
|
||||
pub dispatch_ip: u32,
|
||||
}
|
||||
|
||||
impl From<BuiltinId> for PrimOp {
|
||||
fn from(id: BuiltinId) -> Self {
|
||||
let BuiltinInfo { arity, .. } = id.info();
|
||||
let dispatch_ip = Continuation::entry_for_builtin(id).ip();
|
||||
Self {
|
||||
id,
|
||||
arity,
|
||||
dispatch_ip,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RawStore for PrimOp {
|
||||
fn to_val(self, value: &mut RawValue) {
|
||||
let bytes = self.dispatch_ip.to_le_bytes();
|
||||
|
||||
Reference in New Issue
Block a user