git.delta.rocks / jrsonnet / refs/commits / 4f4be44d138e

difftreelog

style fix clippy warnings

Yaroslav Bolyukin2022-04-20parent: #ed4ee4d.patch.diff
in: master

5 files changed

modifiedcrates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/function.rs
1use crate::{2	error::{Error::*, LocError},3	evaluate, evaluate_named,4	gc::TraceBox,5	throw,6	typed::Typed,7	Context, FutureWrapper, GcHashMap, LazyVal, LazyValValue, Result, Val,8};9use gcmodule::Trace;10use jrsonnet_interner::IStr;11pub use jrsonnet_macros::builtin;12use jrsonnet_parser::{ArgsDesc, ExprLocation, LocExpr, ParamsDesc};13use std::{borrow::Cow, collections::HashMap, convert::TryFrom};1415#[derive(Clone, Copy)]16pub struct CallLocation<'l>(pub Option<&'l ExprLocation>);17impl<'l> CallLocation<'l> {18	pub fn new(loc: &'l ExprLocation) -> Self {19		Self(Some(loc))20	}21}22impl CallLocation<'static> {23	pub fn native() -> Self {24		Self(None)25	}26}2728#[derive(Trace)]29struct EvaluateLazyVal {30	context: Context,31	expr: LocExpr,32}33impl LazyValValue for EvaluateLazyVal {34	fn get(self: Box<Self>) -> Result<Val> {35		evaluate(self.context, &self.expr)36	}37}3839#[derive(Trace)]40struct EvaluateNamedLazyVal {41	future_context: FutureWrapper<Context>,42	name: IStr,43	value: LocExpr,44}45impl LazyValValue for EvaluateNamedLazyVal {46	fn get(self: Box<Self>) -> Result<Val> {47		evaluate_named(self.future_context.unwrap(), &self.value, self.name)48	}49}5051pub trait ArgLike {52	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<LazyVal>;53}54impl ArgLike for &LocExpr {55	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<LazyVal> {56		Ok(if tailstrict {57			LazyVal::new_resolved(evaluate(ctx, self)?)58		} else {59			LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {60				context: ctx,61				expr: (*self).clone(),62			})))63		})64	}65}66impl<T> ArgLike for T67where68	T: Typed + Clone,69	Val: TryFrom<T, Error = LocError>,70{71	fn evaluate_arg(&self, _ctx: Context, _tailstrict: bool) -> Result<LazyVal> {72		let val: Val = Val::try_from(self.clone())?;73		Ok(LazyVal::new_resolved(val))74	}75}76pub enum TlaArg {77	String(IStr),78	Code(LocExpr),79	Val(Val),80}81impl ArgLike for TlaArg {82	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<LazyVal> {83		match self {84			TlaArg::String(s) => Ok(LazyVal::new_resolved(Val::Str(s.clone()))),85			TlaArg::Code(code) => Ok(if tailstrict {86				LazyVal::new_resolved(evaluate(ctx, code)?)87			} else {88				LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {89					context: ctx,90					expr: code.clone(),91				})))92			}),93			TlaArg::Val(val) => Ok(LazyVal::new_resolved(val.clone())),94		}95	}96}9798pub trait ArgsLike {99	fn unnamed_len(&self) -> usize;100	fn unnamed_iter(101		&self,102		ctx: Context,103		tailstrict: bool,104		handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,105	) -> Result<()>;106	fn named_iter(107		&self,108		ctx: Context,109		tailstrict: bool,110		handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,111	) -> Result<()>;112	fn named_names(&self, handler: &mut dyn FnMut(&IStr));113}114115impl ArgsLike for ArgsDesc {116	fn unnamed_len(&self) -> usize {117		self.unnamed.len()118	}119120	fn unnamed_iter(121		&self,122		ctx: Context,123		tailstrict: bool,124		handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,125	) -> Result<()> {126		for (id, arg) in self.unnamed.iter().enumerate() {127			handler(128				id,129				if tailstrict {130					LazyVal::new_resolved(evaluate(ctx.clone(), arg)?)131				} else {132					LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {133						context: ctx.clone(),134						expr: arg.clone(),135					})))136				},137			)?;138		}139		Ok(())140	}141142	fn named_iter(143		&self,144		ctx: Context,145		tailstrict: bool,146		handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,147	) -> Result<()> {148		for (name, arg) in self.named.iter() {149			handler(150				name,151				if tailstrict {152					LazyVal::new_resolved(evaluate(ctx.clone(), arg)?)153				} else {154					LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {155						context: ctx.clone(),156						expr: arg.clone(),157					})))158				},159			)?;160		}161		Ok(())162	}163164	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {165		for (name, _) in self.named.iter() {166			handler(name)167		}168	}169}170171impl<A: ArgLike> ArgsLike for [(IStr, A)] {172	fn unnamed_len(&self) -> usize {173		0174	}175176	fn unnamed_iter(177		&self,178		_ctx: Context,179		_tailstrict: bool,180		_handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,181	) -> Result<()> {182		Ok(())183	}184185	fn named_iter(186		&self,187		ctx: Context,188		tailstrict: bool,189		handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,190	) -> Result<()> {191		for (name, val) in self.iter() {192			handler(name, val.evaluate_arg(ctx.clone(), tailstrict)?)?;193		}194		Ok(())195	}196197	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {198		for (name, _) in self.iter() {199			handler(name);200		}201	}202}203204impl<A: ArgLike> ArgsLike for HashMap<IStr, A> {205	fn unnamed_len(&self) -> usize {206		0207	}208209	fn unnamed_iter(210		&self,211		_ctx: Context,212		_tailstrict: bool,213		_handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,214	) -> Result<()> {215		Ok(())216	}217218	fn named_iter(219		&self,220		ctx: Context,221		tailstrict: bool,222		handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,223	) -> Result<()> {224		for (name, value) in self.iter() {225			handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;226		}227		Ok(())228	}229230	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {231		for (name, _) in self.iter() {232			handler(name);233		}234	}235}236237impl<A: ArgLike> ArgsLike for [A] {238	fn unnamed_len(&self) -> usize {239		self.len()240	}241242	fn unnamed_iter(243		&self,244		ctx: Context,245		tailstrict: bool,246		handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,247	) -> Result<()> {248		for (i, arg) in self.iter().enumerate() {249			handler(i, arg.evaluate_arg(ctx.clone(), tailstrict)?)?;250		}251		Ok(())252	}253254	fn named_iter(255		&self,256		_ctx: Context,257		_tailstrict: bool,258		_handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,259	) -> Result<()> {260		Ok(())261	}262263	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}264}265impl<A: ArgLike> ArgsLike for &[A] {266	fn unnamed_len(&self) -> usize {267		(*self).unnamed_len()268	}269270	fn unnamed_iter(271		&self,272		ctx: Context,273		tailstrict: bool,274		handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,275	) -> Result<()> {276		(*self).unnamed_iter(ctx, tailstrict, handler)277	}278279	fn named_iter(280		&self,281		ctx: Context,282		tailstrict: bool,283		handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,284	) -> Result<()> {285		(*self).named_iter(ctx, tailstrict, handler)286	}287288	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {289		(*self).named_names(handler)290	}291}292293/// Creates correct [context](Context) for function body evaluation returning error on invalid call.294///295/// ## Parameters296/// * `ctx`: used for passed argument expressions' execution and for body execution (if `body_ctx` is not set)297/// * `body_ctx`: used for default parameter values' execution and for body execution (if set)298/// * `params`: function parameters' definition299/// * `args`: passed function arguments300/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily301pub fn parse_function_call(302	ctx: Context,303	body_ctx: Context,304	params: &ParamsDesc,305	args: &dyn ArgsLike,306	tailstrict: bool,307) -> Result<Context> {308	let mut passed_args = GcHashMap::with_capacity(params.len());309	if args.unnamed_len() > params.len() {310		throw!(TooManyArgsFunctionHas(params.len()))311	}312313	let mut filled_args = 0;314315	args.unnamed_iter(ctx.clone(), tailstrict, &mut |id, arg| {316		let name = params[id].0.clone();317		passed_args.insert(name, arg);318		filled_args += 1;319		Ok(())320	})?;321322	args.named_iter(ctx, tailstrict, &mut |name, value| {323		// FIXME: O(n) for arg existence check324		if !params.iter().any(|p| &p.0 == name) {325			throw!(UnknownFunctionParameter((name as &str).to_owned()));326		}327		if passed_args.insert(name.clone(), value).is_some() {328			throw!(BindingParameterASecondTime(name.clone()));329		}330		filled_args += 1;331		Ok(())332	})?;333334	if filled_args < params.len() {335		// Some args are unset, but maybe we have defaults for them336		// Default values should be created in newly created context337		let future_context = Context::new_future();338		let mut defaults = GcHashMap::with_capacity(params.len() - filled_args);339340		for param in params.iter().filter(|p| p.1.is_some()) {341			if passed_args.contains_key(&param.0.clone()) {342				continue;343			}344			LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {345				future_context: future_context.clone(),346				name: param.0.clone(),347				value: param.1.clone().unwrap(),348			})));349350			defaults.insert(351				param.0.clone(),352				LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {353					future_context: future_context.clone(),354					name: param.0.clone(),355					value: param.1.clone().unwrap(),356				}))),357			);358			filled_args += 1;359		}360361		// Some args still wasn't filled362		if filled_args != params.len() {363			for param in params.iter().skip(args.unnamed_len()) {364				let mut found = false;365				args.named_names(&mut |name| {366					if name == &param.0 {367						found = true;368					}369				});370				if !found {371					throw!(FunctionParameterNotBoundInCall(param.0.clone()));372				}373			}374			unreachable!();375		}376377		Ok(body_ctx378			.extend(passed_args, None, None, None)379			.extend_bound(defaults)380			.into_future(future_context))381	} else {382		let body_ctx = body_ctx.extend(passed_args, None, None, None);383		Ok(body_ctx)384	}385}386387type BuiltinParamName = Cow<'static, str>;388389#[derive(Clone, Trace)]390pub struct BuiltinParam {391	pub name: BuiltinParamName,392	pub has_default: bool,393}394395/// Do not implement it directly, instead use #[builtin] macro396pub trait Builtin: Trace {397	fn name(&self) -> &str;398	fn params(&self) -> &[BuiltinParam];399	fn call(&self, context: Context, loc: CallLocation, args: &dyn ArgsLike) -> Result<Val>;400}401402pub trait StaticBuiltin: Builtin + Send + Sync403where404	Self: 'static,405{406	// In impl, to make it object safe:407	// const INST: &'static Self;408}409410/// You shouldn't probally use this function, use jrsonnet_macros::builtin instead411///412/// ## Parameters413/// * `ctx`: used for passed argument expressions' execution and for body execution (if `body_ctx` is not set)414/// * `params`: function parameters' definition415/// * `args`: passed function arguments416/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily417pub fn parse_builtin_call(418	ctx: Context,419	params: &[BuiltinParam],420	args: &dyn ArgsLike,421	tailstrict: bool,422) -> Result<GcHashMap<BuiltinParamName, LazyVal>> {423	let mut passed_args = GcHashMap::with_capacity(params.len());424	if args.unnamed_len() > params.len() {425		throw!(TooManyArgsFunctionHas(params.len()))426	}427428	let mut filled_args = 0;429430	args.unnamed_iter(ctx.clone(), tailstrict, &mut |id, arg| {431		let name = params[id].name.clone();432		passed_args.insert(name, arg);433		filled_args += 1;434		Ok(())435	})?;436437	args.named_iter(ctx, tailstrict, &mut |name, arg| {438		// FIXME: O(n) for arg existence check439		let p = params440			.iter()441			.find(|p| p.name == name as &str)442			.ok_or_else(|| UnknownFunctionParameter((name as &str).to_owned()))?;443		if passed_args.insert(p.name.clone(), arg).is_some() {444			throw!(BindingParameterASecondTime(name.clone()));445		}446		filled_args += 1;447		Ok(())448	})?;449450	if filled_args < params.len() {451		for param in params.iter().filter(|p| p.has_default) {452			if passed_args.contains_key(&param.name) {453				continue;454			}455			filled_args += 1;456		}457458		// Some args still wasn't filled459		if filled_args != params.len() {460			for param in params.iter().skip(args.unnamed_len()) {461				let mut found = false;462				args.named_names(&mut |name| {463					if name as &str == &param.name as &str {464						found = true;465					}466				});467				if !found {468					throw!(FunctionParameterNotBoundInCall(param.name.clone().into()));469				}470			}471			unreachable!();472		}473	}474	Ok(passed_args)475}476477/// Creates Context, which has all argument default values applied478/// and with unbound values causing error to be returned479pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Context {480	let ctx = Context::new_future();481482	let mut bindings = GcHashMap::new();483484	#[derive(Trace)]485	struct DependsOnUnbound(IStr);486	impl LazyValValue for DependsOnUnbound {487		fn get(self: Box<Self>) -> Result<Val> {488			Err(FunctionParameterNotBoundInCall(self.0.clone()).into())489		}490	}491492	for param in params.iter() {493		if let Some(v) = &param.1 {494			bindings.insert(495				param.0.clone(),496				LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {497					future_context: ctx.clone(),498					name: param.0.clone(),499					value: v.clone(),500				}))),501			);502		} else {503			bindings.insert(504				param.0.clone(),505				LazyVal::new(TraceBox(Box::new(DependsOnUnbound(param.0.clone())))),506			);507		}508	}509510	body_ctx.extend(bindings, None, None, None).into_future(ctx)511}
after · crates/jrsonnet-evaluator/src/function.rs
1use crate::{2	error::{Error::*, LocError},3	evaluate, evaluate_named,4	gc::TraceBox,5	throw,6	typed::Typed,7	Context, FutureWrapper, GcHashMap, LazyVal, LazyValValue, Result, Val,8};9use gcmodule::Trace;10use jrsonnet_interner::IStr;11pub use jrsonnet_macros::builtin;12use jrsonnet_parser::{ArgsDesc, ExprLocation, LocExpr, ParamsDesc};13use std::{borrow::Cow, collections::HashMap, convert::TryFrom};1415#[derive(Clone, Copy)]16pub struct CallLocation<'l>(pub Option<&'l ExprLocation>);17impl<'l> CallLocation<'l> {18	pub const fn new(loc: &'l ExprLocation) -> Self {19		Self(Some(loc))20	}21}22impl CallLocation<'static> {23	pub const fn native() -> Self {24		Self(None)25	}26}2728#[derive(Trace)]29struct EvaluateLazyVal {30	context: Context,31	expr: LocExpr,32}33impl LazyValValue for EvaluateLazyVal {34	fn get(self: Box<Self>) -> Result<Val> {35		evaluate(self.context, &self.expr)36	}37}3839#[derive(Trace)]40struct EvaluateNamedLazyVal {41	future_context: FutureWrapper<Context>,42	name: IStr,43	value: LocExpr,44}45impl LazyValValue for EvaluateNamedLazyVal {46	fn get(self: Box<Self>) -> Result<Val> {47		evaluate_named(self.future_context.unwrap(), &self.value, self.name)48	}49}5051pub trait ArgLike {52	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<LazyVal>;53}54impl ArgLike for &LocExpr {55	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<LazyVal> {56		Ok(if tailstrict {57			LazyVal::new_resolved(evaluate(ctx, self)?)58		} else {59			LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {60				context: ctx,61				expr: (*self).clone(),62			})))63		})64	}65}66impl<T> ArgLike for T67where68	T: Typed + Clone,69	Val: TryFrom<T, Error = LocError>,70{71	fn evaluate_arg(&self, _ctx: Context, _tailstrict: bool) -> Result<LazyVal> {72		let val: Val = Val::try_from(self.clone())?;73		Ok(LazyVal::new_resolved(val))74	}75}76pub enum TlaArg {77	String(IStr),78	Code(LocExpr),79	Val(Val),80}81impl ArgLike for TlaArg {82	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<LazyVal> {83		match self {84			TlaArg::String(s) => Ok(LazyVal::new_resolved(Val::Str(s.clone()))),85			TlaArg::Code(code) => Ok(if tailstrict {86				LazyVal::new_resolved(evaluate(ctx, code)?)87			} else {88				LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {89					context: ctx,90					expr: code.clone(),91				})))92			}),93			TlaArg::Val(val) => Ok(LazyVal::new_resolved(val.clone())),94		}95	}96}9798pub trait ArgsLike {99	fn unnamed_len(&self) -> usize;100	fn unnamed_iter(101		&self,102		ctx: Context,103		tailstrict: bool,104		handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,105	) -> Result<()>;106	fn named_iter(107		&self,108		ctx: Context,109		tailstrict: bool,110		handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,111	) -> Result<()>;112	fn named_names(&self, handler: &mut dyn FnMut(&IStr));113}114115impl ArgsLike for ArgsDesc {116	fn unnamed_len(&self) -> usize {117		self.unnamed.len()118	}119120	fn unnamed_iter(121		&self,122		ctx: Context,123		tailstrict: bool,124		handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,125	) -> Result<()> {126		for (id, arg) in self.unnamed.iter().enumerate() {127			handler(128				id,129				if tailstrict {130					LazyVal::new_resolved(evaluate(ctx.clone(), arg)?)131				} else {132					LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {133						context: ctx.clone(),134						expr: arg.clone(),135					})))136				},137			)?;138		}139		Ok(())140	}141142	fn named_iter(143		&self,144		ctx: Context,145		tailstrict: bool,146		handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,147	) -> Result<()> {148		for (name, arg) in self.named.iter() {149			handler(150				name,151				if tailstrict {152					LazyVal::new_resolved(evaluate(ctx.clone(), arg)?)153				} else {154					LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {155						context: ctx.clone(),156						expr: arg.clone(),157					})))158				},159			)?;160		}161		Ok(())162	}163164	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {165		for (name, _) in self.named.iter() {166			handler(name)167		}168	}169}170171impl<A: ArgLike> ArgsLike for [(IStr, A)] {172	fn unnamed_len(&self) -> usize {173		0174	}175176	fn unnamed_iter(177		&self,178		_ctx: Context,179		_tailstrict: bool,180		_handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,181	) -> Result<()> {182		Ok(())183	}184185	fn named_iter(186		&self,187		ctx: Context,188		tailstrict: bool,189		handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,190	) -> Result<()> {191		for (name, val) in self.iter() {192			handler(name, val.evaluate_arg(ctx.clone(), tailstrict)?)?;193		}194		Ok(())195	}196197	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {198		for (name, _) in self.iter() {199			handler(name);200		}201	}202}203204impl<A: ArgLike> ArgsLike for HashMap<IStr, A> {205	fn unnamed_len(&self) -> usize {206		0207	}208209	fn unnamed_iter(210		&self,211		_ctx: Context,212		_tailstrict: bool,213		_handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,214	) -> Result<()> {215		Ok(())216	}217218	fn named_iter(219		&self,220		ctx: Context,221		tailstrict: bool,222		handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,223	) -> Result<()> {224		for (name, value) in self.iter() {225			handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;226		}227		Ok(())228	}229230	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {231		for (name, _) in self.iter() {232			handler(name);233		}234	}235}236237impl<A: ArgLike> ArgsLike for [A] {238	fn unnamed_len(&self) -> usize {239		self.len()240	}241242	fn unnamed_iter(243		&self,244		ctx: Context,245		tailstrict: bool,246		handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,247	) -> Result<()> {248		for (i, arg) in self.iter().enumerate() {249			handler(i, arg.evaluate_arg(ctx.clone(), tailstrict)?)?;250		}251		Ok(())252	}253254	fn named_iter(255		&self,256		_ctx: Context,257		_tailstrict: bool,258		_handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,259	) -> Result<()> {260		Ok(())261	}262263	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}264}265impl<A: ArgLike> ArgsLike for &[A] {266	fn unnamed_len(&self) -> usize {267		(*self).unnamed_len()268	}269270	fn unnamed_iter(271		&self,272		ctx: Context,273		tailstrict: bool,274		handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,275	) -> Result<()> {276		(*self).unnamed_iter(ctx, tailstrict, handler)277	}278279	fn named_iter(280		&self,281		ctx: Context,282		tailstrict: bool,283		handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,284	) -> Result<()> {285		(*self).named_iter(ctx, tailstrict, handler)286	}287288	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {289		(*self).named_names(handler)290	}291}292293/// Creates correct [context](Context) for function body evaluation returning error on invalid call.294///295/// ## Parameters296/// * `ctx`: used for passed argument expressions' execution and for body execution (if `body_ctx` is not set)297/// * `body_ctx`: used for default parameter values' execution and for body execution (if set)298/// * `params`: function parameters' definition299/// * `args`: passed function arguments300/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily301pub fn parse_function_call(302	ctx: Context,303	body_ctx: Context,304	params: &ParamsDesc,305	args: &dyn ArgsLike,306	tailstrict: bool,307) -> Result<Context> {308	let mut passed_args = GcHashMap::with_capacity(params.len());309	if args.unnamed_len() > params.len() {310		throw!(TooManyArgsFunctionHas(params.len()))311	}312313	let mut filled_args = 0;314315	args.unnamed_iter(ctx.clone(), tailstrict, &mut |id, arg| {316		let name = params[id].0.clone();317		passed_args.insert(name, arg);318		filled_args += 1;319		Ok(())320	})?;321322	args.named_iter(ctx, tailstrict, &mut |name, value| {323		// FIXME: O(n) for arg existence check324		if !params.iter().any(|p| &p.0 == name) {325			throw!(UnknownFunctionParameter((name as &str).to_owned()));326		}327		if passed_args.insert(name.clone(), value).is_some() {328			throw!(BindingParameterASecondTime(name.clone()));329		}330		filled_args += 1;331		Ok(())332	})?;333334	if filled_args < params.len() {335		// Some args are unset, but maybe we have defaults for them336		// Default values should be created in newly created context337		let future_context = Context::new_future();338		let mut defaults = GcHashMap::with_capacity(params.len() - filled_args);339340		for param in params.iter().filter(|p| p.1.is_some()) {341			if passed_args.contains_key(&param.0.clone()) {342				continue;343			}344			LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {345				future_context: future_context.clone(),346				name: param.0.clone(),347				value: param.1.clone().unwrap(),348			})));349350			defaults.insert(351				param.0.clone(),352				LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {353					future_context: future_context.clone(),354					name: param.0.clone(),355					value: param.1.clone().unwrap(),356				}))),357			);358			filled_args += 1;359		}360361		// Some args still wasn't filled362		if filled_args != params.len() {363			for param in params.iter().skip(args.unnamed_len()) {364				let mut found = false;365				args.named_names(&mut |name| {366					if name == &param.0 {367						found = true;368					}369				});370				if !found {371					throw!(FunctionParameterNotBoundInCall(param.0.clone()));372				}373			}374			unreachable!();375		}376377		Ok(body_ctx378			.extend(passed_args, None, None, None)379			.extend_bound(defaults)380			.into_future(future_context))381	} else {382		let body_ctx = body_ctx.extend(passed_args, None, None, None);383		Ok(body_ctx)384	}385}386387type BuiltinParamName = Cow<'static, str>;388389#[derive(Clone, Trace)]390pub struct BuiltinParam {391	pub name: BuiltinParamName,392	pub has_default: bool,393}394395/// Do not implement it directly, instead use #[builtin] macro396pub trait Builtin: Trace {397	fn name(&self) -> &str;398	fn params(&self) -> &[BuiltinParam];399	fn call(&self, context: Context, loc: CallLocation, args: &dyn ArgsLike) -> Result<Val>;400}401402pub trait StaticBuiltin: Builtin + Send + Sync403where404	Self: 'static,405{406	// In impl, to make it object safe:407	// const INST: &'static Self;408}409410/// You shouldn't probally use this function, use jrsonnet_macros::builtin instead411///412/// ## Parameters413/// * `ctx`: used for passed argument expressions' execution and for body execution (if `body_ctx` is not set)414/// * `params`: function parameters' definition415/// * `args`: passed function arguments416/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily417pub fn parse_builtin_call(418	ctx: Context,419	params: &[BuiltinParam],420	args: &dyn ArgsLike,421	tailstrict: bool,422) -> Result<GcHashMap<BuiltinParamName, LazyVal>> {423	let mut passed_args = GcHashMap::with_capacity(params.len());424	if args.unnamed_len() > params.len() {425		throw!(TooManyArgsFunctionHas(params.len()))426	}427428	let mut filled_args = 0;429430	args.unnamed_iter(ctx.clone(), tailstrict, &mut |id, arg| {431		let name = params[id].name.clone();432		passed_args.insert(name, arg);433		filled_args += 1;434		Ok(())435	})?;436437	args.named_iter(ctx, tailstrict, &mut |name, arg| {438		// FIXME: O(n) for arg existence check439		let p = params440			.iter()441			.find(|p| p.name == name as &str)442			.ok_or_else(|| UnknownFunctionParameter((name as &str).to_owned()))?;443		if passed_args.insert(p.name.clone(), arg).is_some() {444			throw!(BindingParameterASecondTime(name.clone()));445		}446		filled_args += 1;447		Ok(())448	})?;449450	if filled_args < params.len() {451		for param in params.iter().filter(|p| p.has_default) {452			if passed_args.contains_key(&param.name) {453				continue;454			}455			filled_args += 1;456		}457458		// Some args still wasn't filled459		if filled_args != params.len() {460			for param in params.iter().skip(args.unnamed_len()) {461				let mut found = false;462				args.named_names(&mut |name| {463					if name as &str == &param.name as &str {464						found = true;465					}466				});467				if !found {468					throw!(FunctionParameterNotBoundInCall(param.name.clone().into()));469				}470			}471			unreachable!();472		}473	}474	Ok(passed_args)475}476477/// Creates Context, which has all argument default values applied478/// and with unbound values causing error to be returned479pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Context {480	let ctx = Context::new_future();481482	let mut bindings = GcHashMap::new();483484	#[derive(Trace)]485	struct DependsOnUnbound(IStr);486	impl LazyValValue for DependsOnUnbound {487		fn get(self: Box<Self>) -> Result<Val> {488			Err(FunctionParameterNotBoundInCall(self.0.clone()).into())489		}490	}491492	for param in params.iter() {493		if let Some(v) = &param.1 {494			bindings.insert(495				param.0.clone(),496				LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {497					future_context: ctx.clone(),498					name: param.0.clone(),499					value: v.clone(),500				}))),501			);502		} else {503			bindings.insert(504				param.0.clone(),505				LazyVal::new(TraceBox(Box::new(DependsOnUnbound(param.0.clone())))),506			);507		}508	}509510	body_ctx.extend(bindings, None, None, None).into_future(ctx)511}
modifiedcrates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/integrations/serde.rs
+++ b/crates/jrsonnet-evaluator/src/integrations/serde.rs
@@ -20,7 +20,7 @@
 			Val::Arr(a) => {
 				let mut out = Vec::with_capacity(a.len());
 				for item in a.iter() {
-					out.push((&item?).try_into()?);
+					out.push(item?.try_into()?);
 				}
 				Self::Array(out)
 			}
