logicaffeine_kernel/dag/sem/
types.rs1use super::value::{CtxId, Head, Sp, Val, V};
6use super::{reject, Sem};
7use crate::dag::error::KResult;
8use crate::dag::level::{LevelId, LevelsId};
9use crate::dag::name::NameId;
10use crate::dag::relevance::{Signature, MAX_TRACKED};
11
12impl Sem<'_> {
13 pub fn type_of(&mut self, v: V) -> KResult<V> {
15 if let Some(t) = self.st.arena.type_memo(v) {
16 return Ok(t);
17 }
18 self.enter()?;
19 let r = self.type_of_uncached(v);
20 self.leave();
21 let r = r?;
22 self.st.arena.set_type_memo(v, r);
23 Ok(r)
24 }
25
26 fn type_of_uncached(&mut self, v: V) -> KResult<V> {
27 match self.st.arena.get(v) {
28 Val::Sort(l) => {
29 let sl = self.k.s.levels.succ(l);
30 Ok(self.st.arena.sort(sl))
31 }
32 Val::Nat(_) => self.const0(self.k.wk.nat),
33 Val::Str(_) => self.const0(self.k.wk.string),
34 Val::Neu { head, spine, .. } => {
35 let mut ty = match self.st.arena.head(head) {
36 Head::Local { ty, .. } => ty,
37 Head::Const { name, levels } => self.const_type(name, levels)?,
38 Head::Proj { s, idx, x } => {
39 let xt = self.type_of(x)?;
40 self.proj_type(s, idx, x, xt, false)?
41 }
42 };
43 for a in self.st.arena.args(spine) {
44 let w = self.whnf(ty)?;
45 ty = self.instantiate(w, a)?;
46 }
47 Ok(ty)
48 }
49 Val::Lam { env, body, .. } => {
50 let d = self.lam_domain(v)?;
51 Ok(self.st.arena.pi_lam(d, env, CtxId::EMPTY, body))
52 }
53 Val::Pi { dom, .. } | Val::PiLam { dom, .. } => {
54 let ld = self.sort_level(dom)?;
55 let lb = self.under(dom, |s, x| {
56 let cod = s.instantiate(v, x)?;
57 s.sort_level(cod)
58 })?;
59 let l = self.k.s.levels.imax(ld, lb);
60 Ok(self.st.arena.sort(l))
61 }
62 }
63 }
64
65 pub(crate) fn sort_level(&mut self, ty: V) -> KResult<LevelId> {
67 let tt = self.type_of(ty)?;
68 match self.sort_of(tt)? {
69 Some(l) => Ok(l),
70 None => Err(reject(format!("type expected, found {}", self.show(ty)))),
71 }
72 }
73
74 pub fn is_prop(&mut self, ty: V) -> KResult<bool> {
76 let l = self.sort_level(ty)?;
77 Ok(self.k.s.levels.is_always_zero(l))
78 }
79
80 pub(crate) fn is_proof(&mut self, v: V) -> KResult<bool> {
84 if let Some(p) = self.st.arena.proof_memo(v) {
85 return Ok(p);
86 }
87 let p = match self.static_proof(v)? {
88 Some(p) => p,
89 None => {
90 self.st.counters.proof_probes += 1;
91 let t = self.type_of(v)?;
92 self.is_prop(t)?
93 }
94 };
95 self.st.arena.set_proof_memo(v, p);
96 Ok(p)
97 }
98
99 fn static_proof(&mut self, v: V) -> KResult<Option<bool>> {
100 Ok(match self.st.arena.get(v) {
101 Val::Sort(_) | Val::Pi { .. } | Val::PiLam { .. } | Val::Nat(_) | Val::Str(_) => {
102 Some(false)
103 }
104 Val::Lam { .. } => None,
105 Val::Neu { head, spine, .. } => match self.st.arena.head(head) {
106 Head::Const { name, levels } => {
107 let k = self.st.arena.spine_len(spine) as usize;
108 self.signature(name, levels)?.and_then(|s| s.is_proof(k))
109 }
110 Head::Local { ty, .. } if spine == Sp::NIL => self.static_proposition(ty)?,
111 _ => None,
112 },
113 })
114 }
115
116 fn static_proposition(&mut self, ty: V) -> KResult<Option<bool>> {
118 Ok(match self.st.arena.get(ty) {
119 Val::Sort(_) => Some(false),
120 Val::Neu { head, spine, .. } => match self.st.arena.head(head) {
121 Head::Const { name, levels } => {
122 let k = self.st.arena.spine_len(spine) as usize;
123 self.signature(name, levels)?
124 .and_then(|s| s.is_proposition(k))
125 }
126 _ => None,
127 },
128 _ => None,
129 })
130 }
131
132 pub fn signature(&mut self, c: NameId, ls: LevelsId) -> KResult<Option<Signature>> {
137 if let Some(s) = self.k.known_signature(c, ls) {
138 return Ok(Some(s));
139 }
140 if !self.k.env.is_settled(c) {
141 return Ok(None);
142 }
143 match self.k.env.get(c) {
144 Some(k) if k.lparams.len() == self.k.s.levels.get_list(ls).len() => {}
145 _ => return Ok(None),
146 }
147 if !self.k.relevance.computing.insert((c, ls)) {
148 return Ok(None);
149 }
150 let r = self
151 .const_type(c, ls)
152 .and_then(|ty| self.telescope_signature(ty));
153 self.k.relevance.computing.remove(&(c, ls));
154 let s = r?;
155 self.k.note_signature(c, ls, s);
156 Ok(Some(s))
157 }
158
159 pub(crate) fn telescope_signature(&mut self, ty: V) -> KResult<Signature> {
163 let mut proof_args = 0u64;
164 let mut bound = 0usize;
165 let r = (|| -> KResult<Signature> {
166 let mut cur = ty;
167 let result = loop {
168 let w = self.whnf(cur)?;
169 let dom = match self.st.arena.get(w) {
170 Val::Pi { dom, .. } | Val::PiLam { dom, .. } => dom,
171 _ => break w,
172 };
173 if bound == MAX_TRACKED {
174 return Ok(Signature::new(proof_args, 0, 0, None));
175 }
176 let l = self.sort_level(dom)?;
177 if self.k.s.levels.is_always_zero(l) {
178 proof_args |= 1 << bound;
179 }
180 let x = self.bind(dom);
181 bound += 1;
182 cur = self.instantiate(w, x)?;
183 };
184 let n = bound;
185 if n >= MAX_TRACKED {
186 return Ok(Signature::new(proof_args, 0, 0, None));
187 }
188 let proposition = match self.st.arena.get(result) {
189 Val::Sort(l) => Some(self.k.s.levels.is_always_zero(l)),
190 _ => None,
191 };
192 let known = u64::MAX >> (MAX_TRACKED - 1 - n);
193 let level = self.sort_level(result)?;
194 let proofs = if self.k.s.levels.is_always_zero(level) {
195 known
196 } else {
197 0
198 };
199 Ok(Signature::new(
200 proof_args,
201 proofs,
202 known,
203 Some((n as u32, proposition)),
204 ))
205 })();
206 for _ in 0..bound {
207 self.unbind();
208 }
209 r
210 }
211
212 pub(crate) fn proj_type(
216 &mut self,
217 sname: NameId,
218 idx: u32,
219 x: V,
220 xt: V,
221 check: bool,
222 ) -> KResult<V> {
223 let fail = |s: &mut Sem| {
224 reject(format!(
225 "invalid projection .{} of '{}'",
226 idx + 1,
227 s.k.s.names.display(sname)
228 ))
229 };
230 let ty = self.whnf(xt)?;
231 let Some((iname, ils, _, tsp)) = self.const_app(ty) else {
232 return Err(fail(self));
233 };
234 if iname != sname {
235 return Err(fail(self));
236 }
237 let Some(ind) = self.k.env.inductive(iname).cloned() else {
238 return Err(fail(self));
239 };
240 let targs = self.st.arena.args(tsp);
241 if ind.ctors.len() != 1 || targs.len() != (ind.num_params + ind.num_indices) as usize {
242 return Err(fail(self));
243 }
244 let mut r = self.const_type(ind.ctors[0], ils)?;
245 for arg in targs.iter().take(ind.num_params as usize) {
246 let w = self.whnf(r)?;
247 if !matches!(self.st.arena.get(w), Val::Pi { .. } | Val::PiLam { .. }) {
248 return Err(fail(self));
249 }
250 r = self.instantiate(w, *arg)?;
251 }
252 let maybe_prop = if check {
253 let sl = self.sort_level(ty)?;
254 !self.k.s.levels.is_never_zero(sl)
255 } else {
256 false
257 };
258 for i in 0..idx {
259 let w = self.whnf(r)?;
260 let (dom, body) = match self.st.arena.get(w) {
261 Val::Pi { dom, body, .. } | Val::PiLam { dom, body, .. } => (dom, body),
262 _ => return Err(fail(self)),
263 };
264 let depends = self.k.s.loose_bvar_mask(body).is_none_or(|m| m & 1 == 1);
265 if maybe_prop && depends && !self.is_prop(dom)? {
266 return Err(fail(self));
267 }
268 let p = self.proj(iname, i, x)?;
269 r = self.instantiate(w, p)?;
270 }
271 let w = self.whnf(r)?;
272 let dom = match self.st.arena.get(w) {
273 Val::Pi { dom, .. } | Val::PiLam { dom, .. } => dom,
274 _ => return Err(fail(self)),
275 };
276 if maybe_prop && !self.is_prop(dom)? {
277 return Err(fail(self));
278 }
279 Ok(dom)
280 }
281}