git.delta.rocks / jrsonnet / refs/commits / 5e6d5ee048e2

difftreelog

refactor unify throw & throw_runtime

Yaroslav Bolyukin2022-10-17parent: #b8bef13.patch.diff
in: master

13 files changed

modifiedcrates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/error.rs
+++ b/crates/jrsonnet-evaluator/src/error.rs
@@ -266,14 +266,13 @@
 
 #[macro_export]
 macro_rules! throw {
-	($e: expr) => {
-		return Err($e.into())
+	($w:ident$(::$i:ident)*$(($($tt:tt)*))?) => {
+		return Err($w$(::$i)*$(($($tt)*))?.into())
 	};
-}
-
-#[macro_export]
-macro_rules! throw_runtime {
-	($($tt:tt)*) => {
-		return Err($crate::error::Error::RuntimeError(format!($($tt)*).into()).into())
+	($l:literal) => {
+		return Err($crate::error::Error::RuntimeError($l.into()).into())
+	};
+	($l:literal, $($tt:tt)*) => {
+		return Err($crate::error::Error::RuntimeError(format!($l, $($tt)*).into()).into())
 	};
 }
modifiedcrates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
@@ -32,7 +32,7 @@
 		Destruct::Array { start, rest, end } => {
 			use jrsonnet_parser::DestructRest;
 
-			use crate::{throw_runtime, val::ArrValue};
+			use crate::{throw, val::ArrValue};
 
 			#[derive(Trace)]
 			struct DataThunk {
@@ -47,14 +47,14 @@
 					let v = self.parent.evaluate(s)?;
 					let arr = match v {
 						Val::Arr(a) => a,
-						_ => throw_runtime!("expected array"),
+						_ => throw!("expected array"),
 					};
 					if !self.has_rest {
 						if arr.len() != self.min_len {
-							throw_runtime!("expected {} elements, got {}", self.min_len, arr.len())
+							throw!("expected {} elements, got {}", self.min_len, arr.len())
 						}
 					} else if arr.len() < self.min_len {
-						throw_runtime!(
+						throw!(
 							"expected at least {} elements, but array was only {}",
 							self.min_len,
 							arr.len()
@@ -163,7 +163,7 @@
 		}
 		#[cfg(feature = "exp-destruct")]
 		Destruct::Object { fields, rest } => {
-			use crate::{obj::ObjValue, throw_runtime};
+			use crate::{obj::ObjValue, throw};
 
 			#[derive(Trace)]
 			struct DataThunk {
@@ -178,17 +178,17 @@
 					let v = self.parent.evaluate(s)?;
 					let obj = match v {
 						Val::Obj(o) => o,
-						_ => throw_runtime!("expected object"),
+						_ => throw!("expected object"),
 					};
 					for field in &self.field_names {
 						if !obj.has_field_ex(field.clone(), true) {
-							throw_runtime!("missing field: {}", field);
+							throw!("missing field: {}", field);
 						}
 					}
 					if !self.has_rest {
 						let len = obj.len();
 						if len != self.field_names.len() {
-							throw_runtime!("too many fields, and rest not found");
+							throw!("too many fields, and rest not found");
 						}
 					}
 					Ok(obj)
modifiedcrates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate/operator.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/operator.rs
@@ -150,13 +150,13 @@
 		(Num(v1), BitXor, Num(v2)) => Num(f64::from((*v1 as i32) ^ (*v2 as i32))),
 		(Num(v1), Lhs, Num(v2)) => {
 			if *v2 < 0.0 {
-				throw!(RuntimeError("shift by negative exponent".into()))
+				throw!("shift by negative exponent")
 			}
 			Num(f64::from((*v1 as i32) << (*v2 as i32)))
 		}
 		(Num(v1), Rhs, Num(v2)) => {
 			if *v2 < 0.0 {
-				throw!(RuntimeError("shift by negative exponent".into()))
+				throw!("shift by negative exponent")
 			}
 			Num(f64::from((*v1 as i32) >> (*v2 as i32)))
 		}
modifiedcrates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/integrations/serde.rs
+++ b/crates/jrsonnet-evaluator/src/integrations/serde.rs
@@ -72,7 +72,7 @@
 				}
 				Self::Object(out)
 			}
-			Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),
+			Val::Func(_) => throw!("tried to manifest function"),
 		})
 	}
 }
modifiedcrates/jrsonnet-evaluator/src/stdlib/format.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/stdlib/format.rs
+++ b/crates/jrsonnet-evaluator/src/stdlib/format.rs
@@ -591,9 +591,7 @@
 			),
 			Val::Str(s) => {
 				if s.chars().count() != 1 {
-					throw!(RuntimeError(
-						format!("%c expected 1 char string, got {}", s.chars().count()).into(),
-					));
+					throw!("%c expected 1 char string, got {}", s.chars().count(),);
 				}
 				tmp_out.push_str(&s);
 			}
modifiedcrates/jrsonnet-evaluator/src/stdlib/manifest.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/stdlib/manifest.rs
+++ b/crates/jrsonnet-evaluator/src/stdlib/manifest.rs
@@ -341,7 +341,7 @@
 				}
 			}
 		}
