git.delta.rocks / jrsonnet / refs/commits / 150f28648ad3

difftreelog

refactor always use prepared calls

wulxrvxzYaroslav Bolyukin2026-04-04parent: #0f5b614.patch.diff
in: master

17 files changed

modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -19,7 +19,7 @@
 	destructure::evaluate_dest,
 	error::{ErrorKind::*, suggest_object_fields},
 	evaluate::operator::{evaluate_binary_op_special, evaluate_unary_op},
-	function::{CallLocation, FuncDesc, FuncVal},
+	function::{CallLocation, FuncDesc, FuncVal, PreparedFuncVal},
 	gc::WithCapacityExt as _,
 	in_frame,
 	typed::{FromUntyped, IntoUntyped as _, Typed},
@@ -430,11 +430,25 @@
 	let value = evaluate(ctx.clone(), value)?;
 	Ok(match value {
 		Val::Func(f) => {
-			let body = || f.evaluate(ctx, loc, args, tailstrict);
+			let name = f.name();
+			let prepare = PreparedFuncVal::new(f, args.unnamed.len(), &args.names)?;
+			let unnamed = args
+				.unnamed
+				.iter()
+				.cloned()
+				.map(|un| evaluate_thunk(ctx.clone(), un, tailstrict))
+				.collect::<Result<Vec<_>>>()?;
+			let named = args
+				.values
+				.iter()
+				.cloned()
+				.map(|un| evaluate_thunk(ctx.clone(), un, tailstrict))
+				.collect::<Result<Vec<_>>>()?;
+			let body = || prepare.call(loc, &unnamed, &named);
 			if tailstrict {
 				body()?
 			} else {
-				in_frame(loc, || format!("function <{}> call", f.name()), body)?
+				in_frame(loc, || format!("function <{name}> call"), body)?
 			}
 		}
 		v => bail!(OnlyFunctionsCanBeCalledGot(v.value_type())),
@@ -479,6 +493,13 @@
 	})
 }
 
+pub fn evaluate_thunk(ctx: Context, expr: Rc<Expr>, tailstrict: bool) -> Result<Thunk<Val>> {
+	Ok(if tailstrict {
+		Thunk::evaluated(evaluate(ctx, &expr)?)
+	} else {
+		Thunk!(move || { evaluate(ctx, &expr) })
+	})
+}
 #[allow(clippy::too_many_lines)]
 pub fn evaluate(ctx: Context, expr: &Expr) -> Result<Val> {
 	use Expr::*;
modifiedcrates/jrsonnet-evaluator/src/function/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/function/mod.rs
+++ b/crates/jrsonnet-evaluator/src/function/mod.rs
@@ -3,12 +3,12 @@
 use educe::Educe;
 use jrsonnet_gcmodule::{Cc, Trace};
 use jrsonnet_interner::IStr;
-use jrsonnet_ir::{ArgsDesc, Destruct, Expr, ExprParams, Span};
+use jrsonnet_ir::{Destruct, Expr, ExprParams, Span};
 pub use jrsonnet_macros::builtin;
 
 use self::{
 	builtin::Builtin,
-	parse::{parse_builtin_call, parse_default_function_call, parse_function_call},
+	parse::parse_default_function_call,
 	prepared::{PreparedCall, parse_prepared_builtin_call, parse_prepared_function_call},
 };
 use crate::{
@@ -22,7 +22,7 @@
 
 pub use jrsonnet_ir::function::*;
 pub use native::NativeFn;
-pub use prepared::PreparedFuncVal;
+pub(crate) use prepared::PreparedFuncVal;
 
 /// Function callsite location.
 /// Either from other jsonnet code, specified by expression location, or from native (without location).
@@ -77,16 +77,6 @@
 		parse_default_function_call(self.ctx.clone(), &self.params)
 	}
 
-	/// Create context, with which body code will run
-	pub(crate) fn call_body_context(
-		&self,
-		call_ctx: Context,
-		args: &ArgsDesc,
-		tailstrict: bool,
-	) -> Result<Context> {
-		parse_function_call(call_ctx, self.ctx.clone(), &self.params, args, tailstrict)
-	}
-
 	pub fn evaluate_trivial(&self) -> Option<Val> {
 		evaluate_trivial(&self.body)
 	}
@@ -137,27 +127,6 @@
 		match self {
 			Self::Normal(normal) => normal.name.clone(),
 			Self::Builtin(builtin) => builtin.name().into(),
-		}
-	}
-	/// Call function using arguments evaluated in specified `call_ctx` [`Context`].
-	///
-	/// If `tailstrict` is specified - then arguments will be evaluated before being passed to function body.
-	pub fn evaluate(
-		&self,
-		call_ctx: Context,
-		loc: CallLocation<'_>,
-		args: &ArgsDesc,
-		tailstrict: bool,
-	) -> Result<Val> {
-		match self {
-			Self::Normal(func) => {
-				let body_ctx = func.call_body_context(call_ctx, args, tailstrict)?;
-				evaluate(body_ctx, &func.body)
-			}
-			Self::Builtin(b) => {
-				let args = parse_builtin_call(call_ctx, b.params(), args, tailstrict)?;
-				b.call(loc, &args)
-			}
 		}
 	}
 
