git.delta.rocks / jrsonnet / refs/commits / ced22d8710e3

difftreelog

refactor Option<&ExprLocation> -> &Option<_>

Yaroslav Bolyukin2021-01-24parent: #a16a15d.patch.diff
in: master

6 files changed

modifiedcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/builtin/mod.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs
@@ -22,7 +22,7 @@
 
 fn std_format(str: IStr, vals: Val) -> Result<Val> {
 	push(
-		&Some(ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0)),
+		Some(&ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0)),
 		|| format!("std.format of {}", str),
 		|| {
 			Ok(match vals {
@@ -34,7 +34,7 @@
 	)
 }
 
-type Builtin = fn(context: Context, loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val>;
+type Builtin = fn(context: Context, loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val>;
 
 type BuiltinsType = HashMap<Box<str>, Builtin>;
 
@@ -78,7 +78,7 @@
 	};
 }
 
-fn builtin_length(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_length(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "length", args, 1, [
 		0, x: ty!((string | object | array));
 	], {
@@ -96,7 +96,7 @@
 	})
 }
 
-fn builtin_type(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_type(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "type", args, 1, [
 		0, x: ty!(any);
 	], {
@@ -106,7 +106,7 @@
 
 fn builtin_make_array(
 	context: Context,
-	_loc: &Option<ExprLocation>,
+	_loc: Option<&ExprLocation>,
 	args: &ArgsDesc,
 ) -> Result<Val> {
 	parse_args!(context, "makeArray", args, 2, [
@@ -126,7 +126,7 @@
 
 fn builtin_codepoint(
 	context: Context,
-	_loc: &Option<ExprLocation>,
+	_loc: Option<&ExprLocation>,
 	args: &ArgsDesc,
 ) -> Result<Val> {
 	parse_args!(context, "codepoint", args, 1, [
@@ -138,7 +138,7 @@
 
 fn builtin_object_fields_ex(
 	context: Context,
-	_loc: &Option<ExprLocation>,
+	_loc: Option<&ExprLocation>,
 	args: &ArgsDesc,
 ) -> Result<Val> {
 	parse_args!(context, "objectFieldsEx", args, 2, [
@@ -157,7 +157,7 @@
 
 fn builtin_object_has_ex(
 	context: Context,
-	_loc: &Option<ExprLocation>,
+	_loc: Option<&ExprLocation>,
 	args: &ArgsDesc,
 ) -> Result<Val> {
 	parse_args!(context, "objectHasEx", args, 3, [
@@ -175,7 +175,7 @@
 }
 
 // faster
-fn builtin_slice(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_slice(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "slice", args, 4, [
 		0, indexable: ty!((string | array));
 		1, index: ty!((number | null));
@@ -216,7 +216,7 @@
 // faster
 fn builtin_primitive_equals(
 	context: Context,
-	_loc: &Option<ExprLocation>,
+	_loc: Option<&ExprLocation>,
 	args: &ArgsDesc,
 ) -> Result<Val> {
 	parse_args!(context, "primitiveEquals", args, 2, [
@@ -228,7 +228,7 @@
 }
 
 // faster
-fn builtin_equals(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_equals(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "equals", args, 2, [
 		0, a: ty!(any);
 		1, b: ty!(any);
@@ -237,7 +237,7 @@
 	})
 }
 
-fn builtin_modulo(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_modulo(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "modulo", args, 2, [
 		0, a: ty!(number) => Val::Num;
 		1, b: ty!(number) => Val::Num;
@@ -246,7 +246,7 @@
 	})
 }
 
-fn builtin_mod(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_mod(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "mod", args, 2, [
 		0, a: ty!((number | string));
 		1, b: ty!(any);
@@ -259,7 +259,7 @@
 	})
 }
 
-fn builtin_floor(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_floor(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "floor", args, 1, [
 		0, x: ty!(number) => Val::Num;
 	], {
@@ -267,7 +267,7 @@
 	})
 }
 
-fn builtin_log(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_log(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "log", args, 1, [
 		0, n: ty!(number) => Val::Num;
 	], {
@@ -275,7 +275,7 @@
 	})
 }
 
-fn builtin_pow(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_pow(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "pow", args, 2, [
 		0, x: ty!(number) => Val::Num;
 		1, n: ty!(number) => Val::Num;
@@ -284,7 +284,7 @@
 	})
 }
 
-fn builtin_ext_var(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_ext_var(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "extVar", args, 1, [
 		0, x: ty!(string) => Val::Str;
 	], {
@@ -292,7 +292,7 @@
 	})
 }
 
-fn builtin_native(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_native(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "native", args, 1, [
 		0, x: ty!(string) => Val::Str;
 	], {
@@ -300,7 +300,7 @@
 	})
 }
 
-fn builtin_filter(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_filter(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "filter", args, 2, [
 		0, func: ty!(function) => Val::Func;
 		1, arr: ty!(array) => Val::Arr;
@@ -318,7 +318,7 @@
 	})
 }
 
-fn builtin_foldl(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_foldl(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "foldl", args, 3, [
 		0, func: ty!(function) => Val::Func;
 		1, arr: ty!(array) => Val::Arr;
@@ -332,7 +332,7 @@
 	})
 }
 
-fn builtin_foldr(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_foldr(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "foldr", args, 3, [
 		0, func: ty!(function) => Val::Func;
 		1, arr: ty!(array) => Val::Arr;
@@ -349,7 +349,7 @@
 #[allow(non_snake_case)]
 fn builtin_sort_impl(
 	context: Context,
-	_loc: &Option<ExprLocation>,
+	_loc: Option<&ExprLocation>,
 	args: &ArgsDesc,
 ) -> Result<Val> {
 	parse_args!(context, "sort", args, 2, [
@@ -364,7 +364,7 @@
 }
 
 // faster
-fn builtin_format(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_format(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "format", args, 2, [
 		0, str: ty!(string) => Val::Str;
 		1, vals: ty!(any)
@@ -373,7 +373,7 @@
 	})
 }
 
-fn builtin_range(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_range(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "range", args, 2, [
 		0, from: ty!(number) => Val::Num;
 		1, to: ty!(number) => Val::Num;
@@ -386,7 +386,7 @@
 	})
 }
 
-fn builtin_char(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_char(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "char", args, 1, [
 		0, n: ty!(number) => Val::Num;
 	], {
@@ -400,7 +400,7 @@
 
 fn builtin_encode_utf8(
 	context: Context,
-	_loc: &Option<ExprLocation>,
+	_loc: Option<&ExprLocation>,
 	args: &ArgsDesc,
 ) -> Result<Val> {
 	parse_args!(context, "encodeUTF8", args, 1, [
@@ -410,7 +410,7 @@
 	})
 }
 
-fn builtin_md5(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_md5(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "md5", args, 1, [
 		0, str: ty!(string) => Val::Str;
 	], {
@@ -418,7 +418,7 @@
 	})
 }
 
-fn builtin_trace(context: Context, loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_trace(context: Context, loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "trace", args, 2, [
 		0, str: ty!(string) => Val::Str;
 		1, rest: ty!(any);
@@ -435,7 +435,7 @@
 	})
 }
 
-fn builtin_base64(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_base64(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "base64", args, 1, [
 		0, input: ty!((string | (Array<number>)));
 	], {
@@ -453,7 +453,7 @@
 	})
 }
 
-fn builtin_join(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_join(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "join", args, 2, [
 		0, sep: ty!((string | array));
 		1, arr: ty!(array) => Val::Arr;
@@ -513,7 +513,7 @@
 // faster
 fn builtin_escape_string_json(
 	context: Context,
-	_loc: &Option<ExprLocation>,
+	_loc: Option<&ExprLocation>,
 	args: &ArgsDesc,
 ) -> Result<Val> {
 	parse_args!(context, "escapeStringJson", args, 1, [
@@ -526,7 +526,7 @@
 // faster
 fn builtin_manifest_json_ex(
 	context: Context,
-	_loc: &Option<ExprLocation>,
+	_loc: Option<&ExprLocation>,
 	args: &ArgsDesc,
 ) -> Result<Val> {
 	parse_args!(context, "manifestJsonEx", args, 2, [
@@ -541,7 +541,7 @@
 }
 
 // faster
-fn builtin_reverse(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_reverse(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "reverse", args, 1, [
 		0, value: ty!(array) => Val::Arr;
 	], {
@@ -549,7 +549,7 @@
 	})
 }
 
-fn builtin_id(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {
+fn builtin_id(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "id", args, 1, [
 		0, v: ty!(any);
 	], {
@@ -560,7 +560,7 @@
 // faster
 fn builtin_str_replace(
 	context: Context,
-	_loc: &Option<ExprLocation>,
+	_loc: Option<&ExprLocation>,
 	args: &ArgsDesc,
 ) -> Result<Val> {
 	parse_args!(context, "strReplace", args, 3, [
@@ -583,10 +583,9 @@
 	})
 }
 
-#[allow(clippy::cognitive_complexity)]
 pub fn call_builtin(
 	context: Context,
-	loc: &Option<ExprLocation>,
+	loc: Option<&ExprLocation>,
 	name: &str,
 	args: &ArgsDesc,
 ) -> Result<Val> {
modifiedcrates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate.rs
@@ -385,7 +385,7 @@
 	context: Context,
 	value: &LocExpr,
 	args: &ArgsDesc,
-	loc: &Option<ExprLocation>,
+	loc: Option<&ExprLocation>,
 	tailstrict: bool,
 ) -> Result<Val> {
 	let value = evaluate(context.clone(), value)?;
@@ -430,7 +430,7 @@
 		BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, v1, *o, v2)?,
 		UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?,
 		Var(name) => push(
-			loc,
+			loc.as_ref(),
 			|| format!("variable <{}>", name),
 			|| Ok(context.binding(name.clone())?.evaluate()?),
 		)?,
@@ -448,7 +448,7 @@
 				(Val::Obj(v), Val::Str(s)) => {
 					let sn = s.clone();
 					push(
-						loc,
+						loc.as_ref(),
 						|| format!("field <{}> access", sn),
 						|| {
 							if let Some(v) = v.get(s.clone())? {
@@ -540,14 +540,14 @@
 			&evaluate(context.clone(), s)?,
 			&Val::Obj(evaluate_object(context, t)?),
 		)?,
-		Apply(value, args, tailstrict) => evaluate_apply(context, value, args, loc, *tailstrict)?,
+		Apply(value, args, tailstrict) => evaluate_apply(context, value, args, loc.as_ref(), *tailstrict)?,
 		Function(params, body) => {
 			evaluate_method(context, "anonymous".into(), params.clone(), body.clone())
 		}
 		Intrinsic(name) => Val::Func(Rc::new(FuncVal::Intrinsic(name.clone()))),
 		AssertExpr(AssertStmt(value, msg), returned) => {
 			let assertion_result = push(
-				&value.1,
+				value.1.as_ref(),
 				|| "assertion condition".to_owned(),
 				|| {
 					evaluate(context.clone(), value)?
@@ -558,7 +558,7 @@
 				evaluate(context, returned)?
 			} else {
 				push(
-					&value.1,
+					value.1.as_ref(),
 					|| "assertion failure".to_owned(),
 					|| {
 						if let Some(msg) = msg {
@@ -571,7 +571,7 @@
 			}
 		}
 		ErrorStmt(e) => push(
-			loc,
+			loc.as_ref(),
 			|| "error statement".to_owned(),
 			|| {
 				throw!(RuntimeError(
@@ -585,7 +585,7 @@
 			cond_else,
 		} => {
 			if push(
-				loc,
+				loc.as_ref(),
 				|| "if condition".to_owned(),
 				|| evaluate(context.clone(), &cond.0)?.try_cast_bool("in if condition"),
 			)? {
@@ -605,7 +605,7 @@
 			let import_location = Rc::make_mut(&mut tmp);
 			import_location.pop();
 			push(
-				loc,
+				loc.as_ref(),
 				|| format!("import {:?}", path),
 				|| with_state(|s| s.import_file(import_location, path)),
 			)?
modifiedcrates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/function.rs
+++ b/crates/jrsonnet-evaluator/src/function.rs
@@ -160,7 +160,7 @@
 					throw!(IntrinsicArgumentReorderingIsNotSupportedYet);
 				}
 			}
-			let $name = push(&None, || format!("evaluating argument"), || {
+			let $name = push(None, || format!("evaluating argument"), || {
 				let value = evaluate($ctx.clone(), &$name.1)?;
 				$ty.check(&value)?;
 				Ok(value)
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -128,7 +128,7 @@
 	EVAL_STATE.with(|s| f(s.borrow().as_ref().unwrap()))
 }
 pub(crate) fn push<T>(
-	e: &Option<ExprLocation>,
+	e: Option<&ExprLocation>,
 	frame_desc: impl FnOnce() -> String,
 	f: impl FnOnce() -> Result<T>,
 ) -> Result<T> {
modifiedcrates/jrsonnet-evaluator/src/typed.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/typed.rs
1use std::{fmt::Display, rc::Rc};23use crate::{4	error::{Error, LocError, Result},5	push, Val,6};7use jrsonnet_parser::ExprLocation;8use jrsonnet_types::{ComplexValType, ValType};9use thiserror::Error;1011#[derive(Debug, Error, Clone)]12pub enum TypeError {13	#[error("expected {0}, got {1}")]14	ExpectedGot(ComplexValType, ValType),15	#[error("missing property {0} from {1:?}")]16	MissingProperty(Rc<str>, ComplexValType),17	#[error("every failed from {0}:\n{1}")]18	UnionFailed(ComplexValType, TypeLocErrorList),19	#[error("number out of bounds: {0} not in {1:?}..{2:?}")]20	BoundsFailed(f64, Option<f64>, Option<f64>),21}22impl From<TypeError> for LocError {23	fn from(e: TypeError) -> Self {24		Error::TypeError(e.into()).into()25	}26}2728#[derive(Debug, Clone)]29pub struct TypeLocError(Box<TypeError>, ValuePathStack);30impl From<TypeError> for TypeLocError {31	fn from(e: TypeError) -> Self {32		TypeLocError(Box::new(e), ValuePathStack(Vec::new()))33	}34}35impl From<TypeLocError> for LocError {36	fn from(e: TypeLocError) -> Self {37		Error::TypeError(e).into()38	}39}40impl Display for TypeLocError {41	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {42		write!(f, "{}", self.0)?;43		if !(self.1).0.is_empty() {44			write!(f, "at {}", self.1)?;45		}46		Ok(())47	}48}4950#[derive(Debug, Clone)]51pub struct TypeLocErrorList(Vec<TypeLocError>);52impl Display for TypeLocErrorList {53	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {54		use std::fmt::Write;55		let mut out = String::new();56		for (i, err) in self.0.iter().enumerate() {57			if i != 0 {58				writeln!(f)?;59			}60			out.clear();61			write!(out, "{}", err)?;6263			for (i, line) in out.lines().enumerate() {64				if line.trim().len() == 0 {65					continue;66				}67				if i != 0 {68					writeln!(f)?;69					write!(f, "    ")?;70				} else {71					write!(f, "  - ")?;72				}73				write!(f, "{}", line)?;74			}75		}76		Ok(())77	}78}7980fn push_type(81	location: &Option<ExprLocation>,82	error_reason: impl Fn() -> String,83	path: impl Fn() -> ValuePathItem,84	item: impl Fn() -> Result<()>,85) -> Result<()> {86	push(location, error_reason, || match item() {87		Ok(_) => Ok(()),88		Err(mut e) => {89			if let Error::TypeError(e) = &mut e.error_mut() {90				(e.1).0.push(path())91			}92			Err(e)93		}94	})95}9697// TODO: check_fast for fast path of union type checking98pub trait CheckType {99	fn check(&self, value: &Val) -> Result<()>;100}101102impl CheckType for ValType {103	fn check(&self, value: &Val) -> Result<()> {104		let got = value.value_type();105		if got != *self {106			let loc_error: TypeLocError = TypeError::ExpectedGot((*self).into(), got).into();107			return Err(loc_error.into());108		}109		Ok(())110	}111}112113#[derive(Clone, Debug)]114enum ValuePathItem {115	Field(Rc<str>),116	Index(u64),117}118impl Display for ValuePathItem {119	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {120		match self {121			ValuePathItem::Field(name) => write!(f, ".{}", name)?,122			ValuePathItem::Index(idx) => write!(f, "[{}]", idx)?,123		}124		Ok(())125	}126}127128#[derive(Clone, Debug)]129struct ValuePathStack(Vec<ValuePathItem>);130impl Display for ValuePathStack {131	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {132		write!(f, "self")?;133		for elem in self.0.iter().rev() {134			write!(f, "{}", elem)?;135		}136		Ok(())137	}138}139140impl CheckType for ComplexValType {141	fn check(&self, value: &Val) -> Result<()> {142		match self {143			ComplexValType::Any => Ok(()),144			ComplexValType::Simple(s) => s.check(value),145			ComplexValType::Char => match value {146				Val::Str(s) if s.len() == 1 || s.chars().count() == 1 => Ok(()),147				v => Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),148			},149			ComplexValType::BoundedNumber(from, to) => {150				if let Val::Num(n) = value {151					if from.map(|from| from > *n).unwrap_or(false)152						|| to.map(|to| to <= *n).unwrap_or(false)153					{154						return Err(TypeError::BoundsFailed(*n, from.clone(), to.clone()).into());155					}156					Ok(())157				} else {158					Err(TypeError::ExpectedGot(self.clone(), value.value_type()).into())159				}160			}161			ComplexValType::Array(elem_type) => match value {162				Val::Arr(a) => {163					for (i, item) in a.iter().enumerate() {164						push_type(165							&None,166							|| format!("array index {}", i),167							|| ValuePathItem::Index(i as u64),168							|| Ok(elem_type.check(&item.clone()?)?),169						)?;170					}171					Ok(())172				}173				v => return Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),174			},175			ComplexValType::ArrayRef(elem_type) => match value {176				Val::Arr(a) => {177					for (i, item) in a.iter().enumerate() {178						push_type(179							&None,180							|| format!("array index {}", i),181							|| ValuePathItem::Index(i as u64),182							|| Ok(elem_type.check(&item.clone()?)?),183						)?;184					}185					Ok(())186				}187				v => return Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),188			},189			ComplexValType::ObjectRef(elems) => match value {190				Val::Obj(obj) => {191					for (k, v) in elems.iter() {192						if let Some(got_v) = obj.get((*k).into())? {193							push_type(194								&None,195								|| format!("property {}", k),196								|| ValuePathItem::Field((*k).into()),197								|| v.check(&got_v),198							)?199						} else {200							return Err(201								TypeError::MissingProperty((*k).into(), self.clone()).into()202							);203						}204					}205					return Ok(());206				}207				v => return Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),208			},209			ComplexValType::Union(types) => {210				let mut errors = Vec::new();211				for ty in types.iter() {212					match ty.check(value) {213						Ok(()) => {214							return Ok(());215						}216						Err(e) => match e.error() {217							Error::TypeError(e) => errors.push(e.clone()),218							_ => return Err(e),219						},220					}221				}222				return Err(TypeError::UnionFailed(self.clone(), TypeLocErrorList(errors)).into());223			}224			ComplexValType::UnionRef(types) => {225				let mut errors = Vec::new();226				for ty in types.iter() {227					match ty.check(value) {228						Ok(()) => {229							return Ok(());230						}231						Err(e) => match e.error() {232							Error::TypeError(e) => errors.push(e.clone()),233							_ => return Err(e),234						},235					}236				}237				return Err(TypeError::UnionFailed(self.clone(), TypeLocErrorList(errors)).into());238			}239			ComplexValType::Sum(types) => {240				for ty in types.iter() {241					ty.check(value)?242				}243				Ok(())244			}245			ComplexValType::SumRef(types) => {246				for ty in types.iter() {247					ty.check(value)?248				}249				Ok(())250			}251		}252	}253}
after · crates/jrsonnet-evaluator/src/typed.rs
1use std::{fmt::Display, rc::Rc};23use crate::{4	error::{Error, LocError, Result},5	push, Val,6};7use jrsonnet_parser::ExprLocation;8use jrsonnet_types::{ComplexValType, ValType};9use thiserror::Error;1011#[derive(Debug, Error, Clone)]12pub enum TypeError {13	#[error("expected {0}, got {1}")]14	ExpectedGot(ComplexValType, ValType),15	#[error("missing property {0} from {1:?}")]16	MissingProperty(Rc<str>, ComplexValType),17	#[error("every failed from {0}:\n{1}")]18	UnionFailed(ComplexValType, TypeLocErrorList),19	#[error("number out of bounds: {0} not in {1:?}..{2:?}")]20	BoundsFailed(f64, Option<f64>, Option<f64>),21}22impl From<TypeError> for LocError {23	fn from(e: TypeError) -> Self {24		Error::TypeError(e.into()).into()25	}26}2728#[derive(Debug, Clone)]29pub struct TypeLocError(Box<TypeError>, ValuePathStack);30impl From<TypeError> for TypeLocError {31	fn from(e: TypeError) -> Self {32		TypeLocError(Box::new(e), ValuePathStack(Vec::new()))33	}34}35impl From<TypeLocError> for LocError {36	fn from(e: TypeLocError) -> Self {37		Error::TypeError(e).into()38	}39}40impl Display for TypeLocError {41	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {42		write!(f, "{}", self.0)?;43		if !(self.1).0.is_empty() {44			write!(f, "at {}", self.1)?;45		}46		Ok(())47	}48}4950#[derive(Debug, Clone)]51pub struct TypeLocErrorList(Vec<TypeLocError>);52impl Display for TypeLocErrorList {53	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {54		use std::fmt::Write;55		let mut out = String::new();56		for (i, err) in self.0.iter().enumerate() {57			if i != 0 {58				writeln!(f)?;59			}60			out.clear();61			write!(out, "{}", err)?;6263			for (i, line) in out.lines().enumerate() {64				if line.trim().len() == 0 {65					continue;66				}67				if i != 0 {68					writeln!(f)?;69					write!(f, "    ")?;70				} else {71					write!(f, "  - ")?;72				}73				write!(f, "{}", line)?;74			}75		}76		Ok(())77	}78}7980fn push_type(81	location: Option<&ExprLocation>,82	error_reason: impl Fn() -> String,83	path: impl Fn() -> ValuePathItem,84	item: impl Fn() -> Result<()>,85) -> Result<()> {86	push(location, error_reason, || match item() {87		Ok(_) => Ok(()),88		Err(mut e) => {89			if let Error::TypeError(e) = &mut e.error_mut() {90				(e.1).0.push(path())91			}92			Err(e)93		}94	})95}9697// TODO: check_fast for fast path of union type checking98pub trait CheckType {99	fn check(&self, value: &Val) -> Result<()>;100}101102impl CheckType for ValType {103	fn check(&self, value: &Val) -> Result<()> {104		let got = value.value_type();105		if got != *self {106			let loc_error: TypeLocError = TypeError::ExpectedGot((*self).into(), got).into();107			return Err(loc_error.into());108		}109		Ok(())110	}111}112113#[derive(Clone, Debug)]114enum ValuePathItem {115	Field(Rc<str>),116	Index(u64),117}118impl Display for ValuePathItem {119	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {120		match self {121			ValuePathItem::Field(name) => write!(f, ".{}", name)?,122			ValuePathItem::Index(idx) => write!(f, "[{}]", idx)?,123		}124		Ok(())125	}126}127128#[derive(Clone, Debug)]129struct ValuePathStack(Vec<ValuePathItem>);130impl Display for ValuePathStack {131	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {132		write!(f, "self")?;133		for elem in self.0.iter().rev() {134			write!(f, "{}", elem)?;135		}136		Ok(())137	}138}139140impl CheckType for ComplexValType {141	fn check(&self, value: &Val) -> Result<()> {142		match self {143			ComplexValType::Any => Ok(()),144			ComplexValType::Simple(s) => s.check(value),145			ComplexValType::Char => match value {146				Val::Str(s) if s.len() == 1 || s.chars().count() == 1 => Ok(()),147				v => Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),148			},149			ComplexValType::BoundedNumber(from, to) => {150				if let Val::Num(n) = value {151					if from.map(|from| from > *n).unwrap_or(false)152						|| to.map(|to| to <= *n).unwrap_or(false)153					{154						return Err(TypeError::BoundsFailed(*n, from.clone(), to.clone()).into());155					}156					Ok(())157				} else {158					Err(TypeError::ExpectedGot(self.clone(), value.value_type()).into())159				}160			}161			ComplexValType::Array(elem_type) => match value {162				Val::Arr(a) => {163					for (i, item) in a.iter().enumerate() {164						push_type(165							None,166							|| format!("array index {}", i),167							|| ValuePathItem::Index(i as u64),168							|| Ok(elem_type.check(&item.clone()?)?),169						)?;170					}171					Ok(())172				}173				v => return Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),174			},175			ComplexValType::ArrayRef(elem_type) => match value {176				Val::Arr(a) => {177					for (i, item) in a.iter().enumerate() {178						push_type(179							None,180							|| format!("array index {}", i),181							|| ValuePathItem::Index(i as u64),182							|| Ok(elem_type.check(&item.clone()?)?),183						)?;184					}185					Ok(())186				}187				v => return Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),188			},189			ComplexValType::ObjectRef(elems) => match value {190				Val::Obj(obj) => {191					for (k, v) in elems.iter() {192						if let Some(got_v) = obj.get((*k).into())? {193							push_type(194								None,195								|| format!("property {}", k),196								|| ValuePathItem::Field((*k).into()),197								|| v.check(&got_v),198							)?199						} else {200							return Err(201								TypeError::MissingProperty((*k).into(), self.clone()).into()202							);203						}204					}205					return Ok(());206				}207				v => return Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),208			},209			ComplexValType::Union(types) => {210				let mut errors = Vec::new();211				for ty in types.iter() {212					match ty.check(value) {213						Ok(()) => {214							return Ok(());215						}216						Err(e) => match e.error() {217							Error::TypeError(e) => errors.push(e.clone()),218							_ => return Err(e),219						},220					}221				}222				return Err(TypeError::UnionFailed(self.clone(), TypeLocErrorList(errors)).into());223			}224			ComplexValType::UnionRef(types) => {225				let mut errors = Vec::new();226				for ty in types.iter() {227					match ty.check(value) {228						Ok(()) => {229							return Ok(());230						}231						Err(e) => match e.error() {232							Error::TypeError(e) => errors.push(e.clone()),233							_ => return Err(e),234						},235					}236				}237				return Err(TypeError::UnionFailed(self.clone(), TypeLocErrorList(errors)).into());238			}239			ComplexValType::Sum(types) => {240				for ty in types.iter() {241					ty.check(value)?242				}243				Ok(())244			}245			ComplexValType::SumRef(types) => {246				for ty in types.iter() {247					ty.check(value)?248				}249				Ok(())250			}251		}252	}253}
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -102,7 +102,7 @@
 	pub fn evaluate(
 		&self,
 		call_ctx: Context,
-		loc: &Option<ExprLocation>,
+		loc: Option<&ExprLocation>,
 		args: &ArgsDesc,
 		tailstrict: bool,
 	) -> Result<Val> {