From 02e6344a77b9d2fa76b8a1d69ffebcf367c0f0cb Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Tue, 5 Nov 2024 03:35:00 +0100 Subject: [PATCH] rune: Simplify the empty sentinel value (#881) --- crates/rune/src/cli/run.rs | 30 +- crates/rune/src/cli/tests.rs | 6 +- crates/rune/src/compile/ir.rs | 4 +- crates/rune/src/compile/ir/eval.rs | 53 +-- crates/rune/src/compile/ir/interpreter.rs | 65 +-- crates/rune/src/compile/unit_builder.rs | 50 +- crates/rune/src/compile/v1/assemble.rs | 42 +- crates/rune/src/macros/format_args.rs | 4 +- crates/rune/src/modules/any.rs | 4 +- crates/rune/src/modules/future.rs | 18 +- crates/rune/src/modules/iter.rs | 14 +- crates/rune/src/modules/string.rs | 26 +- crates/rune/src/runtime/access.rs | 9 - crates/rune/src/runtime/const_value.rs | 10 +- crates/rune/src/runtime/dynamic.rs | 14 +- crates/rune/src/runtime/format.rs | 26 +- crates/rune/src/runtime/inst.rs | 13 +- crates/rune/src/runtime/mod.rs | 2 +- crates/rune/src/runtime/protocol_caller.rs | 12 +- crates/rune/src/runtime/range.rs | 10 +- crates/rune/src/runtime/range_from.rs | 10 +- crates/rune/src/runtime/range_inclusive.rs | 10 +- crates/rune/src/runtime/runtime_context.rs | 15 +- crates/rune/src/runtime/type_info.rs | 8 + crates/rune/src/runtime/unit.rs | 61 ++- crates/rune/src/runtime/value.rs | 261 ++++------ crates/rune/src/runtime/value/inline.rs | 12 + crates/rune/src/runtime/value/macros.rs | 6 - crates/rune/src/runtime/value/serde.rs | 11 +- crates/rune/src/runtime/vec.rs | 2 +- crates/rune/src/runtime/vm.rs | 523 ++++++++++----------- crates/rune/src/runtime/vm_error.rs | 16 +- crates/rune/src/tests.rs | 1 + crates/rune/src/tests/bug_344.rs | 14 +- crates/rune/src/tests/unit_constants.rs | 6 +- 35 files changed, 684 insertions(+), 684 deletions(-) diff --git a/crates/rune/src/cli/run.rs b/crates/rune/src/cli/run.rs index 64af98917..ee1f1573f 100644 --- a/crates/rune/src/cli/run.rs +++ b/crates/rune/src/cli/run.rs @@ -181,6 +181,8 @@ pub(super) async fn run( let mut functions = unit.iter_functions().peekable(); let mut strings = unit.iter_static_strings().peekable(); + let mut bytes = unit.iter_static_bytes().peekable(); + let mut drop_sets = unit.iter_static_drop_sets().peekable(); let mut keys = unit.iter_static_object_keys().peekable(); let mut constants = unit.iter_constants().peekable(); @@ -199,16 +201,16 @@ pub(super) async fn run( if strings.peek().is_some() { writeln!(io.stdout, "# strings")?; - for string in strings { - writeln!(io.stdout, "{} = {:?}", string.hash(), string)?; + for (i, string) in strings.enumerate() { + writeln!(io.stdout, "{i} = {string:?}")?; } } - if args.dump_constants && constants.peek().is_some() { - writeln!(io.stdout, "# constants")?; + if bytes.peek().is_some() { + writeln!(io.stdout, "# bytes")?; - for constant in constants { - writeln!(io.stdout, "{} = {:?}", constant.0, constant.1)?; + for (i, bytes) in bytes.enumerate() { + writeln!(io.stdout, "{i} = {bytes:?}")?; } } @@ -219,6 +221,22 @@ pub(super) async fn run( writeln!(io.stdout, "{} = {:?}", hash, keys)?; } } + + if drop_sets.peek().is_some() { + writeln!(io.stdout, "# drop sets")?; + + for (i, set) in drop_sets.enumerate() { + writeln!(io.stdout, "{i} = {set:?}")?; + } + } + + if args.dump_constants && constants.peek().is_some() { + writeln!(io.stdout, "# constants")?; + + for (hash, constant) in constants { + writeln!(io.stdout, "{hash} = {constant:?}")?; + } + } } let runtime = Arc::new(context.runtime()?); diff --git a/crates/rune/src/cli/tests.rs b/crates/rune/src/cli/tests.rs index 179552ac1..5beba8d63 100644 --- a/crates/rune/src/cli/tests.rs +++ b/crates/rune/src/cli/tests.rs @@ -18,7 +18,7 @@ use crate::cli::{ use crate::compile::FileSourceLoader; use crate::doc::{TestKind, TestParams}; use crate::modules::capture_io::CaptureIo; -use crate::runtime::{ReprRef, Value, Vm, VmError, VmResult}; +use crate::runtime::{Repr, Value, Vm, VmError, VmResult}; use crate::{Diagnostics, Hash, Item, ItemBuf, Source, Sources, TypeHash, Unit}; mod cli { @@ -534,8 +534,8 @@ impl TestCase { capture_io.drain_into(&mut self.output)?; self.outcome = match result { - VmResult::Ok(v) => match v.as_ref()? { - ReprRef::Any(value) => match value.type_hash() { + VmResult::Ok(v) => match v.as_ref() { + Repr::Any(value) => match value.type_hash() { Result::::HASH => { let result = value.borrow_ref::>()?; diff --git a/crates/rune/src/compile/ir.rs b/crates/rune/src/compile/ir.rs index 5335b355d..02f191f65 100644 --- a/crates/rune/src/compile/ir.rs +++ b/crates/rune/src/compile/ir.rs @@ -534,8 +534,8 @@ impl IrAssignOp { where S: Copy + Spanned, { - if let Some(Inline::Signed(target)) = target.as_inline_mut().with_span(spanned)? { - if let Some(Inline::Signed(operand)) = operand.as_inline().with_span(spanned)? { + if let Some(Inline::Signed(target)) = target.as_inline_mut() { + if let Some(Inline::Signed(operand)) = operand.as_inline() { return self.assign_int(spanned, target, *operand); } } diff --git a/crates/rune/src/compile/ir/eval.rs b/crates/rune/src/compile/ir/eval.rs index 159eb6a53..5ec4aca7d 100644 --- a/crates/rune/src/compile/ir/eval.rs +++ b/crates/rune/src/compile/ir/eval.rs @@ -7,7 +7,7 @@ use crate::ast::{Span, Spanned}; use crate::compile::ir::{self}; use crate::compile::{self, WithSpan}; use crate::query::Used; -use crate::runtime::{Inline, Object, OwnedTuple, ReprRef, Value}; +use crate::runtime::{Inline, Object, OwnedTuple, Repr, Value}; use crate::TypeHash; /// The outcome of a constant evaluation. @@ -72,11 +72,11 @@ fn eval_ir_binary( let a = eval_ir(&ir.lhs, interp, used)?; let b = eval_ir(&ir.rhs, interp, used)?; - let a = a.as_ref().with_span(ir)?; - let b = b.as_ref().with_span(ir)?; + let a = a.as_ref(); + let b = b.as_ref(); match (a, b) { - (ReprRef::Inline(a), ReprRef::Inline(b)) => { + (Repr::Inline(a), Repr::Inline(b)) => { let out = 'out: { match (a, b) { (Inline::Signed(a), Inline::Signed(b)) => match ir.op { @@ -140,7 +140,7 @@ fn eval_ir_binary( return Ok(Value::from(out)); } - (ReprRef::Any(a), ReprRef::Any(b)) => { + (Repr::Any(a), Repr::Any(b)) => { let value = 'out: { if let (String::HASH, String::HASH) = (a.type_hash(), b.type_hash()) { let a = a.borrow_ref::().with_span(span)?; @@ -353,34 +353,23 @@ fn eval_ir_template( } ir::IrTemplateComponent::Ir(ir) => { let const_value = eval_ir(ir, interp, used)?; - let value = const_value.as_ref().with_span(ir)?; - match value { - ReprRef::Inline(value) => match value { - Inline::Signed(integer) => { - write!(buf, "{integer}")?; - } - Inline::Float(float) => { - let mut buffer = ryu::Buffer::new(); - buf.try_push_str(buffer.format(*float))?; - } - Inline::Bool(b) => { - write!(buf, "{b}")?; - } - _ => { - return Err(EvalOutcome::not_const(ir)); - } - }, - ReprRef::Any(value) => match value.type_hash() { - String::HASH => { - let s = value.borrow_ref::().with_span(ir)?; - buf.try_push_str(&s)?; - } - _ => { - return Err(EvalOutcome::not_const(ir)); - } - }, - ReprRef::Dynamic(..) => { + match const_value.as_ref() { + Repr::Inline(Inline::Signed(integer)) => { + write!(buf, "{integer}")?; + } + Repr::Inline(Inline::Float(float)) => { + let mut buffer = ryu::Buffer::new(); + buf.try_push_str(buffer.format(*float))?; + } + Repr::Inline(Inline::Bool(b)) => { + write!(buf, "{b}")?; + } + Repr::Any(value) if value.type_hash() == String::HASH => { + let s = value.borrow_ref::().with_span(ir)?; + buf.try_push_str(&s)?; + } + _ => { return Err(EvalOutcome::not_const(ir)); } } diff --git a/crates/rune/src/compile/ir/interpreter.rs b/crates/rune/src/compile/ir/interpreter.rs index cbaf30b87..a173503de 100644 --- a/crates/rune/src/compile/ir/interpreter.rs +++ b/crates/rune/src/compile/ir/interpreter.rs @@ -7,7 +7,7 @@ use crate::compile::meta; use crate::compile::{self, IrErrorKind, ItemId, ModId, WithSpan}; use crate::hir; use crate::query::{Query, Used}; -use crate::runtime::{self, ConstValue, Object, OwnedTuple, ReprRef, Value}; +use crate::runtime::{self, ConstValue, Object, OwnedTuple, Repr, Value}; use crate::TypeHash; /// The interpreter that executed [Ir][crate::ir::Ir]. @@ -200,45 +200,30 @@ impl ir::Scopes { } ir::IrTargetKind::Index(target, index) => { let value = self.get_target(target)?; - let target = value.as_ref().with_span(ir_target)?; - match target { - ReprRef::Inline(value) => { - return Err(compile::Error::expected_type::( - ir_target, - value.type_info(), - )); + match value.type_hash() { + runtime::Vec::HASH => { + let vec = value.borrow_ref::().with_span(ir_target)?; + + if let Some(value) = vec.get(*index) { + return Ok(value.clone()); + } } - ReprRef::Dynamic(value) => { + runtime::OwnedTuple::HASH => { + let tuple = value + .borrow_ref::() + .with_span(ir_target)?; + + if let Some(value) = tuple.get(*index) { + return Ok(value.clone()); + } + } + _ => { return Err(compile::Error::expected_type::( ir_target, value.type_info(), )); } - ReprRef::Any(value) => match value.type_hash() { - runtime::Vec::HASH => { - let vec = value.borrow_ref::().with_span(ir_target)?; - - if let Some(value) = vec.get(*index) { - return Ok(value.clone()); - } - } - runtime::OwnedTuple::HASH => { - let tuple = value - .borrow_ref::() - .with_span(ir_target)?; - - if let Some(value) = tuple.get(*index) { - return Ok(value.clone()); - } - } - _ => { - return Err(compile::Error::expected_type::( - ir_target, - value.type_info(), - )); - } - }, } Err(compile::Error::new( @@ -270,20 +255,20 @@ impl ir::Scopes { ir::IrTargetKind::Index(target, index) => { let target = self.get_target(target)?; - match target.as_ref().with_span(ir_target)? { - ReprRef::Inline(value) => { + match target.as_ref() { + Repr::Inline(value) => { return Err(compile::Error::expected_type::( ir_target, value.type_info(), )); } - ReprRef::Dynamic(value) => { + Repr::Dynamic(value) => { return Err(compile::Error::expected_type::( ir_target, value.type_info(), )); } - ReprRef::Any(any) => match any.type_hash() { + Repr::Any(any) => match any.type_hash() { runtime::Vec::HASH => { let mut vec = any.borrow_mut::().with_span(ir_target)?; @@ -345,12 +330,12 @@ impl ir::Scopes { ir::IrTargetKind::Index(target, index) => { let current = self.get_target(target)?; - match current.as_ref().with_span(ir_target)? { - ReprRef::Dynamic(value) => Err(compile::Error::expected_type::( + match current.as_ref() { + Repr::Dynamic(value) => Err(compile::Error::expected_type::( ir_target, value.type_info(), )), - ReprRef::Any(value) => match value.type_hash() { + Repr::Any(value) => match value.type_hash() { runtime::Vec::HASH => { let mut vec = value.borrow_mut::().with_span(ir_target)?; diff --git a/crates/rune/src/compile/unit_builder.rs b/crates/rune/src/compile/unit_builder.rs index db24c78c4..fd29aded9 100644 --- a/crates/rune/src/compile/unit_builder.rs +++ b/crates/rune/src/compile/unit_builder.rs @@ -18,8 +18,8 @@ use crate::query::QueryInner; use crate::runtime::debug::{DebugArgs, DebugSignature}; use crate::runtime::unit::UnitEncoder; use crate::runtime::{ - Call, ConstValue, DebugInfo, DebugInst, Inst, Label, Protocol, Rtti, RttiKind, StaticString, - Unit, UnitFn, + Call, ConstValue, DebugInfo, DebugInst, Inst, InstAddress, Label, Protocol, Rtti, RttiKind, + StaticString, Unit, UnitFn, }; use crate::{Context, Diagnostics, Hash, Item, SourceId}; @@ -72,6 +72,10 @@ pub(crate) struct UnitBuilder { static_object_keys: Vec>, /// Used to detect duplicates in the collection of static object keys. static_object_keys_rev: HashMap, + /// A static string. + drop_sets: Vec>, + /// Reverse lookup for drop sets. + drop_sets_rev: HashMap, usize>, /// Runtime type information for types. rtti: hash::Map>, /// The current label count. @@ -87,6 +91,14 @@ pub(crate) struct UnitBuilder { } impl UnitBuilder { + /// Construct a new drop set. + pub(crate) fn drop_set(&mut self) -> DropSet<'_> { + DropSet { + builder: self, + addresses: Vec::new(), + } + } + /// Insert an identifier for debug purposes. pub(crate) fn insert_debug_ident(&mut self, ident: &str) -> alloc::Result<()> { self.hash_to_ident @@ -150,6 +162,7 @@ impl UnitBuilder { self.static_strings, self.static_bytes, self.static_object_keys, + self.drop_sets, self.rtti, self.debug, self.constants, @@ -914,3 +927,36 @@ impl UnitBuilder { Ok(()) } } + +/// A set of addresses that should be dropped. +pub(crate) struct DropSet<'a> { + builder: &'a mut UnitBuilder, + addresses: Vec, +} + +impl DropSet<'_> { + /// Construct a new drop set. + pub(crate) fn push(&mut self, addr: InstAddress) -> alloc::Result<()> { + self.addresses.try_push(addr) + } + + pub(crate) fn finish(self) -> alloc::Result> { + if self.addresses.is_empty() { + return Ok(None); + } + + if let Some(set) = self.builder.drop_sets_rev.get(&self.addresses) { + return Ok(Some(*set)); + } + + let set = self.builder.drop_sets.len(); + + self.builder + .drop_sets_rev + .try_insert(self.addresses.try_clone()?, set)?; + self.builder + .drop_sets + .try_push(Arc::from(&self.addresses[..]))?; + Ok(Some(set)) + } +} diff --git a/crates/rune/src/compile/v1/assemble.rs b/crates/rune/src/compile/v1/assemble.rs index 733865f3e..7055ba4cc 100644 --- a/crates/rune/src/compile/v1/assemble.rs +++ b/crates/rune/src/compile/v1/assemble.rs @@ -75,8 +75,14 @@ impl<'a, 'hir, 'arena> Ctxt<'a, 'hir, 'arena> { .drain_dangling_into(&mut self.drop) .with_span(span)?; + let mut drop_set = self.q.unit.drop_set(); + for addr in self.drop.drain(..).rev() { - self.asm.push(Inst::Drop { addr }, span)?; + drop_set.push(addr)?; + } + + if let Some(set) = drop_set.finish()? { + self.asm.push(Inst::Drop { set }, span)?; } Ok(()) @@ -1101,6 +1107,12 @@ fn const_<'a, 'hir>( match *value.as_kind() { ConstValueKind::Inline(value) => match value { + Inline::Empty => { + return Err(compile::Error::msg( + span, + "Empty inline constant value is not supported", + )); + } Inline::Unit => { cx.asm.push(Inst::unit(out), span)?; } @@ -1732,9 +1744,15 @@ fn expr_break<'hir>( cx.asm.push(Inst::unit(out), span)?; } + let mut drop_set = cx.q.unit.drop_set(); + // Drop loop temporaries. for addr in cx.drop.drain(..) { - cx.asm.push(Inst::Drop { addr }, span)?; + drop_set.push(addr)?; + } + + if let Some(set) = drop_set.finish()? { + cx.asm.push(Inst::Drop { set }, span)?; } cx.asm.jump(&break_label, span)?; @@ -2211,15 +2229,15 @@ fn expr_for<'a, 'hir>( cx.asm.label(&end_label)?; + let mut drop_set = cx.q.unit.drop_set(); + drop_set.push(into_iter.addr())?; + // NB: Dropping has to happen before the break label. When breaking, // the break statement is responsible for ensuring that active // iterators are dropped. - cx.asm.push( - Inst::Drop { - addr: into_iter.addr(), - }, - span, - )?; + if let Some(set) = drop_set.finish()? { + cx.asm.push(Inst::Drop { set }, span)?; + } cx.asm.label(&break_label)?; @@ -2814,9 +2832,15 @@ fn expr_select_inner<'a, 'hir>( cx.asm.label(&end_label)?; + let mut drop_set = cx.q.unit.drop_set(); + // Drop futures we are currently using. for addr in &linear { - cx.asm.push(Inst::Drop { addr: addr.addr() }, span)?; + drop_set.push(addr.addr())?; + } + + if let Some(set) = drop_set.finish()? { + cx.asm.push(Inst::Drop { set }, span)?; } value_addr.free()?; diff --git a/crates/rune/src/macros/format_args.rs b/crates/rune/src/macros/format_args.rs index 95985bd1c..4d91cc9d7 100644 --- a/crates/rune/src/macros/format_args.rs +++ b/crates/rune/src/macros/format_args.rs @@ -572,7 +572,7 @@ fn expand_format_spec<'a>( let value = cx.eval(expr)?; - let number = match value.as_inline().with_span(expr)? { + let number = match value.as_inline() { Some(Inline::Signed(n)) => n.to_usize(), _ => None, }; @@ -589,7 +589,7 @@ fn expand_format_spec<'a>( to be a positive number in use as precision, \ but got `{}`", count, - value.type_info().with_span(span)? + value.type_info() ), )); }; diff --git a/crates/rune/src/modules/any.rs b/crates/rune/src/modules/any.rs index c86f2085b..284070e20 100644 --- a/crates/rune/src/modules/any.rs +++ b/crates/rune/src/modules/any.rs @@ -39,8 +39,8 @@ pub fn module() -> Result { /// ``` #[rune::function(free, path = Type::of_val)] #[inline] -fn type_of_val(value: Value) -> VmResult { - VmResult::Ok(Type::new(vm_try!(value.type_hash()))) +fn type_of_val(value: Value) -> Type { + Type::new(value.type_hash()) } /// Formatting a type. diff --git a/crates/rune/src/modules/future.rs b/crates/rune/src/modules/future.rs index 07914b23e..5bc206317 100644 --- a/crates/rune/src/modules/future.rs +++ b/crates/rune/src/modules/future.rs @@ -2,7 +2,7 @@ use crate as rune; use crate::alloc::Vec; -use crate::runtime::{self, Future, Inline, ReprRef, SelectFuture, Value, VmErrorKind, VmResult}; +use crate::runtime::{self, Future, Inline, Repr, SelectFuture, Value, VmErrorKind, VmResult}; use crate::{ContextError, Module, TypeHash}; /// Asynchronous computations. @@ -25,20 +25,20 @@ where let mut results = vm_try!(Vec::try_with_capacity(len)); for (index, value) in values.into_iter().enumerate() { - match vm_try!(value.as_ref()) { - ReprRef::Inline(value) => { + match value.as_ref() { + Repr::Inline(value) => { return VmResult::err([ VmErrorKind::expected::(value.type_info()), VmErrorKind::bad_argument(index), ]); } - ReprRef::Dynamic(value) => { + Repr::Dynamic(value) => { return VmResult::err([ VmErrorKind::expected::(value.type_info()), VmErrorKind::bad_argument(index), ]); } - ReprRef::Any(value) => match value.type_hash() { + Repr::Any(value) => match value.type_hash() { Future::HASH => { let future = vm_try!(Value::from(value.clone()).into_future()); futures.push(SelectFuture::new(index, future)); @@ -98,19 +98,19 @@ where /// ``` #[rune::function(keep)] async fn join(value: Value) -> VmResult { - match vm_try!(value.as_ref()) { - ReprRef::Inline(value) => match value { + match value.as_ref() { + Repr::Inline(value) => match value { Inline::Unit => VmResult::Ok(Value::unit()), value => VmResult::err([ VmErrorKind::bad_argument(0), VmErrorKind::expected::(value.type_info()), ]), }, - ReprRef::Dynamic(value) => VmResult::err([ + Repr::Dynamic(value) => VmResult::err([ VmErrorKind::bad_argument(0), VmErrorKind::expected::(value.type_info()), ]), - ReprRef::Any(value) => match value.type_hash() { + Repr::Any(value) => match value.type_hash() { runtime::Vec::HASH => { let vec = vm_try!(value.borrow_ref::()); let result = try_join_impl(vec.iter(), vec.len(), |vec| { diff --git a/crates/rune/src/modules/iter.rs b/crates/rune/src/modules/iter.rs index b673d5e06..0425c959a 100644 --- a/crates/rune/src/modules/iter.rs +++ b/crates/rune/src/modules/iter.rs @@ -8,8 +8,8 @@ use crate::modules::collections::VecDeque; use crate::modules::collections::{HashMap, HashSet}; use crate::runtime::range::RangeIter; use crate::runtime::{ - FromValue, Function, Inline, InstAddress, Object, Output, OwnedTuple, Protocol, ReprRef, - TypeHash, Value, Vec, VmErrorKind, VmResult, + FromValue, Function, Inline, InstAddress, Object, Output, OwnedTuple, Protocol, Repr, TypeHash, + Value, Vec, VmErrorKind, VmResult, }; use crate::shared::Caller; use crate::{Any, ContextError, Module, Params}; @@ -473,17 +473,17 @@ pub fn module() -> Result { let mut string = String::new(); while let Some(value) = vm_try!(next.call((iter.clone(),))) { - match vm_try!(value.as_ref()) { - ReprRef::Inline(Inline::Char(c)) => { + match value.as_ref() { + Repr::Inline(Inline::Char(c)) => { vm_try!(string.try_push(*c)); } - ReprRef::Inline(value) => { + Repr::Inline(value) => { return VmResult::expected::(value.type_info()); } - ReprRef::Dynamic(value) => { + Repr::Dynamic(value) => { return VmResult::expected::(value.type_info()); } - ReprRef::Any(value) => match value.type_hash() { + Repr::Any(value) => match value.type_hash() { String::HASH => { let s = vm_try!(value.borrow_ref::()); vm_try!(string.try_push_str(&s)); diff --git a/crates/rune/src/modules/string.rs b/crates/rune/src/modules/string.rs index 3cb9eadaa..fa727d35e 100644 --- a/crates/rune/src/modules/string.rs +++ b/crates/rune/src/modules/string.rs @@ -12,7 +12,7 @@ use crate::alloc::{String, Vec}; use crate::compile::Named; use crate::runtime::{ Bytes, Formatter, FromValue, Function, Hasher, Inline, MaybeTypeOf, Panic, Range, RangeFrom, - RangeFull, RangeInclusive, RangeTo, RangeToInclusive, Ref, ReprRef, ToValue, TypeOf, Value, + RangeFull, RangeInclusive, RangeTo, RangeToInclusive, Ref, Repr, ToValue, TypeOf, Value, VmErrorKind, VmResult, }; use crate::{Any, ContextError, Module, TypeHash}; @@ -888,19 +888,19 @@ fn shrink_to_fit(s: &mut String) -> VmResult<()> { /// [`split_whitespace`]: str::split_whitespace #[rune::function(instance, deprecated = "Use String::split instead")] fn split(this: Ref, value: Value) -> VmResult { - match vm_try!(value.as_ref()) { - ReprRef::Inline(Inline::Char(c)) => { + match value.as_ref() { + Repr::Inline(Inline::Char(c)) => { VmResult::Ok(vm_try!(rune::to_value(Split::new(this, *c)))) } - ReprRef::Inline(value) => VmResult::err([ + Repr::Inline(value) => VmResult::err([ VmErrorKind::expected::(value.type_info()), VmErrorKind::bad_argument(0), ]), - ReprRef::Dynamic(value) => VmResult::err([ + Repr::Dynamic(value) => VmResult::err([ VmErrorKind::expected::(value.type_info()), VmErrorKind::bad_argument(0), ]), - ReprRef::Any(value) => match value.type_hash() { + Repr::Any(value) => match value.type_hash() { String::HASH => { let s = vm_try!(value.borrow_ref::()); @@ -937,21 +937,21 @@ fn split(this: Ref, value: Value) -> VmResult { /// ``` #[rune::function(instance)] fn split_once(this: &str, value: Value) -> VmResult> { - let outcome = match vm_try!(value.as_ref()) { - ReprRef::Inline(Inline::Char(pat)) => this.split_once(*pat), - ReprRef::Inline(value) => { + let outcome = match value.as_ref() { + Repr::Inline(Inline::Char(pat)) => this.split_once(*pat), + Repr::Inline(value) => { return VmResult::err([ VmErrorKind::expected::(value.type_info()), VmErrorKind::bad_argument(0), ]); } - ReprRef::Dynamic(value) => { + Repr::Dynamic(value) => { return VmResult::err([ VmErrorKind::expected::(value.type_info()), VmErrorKind::bad_argument(0), ]); } - ReprRef::Any(value) => match value.type_hash() { + Repr::Any(value) => match value.type_hash() { String::HASH => { let s = vm_try!(value.borrow_ref::()); this.split_once(s.as_str()) @@ -1168,7 +1168,7 @@ fn chars(s: Ref) -> Chars { fn get(this: &str, key: Value) -> VmResult> { use crate::runtime::TypeOf; - let slice = match vm_try!(key.as_any()) { + let slice = match key.as_any() { Some(value) => match value.type_hash() { RangeFrom::HASH => { let range = vm_try!(value.borrow_ref::()); @@ -1211,7 +1211,7 @@ fn get(this: &str, key: Value) -> VmResult> { _ => { return VmResult::err(VmErrorKind::UnsupportedIndexGet { target: String::type_info(), - index: vm_try!(key.type_info()), + index: key.type_info(), }) } }; diff --git a/crates/rune/src/runtime/access.rs b/crates/rune/src/runtime/access.rs index 1e32a4be1..9f67363ee 100644 --- a/crates/rune/src/runtime/access.rs +++ b/crates/rune/src/runtime/access.rs @@ -27,13 +27,6 @@ pub struct AccessError { } impl AccessError { - #[inline] - pub(crate) const fn empty() -> Self { - Self { - kind: AccessErrorKind::Empty, - } - } - #[inline] pub(crate) const fn not_owned(type_info: TypeInfo) -> Self { Self { @@ -50,7 +43,6 @@ impl AccessError { impl fmt::Display for AccessError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match &self.kind { - AccessErrorKind::Empty => write!(f, "Empty value"), AccessErrorKind::NotAccessibleRef(s) => write!(f, "Cannot read, value is {s}"), AccessErrorKind::NotAccessibleMut(s) => write!(f, "Cannot write, value is {s}"), AccessErrorKind::NotAccessibleTake(s) => write!(f, "Cannot take, value is {s}"), @@ -73,7 +65,6 @@ impl From for AccessError { #[derive(Debug)] #[cfg_attr(test, derive(PartialEq))] pub(crate) enum AccessErrorKind { - Empty, NotAccessibleRef(Snapshot), NotAccessibleMut(Snapshot), NotAccessibleTake(Snapshot), diff --git a/crates/rune/src/runtime/const_value.rs b/crates/rune/src/runtime/const_value.rs index 0fec86315..2adc18b30 100644 --- a/crates/rune/src/runtime/const_value.rs +++ b/crates/rune/src/runtime/const_value.rs @@ -16,7 +16,7 @@ use crate::runtime; use crate::{Hash, TypeHash}; use super::{ - Bytes, FromValue, Inline, Object, OwnedTuple, ReprRef, ToValue, Tuple, Type, TypeInfo, Value, + Bytes, FromValue, Inline, Object, OwnedTuple, Repr, ToValue, Tuple, Type, TypeInfo, Value, VmErrorKind, }; @@ -234,14 +234,14 @@ impl ConstValue { /// Construct a constant value from a reference to a value.. pub(crate) fn from_value_ref(value: &Value) -> Result { - let inner = match value.as_ref()? { - ReprRef::Inline(value) => ConstValueKind::Inline(*value), - ReprRef::Dynamic(value) => { + let inner = match value.as_ref() { + Repr::Inline(value) => ConstValueKind::Inline(*value), + Repr::Dynamic(value) => { return Err(RuntimeError::from(VmErrorKind::ConstNotSupported { actual: value.type_info(), })); } - ReprRef::Any(value) => match value.type_hash() { + Repr::Any(value) => match value.type_hash() { Option::::HASH => { let option = value.borrow_ref::>()?; diff --git a/crates/rune/src/runtime/dynamic.rs b/crates/rune/src/runtime/dynamic.rs index 866057901..31c842643 100644 --- a/crates/rune/src/runtime/dynamic.rs +++ b/crates/rune/src/runtime/dynamic.rs @@ -4,7 +4,7 @@ use core::ops::Deref; use crate::alloc::{Box, Vec}; -use super::{FromValue, ReprOwned, Rtti, RttiKind, RuntimeError, Tuple, TypeInfo, Value}; +use super::{FromValue, Repr, Rtti, RttiKind, RuntimeError, Tuple, TypeInfo, Value}; use rust_alloc::sync::Arc; @@ -16,8 +16,8 @@ pub struct DynamicEmpty { impl FromValue for DynamicEmpty { #[inline] fn from_value(value: Value) -> Result { - match value.take_repr()? { - ReprOwned::Dynamic(value) if matches!(value.rtti().kind, RttiKind::Empty) => Ok(Self { + match value.take_repr() { + Repr::Dynamic(value) if matches!(value.rtti().kind, RttiKind::Empty) => Ok(Self { rtti: value.rtti().clone(), }), value => Err(RuntimeError::expected_empty(value.type_info())), @@ -44,8 +44,8 @@ pub struct DynamicTuple { impl FromValue for DynamicTuple { #[inline] fn from_value(value: Value) -> Result { - match value.take_repr()? { - ReprOwned::Dynamic(value) if matches!(value.rtti().kind, RttiKind::Tuple) => { + match value.take_repr() { + Repr::Dynamic(value) if matches!(value.rtti().kind, RttiKind::Tuple) => { let mut values = Vec::try_with_capacity(value.len())?; for value in value.borrow_ref()?.iter() { @@ -87,8 +87,8 @@ pub struct DynamicStruct { impl FromValue for DynamicStruct { #[inline] fn from_value(value: Value) -> Result { - match value.take_repr()? { - ReprOwned::Dynamic(value) if matches!(value.rtti().kind, RttiKind::Struct) => { + match value.take_repr() { + Repr::Dynamic(value) if matches!(value.rtti().kind, RttiKind::Struct) => { let mut values = Vec::try_with_capacity(value.len())?; for value in value.borrow_ref()?.iter() { diff --git a/crates/rune/src/runtime/format.rs b/crates/rune/src/runtime/format.rs index 7c9730c00..ec7778952 100644 --- a/crates/rune/src/runtime/format.rs +++ b/crates/rune/src/runtime/format.rs @@ -13,7 +13,7 @@ use crate as rune; use crate::alloc::clone::TryClone; use crate::alloc::fmt::TryWrite; use crate::alloc::String; -use crate::runtime::{Formatter, Inline, ProtocolCaller, ReprRef, Value, VmErrorKind, VmResult}; +use crate::runtime::{Formatter, Inline, ProtocolCaller, Repr, Value, VmErrorKind, VmResult}; use crate::{Any, TypeHash}; /// Error raised when trying to parse a type string and it fails. @@ -208,8 +208,8 @@ impl FormatSpec { caller: &mut dyn ProtocolCaller, ) -> VmResult<()> { 'fallback: { - match vm_try!(value.as_ref()) { - ReprRef::Inline(value) => match value { + match value.as_ref() { + Repr::Inline(value) => match value { Inline::Char(c) => { vm_try!(f.buf_mut().try_push(*c)); vm_try!(self.format_fill(f, self.align, self.fill, None)); @@ -228,10 +228,10 @@ impl FormatSpec { break 'fallback; } }, - ReprRef::Dynamic(..) => { + Repr::Dynamic(..) => { break 'fallback; } - ReprRef::Any(value) => match value.type_hash() { + Repr::Any(value) => match value.type_hash() { String::HASH => { let s = vm_try!(value.borrow_ref::()); vm_try!(f.buf_mut().try_push_str(&s)); @@ -256,8 +256,8 @@ impl FormatSpec { caller: &mut dyn ProtocolCaller, ) -> VmResult<()> { 'fallback: { - match vm_try!(value.as_ref()) { - ReprRef::Inline(value) => match value { + match value.as_ref() { + Repr::Inline(value) => match value { Inline::Signed(n) => { let (n, align, fill, sign) = self.int_traits(*n); vm_try!(self.format_number(f.buf_mut(), n)); @@ -272,10 +272,10 @@ impl FormatSpec { break 'fallback; } }, - ReprRef::Dynamic(..) => { + Repr::Dynamic(..) => { break 'fallback; } - ReprRef::Any(value) => match value.type_hash() { + Repr::Any(value) => match value.type_hash() { String::HASH => { let s = vm_try!(value.borrow_ref::()); vm_try!(vm_write!(f, "{s:?}")); @@ -293,7 +293,7 @@ impl FormatSpec { } fn format_upper_hex(&self, value: &Value, f: &mut Formatter) -> VmResult<()> { - match vm_try!(value.as_inline()) { + match value.as_inline() { Some(Inline::Signed(n)) => { let (n, align, fill, sign) = self.int_traits(*n); vm_try!(vm_write!(f.buf_mut(), "{:X}", n)); @@ -308,7 +308,7 @@ impl FormatSpec { } fn format_lower_hex(&self, value: &Value, f: &mut Formatter) -> VmResult<()> { - match vm_try!(value.as_inline()) { + match value.as_inline() { Some(Inline::Signed(n)) => { let (n, align, fill, sign) = self.int_traits(*n); vm_try!(vm_write!(f.buf_mut(), "{:x}", n)); @@ -323,7 +323,7 @@ impl FormatSpec { } fn format_binary(&self, value: &Value, f: &mut Formatter) -> VmResult<()> { - match vm_try!(value.as_inline()) { + match value.as_inline() { Some(Inline::Signed(n)) => { let (n, align, fill, sign) = self.int_traits(*n); vm_try!(vm_write!(f.buf_mut(), "{:b}", n)); @@ -338,7 +338,7 @@ impl FormatSpec { } fn format_pointer(&self, value: &Value, f: &mut Formatter) -> VmResult<()> { - match vm_try!(value.as_inline()) { + match value.as_inline() { Some(Inline::Signed(n)) => { let (n, align, fill, sign) = self.int_traits(*n); vm_try!(vm_write!(f.buf_mut(), "{:p}", n as *const ())); diff --git a/crates/rune/src/runtime/inst.rs b/crates/rune/src/runtime/inst.rs index 6a75ec6b9..736dd74e2 100644 --- a/crates/rune/src/runtime/inst.rs +++ b/crates/rune/src/runtime/inst.rs @@ -414,18 +414,11 @@ pub enum Inst { /// Where the value is being moved to. out: Output, }, - /// Drop the value in the given frame offset, cleaning out it's slot in - /// memory. - /// - /// # Operation - /// - /// ```text - /// => *noop* - /// ``` + /// Drop the given value set. #[musli(packed)] Drop { - /// Address of the value being dropped. - addr: InstAddress, + /// An indicator of the set of addresses to drop. + set: usize, }, /// Swap two values on the stack using their offsets relative to the current /// stack frame. diff --git a/crates/rune/src/runtime/mod.rs b/crates/rune/src/runtime/mod.rs index c98a00bf0..2835d5431 100644 --- a/crates/rune/src/runtime/mod.rs +++ b/crates/rune/src/runtime/mod.rs @@ -165,7 +165,7 @@ pub use self::value::{ Accessor, EmptyStruct, Inline, RawValueGuard, Rtti, Struct, TupleStruct, TypeValue, Value, ValueMutGuard, ValueRefGuard, }; -pub(crate) use self::value::{Dynamic, DynamicTakeError, ReprMut, ReprOwned, ReprRef, RttiKind}; +pub(crate) use self::value::{Dynamic, DynamicTakeError, Repr, RttiKind}; pub mod slice; diff --git a/crates/rune/src/runtime/protocol_caller.rs b/crates/rune/src/runtime/protocol_caller.rs index 94ba5c146..fa2360db2 100644 --- a/crates/rune/src/runtime/protocol_caller.rs +++ b/crates/rune/src/runtime/protocol_caller.rs @@ -18,7 +18,7 @@ pub(crate) trait ProtocolCaller: 'static { CallResultOnly::Unsupported(value) => { VmResult::err(VmErrorKind::MissingProtocolFunction { protocol, - instance: vm_try!(value.type_info()), + instance: value.type_info(), }) } } @@ -59,26 +59,26 @@ impl ProtocolCaller for EnvProtocolCaller { crate::runtime::env::shared(|context, unit| { let count = args.count() + 1; - let hash = Hash::associated_function(vm_try!(target.type_hash()), protocol.hash); + let hash = Hash::associated_function(target.type_hash(), protocol.hash); if let Some(UnitFn::Offset { offset, args: expected, call, .. - }) = unit.function(hash) + }) = unit.function(&hash) { - vm_try!(check_args(count, expected)); + vm_try!(check_args(count, *expected)); let mut stack = vm_try!(Stack::with_capacity(count)); vm_try!(stack.push(target)); vm_try!(args.push_to_stack(&mut stack)); let mut vm = Vm::with_stack(context.clone(), unit.clone(), stack); - vm.set_ip(offset); + vm.set_ip(*offset); return VmResult::Ok(CallResultOnly::Ok(vm_try!(call.call_with_vm(vm)))); } - if let Some(handler) = context.function(hash) { + if let Some(handler) = context.function(&hash) { let mut stack = vm_try!(Stack::with_capacity(count)); let addr = stack.addr(); vm_try!(stack.push(target)); diff --git a/crates/rune/src/runtime/range.rs b/crates/rune/src/runtime/range.rs index cf5acecd4..1ae3a7f67 100644 --- a/crates/rune/src/runtime/range.rs +++ b/crates/rune/src/runtime/range.rs @@ -5,7 +5,7 @@ use core::ops; use crate as rune; use crate::alloc::clone::TryClone; use crate::runtime::{ - EnvProtocolCaller, FromValue, Inline, ProtocolCaller, ReprRef, RuntimeError, ToValue, Value, + EnvProtocolCaller, FromValue, Inline, ProtocolCaller, Repr, RuntimeError, ToValue, Value, VmErrorKind, VmResult, }; use crate::Any; @@ -94,16 +94,16 @@ impl Range { /// ``` #[rune::function(keep)] pub fn iter(&self) -> VmResult { - let value = match (&vm_try!(self.start.as_ref()), vm_try!(self.end.as_ref())) { - (ReprRef::Inline(Inline::Unsigned(start)), ReprRef::Inline(end)) => { + let value = match (self.start.as_ref(), self.end.as_ref()) { + (Repr::Inline(Inline::Unsigned(start)), Repr::Inline(end)) => { let end = vm_try!(end.as_integer::()); vm_try!(rune::to_value(RangeIter::new(*start..end))) } - (ReprRef::Inline(Inline::Signed(start)), ReprRef::Inline(end)) => { + (Repr::Inline(Inline::Signed(start)), Repr::Inline(end)) => { let end = vm_try!(end.as_integer::()); vm_try!(rune::to_value(RangeIter::new(*start..end))) } - (ReprRef::Inline(Inline::Char(start)), ReprRef::Inline(Inline::Char(end))) => { + (Repr::Inline(Inline::Char(start)), Repr::Inline(Inline::Char(end))) => { vm_try!(rune::to_value(RangeIter::new(*start..*end))) } (start, end) => { diff --git a/crates/rune/src/runtime/range_from.rs b/crates/rune/src/runtime/range_from.rs index ab33ebb77..8c9a0e013 100644 --- a/crates/rune/src/runtime/range_from.rs +++ b/crates/rune/src/runtime/range_from.rs @@ -5,7 +5,7 @@ use core::ops; use crate as rune; use crate::alloc::clone::TryClone; use crate::runtime::{ - EnvProtocolCaller, FromValue, Inline, ProtocolCaller, ReprRef, RuntimeError, ToValue, Value, + EnvProtocolCaller, FromValue, Inline, ProtocolCaller, Repr, RuntimeError, ToValue, Value, VmErrorKind, VmResult, }; use crate::Any; @@ -88,14 +88,14 @@ impl RangeFrom { /// ``` #[rune::function(keep)] pub fn iter(&self) -> VmResult { - let value = match vm_try!(self.start.as_ref()) { - ReprRef::Inline(Inline::Unsigned(start)) => { + let value = match self.start.as_ref() { + Repr::Inline(Inline::Unsigned(start)) => { vm_try!(crate::to_value(RangeFromIter::new(*start..))) } - ReprRef::Inline(Inline::Signed(start)) => { + Repr::Inline(Inline::Signed(start)) => { vm_try!(crate::to_value(RangeFromIter::new(*start..))) } - ReprRef::Inline(Inline::Char(start)) => { + Repr::Inline(Inline::Char(start)) => { vm_try!(crate::to_value(RangeFromIter::new(*start..))) } start => { diff --git a/crates/rune/src/runtime/range_inclusive.rs b/crates/rune/src/runtime/range_inclusive.rs index 6b3c32763..31d5f4bab 100644 --- a/crates/rune/src/runtime/range_inclusive.rs +++ b/crates/rune/src/runtime/range_inclusive.rs @@ -5,7 +5,7 @@ use core::ops; use crate as rune; use crate::alloc::clone::TryClone; use crate::runtime::{ - EnvProtocolCaller, FromValue, Inline, ProtocolCaller, ReprRef, RuntimeError, ToValue, Value, + EnvProtocolCaller, FromValue, Inline, ProtocolCaller, Repr, RuntimeError, ToValue, Value, VmErrorKind, VmResult, }; use crate::Any; @@ -95,16 +95,16 @@ impl RangeInclusive { /// ``` #[rune::function(keep)] pub fn iter(&self) -> VmResult { - let value = match (vm_try!(self.start.as_ref()), vm_try!(self.end.as_ref())) { - (ReprRef::Inline(Inline::Unsigned(start)), ReprRef::Inline(end)) => { + let value = match (self.start.as_ref(), self.end.as_ref()) { + (Repr::Inline(Inline::Unsigned(start)), Repr::Inline(end)) => { let end = vm_try!(end.as_integer::()); vm_try!(rune::to_value(RangeInclusiveIter::new(*start..=end))) } - (ReprRef::Inline(Inline::Signed(start)), ReprRef::Inline(end)) => { + (Repr::Inline(Inline::Signed(start)), Repr::Inline(end)) => { let end = vm_try!(end.as_integer::()); vm_try!(rune::to_value(RangeInclusiveIter::new(*start..=end))) } - (ReprRef::Inline(Inline::Char(start)), ReprRef::Inline(Inline::Char(end))) => { + (Repr::Inline(Inline::Char(start)), Repr::Inline(Inline::Char(end))) => { vm_try!(rune::to_value(RangeInclusiveIter::new(*start..=*end))) } (start, end) => { diff --git a/crates/rune/src/runtime/runtime_context.rs b/crates/rune/src/runtime/runtime_context.rs index 82742db9a..bbed74515 100644 --- a/crates/rune/src/runtime/runtime_context.rs +++ b/crates/rune/src/runtime/runtime_context.rs @@ -42,18 +42,21 @@ impl RuntimeContext { } /// Lookup the given native function handler in the context. - pub fn function(&self, hash: Hash) -> Option<&Arc> { - self.functions.get(&hash) + #[inline] + pub fn function(&self, hash: &Hash) -> Option<&Arc> { + self.functions.get(hash) } /// Read a constant value. - pub fn constant(&self, hash: Hash) -> Option<&ConstValue> { - self.constants.get(&hash) + #[inline] + pub fn constant(&self, hash: &Hash) -> Option<&ConstValue> { + self.constants.get(hash) } /// Read a constant constructor. - pub(crate) fn construct(&self, hash: Hash) -> Option<&dyn ConstConstruct> { - Some(&**self.construct.get(&hash)?) + #[inline] + pub(crate) fn construct(&self, hash: &Hash) -> Option<&dyn ConstConstruct> { + Some(&**self.construct.get(hash)?) } } diff --git a/crates/rune/src/runtime/type_info.rs b/crates/rune/src/runtime/type_info.rs index 122da15c8..4e845f204 100644 --- a/crates/rune/src/runtime/type_info.rs +++ b/crates/rune/src/runtime/type_info.rs @@ -38,6 +38,14 @@ impl TypeInfo { Self { kind } } + /// Construct type info for the empty type. + pub const fn empty() -> Self { + Self::new(TypeInfoKind::Any(AnyTypeInfo { + full_name: |f| write!(f, "empty"), + hash: crate::hash!(::std::empty::Empty), + })) + } + /// Construct type info from an statically known [`Any`] type. #[inline] pub const fn any() -> Self diff --git a/crates/rune/src/runtime/unit.rs b/crates/rune/src/runtime/unit.rs index ff94cf6a8..6e97ddd29 100644 --- a/crates/rune/src/runtime/unit.rs +++ b/crates/rune/src/runtime/unit.rs @@ -18,7 +18,7 @@ use crate as rune; use crate::alloc::prelude::*; use crate::alloc::{self, Box, String, Vec}; use crate::hash; -use crate::runtime::{Call, ConstValue, DebugInfo, Inst, Rtti, StaticString, VmError, VmErrorKind}; +use crate::runtime::{Call, ConstValue, DebugInfo, Inst, InstAddress, Rtti, StaticString}; use crate::Hash; pub use self::storage::{ArrayUnit, EncodeError, UnitEncoder, UnitStorage}; @@ -57,7 +57,7 @@ pub struct Logic { storage: S, /// Where functions are located in the collection of instructions. functions: hash::Map, - /// A static string. + /// Static strings. static_strings: Vec>, /// A static byte string. static_bytes: Vec>, @@ -68,6 +68,8 @@ pub struct Logic { /// /// All keys are sorted with the default string sort. static_object_keys: Vec>, + /// Drop sets. + drop_sets: Vec>, /// Runtime information for types. rtti: hash::Map>, /// Named constants @@ -93,6 +95,7 @@ impl Unit { static_strings: Vec>, static_bytes: Vec>, static_object_keys: Vec>, + drop_sets: Vec>, rtti: hash::Map>, debug: Option>, constants: hash::Map, @@ -104,6 +107,7 @@ impl Unit { static_strings, static_bytes, static_object_keys, + drop_sets, rtti, constants, }, @@ -136,6 +140,20 @@ impl Unit { self.logic.static_strings.iter() } + /// Iterate over all static bytes in the unit. + #[cfg(feature = "cli")] + #[inline] + pub(crate) fn iter_static_bytes(&self) -> impl Iterator + '_ { + self.logic.static_bytes.iter().map(|v| &**v) + } + + /// Iterate over all available drop sets. + #[cfg(feature = "cli")] + #[inline] + pub(crate) fn iter_static_drop_sets(&self) -> impl Iterator + '_ { + self.logic.drop_sets.iter().map(|v| &**v) + } + /// Iterate over all constants in the unit. #[cfg(feature = "cli")] #[inline] @@ -166,50 +184,43 @@ impl Unit { /// Lookup the static string by slot, if it exists. #[inline] - pub(crate) fn lookup_string(&self, slot: usize) -> Result<&Arc, VmError> { - Ok(self - .logic - .static_strings - .get(slot) - .ok_or(VmErrorKind::MissingStaticString { slot })?) + pub(crate) fn lookup_string(&self, slot: usize) -> Option<&Arc> { + self.logic.static_strings.get(slot) } /// Lookup the static byte string by slot, if it exists. #[inline] - pub(crate) fn lookup_bytes(&self, slot: usize) -> Result<&[u8], VmError> { - Ok(self - .logic - .static_bytes - .get(slot) - .ok_or(VmErrorKind::MissingStaticString { slot })? - .as_ref()) + pub(crate) fn lookup_bytes(&self, slot: usize) -> Option<&[u8]> { + Some(self.logic.static_bytes.get(slot)?) } /// Lookup the static object keys by slot, if it exists. #[inline] pub(crate) fn lookup_object_keys(&self, slot: usize) -> Option<&[String]> { - self.logic - .static_object_keys - .get(slot) - .map(|keys| &keys[..]) + Some(self.logic.static_object_keys.get(slot)?) + } + + #[inline] + pub(crate) fn lookup_drop_set(&self, set: usize) -> Option<&[InstAddress]> { + Some(self.logic.drop_sets.get(set)?) } /// Lookup run-time information for the given type hash. #[inline] - pub(crate) fn lookup_rtti(&self, hash: Hash) -> Option<&Arc> { - self.logic.rtti.get(&hash) + pub(crate) fn lookup_rtti(&self, hash: &Hash) -> Option<&Arc> { + self.logic.rtti.get(hash) } /// Lookup a function in the unit. #[inline] - pub(crate) fn function(&self, hash: Hash) -> Option { - self.logic.functions.get(&hash).copied() + pub(crate) fn function(&self, hash: &Hash) -> Option<&UnitFn> { + self.logic.functions.get(hash) } /// Lookup a constant from the unit. #[inline] - pub(crate) fn constant(&self, hash: Hash) -> Option<&ConstValue> { - self.logic.constants.get(&hash) + pub(crate) fn constant(&self, hash: &Hash) -> Option<&ConstValue> { + self.logic.constants.get(hash) } } diff --git a/crates/rune/src/runtime/value.rs b/crates/rune/src/runtime/value.rs index 886a6daef..ca8b0e470 100644 --- a/crates/rune/src/runtime/value.rs +++ b/crates/rune/src/runtime/value.rs @@ -74,54 +74,23 @@ where } #[derive(Clone)] -enum Repr { - Empty, +pub(crate) enum Repr { Inline(Inline), Dynamic(Dynamic, Value>), Any(AnyObj), } -pub(crate) enum ReprOwned { - Inline(Inline), - Dynamic(Dynamic, Value>), - Any(AnyObj), -} - -impl ReprOwned { - #[inline] - pub(crate) fn type_info(&self) -> TypeInfo { - match self { - ReprOwned::Inline(value) => value.type_info(), - ReprOwned::Dynamic(value) => value.type_info(), - ReprOwned::Any(value) => value.type_info(), - } - } -} - -pub(crate) enum ReprRef<'a> { - Inline(&'a Inline), - Dynamic(&'a Dynamic, Value>), - Any(&'a AnyObj), -} - -impl ReprRef<'_> { +impl Repr { #[inline] pub(crate) fn type_info(&self) -> TypeInfo { match self { - ReprRef::Inline(value) => value.type_info(), - ReprRef::Dynamic(value) => value.type_info(), - ReprRef::Any(value) => value.type_info(), + Repr::Inline(value) => value.type_info(), + Repr::Dynamic(value) => value.type_info(), + Repr::Any(value) => value.type_info(), } } } -/// Access the internals of a value mutably. -pub(crate) enum ReprMut<'a> { - Inline(&'a mut Inline), - Dynamic(#[allow(unused)] &'a Dynamic, Value>), - Any(#[allow(unused)] &'a AnyObj), -} - /// An entry on the stack. pub struct Value { repr: Repr, @@ -286,7 +255,7 @@ impl Value { /// Test if the value is writable. pub fn is_writable(&self) -> bool { match self.repr { - Repr::Empty => false, + Repr::Inline(Inline::Empty) => false, Repr::Inline(..) => true, Repr::Dynamic(ref value) => value.is_writable(), Repr::Any(ref any) => any.is_writable(), @@ -296,7 +265,7 @@ impl Value { /// Test if the value is readable. pub fn is_readable(&self) -> bool { match &self.repr { - Repr::Empty => false, + Repr::Inline(Inline::Empty) => false, Repr::Inline(..) => true, Repr::Dynamic(ref value) => value.is_readable(), Repr::Any(ref any) => any.is_readable(), @@ -312,7 +281,9 @@ impl Value { /// Construct an empty value. pub const fn empty() -> Self { - Self { repr: Repr::Empty } + Self { + repr: Repr::Inline(Inline::Empty), + } } /// Format the value using the [Protocol::DISPLAY_FMT] protocol. @@ -341,8 +312,8 @@ impl Value { caller: &mut dyn ProtocolCaller, ) -> VmResult<()> { 'fallback: { - match vm_try!(self.as_ref()) { - ReprRef::Inline(value) => match value { + match self.as_ref() { + Repr::Inline(value) => match value { Inline::Char(c) => { vm_try!(f.try_write_char(*c)); } @@ -400,19 +371,19 @@ impl Value { } pub(crate) fn clone_with(&self, caller: &mut dyn ProtocolCaller) -> VmResult { - match vm_try!(self.as_ref()) { - ReprRef::Inline(value) => { + match self.as_ref() { + Repr::Inline(value) => { return VmResult::Ok(Self { repr: Repr::Inline(*value), }); } - ReprRef::Dynamic(value) => { + Repr::Dynamic(value) => { // TODO: This type of cloning should be deep, not shallow. return VmResult::Ok(Self { repr: Repr::Dynamic(value.clone()), }); } - ReprRef::Any(..) => {} + Repr::Any(..) => {} } VmResult::Ok(vm_try!(caller.call_protocol_fn( @@ -445,9 +416,6 @@ impl Value { caller: &mut dyn ProtocolCaller, ) -> VmResult<()> { match &self.repr { - Repr::Empty => { - vm_try!(vm_write!(f, "")); - } Repr::Inline(value) => { vm_try!(vm_write!(f, "{value:?}")); } @@ -467,9 +435,6 @@ impl Value { vm_try!(<()>::from_value(value)); } CallResultOnly::Unsupported(value) => match &value.repr { - Repr::Empty => { - vm_try!(vm_write!(f, "")); - } Repr::Inline(value) => { vm_try!(vm_write!(f, "{value:?}")); } @@ -524,10 +489,10 @@ impl Value { /// /// [`Vm`]: crate::Vm pub fn into_type_name(self) -> VmResult { - let hash = Hash::associated_function(vm_try!(self.type_hash()), Protocol::INTO_TYPE_NAME); + let hash = Hash::associated_function(self.type_hash(), Protocol::INTO_TYPE_NAME); crate::runtime::env::shared(|context, unit| { - if let Some(name) = context.constant(hash) { + if let Some(name) = context.constant(&hash) { match name.as_kind() { ConstValueKind::String(s) => { return VmResult::Ok(vm_try!(String::try_from(s.as_str()))) @@ -536,7 +501,7 @@ impl Value { } } - if let Some(name) = unit.constant(hash) { + if let Some(name) = unit.constant(&hash) { match name.as_kind() { ConstValueKind::String(s) => { return VmResult::Ok(vm_try!(String::try_from(s.as_str()))) @@ -545,7 +510,7 @@ impl Value { } } - VmResult::Ok(vm_try!(vm_try!(self.type_info()).try_to_string())) + VmResult::Ok(vm_try!(self.type_info().try_to_string())) }) } @@ -625,8 +590,8 @@ impl Value { /// Take the current value as a string. #[inline] pub fn into_string(self) -> Result { - match self.take_repr()? { - ReprOwned::Any(value) => Ok(value.downcast()?), + match self.take_repr() { + Repr::Any(value) => Ok(value.downcast()?), actual => Err(RuntimeError::expected::(actual.type_info())), } } @@ -635,12 +600,12 @@ impl Value { #[doc(hidden)] #[inline] pub fn as_type_value(&self) -> Result, RuntimeError> { - match self.as_ref()? { - ReprRef::Inline(value) => match value { + match self.as_ref() { + Repr::Inline(value) => match value { Inline::Unit => Ok(TypeValue::Unit), value => Ok(TypeValue::NotTypedInline(NotTypedInline(*value))), }, - ReprRef::Dynamic(value) => match value.rtti().kind { + Repr::Dynamic(value) => match value.rtti().kind { RttiKind::Empty => Ok(TypeValue::EmptyStruct(EmptyStruct { rtti: value.rtti() })), RttiKind::Tuple => Ok(TypeValue::TupleStruct(TupleStruct { rtti: value.rtti(), @@ -651,7 +616,7 @@ impl Value { data: value.borrow_ref()?, })), }, - ReprRef::Any(value) => match value.type_hash() { + Repr::Any(value) => match value.type_hash() { OwnedTuple::HASH => Ok(TypeValue::Tuple(value.borrow_ref()?)), Object::HASH => Ok(TypeValue::Object(value.borrow_ref()?)), _ => Ok(TypeValue::NotTypedAnyObj(NotTypedAnyObj(value))), @@ -662,8 +627,8 @@ impl Value { /// Coerce into a unit. #[inline] pub fn into_unit(&self) -> Result<(), RuntimeError> { - match self.as_ref()? { - ReprRef::Inline(Inline::Unit) => Ok(()), + match self.as_ref() { + Repr::Inline(Inline::Unit) => Ok(()), value => Err(RuntimeError::expected::<()>(value.type_info())), } } @@ -723,11 +688,11 @@ impl Value { /// and does not consume it. #[inline] pub fn borrow_tuple_ref(&self) -> Result, RuntimeError> { - match self.as_ref()? { - ReprRef::Inline(Inline::Unit) => Ok(BorrowRef::from_static(Tuple::new(&[]))), - ReprRef::Inline(value) => Err(RuntimeError::expected::(value.type_info())), - ReprRef::Dynamic(value) => Err(RuntimeError::expected::(value.type_info())), - ReprRef::Any(value) => { + match self.as_ref() { + Repr::Inline(Inline::Unit) => Ok(BorrowRef::from_static(Tuple::new(&[]))), + Repr::Inline(value) => Err(RuntimeError::expected::(value.type_info())), + Repr::Dynamic(value) => Err(RuntimeError::expected::(value.type_info())), + Repr::Any(value) => { let value = value.borrow_ref::()?; let value = BorrowRef::map(value, OwnedTuple::as_ref); Ok(value) @@ -741,11 +706,11 @@ impl Value { /// does not consume it. #[inline] pub fn borrow_tuple_mut(&self) -> Result, RuntimeError> { - match self.as_ref()? { - ReprRef::Inline(Inline::Unit) => Ok(BorrowMut::from_static(Tuple::new_mut(&mut []))), - ReprRef::Inline(value) => Err(RuntimeError::expected::(value.type_info())), - ReprRef::Dynamic(value) => Err(RuntimeError::expected::(value.type_info())), - ReprRef::Any(value) => { + match self.as_ref() { + Repr::Inline(Inline::Unit) => Ok(BorrowMut::from_static(Tuple::new_mut(&mut []))), + Repr::Inline(value) => Err(RuntimeError::expected::(value.type_info())), + Repr::Dynamic(value) => Err(RuntimeError::expected::(value.type_info())), + Repr::Any(value) => { let value = value.borrow_mut::()?; let value = BorrowMut::map(value, OwnedTuple::as_mut); Ok(value) @@ -759,11 +724,11 @@ impl Value { /// does not consume it. #[inline] pub fn into_tuple(&self) -> Result, RuntimeError> { - match self.as_ref()? { - ReprRef::Inline(Inline::Unit) => Ok(Tuple::from_boxed(Box::default())), - ReprRef::Inline(value) => Err(RuntimeError::expected::(value.type_info())), - ReprRef::Dynamic(value) => Err(RuntimeError::expected::(value.type_info())), - ReprRef::Any(value) => Ok(value.clone().downcast::()?.into_boxed_tuple()), + match self.as_ref() { + Repr::Inline(Inline::Unit) => Ok(Tuple::from_boxed(Box::default())), + Repr::Inline(value) => Err(RuntimeError::expected::(value.type_info())), + Repr::Dynamic(value) => Err(RuntimeError::expected::(value.type_info())), + Repr::Any(value) => Ok(value.clone().downcast::()?.into_boxed_tuple()), } } @@ -773,11 +738,11 @@ impl Value { /// does not consume it. #[inline] pub fn into_tuple_ref(&self) -> Result, RuntimeError> { - match self.as_ref()? { - ReprRef::Inline(Inline::Unit) => Ok(Ref::from_static(Tuple::new(&[]))), - ReprRef::Inline(value) => Err(RuntimeError::expected::(value.type_info())), - ReprRef::Dynamic(value) => Err(RuntimeError::expected::(value.type_info())), - ReprRef::Any(value) => { + match self.as_ref() { + Repr::Inline(Inline::Unit) => Ok(Ref::from_static(Tuple::new(&[]))), + Repr::Inline(value) => Err(RuntimeError::expected::(value.type_info())), + Repr::Dynamic(value) => Err(RuntimeError::expected::(value.type_info())), + Repr::Any(value) => { let value = value.clone().into_ref::()?; let value = Ref::map(value, OwnedTuple::as_ref); Ok(value) @@ -791,11 +756,11 @@ impl Value { /// does not consume it. #[inline] pub fn into_tuple_mut(&self) -> Result, RuntimeError> { - match self.as_ref()? { - ReprRef::Inline(Inline::Unit) => Ok(Mut::from_static(Tuple::new_mut(&mut []))), - ReprRef::Inline(value) => Err(RuntimeError::expected::(value.type_info())), - ReprRef::Dynamic(value) => Err(RuntimeError::expected::(value.type_info())), - ReprRef::Any(value) => { + match self.as_ref() { + Repr::Inline(Inline::Unit) => Ok(Mut::from_static(Tuple::new_mut(&mut []))), + Repr::Inline(value) => Err(RuntimeError::expected::(value.type_info())), + Repr::Dynamic(value) => Err(RuntimeError::expected::(value.type_info())), + Repr::Any(value) => { let value = value.clone().into_mut::()?; let value = Mut::map(value, OwnedTuple::as_mut); Ok(value) @@ -809,7 +774,6 @@ impl Value { #[inline] pub fn into_any_obj(self) -> Result { match self.repr { - Repr::Empty => Err(RuntimeError::from(AccessError::empty())), Repr::Inline(value) => Err(RuntimeError::expected_any_obj(value.type_info())), Repr::Dynamic(value) => Err(RuntimeError::expected_any_obj(value.type_info())), Repr::Any(value) => Ok(value), @@ -834,7 +798,6 @@ impl Value { #[inline] pub fn into_future(self) -> Result { let target = match self.repr { - Repr::Empty => return Err(RuntimeError::from(AccessError::empty())), Repr::Any(value) => match value.type_hash() { Future::HASH => { return Ok(value.downcast::()?); @@ -863,7 +826,6 @@ impl Value { T: Any, { match self.repr { - Repr::Empty => Err(RuntimeError::from(AccessError::empty())), Repr::Inline(value) => Err(RuntimeError::expected_any::(value.type_info())), Repr::Dynamic(value) => Err(RuntimeError::expected_any::(value.type_info())), Repr::Any(value) => { @@ -887,7 +849,6 @@ impl Value { T: Any, { match self.repr { - Repr::Empty => Err(RuntimeError::from(AccessError::empty())), Repr::Inline(value) => Err(RuntimeError::expected_any::(value.type_info())), Repr::Dynamic(value) => Err(RuntimeError::expected_any::(value.type_info())), Repr::Any(value) => { @@ -933,7 +894,6 @@ impl Value { T: Any, { match self.repr { - Repr::Empty => Err(RuntimeError::from(AccessError::empty())), Repr::Inline(value) => Err(RuntimeError::expected_any::(value.type_info())), Repr::Dynamic(value) => Err(RuntimeError::expected_any::(value.type_info())), Repr::Any(value) => Ok(value.downcast::()?), @@ -967,7 +927,6 @@ impl Value { T: Any, { match &self.repr { - Repr::Empty => Err(RuntimeError::from(AccessError::empty())), Repr::Inline(value) => Err(RuntimeError::expected_any::(value.type_info())), Repr::Dynamic(value) => Err(RuntimeError::expected_any::(value.type_info())), Repr::Any(value) => Ok(value.borrow_ref()?), @@ -1000,7 +959,6 @@ impl Value { T: Any, { match self.repr { - Repr::Empty => Err(RuntimeError::from(AccessError::empty())), Repr::Inline(value) => Err(RuntimeError::expected_any::(value.type_info())), Repr::Dynamic(value) => Err(RuntimeError::expected_any::(value.type_info())), Repr::Any(value) => Ok(value.into_ref()?), @@ -1014,7 +972,6 @@ impl Value { T: Any, { match &self.repr { - Repr::Empty => Err(RuntimeError::from(AccessError::empty())), Repr::Inline(value) => Err(RuntimeError::expected_any::(value.type_info())), Repr::Dynamic(value) => Err(RuntimeError::expected_any::(value.type_info())), Repr::Any(value) => Ok(value.borrow_mut()?), @@ -1055,7 +1012,6 @@ impl Value { T: Any, { match self.repr { - Repr::Empty => Err(RuntimeError::from(AccessError::empty())), Repr::Inline(value) => Err(RuntimeError::expected_any::(value.type_info())), Repr::Dynamic(value) => Err(RuntimeError::expected_any::(value.type_info())), Repr::Any(value) => Ok(value.into_mut()?), @@ -1066,22 +1022,22 @@ impl Value { /// /// One notable feature is that the type of a variant is its container /// *enum*, and not the type hash of the variant itself. - pub fn type_hash(&self) -> Result { + #[inline(always)] + pub fn type_hash(&self) -> Hash { match &self.repr { - Repr::Empty => Err(RuntimeError::from(AccessError::empty())), - Repr::Inline(value) => Ok(value.type_hash()), - Repr::Dynamic(value) => Ok(value.type_hash()), - Repr::Any(value) => Ok(value.type_hash()), + Repr::Inline(value) => value.type_hash(), + Repr::Dynamic(value) => value.type_hash(), + Repr::Any(value) => value.type_hash(), } } /// Get the type information for the current value. - pub fn type_info(&self) -> Result { + #[inline(always)] + pub fn type_info(&self) -> TypeInfo { match &self.repr { - Repr::Empty => Err(RuntimeError::from(AccessError::empty())), - Repr::Inline(value) => Ok(value.type_info()), - Repr::Dynamic(value) => Ok(value.type_info()), - Repr::Any(value) => Ok(value.type_info()), + Repr::Inline(value) => value.type_info(), + Repr::Dynamic(value) => value.type_info(), + Repr::Any(value) => value.type_info(), } } @@ -1238,9 +1194,9 @@ impl Value { hasher: &mut Hasher, caller: &mut dyn ProtocolCaller, ) -> VmResult<()> { - match vm_try!(self.as_ref()) { - ReprRef::Inline(value) => return VmResult::Ok(vm_try!(value.hash(hasher))), - ReprRef::Any(value) => match value.type_hash() { + match self.as_ref() { + Repr::Inline(value) => return VmResult::Ok(vm_try!(value.hash(hasher))), + Repr::Any(value) => match value.type_hash() { Vec::HASH => { let vec = vm_try!(value.borrow_ref::()); return Vec::hash_with(&vec, hasher, caller); @@ -1264,7 +1220,7 @@ impl Value { err(VmErrorKind::UnsupportedUnaryOperation { op: Protocol::HASH.name, - operand: vm_try!(self.type_info()), + operand: self.type_info(), }) } @@ -1283,18 +1239,18 @@ impl Value { where T: FromValue, { - match (vm_try!(self.as_ref()), vm_try!(b.as_ref())) { - (ReprRef::Inline(lhs), ReprRef::Inline(rhs)) => { + match (self.as_ref(), b.as_ref()) { + (Repr::Inline(lhs), Repr::Inline(rhs)) => { return VmResult::Ok(vm_try!(inline(lhs, rhs))) } - (ReprRef::Inline(lhs), rhs) => { + (Repr::Inline(lhs), rhs) => { return VmResult::err(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), }); } - (ReprRef::Dynamic(lhs), ReprRef::Dynamic(rhs)) => { + (Repr::Dynamic(lhs), Repr::Dynamic(rhs)) => { let lhs_rtti = lhs.rtti(); let rhs_rtti = rhs.rtti(); @@ -1322,8 +1278,8 @@ impl Value { err(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, - lhs: vm_try!(self.type_info()), - rhs: vm_try!(b.type_info()), + lhs: self.type_info(), + rhs: b.type_info(), }) } @@ -1344,7 +1300,6 @@ impl Value { T: TryFrom + TryFrom, { match self.repr { - Repr::Empty => Err(RuntimeError::from(AccessError::empty())), Repr::Inline(value) => value.as_integer(), Repr::Dynamic(ref value) => Err(RuntimeError::new(VmErrorKind::ExpectedNumber { actual: value.type_info(), @@ -1371,22 +1326,20 @@ impl Value { /// /// Any empty value will cause an access error. #[inline] - pub(crate) fn as_inline(&self) -> Result, AccessError> { + pub(crate) fn as_inline(&self) -> Option<&Inline> { match &self.repr { - Repr::Empty => Err(AccessError::empty()), - Repr::Inline(value) => Ok(Some(value)), - Repr::Dynamic(..) => Ok(None), - Repr::Any(..) => Ok(None), + Repr::Inline(value) => Some(value), + Repr::Dynamic(..) => None, + Repr::Any(..) => None, } } #[inline] - pub(crate) fn as_inline_mut(&mut self) -> Result, AccessError> { + pub(crate) fn as_inline_mut(&mut self) -> Option<&mut Inline> { match &mut self.repr { - Repr::Empty => Err(AccessError::empty()), - Repr::Inline(value) => Ok(Some(value)), - Repr::Dynamic(..) => Ok(None), - Repr::Any(..) => Ok(None), + Repr::Inline(value) => Some(value), + Repr::Dynamic(..) => None, + Repr::Any(..) => None, } } @@ -1394,43 +1347,27 @@ impl Value { /// /// Any empty value will cause an access error. #[inline] - pub(crate) fn as_any(&self) -> Result, AccessError> { + pub(crate) fn as_any(&self) -> Option<&AnyObj> { match &self.repr { - Repr::Empty => Err(AccessError::empty()), - Repr::Inline(..) => Ok(None), - Repr::Dynamic(..) => Ok(None), - Repr::Any(value) => Ok(Some(value)), + Repr::Inline(..) => None, + Repr::Dynamic(..) => None, + Repr::Any(value) => Some(value), } } - #[inline] - pub(crate) fn take_repr(self) -> Result { - match self.repr { - Repr::Empty => Err(AccessError::empty()), - Repr::Inline(value) => Ok(ReprOwned::Inline(value)), - Repr::Dynamic(value) => Ok(ReprOwned::Dynamic(value)), - Repr::Any(value) => Ok(ReprOwned::Any(value)), - } + #[inline(always)] + pub(crate) fn take_repr(self) -> Repr { + self.repr } - #[inline] - pub(crate) fn as_ref(&self) -> Result, AccessError> { - match &self.repr { - Repr::Empty => Err(AccessError::empty()), - Repr::Inline(value) => Ok(ReprRef::Inline(value)), - Repr::Dynamic(value) => Ok(ReprRef::Dynamic(value)), - Repr::Any(value) => Ok(ReprRef::Any(value)), - } + #[inline(always)] + pub(crate) fn as_ref(&self) -> &Repr { + &self.repr } - #[inline] - pub(crate) fn as_mut(&mut self) -> Result, AccessError> { - match &mut self.repr { - Repr::Empty => Err(AccessError::empty()), - Repr::Inline(value) => Ok(ReprMut::Inline(value)), - Repr::Dynamic(value) => Ok(ReprMut::Dynamic(value)), - Repr::Any(value) => Ok(ReprMut::Any(value)), - } + #[inline(always)] + pub(crate) fn as_mut(&mut self) -> &mut Repr { + &mut self.repr } #[inline] @@ -1439,7 +1376,6 @@ impl Value { T: Any, { match &self.repr { - Repr::Empty => Err(AccessError::empty()), Repr::Inline(..) => Ok(None), Repr::Dynamic(..) => Ok(None), Repr::Any(value) => value.try_borrow_ref(), @@ -1452,7 +1388,6 @@ impl Value { T: Any, { match &self.repr { - Repr::Empty => Err(AccessError::empty()), Repr::Inline(..) => Ok(None), Repr::Dynamic(..) => Ok(None), Repr::Any(value) => value.try_borrow_mut(), @@ -1505,9 +1440,6 @@ impl Value { impl fmt::Debug for Value { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.repr { - Repr::Empty => { - write!(f, "")?; - } Repr::Inline(value) => { write!(f, "{value:?}")?; } @@ -1517,9 +1449,6 @@ impl fmt::Debug for Value { if let Err(e) = result.into_result() { match &self.repr { - Repr::Empty => { - write!(f, "")?; - } Repr::Inline(value) => { write!(f, "<{value:?}: {e}>")?; } @@ -1654,7 +1583,6 @@ impl Clone for Value { #[inline] fn clone(&self) -> Self { let repr = match &self.repr { - Repr::Empty => Repr::Empty, Repr::Inline(inline) => Repr::Inline(*inline), Repr::Dynamic(mutable) => Repr::Dynamic(mutable.clone()), Repr::Any(any) => Repr::Any(any.clone()), @@ -1666,7 +1594,6 @@ impl Clone for Value { #[inline] fn clone_from(&mut self, source: &Self) { match (&mut self.repr, &source.repr) { - (Repr::Empty, Repr::Empty) => {} (Repr::Inline(lhs), Repr::Inline(rhs)) => { *lhs = *rhs; } diff --git a/crates/rune/src/runtime/value/inline.rs b/crates/rune/src/runtime/value/inline.rs index 7cab10f1f..1bd3b7038 100644 --- a/crates/rune/src/runtime/value/inline.rs +++ b/crates/rune/src/runtime/value/inline.rs @@ -6,6 +6,7 @@ use core::hash::Hash as _; use musli::{Decode, Encode}; use serde::{Deserialize, Serialize}; +use crate as rune; use crate::hash::Hash; use crate::runtime::{ Hasher, OwnedTuple, Protocol, RuntimeError, Type, TypeInfo, VmErrorKind, VmIntegerRepr, @@ -15,6 +16,14 @@ use crate::TypeHash; /// An inline value. #[derive(Clone, Copy, Encode, Decode, Deserialize, Serialize)] pub enum Inline { + /// An empty value. + /// + /// Note that this value *can not* be instantiated. Internally any + /// operations over it will result in a type error, even when operating with + /// itself. + /// + /// Some operations will return a "falsy" value, like type checks. + Empty, /// The unit value. Unit, /// A boolean. @@ -214,6 +223,7 @@ impl Inline { impl fmt::Debug for Inline { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { + Inline::Empty => write!(f, ""), Inline::Unit => write!(f, "()"), Inline::Bool(value) => value.fmt(f), Inline::Char(value) => value.fmt(f), @@ -229,6 +239,7 @@ impl fmt::Debug for Inline { impl Inline { pub(crate) fn type_info(&self) -> TypeInfo { match self { + Inline::Empty => TypeInfo::empty(), Inline::Unit => TypeInfo::any::(), Inline::Bool(..) => TypeInfo::named::(), Inline::Char(..) => TypeInfo::named::(), @@ -246,6 +257,7 @@ impl Inline { /// *enum*, and not the type hash of the variant itself. pub(crate) fn type_hash(&self) -> Hash { match self { + Inline::Empty => crate::hash!(::std::empty::Empty), Inline::Unit => OwnedTuple::HASH, Inline::Bool(..) => bool::HASH, Inline::Char(..) => char::HASH, diff --git a/crates/rune/src/runtime/value/macros.rs b/crates/rune/src/runtime/value/macros.rs index 28e263712..323990aeb 100644 --- a/crates/rune/src/runtime/value/macros.rs +++ b/crates/rune/src/runtime/value/macros.rs @@ -23,9 +23,6 @@ macro_rules! inline_into { Repr::Any(value) => { Err(RuntimeError::expected::<$ty>(value.type_info())) } - Repr::Empty => { - Err(RuntimeError::from(AccessError::empty())) - } } } @@ -47,9 +44,6 @@ macro_rules! inline_into { Repr::Any(value) => { Err(RuntimeError::expected::<$ty>(value.type_info())) } - Repr::Empty => { - Err(RuntimeError::from(AccessError::empty())) - } } } } diff --git a/crates/rune/src/runtime/value/serde.rs b/crates/rune/src/runtime/value/serde.rs index bb58b06c9..28122e7e6 100644 --- a/crates/rune/src/runtime/value/serde.rs +++ b/crates/rune/src/runtime/value/serde.rs @@ -2,7 +2,7 @@ use core::fmt; use crate::alloc; use crate::alloc::prelude::*; -use crate::runtime::{self, Bytes, Inline, Object, OwnedTuple, ReprRef, RttiKind, Vec}; +use crate::runtime::{self, Bytes, Inline, Object, OwnedTuple, Repr, RttiKind, Vec}; use crate::TypeHash; use serde::de::{self, Deserialize as _, Error as _}; @@ -26,8 +26,9 @@ impl ser::Serialize for Value { where S: ser::Serializer, { - match self.as_ref().map_err(S::Error::custom)? { - ReprRef::Inline(value) => match *value { + match self.as_ref() { + Repr::Inline(value) => match *value { + Inline::Empty => Err(ser::Error::custom("cannot serialize empty values")), Inline::Unit => serializer.serialize_unit(), Inline::Bool(value) => serializer.serialize_bool(value), Inline::Char(value) => serializer.serialize_char(value), @@ -37,7 +38,7 @@ impl ser::Serialize for Value { Inline::Type(..) => Err(ser::Error::custom("cannot serialize types")), Inline::Ordering(..) => Err(ser::Error::custom("cannot serialize orderings")), }, - ReprRef::Dynamic(value) => match value.rtti().kind { + Repr::Dynamic(value) => match value.rtti().kind { RttiKind::Empty => Err(ser::Error::custom(format!( "cannot serialize empty struct {}", value.rtti().item @@ -51,7 +52,7 @@ impl ser::Serialize for Value { value.rtti().item ))), }, - ReprRef::Any(value) => match value.type_hash() { + Repr::Any(value) => match value.type_hash() { Option::::HASH => { let option = value .borrow_ref::>() diff --git a/crates/rune/src/runtime/vec.rs b/crates/rune/src/runtime/vec.rs index bc7ef4498..511bbafbf 100644 --- a/crates/rune/src/runtime/vec.rs +++ b/crates/rune/src/runtime/vec.rs @@ -368,7 +368,7 @@ impl Vec { /// types, such as vectors and tuples. pub(crate) fn index_get(this: &[Value], index: Value) -> VmResult> { let slice: Option<&[Value]> = 'out: { - if let Some(value) = vm_try!(index.as_any()) { + if let Some(value) = index.as_any() { match value.type_hash() { RangeFrom::HASH => { let range = vm_try!(value.borrow_ref::()); diff --git a/crates/rune/src/runtime/vm.rs b/crates/rune/src/runtime/vm.rs index ab7a7ea61..2aa2e8643 100644 --- a/crates/rune/src/runtime/vm.rs +++ b/crates/rune/src/runtime/vm.rs @@ -19,7 +19,7 @@ use super::{ Format, FormatSpec, Formatter, FromValue, Function, Future, Generator, GeneratorState, GuardedArgs, Inline, Inst, InstAddress, InstAssignOp, InstOp, InstRange, InstTarget, InstValue, InstVariant, Object, Output, OwnedTuple, Pair, Panic, Protocol, ProtocolCaller, Range, - RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, ReprMut, ReprRef, RttiKind, + RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, Repr, RttiKind, RuntimeContext, Select, SelectFuture, Stack, Stream, Type, TypeCheck, TypeHash, TypeInfo, TypeOf, Unit, UnitFn, UnitStorage, Value, Vec, VmDiagnostics, VmDiagnosticsObj, VmError, VmErrorKind, VmExecution, VmHalt, VmIntegerRepr, VmResult, VmSendExecution, @@ -144,7 +144,9 @@ macro_rules! target_value { InstTarget::Field(lhs, field) => { let rhs = vm_try!($vm.stack.at($rhs)); - let field = vm_try!($vm.unit.lookup_string(field)); + let Some(field) = $vm.unit.lookup_string(field) else { + return err(VmErrorKind::MissingStaticString { slot: field }); + }; $lhs = vm_try!($vm.stack.at(lhs)).clone(); @@ -595,7 +597,7 @@ impl Vm { { let hash = name.to_type_hash(); - let Some(info) = self.unit.function(hash) else { + let Some(info) = self.unit.function(&hash) else { return Err(if let Some(item) = name.to_item()? { VmErrorKind::MissingEntry { hash, item } } else { @@ -611,8 +613,8 @@ impl Vm { args: expected, .. } => { - check_args(count, expected)?; - offset + check_args(count, *expected)?; + *offset } _ => { return Err(VmErrorKind::MissingFunction { hash }); @@ -636,7 +638,7 @@ impl Vm { out: Output, ) -> VmResult> { let count = args.count().wrapping_add(1); - let type_hash = vm_try!(target.type_hash()); + let type_hash = target.type_hash(); let hash = Hash::associated_function(type_hash, hash.to_type_hash()); self.call_hash_with(isolated, hash, target, args, count, out) } @@ -652,7 +654,7 @@ impl Vm { out: Output, ) -> VmResult> { let count = args.count().wrapping_add(1); - let hash = Hash::field_function(protocol, vm_try!(target.type_hash()), name); + let hash = Hash::field_function(protocol, target.type_hash(), name); self.call_hash_with(Isolated::None, hash, target, args, count, out) } @@ -667,7 +669,7 @@ impl Vm { out: Output, ) -> VmResult> { let count = args.count().wrapping_add(1); - let hash = Hash::index_function(protocol, vm_try!(target.type_hash()), Hash::index(index)); + let hash = Hash::index_function(protocol, target.type_hash(), Hash::index(index)); self.call_hash_with(Isolated::None, hash, target, args, count, out) } @@ -691,7 +693,7 @@ impl Vm { count: usize, out: Output, ) -> VmResult> { - if let Some(handler) = self.context.function(hash) { + if let Some(handler) = self.context.function(&hash) { let addr = self.stack.addr(); vm_try!(self.called_function_hook(hash)); @@ -709,16 +711,17 @@ impl Vm { call, args: expected, .. - }) = self.unit.function(hash) + }) = self.unit.function(&hash) { - vm_try!(check_args(count, expected)); + vm_try!(check_args(count, *expected)); let addr = self.stack.addr(); + vm_try!(self.called_function_hook(hash)); vm_try!(self.stack.push(target)); vm_try!(args.push_to_stack(&mut self.stack)); - let result = self.call_offset_fn(offset, call, addr, count, isolated, out); + let result = self.call_offset_fn(*offset, *call, addr, count, isolated, out); if vm_try!(result) { self.stack.truncate(addr); @@ -818,8 +821,8 @@ impl Vm { /// Implementation of getting a string index on an object-like type. fn try_object_like_index_get(target: &Value, field: &str) -> VmResult> { - match vm_try!(target.as_ref()) { - ReprRef::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Struct) => { + match target.as_ref() { + Repr::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Struct) => { let Some(value) = vm_try!(data.get_field_ref(field)) else { return err(VmErrorKind::MissingField { target: data.type_info(), @@ -829,7 +832,7 @@ impl Vm { VmResult::Ok(Some(value.clone())) } - ReprRef::Any(value) => match value.type_hash() { + Repr::Any(value) => match value.type_hash() { Object::HASH => { let target = vm_try!(value.borrow_ref::()); @@ -850,19 +853,19 @@ impl Vm { /// Implementation of getting a string index on an object-like type. fn try_tuple_like_index_get(target: &Value, index: usize) -> VmResult> { - let result = match vm_try!(target.as_ref()) { - ReprRef::Inline(target) => match target { + let result = match target.as_ref() { + Repr::Inline(target) => match target { Inline::Unit => Err(target.type_info()), _ => return VmResult::Ok(None), }, - ReprRef::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Tuple) => { + Repr::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Tuple) => { match vm_try!(data.get_ref(index)) { Some(value) => Ok(value.clone()), None => Err(data.type_info()), } } - ReprRef::Dynamic(data) => Err(data.type_info()), - ReprRef::Any(target) => match target.type_hash() { + Repr::Dynamic(data) => Err(data.type_info()), + Repr::Any(target) => match target.type_hash() { Result::::HASH => { match ( index, @@ -920,8 +923,8 @@ impl Vm { target: &Value, index: usize, ) -> VmResult>> { - match vm_try!(target.as_ref()) { - ReprRef::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Tuple) => { + match target.as_ref() { + Repr::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Tuple) => { let Some(value) = vm_try!(data.get_mut(index)) else { return err(VmErrorKind::MissingIndexInteger { target: data.type_info(), @@ -931,11 +934,11 @@ impl Vm { VmResult::Ok(Some(value)) } - ReprRef::Dynamic(data) => err(VmErrorKind::MissingIndexInteger { + Repr::Dynamic(data) => err(VmErrorKind::MissingIndexInteger { target: data.type_info(), index: VmIntegerRepr::from(index), }), - ReprRef::Any(value) => match value.type_hash() { + Repr::Any(value) => match value.type_hash() { Result::::HASH => { let result = BorrowMut::try_map( vm_try!(value.borrow_mut::>()), @@ -1029,19 +1032,19 @@ impl Vm { target: &'a Value, field: &str, ) -> VmResult>> { - match vm_try!(target.as_ref()) { - ReprRef::Inline(value) => err(VmErrorKind::MissingField { + match target.as_ref() { + Repr::Inline(value) => err(VmErrorKind::MissingField { target: value.type_info(), field: vm_try!(field.try_to_owned()), }), - ReprRef::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Struct) => { + Repr::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Struct) => { VmResult::Ok(vm_try!(data.get_field_mut(field))) } - ReprRef::Dynamic(data) => err(VmErrorKind::MissingField { + Repr::Dynamic(data) => err(VmErrorKind::MissingField { target: data.type_info(), field: vm_try!(field.try_to_owned()), }), - ReprRef::Any(value) => match value.type_hash() { + Repr::Any(value) => match value.type_hash() { Object::HASH => { let object = vm_try!(value.borrow_mut::()); @@ -1061,12 +1064,12 @@ impl Vm { /// Implementation of getting a string index on an object-like type. fn try_tuple_like_index_set(target: &Value, index: usize, from: &Value) -> VmResult { - match vm_try!(target.as_ref()) { - ReprRef::Inline(target) => match target { + match target.as_ref() { + Repr::Inline(target) => match target { Inline::Unit => VmResult::Ok(false), _ => VmResult::Ok(false), }, - ReprRef::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Tuple) => { + Repr::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Tuple) => { if let Some(target) = vm_try!(data.borrow_mut()).get_mut(index) { target.clone_from(from); return VmResult::Ok(true); @@ -1074,8 +1077,8 @@ impl Vm { VmResult::Ok(false) } - ReprRef::Dynamic(..) => VmResult::Ok(false), - ReprRef::Any(value) => match value.type_hash() { + Repr::Dynamic(..) => VmResult::Ok(false), + Repr::Any(value) => match value.type_hash() { Result::::HASH => { let mut result = vm_try!(value.borrow_mut::>()); @@ -1129,8 +1132,8 @@ impl Vm { field: &str, value: &Value, ) -> Result { - match target.as_ref()? { - ReprRef::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Struct) => { + match target.as_ref() { + Repr::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Struct) => { if let Some(mut v) = data.get_field_mut(field)? { v.clone_from(value); return Ok(true); @@ -1141,7 +1144,7 @@ impl Vm { field: field.try_to_owned()?, }) } - ReprRef::Any(target) => match target.type_hash() { + Repr::Any(target) => match target.type_hash() { Object::HASH => { let mut target = target.borrow_mut::()?; @@ -1167,12 +1170,12 @@ impl Vm { where F: FnOnce(&[Value]) -> O, { - let value = match vm_try!(value.as_ref()) { - ReprRef::Inline(value) => match (ty, value) { + let value = match value.as_ref() { + Repr::Inline(value) => match (ty, value) { (TypeCheck::Unit, Inline::Unit) => Some(f(&[])), _ => None, }, - ReprRef::Any(value) => match (ty, value.type_hash()) { + Repr::Any(value) => match (ty, value.type_hash()) { (TypeCheck::Vec, runtime::Vec::HASH) => { let vec = vm_try!(value.borrow_ref::()); Some(f(&vec)) @@ -1194,10 +1197,10 @@ impl Vm { let b = vm_try!(self.stack.at(rhs)); let a = vm_try!(self.stack.at(lhs)); - let ReprRef::Inline(Inline::Type(ty)) = vm_try!(b.as_ref()) else { + let Repr::Inline(Inline::Type(ty)) = b.as_ref() else { return err(VmErrorKind::UnsupportedIs { - value: vm_try!(a.type_info()), - test_type: vm_try!(b.type_info()), + value: a.type_info(), + test_type: b.type_info(), }); }; @@ -1217,10 +1220,10 @@ impl Vm { }; } - let value = match vm_try!(a.as_ref()) { - ReprRef::Inline(Inline::Unsigned(a)) => convert!(u64, *a), - ReprRef::Inline(Inline::Signed(a)) => convert!(i64, *a), - ReprRef::Inline(Inline::Float(a)) => convert!(f64, *a), + let value = match a.as_ref() { + Repr::Inline(Inline::Unsigned(a)) => convert!(u64, *a), + Repr::Inline(Inline::Signed(a)) => convert!(i64, *a), + Repr::Inline(Inline::Float(a)) => convert!(f64, *a), value => { return err(VmErrorKind::UnsupportedAs { value: value.type_info(), @@ -1237,14 +1240,14 @@ impl Vm { let b = vm_try!(self.stack.at(rhs)); let a = vm_try!(self.stack.at(lhs)); - let Some(Inline::Type(ty)) = vm_try!(b.as_inline()) else { + let Some(Inline::Type(ty)) = b.as_inline() else { return err(VmErrorKind::UnsupportedIs { - value: vm_try!(a.type_info()), - test_type: vm_try!(b.type_info()), + value: a.type_info(), + test_type: b.type_info(), }); }; - VmResult::Ok(vm_try!(a.type_hash()) == ty.into_hash()) + VmResult::Ok(a.type_hash() == ty.into_hash()) } fn internal_bool( @@ -1258,17 +1261,10 @@ impl Vm { let rhs = vm_try!(self.stack.at(rhs)); let lhs = vm_try!(self.stack.at(lhs)); - let inline = match (vm_try!(lhs.as_ref()), vm_try!(rhs.as_ref())) { - (ReprRef::Inline(lhs), ReprRef::Inline(rhs)) => match (lhs, rhs) { - (Inline::Bool(lhs), Inline::Bool(rhs)) => Inline::Bool(bool_op(*lhs, *rhs)), - (lhs, rhs) => { - return err(VmErrorKind::UnsupportedBinaryOperation { - op, - lhs: lhs.type_info(), - rhs: rhs.type_info(), - }); - } - }, + let inline = match (lhs.as_ref(), rhs.as_ref()) { + (Repr::Inline(Inline::Bool(lhs)), Repr::Inline(Inline::Bool(rhs))) => { + Inline::Bool(bool_op(*lhs, *rhs)) + } (lhs, rhs) => { return err(VmErrorKind::UnsupportedBinaryOperation { op, @@ -1399,23 +1395,23 @@ impl Vm { let fallback = match target_value!(self, target, guard, lhs, rhs) { TargetValue::Same(value) => { - match vm_try!(value.as_mut()) { - ReprMut::Inline(Inline::Signed(value)) => { + match value.as_mut() { + Repr::Inline(Inline::Signed(value)) => { let out = vm_try!(signed_op(*value, *value).ok_or_else(error)); *value = out; return VmResult::Ok(()); } - ReprMut::Inline(Inline::Unsigned(value)) => { + Repr::Inline(Inline::Unsigned(value)) => { let out = vm_try!(unsigned_op(*value, *value).ok_or_else(error)); *value = out; return VmResult::Ok(()); } - ReprMut::Inline(Inline::Float(value)) => { + Repr::Inline(Inline::Float(value)) => { let out = float_op(*value, *value); *value = out; return VmResult::Ok(()); } - ReprMut::Inline(value) => { + Repr::Inline(value) => { return err(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, lhs: value.type_info(), @@ -1428,8 +1424,8 @@ impl Vm { TargetFallback::Value(value.clone(), value.clone()) } TargetValue::Pair(lhs, rhs) => { - match (vm_try!(lhs.as_mut()), vm_try!(rhs.as_ref())) { - (ReprMut::Inline(lhs), ReprRef::Inline(rhs)) => match (lhs, rhs) { + match (lhs.as_mut(), rhs.as_ref()) { + (Repr::Inline(lhs), Repr::Inline(rhs)) => match (lhs, rhs) { (Inline::Signed(lhs), rhs) => { let rhs = vm_try!(rhs.as_integer()); let out = vm_try!(signed_op(*lhs, rhs).ok_or_else(error)); @@ -1455,7 +1451,7 @@ impl Vm { }); } }, - (ReprMut::Inline(lhs), rhs) => { + (Repr::Inline(lhs), rhs) => { return err(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, lhs: lhs.type_info(), @@ -1493,8 +1489,8 @@ impl Vm { )) { return err(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, - lhs: vm_try!(lhs.type_info()), - rhs: vm_try!(rhs.type_info()), + lhs: lhs.type_info(), + rhs: rhs.type_info(), }); }; @@ -1511,7 +1507,7 @@ impl Vm { Output::discard() )) { return err(VmErrorKind::UnsupportedObjectSlotIndexGet { - target: vm_try!(lhs.type_info()), + target: lhs.type_info(), }); } @@ -1528,7 +1524,7 @@ impl Vm { Output::discard() )) { return err(VmErrorKind::UnsupportedTupleIndexGet { - target: vm_try!(lhs.type_info()), + target: lhs.type_info(), index, }); } @@ -1555,8 +1551,8 @@ impl Vm { let lhs = vm_try!(self.stack.at(lhs)); 'fallback: { - let inline = match (vm_try!(lhs.as_ref()), vm_try!(rhs.as_ref())) { - (ReprRef::Inline(lhs), ReprRef::Inline(rhs)) => match (lhs, rhs) { + let inline = match (lhs.as_ref(), rhs.as_ref()) { + (Repr::Inline(lhs), Repr::Inline(rhs)) => match (lhs, rhs) { (Inline::Unsigned(lhs), rhs) => { let rhs = vm_try!(rhs.as_integer()); Inline::Unsigned(vm_try!(unsigned_op(*lhs, rhs).ok_or_else(error))) @@ -1574,7 +1570,7 @@ impl Vm { }); } }, - (ReprRef::Inline(lhs), rhs) => { + (Repr::Inline(lhs), rhs) => { return err(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, lhs: lhs.type_info(), @@ -1600,8 +1596,8 @@ impl Vm { { return err(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, - lhs: vm_try!(lhs.type_info()), - rhs: vm_try!(rhs.type_info()), + lhs: lhs.type_info(), + rhs: rhs.type_info(), }); } @@ -1624,8 +1620,8 @@ impl Vm { let rhs = vm_try!(self.stack.at(rhs)); 'fallback: { - let inline = match (vm_try!(lhs.as_ref()), vm_try!(rhs.as_ref())) { - (ReprRef::Inline(lhs), ReprRef::Inline(rhs)) => match (lhs, rhs) { + let inline = match (lhs.as_ref(), rhs.as_ref()) { + (Repr::Inline(lhs), Repr::Inline(rhs)) => match (lhs, rhs) { (Inline::Unsigned(lhs), rhs) => { let rhs = vm_try!(rhs.as_integer()); Inline::Unsigned(unsigned_op(*lhs, rhs)) @@ -1643,7 +1639,7 @@ impl Vm { }); } }, - (ReprRef::Inline(lhs), rhs) => { + (Repr::Inline(lhs), rhs) => { return err(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, lhs: lhs.type_info(), @@ -1669,8 +1665,8 @@ impl Vm { { return err(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, - lhs: vm_try!(lhs.type_info()), - rhs: vm_try!(rhs.type_info()), + lhs: lhs.type_info(), + rhs: rhs.type_info(), }); } @@ -1691,23 +1687,23 @@ impl Vm { let fallback = match target_value!(self, target, guard, lhs, rhs) { TargetValue::Same(value) => { - match vm_try!(value.as_mut()) { - ReprMut::Inline(Inline::Unsigned(value)) => { + match value.as_mut() { + Repr::Inline(Inline::Unsigned(value)) => { let rhs = *value; unsigned_op(value, rhs); return VmResult::Ok(()); } - ReprMut::Inline(Inline::Signed(value)) => { + Repr::Inline(Inline::Signed(value)) => { let rhs = *value; signed_op(value, rhs); return VmResult::Ok(()); } - ReprMut::Inline(Inline::Bool(value)) => { + Repr::Inline(Inline::Bool(value)) => { let rhs = *value; bool_op(value, rhs); return VmResult::Ok(()); } - ReprMut::Inline(value) => { + Repr::Inline(value) => { return err(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, lhs: value.type_info(), @@ -1720,8 +1716,8 @@ impl Vm { TargetFallback::Value(value.clone(), value.clone()) } TargetValue::Pair(lhs, rhs) => { - match (vm_try!(lhs.as_mut()), vm_try!(rhs.as_ref())) { - (ReprMut::Inline(lhs), ReprRef::Inline(rhs)) => match (lhs, rhs) { + match (lhs.as_mut(), rhs.as_ref()) { + (Repr::Inline(lhs), Repr::Inline(rhs)) => match (lhs, rhs) { (Inline::Unsigned(lhs), rhs) => { let rhs = vm_try!(rhs.as_integer()); unsigned_op(lhs, rhs); @@ -1744,7 +1740,7 @@ impl Vm { }); } }, - (ReprMut::Inline(lhs), rhs) => { + (Repr::Inline(lhs), rhs) => { return err(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, lhs: lhs.type_info(), @@ -1776,7 +1772,7 @@ impl Vm { let inline = 'inline: { match vm_try!(self.stack.pair(lhs, rhs)) { Pair::Same(value) => { - if let ReprMut::Inline(lhs) = vm_try!(value.as_mut()) { + if let Repr::Inline(lhs) = value.as_mut() { match lhs { Inline::Unsigned(value) => { let shift = @@ -1804,8 +1800,8 @@ impl Vm { break 'fallback (value.clone(), value.clone()); } Pair::Pair(lhs, rhs) => { - match (vm_try!(lhs.as_mut()), vm_try!(rhs.as_ref())) { - (ReprMut::Inline(lhs), ReprRef::Inline(rhs)) => match (lhs, rhs) { + match (lhs.as_mut(), rhs.as_ref()) { + (Repr::Inline(lhs), Repr::Inline(rhs)) => match (lhs, rhs) { (Inline::Unsigned(lhs), rhs) => { let rhs = vm_try!(rhs.as_integer()); let value = vm_try!(unsigned_op(*lhs, rhs).ok_or_else(error)); @@ -1824,7 +1820,7 @@ impl Vm { }); } }, - (ReprMut::Inline(lhs), rhs) => { + (Repr::Inline(lhs), rhs) => { return err(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, lhs: lhs.type_info(), @@ -1850,8 +1846,8 @@ impl Vm { { return err(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, - lhs: vm_try!(lhs.type_info()), - rhs: vm_try!(rhs.type_info()), + lhs: lhs.type_info(), + rhs: rhs.type_info(), }); } @@ -1872,20 +1868,20 @@ impl Vm { let fallback = match target_value!(self, target, guard, lhs, rhs) { TargetValue::Same(value) => { - match vm_try!(value.as_mut()) { - ReprMut::Inline(Inline::Unsigned(value)) => { + match value.as_mut() { + Repr::Inline(Inline::Unsigned(value)) => { let shift = vm_try!(u32::try_from(*value).ok().ok_or_else(error)); let out = vm_try!(unsigned_op(*value, shift).ok_or_else(error)); *value = out; return VmResult::Ok(()); } - ReprMut::Inline(Inline::Signed(value)) => { + Repr::Inline(Inline::Signed(value)) => { let shift = vm_try!(u32::try_from(*value).ok().ok_or_else(error)); let out = vm_try!(signed_op(*value, shift).ok_or_else(error)); *value = out; return VmResult::Ok(()); } - ReprMut::Inline(value) => { + Repr::Inline(value) => { return err(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, lhs: value.type_info(), @@ -1898,8 +1894,8 @@ impl Vm { TargetFallback::Value(value.clone(), value.clone()) } TargetValue::Pair(lhs, rhs) => { - match (vm_try!(lhs.as_mut()), vm_try!(rhs.as_ref())) { - (ReprMut::Inline(lhs), ReprRef::Inline(rhs)) => match (lhs, rhs) { + match (lhs.as_mut(), rhs.as_ref()) { + (Repr::Inline(lhs), Repr::Inline(rhs)) => match (lhs, rhs) { (Inline::Unsigned(lhs), rhs) => { let rhs = vm_try!(rhs.as_integer()); let out = vm_try!(unsigned_op(*lhs, rhs).ok_or_else(error)); @@ -1920,7 +1916,7 @@ impl Vm { }); } }, - (ReprMut::Inline(lhs), rhs) => { + (Repr::Inline(lhs), rhs) => { return err(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, lhs: lhs.type_info(), @@ -1994,8 +1990,15 @@ impl Vm { } #[cfg_attr(feature = "bench", inline(never))] - fn op_drop(&mut self, addr: InstAddress) -> VmResult<()> { - *vm_try!(self.stack.at_mut(addr)) = Value::empty(); + fn op_drop(&mut self, set: usize) -> VmResult<()> { + let Some(addresses) = self.unit.lookup_drop_set(set) else { + return err(VmErrorKind::MissingDropSet { set }); + }; + + for &addr in addresses { + *vm_try!(self.stack.at_mut(addr)) = Value::empty(); + } + VmResult::Ok(()) } @@ -2104,8 +2107,8 @@ impl Vm { fn op_not(&mut self, operand: InstAddress, out: Output) -> VmResult<()> { let value = vm_try!(self.stack.at(operand)); - let value = match vm_try!(value.as_ref()) { - ReprRef::Inline(value) => match value { + let value = match value.as_ref() { + Repr::Inline(value) => match value { Inline::Bool(value) => Value::from(!value), Inline::Unsigned(value) => Value::from(!value), Inline::Signed(value) => Value::from(!value), @@ -2128,8 +2131,8 @@ impl Vm { fn op_neg(&mut self, addr: InstAddress, out: Output) -> VmResult<()> { let value = vm_try!(self.stack.at(addr)); - let value = match vm_try!(value.as_ref()) { - ReprRef::Inline(value) => match value { + let value = match value.as_ref() { + Repr::Inline(value) => match value { Inline::Float(value) => Value::from(-value), Inline::Signed(value) => Value::from(-value), actual => { @@ -2300,9 +2303,7 @@ impl Vm { let rhs = vm_try!(self.stack.at(rhs)); let lhs = vm_try!(self.stack.at(lhs)); - let test = if let (Some(lhs), Some(rhs)) = - (vm_try!(lhs.as_inline()), vm_try!(rhs.as_inline())) - { + let test = if let (Some(lhs), Some(rhs)) = (lhs.as_inline(), rhs.as_inline()) { vm_try!(lhs.partial_eq(rhs)) } else { let lhs = lhs.clone(); @@ -2316,9 +2317,7 @@ impl Vm { let rhs = vm_try!(self.stack.at(rhs)); let lhs = vm_try!(self.stack.at(lhs)); - let test = if let (Some(lhs), Some(rhs)) = - (vm_try!(lhs.as_inline()), vm_try!(rhs.as_inline())) - { + let test = if let (Some(lhs), Some(rhs)) = (lhs.as_inline(), rhs.as_inline()) { vm_try!(lhs.partial_eq(rhs)) } else { let lhs = lhs.clone(); @@ -2501,9 +2500,9 @@ impl Vm { Output::discard() )) { return err(VmErrorKind::UnsupportedIndexSet { - target: vm_try!(target.type_info()), - index: vm_try!(index.type_info()), - value: vm_try!(value.type_info()), + target: target.type_info(), + index: index.type_info(), + value: value.type_info(), }); } @@ -2528,44 +2527,42 @@ impl Vm { } fn lookup_function_by_hash(&self, hash: Hash) -> Result { - Ok(match self.unit.function(hash) { - Some(info) => match info { - UnitFn::Offset { - offset, call, args, .. - } => Function::from_vm_offset( - self.context.clone(), - self.unit.clone(), - offset, - call, - args, - hash, - ), - UnitFn::EmptyStruct { hash } => { - let rtti = self - .unit - .lookup_rtti(hash) - .ok_or(VmErrorKind::MissingRtti { hash })?; + let Some(info) = self.unit.function(&hash) else { + let Some(handler) = self.context.function(&hash) else { + return Err(VmErrorKind::MissingContextFunction { hash }); + }; - Function::from_unit_struct(rtti.clone()) - } - UnitFn::TupleStruct { hash, args } => { - let rtti = self - .unit - .lookup_rtti(hash) - .ok_or(VmErrorKind::MissingRtti { hash })?; + return Ok(Function::from_handler(handler.clone(), hash)); + }; - Function::from_tuple_struct(rtti.clone(), args) - } - }, - None => { - let handler = self - .context - .function(hash) - .ok_or(VmErrorKind::MissingContextFunction { hash })?; + let f = match info { + UnitFn::Offset { + offset, call, args, .. + } => Function::from_vm_offset( + self.context.clone(), + self.unit.clone(), + *offset, + *call, + *args, + hash, + ), + UnitFn::EmptyStruct { hash } => { + let Some(rtti) = self.unit.lookup_rtti(hash) else { + return Err(VmErrorKind::MissingRtti { hash: *hash }); + }; - Function::from_handler(handler.clone(), hash) + Function::from_unit_struct(rtti.clone()) } - }) + UnitFn::TupleStruct { hash, args } => { + let Some(rtti) = self.unit.lookup_rtti(hash) else { + return Err(VmErrorKind::MissingRtti { hash: *hash }); + }; + + Function::from_tuple_struct(rtti.clone(), *args) + } + }; + + Ok(f) } #[cfg_attr(feature = "bench", inline(never))] @@ -2594,7 +2591,7 @@ impl Vm { #[cfg_attr(feature = "bench", inline(never))] fn op_load_instance_fn(&mut self, addr: InstAddress, hash: Hash, out: Output) -> VmResult<()> { let instance = vm_try!(self.stack.at(addr)); - let ty = vm_try!(instance.type_hash()); + let ty = instance.type_hash(); let hash = Hash::associated_function(ty, hash); vm_try!(out.store(&mut self.stack, || Type::new(hash))); VmResult::Ok(()) @@ -2612,15 +2609,15 @@ impl Vm { let index = vm_try!(self.stack.at(index)); let target = vm_try!(self.stack.at(target)); - match vm_try!(index.as_ref()) { - ReprRef::Inline(inline) => { + match index.as_ref() { + Repr::Inline(inline) => { let index = vm_try!(inline.as_integer::()); if let Some(value) = vm_try!(Self::try_tuple_like_index_get(target, index)) { break 'store value; } } - ReprRef::Any(value) => { + Repr::Any(value) => { if let Some(index) = vm_try!(value.try_borrow_ref::()) { if let Some(value) = vm_try!(Self::try_object_like_index_get(target, index.as_str())) @@ -2645,8 +2642,8 @@ impl Vm { out )) { return err(VmErrorKind::UnsupportedIndexGet { - target: vm_try!(target.type_info()), - index: vm_try!(index.type_info()), + target: target.type_info(), + index: index.type_info(), }); } @@ -2673,7 +2670,7 @@ impl Vm { } err(VmErrorKind::UnsupportedTupleIndexSet { - target: vm_try!(target.type_info()), + target: target.type_info(), }) } @@ -2698,7 +2695,7 @@ impl Vm { vm_try!(self.call_index_fn(Protocol::GET, value, index, &mut (), out)) { return err(VmErrorKind::UnsupportedTupleIndexGet { - target: vm_try!(value.type_info()), + target: value.type_info(), index, }); } @@ -2716,7 +2713,10 @@ impl Vm { ) -> VmResult<()> { let target = vm_try!(self.stack.at(target)); let value = vm_try!(self.stack.at(value)); - let field = vm_try!(self.unit.lookup_string(slot)); + + let Some(field) = self.unit.lookup_string(slot) else { + return err(VmErrorKind::MissingStaticString { slot }); + }; if vm_try!(Self::try_object_slot_index_set(target, field, value)) { return VmResult::Ok(()); @@ -2734,7 +2734,7 @@ impl Vm { if let CallResult::Unsupported(target) = result { return err(VmErrorKind::UnsupportedObjectSlotIndexSet { - target: vm_try!(target.type_info()), + target: target.type_info(), }); }; @@ -2750,10 +2750,13 @@ impl Vm { out: Output, ) -> VmResult<()> { let target = vm_try!(self.stack.at(addr)); - let index = vm_try!(self.unit.lookup_string(slot)); - match vm_try!(target.as_ref()) { - ReprRef::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Struct) => { + let Some(index) = self.unit.lookup_string(slot) else { + return err(VmErrorKind::MissingStaticString { slot }); + }; + + match target.as_ref() { + Repr::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Struct) => { let Some(value) = vm_try!(data.get_field_ref(index.as_str())) else { return err(VmErrorKind::ObjectIndexMissing { slot }); }; @@ -2762,7 +2765,7 @@ impl Vm { vm_try!(out.store(&mut self.stack, value)); return VmResult::Ok(()); } - ReprRef::Any(value) if value.type_hash() == Object::HASH => { + Repr::Any(value) if value.type_hash() == Object::HASH => { let object = vm_try!(value.borrow_ref::()); let Some(value) = object.get(index.as_str()) else { @@ -2773,7 +2776,7 @@ impl Vm { vm_try!(out.store(&mut self.stack, value)); return VmResult::Ok(()); } - ReprRef::Any(..) => {} + Repr::Any(..) => {} target => { return err(VmErrorKind::UnsupportedObjectSlotIndexGet { target: target.type_info(), @@ -2787,7 +2790,7 @@ impl Vm { vm_try!(self.call_field_fn(Protocol::GET, target, index.hash(), &mut (), out)) { return err(VmErrorKind::UnsupportedObjectSlotIndexGet { - target: vm_try!(target.type_info()), + target: target.type_info(), }); } @@ -2797,10 +2800,9 @@ impl Vm { /// Operation to allocate an object. #[cfg_attr(feature = "bench", inline(never))] fn op_object(&mut self, addr: InstAddress, slot: usize, out: Output) -> VmResult<()> { - let keys = vm_try!(self - .unit - .lookup_object_keys(slot) - .ok_or(VmErrorKind::MissingStaticObjectKeys { slot })); + let Some(keys) = self.unit.lookup_object_keys(slot) else { + return err(VmErrorKind::MissingStaticObjectKeys { slot }); + }; let mut object = vm_try!(Object::with_capacity(keys.len())); let values = vm_try!(self.stack.slice_at_mut(addr, keys.len())); @@ -2852,10 +2854,9 @@ impl Vm { /// Operation to allocate an empty struct. #[cfg_attr(feature = "bench", inline(never))] fn op_empty_struct(&mut self, hash: Hash, out: Output) -> VmResult<()> { - let rtti = vm_try!(self - .unit - .lookup_rtti(hash) - .ok_or(VmErrorKind::MissingRtti { hash })); + let Some(rtti) = self.unit.lookup_rtti(&hash) else { + return err(VmErrorKind::MissingRtti { hash }); + }; let value = vm_try!(Dynamic::<_, Value>::new(rtti.clone(), [])); vm_try!(out.store(&mut self.stack, value)); @@ -2865,10 +2866,9 @@ impl Vm { /// Operation to allocate an object struct. #[cfg_attr(feature = "bench", inline(never))] fn op_struct(&mut self, addr: InstAddress, hash: Hash, out: Output) -> VmResult<()> { - let rtti = vm_try!(self - .unit - .lookup_rtti(hash) - .ok_or(VmErrorKind::MissingRtti { hash })); + let Some(rtti) = self.unit.lookup_rtti(&hash) else { + return err(VmErrorKind::MissingRtti { hash }); + }; let values = vm_try!(self.stack.slice_at_mut(addr, rtti.fields.len())); let value = vm_try!(Dynamic::new(rtti.clone(), values.iter_mut().map(take))); @@ -2887,7 +2887,7 @@ impl Vm { ) -> VmResult<()> { let values = vm_try!(self.stack.slice_at_mut(addr, count)); - let Some(construct) = self.context.construct(hash) else { + let Some(construct) = self.context.construct(&hash) else { return err(VmErrorKind::MissingConstantConstructor { hash }); }; @@ -2898,14 +2898,20 @@ impl Vm { #[cfg_attr(feature = "bench", inline(never))] fn op_string(&mut self, slot: usize, out: Output) -> VmResult<()> { - let string = vm_try!(self.unit.lookup_string(slot)); + let Some(string) = self.unit.lookup_string(slot) else { + return err(VmErrorKind::MissingStaticString { slot }); + }; + vm_try!(out.store(&mut self.stack, string.as_str())); VmResult::Ok(()) } #[cfg_attr(feature = "bench", inline(never))] fn op_bytes(&mut self, slot: usize, out: Output) -> VmResult<()> { - let bytes = vm_try!(self.unit.lookup_bytes(slot)); + let Some(bytes) = self.unit.lookup_bytes(slot) else { + return err(VmErrorKind::MissingStaticBytes { slot }); + }; + vm_try!(out.store(&mut self.stack, bytes)); VmResult::Ok(()) } @@ -2948,7 +2954,7 @@ impl Vm { #[cfg_attr(feature = "bench", inline(never))] fn op_is_unit(&mut self, addr: InstAddress, out: Output) -> VmResult<()> { let value = vm_try!(self.stack.at(addr)); - let is_unit = matches!(vm_try!(value.as_inline()), Some(Inline::Unit)); + let is_unit = matches!(value.as_inline(), Some(Inline::Unit)); vm_try!(out.store(&mut self.stack, is_unit)); VmResult::Ok(()) } @@ -2960,7 +2966,7 @@ impl Vm { let value = { let value = vm_try!(self.stack.at(addr)); - if let ReprRef::Any(value) = vm_try!(value.as_ref()) { + if let Repr::Any(value) = value.as_ref() { match value.type_hash() { Result::::HASH => { let result = vm_try!(value.borrow_ref::>()); @@ -2981,7 +2987,7 @@ impl Vm { CallResultOnly::Ok(value) => vm_try!(ControlFlow::from_value(value)), CallResultOnly::Unsupported(target) => { return err(VmErrorKind::UnsupportedTryOperand { - actual: vm_try!(target.type_info()), + actual: target.type_info(), }) } } @@ -3000,7 +3006,7 @@ impl Vm { fn op_eq_character(&mut self, addr: InstAddress, value: char, out: Output) -> VmResult<()> { let v = vm_try!(self.stack.at(addr)); - let is_match = match vm_try!(v.as_inline()) { + let is_match = match v.as_inline() { Some(Inline::Char(actual)) => *actual == value, _ => false, }; @@ -3013,7 +3019,7 @@ impl Vm { fn op_eq_unsigned(&mut self, addr: InstAddress, value: u64, out: Output) -> VmResult<()> { let v = vm_try!(self.stack.at(addr)); - let is_match = match vm_try!(v.as_inline()) { + let is_match = match v.as_inline() { Some(Inline::Unsigned(actual)) => *actual == value, _ => false, }; @@ -3026,7 +3032,7 @@ impl Vm { fn op_eq_signed(&mut self, addr: InstAddress, value: i64, out: Output) -> VmResult<()> { let v = vm_try!(self.stack.at(addr)); - let is_match = match vm_try!(v.as_inline()) { + let is_match = match v.as_inline() { Some(Inline::Signed(actual)) => *actual == value, _ => false, }; @@ -3039,7 +3045,7 @@ impl Vm { fn op_eq_bool(&mut self, addr: InstAddress, value: bool, out: Output) -> VmResult<()> { let v = vm_try!(self.stack.at(addr)); - let is_match = match vm_try!(v.as_inline()) { + let is_match = match v.as_inline() { Some(Inline::Bool(actual)) => *actual == value, _ => false, }; @@ -3059,7 +3065,10 @@ impl Vm { break 'out false; }; - let string = vm_try!(self.unit.lookup_string(slot)); + let Some(string) = self.unit.lookup_string(slot) else { + return err(VmErrorKind::MissingStaticString { slot }); + }; + actual.as_str() == string.as_str() }; @@ -3078,7 +3087,10 @@ impl Vm { break 'out false; }; - let bytes = vm_try!(self.unit.lookup_bytes(slot)); + let Some(bytes) = self.unit.lookup_bytes(slot) else { + return err(VmErrorKind::MissingStaticBytes { slot }); + }; + value.as_slice() == bytes }; @@ -3112,7 +3124,7 @@ impl Vm { #[cfg_attr(feature = "bench", inline(never))] fn op_match_type(&mut self, hash: Hash, addr: InstAddress, out: Output) -> VmResult<()> { let value = vm_try!(self.stack.at(addr)); - let is_match = vm_try!(value.type_hash()) == hash; + let is_match = value.type_hash() == hash; vm_try!(out.store(&mut self.stack, is_match)); VmResult::Ok(()) } @@ -3129,11 +3141,11 @@ impl Vm { let value = vm_try!(self.stack.at(addr)); let is_match = 'out: { - match vm_try!(value.as_ref()) { - ReprRef::Dynamic(value) => { + match value.as_ref() { + Repr::Dynamic(value) => { break 'out value.rtti().is(enum_hash, variant_hash); } - ReprRef::Any(any) => match enum_hash { + Repr::Any(any) => match enum_hash { Result::::HASH => { let result = vm_try!(any.borrow_ref::>()); @@ -3188,13 +3200,13 @@ impl Vm { ) -> VmResult<()> { let value = vm_try!(self.stack.at(addr)); - let is_match = match vm_try!(value.as_ref()) { - ReprRef::Inline(value) => match (type_check, value) { + let is_match = match value.as_ref() { + Repr::Inline(value) => match (type_check, value) { (TypeCheck::Unit, Inline::Unit) => true, _ => false, }, - ReprRef::Dynamic(..) => false, - ReprRef::Any(value) => match (type_check, value.type_hash()) { + Repr::Dynamic(..) => false, + Repr::Any(value) => match (type_check, value.type_hash()) { (TypeCheck::Vec, runtime::Vec::HASH) => true, (TypeCheck::Tuple, runtime::OwnedTuple::HASH) => true, _ => false, @@ -3235,10 +3247,9 @@ impl Vm { let is_match = match vm_try!(value.try_borrow_ref::()) { Some(object) => { - let keys = vm_try!(self - .unit - .lookup_object_keys(slot) - .ok_or(VmErrorKind::MissingStaticObjectKeys { slot })); + let Some(keys) = self.unit.lookup_object_keys(slot) else { + return err(VmErrorKind::MissingStaticObjectKeys { slot }); + }; test(&object, keys, exact) } @@ -3290,24 +3301,19 @@ impl Vm { count: usize, out: Output, ) -> VmResult<()> { - let info = vm_try!(self - .unit - .function(hash) - .ok_or(VmErrorKind::MissingFunction { hash })); - - let UnitFn::Offset { + let Some(UnitFn::Offset { offset, call, args, captures: Some(captures), - } = info + }) = self.unit.function(&hash) else { return err(VmErrorKind::MissingFunction { hash }); }; - if captures != count { + if *captures != count { return err(VmErrorKind::BadEnvironmentCount { - expected: captures, + expected: *captures, actual: count, }); } @@ -3322,9 +3328,9 @@ impl Vm { let function = Function::from_vm_closure( self.context.clone(), self.unit.clone(), - offset, - call, - args, + *offset, + *call, + *args, environment, hash, ); @@ -3336,11 +3342,10 @@ impl Vm { /// Implementation of a function call. #[cfg_attr(feature = "bench", inline(never))] fn op_call(&mut self, hash: Hash, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { - let Some(info) = self.unit.function(hash) else { - let handler = vm_try!(self - .context - .function(hash) - .ok_or(VmErrorKind::MissingFunction { hash })); + let Some(info) = self.unit.function(&hash) else { + let Some(handler) = self.context.function(&hash) else { + return err(VmErrorKind::MissingFunction { hash }); + }; vm_try!(handler(&mut self.stack, addr, args, out)); return VmResult::Ok(()); @@ -3353,16 +3358,15 @@ impl Vm { args: expected, .. } => { - vm_try!(check_args(args, expected)); - vm_try!(self.call_offset_fn(offset, call, addr, args, Isolated::None, out)); + vm_try!(check_args(args, *expected)); + vm_try!(self.call_offset_fn(*offset, *call, addr, args, Isolated::None, out)); } UnitFn::EmptyStruct { hash } => { vm_try!(check_args(args, 0)); - let rtti = vm_try!(self - .unit - .lookup_rtti(hash) - .ok_or(VmErrorKind::MissingRtti { hash })); + let Some(rtti) = self.unit.lookup_rtti(hash) else { + return err(VmErrorKind::MissingRtti { hash: *hash }); + }; vm_try!(out.store(&mut self.stack, || Value::empty_struct(rtti.clone()))); } @@ -3370,12 +3374,11 @@ impl Vm { hash, args: expected, } => { - vm_try!(check_args(args, expected)); + vm_try!(check_args(args, *expected)); - let rtti = vm_try!(self - .unit - .lookup_rtti(hash) - .ok_or(VmErrorKind::MissingRtti { hash })); + let Some(rtti) = self.unit.lookup_rtti(hash) else { + return err(VmErrorKind::MissingRtti { hash: *hash }); + }; let tuple = vm_try!(self.stack.slice_at_mut(addr, args)); let data = tuple.iter_mut().map(take); @@ -3410,10 +3413,10 @@ impl Vm { out: Output, ) -> VmResult<()> { let instance = vm_try!(self.stack.at(addr)); - let type_hash = vm_try!(instance.type_hash()); + let type_hash = instance.type_hash(); let hash = Hash::associated_function(type_hash, hash); - if let Some(handler) = self.context.function(hash) { + if let Some(handler) = self.context.function(&hash) { vm_try!(self.called_function_hook(hash)); vm_try!(handler(&mut self.stack, addr, args, out)); return VmResult::Ok(()); @@ -3424,16 +3427,16 @@ impl Vm { call, args: expected, .. - }) = self.unit.function(hash) + }) = self.unit.function(&hash) { vm_try!(self.called_function_hook(hash)); - vm_try!(check_args(args, expected)); - vm_try!(self.call_offset_fn(offset, call, addr, args, Isolated::None, out)); + vm_try!(check_args(args, *expected)); + vm_try!(self.call_offset_fn(*offset, *call, addr, args, Isolated::None, out)); return VmResult::Ok(()); } err(VmErrorKind::MissingInstanceFunction { - instance: vm_try!(instance.type_info()), + instance: instance.type_info(), hash, }) } @@ -3449,32 +3452,19 @@ impl Vm { ) -> VmResult> { let function = vm_try!(self.stack.at(function)); - if let Some(value) = vm_try!(function.as_inline()) { - let ty = match value { - Inline::Type(ty) => *ty, - actual => { - return err(VmErrorKind::UnsupportedCallFn { - actual: actual.type_info(), - }); - } - }; - - vm_try!(self.op_call(ty.into_hash(), addr, args, out)); - return VmResult::Ok(None); - } - - match vm_try!(function.as_ref()) { - ReprRef::Inline(value) => err(VmErrorKind::UnsupportedCallFn { - actual: value.type_info(), - }), - ReprRef::Dynamic(value) => err(VmErrorKind::UnsupportedCallFn { - actual: value.type_info(), - }), - ReprRef::Any(value) => { + match function.as_ref() { + Repr::Inline(Inline::Type(ty)) => { + vm_try!(self.op_call(ty.into_hash(), addr, args, out)); + VmResult::Ok(None) + } + Repr::Any(value) if value.type_hash() == Function::HASH => { let value = value.clone(); let f = vm_try!(value.borrow_ref::()); f.call_with_vm(self, addr, args, out) } + value => err(VmErrorKind::UnsupportedCallFn { + actual: value.type_info(), + }), } } @@ -3482,8 +3472,8 @@ impl Vm { fn op_iter_next(&mut self, addr: InstAddress, jump: usize, out: Output) -> VmResult<()> { let value = vm_try!(self.stack.at(addr)); - let some = match vm_try!(value.as_ref()) { - ReprRef::Any(value) => match value.type_hash() { + let some = match value.as_ref() { + Repr::Any(value) => match value.type_hash() { Option::::HASH => { let option = vm_try!(value.borrow_ref::>()); @@ -3685,8 +3675,8 @@ impl Vm { Inst::Move { addr, out } => { vm_try!(self.op_move(addr, out)); } - Inst::Drop { addr } => { - vm_try!(self.op_drop(addr)); + Inst::Drop { set } => { + vm_try!(self.op_drop(set)); } Inst::Swap { a, b } => { vm_try!(self.op_swap(a, b)); @@ -3917,6 +3907,7 @@ impl Drop for ClearStack<'_> { } /// Check that arguments matches expected or raise the appropriate error. +#[inline(always)] fn check_args(args: usize, expected: usize) -> Result<(), VmErrorKind> { if args != expected { return Err(VmErrorKind::BadArgumentCount { diff --git a/crates/rune/src/runtime/vm_error.rs b/crates/rune/src/runtime/vm_error.rs index 14727e951..3166f0123 100644 --- a/crates/rune/src/runtime/vm_error.rs +++ b/crates/rune/src/runtime/vm_error.rs @@ -700,9 +700,15 @@ pub(crate) enum VmErrorKind { MissingStaticString { slot: usize, }, + MissingStaticBytes { + slot: usize, + }, MissingStaticObjectKeys { slot: usize, }, + MissingDropSet { + set: usize, + }, MissingRtti { hash: Hash, }, @@ -914,10 +920,16 @@ impl fmt::Display for VmErrorKind { write!(f, "Unsupported unary operation `{op}` on {operand}") } VmErrorKind::MissingStaticString { slot } => { - write!(f, "Static string slot `{slot}` does not exist") + write!(f, "Static string slot {slot} does not exist") + } + VmErrorKind::MissingStaticBytes { slot } => { + write!(f, "Static bytes slot {slot} does not exist") } VmErrorKind::MissingStaticObjectKeys { slot } => { - write!(f, "Static object keys slot `{slot}` does not exist") + write!(f, "Static object keys slot {slot} does not exist") + } + VmErrorKind::MissingDropSet { set } => { + write!(f, "Static drop set {set} does not exist") } VmErrorKind::MissingRtti { hash } => { write!(f, "Missing runtime information for type with hash `{hash}`") diff --git a/crates/rune/src/tests.rs b/crates/rune/src/tests.rs index 9df349c0e..f05b7749f 100644 --- a/crates/rune/src/tests.rs +++ b/crates/rune/src/tests.rs @@ -12,6 +12,7 @@ pub(crate) mod prelude { pub(crate) use crate::ast; pub(crate) use crate::compile::{self, ErrorKind, Located, Named}; pub(crate) use crate::diagnostics::{self, WarningDiagnosticKind}; + pub(crate) use crate::hash; pub(crate) use crate::macros; pub(crate) use crate::module::InstallWith; pub(crate) use crate::parse; diff --git a/crates/rune/src/tests/bug_344.rs b/crates/rune/src/tests/bug_344.rs index 73bdd5abe..847100ad6 100644 --- a/crates/rune/src/tests/bug_344.rs +++ b/crates/rune/src/tests/bug_344.rs @@ -25,9 +25,7 @@ fn bug_344_function() -> Result<()> { context.install(module)?; let runtime = context.runtime()?; - let hash = Hash::type_hash(["function"]); - - let function = runtime.function(hash).expect("expect function"); + let function = runtime.function(&hash!(function)).expect("expect function"); let mut stack = Stack::new(); stack.push(rune::to_value(GuardCheck::new())?)?; @@ -60,8 +58,7 @@ fn bug_344_inst_fn() -> Result<()> { let runtime = context.runtime()?; let hash = Hash::associated_function(GuardCheck::HASH, "function"); - - let function = runtime.function(hash).expect("expect function"); + let function = runtime.function(&hash).expect("expect function"); let mut stack = Stack::new(); stack.push(rune::to_value(GuardCheck::new())?)?; @@ -82,9 +79,7 @@ fn bug_344_async_function() -> Result<()> { context.install(module)?; let runtime = context.runtime()?; - let hash = Hash::type_hash(["function"]); - - let function = runtime.function(hash).expect("expect function"); + let function = runtime.function(&hash!(function)).expect("expect function"); let mut stack = Stack::new(); stack.push(rune::to_value(GuardCheck::new())?)?; @@ -118,8 +113,7 @@ fn bug_344_async_inst_fn() -> Result<()> { let runtime = context.runtime()?; let hash = Hash::associated_function(GuardCheck::HASH, "function"); - - let function = runtime.function(hash).expect("expect function"); + let function = runtime.function(&hash).expect("expect function"); let mut stack = Stack::new(); stack.push(rune::to_value(GuardCheck::new())?)?; diff --git a/crates/rune/src/tests/unit_constants.rs b/crates/rune/src/tests/unit_constants.rs index 4a086b9b1..661f4865f 100644 --- a/crates/rune/src/tests/unit_constants.rs +++ b/crates/rune/src/tests/unit_constants.rs @@ -13,7 +13,7 @@ fn test_get_const() -> Result<()> { let unit = prepare(&mut sources).with_context(&context).build()?; assert_eq!( - unit.constant(Hash::type_hash(["LEET"])) + unit.constant(&hash!(LEET)) .context("missing constant")? .to_value()? .as_signed()?, @@ -39,7 +39,7 @@ fn test_get_const_re_export() -> Result<()> { let unit = prepare(&mut sources).with_context(&context).build()?; assert_eq!( - unit.constant(Hash::type_hash(["LEET"])) + unit.constant(&hash!(LEET)) .context("missing constant")? .to_value()? .as_signed()?, @@ -63,7 +63,7 @@ fn test_get_const_nested() -> Result<()> { let unit = prepare(&mut sources).with_context(&context).build()?; assert_eq!( - unit.constant(Hash::type_hash(["inner", "LEET"])) + unit.constant(&hash!(inner::LEET)) .expect("successful lookup") .to_value() .expect("could not allocate value")