modifiedcrates/jrsonnet-evaluator/src/function/native.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/function/native.rs
+++ b/crates/jrsonnet-evaluator/src/function/native.rs
@@ -39,12 +39,19 @@
 		impl<$($gen,)* O> FromUntyped for NativeFn<($($gen,)* O,)> {
 			fn from_untyped(untyped: Val) -> Result<Self> {
 				let func = FuncVal::from_untyped(untyped)?;
+				Self::try_from(func)
+			}
+		}
+		impl<$($gen,)* O> TryFrom<FuncVal> for NativeFn<($($gen,)* O,)> {
+			type Error = crate::Error;
+			fn try_from(v: FuncVal) -> Result<Self> {
 				Ok(Self(
-					PreparedFuncVal::new(func, $i, &[])?,
+					PreparedFuncVal::new(v, $i, &[])?,
 					PhantomData,
 				))
 			}
 		}
+
 	};
 	($i:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {
 		impl_native_desc!($i; $($cur)*);
modifiedcrates/jrsonnet-evaluator/src/function/parse.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/function/parse.rs
+++ b/crates/jrsonnet-evaluator/src/function/parse.rs
@@ -1,215 +1,13 @@
-use std::rc::Rc;
-
-use jrsonnet_ir::{
-	ArgsDesc, Expr, ExprParams,
-	function::{FunctionSignature, ParamName},
-};
+use jrsonnet_ir::ExprParams;
 use rustc_hash::FxHashMap;
 
 use crate::{
-	Context, Pending, Thunk, Val, bail,
+	Context, Thunk,
 	destructure::destruct,
 	error::{ErrorKind::*, Result},
-	evaluate, evaluate_named_param,
+	evaluate_named_param,
 	gc::WithCapacityExt as _,
 };
-
-fn eval_arg(ctx: Context, arg: &Rc<Expr>, tailstrict: bool) -> Result<Thunk<Val>> {
-	if tailstrict {
-		Ok(Thunk::evaluated(evaluate(ctx, arg)?))
-	} else {
-		let arg = arg.clone();
-		Ok(Thunk!(move || evaluate(ctx, &arg)))
-	}
-}
-
-/// Creates correct [context](Context) for function body evaluation returning error on invalid call.
-///
-/// ## Parameters
-/// * `ctx`: used for passed argument expressions' execution and for body execution (if `body_ctx` is not set)
-/// * `body_ctx`: used for default parameter values' execution and for body execution (if set)
-/// * `params`: function parameters' definition
-/// * `args`: passed function arguments
-/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily
-pub(crate) fn parse_function_call(
-	ctx: Context,
-	body_ctx: Context,
-	params: &ExprParams,
-	args: &ArgsDesc,
-	tailstrict: bool,
-) -> Result<Context> {
-	let mut passed_args = FxHashMap::with_capacity(params.binds_len());
-	if args.unnamed.len() > params.signature.len() {
-		bail!(TooManyArgsFunctionHas(
-			params.signature.len(),
-			params.signature.clone(),
-		))
-	}
-
-	let mut filled_named = 0;
-	let mut filled_positionals = 0;
-
-	for (id, arg) in args.unnamed.iter().enumerate() {
-		destruct(
-			&params.exprs[id].destruct,
-			eval_arg(ctx.clone(), arg, tailstrict)?,
-			Pending::new_filled(ctx.clone()),
-			&mut passed_args,
-		)?;
-		filled_positionals += 1;
-	}
-
-	for (name, value) in &args.named {
-		// FIXME: O(n) for arg existence check
-		if !params.exprs.iter().any(|p| &p.destruct.name() == name) {
-			bail!(UnknownFunctionParameter(name.clone()));
-		}
-		if passed_args
-			.insert(name.clone(), eval_arg(ctx.clone(), value, tailstrict)?)
-			.is_some()
-		{
-			bail!(BindingParameterASecondTime(name.clone()));
-		}
-		filled_named += 1;
-	}
-
-	if filled_named + filled_positionals < params.len() {
-		// Some args are unset, but maybe we have defaults for them
-		// Default values should be created in newly created context
-		let fctx = Context::new_future();
-		let mut defaults =
-			FxHashMap::with_capacity(params.binds_len() - filled_named - filled_positionals);
-
-		for (idx, into, default) in params
-			.exprs
-			.iter()
-			.enumerate()
-			.filter_map(|(i, p)| Some((i, &p.destruct, p.default.as_ref()?)))
-		{
-			if let ParamName::Named(name) = into.name() {
-				if passed_args.contains_key(&name) {
-					continue;
-				}
-			} else if idx < filled_positionals {
-				continue;
-			}
-
-			destruct(
-				into,
-				{
-					let ctx = fctx.clone();
-					let name = into.name();
-					let value = default.clone();
-					Thunk!(move || evaluate_named_param(ctx.unwrap(), &value, name))
-				},
-				fctx.clone(),
-				&mut defaults,
-			)?;
-			if into.name().is_named() {
-				filled_named += 1;
-			} else {
-				filled_positionals += 1;
-			}
-		}
-
-		// Some args still weren't filled
-		if filled_named + filled_positionals != params.len() {
-			for param in params.exprs.iter().skip(args.unnamed.len()) {
-				let mut found = false;
-				for (name, _) in &args.named {
-					if &param.destruct.name() == name {
-						found = true;
-					}
-				}
-				if !found {
-					bail!(FunctionParameterNotBoundInCall(
-						param.destruct.name(),
-						params.signature.clone()
-					));
-				}
-			}
-			unreachable!();
-		}
-
-		Ok(body_ctx
-			.extend_bindings(passed_args)
-			.extend_bindings(defaults)
-			.into_future(fctx))
-	} else {
-		let body_ctx = body_ctx.extend_bindings(passed_args);
-		Ok(body_ctx)
-	}
-}
-
-/// You shouldn't probally use this function, use `jrsonnet_macros::builtin` instead
-///
-/// ## Parameters
-/// * `ctx`: used for passed argument expressions' execution and for body execution (if `body_ctx` is not set)
-/// * `params`: function parameters' definition
-/// * `args`: passed function arguments
-/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily
-pub fn parse_builtin_call(
-	ctx: Context,
-	params: FunctionSignature,
-	args: &ArgsDesc,
-	tailstrict: bool,
-) -> Result<Vec<Option<Thunk<Val>>>> {
-	let mut passed_args: Vec<Option<Thunk<Val>>> = vec![None; params.len()];
-	if args.unnamed.len() > params.len() {
-		bail!(TooManyArgsFunctionHas(params.len(), params,))
-	}
-
-	let mut filled_args = 0;
-
-	for (id, arg) in args.unnamed.iter().enumerate() {
-		passed_args[id] = Some(eval_arg(ctx.clone(), arg, tailstrict)?);
-		filled_args += 1;
-	}
-
-	for (name, arg) in &args.named {
-		// FIXME: O(n) for arg existence check
-		let id = params
-			.iter()
-			.position(|p| p.name() == name)
-			.ok_or_else(|| UnknownFunctionParameter(name.clone()))?;
-		if passed_args[id]
-			.replace(eval_arg(ctx.clone(), arg, tailstrict)?)
-			.is_some()
-		{
-			bail!(BindingParameterASecondTime(name.clone()));
-		}
-		filled_args += 1;
-	}
-
-	if filled_args < params.len() {
-		for (id, _) in params.iter().enumerate().filter(|(_, p)| p.has_default()) {
-			if passed_args[id].is_some() {
-				continue;
-			}
-			filled_args += 1;
-		}
-
-		// Some args still wasn't filled
-		if filled_args != params.len() {
-			for param in params.iter().skip(args.unnamed.len()) {
-				let mut found = false;
-				for (name, _) in &args.named {
-					if param.name() == name {
-						found = true;
-					}
-				}
-				if !found {
-					bail!(FunctionParameterNotBoundInCall(
-						param.name().clone(),
-						params,
-					));
-				}
-			}
-			unreachable!();
-		}
-	}
-	Ok(passed_args)
-}
 
 /// Creates Context, which has all argument default values applied
 /// and with unbound values causing error to be returned
modifiedcrates/jrsonnet-ir-parser/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-ir-parser/src/lib.rs
+++ b/crates/jrsonnet-ir-parser/src/lib.rs
@@ -416,10 +416,11 @@
 
 fn args(p: &mut Parser<'_>) -> Result<ArgsDesc> {
 	if p.at(T![')']) {
-		return Ok(ArgsDesc::new(Vec::new(), Vec::new()));
+		return Ok(ArgsDesc::new(Vec::new(), Vec::new(), Vec::new()));
 	}
 	let mut unnamed = Vec::new();
-	let mut named = Vec::new();
+	let mut names = Vec::new();
+	let mut values = Vec::new();
 	let mut named_started = false;
 	loop {
 		let is_named = p.at(SyntaxKind::IDENT) && {
@@ -430,7 +431,9 @@
 			let name: IStr = ident(p)?;
 			p.eat(T![=])?;
 			let value = Rc::new(expr(p)?);
-			named.push((name, value));
+
+			names.push(name);
+			values.push(value);
 			named_started = true;
 		} else {
 			if named_started {
@@ -445,7 +448,7 @@
 			break;
 		}
 	}
-	Ok(ArgsDesc::new(unnamed, named))
+	Ok(ArgsDesc::new(unnamed, names, values))
 }
 
 fn bind(p: &mut Parser<'_>) -> Result<BindSpec> {
modifiedcrates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__function_and_call.snapdiffbeforeafterboth
--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__function_and_call.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__function_and_call.snap
@@ -66,12 +66,12 @@
                     2.0,
                 ),
             ],
-            named: [
-                (
-                    "y",
-                    Num(
-                        3.0,
-                    ),
+            names: [
+                "y",
+            ],
+            values: [
+                Num(
+                    3.0,
                 ),
             ],
         } from virtual:<test>:26-34,
modifiedcrates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__index_and_suffix.snapdiffbeforeafterboth
--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__index_and_suffix.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__index_and_suffix.snap
@@ -23,7 +23,8 @@
                     2.0,
                 ),
             ],
-            named: [],
+            names: [],
+            values: [],
         } from virtual:<test>:8-11,
         false,
     ),
