git.delta.rocks / jrsonnet / refs/commits / b5fcc2639d61

difftreelog

fix ObjExtend should work with non-object lhs

urkyrlvxYaroslav Bolyukin2026-07-31parent: #3132268.patch.diff
in: master

2 files changed

modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
8use self::{8use self::{
9 compspec::{evaluate_arr_comp, evaluate_obj_comp},9 compspec::{evaluate_arr_comp, evaluate_obj_comp},
10 destructure::evaluate_locals_unbound,10 destructure::evaluate_locals_unbound,
11 operator::evaluate_binary_op_special,11 operator::{evaluate_add_op, evaluate_binary_op},
12};12};
13use crate::{13use crate::{
14 CcObjectAssertion, CcUnbound, Context, Error, MaybeUnbound, ObjValue, ObjValueBuilder,14 CcObjectAssertion, CcUnbound, Context, Error, MaybeUnbound, ObjValue, ObjValueBuilder,
137 let value = evaluate(ctx, value)?;137 let value = evaluate(ctx, value)?;
138 evaluate_unary_op(*op, &value)?138 evaluate_unary_op(*op, &value)?
139 }139 }
140 LExpr::BinaryOp { lhs, op, rhs } => evaluate_binary_op_special(ctx, lhs, *op, rhs)?,140 LExpr::BinaryOp { lhs, op, rhs } => evaluate_binary_op(ctx, lhs, *op, rhs)?,
141 LExpr::LocalExpr(l) => {141 LExpr::LocalExpr(l) => {
142 ctx = ctx142 ctx = ctx
143 .pack_captures_sup_this(&l.frame_shape)143 .pack_captures_sup_this(&l.frame_shape)
202 LExpr::ObjExtend(lhs, body) => {202 LExpr::ObjExtend(lhs, body) => {
203 let lhs_val = evaluate(ctx.clone(), lhs)?;203 let lhs_val = evaluate(ctx.clone(), lhs)?;
204 let Val::Obj(lhs_obj) = lhs_val else {204 let Val::Obj(lhs_obj) = lhs_val else {
205 bail!(TypeMismatch(205 return evaluate_add_op(&lhs_val, &evaluate_obj_body(None, ctx, body)?);
206 "object extend lhs",
207 vec![ValType::Obj],
208 lhs_val.value_type(),
209 ))
210 };206 };
211 evaluate_obj_body(Some(lhs_obj), ctx, body)?207 evaluate_obj_body(Some(lhs_obj), ctx, body)?
modifiedcrates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth
159 })159 })
160}160}
161
162pub fn evaluate_binary_op_special(
163 ctx: Context,
164 a: &LExpr,
165 op: BinaryOpType,
166 b: &LExpr,
167) -> Result<Val> {
168 use BinaryOpType::*;
169 use Val::*;
170
171 Ok(match (evaluate(ctx.clone(), a)?, op, b) {
172 (Bool(true), Or, _) => Val::Bool(true),
173 (Bool(false), And, _) => Val::Bool(false),
174 #[cfg(feature = "exp-null-coaelse")]
175 (Null, NullCoaelse, eb) => evaluate(ctx, eb)?,
176 #[cfg(feature = "exp-null-coaelse")]
177 (a, NullCoaelse, _) => a,
178 (a, In, LExpr::Super) => {
179 let sup_this = ctx.try_sup_this()?;
180 if !sup_this.has_super() {
181 return Ok(Val::Bool(false));
182 }
183 return Ok(Val::Bool(sup_this.field_in_super(a.to_string()?)));
184 }
185 (a, op, eb) => evaluate_binary_op_normal(&a, op, &evaluate(ctx, eb)?)?,
186 })
187}
188161
189pub fn evaluate_compare_op(a: &Val, b: &Val, op: BinaryOpType) -> Result<Ordering> {162pub fn evaluate_compare_op(a: &Val, b: &Val, op: BinaryOpType) -> Result<Ordering> {
190 use Val::*;163 use Val::*;
216 })189 })
217}190}
218191
192/// Short-circuit operators (`||`, `&&`, `??`) and `in super`
193pub fn evaluate_binary_op(ctx: Context, a: &LExpr, op: BinaryOpType, b: &LExpr) -> Result<Val> {
194 use BinaryOpType::*;
195 use Val::*;
196
197 Ok(match (evaluate(ctx.clone(), a)?, op, b) {
198 (Bool(true), Or, _) => Val::Bool(true),
199 (Bool(false), And, _) => Val::Bool(false),
200 #[cfg(feature = "exp-null-coaelse")]
201 (Null, NullCoaelse, eb) => evaluate(ctx, eb)?,
202 #[cfg(feature = "exp-null-coaelse")]
203 (a, NullCoaelse, _) => a,
204 (a, In, LExpr::Super) => {
205 let sup_this = ctx.try_sup_this()?;
206 if !sup_this.has_super() {
207 return Ok(Val::Bool(false));
208 }
209 return Ok(Val::Bool(sup_this.field_in_super(a.to_string()?)));
210 }
211 (a, op, eb) => evaluate_binary_op_eager(&a, op, &evaluate(ctx, eb)?)?,
212 })
213}
214
215/// Evaluation of non-short-circuiting binary operators
216/// short-circuit operators will be thrown out of here.
219pub fn evaluate_binary_op_normal(a: &Val, op: BinaryOpType, b: &Val) -> Result<Val> {217fn evaluate_binary_op_eager(a: &Val, op: BinaryOpType, b: &Val) -> Result<Val> {
220 use BinaryOpType::*;218 use BinaryOpType::*;
221 use Val::*;219 use Val::*;
222 Ok(match (a, op, b) {220 Ok(match (a, op, b) {
228 (a, Lte, b) => Bool(evaluate_compare_op(a, b, Lte)?.is_le()),226 (a, Lte, b) => Bool(evaluate_compare_op(a, b, Lte)?.is_le()),
229 (a, Gte, b) => Bool(evaluate_compare_op(a, b, Gte)?.is_ge()),227 (a, Gte, b) => Bool(evaluate_compare_op(a, b, Gte)?.is_ge()),
230228
231 (Str(a), In, Obj(obj)) => Bool(obj.has_field_ex(a.clone().into_flat(), true)),229 (Str(a), In, Obj(obj)) => {
230 // standalone super obj should not reach this path, because of short-circuit impl
231 Bool(obj.has_field_ex(a.clone().into_flat(), true))
232 }
232233
233 // Bool X Bool234 // Bool X Bool
234 (Bool(a), And, Bool(b)) => Bool(*a && *b),235 (Bool(a), And, Bool(b)) => {
236 assert!(*a, "a == false would return from short-circuit impl");
237 Bool(*b)
238 }
235 (Bool(a), Or, Bool(b)) => Bool(*a || *b),239 (Bool(a), Or, Bool(b)) => {
240 assert!(!a, "a == true would return from short-circuit impl");
241 Bool(*b)
242 }
243
244 #[cfg(feature = "exp-null-coaelse")]
245 (_, NullCoaelse, _) => panic!("?? should return from short-circuit impl"),
236246
237 (a, Add, b) => evaluate_add_op(a, b)?,247 (a, Add, b) => evaluate_add_op(a, b)?,
238 (a, Sub, b) => evaluate_sub_op(a, b)?,248 (a, Sub, b) => evaluate_sub_op(a, b)?,