-		Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),
+		Val::Func(_) => throw!("tried to manifest function"),
 	}
 	Ok(())
 }
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/typed/conversions.rs
1use std::ops::Deref;23use jrsonnet_gcmodule::Cc;4use jrsonnet_interner::{IBytes, IStr};5pub use jrsonnet_macros::Typed;6use jrsonnet_types::{ComplexValType, ValType};78use crate::{9	error::{Error::*, Result},10	function::{FuncDesc, FuncVal},11	throw,12	typed::CheckType,13	val::{ArrValue, IndexableVal},14	ObjValue, ObjValueBuilder, State, Val,15};1617pub trait TypedObj: Typed {18	fn serialize(self, s: State, out: &mut ObjValueBuilder) -> Result<()>;19	fn parse(obj: &ObjValue, s: State) -> Result<Self>;20	fn into_object(self, s: State) -> Result<ObjValue> {21		let mut builder = ObjValueBuilder::new();22		self.serialize(s, &mut builder)?;23		Ok(builder.build())24	}25}2627pub trait Typed: Sized {28	const TYPE: &'static ComplexValType;29	fn into_untyped(typed: Self, s: State) -> Result<Val>;30	fn from_untyped(untyped: Val, s: State) -> Result<Self>;31}3233macro_rules! impl_int {34	($($ty:ty)*) => {$(35		impl Typed for $ty {36			const TYPE: &'static ComplexValType =37				&ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64));38			fn from_untyped(value: Val, s: State) -> Result<Self> {39				<Self as Typed>::TYPE.check(s, &value)?;40				match value {41					Val::Num(n) => {42						#[allow(clippy::float_cmp)]43						if n.trunc() != n {44							throw!(RuntimeError(45								format!(46									"cannot convert number with fractional part to {}",47									stringify!($ty)48								)49								.into()50							))51						}52						Ok(n as Self)53					}54					_ => unreachable!(),55				}56			}57			fn into_untyped(value: Self, _: State) -> Result<Val> {58				Ok(Val::Num(value as f64))59			}60		}61	)*};62}6364impl_int!(i8 u8 i16 u16 i32 u32);6566macro_rules! impl_bounded_int {67	($($name:ident = $ty:ty)*) => {$(68		#[derive(Clone, Copy)]69		pub struct $name<const MIN: $ty, const MAX: $ty>($ty);70		impl<const MIN: $ty, const MAX: $ty> $name<MIN, MAX> {71			pub const fn new(value: $ty) -> Option<$name<MIN, MAX>> {72				if value >= MIN && value <= MAX {73					Some(Self(value))74				} else {75					None76				}77			}78			pub const fn value(self) -> $ty {79				self.080			}81		}82		impl<const MIN: $ty, const MAX: $ty> Deref for $name<MIN, MAX> {83			type Target = $ty;84			fn deref(&self) -> &Self::Target {85				&self.086			}87		}8889		impl<const MIN: $ty, const MAX: $ty> Typed for $name<MIN, MAX> {90			const TYPE: &'static ComplexValType =91				&ComplexValType::BoundedNumber(92					Some(MIN as f64),93					Some(MAX as f64),94				);9596			fn from_untyped(value: Val, s: State) -> Result<Self> {97				<Self as Typed>::TYPE.check(s, &value)?;98				match value {99					Val::Num(n) => {100						#[allow(clippy::float_cmp)]101						if n.trunc() != n {102							throw!(RuntimeError(103								format!(104									"cannot convert number with fractional part to {}",105									stringify!($ty)106								)107								.into()108							))109						}110						Ok(Self(n as $ty))111					}112					_ => unreachable!(),113				}114			}115116			fn into_untyped(value: Self, _: State) -> Result<Val> {117				Ok(Val::Num(value.0 as f64))118			}119		}120	)*};121}122123impl_bounded_int!(124	BoundedI8 = i8125	BoundedI16 = i16126	BoundedI32 = i32127	BoundedI64 = i64128	BoundedUsize = usize129);130131impl Typed for f64 {132	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);133134	fn into_untyped(value: Self, _: State) -> Result<Val> {135		Ok(Val::Num(value))136	}137138	fn from_untyped(value: Val, s: State) -> Result<Self> {139		<Self as Typed>::TYPE.check(s, &value)?;140		match value {141			Val::Num(n) => Ok(n),142			_ => unreachable!(),143		}144	}145}146147pub struct PositiveF64(pub f64);148impl Typed for PositiveF64 {149	const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None);150151	fn into_untyped(value: Self, _: State) -> Result<Val> {152		Ok(Val::Num(value.0))153	}154155	fn from_untyped(value: Val, s: State) -> Result<Self> {156		<Self as Typed>::TYPE.check(s, &value)?;157		match value {158			Val::Num(n) => Ok(Self(n)),159			_ => unreachable!(),160		}161	}162}163impl Typed for usize {164	// It is possible to store 54 bits of precision in f64, but leaving u32::MAX here for compatibility165	const TYPE: &'static ComplexValType =166		&ComplexValType::BoundedNumber(Some(0.0), Some(u32::MAX as f64));167168	fn into_untyped(value: Self, _: State) -> Result<Val> {169		if value > u32::MAX as Self {170			throw!(RuntimeError("number is too large".into()))171		}172		Ok(Val::Num(value as f64))173	}174175	fn from_untyped(value: Val, s: State) -> Result<Self> {176		<Self as Typed>::TYPE.check(s, &value)?;177		match value {178			Val::Num(n) => {179				#[allow(clippy::float_cmp)]180				if n.trunc() != n {181					throw!(RuntimeError(182						"cannot convert number with fractional part to usize".into()183					))184				}185				Ok(n as Self)186			}187			_ => unreachable!(),188		}189	}190}191192impl Typed for IStr {193	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);194195	fn into_untyped(value: Self, _: State) -> Result<Val> {196		Ok(Val::Str(value))197	}198199	fn from_untyped(value: Val, s: State) -> Result<Self> {200		<Self as Typed>::TYPE.check(s, &value)?;201		match value {202			Val::Str(s) => Ok(s),203			_ => unreachable!(),204		}205	}206}207208impl Typed for String {209	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);210211	fn into_untyped(value: Self, _: State) -> Result<Val> {212		Ok(Val::Str(value.into()))213	}214215	fn from_untyped(value: Val, s: State) -> Result<Self> {216		<Self as Typed>::TYPE.check(s, &value)?;217		match value {218			Val::Str(s) => Ok(s.to_string()),219			_ => unreachable!(),220		}221	}222}223224impl Typed for char {225	const TYPE: &'static ComplexValType = &ComplexValType::Char;226227	fn into_untyped(value: Self, _: State) -> Result<Val> {228		Ok(Val::Str(value.to_string().into()))229	}230231	fn from_untyped(value: Val, s: State) -> Result<Self> {232		<Self as Typed>::TYPE.check(s, &value)?;233		match value {234			Val::Str(s) => Ok(s.chars().next().unwrap()),235			_ => unreachable!(),236		}237	}238}239240impl<T> Typed for Vec<T>241where242	T: Typed,243{244	const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE);245246	fn into_untyped(value: Self, s: State) -> Result<Val> {247		let mut o = Vec::with_capacity(value.len());248		for i in value {249			o.push(T::into_untyped(i, s.clone())?);250		}251		Ok(Val::Arr(o.into()))252	}253254	fn from_untyped(value: Val, s: State) -> Result<Self> {255		<Self as Typed>::TYPE.check(s.clone(), &value)?;256		match value {257			Val::Arr(a) => {258				let mut o = Self::with_capacity(a.len());259				for i in a.iter(s.clone()) {260					o.push(T::from_untyped(i?, s.clone())?);261				}262				Ok(o)263			}264			_ => unreachable!(),265		}266	}267}268269/// To be used in Vec<Any>270/// Regular Val can't be used here, because it has wrong `TryFrom::Error` type271#[derive(Clone)]272pub struct Any(pub Val);273274impl Typed for Any {275	const TYPE: &'static ComplexValType = &ComplexValType::Any;276277	fn into_untyped(value: Self, _: State) -> Result<Val> {278		Ok(value.0)279	}280281	fn from_untyped(value: Val, _: State) -> Result<Self> {282		Ok(Self(value))283	}284}285286/// Specialization, provides faster `TryFrom<VecVal>` for Val287pub struct VecVal(pub Cc<Vec<Val>>);288289impl Typed for VecVal {290	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);291292	fn into_untyped(value: Self, _: State) -> Result<Val> {293		Ok(Val::Arr(ArrValue::Eager(value.0)))294	}295296	fn from_untyped(value: Val, s: State) -> Result<Self> {297		<Self as Typed>::TYPE.check(s.clone(), &value)?;298		match value {299			Val::Arr(a) => Ok(Self(a.evaluated(s)?)),300			_ => unreachable!(),301		}302	}303}304305/// Specialization306impl Typed for IBytes {307	const TYPE: &'static ComplexValType =308		&ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0)));309310	fn into_untyped(value: Self, _: State) -> Result<Val> {311		Ok(Val::Arr(ArrValue::Bytes(value)))312	}313314	fn from_untyped(value: Val, s: State) -> Result<Self> {315		if let Val::Arr(ArrValue::Bytes(bytes)) = value {316			return Ok(bytes);317		}318		<Self as Typed>::TYPE.check(s.clone(), &value)?;319		match value {320			Val::Arr(a) => {321				let mut out = Vec::with_capacity(a.len());322				for e in a.iter(s.clone()) {323					let r = e?;324					out.push(u8::from_untyped(r, s.clone())?);325				}326				Ok(out.as_slice().into())327			}328			_ => unreachable!(),329		}330	}331}332333pub struct M1;334impl Typed for M1 {335	const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0));336337	fn into_untyped(_: Self, _: State) -> Result<Val> {338		Ok(Val::Num(-1.0))339	}340341	fn from_untyped(value: Val, s: State) -> Result<Self> {342		<Self as Typed>::TYPE.check(s, &value)?;343		Ok(Self)344	}345}346347macro_rules! decl_either {348	($($name: ident, $($id: ident)*);*) => {$(349		pub enum $name<$($id),*> {350			$($id($id)),*351		}352		impl<$($id),*> Typed for $name<$($id),*>353		where354			$($id: Typed,)*355		{356			const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]);357358			fn into_untyped(value: Self, s: State) -> Result<Val> {359				match value {$(360					$name::$id(v) => $id::into_untyped(v, s)361				),*}362			}363364			fn from_untyped(value: Val, s: State) -> Result<Self> {365				$(366					if $id::TYPE.check(s.clone(), &value).is_ok() {367						$id::from_untyped(value, s.clone()).map(Self::$id)368					} else369				)* {370					<Self as Typed>::TYPE.check(s, &value)?;371					unreachable!()372				}373			}374		}375	)*}376}377decl_either!(378	Either1, A;379	Either2, A B;380	Either3, A B C;381	Either4, A B C D;382	Either5, A B C D E;383	Either6, A B C D E F;384	Either7, A B C D E F G385);386#[macro_export]387macro_rules! Either {388	($a:ty) => {Either1<$a>};389	($a:ty, $b:ty) => {Either2<$a, $b>};390	($a:ty, $b:ty, $c:ty) => {Either3<$a, $b, $c>};391	($a:ty, $b:ty, $c:ty, $d:ty) => {Either4<$a, $b, $c, $d>};392	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty) => {Either5<$a, $b, $c, $d, $e>};393	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty) => {Either6<$a, $b, $c, $d, $e, $f>};394	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty, $g:ty) => {Either7<$a, $b, $c, $d, $e, $f, $g>};395}396pub use Either;397398pub type MyType = Either![u32, f64, String];399400impl Typed for ArrValue {401	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);402403	fn into_untyped(value: Self, _: State) -> Result<Val> {404		Ok(Val::Arr(value))405	}406407	fn from_untyped(value: Val, s: State) -> Result<Self> {408		<Self as Typed>::TYPE.check(s, &value)?;409		match value {410			Val::Arr(a) => Ok(a),411			_ => unreachable!(),412		}413	}414}415416impl Typed for FuncVal {417	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);418419	fn into_untyped(value: Self, _: State) -> Result<Val> {420		Ok(Val::Func(value))421	}422423	fn from_untyped(value: Val, s: State) -> Result<Self> {424		<Self as Typed>::TYPE.check(s, &value)?;425		match value {426			Val::Func(a) => Ok(a),427			_ => unreachable!(),428		}429	}430}431432impl Typed for Cc<FuncDesc> {433	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);434435	fn into_untyped(value: Self, _: State) -> Result<Val> {436		Ok(Val::Func(FuncVal::Normal(value)))437	}438439	fn from_untyped(value: Val, s: State) -> Result<Self> {440		<Self as Typed>::TYPE.check(s, &value)?;441		match value {442			Val::Func(FuncVal::Normal(desc)) => Ok(desc),443			Val::Func(_) => throw!(RuntimeError("expected normal function, not builtin".into())),444			_ => unreachable!(),445		}446	}447}448449impl Typed for ObjValue {450	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Obj);451452	fn into_untyped(value: Self, _: State) -> Result<Val> {453		Ok(Val::Obj(value))454	}455456	fn from_untyped(value: Val, s: State) -> Result<Self> {457		<Self as Typed>::TYPE.check(s, &value)?;458		match value {459			Val::Obj(a) => Ok(a),460			_ => unreachable!(),461		}462	}463}464465impl Typed for bool {466	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool);467468	fn into_untyped(value: Self, _: State) -> Result<Val> {469		Ok(Val::Bool(value))470	}471472	fn from_untyped(value: Val, s: State) -> Result<Self> {473		<Self as Typed>::TYPE.check(s, &value)?;474		match value {475			Val::Bool(a) => Ok(a),476			_ => unreachable!(),477		}478	}479}480impl Typed for IndexableVal {481	const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[482		&ComplexValType::Simple(ValType::Arr),483		&ComplexValType::Simple(ValType::Str),484	]);485486	fn into_untyped(value: Self, _: State) -> Result<Val> {487		match value {488			IndexableVal::Str(s) => Ok(Val::Str(s)),489			IndexableVal::Arr(a) => Ok(Val::Arr(a)),490		}491	}492493	fn from_untyped(value: Val, s: State) -> Result<Self> {494		<Self as Typed>::TYPE.check(s, &value)?;495		value.into_indexable()496	}497}498499pub struct Null;500impl Typed for Null {501	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null);502503	fn into_untyped(_: Self, _: State) -> Result<Val> {504		Ok(Val::Null)505	}506507	fn from_untyped(value: Val, s: State) -> Result<Self> {508		<Self as Typed>::TYPE.check(s, &value)?;509		Ok(Self)510	}511}
after · crates/jrsonnet-evaluator/src/typed/conversions.rs
1use std::ops::Deref;23use jrsonnet_gcmodule::Cc;4use jrsonnet_interner::{IBytes, IStr};5pub use jrsonnet_macros::Typed;6use jrsonnet_types::{ComplexValType, ValType};78use crate::{9	error::Result,10	function::{FuncDesc, FuncVal},11	throw,12	typed::CheckType,13	val::{ArrValue, IndexableVal},14	ObjValue, ObjValueBuilder, State, Val,15};1617pub trait TypedObj: Typed {18	fn serialize(self, s: State, out: &mut ObjValueBuilder) -> Result<()>;19	fn parse(obj: &ObjValue, s: State) -> Result<Self>;20	fn into_object(self, s: State) -> Result<ObjValue> {21		let mut builder = ObjValueBuilder::new();22		self.serialize(s, &mut builder)?;23		Ok(builder.build())24	}25}2627pub trait Typed: Sized {28	const TYPE: &'static ComplexValType;29	fn into_untyped(typed: Self, s: State) -> Result<Val>;30	fn from_untyped(untyped: Val, s: State) -> Result<Self>;31}3233macro_rules! impl_int {34	($($ty:ty)*) => {$(35		impl Typed for $ty {36			const TYPE: &'static ComplexValType =37				&ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64));38			fn from_untyped(value: Val, s: State) -> Result<Self> {39				<Self as Typed>::TYPE.check(s, &value)?;40				match value {41					Val::Num(n) => {42						#[allow(clippy::float_cmp)]43						if n.trunc() != n {44							throw!(45								"cannot convert number with fractional part to {}",46								stringify!($ty)47							)48						}49						Ok(n as Self)50					}51					_ => unreachable!(),52				}53			}54			fn into_untyped(value: Self, _: State) -> Result<Val> {55				Ok(Val::Num(value as f64))56			}57		}58	)*};59}6061impl_int!(i8 u8 i16 u16 i32 u32);6263macro_rules! impl_bounded_int {64	($($name:ident = $ty:ty)*) => {$(65		#[derive(Clone, Copy)]66		pub struct $name<const MIN: $ty, const MAX: $ty>($ty);67		impl<const MIN: $ty, const MAX: $ty> $name<MIN, MAX> {68			pub const fn new(value: $ty) -> Option<$name<MIN, MAX>> {69				if value >= MIN && value <= MAX {70					Some(Self(value))71				} else {72					None73				}74			}75			pub const fn value(self) -> $ty {76				self.077			}78		}79		impl<const MIN: $ty, const MAX: $ty> Deref for $name<MIN, MAX> {80			type Target = $ty;81			fn deref(&self) -> &Self::Target {82				&self.083			}84		}8586		impl<const MIN: $ty, const MAX: $ty> Typed for $name<MIN, MAX> {87			const TYPE: &'static ComplexValType =88				&ComplexValType::BoundedNumber(89					Some(MIN as f64),90					Some(MAX as f64),91				);9293			fn from_untyped(value: Val, s: State) -> Result<Self> {94				<Self as Typed>::TYPE.check(s, &value)?;95				match value {96					Val::Num(n) => {97						#[allow(clippy::float_cmp)]98						if n.trunc() != n {99							throw!(100								"cannot convert number with fractional part to {}",101								stringify!($ty)102							)103						}104						Ok(Self(n as $ty))105					}106					_ => unreachable!(),107				}108			}109110			fn into_untyped(value: Self, _: State) -> Result<Val> {111				Ok(Val::Num(value.0 as f64))112			}113		}114	)*};115}116117impl_bounded_int!(118	BoundedI8 = i8119	BoundedI16 = i16120	BoundedI32 = i32121	BoundedI64 = i64122	BoundedUsize = usize123);124125impl Typed for f64 {126	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);127128	fn into_untyped(value: Self, _: State) -> Result<Val> {129		Ok(Val::Num(value))130	}131132	fn from_untyped(value: Val, s: State) -> Result<Self> {133		<Self as Typed>::TYPE.check(s, &value)?;134		match value {135			Val::Num(n) => Ok(n),136			_ => unreachable!(),137		}138	}139}140141pub struct PositiveF64(pub f64);142impl Typed for PositiveF64 {143	const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None);144145	fn into_untyped(value: Self, _: State) -> Result<Val> {146		Ok(Val::Num(value.0))147	}148149	fn from_untyped(value: Val, s: State) -> Result<Self> {150		<Self as Typed>::TYPE.check(s, &value)?;151		match value {152			Val::Num(n) => Ok(Self(n)),153			_ => unreachable!(),154		}155	}156}157impl Typed for usize {158	// It is possible to store 54 bits of precision in f64, but leaving u32::MAX here for compatibility159	const TYPE: &'static ComplexValType =160		&ComplexValType::BoundedNumber(Some(0.0), Some(u32::MAX as f64));161162	fn into_untyped(value: Self, _: State) -> Result<Val> {163		if value > u32::MAX as Self {164			throw!("number is too large")165		}166		Ok(Val::Num(value as f64))167	}168169	fn from_untyped(value: Val, s: State) -> Result<Self> {170		<Self as Typed>::TYPE.check(s, &value)?;171		match value {172			Val::Num(n) => {173				#[allow(clippy::float_cmp)]174				if n.trunc() != n {175					throw!("cannot convert number with fractional part to usize")176				}177				Ok(n as Self)178			}179			_ => unreachable!(),180		}181	}182}183184impl Typed for IStr {185	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);186187	fn into_untyped(value: Self, _: State) -> Result<Val> {188		Ok(Val::Str(value))189	}190191	fn from_untyped(value: Val, s: State) -> Result<Self> {192		<Self as Typed>::TYPE.check(s, &value)?;193		match value {194			Val::Str(s) => Ok(s),195			_ => unreachable!(),196		}197	}198}199200impl Typed for String {201	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);202203	fn into_untyped(value: Self, _: State) -> Result<Val> {204		Ok(Val::Str(value.into()))205	}206207	fn from_untyped(value: Val, s: State) -> Result<Self> {208		<Self as Typed>::TYPE.check(s, &value)?;209		match value {210			Val::Str(s) => Ok(s.to_string()),211			_ => unreachable!(),212		}213	}214}215216impl Typed for char {217	const TYPE: &'static ComplexValType = &ComplexValType::Char;218219	fn into_untyped(value: Self, _: State) -> Result<Val> {220		Ok(Val::Str(value.to_string().into()))221	}222223	fn from_untyped(value: Val, s: State) -> Result<Self> {224		<Self as Typed>::TYPE.check(s, &value)?;225		match value {226			Val::Str(s) => Ok(s.chars().next().unwrap()),227			_ => unreachable!(),228		}229	}230}231232impl<T> Typed for Vec<T>233where234	T: Typed,235{236	const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE);237238	fn into_untyped(value: Self, s: State) -> Result<Val> {239		let mut o = Vec::with_capacity(value.len());240		for i in value {241			o.push(T::into_untyped(i, s.clone())?);242		}243		Ok(Val::Arr(o.into()))244	}245246	fn from_untyped(value: Val, s: State) -> Result<Self> {247		<Self as Typed>::TYPE.check(s.clone(), &value)?;248		match value {249			Val::Arr(a) => {250				let mut o = Self::with_capacity(a.len());251				for i in a.iter(s.clone()) {252					o.push(T::from_untyped(i?, s.clone())?);253				}254				Ok(o)255			}256			_ => unreachable!(),257		}258	}259}260261/// To be used in Vec<Any>262/// Regular Val can't be used here, because it has wrong `TryFrom::Error` type263#[derive(Clone)]264pub struct Any(pub Val);265266impl Typed for Any {267	const TYPE: &'static ComplexValType = &ComplexValType::Any;268269	fn into_untyped(value: Self, _: State) -> Result<Val> {270		Ok(value.0)271	}272273	fn from_untyped(value: Val, _: State) -> Result<Self> {274		Ok(Self(value))275	}276}277278/// Specialization, provides faster `TryFrom<VecVal>` for Val279pub struct VecVal(pub Cc<Vec<Val>>);280281impl Typed for VecVal {282	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);283284	fn into_untyped(value: Self, _: State) -> Result<Val> {285		Ok(Val::Arr(ArrValue::Eager(value.0)))286	}287288	fn from_untyped(value: Val, s: State) -> Result<Self> {289		<Self as Typed>::TYPE.check(s.clone(), &value)?;290		match value {291			Val::Arr(a) => Ok(Self(a.evaluated(s)?)),292			_ => unreachable!(),293		}294	}295}296297/// Specialization298impl Typed for IBytes {299	const TYPE: &'static ComplexValType =300		&ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0)));301302	fn into_untyped(value: Self, _: State) -> Result<Val> {303		Ok(Val::Arr(ArrValue::Bytes(value)))304	}305306	fn from_untyped(value: Val, s: State) -> Result<Self> {307		if let Val::Arr(ArrValue::Bytes(bytes)) = value {308			return Ok(bytes);309		}310		<Self as Typed>::TYPE.check(s.clone(), &value)?;311		match value {312			Val::Arr(a) => {313				let mut out = Vec::with_capacity(a.len());314				for e in a.iter(s.clone()) {315					let r = e?;316					out.push(u8::from_untyped(r, s.clone())?);317				}318				Ok(out.as_slice().into())319			}320			_ => unreachable!(),321		}322	}323}324325pub struct M1;326impl Typed for M1 {327	const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0));328329	fn into_untyped(_: Self, _: State) -> Result<Val> {330		Ok(Val::Num(-1.0))331	}332333	fn from_untyped(value: Val, s: State) -> Result<Self> {334		<Self as Typed>::TYPE.check(s, &value)?;335		Ok(Self)336	}337}338339macro_rules! decl_either {340	($($name: ident, $($id: ident)*);*) => {$(341		pub enum $name<$($id),*> {342			$($id($id)),*343		}344		impl<$($id),*> Typed for $name<$($id),*>345		where346			$($id: Typed,)*347		{348			const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]);349350			fn into_untyped(value: Self, s: State) -> Result<Val> {351				match value {$(352					$name::$id(v) => $id::into_untyped(v, s)353				),*}354			}355356			fn from_untyped(value: Val, s: State) -> Result<Self> {357				$(358					if $id::TYPE.check(s.clone(), &value).is_ok() {359						$id::from_untyped(value, s.clone()).map(Self::$id)360					} else361				)* {362					<Self as Typed>::TYPE.check(s, &value)?;363					unreachable!()364				}365			}366		}367	)*}368}369decl_either!(370	Either1, A;371	Either2, A B;372	Either3, A B C;373	Either4, A B C D;374	Either5, A B C D E;375	Either6, A B C D E F;376	Either7, A B C D E F G377);378#[macro_export]379macro_rules! Either {380	($a:ty) => {Either1<$a>};381	($a:ty, $b:ty) => {Either2<$a, $b>};382	($a:ty, $b:ty, $c:ty) => {Either3<$a, $b, $c>};383	($a:ty, $b:ty, $c:ty, $d:ty) => {Either4<$a, $b, $c, $d>};384	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty) => {Either5<$a, $b, $c, $d, $e>};385	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty) => {Either6<$a, $b, $c, $d, $e, $f>};386	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty, $g:ty) => {Either7<$a, $b, $c, $d, $e, $f, $g>};387}388pub use Either;389390pub type MyType = Either![u32, f64, String];391392impl Typed for ArrValue {393	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);394395	fn into_untyped(value: Self, _: State) -> Result<Val> {396		Ok(Val::Arr(value))397	}398399	fn from_untyped(value: Val, s: State) -> Result<Self> {400		<Self as Typed>::TYPE.check(s, &value)?;401		match value {402			Val::Arr(a) => Ok(a),403			_ => unreachable!(),404		}405	}406}407408impl Typed for FuncVal {409	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);410411	fn into_untyped(value: Self, _: State) -> Result<Val> {412		Ok(Val::Func(value))413	}414415	fn from_untyped(value: Val, s: State) -> Result<Self> {416		<Self as Typed>::TYPE.check(s, &value)?;417		match value {418			Val::Func(a) => Ok(a),419			_ => unreachable!(),420		}421	}422}423424impl Typed for Cc<FuncDesc> {425	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);426427	fn into_untyped(value: Self, _: State) -> Result<Val> {428		Ok(Val::Func(FuncVal::Normal(value)))429	}430431	fn from_untyped(value: Val, s: State) -> Result<Self> {432		<Self as Typed>::TYPE.check(s, &value)?;433		match value {434			Val::Func(FuncVal::Normal(desc)) => Ok(desc),435			Val::Func(_) => throw!("expected normal function, not builtin"),436			_ => unreachable!(),437		}438	}439}440441impl Typed for ObjValue {442	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Obj);443444	fn into_untyped(value: Self, _: State) -> Result<Val> {445		Ok(Val::Obj(value))446	}447448	fn from_untyped(value: Val, s: State) -> Result<Self> {449		<Self as Typed>::TYPE.check(s, &value)?;450		match value {451			Val::Obj(a) => Ok(a),452			_ => unreachable!(),453		}454	}455}456457impl Typed for bool {458	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool);459460	fn into_untyped(value: Self, _: State) -> Result<Val> {461		Ok(Val::Bool(value))462	}463464	fn from_untyped(value: Val, s: State) -> Result<Self> {465		<Self as Typed>::TYPE.check(s, &value)?;466		match value {467			Val::Bool(a) => Ok(a),468			_ => unreachable!(),469		}470	}471}472impl Typed for IndexableVal {473	const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[474		&ComplexValType::Simple(ValType::Arr),475		&ComplexValType::Simple(ValType::Str),476	]);477478	fn into_untyped(value: Self, _: State) -> Result<Val> {479		match value {480			IndexableVal::Str(s) => Ok(Val::Str(s)),481			IndexableVal::Arr(a) => Ok(Val::Arr(a)),482		}483	}484485	fn from_untyped(value: Val, s: State) -> Result<Self> {486		<Self as Typed>::TYPE.check(s, &value)?;487		value.into_indexable()488	}489}490491pub struct Null;492impl Typed for Null {493	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null);494495	fn into_untyped(_: Self, _: State) -> Result<Val> {496		Ok(Val::Null)497	}498499	fn from_untyped(value: Val, s: State) -> Result<Self> {500		<Self as Typed>::TYPE.check(s, &value)?;501		Ok(Self)502	}503}
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -629,7 +629,7 @@
 		if num.is_finite() {
 			Ok(Self::Num(num))
 		} else {
-			throw!(RuntimeError("overflow".into()))
+			throw!("overflow")
 		}
 	}
 
@@ -843,14 +843,14 @@
 		(Val::Null, Val::Null) => true,
 		(Val::Str(a), Val::Str(b)) => a == b,
 		(Val::Num(a), Val::Num(b)) => (a - b).abs() <= f64::EPSILON,
-		(Val::Arr(_), Val::Arr(_)) => throw!(RuntimeError(
-			"primitiveEquals operates on primitive types, got array".into(),
-		)),
-		(Val::Obj(_), Val::Obj(_)) => throw!(RuntimeError(
-			"primitiveEquals operates on primitive types, got object".into(),
-		)),
+		(Val::Arr(_), Val::Arr(_)) => {
+			throw!("primitiveEquals operates on primitive types, got array")
+		}
+		(Val::Obj(_), Val::Obj(_)) => {
+			throw!("primitiveEquals operates on primitive types, got object")
+		}
 		(a, b) if is_function_like(a) && is_function_like(b) => {
-			throw!(RuntimeError("cannot test equality of functions".into()))
+			throw!("cannot test equality of functions")
 		}
 		(_, _) => false,
 	})
modifiedcrates/jrsonnet-stdlib/src/arrays.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/arrays.rs
+++ b/crates/jrsonnet-stdlib/src/arrays.rs
@@ -1,7 +1,7 @@
 use jrsonnet_evaluator::{
 	error::Result,
 	function::{builtin, FuncVal},
-	throw_runtime,
+	throw,
 	typed::{Any, BoundedUsize, Typed, VecVal},
 	val::{equals, ArrValue, IndexableVal},
 	IStr, State, Val,
@@ -43,7 +43,7 @@
 				match func.evaluate_simple(s.clone(), &(c.to_string(),))? {
 					Val::Str(o) => out.push_str(&o),
 					Val::Null => continue,
-					_ => throw_runtime!("in std.join all items should be strings"),
+					_ => throw!("in std.join all items should be strings"),
 				};
 			}
 			Ok(IndexableVal::Str(out.into()))
@@ -59,7 +59,7 @@
 						}
 					}
 					Val::Null => continue,