modifiedcrates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@array_comp.jsonnet.snapdiffbeforeafterboth
--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@array_comp.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@array_comp.jsonnet.snap
@@ -26,7 +26,8 @@
                             "x" from virtual:<test>:16-17,
                         ),
                     ],
-                    named: [],
+                    names: [],
+                    values: [],
                 } from virtual:<test>:15-18,
                 false,
             ),
modifiedcrates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@reserved.jsonnet.snapdiffbeforeafterboth
--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@reserved.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@reserved.jsonnet.snap
@@ -24,7 +24,8 @@
                         "null_fields" from virtual:<test>:20-31,
                     ),
                 ],
-                named: [],
+                names: [],
+                values: [],
             } from virtual:<test>:16-32,
             false,
         ),
modifiedcrates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@suffix.jsonnet.snapdiffbeforeafterboth
--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@suffix.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@suffix.jsonnet.snap
@@ -28,7 +28,8 @@
                         2.0,
                     ),
                 ],
-                named: [],
+                names: [],
+                values: [],
             } from virtual:<test>:15-18,
             false,
         ),
@@ -52,7 +53,8 @@
                         2.0,
                     ),
                 ],
-                named: [],
+                names: [],
+                values: [],
             } from virtual:<test>:28-31,
             false,
         ),
