treewide: enforce strict clippy check

This commit is contained in:
2026-08-22 18:41:23 +08:00
parent 5f494983b8
commit cb38031f85
51 changed files with 1237 additions and 568 deletions
+3
View File
@@ -16,3 +16,6 @@ fix-runtime = { path = "../fix-runtime" }
[features]
tailcall = []
[lints]
workspace = true
+6 -1
View File
@@ -22,6 +22,7 @@ pub(crate) type OpFn<'gc, C> = extern "rust-preserve-none" fn(
pub(crate) struct DispatchTable<'gc, C: VmRuntimeCtx>(pub(crate) [OpFn<'gc, C>; 256]);
#[expect(clippy::panic, reason = "illegal opcode should panic")]
extern "rust-preserve-none" fn op_illegal<'gc, C: VmRuntimeCtx>(
_vm: &mut Vm<'gc>,
_mc: &Mutation<'gc>,
@@ -200,6 +201,7 @@ tail_fn!(op_load_scoped_binding, (ctx, reader, mc));
macro_rules! table {
($($variant:ident => $fn:ident),* $(,)?) => {
impl<'gc, C: VmRuntimeCtx> DispatchTable<'gc, C> {
#[expect(clippy::indexing_slicing, reason = "Op is repr(u8)")]
pub(crate) const NEW: Self = {
let mut arr: [OpFn<'gc, C>; 256] = [op_illegal; 256];
$( arr[fix_bytecode::Op::$variant as usize] = $fn; )*
@@ -209,7 +211,6 @@ macro_rules! table {
// Exhaustiveness check: fails to compile if `fix_bytecode::Op` gains,
// loses, or renames a variant that isn't wired up above.
#[allow(dead_code)]
const _: fn(fix_bytecode::Op) = |op| match op {
$( fix_bytecode::Op::$variant => (), )*
};
@@ -291,6 +292,10 @@ table! {
Illegal => op_illegal,
}
#[expect(
clippy::indexing_slicing,
reason = "assume well-formed bytecode; Op is repr(u8)"
)]
pub(crate) fn run_tailcall<'gc, C: VmRuntimeCtx>(
vm: &mut Vm<'gc>,
mc: &Mutation<'gc>,
+4
View File
@@ -9,6 +9,10 @@ use crate::{
};
#[inline(always)]
#[expect(
clippy::indexing_slicing,
reason = "app.args is a fixed [Value; 3]; indices are bounded by primop arity (<= 3) validated at PrimOpApp construction"
)]
pub(crate) fn call<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
+21
View File
@@ -117,6 +117,10 @@ pub(crate) fn op_select_dynamic<'gc, M: Machine<'gc>>(
/// Only recognises Select opcodes and jumps; encountering any other
/// opcode means we've reached the end of the select sequence and
/// should report the missing-attribute error.
#[expect(
clippy::cast_sign_loss,
reason = "jump target = pc + offset is a non-negative bytecode address by codegen invariant"
)]
fn select_skip<'gc, M: Machine<'gc>>(
m: &mut M,
key: StringId,
@@ -126,6 +130,7 @@ fn select_skip<'gc, M: Machine<'gc>>(
use fix_bytecode::Op::*;
loop {
match reader.read_op() {
// Skip rest of the attrpath
SelectStatic => {
reader.set_pc(reader.pc() + 4 + 4);
}
@@ -136,10 +141,14 @@ fn select_skip<'gc, M: Machine<'gc>>(
reader.set_pc(reader.pc() + 4);
break Step::Continue(());
}
// Default (`a.b or c`)
JumpIfSelectFailed => {
let offset = reader.read_i32();
reader.set_pc(((reader.pc() as isize) + (offset as isize)) as usize);
}
// Report error
_ => {
let name = ctx.resolve_string(key);
return m.finish_err(Error::eval_error(format!("attribute '{name}' missing")));
@@ -150,6 +159,14 @@ fn select_skip<'gc, M: Machine<'gc>>(
/// Skip the rest of a **HasAttr** attrpath after an intermediate
/// lookup failed. Only recognises HasAttr opcodes and jumps.
#[expect(
clippy::cast_sign_loss,
reason = "jump target = pc + offset is a non-negative bytecode address by codegen invariant"
)]
#[expect(
clippy::unreachable,
reason = "has_attr_skip only runs over a codegen-produced HasAttr attrpath sequence; any other opcode is a codegen bug"
)]
fn has_attr_skip(reader: &mut BytecodeReader<'_>) -> Step {
use fix_bytecode::Op::*;
loop {
@@ -245,6 +262,10 @@ pub(crate) fn op_jump_if_select_failed<'gc, M: Machine<'gc>>(
}
#[inline(always)]
#[expect(
clippy::cast_sign_loss,
reason = "jump target = pc + offset is a non-negative bytecode address by codegen invariant"
)]
pub(crate) fn op_jump_if_select_succeeded<'gc, M: Machine<'gc>>(
_m: &mut M,
reader: &mut BytecodeReader<'_>,
+12
View File
@@ -5,6 +5,10 @@ use gc_arena::Mutation;
use crate::{BytecodeReader, Step, VmRuntimeCtx};
#[inline(always)]
#[expect(
clippy::cast_sign_loss,
reason = "jump target = pc + offset is a non-negative bytecode address by codegen invariant"
)]
pub(crate) fn op_jump_if_false<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
@@ -19,6 +23,10 @@ pub(crate) fn op_jump_if_false<'gc, M: Machine<'gc>>(
}
#[inline(always)]
#[expect(
clippy::cast_sign_loss,
reason = "jump target = pc + offset is a non-negative bytecode address by codegen invariant"
)]
pub(crate) fn op_jump_if_true<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
@@ -33,6 +41,10 @@ pub(crate) fn op_jump_if_true<'gc, M: Machine<'gc>>(
}
#[inline(always)]
#[expect(
clippy::cast_sign_loss,
reason = "jump target = pc + offset is a non-negative bytecode address by codegen invariant"
)]
pub(crate) fn op_jump<'gc, M: Machine<'gc>>(_m: &mut M, reader: &mut BytecodeReader<'_>) -> Step {
let offset = reader.read_i32();
reader.set_pc(((reader.pc() as isize) + (offset as isize)) as usize);
+7 -3
View File
@@ -2,7 +2,7 @@ use std::path::PathBuf;
use fix_bytecode::Continuation;
use fix_error::Error;
use fix_lang::{BUILTINS, BuiltinId, StringId};
use fix_lang::{BuiltinId, StringId};
use fix_runtime::{
AttrSet, Machine, MachineExt, NixString, Path, StrictValue, StringContext, canon_path_str,
};
@@ -11,11 +11,15 @@ use crate::{BytecodeReader, PrimOp, Step, Value, VmRuntimeCtx, VmRuntimeCtxExt};
#[inline(always)]
pub(crate) fn op_load_builtins<'gc, M: Machine<'gc>>(m: &mut M) -> Step {
m.push(m.builtins());
m.push(m.builtins().into());
Step::Continue(())
}
#[inline(always)]
#[expect(
clippy::panic,
reason = "codegen only emits LoadBuiltin with valid BuiltinId bytes; an unknown id is a codegen/bytecode-corruption bug"
)]
pub(crate) fn op_load_builtin<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
@@ -24,7 +28,7 @@ pub(crate) fn op_load_builtin<'gc, M: Machine<'gc>>(
.map_err(|err| panic!("unknown builtin id: {}", err.number));
m.push(Value::new(PrimOp {
id,
arity: BUILTINS[id as usize].1,
arity: id.info().arity,
dispatch_ip: Continuation::entry_for_builtin(id).ip(),
}));
Step::Continue(())
+12
View File
@@ -3,6 +3,10 @@ use fix_runtime::Machine;
use crate::{BytecodeReader, Mutation, Step, Value};
#[inline(always)]
#[expect(
clippy::indexing_slicing,
reason = "local slot index is produced by codegen and bounded by the frame's AllocLocals count"
)]
pub(crate) fn op_load_local<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
@@ -13,6 +17,10 @@ pub(crate) fn op_load_local<'gc, M: Machine<'gc>>(
}
#[inline(always)]
#[expect(
clippy::indexing_slicing,
reason = "local slot index is produced by codegen and bounded by the target frame's AllocLocals count"
)]
pub(crate) fn op_load_outer<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
@@ -30,6 +38,10 @@ pub(crate) fn op_load_outer<'gc, M: Machine<'gc>>(
}
#[inline(always)]
#[expect(
clippy::indexing_slicing,
reason = "local slot index is produced by codegen and bounded by the frame's AllocLocals count"
)]
pub(crate) fn op_store_local<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
+9 -2
View File
@@ -6,14 +6,21 @@ use smallvec::SmallVec;
use crate::{Break, BytecodeReader, CallFrame, Step, VmRuntimeCtx};
#[inline(always)]
#[expect(
clippy::indexing_slicing,
clippy::cast_sign_loss,
reason = "counter is a non-negative with-scope index in 0..n, staying within the namespaces vec of length n"
)]
pub(crate) fn op_lookup_with<'gc, M: Machine<'gc>>(
m: &mut M,
ctx: &mut impl VmRuntimeCtx,
reader: &mut BytecodeReader<'_>,
mc: &gc_arena::Mutation<'gc>,
) -> Step {
#[allow(clippy::unwrap_used)]
let counter = m.peek_forced(0).downcast::<i32>().unwrap();
let counter = m
.peek_forced(0)
.downcast::<i32>()
.expect("stack slot must be an integer");
let name = reader.read_string_id();
let n = reader.read_u8();
+21 -13
View File
@@ -1,5 +1,7 @@
#![warn(clippy::unwrap_used)]
#![cfg_attr(feature = "tailcall", expect(incomplete_features))]
#![cfg_attr(
feature = "tailcall",
expect(incomplete_features, reason = "for testing purpose only")
)]
#![cfg_attr(
feature = "tailcall",
feature(explicit_tail_calls, rust_preserve_none_cc)
@@ -9,7 +11,7 @@ use std::path::PathBuf;
use fix_bytecode::{Continuation, InstructionPtr};
use fix_error::{Error, Result, Source};
use fix_lang::{BUILTINS, BuiltinId, StringId};
use fix_lang::{BuiltinId, StringId};
use gc_arena::metrics::Pacing;
use gc_arena::{Arena, Collect, Gc, Mutation, RefLock, Rootable};
use hashbrown::HashMap;
@@ -29,7 +31,10 @@ pub struct Vm<'gc> {
stack: Vec<Value<'gc>>,
call_stack: Vec<CallFrame<'gc>>,
call_depth: usize,
#[allow(dead_code)]
#[expect(
dead_code,
reason = "error_context is reserved for tryEval catch-frame tracking, not yet wired up"
)]
#[collect(require_static)]
error_context: Vec<ErrorFrame>,
@@ -38,7 +43,7 @@ pub struct Vm<'gc> {
import_cache: HashMap<PathBuf, Value<'gc>>,
scope_slots: Vec<Value<'gc>>,
builtins: Value<'gc>,
builtins: Gc<'gc, AttrSet<'gc>>,
empty_list: Value<'gc>,
empty_attrs: Value<'gc>,
@@ -53,13 +58,12 @@ pub struct Vm<'gc> {
functor_sym: StringId,
}
fn init_builtins<'gc>(mc: &Mutation<'gc>, ctx: &mut impl VmRuntimeCtx) -> Value<'gc> {
let mut entries = SmallVec::with_capacity(BUILTINS.len());
fn init_builtins<'gc>(mc: &Mutation<'gc>, ctx: &mut impl VmRuntimeCtx) -> Gc<'gc, AttrSet<'gc>> {
let mut entries = SmallVec::with_capacity(BuiltinId::TOTAL);
for (idx, &(name, arity)) in BUILTINS.iter().enumerate() {
let id = BuiltinId::try_from(idx as u8).expect("infallible");
let name = name.strip_prefix("__").unwrap_or(name);
let name = ctx.intern_string(name);
for id in BuiltinId::ALL {
let arity = id.info().arity;
let name = ctx.intern_string(id.info().name);
let dispatch_ip = Continuation::entry_for_builtin(id).ip();
entries.push((
name,
@@ -101,7 +105,7 @@ fn init_builtins<'gc>(mc: &Mutation<'gc>, ctx: &mut impl VmRuntimeCtx) -> Value<
let builtins_value = Value::new(builtins_set);
*self_ref_thunk.borrow_mut(mc) =
ThunkState::Evaluated(builtins_value.restrict().expect("builtins is not a thunk"));
builtins_value
builtins_set
}
impl<'gc> Vm<'gc> {
@@ -298,7 +302,7 @@ impl<'gc> Machine<'gc> for Vm<'gc> {
}
#[inline(always)]
fn builtins(&self) -> Value<'gc> {
fn builtins(&self) -> Gc<'gc, AttrSet<'gc>> {
self.builtins
}
@@ -456,6 +460,10 @@ impl<'gc> Vm<'gc> {
#[inline(always)]
#[cfg(not(feature = "tailcall"))]
#[expect(
clippy::unreachable,
reason = "Op::Illegal is a sentinel never emitted by codegen; reaching it is a codegen bug"
)]
fn execute_batch(
&mut self,
bytecode: &[u8],
+89 -37
View File
@@ -200,16 +200,25 @@ pub fn append_context<'gc, M: Machine<'gc>>(
Step::Continue(())
}
#[expect(
clippy::indexing_slicing,
clippy::cast_sign_loss,
reason = "idx is a non-negative loop counter guarded by `idx as usize >= attrs.entries.len()`, so it indexes attrs.entries in bounds"
)]
pub fn append_context_loop<'gc, M: Machine<'gc>>(
m: &mut M,
ctx: &mut impl VmRuntimeCtx,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
#[allow(clippy::unwrap_used)]
let idx = m.peek(1).downcast::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let attrs = m.peek_forced(2).downcast::<AttrSet>().unwrap();
let idx = m
.peek(1)
.downcast::<i32>()
.expect("stack slot must be an integer");
let attrs = m
.peek_forced(2)
.downcast::<AttrSet>()
.expect("stack slot must be an attrset");
if idx as usize >= attrs.entries.len() {
return append_context_finalize(m, ctx, reader, mc);
@@ -227,6 +236,11 @@ pub fn append_context_loop<'gc, M: Machine<'gc>>(
Step::Continue(())
}
#[expect(
clippy::indexing_slicing,
clippy::cast_sign_loss,
reason = "idx is the same non-negative outer-loop counter, in range for outer.entries validated by append_context_loop"
)]
pub fn append_context_entry_forced<'gc, M: Machine<'gc>>(
m: &mut M,
ctx: &mut impl VmRuntimeCtx,
@@ -242,10 +256,14 @@ pub fn append_context_entry_forced<'gc, M: Machine<'gc>>(
return m.finish_type_err(NixType::AttrSet, entry_val.ty());
};
#[allow(clippy::unwrap_used)]
let idx = m.peek(2).downcast::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let outer = m.peek_forced(3).downcast::<AttrSet>().unwrap();
let idx = m
.peek(2)
.downcast::<i32>()
.expect("stack slot must be an integer");
let outer = m
.peek_forced(3)
.downcast::<AttrSet>()
.expect("stack slot must be an attrset");
let path_key = outer.entries[idx as usize].0;
let path_str_owned: Box<str> = ctx.resolve_string(path_key).into();
if !path_str_owned.starts_with("/nix/store/") {
@@ -262,8 +280,10 @@ pub fn append_context_entry_forced<'gc, M: Machine<'gc>>(
let all_outputs_id = ctx.intern_string("allOutputs");
let outputs_id = ctx.intern_string("outputs");
#[allow(clippy::unwrap_used)]
let acc_gc = m.peek(1).downcast::<NixString>().unwrap();
let acc_gc = m
.peek(1)
.downcast::<NixString>()
.expect("stack slot must be a string");
let mut new_acc: StringContext = acc_gc.context().iter().cloned().collect();
if let Some(v) = entry_attrs.lookup(path_id)
@@ -302,9 +322,11 @@ pub fn append_context_entry_forced<'gc, M: Machine<'gc>>(
return Step::Continue(());
}
let _ = m.pop();
#[allow(clippy::unwrap_used)]
let idx_back = m.peek(1).downcast::<i32>().unwrap();
m.drop_n(1);
let idx_back = m
.peek(1)
.downcast::<i32>()
.expect("stack slot must be an integer");
m.replace(1, Value::new(idx_back + 1));
reader.set_pc(Continuation::PAppendContextLoop.ip() as usize);
Step::Continue(())
@@ -323,9 +345,11 @@ pub fn append_context_outputs_forced<'gc, M: Machine<'gc>>(
};
if list.inner.borrow().is_empty() {
// Stack: [strVal, attrs, idx, acc, list] -> drop list, bump idx.
let _ = m.pop();
#[allow(clippy::unwrap_used)]
let idx_back = m.peek(1).downcast::<i32>().unwrap();
m.drop_n(1);
let idx_back = m
.peek(1)
.downcast::<i32>()
.expect("stack slot must be an integer");
m.replace(1, Value::new(idx_back + 1));
reader.set_pc(Continuation::PAppendContextLoop.ip() as usize);
return Step::Continue(());
@@ -336,24 +360,34 @@ pub fn append_context_outputs_forced<'gc, M: Machine<'gc>>(
Step::Continue(())
}
#[expect(
clippy::indexing_slicing,
clippy::cast_sign_loss,
reason = "oidx is a non-negative loop counter guarded by `oidx as usize >= len`, so it indexes the list in bounds"
)]
pub fn append_context_output_element_loop<'gc, M: Machine<'gc>>(
m: &mut M,
_ctx: &mut impl VmRuntimeCtx,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
#[allow(clippy::unwrap_used)]
let oidx = m.peek(0).downcast::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let list = m.peek_forced(1).downcast::<VmList>().unwrap();
let oidx = m
.peek(0)
.downcast::<i32>()
.expect("stack slot must be an integer");
let list = m
.peek_forced(1)
.downcast::<VmList>()
.expect("stack slot must be a list");
let len = list.inner.borrow().len();
if oidx as usize >= len {
// Stack: [strVal, attrs, idx, acc, list, oidx] -> drop oidx & list,
// bump idx in place.
let _ = m.pop();
let _ = m.pop();
#[allow(clippy::unwrap_used)]
let idx_back = m.peek(1).downcast::<i32>().unwrap();
m.drop_n(2);
let idx_back = m
.peek(1)
.downcast::<i32>()
.expect("stack slot must be an integer");
m.replace(1, Value::new(idx_back + 1));
reader.set_pc(Continuation::PAppendContextLoop.ip() as usize);
return Step::Continue(());
@@ -371,6 +405,11 @@ pub fn append_context_output_element_loop<'gc, M: Machine<'gc>>(
Step::Continue(())
}
#[expect(
clippy::indexing_slicing,
clippy::cast_sign_loss,
reason = "idx is the non-negative outer-loop counter, in range for outer.entries validated by append_context_loop"
)]
pub fn append_context_output_element_forced<'gc, M: Machine<'gc>>(
m: &mut M,
ctx: &mut impl VmRuntimeCtx,
@@ -384,10 +423,14 @@ pub fn append_context_output_element_forced<'gc, M: Machine<'gc>>(
};
let output_name: Box<str> = output_name.into();
#[allow(clippy::unwrap_used)]
let idx = m.peek(4).downcast::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let outer = m.peek_forced(5).downcast::<AttrSet>().unwrap();
let idx = m
.peek(4)
.downcast::<i32>()
.expect("stack slot must be an integer");
let outer = m
.peek_forced(5)
.downcast::<AttrSet>()
.expect("stack slot must be an attrset");
let path_key = outer.entries[idx as usize].0;
let path_str: Box<str> = ctx.resolve_string(path_key).into();
if !path_str.ends_with(".drv") {
@@ -396,8 +439,10 @@ pub fn append_context_output_element_forced<'gc, M: Machine<'gc>>(
)));
}
#[allow(clippy::unwrap_used)]
let acc_gc = m.peek(3).downcast::<NixString>().unwrap();
let acc_gc = m
.peek(3)
.downcast::<NixString>()
.expect("stack slot must be a string");
let mut new_acc: StringContext = acc_gc.context().iter().cloned().collect();
new_acc.insert(StringContextElem::Built {
drv_path: path_str,
@@ -408,14 +453,20 @@ pub fn append_context_output_element_forced<'gc, M: Machine<'gc>>(
// Stack: [strVal, attrs, idx, acc, list, oidx, outElem] -> drop outElem,
// bump oidx in place.
let _ = m.pop();
#[allow(clippy::unwrap_used)]
let oidx = m.peek(0).downcast::<i32>().unwrap();
m.drop_n(1);
let oidx = m
.peek(0)
.downcast::<i32>()
.expect("stack slot must be an integer");
m.replace(0, Value::new(oidx + 1));
reader.set_pc(Continuation::PAppendContextOutputElementLoop.ip() as usize);
Step::Continue(())
}
#[expect(
clippy::panic,
reason = "strVal was forced to WHNF at appendContext entry, so restrict() can never observe a thunk here"
)]
fn append_context_finalize<'gc, M: Machine<'gc>>(
m: &mut M,
ctx: &mut impl VmRuntimeCtx,
@@ -423,10 +474,11 @@ fn append_context_finalize<'gc, M: Machine<'gc>>(
mc: &Mutation<'gc>,
) -> Step {
// Stack: [strVal, attrs, idx, acc]
#[allow(clippy::unwrap_used)]
let acc_gc = m.pop().downcast::<NixString>().unwrap();
let _ = m.pop(); // idx
let _ = m.pop(); // attrs
let acc_gc = m
.pop()
.downcast::<NixString>()
.expect("stack slot must be a string");
m.drop_n(2);
let str_val_raw = m.pop();
// The strVal was already forced at entry; restrict() is infallible here.
+55 -29
View File
@@ -15,7 +15,7 @@ pub fn seq<'gc, M: Machine<'gc>>(
// stack: [e1, e2] - force e1, return e2
m.force_slot(1, reader, mc)?;
let e2 = m.pop();
let _ = m.pop();
m.drop_n(1);
m.return_from_primop(e2, reader)
}
@@ -64,7 +64,7 @@ pub fn deep_seq_force_top<'gc, M: Machine<'gc>>(
if children.is_empty() {
let e2 = m.pop();
let _ = m.pop();
m.drop_n(1);
return m.return_from_primop(e2, reader);
}
@@ -73,7 +73,7 @@ pub fn deep_seq_force_top<'gc, M: Machine<'gc>>(
let worklist = List::new(mc, children);
let e2 = m.pop();
let _ = m.pop();
m.drop_n(1);
m.push(e2);
m.push(Value::new(seen));
m.push(Value::new(worklist));
@@ -88,20 +88,25 @@ pub fn deep_seq_push<'gc, M: Machine<'gc>>(
mc: &Mutation<'gc>,
) -> Step {
// stack: [e2, seen, worklist, counter]
#[allow(clippy::unwrap_used)]
let counter = m.peek(0).downcast::<i32>().unwrap();
let counter = m
.peek(0)
.downcast::<i32>()
.expect("stack slot must be an integer");
if counter == 0 {
let _ = m.pop(); // counter
let _ = m.pop(); // worklist
let _ = m.pop(); // seen
m.drop_n(3);
let val = m.pop();
return m.return_from_primop(val, reader);
}
#[allow(clippy::unwrap_used)]
let worklist = m.peek_forced(1).downcast::<List>().unwrap();
#[allow(clippy::unwrap_used)]
let item = worklist.unlock(mc).borrow_mut().pop().unwrap();
let worklist = m
.peek_forced(1)
.downcast::<List>()
.expect("stack slot must be a list");
let item = worklist
.unlock(mc)
.borrow_mut()
.pop()
.expect("worklist is non-empty while counter > 0");
m.replace(0, Value::new(counter - 1));
m.push(item);
@@ -118,18 +123,24 @@ pub fn deep_seq_loop<'gc, M: Machine<'gc>>(
) -> Step {
// stack after pop: [e2, seen, worklist, counter]
let item = m.pop();
#[allow(clippy::unwrap_used)]
let counter = m.peek(0).downcast::<i32>().unwrap();
let counter = m
.peek(0)
.downcast::<i32>()
.expect("stack slot must be an integer");
let mut added: usize = 0;
if let Some(attrs) = item.downcast::<AttrSet>() {
let attrs = &attrs.entries;
#[allow(clippy::unwrap_used)]
let seen = m.peek_forced(2).downcast::<List>().unwrap();
let seen = m
.peek_forced(2)
.downcast::<List>()
.expect("stack slot must be a list");
if !is_value_in_seen(seen, item) {
add_value_to_seen(seen, mc, item);
#[allow(clippy::unwrap_used)]
let worklist = m.peek_forced(1).downcast::<List>().unwrap();
let worklist = m
.peek_forced(1)
.downcast::<List>()
.expect("stack slot must be a list");
{
let mut wl = worklist.unlock(mc).borrow_mut();
for &(_, v) in attrs.iter() {
@@ -139,12 +150,16 @@ pub fn deep_seq_loop<'gc, M: Machine<'gc>>(
}
}
} else if let Some(list) = item.downcast::<List>() {
#[allow(clippy::unwrap_used)]
let seen = m.peek_forced(2).downcast::<List>().unwrap();
let seen = m
.peek_forced(2)
.downcast::<List>()
.expect("stack slot must be a list");
if !is_value_in_seen(seen, item) {
add_value_to_seen(seen, mc, item);
#[allow(clippy::unwrap_used)]
let worklist = m.peek_forced(1).downcast::<List>().unwrap();
let worklist = m
.peek_forced(1)
.downcast::<List>()
.expect("stack slot must be a list");
{
let inner = list.inner.borrow();
let mut wl = worklist.unlock(mc).borrow_mut();
@@ -191,20 +206,27 @@ pub fn force_result_shallow<'gc, M: Machine<'gc>>(
Step::Continue(())
}
#[expect(
clippy::cast_sign_loss,
reason = "idx is a non-negative loop counter (0..=len); used only with .get(), so the cast is always a valid index or safely out of range"
)]
pub fn force_result_shallow_push<'gc, M: Machine<'gc>>(
m: &mut M,
ctx: &mut impl VmRuntimeCtx,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
#[allow(clippy::unwrap_used)]
let idx = m.peek(1).downcast::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let len = m.peek(0).downcast::<i32>().unwrap();
let idx = m
.peek(1)
.downcast::<i32>()
.expect("stack slot must be an integer");
let len = m
.peek(0)
.downcast::<i32>()
.expect("stack slot must be an integer");
if idx == len {
let _ = m.pop(); // len
let _ = m.pop(); // idx
m.drop_n(2);
let val = m.pop();
return m.finish_ok(ctx.convert_value(val));
}
@@ -237,7 +259,7 @@ pub fn force_result_shallow_loop<'gc, M: Machine<'gc>>(
reader: &mut BytecodeReader<'_>,
_mc: &Mutation<'gc>,
) -> Step {
let _ = m.pop(); // forced child
m.drop_n(1);
reader.set_pc(Continuation::ForceResultShallowPush.ip() as usize);
Step::Continue(())
}
@@ -308,6 +330,10 @@ pub fn call_functor_2<'gc, M: Machine<'gc>>(
m.call(reader, mc, orig_arg, saved.pc)
}
#[expect(
clippy::unreachable,
reason = "CallPattern is only dispatched for closures whose pattern is Some, established when the Call opcode routed here"
)]
pub fn call_pattern<'gc, M: Machine<'gc>>(
m: &mut M,
ctx: &mut impl VmRuntimeCtx,
+4
View File
@@ -27,6 +27,10 @@ pub fn to_string<'gc, M: Machine<'gc>>(
)))
}
#[expect(
clippy::unreachable,
reason = "val was forced to WHNF by force_and_retry, so its type is never Thunk here"
)]
pub fn type_of<'gc, M: Machine<'gc>>(
m: &mut M,
ctx: &mut impl VmRuntimeCtx,
+1 -2
View File
@@ -88,8 +88,7 @@ pub fn eq_force<'gc, M: Machine<'gc>>(
}
fn finalize<'gc, M: Machine<'gc>>(m: &mut M, reader: &mut BytecodeReader<'_>) -> Step {
let _ = m.pop();
let _ = m.pop();
m.drop_n(2);
let result = m
.pop()
.downcast::<bool>()
+8 -2
View File
@@ -55,6 +55,10 @@ pub fn import<'gc, M: Machine<'gc>>(
Step::Break(Break::LoadFile)
}
#[expect(
clippy::unreachable,
reason = "import always pushes the PImportFinalize call frame before this runs, so pop_call_frame is always Some"
)]
pub fn import_finalize<'gc, M: Machine<'gc>>(
m: &mut M,
ctx: &mut impl VmRuntimeCtx,
@@ -62,8 +66,10 @@ pub fn import_finalize<'gc, M: Machine<'gc>>(
) -> Step {
// stack: [path_sid, return_value]
let val = m.pop();
#[allow(clippy::unwrap_used)]
let path_sid = m.pop().downcast::<StringId>().unwrap();
let path_sid = m
.pop()
.downcast::<StringId>()
.expect("stack slot must be a string");
// The cache key is keyed by the absolute path string we interned in
// `import`. Resolve it back to the host PathBuf.
let path_str = ctx.resolve_string(path_sid).to_owned();
+117 -48
View File
@@ -24,6 +24,11 @@ pub fn filter_force_list<'gc, M: Machine<'gc>>(
Step::Continue(())
}
#[expect(
clippy::indexing_slicing,
clippy::cast_sign_loss,
reason = "idx is a non-negative loop counter in 0..list.len(), so it indexes the list in bounds"
)]
pub fn filter_call_pred<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
@@ -31,36 +36,51 @@ pub fn filter_call_pred<'gc, M: Machine<'gc>>(
) -> Step {
m.force_slot(3, reader, mc)?;
let pred = m.peek_forced(3);
#[allow(clippy::unwrap_used)]
let idx = m.peek(1).downcast::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let elem = m.peek_forced(2).downcast::<List>().unwrap().inner.borrow()[idx as usize];
let idx = m
.peek(1)
.downcast::<i32>()
.expect("stack slot must be an integer");
let elem = m
.peek_forced(2)
.downcast::<List>()
.expect("stack slot must be a list")
.inner
.borrow()[idx as usize];
m.push(pred.relax());
m.call(reader, mc, elem, Continuation::PFilterCheck.ip() as usize)
}
#[expect(
clippy::indexing_slicing,
clippy::cast_sign_loss,
reason = "idx is a non-negative loop counter in 0..list.len(), so it indexes the list in bounds"
)]
pub fn filter_check<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
let ret = m.force_and_retry::<bool>(reader, mc)?;
#[allow(clippy::unwrap_used)]
let idx = m.peek(1).downcast::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let list = m.peek_forced(2).downcast::<List>().unwrap();
let idx = m
.peek(1)
.downcast::<i32>()
.expect("stack slot must be an integer");
let list = m
.peek_forced(2)
.downcast::<List>()
.expect("stack slot must be a list");
let list = list.inner.borrow();
#[allow(clippy::unwrap_used)]
let acc = m.peek_forced(0).downcast::<List>().unwrap();
let acc = m
.peek_forced(0)
.downcast::<List>()
.expect("stack slot must be a list");
if ret {
let mut acc = acc.unlock(mc).borrow_mut();
acc.push(list[idx as usize]);
}
if idx as usize == list.len() - 1 {
let acc = m.pop();
let _ = m.pop(); // idx
let _ = m.pop(); // list
let _ = m.pop(); // pred
m.drop_n(3);
return m.return_from_primop(acc, reader);
}
m.replace(1, Value::new(idx + 1));
@@ -87,7 +107,7 @@ pub fn foldl_strict_entry<'gc, M: Machine<'gc>>(
return m.finish_type_err(NixType::List, list_val.ty());
};
if list.inner.borrow().is_empty() {
let _ = m.pop(); // list
m.drop_n(1);
reader.set_pc(Continuation::PFoldlStrictEmpty.ip() as usize);
return Step::Continue(());
}
@@ -106,7 +126,7 @@ pub fn foldl_strict_empty<'gc, M: Machine<'gc>>(
mc: &Mutation<'gc>,
) -> Step {
let nul = m.force_and_retry::<StrictValue>(reader, mc)?;
let _ = m.pop(); // op
m.drop_n(1);
m.return_from_primop(nul.relax(), reader)
}
@@ -127,15 +147,24 @@ pub fn foldl_strict_call1<'gc, M: Machine<'gc>>(
)
}
#[expect(
clippy::indexing_slicing,
clippy::cast_sign_loss,
reason = "idx is a non-negative loop counter in 0..list.len(), so it indexes the list in bounds"
)]
pub fn foldl_strict_call2<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
#[allow(clippy::unwrap_used)]
let idx = m.peek(2).downcast::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let list = m.peek_forced(3).downcast::<List>().unwrap();
let idx = m
.peek(2)
.downcast::<i32>()
.expect("stack slot must be an integer");
let list = m
.peek_forced(3)
.downcast::<List>()
.expect("stack slot must be a list");
let elem = list.inner.borrow()[idx as usize];
m.call(
reader,
@@ -145,6 +174,10 @@ pub fn foldl_strict_call2<'gc, M: Machine<'gc>>(
)
}
#[expect(
clippy::cast_sign_loss,
reason = "idx is a non-negative loop counter in 0..list.len()"
)]
pub fn foldl_strict_update<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
@@ -152,16 +185,18 @@ pub fn foldl_strict_update<'gc, M: Machine<'gc>>(
) -> Step {
let result = m.pop();
m.replace(0, result);
#[allow(clippy::unwrap_used)]
let idx = m.peek(1).downcast::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let list = m.peek_forced(2).downcast::<List>().unwrap();
let idx = m
.peek(1)
.downcast::<i32>()
.expect("stack slot must be an integer");
let list = m
.peek_forced(2)
.downcast::<List>()
.expect("stack slot must be a list");
let len = list.inner.borrow().len();
if (idx as usize) + 1 == len {
let acc = m.pop();
let _ = m.pop(); // idx
let _ = m.pop(); // list
let _ = m.pop(); // op
m.drop_n(3);
return m.return_from_primop(acc, reader);
}
m.replace(1, Value::new(idx + 1));
@@ -192,35 +227,52 @@ pub fn all_entry<'gc, M: Machine<'gc>>(
Step::Continue(())
}
#[expect(
clippy::indexing_slicing,
clippy::cast_sign_loss,
reason = "idx is a non-negative loop counter in 0..list.len(), so it indexes the list in bounds"
)]
pub fn all_call_pred<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
let pred = m.peek_forced(2);
#[allow(clippy::unwrap_used)]
let idx = m.peek(0).downcast::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let elem = m.peek_forced(1).downcast::<List>().unwrap().inner.borrow()[idx as usize];
let idx = m
.peek(0)
.downcast::<i32>()
.expect("stack slot must be an integer");
let elem = m
.peek_forced(1)
.downcast::<List>()
.expect("stack slot must be a list")
.inner
.borrow()[idx as usize];
m.push(pred.relax());
m.call(reader, mc, elem, Continuation::PAllCheck.ip() as usize)
}
#[expect(
clippy::cast_sign_loss,
reason = "idx is a non-negative loop counter in 0..list.len()"
)]
pub fn all_check<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
let ret = m.force_and_retry::<bool>(reader, mc)?;
#[allow(clippy::unwrap_used)]
let idx = m.peek(0).downcast::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let list = m.peek_forced(1).downcast::<List>().unwrap();
let idx = m
.peek(0)
.downcast::<i32>()
.expect("stack slot must be an integer");
let list = m
.peek_forced(1)
.downcast::<List>()
.expect("stack slot must be a list");
let list = list.inner.borrow();
if idx as usize == list.len() - 1 || !ret {
let _ = m.pop(); // idx
let _ = m.pop(); // list
let _ = m.pop(); // pred
m.drop_n(3);
return m.return_from_primop(Value::new(ret), reader);
}
m.replace(0, Value::new(idx + 1));
@@ -251,35 +303,52 @@ pub fn any_entry<'gc, M: Machine<'gc>>(
Step::Continue(())
}
#[expect(
clippy::indexing_slicing,
clippy::cast_sign_loss,
reason = "idx is a non-negative loop counter in 0..list.len(), so it indexes the list in bounds"
)]
pub fn any_call_pred<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
let pred = m.peek_forced(2);
#[allow(clippy::unwrap_used)]
let idx = m.peek(0).downcast::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let elem = m.peek_forced(1).downcast::<List>().unwrap().inner.borrow()[idx as usize];
let idx = m
.peek(0)
.downcast::<i32>()
.expect("stack slot must be an integer");
let elem = m
.peek_forced(1)
.downcast::<List>()
.expect("stack slot must be a list")
.inner
.borrow()[idx as usize];
m.push(pred.relax());
m.call(reader, mc, elem, Continuation::PAnyCheck.ip() as usize)
}
#[expect(
clippy::cast_sign_loss,
reason = "idx is a non-negative loop counter in 0..list.len()"
)]
pub fn any_check<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
let ret = m.force_and_retry::<bool>(reader, mc)?;
#[allow(clippy::unwrap_used)]
let idx = m.peek(0).downcast::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let list = m.peek_forced(1).downcast::<List>().unwrap();
let idx = m
.peek(0)
.downcast::<i32>()
.expect("stack slot must be an integer");
let list = m
.peek_forced(1)
.downcast::<List>()
.expect("stack slot must be a list");
let list = list.inner.borrow();
if idx as usize == list.len() - 1 || ret {
let _ = m.pop(); // idx
let _ = m.pop(); // list
let _ = m.pop(); // pred
m.drop_n(3);
return m.return_from_primop(Value::new(ret), reader);
}
m.replace(0, Value::new(idx + 1));
-1
View File
@@ -18,7 +18,6 @@ pub use io::*;
pub use list::*;
pub use path::*;
#[allow(clippy::too_many_lines)]
pub fn dispatch_cont<'gc, M: Machine<'gc>>(
m: &mut M,
ctx: &mut impl VmRuntimeCtx,