@@ -29,8 +29,8 @@
 				for key in o.fields() {
 					out.insert(
 						(&key as &str).into(),
-						(&o.get(key)?
-							.expect("key is present in fields, so value should exist"))
+						o.get(key)?
+							.expect("key is present in fields, so value should exist")
 							.try_into()?,
 					);
 				}
@@ -40,6 +40,13 @@
 		})
 	}
 }
+impl TryFrom<Val> for Value {
+	type Error = LocError;
+
+	fn try_from(value: Val) -> Result<Self, Self::Error> {
+		<Self as TryFrom<&Val>>::try_from(&value)
+	}
+}
 
 impl TryFrom<&Value> for Val {
 	type Error = LocError;
@@ -68,3 +75,10 @@
 		})
 	}
 }
+impl TryFrom<Value> for Val {
+	type Error = LocError;
+
+	fn try_from(value: Value) -> Result<Self, Self::Error> {
+		<Self as TryFrom<&Value>>::try_from(&value)
+	}
+}
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/typed/conversions.rs
+++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs
@@ -442,7 +442,7 @@
 	fn try_from(value: Val) -> Result<Self, Self::Error> {
 		<Self as Typed>::TYPE.check(&value)?;
 		match value {
-			Val::Func(FuncVal::Normal(desc)) => Ok(desc.clone()),
+			Val::Func(FuncVal::Normal(desc)) => Ok(desc),
 			Val::Func(_) => throw!(RuntimeError("expected normal function, not builtin".into())),
 			_ => unreachable!(),
 		}
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -126,15 +126,6 @@
 	}
 }
 