modifiedcrates/jrsonnet-ir/src/expr.rsdiffbeforeafterboth
--- a/crates/jrsonnet-ir/src/expr.rs
+++ b/crates/jrsonnet-ir/src/expr.rs
@@ -195,11 +195,16 @@
 #[derive(Debug, PartialEq, Acyclic)]
 pub struct ArgsDesc {
 	pub unnamed: Vec<Rc<Expr>>,
-	pub named: Vec<(IStr, Rc<Expr>)>,
+	pub names: Vec<IStr>,
+	pub values: Vec<Rc<Expr>>,
 }
 impl ArgsDesc {
-	pub fn new(unnamed: Vec<Rc<Expr>>, named: Vec<(IStr, Rc<Expr>)>) -> Self {
-		Self { unnamed, named }
+	pub fn new(unnamed: Vec<Rc<Expr>>, names: Vec<IStr>, values: Vec<Rc<Expr>>) -> Self {
+		Self {
+			unnamed,
+			names,
+			values,
+		}
 	}
 }
 
modifiedcrates/jrsonnet-ir/src/visit.rsdiffbeforeafterboth
216 }216 }
217 Expr::Apply(expr, spanned, _) => {217 Expr::Apply(expr, spanned, _) => {
218 v.visit_expr(expr);218 v.visit_expr(expr);
219 let ArgsDesc { unnamed, named } = &**spanned;219 let ArgsDesc {
220 unnamed,
221 names: _,
222 values,
223 } = &**spanned;
220 for unnamed in unnamed {224 for unnamed in unnamed {
221 v.visit_expr(unnamed);225 v.visit_expr(unnamed);
222 }226 }
223 for (_name, named) in named {227 for named in values {
224 v.visit_expr(named);228 v.visit_expr(named);
225 }229 }
226 }230 }
modifiedcrates/jrsonnet-peg-parser/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-peg-parser/src/lib.rs
+++ b/crates/jrsonnet-peg-parser/src/lib.rs
@@ -73,12 +73,14 @@
 			= args:arg(s)**comma() comma()? {?
 				let unnamed_count = args.iter().take_while(|(n, _)| n.is_none()).count();
 				let mut unnamed = Vec::with_capacity(unnamed_count);
-				let mut named = Vec::with_capacity(args.len() - unnamed_count);
+				let mut names = Vec::with_capacity(args.len() - unnamed_count);
+				let mut values = Vec::with_capacity(args.len() - unnamed_count);
 				let mut named_started = false;
 				for (name, value) in args {
 					if let Some(name) = name {
 						named_started = true;
-						named.push((name, value));
+						names.push(name);
+						values.push(value);
 					} else {
 						if named_started {
 							return Err("<named argument>")
@@ -86,7 +88,7 @@
 						unnamed.push(value);
 					}
 				}
-				Ok(ArgsDesc::new(unnamed, named))
+				Ok(ArgsDesc{unnamed, names, values})
 			}
 
 		pub rule destruct_rest() -> DestructRest
modifiedcrates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@array_comp.jsonnet.snapdiffbeforeafterboth
--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@array_comp.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@array_comp.jsonnet.snap
@@ -26,7 +26,8 @@
                             "x" from virtual:<test>:16-17,
                         ),
                     ],
