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