--- a/crates/jrsonnet-evaluator/src/obj/mod.rs +++ b/crates/jrsonnet-evaluator/src/obj/mod.rs @@ -231,6 +231,7 @@ struct ObjValueInner { cores: Vec, assertions_ran: Cell, + #[trace(skip)] has_assertions: bool, value_cache: RefCell>, } @@ -475,7 +476,8 @@ #[must_use] pub fn extend_from(&self, sup: Self) -> Self { - let mut cores = sup.0.cores.clone(); + let mut cores = Vec::with_capacity(sup.0.cores.len() + self.0.cores.len()); + cores.extend(sup.0.cores.iter().cloned()); cores.extend(self.0.cores.iter().cloned()); let has_assertions = sup.0.has_assertions || self.0.has_assertions; ObjValue(Cc::new(ObjValueInner { @@ -603,7 +605,8 @@ } fn get_idx_uncached(&self, key: IStr, core: CoreIdx) -> Result> { self.run_assertions()?; - let mut add_stack = Vec::with_capacity(2); + let mut first_add = None; + let mut add_stack: Vec = Vec::new(); let mut skip = Saturating(0); for (sup, core) in self.0.cores[..core.idx].iter().enumerate().rev() { let sup_this = SupThis { @@ -611,7 +614,7 @@ this: self.clone(), }; match core.0.get_for_core(key.clone(), sup_this, skip.0 != 0)? { - GetFor::Final(val) if add_stack.is_empty() => { + GetFor::Final(val) if first_add.is_none() => { if skip.0 == 0 { return Ok(Some(val)); } @@ -624,33 +627,36 @@ } GetFor::SuperPlus(val) => { if skip.0 == 0 { - add_stack.push(val); + if first_add.is_none() { + first_add = Some(val); + } else { + add_stack.push(val); + } } } GetFor::Omit(new_skip) => { - // +1 including this core skip = skip.max(new_skip + Saturating(1)); } GetFor::NotFound => {} } skip -= 1; } + let Some(first) = first_add else { + if add_stack.is_empty() { + return Ok(None); + } + return Ok(Some(add_stack.pop().expect("single element on stack"))); + }; if add_stack.is_empty() { - // None of layers had this field - return Ok(None); - } else if add_stack.len() == 1 { - // A layer had this field, but it wanted this field to be added with super. - // However, no super had this field, fail-safe - return Ok(Some(add_stack.pop().expect("single element on stack"))); + return Ok(Some(first)); } + add_stack.insert(0, first); let mut values = add_stack.into_iter().rev(); let init = values.next().expect("at least 2 elements"); values .try_fold(init, |a, b| evaluate_add_op(&a, &b)) .map(Some) - - // self.0.get_raw(key, this) } pub fn get_or_bail(&self, key: IStr) -> Result {