From e06bcf3f9dcac7886c77bb933b6a7c7ced125262 Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Thu, 17 Jul 2025 22:50:01 +0800 Subject: [PATCH] fix: fixpoint --- src/engine/test.rs | 1 + src/env.rs | 69 ++++++++++++---------------------- src/eval/jit/compile.rs | 6 +++ src/eval/mod.rs | 6 +++ src/ir/ctx.rs | 3 -- src/ir/mod.rs | 82 +++++++++++++++++++++++------------------ src/ir/scc.rs | 45 +++++++++++----------- src/ty/internal/mod.rs | 6 +-- 8 files changed, 111 insertions(+), 107 deletions(-) diff --git a/src/engine/test.rs b/src/engine/test.rs index ca04571..eb9e469 100644 --- a/src/engine/test.rs +++ b/src/engine/test.rs @@ -207,6 +207,7 @@ fn test_func() { "(inputs@{ x, y, ... }: x + inputs.y) { x = 1; y = 2; z = 3; }", int!(3), ); + test_expr("let fix = f: let x = f x; in x; in (fix (self: { x = 1; y = self.x + 1; })).y", int!(2)); } #[bench] diff --git a/src/env.rs b/src/env.rs index 86d8ea9..29b1f34 100644 --- a/src/env.rs +++ b/src/env.rs @@ -8,9 +8,8 @@ use crate::ty::internal::Value; #[derive(Clone, Debug)] pub struct Env { - cache: Vec>, + stack: Vec, with: Vec>>, - args: Vec, } impl Default for Env { @@ -22,36 +21,37 @@ impl Default for Env { impl Env { pub fn new() -> Self { Self { - cache: Vec::from([HashMap::new()]), + stack: Vec::new(), with: Vec::new(), - args: Vec::new(), } } pub fn with_new_cache( &mut self, + len: usize, f: impl FnOnce(&mut Self) -> T, - ) -> (T, HashMap) { - self.cache.push(HashMap::new()); + ) -> (T, Vec) { + self.stack.reserve(len); let ret = f(self); - (ret, self.cache.pop().unwrap()) + (ret, self.stack.split_off(self.stack.len() - len)) } pub fn with_cache( &mut self, - cache: HashMap, + cache: Vec, + len: usize, f: impl FnOnce(&mut Self) -> T, - ) -> (T, HashMap) { - self.cache.push(cache); + ) -> (T, Vec) { + self.stack.extend(cache); let ret = f(self); - (ret, self.cache.pop().unwrap()) + (ret, self.stack.split_off(self.stack.len() - len)) } - pub fn insert_cache(&mut self, idx: usize, val: Value) { + /* pub fn insert_cache(&mut self, idx: usize, val: Value) { self.cache.last_mut().unwrap().insert(idx, val); - } + } */ - pub fn insert_cache_lazy( + /* pub fn insert_cache_lazy( &mut self, idx: usize, f: impl FnOnce(&mut Self) -> Result, @@ -61,25 +61,20 @@ impl Env { self.cache.last_mut().unwrap().insert(idx, val); } Ok(()) - } + } */ - pub fn lookup_cache( - &mut self, - idx: usize, - f: impl FnOnce(&mut Env) -> Result, - ) -> Result { - for level in self.cache.iter().rev() { - if let Some(ret) = level.get(&idx) { - return ret.clone().ok(); - } + pub fn insert_stack(&mut self, iter: impl IntoIterator Result>) -> Result<()> { + let iter = iter.into_iter(); + self.stack.reserve(iter.size_hint().0); + for f in iter { + let val = f(self)?; + self.stack.push(val); } - let val = f(self)?; - self.cache.last_mut().unwrap().insert(idx, val.clone()); - val.ok() + Ok(()) } - pub fn lookup_arg(&self, level: usize) -> Value { - self.args[self.args.len() - level - 1].clone() + pub fn lookup_stack(&mut self, idx: usize) -> Value { + self.stack.get(self.stack.len() - idx - 1).unwrap().clone() } pub fn lookup_with(&self, symbol: &str) -> Option { @@ -91,22 +86,6 @@ impl Env { None } - pub fn enter_arg(&mut self, arg: Value) { - self.args.push(arg); - } - - pub fn pop_args(&mut self, len: usize) -> Vec { - self.args.split_off(self.args.len() - len) - } - - pub fn reserve_args(&mut self, len: usize) { - self.args.reserve(len); - } - - pub fn enter_args(&mut self, args: Vec) { - self.args.extend(args); - } - pub fn exit_with(&mut self) { self.with.pop(); } diff --git a/src/eval/jit/compile.rs b/src/eval/jit/compile.rs index 544f305..02c08b1 100644 --- a/src/eval/jit/compile.rs +++ b/src/eval/jit/compile.rs @@ -540,6 +540,12 @@ impl JITCompile for LetVar { } } +impl JITCompile for Cache { + fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot { + todo!() + } +} + impl JITCompile for Thunk { fn compile(&self, ctx: &mut JITContext, engine: ir::Value, env: ir::Value) -> StackSlot { let slot = ctx.alloca(); diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 5cea40b..97a9f13 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -305,6 +305,12 @@ impl Evaluate for ir::LetVar { } } +impl Evaluate for ir::Cache { + fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { + todo!() + } +} + impl Evaluate for ir::Thunk { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { Value::Thunk(self.idx).ok() diff --git a/src/ir/ctx.rs b/src/ir/ctx.rs index c67ec0b..212159c 100644 --- a/src/ir/ctx.rs +++ b/src/ir/ctx.rs @@ -16,7 +16,6 @@ pub struct DowngradeContext { pub thunks: Vec<(Ir, bool)>, pub thunk_deps: Vec>, pub func_deps: Vec>, - pub func_arg_dep: Vec, pub funcs: Vec, } @@ -148,7 +147,6 @@ impl DowngradeContext { thunks: Vec::new(), thunk_deps: Vec::new(), func_deps: Vec::new(), - func_arg_dep: Vec::new(), funcs: Vec::new(), } } @@ -190,7 +188,6 @@ impl DowngradeContext { let idx = self.funcs.len(); self.funcs.push(func); self.func_deps.push(HashMap::new()); - self.func_arg_dep.push(false); LoadFunc { idx } } diff --git a/src/ir/mod.rs b/src/ir/mod.rs index fe1a998..93873ff 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -147,6 +147,8 @@ ir! { #[derive(Copy)] LetVar => { level: usize, idx: usize }, #[derive(Copy)] + Cache => { idx: usize }, + #[derive(Copy)] Thunk => { idx: usize }, Path => { expr: Box }, } @@ -362,9 +364,20 @@ impl Thunk { ctx: &mut DowngradeContext, env: &Env<'a, 'env>, ) -> Result { - ctx.new_dep(self_idx, Dep::Thunk(self.idx)); + let idx = ctx.new_dep(self_idx, Dep::Thunk(self.idx)); ctx.resolve_thunk(self.idx, env)?; - self.ir().ok() + Cache { idx }.ir().ok() + } +} + +impl Cache { + fn resolve<'a, 'env>( + self, + self_idx: Index, + ctx: &mut DowngradeContext, + env: &Env<'a, 'env>, + ) -> Result { + unreachable!() } } @@ -468,27 +481,28 @@ where impl Downgrade for Expr { fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + use Expr::*; match self { - Expr::Apply(apply) => apply.downgrade(ctx), - Expr::Assert(assert) => assert.downgrade(ctx), - Expr::Error(error) => Err(Error::DowngradeError(error.to_string())), - Expr::IfElse(ifelse) => ifelse.downgrade(ctx), - Expr::Select(select) => select.downgrade(ctx), - Expr::Str(str) => str.downgrade(ctx), - Expr::Path(path) => path.downgrade(ctx), - Expr::Literal(lit) => lit.downgrade(ctx), - Expr::Lambda(lambda) => lambda.downgrade(ctx), - Expr::LegacyLet(let_) => let_.downgrade(ctx), - Expr::LetIn(letin) => letin.downgrade(ctx), - Expr::List(list) => list.downgrade(ctx), - Expr::BinOp(op) => op.downgrade(ctx), - Expr::Paren(paren) => paren.expr().unwrap().downgrade(ctx), - Expr::Root(root) => root.expr().unwrap().downgrade(ctx), - Expr::AttrSet(attrs) => attrs.downgrade(ctx), - Expr::UnaryOp(op) => op.downgrade(ctx), - Expr::Ident(ident) => ident.downgrade(ctx), - Expr::With(with) => with.downgrade(ctx), - Expr::HasAttr(has) => has.downgrade(ctx), + Apply(apply) => apply.downgrade(ctx), + Assert(assert) => assert.downgrade(ctx), + Error(error) => Err(self::Error::DowngradeError(error.to_string())), + IfElse(ifelse) => ifelse.downgrade(ctx), + Select(select) => select.downgrade(ctx), + Str(str) => str.downgrade(ctx), + Path(path) => path.downgrade(ctx), + Literal(lit) => lit.downgrade(ctx), + Lambda(lambda) => lambda.downgrade(ctx), + LegacyLet(let_) => let_.downgrade(ctx), + LetIn(letin) => letin.downgrade(ctx), + List(list) => list.downgrade(ctx), + BinOp(op) => op.downgrade(ctx), + Paren(paren) => paren.expr().unwrap().downgrade(ctx), + Root(root) => root.expr().unwrap().downgrade(ctx), + AttrSet(attrs) => attrs.downgrade(ctx), + UnaryOp(op) => op.downgrade(ctx), + Ident(ident) => ident.downgrade(ctx), + With(with) => with.downgrade(ctx), + HasAttr(has) => has.downgrade(ctx), } } } @@ -935,14 +949,13 @@ impl Select { .collect::>>()?; let res = match &expr { Ir::Attrs(attrs) => attrs.select(&attrpath), - &Ir::Thunk(Thunk { idx }) => ctx.thunks[idx] - .0 - .as_ref() - .try_unwrap_attrs() - .map_err(|_| Error::DowngradeError("can not select from ".into()))? - .select(&attrpath), - Ir::Arg(_) => Ok(None), - _ => return Err(Error::DowngradeError("can not select from ".into())), + &Ir::Thunk(Thunk { idx }) => { + match ctx.thunks[idx].0.as_ref() { + IrRef::Attrs(attrs) => attrs.select(&attrpath), + _ => Ok(None) + } + } + _ => Ok(None), }; let res = match res { Err(err) => { @@ -1061,11 +1074,10 @@ impl Let { ) -> Result { let map = self.bindings.clone(); let env = env.enter_let(&map); - self.bindings - .into_iter().try_for_each(|(_, ir)| { - ir.resolve(self_idx, ctx, &env)?; - Ok(()) - })?; + self.bindings.into_iter().try_for_each(|(_, ir)| { + ir.resolve(self_idx, ctx, &env)?; + Ok(()) + })?; self.expr.resolve(self_idx, ctx, &env)?.ok() } } diff --git a/src/ir/scc.rs b/src/ir/scc.rs index d0eb72b..23ee663 100644 --- a/src/ir/scc.rs +++ b/src/ir/scc.rs @@ -1,3 +1,5 @@ +use std::collections::VecDeque; + use hashbrown::{HashMap, HashSet}; use super::*; @@ -22,7 +24,7 @@ pub struct SccGraph { } impl SccGraph { - fn from(ctx: &DowngradeContext, sccs: Vec>) -> Self { + fn new(ctx: &DowngradeContext, sccs: Vec>) -> Self { let mut graph = SccGraph::default(); let mut thunk_to_scc = HashMap::new(); @@ -92,11 +94,11 @@ impl SccGraph { } } - let mut queue: std::collections::VecDeque = in_degrees + let mut queue = in_degrees .iter() - .filter(|(_, deg)| **deg == 0) + .filter(|&(_, °)| deg == 0) .map(|(&id, _)| id) - .collect(); + .collect::>(); queue.make_contiguous().sort(); @@ -119,7 +121,7 @@ impl SccGraph { } if sorted_order.len() != reachable.len() { - panic!("Cycle detected in the reachable part of SCC graph!"); + unreachable!("Cycle detected in the reachable part of SCC graph!"); } sorted_order @@ -155,7 +157,7 @@ impl<'ctx> SccAnalyzer<'ctx> { self.strong_connect(idx); } } - SccGraph::from(self.ctx, self.sccs).sorted() + SccGraph::new(self.ctx, self.sccs).sorted() } fn strong_connect(&mut self, v_id: usize) { @@ -165,21 +167,22 @@ impl<'ctx> SccAnalyzer<'ctx> { self.stack.push(v_id); self.on_stack.insert(v_id); - if let Some(deps) = self.ctx.thunk_deps.get(v_id) { - for (&w_id, _) in deps { - if !self.indices.contains_key(&w_id) { - self.strong_connect(w_id); - let v_low_link = *self.low_links.get(&v_id).unwrap(); - let w_low_link = *self.low_links.get(&w_id).unwrap(); - if w_low_link < v_low_link { - self.low_links.insert(v_id, w_low_link); - } - } else if self.on_stack.contains(&w_id) { - let v_low_link = *self.low_links.get(&v_id).unwrap(); - let w_index = *self.indices.get(&w_id).unwrap(); - if w_index < v_low_link { - self.low_links.insert(v_id, w_index); - } + let Some(deps) = self.ctx.thunk_deps.get(v_id) else { + unreachable!() + }; + for (&w_id, _) in deps { + if !self.indices.contains_key(&w_id) { + self.strong_connect(w_id); + let v_low_link = *self.low_links.get(&v_id).unwrap(); + let w_low_link = *self.low_links.get(&w_id).unwrap(); + if w_low_link < v_low_link { + self.low_links.insert(v_id, w_low_link); + } + } else if self.on_stack.contains(&w_id) { + let v_low_link = *self.low_links.get(&v_id).unwrap(); + let w_index = *self.indices.get(&w_id).unwrap(); + if w_index < v_low_link { + self.low_links.insert(v_id, w_index); } } } diff --git a/src/ty/internal/mod.rs b/src/ty/internal/mod.rs index f4e283c..59f0155 100644 --- a/src/ty/internal/mod.rs +++ b/src/ty/internal/mod.rs @@ -462,7 +462,7 @@ impl Value { AttrSet(attrs) => attrs.select(path), Catchable(_) => return Ok(self), _ => Err(Error::EvalError(format!( - "cannot select from {:?}", + "can not select from {:?}", self.typename() ))), }?; @@ -481,7 +481,7 @@ impl Value { Catchable(_) => return Ok(self), _ => { return Err(Error::EvalError(format!( - "cannot select from {:?}", + "can not select from {:?}", self.typename() ))); } @@ -517,7 +517,7 @@ impl Value { pub fn force(&mut self, engine: &mut Engine, env: &mut Env) -> Result<&mut Self> { if let &mut Value::Thunk(idx) = self { - *self = env.lookup_cache(idx, |_| unreachable!())? + *self = env.lookup_stack(idx, |_| unreachable!())? } Ok(self) }