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