MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
check.cpp
Go to the documentation of this file.
1#include "mim/check.h"
2
3#include <fe/assert.h>
4
5#include "mim/rewrite.h"
6#include "mim/rule.h"
7#include "mim/world.h"
8
9namespace mim {
10
11bool Def::needs_zonk() const {
12 if (has_hole()) {
13 for (auto mut : local_muts())
14 if (Hole::isa_set(mut)) return true;
15 }
16
17 return false;
18}
19
20const Def* Def::zonk() const {
21 // A Hole needs special care: even when it is still unset, its *type* may have to be refreshed; see zonk_mut.
22 if (isa_mut<Hole>()) return zonk_mut();
23 return needs_zonk() ? world().zonker().rewrite(this) : this;
24}
25
26const Def* Def::zonk_mut() const {
27 if (auto hole = isa_mut<Hole>()) {
28 auto [last, op] = hole->find();
29 if (op) return op->zonk();
30 // The Hole is still unset, but its *type* may mention Hole%s that have been resolved in the meantime.
31 // Refresh it; otherwise e.g. an `«?n; T»` type won't collapse to `T` after `?n` has been unified with `1`.
32 if (auto t = last->type())
33 if (auto new_t = t->zonk_mut(); new_t != t) last->set_type(new_t);
34 return last;
35 }
36
37 if (!is_set()) return this;
38
39 if (auto mut = isa_mut()) {
40 for (auto def : deps())
41 if (def->needs_zonk()) return world().zonker().rewire_mut(mut);
42
43 if (auto imm = mut->immutabilize()) return imm;
44 return this;
45 }
46
47 return zonk();
48}
49
51 return DefVec(defs, [](const Def* def) { return def->zonk(); });
52}
53
54/*
55 * Hole
56 */
57
58std::pair<Hole*, const Def*> Hole::find() {
59 auto def = Def::op(0);
60 auto last = this;
61
62 while (def) {
63 auto h = def->isa_mut<Hole>();
64 if (!h) break;
65 def = h->op();
66 last = h;
67 }
68
69 auto root = def ? def : last;
70
71 // path compression
72 for (auto h = this; h != last;) {
73 auto next = h->op()->as_mut<Hole>();
74 h->set(root);
75 h = next;
76 }
77
78 return {last, def};
79}
80
81const Def* Hole::tuplefy(nat_t n) {
82 if (is_set()) return this;
83
84 auto& w = world();
85 auto holes = DefVec(n);
86 if (auto [sigma, var] = type()->isa_binder<Sigma>(); sigma && n >= 1) {
87 auto rw = VarRewriter(var, this);
88 holes[0] = w.mut_hole(sigma->op(0));
89 for (size_t i = 1; i != n; ++i) {
90 rw.map(sigma->var(n, i - 1), holes[i - 1]);
91 holes[i] = w.mut_hole(rw.rewrite(sigma->op(i)));
92 }
93 } else {
94 for (size_t i = 0; i != n; ++i)
95 holes[i] = w.mut_hole(type()->proj(n, i));
96 }
97
98 auto tuple = w.tuple(holes);
99 set(tuple);
100 return tuple;
101}
102
103/*
104 * Checker
105 */
106
107#ifdef MIM_ENABLE_CHECKS
108template<Check::Mode mode>
109bool Check::fail() {
110 if (mode == C && world().flags().break_on_alpha) fe::breakpoint();
111 return false;
112}
113
114const Def* Check::fail() {
115 if (world().flags().break_on_alpha) fe::breakpoint();
116 return {};
117}
118#endif
119
121 if (defs.empty()) return nullptr;
122 auto first = defs.front();
123 auto same = [first](const Def* def) { return alpha<T>(first, def); };
124 return std::ranges::all_of(defs.subspan(1), same) ? first : nullptr;
125}
126
127const Def* Check::coerce_(const Def* type, const Def* val) {
128 auto val_t = val->unfold_type();
129 if (!val_t) return fail(); // Level has no type, so it is assignable to nothing
130 auto val_ty = val_t->zonk();
131 if (type == val_ty) return val;
132
133 auto& w = world();
134
135 // Implicit insertion at a coercion site: @p val expects implicit arguments, but @p type is an
136 // *explicit* function type. Fill them with Hole%s, as World::implicit_app does at application sites.
137 // This lets polymorphic functions be passed as arguments, e.g. `affine.id` to a parameter of type
138 // `«r; affine.Index» → «r; affine.Index»`, without writing `affine.id @r`.
139 // Only do this when @p type is a Pi: if it is a Hole, we'd commit before knowing what's expected;
140 // if it's an aggregate, we might consume implicits belonging to the value's element type.
141 if (auto pi = type->isa<Pi>(); pi && !pi->is_implicit() && Pi::isa_implicit(val_ty)) {
142 val = w.implicit_holes(val);
143 val_ty = val->unfold_type()->zonk();
144 if (type == val_ty) return val;
145 }
146
147 if (auto sigma = type->isa<Sigma>()) {
148 if (!alpha_<C>(type->arity(), val_ty->arity())) return fail();
149
150 size_t a = sigma->num_ops();
151 auto new_ops = DefVec(a, [&](size_t i) { return val->proj(a, i); });
152 for (size_t i = 0; i != a; ++i) {
153 // A telescope's component only depends on its predecessors, which must have been checked.
154 auto new_val = coerce_(w.component(sigma, new_ops, a, i), new_ops[i]);
155 if (!new_val) return fail();
156 new_ops[i] = new_val;
157 }
158 return w.tuple(new_ops);
159 }
160
161 // A dynamic Extract's type joins its components' types, which may only agree once each is coerced on its own.
162 if (auto extract = val->isa<Extract>();
163 extract && val_ty->isa<Join>() && !type->isa<Join>() && !Hole::isa_unset(type)) {
164 auto tuple = extract->tuple();
165 if (auto sigma = tuple->unfold_type()->zonk()->isa_imm<Sigma>()) {
166 auto n = sigma->num_ops();
167 auto new_ops = DefVec(n);
168 for (size_t i = 0; i != n; ++i)
169 if (!(new_ops[i] = coerce_(type, tuple->proj(n, i)))) return fail();
170 return w.extract(w.tuple(new_ops), extract->index());
171 }
172 }
173
174 auto num_deferred = deferred_.size();
175 if (alpha_<C>(type, val_ty)) return val;
176 // Ex falso: a value of the empty type is dead code, e.g. an extract with an `Idx 0` index.
177 if (auto bot = val_ty->isa<Bot>(); bot && bot->type()->isa<Type>()) {
178 deferred_.resize(num_deferred);
179 return val;
180 }
181 return fail();
182}
183
184std::pair<Check::Binders::iterator, bool> Check::bind(Def* mut, const Def* d) {
185 if (!mut) return {binders_.end(), true};
186
187 auto res = binders_.emplace(mut, d);
188 if (res.second) {
189 // A new binding may change how bound Var%s compare, so positive memo entries may become invalid.
190 for (auto& memo : memo_)
191 memo.clear();
192 // A Var that has never been created cannot occur in any Def.
193 if (auto var = mut->has_var()) bound_ = world().vars().insert(bound_, var);
194 }
195
196 return res;
197}
198
199/// The statically known rank of @p def: `0` if it isn't a Seq at all, `nullopt` if its own rank is dynamic.
200static std::optional<nat_t> known_rank(const Def* def) {
201 if (auto seq = def->zonk_mut()->isa<Seq>()) return seq->shape().rank();
202 return 0;
203}
204
205/// The rank of `«s; T»` with `s: «r; Nat»` is unknown as long as `r` is, and so is Def::arity.
206/// @returns the unset Hole standing for `r`, or `nullptr`.
207static Hole* isa_flex_rank(const Def* def) {
208 if (auto seq = def->isa_imm<Seq>()) {
209 if (auto shape = Hole::isa_unset(seq->shape()->zonk_mut())) {
210 if (auto arr = shape->type()->zonk_mut()->isa<Arr>()) return Hole::isa_unset(arr->arity()->zonk_mut());
211 }
212 }
213 return nullptr;
214}
215
216// These may be α-equivalent to a Def with a different Node or Def::flags(); see alpha_impl_.
217static bool is_flex(const Def* def) {
218 auto n = def->node();
219 return n == Node::Hole || Prod::isa_node(n) || Seq::isa_node(n);
220}
221
222template<Check::Mode mode>
223std::optional<bool> Check::try_alpha_(const Def* d1, const Def* d2) {
224 // Pointer equality decides the matter, unless a free Var of an immutable is bound on one side only: λx.x vs λz.x.
225 if (d1 == d2 && (d1->isa_mut() || bound_.empty() || !d1->has_free_vars_in(bound_))) return true;
226
227 // Only a ground Def is stable under Def::zonk_mut, which rewires mutables in place and unifies Hole%s.
228 if ((d1->node() != d2->node() || d1->flags() != d2->flags()) && d1->is_ground() && d2->is_ground() && !is_flex(d1)
229 && !is_flex(d2))
230 return fail<mode>();
231
232 return {};
233}
234
235template<Check::Mode mode>
236bool Check::alpha_(const Def* d1, const Def* d2) {
237 if (auto res = try_alpha_<mode>(d1, d2)) return *res;
238
239 auto& memo = memo_[mode];
240 auto key = memo_key(d1, d2);
241 if (memo.contains(key)) return true;
242 if (!alpha_impl_<mode>(d1, d2)) return false;
243 memo.emplace(key);
244 return true;
245}
246
247template<Check::Mode mode>
248bool Check::alpha_impl_(const Def* d1, const Def* d2) {
249 for (bool todo = true; todo;) {
250 // below we check type and arity which may in turn open up more opportunities for zonking
251 todo = false;
252 d1 = d1->zonk_mut();
253 d2 = d2->zonk_mut();
254
255 if (auto res = try_alpha_<mode>(d1, d2); res.has_value()) return *res;
256
257 auto h1 = d1->isa_mut<Hole>();
258 auto h2 = d2->isa_mut<Hole>();
259
260 if constexpr (mode == C) {
261 if (h1) return check(h1, d2);
262 if (h2) return check(h2, d1);
263 } else if (h1 || h2) // mode == Test and h1 or h2 is an unresolved Hole
264 return fail<T>();
265
266 if (!d1->is_set() || !d2->is_set()) return fail<mode>();
267
268 auto mut1 = d1->isa_mut();
269 auto mut2 = d2->isa_mut();
270
271 if (mut1 && mut2 && mut1 == mut2) return true;
272
273 if (auto [i, ins] = bind(mut1, d2); !ins) return i->second == d2;
274 if (auto [i, ins] = bind(mut2, d1); !ins) return i->second == d1;
275
276 auto t1 = d1->type();
277 auto t2 = d2->type();
278 if (t1 && t2 && !alpha_<mode>(t1, t2)) return fail<mode>();
279
280 // Def::arity of a flex-rank Seq is its first extent, which needs the rank pinned down first.
281 if constexpr (mode == C) {
282 // Only a statically known rank on the *other* side pins it down; two dynamic ranks unify
283 // their shapes structurally further below.
284 if (auto rank = isa_flex_rank(d1); rank && known_rank(d2)) {
285 if (!check_rank(d1->as<Seq>(), rank, d2)) return fail<C>();
286 todo = true;
287 continue;
288 }
289 if (auto rank = isa_flex_rank(d2); rank && known_rank(d1)) {
290 if (!check_rank(d2->as<Seq>(), rank, d1)) return fail<C>();
291 todo = true;
292 continue;
293 }
294 }
295
296 if (!alpha_<mode>(d1->arity(), d2->arity())) return fail<mode>();
297
298 auto new_d1 = d1->zonk_mut();
299 auto new_d2 = d2->zonk_mut();
300 if (new_d1 != d1 || new_d2 != d2) {
301 todo = true;
302 d1 = new_d1;
303 d2 = new_d2;
304 }
305 }
306
307 auto seq1 = d1->isa<Seq>();
308 auto seq2 = d2->isa<Seq>();
309
310 if constexpr (mode == C) {
311 if (auto lmax = d1->isa<LMax>()) return check(lmax, d2);
312 if (auto lmax = d2->isa<LMax>()) return check(lmax, d1);
313 if (auto inc = d1->isa<LSucc>()) return check(inc, d2);
314 if (auto inc = d2->isa<LSucc>()) return check(inc, d1);
315
316 if (seq1 && !seq1->shape().is_fused() && seq1->arity() == world().lit_nat_1() && !seq2) return check1(seq1, d2);
317 if (seq2 && !seq2->shape().is_fused() && seq2->arity() == world().lit_nat_1() && !seq1) return check1(seq2, d1);
318
319 if (seq1 && seq2) {
320 if (auto mut_seq = seq1->isa_mut<Seq>(); mut_seq && seq2->isa_imm()) return check(mut_seq, seq2);
321 if (auto mut_seq = seq2->isa_mut<Seq>(); mut_seq && seq1->isa_imm()) return check(mut_seq, seq1);
322 }
323 }
324
325 if (auto prod = d1->isa<Prod>()) return check<mode>(prod, d2);
326 if (auto prod = d2->isa<Prod>()) return check<mode>(prod, d1);
327 if (seq1 && seq2) return check<mode>(seq1, seq2);
328
329 if (d1->node() != d2->node() || d1->flags() != d2->flags()) return fail<mode>();
330
331 if (auto var1 = d1->isa<Var>()) {
332 auto var2 = d2->as<Var>();
333 if (auto i = binders_.find(var1->binder()); i != binders_.end()) return i->second == var2->binder();
334 if (binders_.contains(var2->binder())) return fail<mode>(); // var2 is bound
335 // both var1 and var2 are free: OK, when they are the same or in Check mode
336 return var1 == var2 || mode == C;
337 }
338
339 for (size_t i = 0, e = d1->num_ops(); i != e; ++i)
340 if (!alpha_<mode>(d1->op(i), d2->op(i))) return fail<mode>();
341 return true;
342}
343
344template<Check::Mode mode>
345bool Check::check(const Prod* prod, const Def* def) {
346 size_t a = prod->num_ops();
347 for (size_t i = 0; i != a; ++i)
348 if (!alpha_<mode>(prod->op(i), def->proj(a, i))) return fail<mode>();
349 return true;
350}
351
352// A recursive type yields `l = max(ops..., l)` for its level whose least solution is `max(ops...)`.
353static const Def* drop_self(Hole* hole, const Def* def) {
354 auto lmax = def->isa<LMax>();
355 if (!lmax) return def;
356
357 DefVec ops;
358 for (auto op : lmax->ops())
359 if (op->zonk_mut() != hole) ops.emplace_back(op);
360
361 return ops.size() == lmax->num_ops() ? def : hole->world().lmax(ops);
362}
363
364// A Hole may only be solved with a Def its type accepts; this is what pins `r` down in `s: «r; Nat»`.
365bool Check::check(Hole* hole, const Def* def) {
366 def = drop_self(hole, def);
367
368 if (def->unfold_type()) { // Level has no type and is assignable to nothing
369 if (auto new_def = coerce_(hole->type(), def))
370 def = new_def;
371 else
372 return fail<C>();
373 }
374 return hole->set(def), true;
375}
376
377// alpha(«?s; body», «e₀, …, e_{r-1}; def»): the fused shape spells out every axis, so the rank follows from
378// what `body` still claims - all of them while it is unknown, all but its own while it is a Seq itself.
379bool Check::check_rank(const Seq* seq, Hole* rank, const Def* def) {
380 auto r = known_rank(def);
381 if (!r) return fail<C>();
382
383 auto n = *r;
384 auto body = seq->body()->zonk_mut();
385 if (!Hole::isa_unset(body))
386 if (auto bseq = body->isa<Seq>())
387 if (auto q = bseq->shape().rank(); q && *q <= *r) n = *r - *q;
388 if (n == 0) return fail<C>();
389
390 rank->set(world().lit_nat(n));
391 Hole::isa_unset(seq->shape()->zonk_mut())->tuplefy(n);
392 return true;
393}
394
395// alpha(«s₁; b₁», «s₂; b₂»): the two shapes may fuse a different number of axes, so compare the leading
396// ones they share and the remainders - `«2, 3; T»` against `«2; X»` binds `X` to `«3; T»`.
397template<Check::Mode mode>
398bool Check::check(const Seq* seq1, const Seq* seq2) {
399 auto r1 = seq1->shape().rank();
400 auto r2 = seq2->shape().rank();
401 if (r1 && r2 && *r1 != *r2) {
402 auto k = std::min(*r1, *r2);
403 auto rest1 = world().drop(seq1, k);
404 auto rest2 = world().drop(seq2, k);
405 if (!rest1 || !rest2) return fail<mode>();
406 for (size_t i = 0; i != k; ++i)
407 if (!alpha_<mode>(seq1->shape()[i], seq2->shape()[i])) return fail<mode>();
408 return alpha_<mode>(rest1, rest2);
409 }
410
411 return alpha_<mode>(*seq1->shape(), *seq2->shape()) && alpha_<mode>(seq1->body(), seq2->body());
412}
413
414// alpha(«1; body», def) -> alpha(body, def);
415bool Check::check1(const Seq* seq, const Def* def) {
416 auto body = seq->reduce(world().lit_idx_1_0()); // try to get rid of var inside of body
417 if (!alpha_<C>(body, def)) return fail<C>();
418 if (auto mut_seq = seq->isa_mut<Seq>()) mut_seq->set(world().lit_nat_1(), body->zonk());
419 return true;
420}
421
422// Try to get rid of mut_seq's var: it may occur in its body and vanish after reduction
423// as holes might have been filled in the meantime.
424bool Check::check(Seq* mut_seq, const Seq* imm_seq) {
425 // `mut_seq` binds only its own axes, so a *fused* `imm_seq` keeps the remaining ones in a sub-Seq:
426 // `«i: n; Ts#i»` against `«n, c, h; T»` matches `Ts#⊤` with `«c, h; T»`, not with `T`.
427 auto r = mut_seq->shape().rank();
428 auto rest = r ? world().drop(imm_seq, *r) : nullptr;
429
430 if (!rest) return fail<C>();
431
432 auto mut_body = mut_seq->reduce(world().top(world().type_indices(mut_seq->shape())));
433 if (!alpha_<C>(mut_body, rest)) return fail<C>();
434
435 mut_seq->set(*mut_seq->shape(), mut_body->zonk());
436 return true;
437}
438
439// `max(xs, c) = l` determines the xs only if `l = 0` or a single x has to reach `l`; World::solve_levels does the rest.
440bool Check::check(const LMax* lmax, const Def* def) {
441 if (auto l = Lit::isa(def)) {
442 auto c = level_t(0);
443 auto xs = DefVec();
444 for (auto op : lmax->ops())
445 if (auto k = Lit::isa(op))
446 c = *k;
447 else
448 xs.emplace_back(op);
449
450 if (c > *l) return fail<C>();
451 if (*l == 0 || (c < *l && xs.size() == 1)) {
452 for (auto x : xs)
453 if (!alpha_<C>(x, def)) return fail<C>();
454 return true;
455 }
456 }
457
458 deferred_.emplace_back(lmax, def);
459 return true;
460}
461
462// `x + k = l` determines `x = l - k`; with `l = y + j` the smaller offset cancels.
463bool Check::check(const LSucc* inc, const Def* def) {
464 auto k = inc->offset();
465 if (auto l = Lit::isa(def)) return *l >= k && alpha_<C>(inc->op(), world().lit_level(*l - k));
466 if (auto other = def->isa<LSucc>()) {
467 auto j = other->offset();
468 return j >= k ? alpha_<C>(inc->op(), world().lsucc(other->op(), j - k))
469 : alpha_<C>(world().lsucc(inc->op(), k - j), other->op());
470 }
471 return fail<C>();
472}
473
474void Check::commit() {
475 for (auto [lmax, level] : deferred_)
476 world().postpone(lmax, level);
477}
478
479#ifndef DOXYGEN
480template bool Check::alpha_<Check::C>(const Def*, const Def*);
481template bool Check::alpha_<Check::T>(const Def*, const Def*);
482#endif
483
484/*
485 * infer
486 */
487
489 return w.sigma(DefVec(ops, [](const Def* op) { return op->unfold_type(); }));
490}
491
492const Def* Sigma::infer(World& w, Defs ops) { return w.type(w.level(ops)); }
493
494const Def* Variant::infer(World& w, Defs ops) { return Sigma::infer(w, ops); }
495
496const Def* Pi::infer(const Def* dom, const Def* codom) {
497 auto& w = dom->world();
498 return w.type(w.level({dom, codom}));
499}
500
501const Def* Reform::infer(const Def* dom) { return dom->unfold_type(); }
502
503/*
504 * Def::check
505 */
506
507const Def* Def::check(size_t i, const Def* def) {
508 auto lam = isa<Lam>();
509 if (!lam) return def; // TODO Pi/Sigma/Arr/Rule accept any op for now
510
511 if (i == 0) {
512 if (auto filter = Check::coerce(world().type_bool(), def)) return filter;
513 def->blame("filter of a lambda is of type `{}` but must be of type `Bool`", type_of(def)).bail();
514 }
515 assert(i == 1);
516 if (auto body = Check::coerce(lam->codom(), def)) return body;
517 auto codom = lam->codom();
518 auto& err = def->blame("function body is not assignable to its declared codomain")
519 .n("expected `{}`, got `{}`", codom, type_of(def));
520 if (codom->isa_mut() || codom->isa<Var>()) err.n(codom->loc(), "codomain `{}` declared here", codom);
521 err.bail();
522}
523
524const Def* Def::check() {
525 auto& w = world();
526 bool pending = type() == w.type_pending();
527
528 switch (mut_node()) {
529 case MutNode::Pi: {
530 auto pi = as<Pi>();
531 auto t = Pi::infer(pi->dom(), pi->codom());
532 if (!pending && !Check::alpha(t, type()))
533 type()->blame("declared sort of function type does not match inferred sort `{}`", t).bail();
534 return t;
535 }
536 case MutNode::Arr: {
537 auto t = as<Arr>()->body()->unfold_type();
538 if (!pending && !Check::alpha(t, type()))
539 type()->blame("declared sort of array does not match inferred sort `{}`", t).bail();
540 return t;
541 }
542 case MutNode::Sigma: {
543 auto t = Sigma::infer(w, ops());
544 if (pending || Check::alpha(t, type())) return t; // TODO HACK
545 w.log().w("expected type {} for {} but keeping the declared {} due to clos-conv bugs", t, this, type());
546 return type();
547 }
548 case MutNode::Variant: {
549 auto t = Variant::infer(w, ops());
550 if (!Check::alpha(t, type()))
551 type()->blame("declared sort of variant does not match inferred sort `{}`", t).bail();
552 return t;
553 }
554 case MutNode::Rule: {
555 auto rule = as<Rule>();
556 auto t1 = rule->lhs()->unfold_type();
557 auto t2 = rule->rhs()->unfold_type();
558 if (!Check::alpha(t1, t2))
559 type()
560 ->blame("type mismatch between rule sides: lhs has type `{}` but rhs has type `{}`", t1, t2)
561 .bail();
562 if (!Check::coerce(w.type_bool(), rule->guard()))
563 rule->guard()
564 ->blame("condition of a rewrite rule is of type `{}` but must be of type `Bool`",
565 type_of(rule->guard()))
566 .bail();
567 return type();
568 }
569 // A Lam's ops are checked one by one in Def::check(size_t, const Def*).
570 case MutNode::Lam:
571 case MutNode::Pack:
572 case MutNode::Hole: return type();
573 }
574 std::unreachable();
575}
576
577} // namespace mim
A (possibly paramterized) Array.
Definition tuple.h:305
static const Def * is_uniform(Defs defs)
Yields defs.front(), if all defs are Check::alpha-equivalent (Mode::Test) and nullptr otherwise.
Definition check.cpp:120
World & world()
Definition check.h:81
static const Def * coerce(const Def *type, const Def *value)
Can value be assigned to sth of type?
Definition check.h:105
@ C
In Mode::Check, type inference is happening and Holes will be resolved, if possible.
Definition check.h:86
static bool alpha(const Def *d1, const Def *d2)
Definition check.h:93
Base class for all Defs.
Definition def.h:289
bool is_set() const
Definition def.h:396
const Def * zonk_mut() const
If mutable, zonk()s all ops and tries to immutabilize it; otherwise just zonk.
Definition check.cpp:26
const Def * proj(nat_t a, nat_t i) const
Similar to World::extract while assuming an arity of a, but also works on Sigmas and Arrays.
Definition def.cpp:647
constexpr Node node() const noexcept
Definition def.h:315
Defs deps() const noexcept
Definition def.cpp:486
const Def * zonk() const
If Holes have been filled, reconstruct the program without them.
Definition check.cpp:20
World & world() const noexcept
Definition def.h:1105
constexpr auto ops() const noexcept
Definition def.h:374
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
Definition def.h:588
const Def * op(size_t i) const noexcept
Definition def.h:377
std::pair< D *, const Var * > isa_binder() const
Is this a mutable that introduces a Var?
Definition def.h:503
const Def * var(nat_t a, nat_t i) noexcept
Definition def.h:492
const Def * unfold_type() const
Yields the type of this Def and builds a new Type (LSucc n) if necessary.
Definition def.cpp:469
Muts local_muts() const
Mutables reachable by following immutable deps(); mut->local_muts() is by definition the set { mut }...
Definition def.h:520
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.h:1119
fe::Error & blame(fe::cite_string< Args... > s, Args &&... args) const
Reports an error that blames this; chain Error::n for Notes and Error::bail to throw.
Definition def.h:333
constexpr MutNode mut_node() const noexcept
node() of a Def whose Node may be mutable, whether this one is or not; see MutNode.
Definition def.h:317
const T * isa_imm() const
Definition def.h:582
bool needs_zonk() const
Yields true, if Def::local_muts() contain a Hole that is set.
Definition check.cpp:11
bool has_hole() const noexcept
Is this a Hole or does it reach one through Def::deps() up to (and excluding) the next mutable?
Definition def.h:425
const Def * check()
After all Def::ops have been Def::set, this method will be invoked to check the type of this mutable.
Definition check.cpp:524
This node is a hole in the IR that is inferred by its context later on.
Definition check.h:16
std::pair< Hole *, const Def * > find()
Transitively walks up Holes until the last one while path-compressing everything.
Definition check.cpp:58
Hole * set(const Def *op)
Definition check.h:35
const Def * tuplefy(nat_t)
If unset, explode to Tuple.
Definition check.cpp:81
static Hole * isa_unset(const Def *def)
Definition check.h:53
static const Def * isa_set(const Def *def)
Definition check.h:48
static std::optional< T > isa(const Def *def)
Definition def.h:976
A dependent function type.
Definition lam.h:14
static const Def * infer(const Def *dom, const Def *codom)
Definition check.cpp:496
bool is_implicit() const
Definition lam.h:26
const Def * dom() const
Definition lam.h:38
const Def * codom() const
Definition lam.h:39
static const Pi * isa_implicit(const Def *d)
Is d an Pi::is_implicit Pi?
Definition lam.h:28
Base class for Sigma and Tuple.
Definition tuple.h:13
static constexpr bool isa_node(mim::Node n) noexcept
Prod groups Sigma and Tuple; see fe::NodeSetable.
Definition tuple.h:19
Def(World *, Node, const Def *type, Defs ops, flags_t flags)
Constructor for an immutable Def.
Definition def.cpp:29
static const Def * infer(const Def *dom)
Definition check.cpp:501
const Def * dom() const
Definition rule.h:18
Base class for Arr and Pack.
Definition tuple.h:267
static constexpr bool isa_node(mim::Node n) noexcept
Seq groups Arr and Pack; see fe::NodeSetable.
Definition tuple.h:273
friend class World
Definition tuple.h:79
static const Def * infer(World &, Defs)
Definition check.cpp:492
friend class World
Definition tuple.h:102
static const Def * infer(World &, Defs)
Definition check.cpp:488
VarRewriter(World &world)
Definition rewrite.h:146
A variable introduced by a binder (mutable).
Definition def.h:857
static const Def * infer(World &, Defs)
Definition check.cpp:494
friend class World
Definition union.h:118
Zonker & zonker()
Definition world.h:111
void postpone(const LMax *lmax, const Def *level)
Postpones lmax = level as it does not determine the level Holes of lmax yet.
Definition world.h:328
const Def * lmax(Defs levels)
Definition world.cpp:260
const Def * drop(const Seq *s, nat_t k)
s without its leading k axes - its body once k covers all of them; nullptr if that isn't a type.
Definition world.cpp:637
auto & vars()
Definition world.h:714
const Def * rewire_mut(Def *)
Definition rewrite.cpp:329
const Def * rewrite(const Def *) final
Definition rewrite.cpp:320
@ bot
Alias for Mode::fast.
Definition math.h:38
Definition ast.h:16
u64 nat_t
Definition types.h:37
static Hole * isa_flex_rank(const Def *def)
The rank of «s; T» with s: «r; Nat» is unknown as long as r is, and so is Def::arity.
Definition check.cpp:207
static const Def * drop_self(Hole *hole, const Def *def)
Definition check.cpp:353
fe::View< const Def * > Defs
Definition def.h:96
u64 level_t
Definition types.h:36
@ Variant
Definition def.h:137
fe::Vector< const Def * > DefVec
Definition def.h:98
static std::optional< nat_t > known_rank(const Def *def)
The statically known rank of def: 0 if it isn't a Seq at all, nullopt if its own rank is dynamic.
Definition check.cpp:200
TExt< false > Bot
Definition union.h:39
auto type_of(const Def *def)
Def::unfold_type of def for a diagnostic - Level is the one Def that has no type at all.
Definition def.h:1144
static bool is_flex(const Def *def)
Definition check.cpp:217
@ Var
Definition def.h:125
@ Hole
Definition def.h:125