1pub mod conv;
29pub mod eval;
30pub mod infer;
31pub mod table;
32pub mod types;
33pub mod value;
34pub mod whnf;
35
36use super::error::{KResult, KernelFailure};
37use super::expr::ExprId;
38use super::level::{LevelId, SubstId};
39use super::tc::Kernel;
40use table::{StampedTable, Table};
41use value::{Arena, CtxId, EnvId, V};
42
43const MAX_DEPTH: u32 = 200_000;
46
47const SESSION_VALUES: usize = 1 << 23;
49
50#[derive(Clone)]
52pub struct State {
53 pub arena: Arena,
54 epoch: u64,
55 const_type: Table<(u32, u32)>,
56 const_body: Table<(u32, u32)>,
57 rule_rhs: Table<(u32, u32, u32)>,
58 eval_cache: Table<(u32, u32)>,
59 prune_cache: Table<(u32, u64)>,
60 wide_prune_cache: Table<(u32, u32)>,
62 loose_sets: rustc_hash::FxHashMap<ExprId, std::rc::Rc<[u32]>>,
65 infer_cache: Table<(u32, u32)>,
68 check_cache: StampedTable<(u32, u32)>,
71 safe_checked: Table<(u32, u32)>,
75 scoped_checked: Table<(u32, u32, u32)>,
79 scope: u32,
81 proven: Table<(u32, u32)>,
83 failure: Table<(u32, u32)>,
85 depth: u32,
86 level: u32,
88 eager: bool,
90 pub(crate) probe: Option<u32>,
92 scratch_seen: bool,
96 pub counters: Counters,
97 atoms: Vec<(u32, u32, u32)>,
102}
103
104const ATOM_MEMO: usize = 1 << 16;
105
106#[derive(Default, Clone, Debug)]
108pub struct Counters {
109 pub sessions: u64,
110 pub resets_epoch: u64,
111 pub resets_scratch: u64,
112 pub resets_budget: u64,
113 pub scratch_unsettled: u64,
114 pub scratch_instance: u64,
115 pub scratch_expr: u64,
116 pub proof_probes: u64,
119}
120
121impl Default for State {
122 fn default() -> Self {
123 State {
124 arena: Arena::new(),
125 epoch: 0,
126 const_type: Table::new(),
127 const_body: Table::new(),
128 rule_rhs: Table::new(),
129 eval_cache: Table::new(),
130 prune_cache: Table::new(),
131 wide_prune_cache: Table::new(),
132 loose_sets: Default::default(),
133 infer_cache: Table::new(),
134 check_cache: StampedTable::new(),
135 safe_checked: Table::new(),
136 scoped_checked: Table::new(),
137 scope: 0,
138 proven: Table::new(),
139 failure: Table::new(),
140 depth: 0,
141 level: 0,
142 eager: false,
143 probe: None,
144 scratch_seen: false,
145 counters: Counters::default(),
146 atoms: vec![(u32::MAX, u32::MAX, u32::MAX); ATOM_MEMO],
147 }
148 }
149}
150
151impl State {
152 fn begin_decl(&mut self, epoch: u64) {
153 if self.epoch != epoch || self.scratch_seen || self.arena.len() > SESSION_VALUES {
154 let c = &mut self.counters;
155 c.sessions += 1;
156 c.resets_epoch += (self.epoch != epoch) as u64;
157 c.resets_scratch += self.scratch_seen as u64;
158 c.resets_budget += (self.arena.len() > SESSION_VALUES) as u64;
159 self.end_session(epoch);
160 }
161 self.check_cache.clear();
162 self.depth = 0;
163 self.level = 0;
164 self.eager = false;
165 self.probe = None;
166 }
167
168 #[inline]
169 fn atom_slot(e: ExprId, s: SubstId) -> usize {
170 (e.0 ^ s.0.wrapping_mul(0x9E37_79B9)) as usize & (ATOM_MEMO - 1)
171 }
172
173 #[inline]
174 pub(crate) fn atom_memo(&self, e: ExprId, s: SubstId) -> Option<V> {
175 let (k, ks, v) = self.atoms[Self::atom_slot(e, s)];
176 (k == e.0 && ks == s.0).then_some(V(v))
177 }
178
179 #[inline]
180 pub(crate) fn note_atom(&mut self, e: ExprId, s: SubstId, v: V) {
181 if !e.is_scratch() {
182 self.atoms[Self::atom_slot(e, s)] = (e.0, s.0, v.0);
183 }
184 }
185
186 fn end_session(&mut self, epoch: u64) {
188 self.arena.reset();
189 self.atoms.fill((u32::MAX, u32::MAX, u32::MAX));
190 self.epoch = epoch;
191 self.const_type.clear();
192 self.const_body.clear();
193 self.rule_rhs.clear();
194 self.eval_cache.clear();
195 self.prune_cache.clear();
196 self.wide_prune_cache.clear();
197 self.infer_cache.clear();
198 self.check_cache.clear();
199 self.safe_checked.clear();
200 self.scoped_checked.clear();
201 self.proven.clear();
202 self.failure.clear();
203 self.scratch_seen = false;
204 }
205
206 pub fn memory_report(&self) -> Vec<(&'static str, usize)> {
208 let mut r = self.arena.memory_report();
209 r.push(("value engine: evaluation cache", self.eval_cache.bytes()));
210 r.push((
211 "value engine: pruning cache",
212 self.prune_cache.bytes() + self.wide_prune_cache.bytes(),
213 ));
214 r.push((
215 "value engine: inference caches",
216 self.infer_cache.bytes()
217 + self.check_cache.bytes()
218 + self.safe_checked.bytes()
219 + self.scoped_checked.bytes(),
220 ));
221 r.push((
222 "value engine: conversion caches",
223 self.proven.bytes() + self.failure.bytes(),
224 ));
225 r.push((
226 "value engine: constant caches",
227 self.const_type.bytes() + self.const_body.bytes() + self.rule_rhs.bytes(),
228 ));
229 r
230 }
231
232 pub fn bytes(&self) -> usize {
233 self.memory_report().iter().map(|(_, b)| b).sum()
234 }
235}
236
237pub struct Sem<'a> {
239 pub k: &'a mut Kernel,
240 pub st: &'a mut State,
241}
242
243fn reject(m: impl Into<String>) -> KernelFailure {
244 KernelFailure::reject(m)
245}
246
247impl<'a> Sem<'a> {
248 pub fn new(k: &'a mut Kernel, st: &'a mut State) -> Sem<'a> {
249 Sem { k, st }
250 }
251
252 #[inline]
253 pub(crate) fn enter(&mut self) -> KResult<()> {
254 if self.st.depth >= MAX_DEPTH {
255 return Err(KernelFailure::resource("recursion depth limit reached"));
256 }
257 self.st.depth += 1;
258 Ok(())
259 }
260
261 #[inline]
262 pub(crate) fn leave(&mut self) {
263 self.st.depth -= 1;
264 }
265
266 #[inline]
269 pub(crate) fn bind(&mut self, ty: V) -> V {
270 let level = self.st.level;
271 self.st.level += 1;
272 self.st
273 .arena
274 .head_value(value::Kind::Local, value::Head::Local { level, ty })
275 }
276
277 #[inline]
278 pub(crate) fn unbind(&mut self) {
279 self.st.level -= 1;
280 }
281
282 pub fn under<T>(&mut self, ty: V, f: impl FnOnce(&mut Self, V) -> KResult<T>) -> KResult<T> {
284 let x = self.bind(ty);
285 let r = f(self, x);
286 self.unbind();
287 r
288 }
289
290 pub fn check_type(&mut self, ty: ExprId) -> KResult<LevelId> {
294 let t = self.infer(EnvId::EMPTY, CtxId::EMPTY, ty, true)?;
295 match self.sort_of(t)? {
296 Some(l) => Ok(l),
297 None => Err(reject(format!("type expected, found {}", self.k.show(ty)))),
298 }
299 }
300
301 pub fn check_value(&mut self, value: ExprId, ty: ExprId) -> KResult<()> {
303 let vt = self.infer(EnvId::EMPTY, CtxId::EMPTY, value, true)?;
304 let tv = self.eval(EnvId::EMPTY, ty)?;
305 if !self.is_def_eq(vt, tv)? {
306 return Err(reject("declaration type mismatch").with_detail(format!(
307 "the value has type\n {}\n but is declared with type\n {}",
308 self.show(vt),
309 self.show(tv)
310 )));
311 }
312 Ok(())
313 }
314
315 pub(crate) fn sort_of(&mut self, t: V) -> KResult<Option<LevelId>> {
317 let w = self.whnf(t)?;
318 Ok(match self.st.arena.get(w) {
319 value::Val::Sort(l) => Some(l),
320 _ => None,
321 })
322 }
323
324 pub fn show(&mut self, v: V) -> String {
326 use value::{Head, Val};
327 match self.st.arena.get(v) {
328 Val::Sort(l) => format!("Sort {l:?}"),
329 Val::Nat(n) => self.k.s.nat(n).to_decimal(),
330 Val::Str(s) => format!("{:?}", self.k.s.string(s)),
331 Val::Lam { body, .. } => format!("fun _ => {}", self.k.show(body)),
332 Val::Pi { dom, env, body } => match self.k.s.node(body) {
333 crate::dag::expr::Node::BVar(i) if i > 0 => {
335 match self.st.arena.lookup(env, i - 1) {
336 Some(cod) => format!("({}) → {}", self.show(dom), self.show(cod)),
337 None => format!("({}) → {}", self.show(dom), self.k.show(body)),
338 }
339 }
340 _ => format!("({}) → {}", self.show(dom), self.k.show(body)),
341 },
342 Val::PiLam { dom, body, .. } => format!("({}) → {}", self.show(dom), self.k.show(body)),
343 Val::Neu { head, spine, .. } => {
344 let h = match self.st.arena.head(head) {
345 Head::Local { level, .. } => format!("x{level}"),
346 Head::Const { name, .. } => self.k.s.names.display(name),
347 Head::Proj { idx, x, .. } => format!("({}).{}", self.show(x), idx + 1),
348 };
349 let n = self.st.arena.spine_len(spine);
350 let args: Vec<String> = self
351 .st
352 .arena
353 .args(spine)
354 .iter()
355 .take(6)
356 .map(|a| self.show_atom(*a))
357 .collect();
358 if n == 0 {
359 h
360 } else if n > 6 {
361 format!("{h} {} …", args.join(" "))
362 } else {
363 format!("{h} {}", args.join(" "))
364 }
365 }
366 }
367 }
368
369 fn show_atom(&mut self, v: V) -> String {
370 use value::{Head, Val};
371 match self.st.arena.get(v) {
372 Val::Neu { head, spine, .. } if spine == value::Sp::NIL => {
373 match self.st.arena.head(head) {
374 Head::Local { level, .. } => format!("x{level}"),
375 Head::Const { name, .. } => self.k.s.names.display(name),
376 Head::Proj { idx, .. } => format!("_.{}", idx + 1),
377 }
378 }
379 Val::Nat(n) => self.k.s.nat(n).to_decimal(),
380 Val::Sort(_) => "Sort _".into(),
381 _ => "(…)".into(),
382 }
383 }
384}
385
386impl Kernel {
387 pub fn with_sem<T>(&mut self, f: impl FnOnce(&mut Sem) -> KResult<T>) -> KResult<T> {
389 let mut st = self.sem.take().unwrap_or_default();
390 st.begin_decl(self.sem_epoch());
391 let ps = self.lparams.clone();
392 st.scope = self.const_levels_of(&ps).0;
393 let r = {
394 let mut sem = Sem::new(self, &mut st);
395 f(&mut sem)
396 };
397 self.sem = Some(st);
398 r
399 }
400
401 pub fn sem_epoch(&self) -> u64 {
408 ((self.validated_primitives.len() as u64) << 1) | self.env.quot_init as u64
409 }
410}