-					_ => throw_runtime!("in std.join all items should be arrays"),
+					_ => throw!("in std.join all items should be arrays"),
 				};
 			}
 			Ok(IndexableVal::Arr(out.into()))
@@ -128,7 +128,7 @@
 				} else if matches!(item, Val::Null) {
 					continue;
 				} else {
-					throw_runtime!("in std.join all items should be arrays");
+					throw!("in std.join all items should be arrays");
 				}
 			}
 
@@ -149,7 +149,7 @@
 				} else if matches!(item, Val::Null) {
 					continue;
 				} else {
-					throw_runtime!("in std.join all items should be strings");
+					throw!("in std.join all items should be strings");
 				}
 			}
 
modifiedcrates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/lib.rs
+++ b/crates/jrsonnet-stdlib/src/lib.rs
@@ -8,7 +8,7 @@
 	error::{Error::*, Result},
 	function::{builtin::Builtin, ArgLike, CallLocation, FuncVal, TlaArg},
 	gc::{GcHashMap, TraceBox},
-	tb, throw_runtime,
+	tb, throw,
 	trace::PathResolver,
 	typed::{Any, Either, Either2, Either4, VecVal, M1},
 	val::{equals, ArrValue},
@@ -500,7 +500,7 @@
 				true
 			}
 		}
