difftreelog
fix exp-destruct
in: master
7 files changed
crates/jrsonnet-evaluator/src/analyze.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/analyze.rs
+++ b/crates/jrsonnet-evaluator/src/analyze.rs
@@ -425,7 +425,7 @@
/// h = 1 => referenced += [], closures += 0, destructs += 1
/// And the result is
///
- /// ```
+ /// ```rust,ignore
/// Closures {
/// referenced: vec![d, e, f, a, b, c, h]
/// spec_shapes: vec![(3, 3), (4, 3), (0, 1)],
crates/jrsonnet-evaluator/src/evaluate/compspec.rsdiffbeforeafterboth1use std::rc::Rc;23use jrsonnet_types::ValType;45use super::{6 destructure::{self, evaluate_locals, evaluate_locals_unbound},7 evaluate_field_member_static, evaluate_field_member_unbound,8};9use crate::{10 Context, ContextBuilder, ObjValue, ObjValueBuilder, Pending, Result, Thunk, Val,11 analyze::{LArrComp, LBind, LCompSpec, LDestruct, LExpr, LFieldMember, LObjComp, LocalId},12 arr::ArrValue,13 bail,14 error::ErrorKind::*,15 evaluate::evaluate,16};1718trait CompCollector {19 fn reserve(&mut self, _guaranteed: usize) {}20 fn collect(&mut self, ctx: Context) -> Result<()>;21}2223struct EagerArrCollector<'a> {24 out: &'a mut Vec<Val>,25 value: &'a LExpr,26}27impl CompCollector for EagerArrCollector<'_> {28 fn reserve(&mut self, size_hint: usize) {29 self.out.reserve(size_hint);30 }31 fn collect(&mut self, ctx: Context) -> Result<()> {32 self.out.push(evaluate(ctx, self.value)?);33 Ok(())34 }35}3637struct LazyArrCollector<'a> {38 out: &'a mut Vec<Thunk<Val>>,39 value: &'a Rc<LExpr>,40}41impl CompCollector for LazyArrCollector<'_> {42 fn reserve(&mut self, size_hint: usize) {43 self.out.reserve(size_hint);44 }45 fn collect(&mut self, ctx: Context) -> Result<()> {46 let value_expr = self.value.clone();47 self.out.push(Thunk!(move || evaluate(ctx, &value_expr)));48 Ok(())49 }50}5152struct ObjCompCollectorStatic<'a> {53 builder: &'a mut ObjValueBuilder,54 locals: &'a [LBind],55 field: &'a LFieldMember,56}57impl CompCollector for ObjCompCollectorStatic<'_> {58 fn reserve(&mut self, guaranteed: usize) {59 self.builder.reserve_fields(guaranteed);60 }61 fn collect(&mut self, inner_ctx: Context) -> Result<()> {62 let value_ctx = evaluate_locals(inner_ctx.clone(), self.locals);63 evaluate_field_member_static(self.builder, inner_ctx, value_ctx, self.field)64 }65}6667struct ObjCompCollectorUnbound<'a> {68 builder: &'a mut ObjValueBuilder,69 locals: Rc<Vec<LBind>>,70 this_id: Option<LocalId>,71 field: &'a LFieldMember,72}73impl CompCollector for ObjCompCollectorUnbound<'_> {74 fn reserve(&mut self, guaranteed: usize) {75 self.builder.reserve_fields(guaranteed);76 }77 fn collect(&mut self, inner_ctx: Context) -> Result<()> {78 let uctx = evaluate_locals_unbound(inner_ctx.clone(), self.locals.clone(), self.this_id);79 evaluate_field_member_unbound(self.builder, inner_ctx, uctx, self.field)80 }81}8283pub fn evaluate_obj_comp(84 super_obj: Option<ObjValue>,85 ctx: Context,86 comp: &LObjComp,87) -> Result<Val> {88 let mut builder = ObjValueBuilder::new();89 if let Some(super_obj) = super_obj {90 builder.with_super(super_obj);91 }9293 let cached_overs = cache_overs(&ctx, &comp.compspecs)?;94 if comp.this.is_some() || comp.uses_super {95 evaluate_compspecs(96 ctx,97 &comp.compspecs,98 &cached_overs,99 0,100 0,101 &mut ObjCompCollectorUnbound {102 builder: &mut builder,103 locals: comp.locals.clone(),104 this_id: comp.this,105 field: &comp.field,106 },107 )?;108 } else {109 evaluate_compspecs(110 ctx,111 &comp.compspecs,112 &cached_overs,113 0,114 0,115 &mut ObjCompCollectorStatic {116 builder: &mut builder,117 locals: &comp.locals,118 field: &comp.field,119 },120 )?;121 }122123 Ok(Val::Obj(builder.build()))124}125126pub fn evaluate_arr_comp(ctx: Context, comp: &LArrComp) -> Result<Val> {127 let cached_overs = cache_overs(&ctx, &comp.compspecs)?;128129 // In eager evaluation, Context is not captured, thus updates in CoW fashion will likely to success130 'eager: {131 let mut out = Vec::new();132133 if evaluate_compspecs_eager(134 ctx.clone(),135 &comp.compspecs,136 &cached_overs,137 0,138 0,139 &mut EagerArrCollector {140 out: &mut out,141 value: &comp.value,142 },143 )144 .is_err()145 {146 break 'eager;147 }148 return Ok(Val::arr(out));149 }150151 let mut items: Vec<Thunk<Val>> = Vec::new();152 evaluate_compspecs(153 ctx,154 &comp.compspecs,155 &cached_overs,156 0,157 0,158 &mut LazyArrCollector {159 out: &mut items,160 value: &comp.value,161 },162 )?;163 Ok(Val::arr(items))164}165166fn cache_overs(ctx: &Context, specs: &[LCompSpec]) -> Result<Vec<Option<ArrValue>>> {167 specs168 .iter()169 .map(|spec| {170 Ok(match spec {171 LCompSpec::For {172 over,173 loop_invariant: true,174 ..175 } => {176 let val = evaluate(ctx.clone(), over)?;177 let Val::Arr(arr) = val else {178 bail!(InComprehensionCanOnlyIterateOverArray)179 };180 Some(arr)181 }182 _ => None,183 })184 })185 .collect::<Result<_>>()186}187188fn evaluate_compspecs_eager(189 ctx: Context,190 specs: &[LCompSpec],191 cached_overs: &[Option<ArrValue>],192 idx: usize,193 guaranteed_reserve: usize,194 collector: &mut dyn CompCollector,195) -> Result<()> {196 if idx >= specs.len() {197 collector.reserve(guaranteed_reserve);198 return collector.collect(ctx);199 }200 match &specs[idx] {201 LCompSpec::If(cond) => {202 let val = evaluate(ctx.clone(), cond)?;203 let Val::Bool(b) = val else {204 bail!(TypeMismatch(205 "if spec condition",206 vec![ValType::Bool],207 val.value_type()208 ))209 };210 if b {211 evaluate_compspecs_eager(ctx, specs, cached_overs, idx + 1, 0, collector)?;212 }213 }214 LCompSpec::For { destruct, over, .. } => {215 let arr = if let Some(cached) = &cached_overs[idx] {216 cached.clone()217 } else {218 let arr_val = evaluate(ctx.clone(), over)?;219 let Val::Arr(arr) = arr_val else {220 bail!(InComprehensionCanOnlyIterateOverArray)221 };222 arr223 };224 let inner_reserve = guaranteed_reserve.max(1) * arr.len() as usize;225 match destruct {226 LDestruct::Full(id) => {227 let id = *id;228 let mut inner_ctx = ContextBuilder::extend(ctx, 1).build();229 for (i, item) in arr.iter().enumerate() {230 // TODO: reuse one ContextBuilder for full evaluate_compspecs pipeline231 inner_ctx.cow_fill_binding(id, Thunk::evaluated(item?));232 evaluate_compspecs_eager(233 inner_ctx.clone(),234 specs,235 cached_overs,236 idx + 1,237 if i == 0 { inner_reserve } else { 0 },238 collector,239 )?;240 }241 }242 // TODO: Should not be eager? CoW won't work here243 #[cfg(feature = "exp-destruct")]244 _ => {245 for (i, item) in arr.iter().enumerate() {246 let item_val = item?;247 let mut inner_builder = ContextBuilder::extend(ctx.clone(), 1);248 let fctx = Pending::new();249 destructure::destruct(250 destruct,251 Thunk::evaluated(item_val),252 fctx.clone(),253 &mut inner_builder,254 );255 let inner_ctx = inner_builder.build().into_future(fctx);256 evaluate_compspecs_eager(257 inner_ctx,258 specs,259 cached_overs,260 idx + 1,261 if i == 0 { inner_reserve } else { 0 },262 collector,263 )?;264 }265 }266 }267 }268 }269 Ok(())270}271272fn evaluate_compspecs(273 ctx: Context,274 specs: &[LCompSpec],275 cached_overs: &[Option<ArrValue>],276 idx: usize,277 guaranteed_reserve: usize,278 collector: &mut dyn CompCollector,279) -> Result<()> {280 if idx >= specs.len() {281 collector.reserve(guaranteed_reserve);282 return collector.collect(ctx);283 }284 match &specs[idx] {285 LCompSpec::If(cond) => {286 let val = evaluate(ctx.clone(), cond)?;287 let Val::Bool(b) = val else {288 bail!(TypeMismatch(289 "if spec condition",290 vec![ValType::Bool],291 val.value_type()292 ))293 };294 if b {295 evaluate_compspecs(ctx, specs, cached_overs, idx + 1, 0, collector)?;296 }297 }298 LCompSpec::For { destruct, over, .. } => {299 let arr = if let Some(cached) = &cached_overs[idx] {300 cached.clone()301 } else {302 let arr_val = evaluate(ctx.clone(), over)?;303 let Val::Arr(arr) = arr_val else {304 bail!(InComprehensionCanOnlyIterateOverArray)305 };306 arr307 };308 let inner_reserve = guaranteed_reserve.max(1) * arr.len() as usize;309 for (i, item) in arr.iter().enumerate() {310 let item_val = item?;311 let mut inner_builder = ContextBuilder::extend(ctx.clone(), 1);312 let fctx = Pending::new();313 destructure::destruct(314 destruct,315 Thunk::evaluated(item_val),316 fctx.clone(),317 &mut inner_builder,318 );319 let inner_ctx = inner_builder.build().into_future(fctx);320 evaluate_compspecs(321 inner_ctx,322 specs,323 cached_overs,324 idx + 1,325 if i == 0 { inner_reserve } else { 0 },326 collector,327 )?;328 }329 }330 }331 Ok(())332}crates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
@@ -12,7 +12,7 @@
#[allow(dead_code, reason = "not dead in exp-destruct")]
fn destruct_array(
start: &[LDestruct],
- rest: Option<LDestructRest>,
+ rest: Option<&LDestructRest>,
end: &[LDestruct],
value: Thunk<Val>,
@@ -56,7 +56,7 @@
if let Some(crate::analyze::LDestructRest::Keep(id)) = rest {
let full = full.clone();
builder.bind(
- id,
+ *id,
Thunk!(move || {
let full = full.evaluate()?;
let to = full.len() - end_len;
@@ -88,7 +88,7 @@
#[allow(dead_code, reason = "not dead in exp-destruct")]
fn destruct_object(
fields: &[LDestructField],
- rest: Option<LDestructRest>,
+ rest: Option<&LDestructRest>,
value: Thunk<Val>,
fctx: Pending<Context>,
@@ -127,7 +127,7 @@
if let Some(crate::analyze::LDestructRest::Keep(id)) = rest {
let full = full.clone();
builder.bind(
- id,
+ *id,
Thunk!(move || {
let full = full.evaluate()?;
let mut out = ObjValueBuilder::new();
@@ -178,9 +178,13 @@
#[cfg(feature = "exp-destruct")]
LDestruct::Skip => {}
#[cfg(feature = "exp-destruct")]
- LDestruct::Array { start, rest, end } => destruct_array(start, rest, end, value, fctx, builder),
+ LDestruct::Array { start, rest, end } => {
+ destruct_array(start, rest.as_ref(), end, value, fctx, builder)
+ }
#[cfg(feature = "exp-destruct")]
- LDestruct::Object { fields, rest } => destruct_object(fields, rest, value, fctx, builder),
+ LDestruct::Object { fields, rest } => {
+ destruct_object(fields, rest.as_ref(), value, fctx, builder)
+ }
}
}
crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@redeclared_local.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@redeclared_local.jsonnet.snap
+++ b/crates/jrsonnet-evaluator/src/snapshots/jrsonnet_evaluator__analyze__tests__snapshots@redeclared_local.jsonnet.snap
@@ -1,7 +1,7 @@
---
source: crates/jrsonnet-evaluator/src/analyze.rs
expression: rendered
-input_file: crates/jrsonnet-evaluator/src/analyze_tests/redeclared_local.jsonnet
+input_file: crates/jrsonnet-evaluator/src/analysis_tests/redeclared_local.jsonnet
---
--- source ---
local x = 1, x = 2; x
@@ -10,7 +10,7 @@
local_dependent_depth: 0
errored: true
--- diagnostics ---
- · ╭── variable redeclared: x
+ · ╭── local is already defined in the current frame: x
1 │ local x = 1, x = 2; x
2 │
--- lir ---
crates/jrsonnet-ir-parser/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/lib.rs
+++ b/crates/jrsonnet-ir-parser/src/lib.rs
@@ -381,7 +381,7 @@
None
};
let default = if p.try_eat(T![=]) {
- Some(Rc::new(spanned(p, expr)?))
+ Some(spanned(p, expr)?)
} else {
None
};
@@ -466,8 +466,10 @@
if !p.at(SyntaxKind::IDENT) {
let d = destruct(p)?;
p.eat(T![=])?;
- let value = Rc::new(expr(p)?);
- return Ok(BindSpec::Field { into: d, value });
+ return Ok(BindSpec::Field {
+ into: d,
+ value: expr(p)?,
+ });
}
}
let name_spanned = spanned(p, ident)?;
crates/jrsonnet-ir/src/expr.rsdiffbeforeafterboth--- a/crates/jrsonnet-ir/src/expr.rs
+++ b/crates/jrsonnet-ir/src/expr.rs
@@ -211,7 +211,7 @@
}
}
-#[derive(Debug, Clone, PartialEq, Eq, Acyclic)]
+#[derive(Debug, PartialEq, Eq, Acyclic)]
pub enum DestructRest {
/// ...rest
Keep(IStr),
@@ -219,7 +219,7 @@
Drop,
}
-#[derive(Debug, Clone, PartialEq, Acyclic)]
+#[derive(Debug, PartialEq, Acyclic)]
pub enum Destruct {
Full(Spanned<IStr>),
#[cfg(feature = "exp-destruct")]
@@ -233,7 +233,7 @@
#[cfg(feature = "exp-destruct")]
Object {
#[allow(clippy::type_complexity)]
- fields: Vec<(IStr, Option<Destruct>, Option<Rc<Spanned<Expr>>>)>,
+ fields: Vec<(IStr, Option<Destruct>, Option<Spanned<Expr>>)>,
rest: Option<DestructRest>,
},
}
crates/jrsonnet-peg-parser/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/src/lib.rs
+++ b/crates/jrsonnet-peg-parser/src/lib.rs
@@ -1,5 +1,3 @@
-use std::rc::Rc;
-
use jrsonnet_gcmodule::Acyclic;
use jrsonnet_ir::{
ArgsDesc, AssertExpr, AssertStmt, BinaryOp, BindSpec, CompSpec, Destruct, DestructRest, Expr,
@@ -110,7 +108,7 @@
}
pub rule destruct_object(s: &ParserSettings) -> Destruct
= "{" _
- fields:(name:id() into:(_ ":" _ into:destruct(s) {into})? default:(_ "=" _ v:spanned(<expr(s)>, s) {v})? {(name, into, default.map(Rc::new))})**comma()
+ fields:(name:id() into:(_ ":" _ into:destruct(s) {into})? default:(_ "=" _ v:spanned(<expr(s)>, s) {v})? {(name, into, default)})**comma()
rest:(
comma() rest:destruct_rest()? {rest}
/ comma()? {None}