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
1use std::rc::Rc;
2
3use jrsonnet_ir::{1use jrsonnet_ir::ExprParams;
4 ArgsDesc, Expr, ExprParams,
5 function::{FunctionSignature, ParamName},
6};
7use rustc_hash::FxHashMap;2use rustc_hash::FxHashMap;
83
9use crate::{4use crate::{
10 Context, Pending, Thunk, Val, bail,5 Context, Thunk,
11 destructure::destruct,6 destructure::destruct,
12 error::{ErrorKind::*, Result},7 error::{ErrorKind::*, Result},
13 evaluate, evaluate_named_param,8 evaluate_named_param,
14 gc::WithCapacityExt as _,9 gc::WithCapacityExt as _,
15};10};
16
17fn eval_arg(ctx: Context, arg: &Rc<Expr>, tailstrict: bool) -> Result<Thunk<Val>> {
18 if tailstrict {
19 Ok(Thunk::evaluated(evaluate(ctx, arg)?))
20 } else {
21 let arg = arg.clone();
22 Ok(Thunk!(move || evaluate(ctx, &arg)))
23 }
24}
25
26/// Creates correct [context](Context) for function body evaluation returning error on invalid call.
27///
28/// ## Parameters
29/// * `ctx`: used for passed argument expressions' execution and for body execution (if `body_ctx` is not set)
30/// * `body_ctx`: used for default parameter values' execution and for body execution (if set)
31/// * `params`: function parameters' definition
32/// * `args`: passed function arguments
33/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily
34pub(crate) fn parse_function_call(
35 ctx: Context,
36 body_ctx: Context,
37 params: &ExprParams,
38 args: &ArgsDesc,
39 tailstrict: bool,
40) -> Result<Context> {
41 let mut passed_args = FxHashMap::with_capacity(params.binds_len());
42 if args.unnamed.len() > params.signature.len() {
43 bail!(TooManyArgsFunctionHas(
44 params.signature.len(),
45 params.signature.clone(),
46 ))
47 }
48
49 let mut filled_named = 0;
50 let mut filled_positionals = 0;
51
52 for (id, arg) in args.unnamed.iter().enumerate() {
53 destruct(
54 &params.exprs[id].destruct,
55 eval_arg(ctx.clone(), arg, tailstrict)?,
56 Pending::new_filled(ctx.clone()),
57 &mut passed_args,
58 )?;
59 filled_positionals += 1;
60 }
61
62 for (name, value) in &args.named {
63 // FIXME: O(n) for arg existence check
64 if !params.exprs.iter().any(|p| &p.destruct.name() == name) {
65 bail!(UnknownFunctionParameter(name.clone()));
66 }
67 if passed_args
68 .insert(name.clone(), eval_arg(ctx.clone(), value, tailstrict)?)
69 .is_some()
70 {
71 bail!(BindingParameterASecondTime(name.clone()));
72 }
73 filled_named += 1;
74 }
75
76 if filled_named + filled_positionals < params.len() {
77 // Some args are unset, but maybe we have defaults for them
78 // Default values should be created in newly created context
79 let fctx = Context::new_future();
80 let mut defaults =
81 FxHashMap::with_capacity(params.binds_len() - filled_named - filled_positionals);
82
83 for (idx, into, default) in params
84 .exprs
85 .iter()
86 .enumerate()
87 .filter_map(|(i, p)| Some((i, &p.destruct, p.default.as_ref()?)))
88 {
89 if let ParamName::Named(name) = into.name() {
90 if passed_args.contains_key(&name) {
91 continue;
92 }
93 } else if idx < filled_positionals {
94 continue;
95 }
96
97 destruct(
98 into,
99 {
100 let ctx = fctx.clone();
101 let name = into.name();
102 let value = default.clone();
103 Thunk!(move || evaluate_named_param(ctx.unwrap(), &value, name))
104 },
105 fctx.clone(),
106 &mut defaults,
107 )?;
108 if into.name().is_named() {
109 filled_named += 1;
110 } else {
111 filled_positionals += 1;
112 }
113 }
114
115 // Some args still weren't filled
116 if filled_named + filled_positionals != params.len() {
117 for param in params.exprs.iter().skip(args.unnamed.len()) {
118 let mut found = false;
119 for (name, _) in &args.named {
120 if &param.destruct.name() == name {
121 found = true;
122 }
123 }
124 if !found {
125 bail!(FunctionParameterNotBoundInCall(
126 param.destruct.name(),
127 params.signature.clone()
128 ));
129 }
130 }
131 unreachable!();
132 }
133
134 Ok(body_ctx
135 .extend_bindings(passed_args)
136 .extend_bindings(defaults)
137 .into_future(fctx))
138 } else {
139 let body_ctx = body_ctx.extend_bindings(passed_args);
140 Ok(body_ctx)
141 }
142}
143
144/// You shouldn't probally use this function, use `jrsonnet_macros::builtin` instead
145///
146/// ## Parameters
147/// * `ctx`: used for passed argument expressions' execution and for body execution (if `body_ctx` is not set)
148/// * `params`: function parameters' definition
149/// * `args`: passed function arguments
150/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily
151pub fn parse_builtin_call(
152 ctx: Context,
153 params: FunctionSignature,
154 args: &ArgsDesc,
155 tailstrict: bool,
156) -> Result<Vec<Option<Thunk<Val>>>> {
157 let mut passed_args: Vec<Option<Thunk<Val>>> = vec![None; params.len()];
158 if args.unnamed.len() > params.len() {
159 bail!(TooManyArgsFunctionHas(params.len(), params,))
160 }
161
162 let mut filled_args = 0;
163
164 for (id, arg) in args.unnamed.iter().enumerate() {
165 passed_args[id] = Some(eval_arg(ctx.clone(), arg, tailstrict)?);
166 filled_args += 1;
167 }
168
169 for (name, arg) in &args.named {
170 // FIXME: O(n) for arg existence check
171 let id = params
172 .iter()
173 .position(|p| p.name() == name)
174 .ok_or_else(|| UnknownFunctionParameter(name.clone()))?;
175 if passed_args[id]
176 .replace(eval_arg(ctx.clone(), arg, tailstrict)?)
177 .is_some()
178 {
179 bail!(BindingParameterASecondTime(name.clone()));
180 }
181 filled_args += 1;
182 }
183
184 if filled_args < params.len() {
185 for (id, _) in params.iter().enumerate().filter(|(_, p)| p.has_default()) {
186 if passed_args[id].is_some() {
187 continue;
188 }
189 filled_args += 1;
190 }
191
192 // Some args still wasn't filled
193 if filled_args != params.len() {
194 for param in params.iter().skip(args.unnamed.len()) {
195 let mut found = false;
196 for (name, _) in &args.named {
197 if param.name() == name {
198 found = true;
199 }
200 }
201 if !found {
202 bail!(FunctionParameterNotBoundInCall(
203 param.name().clone(),
204 params,
205 ));
206 }
207 }
208 unreachable!();
209 }
210 }
211 Ok(passed_args)
212}
21311
214/// Creates Context, which has all argument default values applied12/// Creates Context, which has all argument default values applied
215/// and with unbound values causing error to be returned13/// 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
--- a/crates/jrsonnet-ir/src/visit.rs
+++ b/crates/jrsonnet-ir/src/visit.rs
@@ -216,11 +216,15 @@
 		}
 		Expr::Apply(expr, spanned, _) => {
 			v.visit_expr(expr);
-			let ArgsDesc { unnamed, named } = &**spanned;
+			let ArgsDesc {
+				unnamed,
+				names: _,
+				values,
+			} = &**spanned;
 			for unnamed in unnamed {
 				v.visit_expr(unnamed);
 			}
-			for (_name, named) in named {
+			for named in values {
 				v.visit_expr(named);
 			}
 		}
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()),
 		}
 	}