-		_ => throw_runtime!("both arguments should be of the same type"),
+		_ => throw!("both arguments should be of the same type"),
 	})
 }
 
@@ -534,7 +534,7 @@
 				true
 			}
 		}
-		_ => throw_runtime!("both arguments should be of the same type"),
+		_ => throw!("both arguments should be of the same type"),
 	})
 }
 
modifiedcrates/jrsonnet-stdlib/src/sort.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/sort.rs
+++ b/crates/jrsonnet-stdlib/src/sort.rs
@@ -1,7 +1,7 @@
 use jrsonnet_evaluator::{
 	error::Result,
 	function::{builtin, FuncVal},
-	throw_runtime,
+	throw,
 	typed::Any,
 	val::ArrValue,
 	State, Val,
@@ -41,9 +41,9 @@
 			(Val::Num(_), SortKeyType::Unknown) => sort_type = SortKeyType::Number,
 			(Val::Str(_), SortKeyType::String) | (Val::Num(_), SortKeyType::Number) => {}
 			(Val::Str(_) | Val::Num(_), _) => {
-				throw_runtime!("sort elements should have the same types")
+				throw!("sort elements should have the same types")
 			}
-			_ => throw_runtime!("sort key should either be a string or a number"),
+			_ => throw!("sort key should either be a string or a number"),
 		}
 	}
 	Ok(sort_type)