-impl PartialEq for FuncVal {
-	fn eq(&self, other: &Self) -> bool {
-		match (self, other) {
-			(Self::Normal(a), Self::Normal(b)) => a == b,
-			(Self::StaticBuiltin(an), Self::StaticBuiltin(bn)) => std::ptr::eq(*an, *bn),
-			(..) => false,
-		}
-	}
-}
 impl FuncVal {
 	pub fn args_len(&self) -> usize {
 		match self {
@@ -353,13 +344,13 @@
 }
 
 impl Val {
-	pub fn as_bool(&self) -> Option<bool> {
+	pub const fn as_bool(&self) -> Option<bool> {
 		match self {
 			Val::Bool(v) => Some(*v),
 			_ => None,
 		}
 	}
-	pub fn as_null(&self) -> Option<()> {
+	pub const fn as_null(&self) -> Option<()> {
 		match self {
 			Val::Null => Some(()),
 			_ => None,
@@ -371,7 +362,7 @@
 			_ => None,
 		}
 	}
-	pub fn as_num(&self) -> Option<f64> {
+	pub const fn as_num(&self) -> Option<f64> {
 		match self {
 			Val::Num(n) => Some(*n),
 			_ => None,
modifiedcrates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-macros/src/lib.rs
+++ b/crates/jrsonnet-macros/src/lib.rs
@@ -35,7 +35,7 @@
 
 fn path_is(path: &Path, needed: &str) -> bool {
 	path.leading_colon.is_none()
-		&& path.segments.len() >= 1
+		&& !path.segments.is_empty()
 		&& path.segments.iter().last().unwrap().ident == needed
 }
 
@@ -119,7 +119,7 @@
 
 enum ArgInfo {
 	Normal {
-		ty: Type,
+		ty: Box<Type>,
 		is_option: bool,
 		name: String,
 		// ident: Ident,
@@ -147,27 +147,27 @@
 				))
 			}
 		};
-		let ty = &typed.ty as &Type;
-		if type_is_path(&ty, "CallLocation").is_some() {
+		let ty = &typed.ty;
+		if type_is_path(ty, "CallLocation").is_some() {
 			return Ok(Self::Location);
-		} else if type_is_path(&ty, "Self").is_some() {
+		} else if type_is_path(ty, "Self").is_some() {
 			return Ok(Self::This);
-		} else if type_is_path(&ty, "LazyVal").is_some() {
+		} else if type_is_path(ty, "LazyVal").is_some() {
 			return Ok(Self::Lazy {
 				is_option: false,
 				name: ident.to_string(),
 			});
 		}
 
-		let (is_option, ty) = if let Some(ty) = extract_type_from_option(&ty)? {
-			if type_is_path(&ty, "LazyVal").is_some() {
+		let (is_option, ty) = if let Some(ty) = extract_type_from_option(ty)? {
+			if type_is_path(ty, "LazyVal").is_some() {
 				return Ok(Self::Lazy {
 					is_option: true,
 					name: ident.to_string(),
 				});
 			}
 
-			(true, ty.clone())
+			(true, Box::new(ty.clone()))
 		} else {
 			(false, ty.clone())
 		};
@@ -210,7 +210,7 @@
 		.sig
 		.inputs
 		.iter()
-		.map(|a| ArgInfo::parse(a))
+		.map(ArgInfo::parse)
 		.collect::<Result<Vec<_>>>()?;
 
 	let params_desc = args.iter().flat_map(|a| match a {
@@ -380,8 +380,7 @@
 struct TypedField<'f>(&'f syn::Field, TypedAttr);
 impl<'f> TypedField<'f> {
 	fn try_new(field: &'f syn::Field) -> Result<Self> {
-		let attr =
-			parse_attr::<TypedAttr, _>(&field.attrs, "typed")?.unwrap_or_else(Default::default);
+		let attr = parse_attr::<TypedAttr, _>(&field.attrs, "typed")?.unwrap_or_default();
 		if field.ident.is_none() {
 			return Err(Error::new(
 				field.span(),
@@ -468,17 +467,15 @@
 					out.member(#name.into()).value(self.#ident.try_into()?);
 				}
 			}
+		} else if self.is_option() {
+			quote! {
+				if let Some(value) = self.#ident {
+					value.serialize(out)?;
+				}
+			}
 		} else {
-			if self.is_option() {
-				quote! {
-					if let Some(value) = self.#ident {
-						value.serialize(out)?;
-					}
-				}
-			} else {
-				quote! {
-					self.#ident.serialize(out)?;
-				}
+			quote! {
+				self.#ident.serialize(out)?;
 			}
 		}
 	}