better force eval ergonomic

This commit is contained in:
2026-04-21 22:05:49 +08:00
parent b31c2a4906
commit e469d1b819
7 changed files with 303 additions and 123 deletions
+4 -24
View File
@@ -3,7 +3,7 @@ use gc_arena::Gc;
use smallvec::SmallVec;
use crate::{
AttrKeyData, AttrSet, BytecodeReader, List, NixString, OperandData, Step, Value,
AttrKeyData, AttrSet, BytecodeReader, List, NixString, OperandData, Step, StrictValue, Value,
};
impl<'gc> crate::Vm<'gc> {
@@ -57,18 +57,11 @@ impl<'gc> crate::Vm<'gc> {
let _span_id = reader.read_u32();
let key = reader.read_string_id();
self.try_force(0, reader, mc)?;
let attrs = self.peek(0).restrict().expect("forced");
let Some(attrset) = attrs.as_gc::<AttrSet>() else {
return self.finish_err(Error::eval_error(
"value is not a set while a set was expected",
));
};
let attrset = self.try_force::<Gc<AttrSet>>(reader, mc)?;
match attrset.lookup(key) {
Some(v) => {
self.replace(0, v);
self.push(v);
}
None => loop {
let byte = reader.bytecode()[reader.pc()];
@@ -78,7 +71,6 @@ impl<'gc> crate::Vm<'gc> {
reader.set_pc(reader.pc() + 1 + 4);
} else if byte == fix_codegen::Op::JumpIfSelectSucceeded as u8 {
reader.set_pc(reader.pc() + 1 + 4);
let _ = self.pop();
break;
} else {
let name = ctx.resolve_string(key);
@@ -99,12 +91,8 @@ impl<'gc> crate::Vm<'gc> {
) -> Step {
let _span_id = reader.read_u32();
self.try_force(0, reader, mc)?;
self.try_force(1, reader, mc)?;
let (attrset, key_val) = self.try_force::<(Gc<AttrSet>, StrictValue)>(reader, mc)?;
let key_val = self.stack[self.stack.len() - 1]
.restrict()
.expect("dynamic key must be forced");
let key_sid = if let Some(sid) = key_val.as_inline::<crate::StringId>() {
sid
} else if let Some(ns) = key_val.as_gc::<NixString>() {
@@ -113,16 +101,8 @@ impl<'gc> crate::Vm<'gc> {
return self.finish_err(Error::eval_error("dynamic select key must be a string"));
};
let attrset_val = self.stack[self.stack.len() - 2].restrict().expect("forced");
let Some(attrset) = attrset_val.as_gc::<AttrSet>() else {
return self.finish_err(Error::eval_error(
"value is not a set while a set was expected",
));
};
match attrset.lookup(key_sid) {
Some(v) => {
self.stack.truncate(self.stack.len() - 2);
self.push(v);
}
None => {