MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
world.cpp
Go to the documentation of this file.
1#include "mim/world.h"
2
3#include <ranges>
4
5#include "mim/check.h"
6#include "mim/def.h"
7#include "mim/driver.h"
8#include "mim/rewrite.h"
9#include "mim/schedule.h"
10#include "mim/tuple.h"
11
12#include "mim/util/util.h"
13
14namespace mim {
15
16namespace {
17
18bool is_shape(const Def* s) {
19 if (s->isa<Nat>()) return true;
20 if (auto arr = s->isa<Arr>()) return arr->body()->zonk()->isa<Nat>();
21 if (auto sig = s->isa_imm<Sigma>())
22 return std::ranges::all_of(sig->ops(), [](const Def* op) { return op->isa<Nat>(); });
23
24 return false;
25}
26
27} // namespace
28
30 assert(!def->is_external());
31 assert(def->is_closed());
32 def->external_ = true;
33 assert_emplace(sym2mut_, def->sym(), def);
34}
35
37 assert(def->is_external());
38 def->external_ = false;
39 auto num = sym2mut_.erase(def->sym());
40 assert_unused(num == 1);
41}
42
43const Def* World::Annexes::attach(flags_t flags, Sym sym, const Def* def) {
44 driver().TLOG("register: 0x{:x} -> {} ({})", flags, def, sym);
45 auto plugin = Annex::demangle(driver(), flags);
46 if (driver().is_loaded(plugin)) {
47 assert_emplace(flags2entry_, flags, Annexes::Entry{sym, def});
48 assert_emplace(sym2flags_, sym, flags);
49 def->annex_ = true;
50 return def;
51 }
52 return nullptr;
53}
54
55/*
56 * constructor & destructor
57 */
58
59#if (!defined(_MSC_VER) && defined(NDEBUG))
60bool World::Lock::guard_ = false;
61#endif
62
64 : driver_(driver)
65 , zonker_(*this)
66 , state_(state)
67 , move_(driver) {
68 data_.univ = insert<Univ>(*this);
69 data_.lit_univ_0 = lit_univ(0);
70 data_.lit_univ_1 = lit_univ(1);
71 data_.type_0 = type(lit_univ_0());
72 data_.type_1 = type(lit_univ_1());
73 data_.type_bot = insert<Bot>(type());
74 data_.type_top = insert<Top>(type());
75 data_.sigma = unify<Sigma>(type(), Defs{})->as<Sigma>();
76 data_.tuple = unify<Tuple>(sigma(), Defs{})->as<Tuple>();
77 data_.type_nat = insert<mim::Nat>(*this);
78 data_.type_idx = insert<mim::Idx>(pi(type_nat(), type()));
79 data_.top_nat = insert<Top>(type_nat());
80 data_.lit_nat_0 = lit_nat(0);
81 data_.lit_nat_1 = lit_nat(1);
82 data_.lit_idx_1_0 = lit_idx(1, 0);
83 data_.type_bool = type_idx(2);
84 data_.lit_bool[0] = lit_idx(2, 0_u64);
85 data_.lit_bool[1] = lit_idx(2, 1_u64);
86 data_.lit_nat_max = lit_nat(nat_t(-1));
87}
88
91
93 for (auto def : move_.defs)
94 def->~Def();
95}
96
97/*
98 * Driver
99 */
100
101Log& World::log() const { return driver().log(); }
102Flags& World::flags() { return driver().flags(); }
103
104Sym World::sym(const char* s) { return driver().sym(s); }
105Sym World::sym(std::string_view s) { return driver().sym(s); }
106Sym World::sym(const std::string& s) { return driver().sym(s); }
107
108/*
109 * factory methods
110 */
111
112const Type* World::type(const Def* level) {
113 if (!level) return nullptr;
114 level = level->zonk();
115
116 if (!level->type()->isa<Univ>())
117 error(level->loc(), "argument `{}` to `Type` must be of type `Univ` but is of type `{}`", level, level->type());
118
119 return unify<Type>(level)->as<Type>();
120}
121
122const Def* World::uinc(const Def* op, level_t offset) {
123 op = op->zonk();
124
125 if (!op->type()->isa<Univ>())
126 error(op->loc(), "operand '{}' of a universe increment must be of type `Univ` but is of type `{}`", op,
127 op->type());
128
129 if (auto l = Lit::isa(op)) return lit_univ(*l + 1);
130 return unify<UInc>(op, offset);
131}
132
133static void flatten_umax(DefVec& ops, const Def* def) {
134 if (auto umax = def->isa<UMax>())
135 for (auto op : umax->ops())
136 flatten_umax(ops, op);
137 else
138 ops.emplace_back(def);
139}
140
141template<int sort>
142const Def* World::umax(Defs ops_) {
143 DefVec ops;
144 for (auto op : ops_) {
145 op = op->zonk();
146
147 if constexpr (sort == UMax::Term) op = op->unfold_type();
148 if constexpr (sort >= UMax::Type) op = op->unfold_type();
149 if constexpr (sort >= UMax::Kind) {
150 if (auto type = op->isa<Type>())
151 op = type->level();
152 else
153 error(op->loc(), "operand '{}' must be a Type of some level", op); // TODO better error message
154 }
155
156 flatten_umax(ops, op);
157 }
158
159 level_t lvl = 0;
160 DefVec res;
161 for (auto op : ops) {
162 if (!op->type()->isa<Univ>())
163 error(op->loc(), "operand '{}' of a universe max must be of type 'Univ' but is of type '{}'", op,
164 op->type());
165
166 if (auto l = Lit::isa(op))
167 lvl = std::max(lvl, *l);
168 else
169 res.emplace_back(op);
170 }
171
172 const Def* l = lit_univ(lvl);
173 if (res.empty()) return sort == UMax::Univ ? l : type(l);
174 if (lvl > 0) res.emplace_back(l);
175
176 std::ranges::sort(res, [](auto op1, auto op2) { return op1->gid() < op2->gid(); });
177 res.erase(std::unique(res.begin(), res.end()), res.end());
178 const Def* umax = unify<UMax>(*this, res);
179 return sort == UMax::Univ ? umax : type(umax);
180}
181
182// TODO more thorough & consistent checks for singleton types
183
184const Def* World::var(Def* mut) {
185 if (auto var = mut->var_) return var;
186
187 if (auto var_type = mut->var_type()) { // could be nullptr, if frozen
188 if (auto s = Idx::isa(var_type)) {
189 if (auto l = Lit::isa(s); l && l == 1) return lit_idx_1_0();
190 } else if (auto s = var_type->isa<Sigma>(); s && s->num_ops() == 0)
191 return tuple(s, {});
192 }
193
194 return mut->var_ = unify<Var>(mut);
195}
196
197template<bool Normalize>
198const Def* World::implicit_app(const Def* callee, const Def* arg) {
199 while (auto pi = Pi::isa_implicit(callee->type()))
200 callee = app(callee, mut_hole(pi->dom()));
201 return app<Normalize>(callee, arg);
202}
203
204template<bool Normalize>
205const Def* World::app(const Def* callee, const Def* arg) {
206 callee = callee->zonk();
207 arg = arg->zonk();
208
209 auto pi = callee->type()->isa<Pi>();
210 if (!pi)
211 throw Error()
212 .error(callee->loc(), "called expression not of function type")
213 .error(callee->loc(), "'{}' <--- callee type", callee->type());
214
215 auto new_arg = Checker::assignable(pi->dom(), arg);
216 if (!new_arg)
217 throw Error()
218 .error(arg->loc(), "cannot apply argument to callee")
219 .note(callee->loc(), "callee: '{}'", callee)
220 .note(arg->loc(), "argument: '{}'", arg)
221 .note(callee->loc(), "vvv domain type vvv\n'{}'\n'{}'", pi->dom(), arg->type())
222 .note(arg->loc(), "^^^ argument type ^^^");
223
224 // re-zonk after assignable check above - we might have inferred new stuff
225 arg = new_arg->zonk();
226 callee = callee->zonk();
227 pi = callee->type()->isa<Pi>();
228
229 // always β-reduce non-recursive, non-parametric lambdas
230 if (auto imm = callee->isa_imm<Lam>()) return imm->body();
231
232 if (auto lam = callee->isa_mut<Lam>(); lam && lam->is_set()) {
233 auto var = lam->has_var();
234
235 // Applying a Lam to its own Var is the identity substitution, so it resolves to the body.
236 // This unfolds a self-application / fixed-point reference.
237 if (var && arg == var) return lam->body();
238
239 // β-reduce or partially evaluate a set, mutable Lam.
240 if (lam->filter() != lit_ff()) {
241 if (!var) {
242 if (lam->filter() == lit_tt()) return lam->body();
243 } else if (auto i = move_.substs.find({var, arg}); i != move_.substs.end()) {
244 // Reuse the cached reduct if its filter held.
245 auto [filter, body] = i->second->defs<2>();
246 if (filter == lit_tt()) return body;
247 } else {
248 // Evaluate the filter; if it holds, reduce the body and cache the reduct.
249 auto rw = VarRewriter(var, arg);
250 auto filter = rw.rewrite(lam->filter());
251 if (filter == lit_tt()) {
252 DLOG("partial evaluate: {} ({})", lam, arg);
253 auto body = rw.rewrite(lam->body());
254 auto size = sizeof(Reduct) + 2 * sizeof(const Def*);
255 auto buf = move_.arena.substs.allocate(size, alignof(const Def*));
256 auto reduct = new (buf) Reduct(2);
257 reduct->defs_[0] = filter;
258 reduct->defs_[1] = body;
259 assert_emplace(move_.substs, std::pair{var, arg}, reduct);
260 return body;
261 }
262 }
263 }
264 }
265
266 auto type = pi->reduce(arg)->zonk();
267 callee = callee->zonk();
268 auto [axm, curry, trip] = Axm::get(callee);
269 if (axm) {
270 curry = curry == 0 ? trip : curry;
271 curry = curry == Axm::Trip_End ? curry : curry - 1;
272
273 if (auto normalizer = axm->normalizer(); Normalize && normalizer && curry == 0)
274 if (auto norm = normalizer(type, callee, arg)) return norm;
275 }
276
277 return raw_app(axm, curry, trip, type, callee, arg);
278}
279
280const Def* World::raw_app(const Def* type, const Def* callee, const Def* arg) {
281 type = type->zonk();
282 callee = callee->zonk();
283 arg = arg->zonk();
284
285 auto [axm, curry, trip] = Axm::get(callee);
286 if (axm) {
287 curry = curry == 0 ? trip : curry;
288 curry = curry == Axm::Trip_End ? curry : curry - 1;
289 }
290
291 return raw_app(axm, curry, trip, type, callee, arg);
292}
293
294const Def* World::raw_app(const Axm* axm, u8 curry, u8 trip, const Def* type, const Def* callee, const Def* arg) {
295 return unify<App>(axm, curry, trip, type, callee, arg);
296}
297
298const Def* World::sigma(Defs ops) {
299 auto n = ops.size();
300 if (n == 0) return sigma();
301 if (n == 1) return ops[0]->zonk();
302
303 auto zops = Def::zonk(ops);
304 if (auto uni = Checker::is_uniform(zops)) return arr(n, uni);
305 return unify<Sigma>(Sigma::infer(*this, zops), zops);
306}
307
308const Def* World::tuple(Defs ops) {
309 auto n = ops.size();
310 if (n == 0) return tuple();
311 if (n == 1) return ops[0]->zonk();
312
313 auto zops = Def::zonk(ops);
314 auto sigma = Tuple::infer(*this, zops);
315 auto t = tuple(sigma, zops);
316 auto new_t = Checker::assignable(sigma, t);
317 if (!new_t)
318 error(t->loc(), "cannot assign tuple '{}' of type '{}' to incompatible tuple type '{}'", t, t->type(), sigma);
319
320 return new_t;
321}
322
323const Def* World::tuple(const Def* type, Defs ops_) {
324 // TODO type-check type vs inferred type
325 type = type->zonk();
326 auto ops = Def::zonk(ops_);
327
328 auto n = ops.size();
329 if (!type->isa_mut<Sigma>()) {
330 if (n == 0) return tuple();
331 if (n == 1) return ops[0];
332 if (auto uni = Checker::is_uniform(ops)) return pack(n, uni);
333 }
334
335 if (n != 0) {
336 // eta rule for tuples:
337 // (extract(tup, 0), extract(tup, 1), extract(tup, 2)) -> tup
338 if (auto extract = ops[0]->isa<Extract>()) {
339 auto tup = extract->tuple();
340 bool eta = tup->type() == type;
341 for (size_t i = 0; i != n && eta; ++i) {
342 if (auto extract = ops[i]->isa<Extract>()) {
343 if (auto index = Lit::isa(extract->index())) {
344 if (eta &= u64(i) == *index) {
345 eta &= extract->tuple() == tup;
346 continue;
347 }
348 }
349 }
350 eta = false;
351 }
352
353 if (eta) return tup;
354 }
355 }
356
357 return unify<Tuple>(type, ops);
358}
359
360const Def* World::tuple(Sym sym) {
361 DefVec defs;
362 std::ranges::transform(sym, std::back_inserter(defs), [this](auto c) { return lit_i8(c); });
363 return tuple(defs);
364}
365
366bool isa_indicies(const Def* def) {
367 if (Idx::isa(def)) return true;
368 if (auto sigma = def->isa<Sigma>()) return std::ranges::all_of(sigma->ops(), [](auto op) { return Idx::isa(op); });
369 if (auto arr = def->isa<Arr>()) return Idx::isa(arr->body());
370 return false;
371}
372
373const Def* World::extract(const Def* d, const Def* index) {
374 if (!d || !index) return nullptr; // can happen if frozen
375 d = d->zonk();
376 index = index->zonk();
377
378 if (!isa_indicies(index->type()))
379 error(index->loc(), "index '{}' is not of Idx type but of type '{}'", index, index->type());
380
381 if (auto tuple = index->isa<Tuple>()) {
382 for (auto op : tuple->ops())
383 d = extract(d, op);
384 return d;
385 } else if (auto pack = index->isa<Pack>()) {
386 if (auto a = Lit::isa(index->arity())) {
387 for (nat_t i = 0, e = *a; i != e; ++i) {
388 auto idx = pack->has_var() ? pack->reduce(lit_idx(*a, i)) : pack->body();
389 d = extract(d, idx);
390 }
391 return d;
392 }
393 }
394
395 auto size = Idx::isa(index->type());
396 auto type = d->unfold_type();
397
398 if (size) {
399 if (auto l = Lit::isa(size); l && *l == 1) {
400 if (auto l = Lit::isa(index); !l || *l != 0) WLOG("unknown Idx of size 1: {}", index);
401 if (auto sigma = type->isa_mut<Sigma>(); sigma && sigma->num_ops() == 1) {
402 // mut sigmas can be 1-tuples; TODO mutables Arr?
403 } else {
404 return d;
405 }
406 }
407 }
408
409 if (size && !Checker::alpha<Checker::Check>(type->arity(), size))
410 error(index->loc(), "index '{}' does not fit within arity '{}'", index, type->arity());
411 // TODO if we have indices we need to check as well that this is compatible with `d`
412
413 if (auto pack = d->isa<Pack>()) {
414 if (pack->has_var())
415 return pack->reduce(index);
416 else
417 return pack->body();
418 }
419
420 // extract(insert(x, index, val), index) -> val
421 if (auto insert = d->isa<Insert>()) {
422 if (index == insert->index()) return insert->value();
423 }
424
425 if (auto i = Lit::isa(index)) {
426 if (auto hole = d->isa_mut<Hole>()) d = hole->tuplefy(Idx::as_lit(index->type()));
427 if (auto tuple = d->isa<Tuple>()) return tuple->op(*i);
428
429 // extract(insert(x, j, val), i) -> extract(x, i) where i != j (guaranteed by rule above)
430 if (auto insert = d->isa<Insert>()) {
431 if (insert->index()->isa<Lit>()) return extract(insert->tuple(), index);
432 }
433
434 if (auto sigma = type->isa<Sigma>()) {
435 if (auto var = sigma->has_var()) {
436 if (is_frozen()) return nullptr; // if frozen, we don't risk rewriting
437 auto t = VarRewriter(var, d).rewrite(sigma->op(*i));
438 return unify<Extract>(t, d, index);
439 }
440
441 return unify<Extract>(sigma->op(*i), d, index);
442 }
443 }
444
445 const Def* elem_t;
446 if (auto arr = type->isa<Arr>())
447 elem_t = arr->reduce(index);
448 else
449 elem_t = join(type->as<Sigma>()->ops());
450
451 if (index->isa<Top>()) {
452 if (auto hole = Hole::isa_unset(d)) {
453 auto elem_hole = mut_hole(elem_t);
454 hole->set(pack(size, elem_hole));
455 return elem_hole;
456 }
457 }
458
459 assert(d);
460 return unify<Extract>(elem_t, d, index);
461}
462
463const Def* World::insert(const Def* d, const Def* index, const Def* val) {
464 d = d->zonk();
465 index = index->zonk();
466 val = val->zonk();
467
468 auto type = d->unfold_type();
469 auto size = Idx::isa(index->type());
470 auto lidx = Lit::isa(index);
471
472 if (!size) error(d->loc(), "index '{}' must be of type 'Idx' but is of type '{}'", index, index->type());
473
474 if (!Checker::alpha<Checker::Check>(type->arity(), size))
475 error(index->loc(), "index '{}' does not fit within arity '{}'", index, type->arity());
476
477 if (lidx) {
478 auto elem_type = type->proj(*lidx);
479 auto new_val = Checker::assignable(elem_type, val);
480 if (!new_val) {
481 throw Error()
482 .error(val->loc(), "value to be inserted not assignable to element")
483 .note(val->loc(), "vvv value type vvv \n'{}'\n'{}'", val->type(), elem_type)
484 .note(val->loc(), "^^^ element type ^^^", elem_type);
485 }
486 val = new_val;
487 }
488
489 if (auto l = Lit::isa(size); l && *l == 1)
490 return tuple(d, {val}); // d could be mut - that's why the tuple ctor is needed
491
492 // insert((a, b, c, d), 2, x) -> (a, b, x, d)
493 if (auto t = d->isa<Tuple>(); t && lidx) return t->refine(*lidx, val);
494
495 // insert(‹4; x›, 2, y) -> (x, x, y, x)
496 if (auto pack = d->isa<Pack>(); pack && lidx) {
497 if (auto a = Lit::isa(pack->arity()); a && *a < flags().scalarize_threshold) {
498 auto new_ops = DefVec(*a, pack->body());
499 new_ops[*lidx] = val;
500 return tuple(type, new_ops);
501 }
502 }
503
504 // insert(insert(x, index, y), index, val) -> insert(x, index, val)
505 if (auto insert = d->isa<Insert>()) {
506 if (insert->index() == index) d = insert->tuple();
507 }
508
509 return unify<Insert>(d, index, val);
510}
511
512const Def* World::seq(bool term, const Def* arity, const Def* body) {
513 arity = arity->zonk();
514 body = body->zonk();
515
516 auto arity_ty = arity->unfold_type();
517 if (!is_shape(arity_ty)) error(arity->loc(), "expected arity but got `{}` of type `{}`", arity, arity_ty);
518
519 if (auto a = Lit::isa(arity)) {
520 if (*a == 0) return unit(term);
521 if (*a == 1) return body;
522 }
523
524 // «(a, b, c); body» -> «a; «(b, c); body»»
525 // e.g. when var, but still has array type
526 if (auto arr_arity = arity->type()->isa<Seq>())
527 if (auto lit_arity_arity = Lit::isa(arr_arity->arity())) {
528 DefVec inner_arity(*lit_arity_arity - 1, [&](u64 i) { return arity->proj(*lit_arity_arity, i + 1); });
529 return seq(term, arity->proj(*lit_arity_arity, 0), seq(term, tuple(inner_arity), body));
530 }
531
532 if (term) {
533 auto type = arr(arity, body->type());
534 return unify<Pack>(type, body);
535 } else {
536 return unify<Arr>(body->unfold_type(), arity, body);
537 }
538}
539
540const Def* World::seq(bool term, Defs shape, const Def* body) {
541 if (shape.empty()) return body;
542 return seq(term, shape.rsubspan(1), seq(term, shape.back(), body));
543}
544
545const Lit* World::lit(const Def* type, u64 val) {
546 if (!type) return nullptr;
547 type = type->zonk();
548
549 if (auto size = Idx::isa(type)) {
550 if (size->isa<Top>()) {
551 // unsafe but fine
552 } else if (auto s = Lit::isa(size)) {
553 if (*s != 0 && val >= *s) error(type->loc(), "index '{}' does not fit within arity '{}'", size, val);
554 } else if (val != 0) { // 0 of any size is allowed
555 error(type->loc(), "cannot create literal '{}' of 'Idx {}' as size is unknown", val, size);
556 }
557 }
558
559 return unify<Lit>(type, val);
560}
561
562/*
563 * set
564 */
565
566template<bool Up>
567const Def* World::ext(const Def* type) {
568 type = type->zonk();
569
570 if (auto arr = type->isa<Arr>()) return pack(arr->arity(), ext<Up>(arr->body()));
571 if (auto sigma = type->isa<Sigma>())
572 return tuple(sigma, DefVec(sigma->num_ops(), [&](size_t i) { return ext<Up>(sigma->op(i)); }));
573 return unify<TExt<Up>>(type);
574}
575
576template<bool Up>
577const Def* World::bound(Defs ops_) {
578 auto ops = DefVec();
579 for (size_t i = 0, e = ops_.size(); i != e; ++i) {
580 auto op = ops_[i]->zonk();
581 if (!op->isa<TExt<!Up>>()) ops.emplace_back(op); // ignore: ext<!Up>
582 }
583
584 auto kind = umax<UMax::Type>(ops);
585
586 // has ext<Up> value?
587 if (std::ranges::any_of(ops, [&](const Def* op) -> bool { return op->isa<TExt<Up>>(); })) return ext<Up>(kind);
588
589 // sort and remove duplicates
590 std::ranges::sort(ops, GIDLt<const Def*>());
591 ops.resize(std::distance(ops.begin(), std::unique(ops.begin(), ops.end())));
592
593 if (ops.size() == 0) return ext<!Up>(kind);
594 if (ops.size() == 1) return ops[0];
595
596 // TODO simplify mixed terms with joins and meets?
597 return unify<TBound<Up>>(kind, ops);
598}
599
600const Def* World::merge(const Def* type, Defs ops_) {
601 type = type->zonk();
602 auto ops = Def::zonk(ops_);
603
604 if (type->isa<Meet>()) {
605 auto types = DefVec(ops.size(), [&](size_t i) { return ops[i]->type(); });
606 return unify<Merge>(meet(types), ops);
607 }
608
609 assert(ops.size() == 1);
610 return ops[0];
611}
612
613const Def* World::merge(Defs ops_) {
614 auto ops = Def::zonk(ops_);
615 return merge(umax<UMax::Term>(ops), ops);
616}
617
618const Def* World::inj(const Def* type, const Def* value) {
619 type = type->zonk();
620 value = value->zonk();
621
622 if (type->isa<Join>()) return unify<Inj>(type, value);
623 return value;
624}
625
626const Def* World::split(const Def* type, const Def* value) {
627 type = type->zonk();
628 value = value->zonk();
629
630 return unify<Split>(type, value);
631}
632
633const Def* World::match(Defs ops_) {
634 auto ops = Def::zonk(ops_);
635 if (ops.size() == 1) return ops.front();
636
637 auto scrutinee = ops.front();
638 auto arms = ops.span().subspan(1);
639 auto join = scrutinee->type()->isa<Join>();
640
641 if (!join) error(scrutinee->loc(), "scrutinee of a test expression must be of union type");
642
643 if (arms.size() != join->num_ops())
644 error(scrutinee->loc(), "test expression has {} arms but union type has {} cases", arms.size(),
645 join->num_ops());
646
647 for (auto arm : arms)
648 if (!arm->type()->isa<Pi>())
649 error(arm->loc(), "arm of test expression does not have a function type but is of type '{}'", arm->type());
650
651 std::ranges::sort(arms, [](const Def* arm1, const Def* arm2) {
652 return arm1->type()->as<Pi>()->dom()->gid() < arm2->type()->as<Pi>()->dom()->gid();
653 });
654
655 const Def* type = nullptr;
656 for (size_t i = 0, e = arms.size(); i != e; ++i) {
657 auto arm = arms[i];
658 auto pi = arm->type()->as<Pi>();
659 if (!Checker::alpha<Checker::Check>(pi->dom(), join->op(i)))
660 error(arm->loc(),
661 "domain type '{}' of arm in a test expression does not match case type '{}' in union type", pi->dom(),
662 join->op(i));
663 type = type ? this->join({type, pi->codom()}) : pi->codom();
664 }
665
666 return unify<Match>(type, ops);
667}
668
669const Def* World::uniq(const Def* inhabitant) {
670 inhabitant = inhabitant->zonk();
671 return unify<Uniq>(inhabitant->type()->unfold_type(), inhabitant);
672}
673
674Sym World::append_suffix(Sym symbol, std::string suffix) {
675 auto name = symbol.str();
676
677 auto pos = name.find(suffix);
678 if (pos != std::string::npos) {
679 auto num = name.substr(pos + suffix.size());
680 if (num.empty()) {
681 name += "_1";
682 } else {
683 num = num.substr(1);
684 num = std::to_string(std::stoi(num) + 1);
685 name = name.substr(0, pos + suffix.size()) + "_" + num;
686 }
687 } else {
688 name += suffix;
689 }
690
691 return sym(std::move(name));
692}
693
694Defs World::reduce(const Var* var, const Def* arg) {
695 auto mut = var->binder();
696 auto offset = mut->reduction_offset();
697 auto size = mut->num_ops() - offset;
698
699 if (auto i = move_.substs.find({var, arg}); i != move_.substs.end()) return i->second->defs();
700
701 auto buf = move_.arena.substs.allocate(sizeof(Reduct) + size * sizeof(const Def*), alignof(const Def*));
702 auto reduct = new (buf) Reduct(size);
703 auto rw = VarRewriter(var, arg);
704 for (size_t i = 0; i != size; ++i)
705 reduct->defs_[i] = rw.rewrite(mut->op(i + offset));
706 assert_emplace(move_.substs, std::pair{var, arg}, reduct);
707 return reduct->defs();
708}
709
710void World::for_each(bool elide_empty, std::function<void(Def*)> f, bool schedule /* = false */) {
712 for (auto mut : externals().muts())
713 queue.push(mut);
714
715 std::vector<Def*> muts;
716 while (!queue.empty()) {
717 auto mut = queue.pop();
718 if (mut && mut->is_closed() && (!elide_empty || mut->is_set())) muts.push_back(mut);
719
720 for (auto op : mut->deps())
721 for (auto mut : op->local_muts())
722 queue.push(mut);
723 }
724
725 // Schedules the mutables in post-order to ensure that they
726 // are emitted in the correct order of dependencies.
727 if (schedule) {
728 const auto mut_nest = Nest(muts);
729 auto schedule = Scheduler::schedule(mut_nest) | std::views::reverse | std::views::filter([&](Def* mut) {
730 return mut->is_closed() && (!elide_empty || mut->is_set());
731 });
732 for (auto* mut : schedule)
733 f(mut);
734 } else {
735 for (auto* mut : muts)
736 f(mut);
737 }
738}
739
740/*
741 * debugging
742 */
743
744#ifdef MIM_ENABLE_CHECKS
745
746void World::breakpoint(u32 gid) { state_.breakpoints.emplace(gid); }
747void World::watchpoint(u32 gid) { state_.watchpoints.emplace(gid); }
748
749const Def* World::gid2def(u32 gid) {
750 auto i = std::ranges::find_if(move_.defs, [=](auto def) { return def->gid() == gid; });
751 if (i == move_.defs.end()) return nullptr;
752 return *i;
753}
754
756 for (auto mut : externals().muts())
757 assert(mut->is_closed() && mut->is_set());
758 for (auto anx : annexes().defs())
759 assert(anx->is_closed());
760 return *this;
761}
762
763#endif
764
765#ifndef DOXYGEN
766template const Def* World::umax<UMax::Term>(Defs);
767template const Def* World::umax<UMax::Type>(Defs);
768template const Def* World::umax<UMax::Kind>(Defs);
769template const Def* World::umax<UMax::Univ>(Defs);
770template const Def* World::ext<true>(const Def*);
771template const Def* World::ext<false>(const Def*);
772template const Def* World::bound<true>(Defs);
773template const Def* World::bound<false>(Defs);
774template const Def* World::app<true>(const Def*, const Def*);
775template const Def* World::app<false>(const Def*, const Def*);
776template const Def* World::implicit_app<true>(const Def*, const Def*);
777template const Def* World::implicit_app<false>(const Def*, const Def*);
778#endif
779
780} // namespace mim
A (possibly paramterized) Array.
Definition tuple.h:121
Definition axm.h:9
static constexpr u8 Trip_End
Definition axm.h:144
static std::tuple< const Axm *, u8, u8 > get(const Def *def)
Yields currying counter of def.
Definition axm.cpp:38
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:114
static bool alpha(const Def *d1, const Def *d2)
Definition check.h:98
static const Def * assignable(const Def *type, const Def *value)
Can value be assigned to sth of type?
Definition check.h:105
Base class for all Defs.
Definition def.h:261
bool is_set() const
Yields true if empty or the last op is set.
Definition def.cpp:308
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
const Def * zonk() const
If Holes have been filled, reconstruct the program without them.
Definition check.cpp:21
constexpr auto ops() const noexcept
Definition def.h:317
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
Definition def.h:527
const Def * unfold_type() const
Yields the type of this Def and builds a new Type (UInc n) if necessary.
Definition def.cpp:496
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.cpp:491
bool is_external() const noexcept
Definition def.h:500
Loc loc() const
Definition def.h:557
Sym sym() const
Definition def.h:558
const Def * var_type()
If this is a binder, compute the type of its Variable.
Definition def.cpp:325
constexpr u32 gid() const noexcept
Global id - unique number for this Def.
Definition def.h:282
const T * isa_imm() const
Definition def.h:521
bool is_closed() const
Has no free_vars()?
Definition def.cpp:428
Some "global" variables needed all over the place.
Definition driver.h:20
Log & log() const
Definition driver.h:37
Flags & flags()
Definition driver.h:35
Error & error(Loc loc, std::format_string< Args... > s, Args &&... args)
Definition dbg.h:63
Error & note(Loc loc, std::format_string< Args... > s, Args &&... args)
Definition dbg.h:65
This node is a hole in the IR that is inferred by its context later on.
Definition check.h:16
static Hole * isa_unset(const Def *def)
Definition check.h:55
static nat_t as_lit(const Def *def)
Definition def.h:940
static const Def * isa(const Def *def)
Checks if def is a Idx s and returns s or nullptr otherwise.
Definition def.cpp:658
Creates a new Tuple / Pack by inserting Insert::value at position Insert::index into Insert::tuple.
Definition tuple.h:237
A function.
Definition lam.h:110
static std::optional< T > isa(const Def *def)
Definition def.h:878
Facility to log what you are doing.
Definition log.h:18
Builds a nesting tree for all mutables/binders.
Definition nest.h:30
A (possibly paramterized) Tuple.
Definition tuple.h:170
A dependent function type.
Definition lam.h:14
static Pi * isa_implicit(const Def *d)
Is d an Pi::is_implicit (mutable) Pi?
Definition lam.h:54
static Schedule schedule(const Nest &)
Definition schedule.cpp:125
Base class for Arr and Pack.
Definition tuple.h:86
A dependent tuple type.
Definition tuple.h:22
static const Def * infer(World &, Defs)
Definition check.cpp:300
Extremum. Either Top (Up) or Bottom.
Definition lattice.h:157
Data constructor for a Sigma.
Definition tuple.h:70
static const Def * infer(World &, Defs)
Definition check.cpp:293
@ Type
Definition def.h:799
@ Univ
Definition def.h:799
@ Term
Definition def.h:799
@ Kind
Definition def.h:799
Extends Rewriter for variable substitution.
Definition rewrite.h:107
const Def * rewrite(const Def *) final
Definition rewrite.cpp:288
A variable introduced by a binder (mutable).
Definition def.h:756
const Def * attach(flags_t, Sym, const Def *)
Definition world.cpp:43
void internalize(Def *)
Definition world.cpp:36
void externalize(Def *)
Definition world.cpp:29
const Lit * lit_idx(nat_t size, u64 val)
Constructs a Lit of type Idx of size size.
Definition world.h:535
const Def * insert(const Def *d, const Def *i, const Def *val)
Definition world.cpp:463
const Def * meet(Defs ops)
Definition world.h:577
const Def * uinc(const Def *op, level_t offset=1)
Definition world.cpp:122
const Lit * lit(const Def *type, u64 val)
Definition world.cpp:545
const Def * seq(bool is_pack, const Def *arity, const Def *body)
Definition world.cpp:512
auto & muts()
Definition world.h:675
const Lit * lit_i8()
Definition world.h:529
World(Driver *, Sym name)
Definition world.cpp:89
void watchpoint(u32 gid)
Trigger breakpoint in your debugger when Def::setting a Def with this gid.
Definition world.cpp:747
const Type * type(const Def *level)
Definition world.cpp:112
const Driver & driver() const
Definition world.h:93
const Lit * lit_tt()
Definition world.h:562
const Def * filter(Lam::Filter filter)
Definition world.h:383
const Def * sigma(Defs ops)
Definition world.cpp:298
const Def * pack(const Def *arity, const Def *body)
Definition world.h:457
const Def * app(const Def *callee, const Def *arg)
Definition world.cpp:205
const Def * match(Defs)
Definition world.cpp:633
const Pi * pi(const Def *dom, const Def *codom, bool implicit=false)
Definition world.h:359
const Def * unit(bool is_pack)
Definition world.h:476
World & verify()
Verifies that all externals() and annexes() are Def::is_closed(), if MIM_ENABLE_CHECKS.
Definition world.cpp:755
const Idx * type_idx()
Definition world.h:595
const Lit * lit_univ_0()
Definition world.h:520
Sym name() const
Definition world.h:97
const Lit * lit_univ_1()
Definition world.h:521
const Nat * type_nat()
Definition world.h:594
void for_each(bool elide_empty, std::function< void(Def *)>, bool schedule=false)
Definition world.cpp:710
Hole * mut_hole(const Def *type)
Definition world.h:326
const Lam * lam(const Pi *pi, Lam::Filter f, const Def *body)
Definition world.h:387
const Def * tuple(Defs ops)
Definition world.cpp:308
const Def * gid2def(u32 gid)
Lookup Def by gid.
Definition world.cpp:749
Flags & flags()
Retrieve compile Flags.
Definition world.cpp:102
const Def * implicit_app(const Def *callee, const Def *arg)
Definition world.cpp:198
Annexes & annexes()
Definition world.h:267
const Def * inj(const Def *type, const Def *value)
Definition world.cpp:618
const Type * type()
Definition world.h:315
const Axm * axm(NormalizeFn n, u8 curry, u8 trip, const Def *type, plugin_t p, tag_t t, sub_t s)
Definition world.h:341
const Def * extract(const Def *d, const Def *i)
Definition world.cpp:373
bool is_frozen() const
Definition world.h:147
const Def * arr(const Def *arity, const Def *body)
Definition world.h:456
Sym sym(std::string_view)
Definition world.cpp:105
const Lit * lit_ff()
Definition world.h:561
const Def * bound(Defs ops)
Definition world.cpp:577
const Def * join(Defs ops)
Definition world.h:576
const Def * ext(const Def *type)
Definition world.cpp:567
Sym append_suffix(Sym name, std::string suffix)
Appends a suffix or an increasing number if the suffix already exists.
Definition world.cpp:674
const Lit * lit_idx_1_0()
Definition world.h:526
const Lit * lit_univ(u64 level)
Definition world.h:519
const Def * var(Def *mut)
Definition world.cpp:184
const Tuple * tuple()
the unit value of type []
Definition world.h:492
const Def * uniq(const Def *inhabitant)
Definition world.cpp:669
const Def * raw_app(const Axm *axm, u8 curry, u8 trip, const Def *type, const Def *callee, const Def *arg)
Definition world.cpp:294
const Externals & externals() const
Definition world.h:264
const Def * umax(Defs)
Definition world.cpp:142
const Def * merge(const Def *type, Defs ops)
Definition world.cpp:600
const Sigma * sigma()
The unit type within Type 0.
Definition world.h:444
const Lit * lit_nat(nat_t a)
Definition world.h:522
const State & state() const
Definition world.h:92
Defs reduce(const Var *var, const Def *arg)
Yields the new body of [mut->var() -> arg]mut.
Definition world.cpp:694
void breakpoint(u32 gid)
Trigger breakpoint in your debugger when creating a Def with this gid.
Definition world.cpp:746
const Def * split(const Def *type, const Def *value)
Definition world.cpp:626
Log & log() const
Definition world.cpp:101
bool empty() const
Definition util.h:141
bool push(T val)
Definition util.h:133
#define WLOG(...)
Definition log.h:89
#define DLOG(...)
Vaporizes to nothingness in Debug build.
Definition log.h:94
Definition ast.h:14
View< const Def * > Defs
Definition def.h:78
u64 nat_t
Definition types.h:37
Vector< const Def * > DefVec
Definition def.h:79
auto assert_emplace(C &container, Args &&... args)
Invokes emplace on container, asserts that insertion actually happened, and returns the iterator.
Definition util.h:117
u64 flags_t
Definition types.h:39
TBound< true > Join
AKA union.
Definition lattice.h:179
u64 level_t
Definition types.h:36
TExt< true > Top
Definition lattice.h:177
uint32_t u32
Definition types.h:27
static void flatten_umax(DefVec &ops, const Def *def)
Definition world.cpp:133
void error(Loc loc, std::format_string< Args... > f, Args &&... args)
Definition dbg.h:114
uint64_t u64
Definition types.h:27
bool isa_indicies(const Def *def)
Definition world.cpp:366
uint8_t u8
Definition types.h:27
TBound< false > Meet
AKA intersection.
Definition lattice.h:178
static Sym demangle(Driver &, plugin_t plugin)
Reverts an Axm::mangled string to a Sym.
Definition plugin.cpp:37
Compiler switches that must be saved and looked up in later phases of compilation.
Definition flags.h:11