-                    named: [],
+                    names: [],
+                    values: [],
                 } from virtual:<test>:15-18,
                 false,
             ),
modifiedcrates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@reserved.jsonnet.snapdiffbeforeafterboth
--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@reserved.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@reserved.jsonnet.snap
@@ -24,7 +24,8 @@
                         "null_fields" from virtual:<test>:20-31,
                     ),
                 ],
-                named: [],
+                names: [],
+                values: [],
             } from virtual:<test>:16-32,
             false,
         ),
modifiedcrates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@suffix.jsonnet.snapdiffbeforeafterboth
--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@suffix.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@suffix.jsonnet.snap
@@ -28,7 +28,8 @@
                         2.0,
                     ),
                 ],
-                named: [],
+                names: [],
+                values: [],
             } from virtual:<test>:15-18,
             false,
         ),
@@ -52,7 +53,8 @@
                         2.0,
                     ),
                 ],
-                named: [],
+                names: [],
+                values: [],
             } from virtual:<test>:28-31,
             false,
         ),
modifiedcrates/jrsonnet-stdlib/src/keyf.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/keyf.rs
+++ b/crates/jrsonnet-stdlib/src/keyf.rs
@@ -1,14 +1,16 @@
 use jrsonnet_evaluator::{
 	Error, Result, Thunk, Val,
-	function::{CallLocation, FuncVal, PreparedFuncVal},
+	function::{FuncVal, NativeFn},
 	typed::{ComplexValType, FromUntyped, Typed, ValType},
 };
 
+type PreparedKeyF = NativeFn!((Thunk<Val>) -> Val);
+
 #[derive(Default, Clone)]
 pub enum KeyF {
 	#[default]
 	Identity,
-	Prepared(PreparedFuncVal),
+	Prepared(PreparedKeyF),
 	PrepareFailure(Error),
 }
 impl KeyF {
@@ -19,13 +21,13 @@
 		if val.is_identity() {
 			Self::Identity
 		} else {
-			PreparedFuncVal::new(val, 1, &[]).map_or_else(Self::PrepareFailure, Self::Prepared)
+			PreparedKeyF::try_from(val).map_or_else(Self::PrepareFailure, Self::Prepared)
 		}
 	}
 	pub fn eval(&self, val: impl Into<Thunk<Val>>) -> Result<Val> {
 		match self {
 			KeyF::Identity => val.into().evaluate(),
-			KeyF::Prepared(p) => p.call(CallLocation::native(), &[val.into()], &[]),
+			KeyF::Prepared(p) => p.call(val.into()),
 			KeyF::PrepareFailure(e) => Err(e.clone()),
 		}
 	}