1use super::value::{CtxId, EnvId, Val, DEAD, V};
11use super::{reject, Sem};
12use crate::dag::env::Safety;
13use crate::dag::error::{KResult, KernelFailure};
14use crate::dag::expr::{ExprId, Node};
15use crate::dag::level::{LevelId, LevelsId};
16use crate::dag::name::NameId;
17
18impl Sem<'_> {
19 pub fn infer(&mut self, env: EnvId, ctx: CtxId, e: ExprId, check: bool) -> KResult<V> {
22 self.note_expr(e);
23 let env = self.env_for(env, e);
24 let key = (env.0, e.0);
25 let lparam_free = !self.k.s.has_lparam(e);
26 let safe = self.k.safety == Safety::Safe;
27 let scoped = (self.st.scope, env.0, e.0);
28 let cached = if !check {
29 self.st.infer_cache.get(&key)
30 } else {
31 let lasting = if lparam_free {
32 self.st.safe_checked.get(&key)
33 } else if safe {
34 self.st.scoped_checked.get(&scoped)
35 } else {
36 None
37 };
38 lasting.or_else(|| self.st.check_cache.get(&key))
39 };
40 if let Some(t) = cached {
41 return Ok(V(t));
42 }
43 self.enter()?;
44 let r = self.infer_uncached(env, ctx, e, check);
45 self.leave();
46 let t = r?;
47 if check {
48 if safe && lparam_free {
49 self.st.safe_checked.insert(key, t.0);
50 } else if safe {
51 self.st.scoped_checked.insert(scoped, t.0);
52 } else {
53 self.st.check_cache.insert(key, t.0);
54 }
55 }
56 if !self.st.infer_cache.contains(&key) {
57 self.st.infer_cache.insert(key, t.0);
58 }
59 Ok(t)
60 }
61
62 fn check_level(&self, l: LevelId) -> KResult<()> {
63 if let Some(n) = self.k.s.levels.undef_param(l, &self.k.lparams) {
64 return Err(reject(format!(
65 "invalid reference to undefined universe level parameter '{}'",
66 self.k.s.names.display(n)
67 )));
68 }
69 Ok(())
70 }
71
72 fn infer_constant(&mut self, n: NameId, ls: LevelsId, check: bool) -> KResult<V> {
73 let Some(c) = self.k.env.get(n).cloned() else {
74 return Err(reject(format!(
75 "unknown constant '{}'",
76 self.k.s.names.display(n)
77 )));
78 };
79 let us = self.k.s.levels.get_list(ls).to_vec();
80 if c.lparams.len() != us.len() {
81 return Err(reject(format!(
82 "incorrect number of universe levels for '{}': {} expected, {} provided",
83 self.k.s.names.display(n),
84 c.lparams.len(),
85 us.len()
86 )));
87 }
88 if check {
89 if c.is_unsafe() && self.k.safety != Safety::Unsafe {
90 return Err(reject(format!(
91 "invalid declaration, it uses unsafe declaration '{}'",
92 self.k.s.names.display(n)
93 )));
94 }
95 if c.is_partial() && self.k.safety == Safety::Safe {
96 return Err(reject(format!(
97 "invalid declaration, safe declaration must not contain partial declaration '{}'",
98 self.k.s.names.display(n)
99 )));
100 }
101 for l in &us {
102 self.check_level(*l)?;
103 }
104 }
105 self.const_type(n, ls)
106 }
107
108 fn ensure_sort(&mut self, t: V, what: &str) -> KResult<LevelId> {
110 match self.sort_of(t)? {
111 Some(l) => Ok(l),
112 None => Err(reject(format!(
113 "type expected, {what} has type {}",
114 self.show(t)
115 ))),
116 }
117 }
118
119 fn is_eager_arg(&self, a: ExprId) -> bool {
120 match self.k.s.const_head(a) {
121 Some((n, _)) => n == self.k.wk.eager_reduce && self.k.s.app_num_args(a) == 2,
122 None => false,
123 }
124 }
125
126 fn infer_uncached(&mut self, env: EnvId, ctx: CtxId, e: ExprId, check: bool) -> KResult<V> {
127 match self.k.s.node(e) {
128 Node::BVar(i) => match self.st.arena.ctx_lookup(ctx, i) {
129 Some(t) => Ok(t),
130 None => {
131 let v = self.st.arena.lookup(env, i).ok_or_else(|| reject("unexpected bound variable"))?;
132 self.type_of(v)
133 }
134 },
135 Node::FVar(_) => Err(reject("the value engine met a free variable")),
136 Node::Sort(l) => {
137 if check {
138 self.check_level(l)?;
139 }
140 let l = self.level_in(env, l);
141 let sl = self.k.s.levels.succ(l);
142 Ok(self.st.arena.sort(sl))
143 }
144 Node::Const(n, ls) => {
145 let ls = self.levels_in(env, ls);
146 self.infer_constant(n, ls, check)
147 }
148 Node::App(..) => self.infer_app(env, ctx, e, check),
149 Node::Lam(dom, body) => {
150 if check {
151 let dt = self.infer(env, ctx, dom, true)?;
152 self.ensure_sort(dt, "a binder type")?;
153 }
154 let d = self.eval(env, dom)?;
155 if check {
156 let ctx2 = self.st.arena.ctx_extend(ctx, d);
157 let bt = self.under(d, |sem, x| {
158 let env2 = sem.st.arena.extend(env, x);
159 sem.infer(env2, ctx2, body, true)
160 })?;
161 if !self.st.arena.is_open(bt) {
165 return Ok(self.constant_pi(d, bt));
166 }
167 }
168 Ok(self.st.arena.pi_lam(d, env, ctx, body))
169 }
170 Node::Pi(dom, body) => {
171 let dt = self.infer(env, ctx, dom, check)?;
172 let l1 = self.ensure_sort(dt, "a binder type")?;
173 let d = self.eval(env, dom)?;
174 let ctx2 = self.st.arena.ctx_extend(ctx, d);
175 let l2 = self.under(d, |sem, x| {
176 let env2 = sem.st.arena.extend(env, x);
177 let bt = sem.infer(env2, ctx2, body, check)?;
178 sem.ensure_sort(bt, "a Π codomain")
179 })?;
180 let l = self.k.s.levels.imax(l1, l2);
181 Ok(self.st.arena.sort(l))
182 }
183 Node::Let(ty, val, body) => {
184 if check {
185 let tt = self.infer(env, ctx, ty, true)?;
186 self.ensure_sort(tt, "a let type")?;
187 }
188 let tv = self.eval(env, ty)?;
189 if check {
190 let vt = self.infer(env, ctx, val, true)?;
191 if !self.is_def_eq(vt, tv)? {
192 return Err(reject("let value type mismatch").with_detail(format!(
193 "in `{}`\n expected type: {}\n but the value has type: {}",
194 self.k.show(e),
195 self.show(tv),
196 self.show(vt)
197 )));
198 }
199 }
200 let v = self.eval(env, val)?;
201 let env2 = self.st.arena.extend(env, v);
202 let ctx2 = self.st.arena.ctx_extend(ctx, tv);
203 self.infer(env2, ctx2, body, check)
204 }
205 Node::NatLit(_) => {
206 if check && !self.k.env.contains(self.k.wk.nat) {
207 return Err(reject("natural number literal used before 'Nat' is declared"));
208 }
209 self.const0(self.k.wk.nat)
210 }
211 Node::StrLit(_) => {
212 if check && !(self.k.env.contains(self.k.wk.char_of_nat) && self.k.env.contains(self.k.wk.string_of_list))
213 {
214 return Err(reject("string literal used before 'String.ofList' and 'Char.ofNat' are declared"));
215 }
216 self.const0(self.k.wk.string)
217 }
218 Node::Proj(s, idx, x) => {
219 let xt = self.infer(env, ctx, x, check)?;
220 let xv = self.eval(env, x)?;
221 self.proj_type(s, idx, xv, xt, check)
222 }
223 Node::Match(..) | Node::Fix(_) | Node::MutualFix(..) | Node::Lit(_) | Node::Seq(..) | Node::Nil => {
224 Err(reject("the value engine checks Lean's theory; LOGOS's is checked by the substitution checker"))
225 }
226 }
227 }
228
229 fn constant_pi(&mut self, dom: V, cod: V) -> V {
232 let (body, _) = self.k.s.with_persistent(|s| s.bvar(1));
233 let env = self.st.arena.extend(EnvId::EMPTY, cod);
234 self.st.arena.pi(dom, env, body)
235 }
236
237 fn infer_app(&mut self, env: EnvId, ctx: CtxId, e: ExprId, check: bool) -> KResult<V> {
238 let (f, args) = self.k.s.app_args(e);
239 let mut fty = self.infer(env, ctx, f, check)?;
240 for &a in args.iter() {
241 let w = self.whnf(fty)?;
242 let dom = match self.st.arena.get(w) {
243 Val::Pi { dom, .. } | Val::PiLam { dom, .. } => dom,
244 _ => {
245 return Err(reject(format!("function expected, found {}", self.show(w))));
246 }
247 };
248 if check {
249 let at = self.infer(env, ctx, a, true)?;
250 let ok = if self.is_eager_arg(a) && !self.st.eager {
251 self.st.eager = true;
252 let r = self.is_def_eq(dom, at);
253 self.st.eager = false;
254 r?
255 } else {
256 self.is_def_eq(dom, at)?
257 };
258 if !ok {
259 return Err(
260 KernelFailure::reject("application type mismatch").with_detail(format!(
261 "in `{}`\n expected type: {}\n but the argument has type: {}",
262 self.k.show(e),
263 self.show(dom),
264 self.show(at)
265 )),
266 );
267 }
268 }
269 let av = if self.codomain_ignores_binder(w) {
270 DEAD
271 } else {
272 self.eval(env, a)?
273 };
274 fty = self.instantiate(w, av)?;
275 }
276 Ok(fty)
277 }
278
279 #[inline]
282 pub(crate) fn codomain_ignores_binder(&self, pi: V) -> bool {
283 match self.st.arena.get(pi) {
284 Val::Pi { body, .. } | Val::PiLam { body, .. } => {
285 let (n, mask) = self.k.s.loose_bvars(body);
286 n == 0 || mask.is_some_and(|m| m & 1 == 0)
287 }
288 _ => false,
289 }
290 }
291}