modifiedtests/tests/common.rsdiffbeforeafterboth
--- a/tests/tests/common.rs
+++ b/tests/tests/common.rs
@@ -1,7 +1,7 @@
 use jrsonnet_evaluator::{
 	error::Result,
 	function::{builtin, FuncVal},
-	throw_runtime, ObjValueBuilder, State, Thunk, Val,
+	throw, ObjValueBuilder, State, Thunk, Val,
 };
 use jrsonnet_stdlib::StateExt;
 
@@ -11,7 +11,7 @@
 		let a = &$a;
 		let b = &$b;
 		if a != b {
-			::jrsonnet_evaluator::throw_runtime!("assertion failed: a != b\na={:#?}\nb={:#?}", a, b)
+			::jrsonnet_evaluator::throw!("assertion failed: a != b\na={:#?}\nb={:#?}", a, b)
 		}
 	}};
 }
@@ -20,7 +20,7 @@
 macro_rules! ensure {
 	($v:expr $(,)?) => {
 		if !$v {
-			::jrsonnet_evaluator::throw_runtime!("assertion failed: {}", stringify!($v))
+			::jrsonnet_evaluator::throw!("assertion failed: {}", stringify!($v))
 		}
 	};
 }
@@ -29,7 +29,7 @@
 macro_rules! ensure_val_eq {
 	($s:expr, $a:expr, $b:expr) => {{
 		if !::jrsonnet_evaluator::val::equals($s.clone(), &$a.clone(), &$b.clone())? {
-			::jrsonnet_evaluator::throw_runtime!(
+			::jrsonnet_evaluator::throw!(
 				"assertion failed: a != b\na={:#?}\nb={:#?}",
 				$a.to_json(
 					$s.clone(),
@@ -52,7 +52,7 @@
 fn assert_throw(s: State, lazy: Thunk<Val>, message: String) -> Result<bool> {
 	match lazy.evaluate(s) {
 		Ok(_) => {
-			throw_runtime!("expected argument to throw on evaluation, but it returned instead")
+			throw!("expected argument to throw on evaluation, but it returned instead")
 		}
 		Err(e) => {
 			let error = format!("{}", e.error());
modifiedtests/tests/sanity.rsdiffbeforeafterboth
--- a/tests/tests/sanity.rs
+++ b/tests/tests/sanity.rs
@@ -1,4 +1,4 @@
-use jrsonnet_evaluator::{error::Result, throw_runtime, State, Val};
+use jrsonnet_evaluator::{error::Result, throw, State, Val};
 use jrsonnet_stdlib::StateExt;
 
 mod common;
@@ -23,7 +23,7 @@
 
 	{
 		let e = match s.evaluate_snippet("snip".to_owned(), "assert 1 == 2: 'fail'; null") {
-			Ok(_) => throw_runtime!("assertion should fail"),
+			Ok(_) => throw!("assertion should fail"),
 			Err(e) => e,
 		};
 		let e = s.stringify_err(&e);
@@ -31,7 +31,7 @@
 	}
 	{
 		let e = match s.evaluate_snippet("snip".to_owned(), "std.assertEqual(1, 2)") {
-			Ok(_) => throw_runtime!("assertion should fail"),
+			Ok(_) => throw!("assertion should fail"),
 			Err(e) => e,
 		};
 		let e = s.stringify_err(&e);