difftreelog
fix prepare with extra named arguments
in: master
2 files changed
crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -431,7 +431,6 @@
Ok(match value {
Val::Func(f) => {
let name = f.name();
- let prepare = PreparedFuncVal::new(f, args.unnamed.len(), &args.names)?;
let unnamed = args
.unnamed
.iter()
@@ -444,6 +443,8 @@
.cloned()
.map(|un| evaluate_thunk(ctx.clone(), un, tailstrict))
.collect::<Result<Vec<_>>>()?;
+ let prepare = PreparedFuncVal::new(f, args.unnamed.len(), &args.names)
+ .with_description_src(loc, || format!("function <{name}> call"))?;
let body = || prepare.call(loc, &unnamed, &named);
if tailstrict {
body()?
crates/jrsonnet-evaluator/src/function/prepared.rsdiffbeforeafterboth1use std::rc::Rc;23use jrsonnet_gcmodule::{Acyclic, Trace};4use jrsonnet_ir::{ExprParams, IStr, function::FunctionSignature};5use rustc_hash::{FxHashMap, FxHashSet};67use super::{CallLocation, FuncVal};8use crate::{9 Context, ContextBuilder, Pending, Result, Thunk, Val, bail, destructure::destruct,10 error::ErrorKind::*, evaluate_named_param, gc::WithCapacityExt,11};1213#[derive(Debug, Trace, Clone)]14pub struct PreparedFuncVal {15 fun: FuncVal,16 prepared: Rc<PreparedCall>,17}1819impl PreparedFuncVal {20 pub fn new(fun: FuncVal, unnamed: usize, named: &[IStr]) -> Result<Self> {21 let prepared = prepare_call(fun.params(), unnamed, named)?;22 Ok(Self {23 fun,24 prepared: Rc::new(prepared),25 })26 }27 pub fn call(28 &self,29 loc: CallLocation<'_>,30 unnamed: &[Thunk<Val>],31 named: &[Thunk<Val>],32 ) -> Result<Val> {33 self.fun34 .evaluate_prepared(&self.prepared, loc, unnamed, named, false)35 }36}3738#[derive(Acyclic, Debug)]39pub struct PreparedCall {40 // Param, named input.41 named: Vec<(usize, usize)>,42 defaults: Vec<usize>,43}4445pub fn prepare_call(46 params: FunctionSignature,47 unnamed: usize,48 named: &[IStr],49) -> Result<PreparedCall> {50 if unnamed > params.len() {51 bail!(TooManyArgsFunctionHas(params.len(), params))52 }5354 let expected_defaults = params.len() - unnamed - named.len();55 let mut ops = PreparedCall {56 named: Vec::with_capacity(named.len()),57 defaults: Vec::with_capacity(expected_defaults),58 };5960 // FIXME: bitmask61 let mut passed: FxHashSet<usize> = (0..unnamed).collect();6263 for (input_id, name) in named.iter().enumerate() {64 // FIXME: O(n) for arg existence check65 let Some(param_idx) = params.iter().position(|p| p.name() == name) else {66 bail!(UnknownFunctionParameter(name.clone()));67 };68 if !passed.insert(param_idx) {69 bail!(BindingParameterASecondTime(name.clone()));70 }71 ops.named.push((param_idx, input_id));72 }7374 if named.len() + unnamed < params.len() {75 let mut defaults = 0;7677 for (param_id, param) in params78 .iter()79 .enumerate()80 .skip(unnamed)81 .filter(|p| p.1.has_default())82 {83 // Skip already passed parameters84 if !param.name().is_anonymous() && passed.contains(¶m_id) {85 continue;86 }87 defaults += 1;8889 ops.defaults.push(param_id);90 }9192 // Some args still weren't filled93 if defaults != expected_defaults {94 for param in params.iter().skip(unnamed) {95 let mut found = false;96 for name in named {97 if param.name() == name {98 found = true;99 }100 }101 if !found {102 bail!(FunctionParameterNotBoundInCall(103 param.name().clone(),104 params105 ));106 }107 }108 unreachable!();109 }110 }111112 Ok(ops)113}114pub fn parse_prepared_function_call(115 body_ctx: Context,116 prepared: &PreparedCall,117 params: &ExprParams,118 unnamed: &[Thunk<Val>],119 named: &[Thunk<Val>],120) -> Result<Context> {121 let mut passed_args = FxHashMap::with_capacity(params.binds_len());122123 let destruct_ctx = Pending::new();124125 for (param_idx, unnamed) in unnamed.iter().enumerate() {126 destruct(127 ¶ms.exprs[param_idx].destruct,128 unnamed.clone(),129 destruct_ctx.clone(),130 &mut passed_args,131 )?;132 }133134 for (param_idx, arg_idx) in prepared.named.iter().copied() {135 destruct(136 ¶ms.exprs[param_idx].destruct,137 named[arg_idx].clone(),138 destruct_ctx.clone(),139 &mut passed_args,140 )?;141 }142143 if prepared.defaults.is_empty() {144 let body_ctx = body_ctx145 .extend_bindings(passed_args)146 .into_future(destruct_ctx);147 Ok(body_ctx)148 } else {149 let fctx = Context::new_future();150 let mut defaults = FxHashMap::with_capacity(params.binds_len() - passed_args.len());151 for param_idx in prepared.defaults.iter().copied() {152 // let param = params.0.rc_idx(param_idx);153 destruct(154 ¶ms.exprs[param_idx].destruct,155 {156 let ctx = fctx.clone();157 let params = params.clone();158 Thunk!(move || {159 let param = ¶ms.exprs[param_idx];160 let name = param.destruct.name();161 let value = param.default.as_ref().expect("default exists");162 evaluate_named_param(ctx.unwrap(), value, name)163 })164 },165 fctx.clone(),166 &mut defaults,167 )?;168 }169170 let mut ctx = ContextBuilder::extend(body_ctx);171 ctx.binds(passed_args);172 ctx.binds(defaults);173 Ok(ctx.build().into_future(fctx).into_future(destruct_ctx))174 }175}176pub fn parse_prepared_builtin_call(177 prepared: &PreparedCall,178 params: FunctionSignature,179 unnamed: &[Thunk<Val>],180 named: &[Thunk<Val>],181) -> Vec<Option<Thunk<Val>>> {182 let mut passed_args = vec![None; params.len()];183184 for (param_idx, unnamed) in unnamed.iter().enumerate() {185 passed_args[param_idx] = Some(unnamed.clone());186 }187188 for (param_idx, arg_idx) in prepared.named.iter().copied() {189 passed_args[param_idx] = Some(named[arg_idx].clone());190 }191192 passed_args193}