MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
world.h
Go to the documentation of this file.
1#pragma once
2
3#include <concepts>
4
5#include <functional>
6#include <map>
7#include <memory>
8#include <span>
9#include <string>
10#include <string_view>
11#include <type_traits>
12#include <utility>
13
14#include <fe/arena.h>
15#include <fe/log.h>
16#include <fe/restore.h>
17#include <fe/span.h>
18#include <fe/vla.h>
19
20#include "mim/axm.h"
21#include "mim/flags.h"
22#include "mim/rewrite.h"
23
24#include "mim/util/dbg.h"
25
26namespace mim {
27
28template<class T>
29concept Enum = std::is_enum_v<std::remove_reference_t<T>>;
30
31class Driver;
32struct Flags;
33
34/// The World represents the whole program and manages creation of MimIR nodes (Def%s).
35/// Def%s are hashed into an internal HashSet.
36/// The World's factory methods just calculate a hash and lookup the Def, if it is already present, or create a new one
37/// otherwise. This corresponds to value numbering.
38///
39/// You can create several worlds.
40/// All worlds are completely independent from each other.
41///
42/// Note that types are also just Def%s and will be hashed as well.
43class World {
44public:
45 /// World::get_loc together with its interned DbgKey, so pushing/popping a Loc never re-interns it.
46 struct CurrLoc {
47 Loc loc = {};
48 DbgKey key = {};
49 };
50
51 /// @name State
52 ///@{
53 struct State {
54 State() = default;
56 : pod{.name = name} {}
57
58 /// [Plain Old Data](https://en.cppreference.com/w/cpp/named_req/PODType)
59 struct POD {
63 Sym name;
64 mutable bool frozen = false;
65 mutable bool lenient = false;
66 } pod;
67
68#ifdef MIM_ENABLE_CHECKS
69 ankerl::unordered_dense::set<uint32_t> breakpoints;
70 ankerl::unordered_dense::set<uint32_t> watchpoints;
71#endif
72 friend void swap(State& s1, State& s2) noexcept {
73 using std::swap;
74 assert((!s1.pod.curr_loc.loc || !s2.pod.curr_loc.loc) && "Why is get_loc() still set?");
75 swap(s1.pod, s2.pod);
76#ifdef MIM_ENABLE_CHECKS
77 swap(s1.breakpoints, s2.breakpoints);
78 swap(s1.watchpoints, s2.watchpoints);
79#endif
80 }
81 };
82
83 /// @name Construction & Destruction
84 ///@{
85 World& operator=(World) = delete;
86
87 explicit World(Driver*, Sym name);
88 World(Driver*, const State&);
89 World(World&& other) noexcept
90 : World(&other.driver(), other.state()) {
91 swap(*this, other);
92 }
94
95 /// Inherits the State into the new World.
96 /// World::curr_gid will be offset to not collide with the original World.
97 std::unique_ptr<World> inherit() {
98 auto s = state();
99 s.pod.curr_gid += move_.sea.size();
100 return std::make_unique<World>(&driver(), s);
101 }
102 ///@}
103
104 /// @name Getters/Setters
105 ///@{
106 const State& state() const { return state_; }
107 Driver& driver() { return *driver_; }
108 const Driver& driver() const { return *driver_; }
109 fe::Error& error();
110 const fe::Error& error() const;
111 Zonker& zonker() { return zonker_; }
112
113 Sym name() const { return state_.pod.name; }
114 void set(Sym name) { state_.pod.name = name; }
115 void set(std::string_view name) { state_.pod.name = sym(name); }
116
117 /// Manage global identifier - a unique number for each Def.
118 u32 curr_gid() const { return state_.pod.curr_gid; }
119 u32 next_gid() { return ++state_.pod.curr_gid; }
120
121 /// Manage run - used to track fixed-point iterations to compute Def::free_vars
122 u32 curr_run() const { return data_.curr_run; }
123 u32 next_run() { return ++data_.curr_run; }
124
125 /// Retrieve compile Flags.
126 Flags& flags();
127 ///@}
128
129 using ScopedLoc = fe::Restore<CurrLoc>;
130 /// @name Loc
131 ///@{
132 Loc get_loc() const { return state_.pod.curr_loc.loc; }
133 DbgKey dbg_key() const { return state_.pod.curr_loc.key; } ///< World::get_loc, already interned.
134 [[nodiscard]] ScopedLoc push(Loc);
135 ///@}
136
137 /// @name Sym
138 ///@{
139 Sym sym(std::string_view);
140 Sym sym(const char*);
141 Sym sym(const std::string&);
142 /// Appends a @p suffix or an increasing number if the suffix already exists.
143 Sym append_suffix(Sym name, std::string suffix);
144 ///@}
145
146 /// @name Freeze
147 /// In frozen state the World does not create any nodes.
148 /// Dumping freezes: a dump that allocated gids would perturb the very program you are debugging.
149 /// So whatever a frozen query cannot answer from what is already there comes back as `nullptr`.
150 ///@{
151 bool is_frozen() const { return state_.pod.frozen; }
152
153 /// Freezes the World until the end of the scope and restores the previous frozen state afterwards:
154 /// ```
155 /// {
156 /// auto _ = world.freeze();
157 /// // do stuff
158 /// }
159 /// ```
160 [[nodiscard]] auto freeze() const { return fe::Restore(state_.pod.frozen, true); }
161 ///@}
162
163 /// @name Lenient
164 /// A lenient World builds ill-typed App%s and Tuple%s instead of reporting them.
165 /// An Analysis rewrites under partial substitutions, which may disagree with dependent types until its fixed point.
166 ///@{
167 bool is_lenient() const { return state_.pod.lenient; }
168 [[nodiscard]] auto lenient() const { return fe::Restore(state_.pod.lenient, true); }
169 ///@}
170
171 /// @name Debugging Features
172 ///@{
173#ifdef MIM_ENABLE_CHECKS
174 const auto& breakpoints() { return state_.breakpoints; }
175 const auto& watchpoints() { return state_.watchpoints; }
176
177 const Def* gid2def(u32 gid); ///< Lookup Def by @p gid.
178 void breakpoint(u32 gid); ///< Trigger breakpoint in your debugger when creating a Def with this @p gid.
179 void watchpoint(u32 gid); ///< Trigger breakpoint in your debugger when Def::set%ting a Def with this @p gid.
180
181 World& verify(); ///< Verifies that all externals() and annexes() are Def::is_closed(), if `MIM_ENABLE_CHECKS`.
182#else
183 World& verify() { return *this; }
184#endif
185 ///@}
186
187 class Externals {
188 public:
189 ///@name Get muts
190 ///@{
191 auto muts() const { return sym2mut_ | std::views::values; }
192 /// Returns a copy of @p muts() in a fe::Vector; this allows you to modify the Externals while iterating.
193 /// @note The iteration will see all old externals, of course.
194 fe::Vector<Def*> mutate() const { return {muts().begin(), muts().end()}; }
195 Def* operator[](Sym name) const { return fe::lookup(sym2mut_, name); } ///< Lookup by @p name.
196 size_t size() const { return sym2mut_.size(); }
197 ///@}
198
199 ///@name externalize/internalize
200 ///@{
201 void externalize(Def*);
202 void internalize(Def*);
203 ///@}
204
205 /// @name Iterators
206 ///@{
207 auto begin() const { return sym2mut_.cbegin(); }
208 auto end() const { return sym2mut_.cend(); }
209 ///@}
210
211 friend void swap(Externals& ex1, Externals& ex2) noexcept {
212 using std::swap;
213 swap(ex1.sym2mut_, ex2.sym2mut_);
214 }
215
216 private:
217 std::map<Sym, Def*> sym2mut_;
218 };
219
220 class Annexes {
221 public:
222 struct Entry {
223 Sym sym;
224 const Def* def;
225 };
226
228 : driver_(driver) {}
229
230 /// @name Getters
231 ///@{
232 Driver& driver() { return *driver_; }
233 /// An annex's flags map to its full name and its Def.
234 auto& flags2entry() { return flags2entry_; }
235 const auto& flags2entry() const { return flags2entry_; }
236 auto entries() const { return flags2entry_ | std::views::values; }
237 auto defs() const {
238 return entries() | std::views::transform([](const Entry& e) { return e.def; });
239 }
240 auto& sym2flags() { return sym2flags_; }
241 const auto& sym2flags() const { return sym2flags_; }
242 /// The flags of the annex @p def, if it is one.
243 const flags_t* flags(const Def* d) const { return d->is_annex() ? fe::lookup(def2flags_, d) : nullptr; }
244 /// Like flags() but only for an Axm or a non-Lam mutable - whose identity phases must preserve.
245 const flags_t* opaque(const Def* d) const { return d->isa<Axm>() || !d->isa_mut<Lam>() ? flags(d) : nullptr; }
246 size_t size() const { return flags2entry_.size(); }
247 ///@}
248
249 /// @name attach
250 ///@{
251 const Def* attach(flags_t, Sym, const Def*);
252 const Def* attach(plugin_t p, tag_t t, sub_t s, Sym sym, const Def* def) {
253 return attach(Annex::flags(p, t, s), sym, def);
254 }
255
256 /// Registers a further Sym for an *already* attach()ed annex, sharing its flags_t; @see mim::ast::AliasDecl.
257 void attach_alias(flags_t, Sym);
258 void attach_alias(plugin_t p, tag_t t, sub_t s, Sym sym) { attach_alias(Annex::flags(p, t, s), sym); }
259 ///@}
260
261 /// @name Iterators
262 ///@{
263 auto begin() const { return flags2entry_.cbegin(); }
264 auto end() const { return flags2entry_.cend(); }
265 ///@}
266
267 friend void swap(Annexes& a1, Annexes& a2) noexcept {
268 using std::swap;
269 // clang-format off
270 swap(a1.driver_, a2.driver_);
271 swap(a1.flags2entry_, a2.flags2entry_);
272 swap(a1.sym2flags_, a2.sym2flags_);
273 swap(a1.def2flags_, a2.def2flags_);
274 // clang-format on
275 }
276
277 private:
278 Driver* driver_;
279 std::map<flags_t, Entry> flags2entry_; ///< Authoritative annex table; iterated in flags order.
280 std::map<Sym, flags_t> sym2flags_; ///< Reverse index: an annex's full name to its flags.
281 DefMap<flags_t> def2flags_; ///< Reverse index: an annex's Def to its flags.
282 };
283
284 /// @name Externals & Annexes
285 ///@{
286 const Externals& externals() const { return move_.externals; }
287 Externals& externals() { return move_.externals; }
288
289 Annexes& annexes() { return move_.annexes; }
290 const Annexes& annexes() const { return move_.annexes; }
291
292 /// Lookup annex by Sym.
293 const Def* annex(Sym sym);
294
295 /// Lookup annex by flags.
296 /// An annex this World does not have yet is imported from Driver::library.
298 if (auto e = fe::lookup(annexes().flags2entry(), flags)) return e->def;
299 return annex_miss(flags);
300 }
301
302 /// Lookup annex by Axm::id
303 const Def* annex(Enum auto id) { return annex(static_cast<flags_t>(id)); }
304
305 /// Get Axm from a plugin.
306 /// Can be used to get an Axm without sub-tags.
307 /// E.g. use `w.annex<mem::M>();` to get the `mem.M` Axm.
308 template<annex_without_subs id>
309 const Def* annex() {
310 return annex(Annex::base<id>());
311 }
312
313 /// Imports @p def of Driver::library into this World.
314 const Def* import(const Def* def) { return importer_.import(def); }
315 ///@}
316
317 /// @name Level, Type, Var, Proxy, Hole
318 ///@{
319 const Level* type_level() { return data_.type_level; }
320 const Def* lsucc(const Def* op, level_t offset = 1);
321 const Def* lmax(Defs levels);
322 const Def* level(Defs types); ///< The lmax of the levels of all @p types, each of which must be a `Type level`.
323 const Type* type(const Def* level);
324 /// Placeholder type of a mutable whose sort Def::finalize infers from its ops.
325 const Level* type_pending() { return type_level(); }
326 const Type* type_infer_level() { return type(mut_hole_level()); }
327 /// Postpones `lmax = level` as it does not determine the level Hole%s of @p lmax yet.
328 void postpone(const LMax* lmax, const Def* level) { move_.levels.push_back({lmax, level, get_loc()}); }
329 /// Defaults the level Hole%s of all postponed constraints that are still unknown to `0` and checks them.
330 void solve_levels();
331 template<level_t level = 0>
332 const Type* type() {
333 if constexpr (level == 0)
334 return data_.type_0;
335 else if constexpr (level == 1)
336 return data_.type_1;
337 else
338 return type(lit_level(level));
339 }
340 const Def* var(Def* mut);
341 /// The sole inhabitant of @p type, if it has exactly one, `nullptr` otherwise.
342 const Def* inhabitant(const Def* type) {
343 // Every elimination asks, so the common case is decided inline.
344 switch (type->node()) {
345 case Node::App: {
346 auto app = type->as<App>();
347 return app->callee()->isa<Idx>() && Lit::isa(app->arg()) == 1 ? lit_idx_1_0() : nullptr;
348 }
349 case Node::Single:
350 case Node::Sigma:
351 case Node::Arr:
352 case Node::Variant: return inhabitant_(type);
353 default: return nullptr;
354 }
355 }
356 /// @see Proxy::tracks_vars, Proxy::tracks_muts
357 const Proxy* proxy(const Def* type, Defs ops, u32 tag, bool vars = false, bool muts = false) {
358 return unify<Proxy>(type, Proxy::mk_flags(tag, vars, muts), ops);
359 }
360
361 Hole* mut_hole(const Def* type) { return insert<Hole>(type); }
364 ///@}
365
366 /// @name Axm
367 ///@{
368 const Axm* axm(NormalizeFn n, u8 curry, u8 trip, const Def* type, plugin_t p, tag_t t, sub_t s) {
369 return unify<Axm>(n, curry, trip, type, p, t, s);
370 }
371 const Axm* axm(const Def* type, plugin_t p, tag_t t, sub_t s) { return axm(nullptr, 0, 0, type, p, t, s); }
372
373 /// Builds a fresh Axm with descending Axm::sub.
374 /// This is useful during testing to come up with some entity of a specific type.
375 /// It uses the plugin Axm::Global_Plugin and starts with `0` for Axm::sub and counts up from there.
376 /// The Axm::tag is set to `0` and the Axm::normalizer to `nullptr`.
377 const Axm* axm(NormalizeFn n, u8 curry, u8 trip, const Def* type) {
378 return axm(n, curry, trip, type, Annex::Global_Plugin, 0, state_.pod.curr_sub++);
379 }
380 const Axm* axm(const Def* type) { return axm(nullptr, 0, 0, type); } ///< See above.
381 ///@}
382
383 /// @name Pi
384 ///@{
385 // clang-format off
386 const Pi* pi(const Def* dom, const Def* codom, bool implicit = false) { return unify<Pi>(Pi::infer(dom, codom), dom, codom, implicit); }
387 const Pi* pi(Defs dom, const Def* codom, bool implicit = false) { return pi(sigma(dom), codom, implicit); }
388 const Pi* pi(const Def* dom, Defs codom, bool implicit = false) { return pi(dom, sigma(codom), implicit); }
389 const Pi* pi(Defs dom, Defs codom, bool implicit = false) { return pi(sigma(dom), sigma(codom), implicit); }
390 Pi* mut_pi(const Def* type, bool implicit = false) { return insert<Pi>(type, implicit); }
391 // clang-format on
392 ///@}
393
394 /// @name Cn
395 /// Pi with codom mim::Bot%tom
396 ///@{
397 // clang-format off
398 const Pi* cn( ) { return cn(sigma( ), false); }
399 const Pi* cn(const Def* dom, bool implicit = false) { return pi( dom , type_bot(), implicit); }
400 const Pi* cn(Defs dom, bool implicit = false) { return cn(sigma(dom), implicit); }
401 const Pi* fn(const Def* dom, const Def* codom, bool implicit = false) { return cn({ dom , cn(codom)}, implicit); }
402 const Pi* fn(Defs dom, const Def* codom, bool implicit = false) { return fn(sigma(dom), codom, implicit); }
403 const Pi* fn(const Def* dom, Defs codom, bool implicit = false) { return fn( dom , sigma(codom), implicit); }
404 const Pi* fn(Defs dom, Defs codom, bool implicit = false) { return fn(sigma(dom), sigma(codom), implicit); }
405 // clang-format on
406 ///@}
407
408 /// @name Lam
409 ///@{
411 if (auto b = std::get_if<bool>(&filter)) return lit_bool(*b);
412 return std::get<const Def*>(filter);
413 }
414 const Lam* lam(const Pi* pi, Lam::Filter f, const Def* body) { return unify<Lam>(pi, filter(f), body); }
415 Lam* mut_lam(const Pi* pi) { return insert<Lam>(pi); }
416 // clang-format off
417 const Lam* con(const Def* dom, Lam::Filter f, const Def* body) { return unify<Lam>(cn(dom ), filter(f), body); }
418 const Lam* con(Defs dom, Lam::Filter f, const Def* body) { return unify<Lam>(cn(dom ), filter(f), body); }
419 const Lam* lam(const Def* dom, const Def* codom, Lam::Filter f, const Def* body) { return unify<Lam>(pi(dom, codom), filter(f), body); }
420 const Lam* lam(Defs dom, const Def* codom, Lam::Filter f, const Def* body) { return unify<Lam>(pi(dom, codom), filter(f), body); }
421 const Lam* lam(const Def* dom, Defs codom, Lam::Filter f, const Def* body) { return unify<Lam>(pi(dom, codom), filter(f), body); }
422 const Lam* lam(Defs dom, Defs codom, Lam::Filter f, const Def* body) { return unify<Lam>(pi(dom, codom), filter(f), body); }
423 const Lam* fun(const Def* dom, const Def* codom, Lam::Filter f, const Def* body) { return unify<Lam>(fn(dom, codom), filter(f), body); }
424 const Lam* fun(Defs dom, const Def* codom, Lam::Filter f, const Def* body) { return unify<Lam>(fn(dom, codom), filter(f), body); }
425 const Lam* fun(const Def* dom, Defs codom, Lam::Filter f, const Def* body) { return unify<Lam>(fn(dom, codom), filter(f), body); }
426 const Lam* fun(Defs dom, Defs codom, Lam::Filter f, const Def* body) { return unify<Lam>(fn(dom, codom), filter(f), body); }
427 Lam* mut_con(const Def* dom ) { return insert<Lam>(cn(dom )); }
428 Lam* mut_con(Defs dom ) { return insert<Lam>(cn(dom )); }
429 Lam* mut_lam(const Def* dom, const Def* codom) { return insert<Lam>(pi(dom, codom)); }
430 Lam* mut_lam(Defs dom, const Def* codom) { return insert<Lam>(pi(dom, codom)); }
431 Lam* mut_lam(const Def* dom, Defs codom) { return insert<Lam>(pi(dom, codom)); }
432 Lam* mut_lam(Defs dom, Defs codom) { return insert<Lam>(pi(dom, codom)); }
433 Lam* mut_fun(const Def* dom, const Def* codom) { return insert<Lam>(fn(dom, codom)); }
434 Lam* mut_fun(Defs dom, const Def* codom) { return insert<Lam>(fn(dom, codom)); }
435 Lam* mut_fun(const Def* dom, Defs codom) { return insert<Lam>(fn(dom, codom)); }
436 Lam* mut_fun(Defs dom, Defs codom) { return insert<Lam>(fn(dom, codom)); }
437 // clang-format on
438 ///@}
439
440 /// @name Rewrite Rules
441 ///@{
442 const Reform* reform(const Def* dom) { return unify<Reform>(Reform::infer(dom), dom); }
443 Rule* mut_rule(const Reform* type) { return insert<Rule>(type); }
444 const Rule* rule(const Reform* type, const Def* lhs, const Def* rhs, const Def* guard) {
445 return unify<Rule>(type, lhs, rhs, guard);
446 }
447 ///@}
448
449 /// @name App
450 ///@{
451 template<bool Normalize = true>
452 const Def* app(const Def* callee, const Def* arg);
453 template<bool Normalize = true>
454 const Def* app(const Def* callee, Defs args) {
455 return app<Normalize>(callee, tuple(args));
456 }
457 const Def* raw_app(const Axm* axm, u8 curry, u8 trip, const Def* type, const Def* callee, const Def* arg);
458 const Def* raw_app(const Def* type, const Def* callee, const Def* arg);
459 const Def* raw_app(const Def* type, const Def* callee, Defs args) { return raw_app(type, callee, tuple(args)); }
460 ///@}
461
462 /// @name Sigma
463 ///@{
464 Sigma* mut_sigma(const Def* type, size_t size) { return insert<Sigma>(type, size); }
465 /// A *mutable* Sigma of type @p level.
466 template<level_t level = 0>
467 Sigma* mut_sigma(size_t size) {
468 return mut_sigma(type<level>(), size);
469 }
470 const Def* sigma(Defs ops);
471 const Sigma* sigma() { return data_.sigma; } ///< The unit type within Type 0.
472 ///@}
473
474 /// @name Arr & Pack
475 ///@{
476 // clang-format off
477 template<level_t level = 0>
479 return mut_arr(type<level>());
480 }
481 Arr * mut_arr (const Def* type) { return mut_seq(false, type)->as<Arr >(); }
482 Pack* mut_pack(const Def* type) { return mut_seq(true , type)->as<Pack>(); }
483 const Def* arr (Shape shape, const Def* body) { return seq(false, shape, body); }
484 const Def* pack(Shape shape, const Def* body) { return seq(true , shape, body); }
485 const Def* arr (Defs shape, const Def* body) { return seq(false, shape, body); }
486 const Def* pack(Defs shape, const Def* body) { return seq(true , shape, body); }
487 const Def* arr (fe::View<u64> shape, const Def* body) { return seq(false, shape, body); }
488 const Def* pack(fe::View<u64> shape, const Def* body) { return seq(true , shape, body); }
489 const Def* arr (u64 n, const Def* body) { return seq(false, n, body); }
490 const Def* pack(u64 n, const Def* body) { return seq(true , n, body); }
491 // clang-format on
492 ///@}
493
494 /// @name prod
495 /// Generic constructor for tuple or sigma.
496 ///@{
497 const Def* prod(bool term, Defs ops) { return term ? tuple(ops) : sigma(ops); }
498 const Def* prod(bool term) { return term ? (const Def*)tuple() : (const Def*)sigma(); } ///< `()` or `[]`.
499 ///@}
500
501 /// @name Seq
502 /// These either build a Pack or an Arr depending on the first argument.
503 /// Oftentimes, the logic for Pack%s and Arr%ays can be quite similar; these methods help factoring such code.
504 ///@{
505 Seq* mut_seq(bool is_pack, const Def* type) { return is_pack ? (Seq*)insert<Pack>(type) : insert<Arr>(type); }
506 const Def* seq(bool is_pack, Shape shape, const Def* body);
507 const Def* seq(bool is_pack, Defs shape, const Def* body);
508 const Def* seq(bool is_pack, u64 n, const Def* body) { return seq(is_pack, lit_nat(n), body); }
509 const Def* seq(bool is_pack, fe::View<u64> shape, const Def* body) {
510 return seq(is_pack, DefVec(shape, [this](u64 n) { return lit_nat(n); }), body);
511 }
512
513 /// @p s without its leading @p k axes - its body once @p k covers all of them; `nullptr` if that isn't a type.
514 const Def* drop(const Seq* s, nat_t k);
515 /// `«i: a; «j: b; T»»` -> `«v: (a, b); T»` - the inverse of World::peel, for a nest that World::seq
516 /// cannot fuse on construction because its body still binds an index. Yields a Def::zonk_mut @p seq if the
517 /// nest is ragged, i.e. if the inner extents depend on the outer index.
518 const Def* fuse(Seq* seq);
519 /// @p seq with the axes covered by @p index peeled off - the element itself once @p index covers all of them.
520 const Def* peel(const Seq* seq, const Def* index);
521 /// The type of an index into @p shape: `Idx n`, a Sigma of those, or `«i: r; Idx (s#i)»` for a dynamic rank.
522 const Def* type_indices(Shape shape);
523 ///@}
524
525 /// @name Tuple
526 ///@{
527 const Def* tuple(Defs ops);
528 /// Ascribes @p type to this tuple - needed for dependently typed and mutable Sigma%s.
529 const Def* tuple(const Def* type, Defs ops);
530 const Tuple* tuple() { return data_.tuple; } ///< the unit value of type `[]`
531 const Def* tuple(Sym sym); ///< Converts @p sym to a tuple of type '«n; I8»'.
532 ///@}
533
534 /// @name Extract
535 ///@{
536 const Def* extract(const Def* d, const Def* i);
537 const Def* extract(const Def* d, u64 a, u64 i) { return extract(d, lit_idx(a, i)); }
538 const Def* extract(const Def* d, u64 i) { return extract(d, Lit::as(d->arity()), i); }
539 /// Builds `(f, t)#cond`.
540 /// @note Expects @p cond as first, @p t as second, and @p f as third argument.
541 const Def* select(const Def* cond, const Def* t, const Def* f) { return extract(tuple({f, t}), cond); }
542 ///@}
543
544 /// @name Insert
545 ///@{
546 const Def* insert(const Def* d, const Def* i, const Def* val);
547 const Def* insert(const Def* d, u64 a, u64 i, const Def* val) { return insert(d, lit_idx(a, i), val); }
548 const Def* insert(const Def* d, u64 i, const Def* val) { return insert(d, Lit::as(d->arity()), i, val); }
549 ///@}
550
551 /// @name Lit
552 ///@{
553 const Lit* lit(const Def* type, u64 val);
555 return level == 0 ? lit_level_0() : level == 1 ? lit_level_1() : lit(type_level(), level);
556 }
557 const Lit* lit_level_0() { return data_.lit_level_0; }
558 const Lit* lit_level_1() { return data_.lit_level_1; }
559 /// Def::arity of a Sigma is `lit_nat(num_ops())` and Def::num_projs reads it straight back out, so a plain
560 /// World::lit would hash-cons a Lit just to launder an integer. Worth ~4% of an `-Og` Debug compile.
561 static constexpr nat_t Num_Lit_Nats = 64;
562
563 const Lit* lit_nat(nat_t a) { return a < Num_Lit_Nats ? data_.lit_nats[a] : lit(type_nat(), a); }
564 const Lit* lit_nat_0() { return data_.lit_nats[0]; }
565 const Lit* lit_nat_1() { return data_.lit_nats[1]; }
566 const Lit* lit_nat_max() { return data_.lit_nat_max; }
567 const Lit* lit_idx_1_0() { return data_.lit_idx_1_0; }
568 // clang-format off
569 const Lit* lit_i1() { return lit_nat(Idx::bitwidth2size( 1)); }
570 const Lit* lit_i8() { return lit_nat(Idx::bitwidth2size( 8)); }
571 const Lit* lit_i16() { return lit_nat(Idx::bitwidth2size(16)); }
572 const Lit* lit_i32() { return lit_nat(Idx::bitwidth2size(32)); }
573 const Lit* lit_i64() { return lit_nat(Idx::bitwidth2size(64)); }
574 /// Constructs a Lit of type Idx of size @p size.
575 /// @note `size = 0` means `2^64`.
576 const Lit* lit_idx(nat_t size, u64 val) { return lit(type_idx(size), val); }
577
578 const Lit* lit_idx(std::integral auto val) { return lit_idx(Idx::bitwidth2size(sizeof(val) * 8), val); }
579
580 /// Constructs a Lit @p of type Idx of size 2^width.
581 /// `val = 64` will be automatically converted to size `0` - the encoding for 2^64.
582 const Lit* lit_int(nat_t width, u64 val) { return lit_idx(Idx::bitwidth2size(width), val); }
583 const Lit* lit_i1 (bool val) { return lit_int( 1, u64(val)); }
584 const Lit* lit_i8 (u8 val) { return lit_int( 8, u64(val)); }
585 const Lit* lit_i16(u16 val) { return lit_int(16, u64(val)); }
586 const Lit* lit_i32(u32 val) { return lit_int(32, u64(val)); }
587 const Lit* lit_i64(u64 val) { return lit_int(64, u64(val)); }
588 // clang-format on
589
590 /// Constructs a Lit of type Idx of size @p mod.
591 /// The value @p val will be adjusted modulo @p mod.
592 /// @note `mod == 0` is the special case for 2^64 and no modulo will be performed on @p val.
593 const Lit* lit_idx_mod(nat_t mod, u64 val) { return lit_idx(mod, mod == 0 ? val : (val % mod)); }
594
595 const Lit* lit_bool(bool val) { return data_.lit_bool[size_t(val)]; }
596 const Lit* lit_ff() { return data_.lit_bool[0]; }
597 const Lit* lit_tt() { return data_.lit_bool[1]; }
598 ///@}
599
600 /// @name Lattice
601 ///@{
602 template<bool Up>
603 const Def* ext(const Def* type);
604 const Def* bot(const Def* type) { return ext<false>(type); }
605 const Def* top(const Def* type) { return ext<true>(type); }
606 const Def* type_bot() { return data_.type_bot; }
607 const Def* type_top() { return data_.type_top; }
608 ///@}
609
610 /// @name Join & Variant
611 ///@{
612 const Def* join(Defs ops);
613 Variant* mut_variant(const Def* type, size_t size) { return insert<Variant>(type, size); }
614 const Def* variant(Defs ops);
615 const Def* inj(const Def* type, const Def* value);
616 const Def* inj(const Def* type, nat_t index, const Def* value); ///< Injects @p value as case @p index of a Variant.
617 const Def* match(Defs);
618 ///@}
619
620 /// @name Types
621 ///@{
622 const Nat* type_nat() { return data_.type_nat; }
623 const Idx* type_idx() { return data_.type_idx; }
624 /// @note `size = 0` means `2^64`.
625 const Def* type_idx(const Def* size) { return app(type_idx(), size); }
626 /// @note `size = 0` means `2^64`.
627 const Def* type_idx(nat_t size) { return type_idx(lit_nat(size)); }
628
629 /// Constructs a type Idx of size 2^width.
630 /// `width = 64` will be automatically converted to size `0` - the encoding for 2^64.
631 const Def* type_int(nat_t width) { return type_idx(lit_nat(Idx::bitwidth2size(width))); }
632 // clang-format off
633 const Def* type_bool() { return data_.type_bool; }
634 const Def* type_i1() { return data_.type_bool; }
635 const Def* type_i8() { return type_int( 8); }
636 const Def* type_i16() { return type_int(16); }
637 const Def* type_i32() { return type_int(32); }
638 const Def* type_i64() { return type_int(64); }
639 // clang-format on
640 ///@}
641
642 /// @name Nominal Newtypes
643 ///@{
644 const Nom* nom(flags_t key, const Def* type); ///< Make @p type Nom%inal under @p key.
645 const Def* name(const Def* nom, const Def* struc); ///< Name a @p struc%tural to make it @p nom%inal.
646 const Def* struc(const Def* nom); ///< Get the structural part of a @p nom%inal.
647 ///@}
648
649 /// @name implicit_app - Cope with implicit Arguments
650 /// Places Hole%s as demanded by Pi::is_implicit() and then apps @p arg.
651 ///@{
652 const Def* implicit_holes(const Def* callee); ///< Only places the Hole%s.
653 template<bool Normalize = true>
654 const Def* implicit_app(const Def* callee, const Def* arg);
655 template<bool Normalize = true>
656 const Def* implicit_app(const Def* callee, Defs args) {
657 return implicit_app<Normalize>(callee, tuple(args));
658 }
659 template<bool Normalize = true>
660 const Def* implicit_app(const Def* callee, nat_t arg) {
661 return implicit_app<Normalize>(callee, lit_nat(arg));
662 }
663 template<bool Normalize = true>
664 const Def* implicit_app(const Def* callee, Enum auto arg)
665 requires std::is_same_v<std::underlying_type_t<decltype(arg)>, nat_t> {
666 return implicit_app<Normalize>(callee, lit_nat(std::to_underlying(arg)));
667 }
668 ///@}
669
670 /// @name call
671 /// Complete curried call of @p callee obeying implicits.
672 ///@{
673 template<bool Normalize = true, class... Args>
674 const Def* call(const Def* callee, auto&& arg, Args&&... args) {
675 return call<Normalize>(implicit_app<Normalize>(callee, std::forward<decltype(arg)>(arg)),
676 std::forward<Args>(args)...);
677 }
678
679 /// Base case.
680 template<bool Normalize = true>
681 const Def* call(const Def* callee, auto&& arg) {
682 return implicit_app<Normalize>(callee, std::forward<decltype(arg)>(arg));
683 }
684
685 /// Annex overload with enum instance as first argument.
686 template<Enum Id, bool Normalize = true, class... Args>
687 const Def* call(Id id, Args&&... args) {
688 return call<Normalize>(annex(id), std::forward<Args>(args)...);
689 }
690
691 /// Annex overload with enum tempalte argument @p Id for annexes w/o subtag.
692 template<class Id, bool Normalize = true, class... Args>
693 requires std::is_enum_v<Id> const Def* call(Args&&... args) {
694 return call<Normalize>(annex<Id>(), std::forward<Args>(args)...);
695 }
696
697 /// Annex overload with `flags_t` as first argument.
698 template<bool Normalize = true, class... Args>
699 const Def* call(flags_t id, Args&&... args) {
700 return call<Normalize>(annex(id), std::forward<Args>(args)...);
701 }
702 ///@}
703
704 /// @name Singletons
705 ///@{
706 const Def* single(const Def*); ///< Singleton type formation.
707 const Def* wrap(const Def*); ///< Singleton term introduction.
708 const Def* unwrap(const Def*); ///< Singleton term elimination. @note There is no explicite Unwrap node.
709 ///@}
710
711 /// @name Vars & Muts
712 /// Manges sets of Vars and Muts.
713 ///@{
714 [[nodiscard]] auto& vars() { return move_.vars; }
715 [[nodiscard]] auto& muts() { return move_.muts; }
716 [[nodiscard]] const auto& vars() const { return move_.vars; }
717 [[nodiscard]] const auto& muts() const { return move_.muts; }
718
719 /// Yields the new body of `[mut->var() -> arg]mut`.
720 /// The new body may have fewer elements as `mut->num_ops()` according to Def::reduction_offset.
721 /// E.g. a Pi has a Pi::reduction_offset of 1, and only Pi::dom will be reduced - *not* Pi::codom.
722 Defs reduce(const Var* var, const Def* arg);
723
724 /// As above but reduces *only* the @p i th op.
725 /// A dependent Sigma is projected while it is still being built - its later ops do not exist yet - so reducing
726 /// all of them is not an option there.
727 const Def* reduce(const Var* var, const Def* arg, size_t i);
728
729 /// The type of component @p i of the @p n-ary @p type, given its leading components @p parts.
730 const Def* component(const Def* type, Defs parts, size_t n, size_t i);
731 ///@}
732
733 /// @name for_each
734 /// Visits all closed mutables in this World.
735 ///@{
736 void for_each(bool elide_empty, std::function<void(Def*)>, bool schedule = false);
737
738 template<class M>
739 void for_each(bool elide_empty, std::invocable<M*> auto f, bool schedule = false) {
740 for_each(
741 elide_empty,
742 [f](Def* m) {
743 if (auto mut = m->template isa<M>()) f(mut);
744 },
745 schedule);
746 }
747 ///@}
748
749 /// @name dump/log
750 ///@{
751 const fe::Log& log() const; ///< Log via `log().e("...", args)` etc.; owned by the Driver.
752 void dump(std::ostream& os); ///< Dump to @p os.
753 void dump(); ///< Dump to `std::cout`.
754 void debug_dump(); ///< Dump in Debug build if World::log::level is fe::Log::Level::Debug.
755 void write(const char* file); ///< Write to a file named @p file.
756 void write(); ///< Same above but file name defaults to World::name.
757 ///@}
758
759 /// @name dot
760 /// GraphViz output.
761 ///@{
762
763 /// Dumps DOT to @p os, configured via @p cfg (see DotConfig).
764 void dot(std::ostream& os, DotConfig cfg = {}) const;
765 /// Same as above but write to @p file or `std::cout` if @p file is `nullptr`.
766 void dot(const char* file = nullptr, DotConfig cfg = {}) const;
767 ///@}
768
769private:
770 const Def* annex_miss(flags_t);
771 const Def* tuple(const Def* type, Defs ops, bool may_be_uniform);
772 void check_tuple(const Tuple*);
773
774 Shape check_index(const Def* index); ///< Validates @p index and folds its size-1 axes away.
775 /// Type-checks a *scalar* @p index of `Idx size`; `true` if the axis has folded out of @p type.
776 bool is_folded_axis(const Def* type, const Def* index, const Def* size);
777 const Def* extract1(const Def* d, const Def* i); ///< World::extract for a *scalar* @p i.
778 const Def* extract_fused(const Def* d, Shape i); ///< World::extract for an @p i that no longer folds.
779 const Def* inhabitant_(const Def* type); ///< World::inhabitant for an aggregate or Single @p type.
780
781 /// @name Put into Sea of Nodes
782 ///@{
783 /// Common tail of World::unify \& World::insert, right after World::allocate.
784 void stamp(auto* def) {
785 if (get_loc()) def->set(dbg_key()); // pre-interned: no Driver lookup inside this window
786#ifdef MIM_ENABLE_CHECKS
787 if (flags().trace_gids) std::println("{}: {} - {}", def->node_name(), def->gid(), def->flags());
788#endif
789 }
790
791 template<class T, class... Args>
792 const T* unify(Args&&... args) {
793 auto num_ops = T::Num_Ops;
794 if constexpr (T::Num_Ops == std::dynamic_extent) {
795 auto&& last = std::get<sizeof...(Args) - 1>(std::forward_as_tuple(std::forward<Args>(args)...));
796 num_ops = last.size();
797 }
798
799 auto state = move_.arena.defs.state();
800 auto def = allocate<T>(num_ops, std::forward<Args>(args)...);
801 assert(!def->isa_mut());
802 stamp(def);
803
804#ifdef MIM_ENABLE_CHECKS
805 if (flags().reeval_breakpoints && breakpoints().contains(def->gid())) fe::breakpoint();
806 for (auto op : def->ops())
807 assert(&op->world() == this && "op of new Def belongs to a different World");
808 assert((!def->type() || &def->type()->world() == this) && "type of new Def belongs to a different World");
809#endif
810
811 if (is_frozen()) {
812 auto i = move_.sea.find(def);
813 deallocate<T>(state, def);
814 if (i != move_.sea.end()) return static_cast<const T*>(*i);
815 return nullptr;
816 }
817
818 if (auto [i, ins] = move_.sea.emplace(def); !ins) {
819 deallocate<T>(state, def);
820 return static_cast<const T*>(*i);
821 }
822 // Most constructions are hash-cons hits, so only a fresh node pays for its local Vars and Muts.
823 if constexpr (!std::is_same_v<T, Var>) def->collect_locals();
824
825#ifdef MIM_ENABLE_CHECKS
826 if (!flags().reeval_breakpoints && breakpoints().contains(def->gid())) fe::breakpoint();
827#endif
828 return def;
829 }
830
831 /// Like World::unify but yields the sole inhabitant of a singleton @p type instead, as World::var does.
832 template<class T, class... Args>
833 const Def* unify_elim(const Def* type, Args&&... args) {
834 if (type) // nullptr in a frozen World
835 if (auto inhabitant = this->inhabitant(type)) return inhabitant;
836 return unify<T>(type, std::forward<Args>(args)...);
837 }
838
839 template<class T>
840 void deallocate(fe::Arena::State state, const T* ptr) {
841 --state_.pod.curr_gid;
842 ptr->~T();
843 move_.arena.defs.deallocate(state);
844 }
845
846 template<class T, class... Args>
847 T* insert(Args&&... args) {
848 if (is_frozen()) return nullptr;
849
850 auto num_ops = T::Num_Ops;
851 if constexpr (T::Num_Ops == std::dynamic_extent)
852 num_ops = std::get<sizeof...(Args) - 1>(std::forward_as_tuple(std::forward<Args>(args)...));
853
854 auto def = allocate<T>(num_ops, std::forward<Args>(args)...);
855 if (def->mut_) def->hash_ = fe::hash_combine(0, def->gid());
856 stamp(def);
857
858#ifdef MIM_ENABLE_CHECKS
859 if (breakpoints().contains(def->gid())) fe::breakpoint();
860#endif
861 fe::assert_emplace(move_.sea, def);
862 if constexpr (!std::is_same_v<T, Var>)
863 if (!def->mut_) def->collect_locals();
864 return def;
865 }
866
867#if !defined(_MSC_VER) && !defined(NDEBUG)
868 struct Lock {
869 Lock() { assert((guard_ = !guard_) && "you are not allowed to recursively invoke allocate"); }
870 ~Lock() { guard_ = !guard_; }
871 static inline bool guard_ = false;
872 };
873#else
874 struct Lock {
875 ~Lock() {}
876 };
877#endif
878
879 template<class T, class... Args>
880 T* allocate(size_t num_ops, Args&&... args) {
881 static_assert(sizeof(Def) == sizeof(T),
882 "you are not allowed to introduce any additional data in subclasses of Def");
883 auto lock = Lock();
884 auto num_bytes = sizeof(Def) + sizeof(uintptr_t) * num_ops;
885 auto ptr = move_.arena.defs.allocate(num_bytes, alignof(T));
886 auto res = new (ptr) T(std::forward<Args>(args)...);
887 res->gid_ = next_gid(); // here, so Def's ctors need not walk the type chain to find this World
888 assert(res->num_ops() == num_ops);
889 return res;
890 }
891 ///@}
892
893 Driver* driver_;
894 Zonker zonker_;
895 State state_;
896 Importer importer_;
897
898 struct SeaHash {
899 using is_avalanching = void;
900
901 size_t operator()(const Def* def) const { return def->hash(); }
902 };
903
904 struct SeaEq {
905 bool operator()(const Def* d1, const Def* d2) const { return d1->equal(d2); }
906 };
907
908 /// The slots of `[var -> arg]mut`, one per reduced Def::op, filled on demand by World::reduce.
909 class Reduct : public fe::VLA<Reduct> {
910 public:
911 using VLA_Types = std::tuple<const Def*>;
912
913 // clang-format off
914 template<size_t N = std::dynamic_extent> auto ops() const noexcept { return vla<0, N>(); }
915 template<size_t N = std::dynamic_extent> auto ops() noexcept { return vla<0, N>(); }
916 // clang-format on
917 };
918
919 /// The cache entry for `[var -> arg]`, created with empty slots if it does not exist yet.
920 /// Registered *before* any slot is computed, so a reduction that re-enters for the same @p var / @p arg finds it.
921 Reduct* reduct(const Var* var, const Def* arg) {
922 auto [i, ins] = move_.substs.try_emplace(std::pair{var, arg}, nullptr);
923 if (ins) {
924 auto n = var->binder()->num_ops() - var->binder()->reduction_offset();
925 i->second = move_.arena.substs.ref<Reduct>(DefVec(n, nullptr)).get();
926 }
927 return i->second;
928 }
929
930 /// The @p i th slot of an *existing* `[var -> arg]` cache entry; `nullptr` if it has not been computed yet.
931 /// Unlike reduct() this never allocates and hence works on a frozen World.
932 const Def* cached_reduct(const Var* var, const Def* arg, size_t i);
933
934 struct LevelEq {
935 const LMax* lmax;
936 const Def* level;
937 Loc loc;
938 };
939
940 struct Move {
941 Move(Driver* driver)
942 : annexes(driver) {}
943
944 struct {
945 fe::Arena defs, substs;
946 } arena;
947
948 Externals externals;
949 Annexes annexes;
950 ankerl::unordered_dense::set<const Def*, SeaHash, SeaEq> sea;
951 fe::Patricia<Def, DefKey> muts;
952 fe::Patricia<const Var, DefKey> vars;
953 ankerl::unordered_dense::map<std::pair<const Var*, const Def*>, Reduct*> substs;
954 fe::Vector<LevelEq> levels;
955
956 friend void swap(Move& m1, Move& m2) noexcept {
957 using std::swap;
958 // clang-format off
959 swap(m1.arena.defs, m2.arena.defs);
960 swap(m1.arena.substs, m2.arena.substs);
961 swap(m1.sea, m2.sea);
962 swap(m1.substs, m2.substs);
963 swap(m1.vars, m2.vars);
964 swap(m1.muts, m2.muts);
965 swap(m1.externals, m2.externals);
966 swap(m1.annexes, m2.annexes);
967 swap(m1.levels, m2.levels);
968 // clang-format on
969 }
970 } move_;
971
972 struct {
973 const Level* type_level;
974 const Type* type_0;
975 const Type* type_1;
976 const Bot* type_bot;
977 const Top* type_top;
978 const Def* type_bool;
979 const Sigma* sigma;
980 const Tuple* tuple;
981 const Nat* type_nat;
982 const Idx* type_idx;
983 const Lit* lit_level_0;
984 const Lit* lit_level_1;
985 const Lit* lit_nat_max;
986 const Lit* lit_idx_1_0;
987 std::array<const Lit*, 2> lit_bool;
988 std::array<const Lit*, Num_Lit_Nats> lit_nats = {}; ///< @see World::lit_nat
989 u32 curr_run = 0;
990 u32 pe_depth = 0;
991 } data_;
992
993 friend void swap(World& w1, World& w2) noexcept {
994 using std::swap;
995 // clang-format off
996 swap(w1.driver_, w2.driver_ );
997 swap(w1.zonker_, w2.zonker_ );
998 swap(w1.state_, w2.state_ );
999 swap(w1.importer_, w2.importer_);
1000 swap(w1.data_, w2.data_ );
1001 swap(w1.move_, w2.move_ );
1002 // clang-format on
1003
1004 swap(w1.data_.type_level->world_, w2.data_.type_level->world_);
1005 assert(&w1.type_level()->world() == &w1);
1006 assert(&w2.type_level()->world() == &w2);
1007 }
1008};
1009
1010} // namespace mim
A (possibly paramterized) Array.
Definition tuple.h:305
Definition axm.h:9
Base class for all Defs.
Definition def.h:289
Some "global" variables needed all over the place.
Definition driver.h:64
This node is a hole in the IR that is inferred by its context later on.
Definition check.h:16
A built-in constant of type Nat -> *.
Definition def.h:1013
static constexpr nat_t bitwidth2size(nat_t n)
Definition def.h:1039
A function.
Definition lam.h:91
std::variant< bool, const Def * > Filter
Definition lam.h:99
static std::optional< T > isa(const Def *def)
Definition def.h:976
static T as(const Def *def)
Definition def.h:982
Nominal newtype formation.
Definition nom.h:11
A (possibly paramterized) Tuple.
Definition tuple.h:332
A dependent function type.
Definition lam.h:14
static const Def * infer(const Def *dom, const Def *codom)
Definition check.cpp:496
Used as intermediate value during optimizatinos such as Analysis.
Definition def.h:1065
Type formation of a rewrite Rule.
Definition rule.h:9
static const Def * infer(const Def *dom)
Definition check.cpp:501
A rewrite rule.
Definition rule.h:40
Base class for Arr and Pack.
Definition tuple.h:267
The extents of a Seq's axes: a plain Nat for a single axis, an aggregate of them for several.
Definition tuple.h:194
A dependent tuple type.
Definition tuple.h:39
Data constructor for a Sigma.
Definition tuple.h:84
A variable introduced by a binder (mutable).
Definition def.h:857
A sum type whose cases are positional: unlike a Join, they are neither sorted nor deduplicated.
Definition union.h:86
Driver & driver()
Definition world.h:232
const flags_t * flags(const Def *d) const
The flags of the annex def, if it is one.
Definition world.h:243
Annexes(Driver *driver)
Definition world.h:227
void attach_alias(flags_t, Sym)
Registers a further Sym for an already attach()ed annex, sharing its flags_t;.
Definition world.cpp:149
const Def * attach(flags_t, Sym, const Def *)
Definition world.cpp:137
const auto & sym2flags() const
Definition world.h:241
auto end() const
Definition world.h:264
size_t size() const
Definition world.h:246
const Def * attach(plugin_t p, tag_t t, sub_t s, Sym sym, const Def *def)
Definition world.h:252
const auto & flags2entry() const
Definition world.h:235
auto defs() const
Definition world.h:237
friend void swap(Annexes &a1, Annexes &a2) noexcept
Definition world.h:267
auto begin() const
Definition world.h:263
void attach_alias(plugin_t p, tag_t t, sub_t s, Sym sym)
Definition world.h:258
const flags_t * opaque(const Def *d) const
Like flags() but only for an Axm or a non-Lam mutable - whose identity phases must preserve.
Definition world.h:245
auto & flags2entry()
An annex's flags map to its full name and its Def.
Definition world.h:234
auto entries() const
Definition world.h:236
auto & sym2flags()
Definition world.h:240
size_t size() const
Definition world.h:196
void internalize(Def *)
Definition world.cpp:130
Def * operator[](Sym name) const
Lookup by name.
Definition world.h:195
friend void swap(Externals &ex1, Externals &ex2) noexcept
Definition world.h:211
auto end() const
Definition world.h:208
fe::Vector< Def * > mutate() const
Returns a copy of muts() in a fe::Vector; this allows you to modify the Externals while iterating.
Definition world.h:194
auto muts() const
Definition world.h:191
auto begin() const
Definition world.h:207
void externalize(Def *)
Definition world.cpp:123
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:43
const Lit * lit_idx(nat_t size, u64 val)
Constructs a Lit of type Idx of size size.
Definition world.h:576
const Def * arr(Defs shape, const Def *body)
Definition world.h:485
const Def * insert(const Def *d, const Def *i, const Def *val)
Definition world.cpp:802
const Def * type_i16()
Definition world.h:636
const Pi * fn(Defs dom, const Def *codom, bool implicit=false)
Definition world.h:402
Variant * mut_variant(const Def *type, size_t size)
Definition world.h:613
std::unique_ptr< World > inherit()
Inherits the State into the new World.
Definition world.h:97
const Lam * con(Defs dom, Lam::Filter f, const Def *body)
Definition world.h:418
const Def * variant(Defs ops)
Definition world.cpp:1023
const Pi * cn()
Definition world.h:398
const Lit * lit(const Def *type, u64 val)
Definition world.cpp:919
const Def * arr(u64 n, const Def *body)
Definition world.h:489
const Def * inhabitant(const Def *type)
The sole inhabitant of type, if it has exactly one, nullptr otherwise.
Definition world.h:342
const Def * call(flags_t id, Args &&... args)
Annex overload with flags_t as first argument.
Definition world.h:699
u32 next_run()
Definition world.h:123
friend void swap(World &w1, World &w2) noexcept
Definition world.h:993
const Def * struc(const Def *nom)
Get the structural part of a nominal.
Definition world.cpp:1150
const Def * implicit_app(const Def *callee, nat_t arg)
Definition world.h:660
const Def * extract(const Def *d, u64 a, u64 i)
Definition world.h:537
auto & muts()
Definition world.h:715
const Def * pack(Shape shape, const Def *body)
Definition world.h:484
const Def * level(Defs types)
The lmax of the levels of all types, each of which must be a Type level.
Definition world.cpp:349
const Lit * lit_i8()
Definition world.h:570
const Pi * cn(const Def *dom, bool implicit=false)
Definition world.h:399
const Def * type_int(nat_t width)
Constructs a type Idx of size 2^width.
Definition world.h:631
World & operator=(World)=delete
World(Driver *, Sym name)
Definition world.cpp:208
const Lit * lit_i16(u16 val)
Definition world.h:585
void watchpoint(u32 gid)
Trigger breakpoint in your debugger when Def::setting a Def with this gid.
Definition world.cpp:1254
const Lit * lit_i1(bool val)
Definition world.h:583
const Def * call(const Def *callee, auto &&arg, Args &&... args)
Definition world.h:674
const Lit * lit_i32()
Definition world.h:572
Driver & driver()
Definition world.h:107
Zonker & zonker()
Definition world.h:111
Lam * mut_fun(const Def *dom, Defs codom)
Definition world.h:435
const Type * type(const Def *level)
Definition world.cpp:235
const Def * component(const Def *type, Defs parts, size_t n, size_t i)
The type of component i of the n-ary type, given its leading components parts.
Definition world.cpp:585
const Def * lsucc(const Def *op, level_t offset=1)
Definition world.cpp:247
const Driver & driver() const
Definition world.h:108
const Lam * lam(const Def *dom, const Def *codom, Lam::Filter f, const Def *body)
Definition world.h:419
Externals & externals()
Definition world.h:287
const Lit * lit_level_1()
Definition world.h:558
Lam * mut_lam(const Def *dom, Defs codom)
Definition world.h:431
const Lit * lit_tt()
Definition world.h:597
const Def * filter(Lam::Filter filter)
Definition world.h:410
const auto & watchpoints()
Definition world.h:175
const Def * sigma(Defs ops)
Definition world.cpp:506
const Def * seq(bool is_pack, u64 n, const Def *body)
Definition world.h:508
const Type * type_infer_level()
Definition world.h:326
const Def * type_idx(nat_t size)
Definition world.h:627
void set(std::string_view name)
Definition world.h:115
const Def * app(const Def *callee, const Def *arg)
Definition world.cpp:416
u32 curr_gid() const
Manage global identifier - a unique number for each Def.
Definition world.h:118
const Axm * axm(const Def *type)
See above.
Definition world.h:380
const Def * match(Defs)
Definition world.cpp:1030
const Def * arr(Shape shape, const Def *body)
Definition world.h:483
const Def * seq(bool is_pack, Shape shape, const Def *body)
Definition world.cpp:887
const Def * type_bot()
Definition world.h:606
const Pi * pi(const Def *dom, const Def *codom, bool implicit=false)
Definition world.h:386
const Def * pack(u64 n, const Def *body)
Definition world.h:490
const Def * insert(const Def *d, u64 a, u64 i, const Def *val)
Definition world.h:547
const auto & muts() const
Definition world.h:717
ScopedLoc push(Loc)
Definition world.cpp:1285
const Def * implicit_holes(const Def *callee)
Only places the Holes.
Definition world.cpp:401
const Lam * lam(Defs dom, const Def *codom, Lam::Filter f, const Def *body)
Definition world.h:420
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 * annex(Enum auto id)
Lookup annex by Axm::id.
Definition world.h:303
const Lam * fun(Defs dom, const Def *codom, Lam::Filter f, const Def *body)
Definition world.h:424
Rule * mut_rule(const Reform *type)
Definition world.h:443
const Def * type_i8()
Definition world.h:635
World & verify()
Verifies that all externals() and annexes() are Def::is_closed(), if MIM_ENABLE_CHECKS.
Definition world.cpp:1262
const Def * bot(const Def *type)
Definition world.h:604
const Lit * lit_i64()
Definition world.h:573
Arr * mut_arr(const Def *type)
Definition world.h:481
const Def * call(const Def *callee, auto &&arg)
Base case.
Definition world.h:681
const Lam * lam(const Def *dom, Defs codom, Lam::Filter f, const Def *body)
Definition world.h:421
const Lit * lit_idx_mod(nat_t mod, u64 val)
Constructs a Lit of type Idx of size mod.
Definition world.h:593
const Def * single(const Def *)
Singleton type formation.
Definition world.cpp:1114
const Idx * type_idx()
Definition world.h:623
const Def * type_i1()
Definition world.h:634
Seq * mut_seq(bool is_pack, const Def *type)
Definition world.h:505
Pi * mut_pi(const Def *type, bool implicit=false)
Definition world.h:390
const Level * type_pending()
Placeholder type of a mutable whose sort Def::finalize infers from its ops.
Definition world.h:325
Sym name() const
Definition world.h:113
const fe::Log & log() const
Log via log().e("...", args) etc.; owned by the Driver.
Definition world.cpp:224
const Pi * cn(Defs dom, bool implicit=false)
Definition world.h:400
bool is_lenient() const
Definition world.h:167
void dump()
Dump to std::cout.
Definition dump.cpp:1548
const Lam * fun(const Def *dom, Defs codom, Lam::Filter f, const Def *body)
Definition world.h:425
const Reform * reform(const Def *dom)
Definition world.h:442
void dot(std::ostream &os, DotConfig cfg={}) const
Dumps DOT to os, configured via cfg (see DotConfig).
Definition dot.cpp:267
void write()
Same above but file name defaults to World::name.
Definition dump.cpp:1559
const Lam * lam(Defs dom, Defs codom, Lam::Filter f, const Def *body)
Definition world.h:422
Lam * mut_fun(Defs dom, const Def *codom)
Definition world.h:434
const Def * fuse(Seq *seq)
«i: a; «j: b; T»» -> «v: (a, b); T» - the inverse of World::peel, for a nest that World::seq cannot f...
Definition world.cpp:660
Lam * mut_fun(const Def *dom, const Def *codom)
Definition world.h:433
const Lit * lit_i1()
Definition world.h:569
const Def * annex(Sym sym)
Lookup annex by Sym.
Definition world.cpp:160
const Axm * axm(NormalizeFn n, u8 curry, u8 trip, const Def *type)
Builds a fresh Axm with descending Axm::sub.
Definition world.h:377
const Nat * type_nat()
Definition world.h:622
const Pi * fn(const Def *dom, Defs codom, bool implicit=false)
Definition world.h:403
void for_each(bool elide_empty, std::function< void(Def *)>, bool schedule=false)
Definition world.cpp:1220
const Def * call(Args &&... args)
Annex overload with enum tempalte argument Id for annexes w/o subtag.
Definition world.h:693
Hole * mut_hole(const Def *type)
Definition world.h:361
const Axm * axm(const Def *type, plugin_t p, tag_t t, sub_t s)
Definition world.h:371
const Lam * lam(const Pi *pi, Lam::Filter f, const Def *body)
Definition world.h:414
const Def * tuple(Defs ops)
Definition world.cpp:516
const Lam * fun(Defs dom, Defs codom, Lam::Filter f, const Def *body)
Definition world.h:426
const Def * pack(fe::View< u64 > shape, const Def *body)
Definition world.h:488
Lam * mut_lam(const Def *dom, const Def *codom)
Definition world.h:429
const Def * gid2def(u32 gid)
Lookup Def by gid.
Definition world.cpp:1256
const Def * lmax(Defs levels)
Definition world.cpp:260
Flags & flags()
Retrieve compile Flags.
Definition world.cpp:225
const Def * implicit_app(const Def *callee, const Def *arg)
Definition world.cpp:411
Annexes & annexes()
Definition world.h:289
const Def * unwrap(const Def *)
Singleton term elimination.
Definition world.cpp:1128
const Def * implicit_app(const Def *callee, Defs args)
Definition world.h:656
void debug_dump()
Dump in Debug build if World::log::level is fe::Log::Level::Debug.
Definition dump.cpp:1550
u32 next_gid()
Definition world.h:119
const Def * extract(const Def *d, u64 i)
Definition world.h:538
const Lam * fun(const Def *dom, const Def *codom, Lam::Filter f, const Def *body)
Definition world.h:423
const Def * inj(const Def *type, const Def *value)
Definition world.cpp:975
const auto & breakpoints()
Definition world.h:174
const Type * type()
Definition world.h:332
const Axm * axm(NormalizeFn n, u8 curry, u8 trip, const Def *type, plugin_t p, tag_t t, sub_t s)
Definition world.h:368
const Def * pack(Defs shape, const Def *body)
Definition world.h:486
const Lit * lit_level_0()
Definition world.h:557
void set(Sym name)
Definition world.h:114
const Def * app(const Def *callee, Defs args)
Definition world.h:454
Lam * mut_fun(Defs dom, Defs codom)
Definition world.h:436
fe::Error & error()
Definition world.cpp:222
void solve_levels()
Defaults the level Holes of all postponed constraints that are still unknown to 0 and checks them.
Definition world.cpp:313
const Def * extract(const Def *d, const Def *i)
Definition world.cpp:598
Pack * mut_pack(const Def *type)
Definition world.h:482
bool is_frozen() const
Definition world.h:151
const Proxy * proxy(const Def *type, Defs ops, u32 tag, bool vars=false, bool muts=false)
Definition world.h:357
Loc get_loc() const
Definition world.h:132
const Lit * lit_nat_0()
Definition world.h:564
const Def * arr(fe::View< u64 > shape, const Def *body)
Definition world.h:487
Sym sym(std::string_view)
Definition world.cpp:228
const Lit * lit_i16()
Definition world.h:571
Hole * mut_hole_level()
Definition world.h:362
Lam * mut_lam(Defs dom, const Def *codom)
Definition world.h:430
const Lit * lit_ff()
Definition world.h:596
const Lit * lit_nat_max()
Definition world.h:566
const Def * raw_app(const Def *type, const Def *callee, Defs args)
Definition world.h:459
const Pi * pi(Defs dom, const Def *codom, bool implicit=false)
Definition world.h:387
fe::Restore< CurrLoc > ScopedLoc
Definition world.h:129
const Def * join(Defs ops)
Definition world.cpp:948
const Def * ext(const Def *type)
Definition world.cpp:939
Sym append_suffix(Sym name, std::string suffix)
Appends a suffix or an increasing number if the suffix already exists.
Definition world.cpp:1157
const Annexes & annexes() const
Definition world.h:290
static constexpr nat_t Num_Lit_Nats
Def::arity of a Sigma is lit_nat(num_ops()) and Def::num_projs reads it straight back out,...
Definition world.h:561
const Lit * lit_i32(u32 val)
Definition world.h:586
const Lit * lit_i8(u8 val)
Definition world.h:584
const Def * implicit_app(const Def *callee, Enum auto arg)
Definition world.h:664
Lam * mut_lam(Defs dom, Defs codom)
Definition world.h:432
const Def * type_top()
Definition world.h:607
const Lit * lit_idx_1_0()
Definition world.h:567
Sigma * mut_sigma(size_t size)
A mutable Sigma of type level.
Definition world.h:467
const Pi * pi(Defs dom, Defs codom, bool implicit=false)
Definition world.h:389
const Def * var(Def *mut)
Definition world.cpp:392
const Tuple * tuple()
the unit value of type []
Definition world.h:530
const Def * annex(flags_t flags)
Lookup annex by flags.
Definition world.h:297
const Def * call(Id id, Args &&... args)
Annex overload with enum instance as first argument.
Definition world.h:687
const Nom * nom(flags_t key, const Def *type)
Make type Nominal under key.
Definition world.cpp:1134
const Def * type_bool()
Definition world.h:633
const Def * raw_app(const Axm *axm, u8 curry, u8 trip, const Def *type, const Def *callee, const Def *arg)
Definition world.cpp:501
DbgKey dbg_key() const
World::get_loc, already interned.
Definition world.h:133
const Def * prod(bool term, Defs ops)
Definition world.h:497
const Externals & externals() const
Definition world.h:286
void for_each(bool elide_empty, std::invocable< M * > auto f, bool schedule=false)
Definition world.h:739
const Def * peel(const Seq *seq, const Def *index)
seq with the axes covered by index peeled off - the element itself once index covers all of them.
Definition world.cpp:646
const Def * prod(bool term)
() or [].
Definition world.h:498
const Def * type_indices(Shape shape)
The type of an index into shape: Idx n, a Sigma of those, or «i: r; Idx (s#i)» for a dynamic rank.
Definition world.cpp:678
const Lam * con(const Def *dom, Lam::Filter f, const Def *body)
Definition world.h:417
const Lit * lit_idx(std::integral auto val)
Definition world.h:578
const Lit * lit_i64(u64 val)
Definition world.h:587
const Def * type_i64()
Definition world.h:638
const Sigma * sigma()
The unit type within Type 0.
Definition world.h:471
const Lit * lit_nat(nat_t a)
Definition world.h:563
const State & state() const
Definition world.h:106
Hole * mut_hole_type()
Definition world.h:363
const Def * wrap(const Def *)
Singleton term introduction.
Definition world.cpp:1123
const auto & vars() const
Definition world.h:716
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
const Def * top(const Def *type)
Definition world.h:605
const Def * type_idx(const Def *size)
Definition world.h:625
auto lenient() const
Definition world.h:168
Lam * mut_con(const Def *dom)
Definition world.h:427
Arr * mut_arr()
Definition world.h:478
auto & vars()
Definition world.h:714
const Lit * lit_level(u64 level)
Definition world.h:554
Defs reduce(const Var *var, const Def *arg)
Yields the new body of [mut->var() -> arg]mut.
Definition world.cpp:1170
const Lit * lit_int(nat_t width, u64 val)
Constructs a Lit of type Idx of size 2^width.
Definition world.h:582
auto freeze() const
Freezes the World until the end of the scope and restores the previous frozen state afterwards:
Definition world.h:160
const Lit * lit_bool(bool val)
Definition world.h:595
void breakpoint(u32 gid)
Trigger breakpoint in your debugger when creating a Def with this gid.
Definition world.cpp:1253
const Def * select(const Def *cond, const Def *t, const Def *f)
Builds (f, t)#cond.
Definition world.h:541
Sigma * mut_sigma(const Def *type, size_t size)
Definition world.h:464
const Def * seq(bool is_pack, fe::View< u64 > shape, const Def *body)
Definition world.h:509
Lam * mut_con(Defs dom)
Definition world.h:428
const Pi * fn(const Def *dom, const Def *codom, bool implicit=false)
Definition world.h:401
const Rule * rule(const Reform *type, const Def *lhs, const Def *rhs, const Def *guard)
Definition world.h:444
u32 curr_run() const
Manage run - used to track fixed-point iterations to compute Def::free_vars.
Definition world.h:122
World(World &&other) noexcept
Definition world.h:89
const Lit * lit_nat_1()
Definition world.h:565
const Pi * pi(const Def *dom, Defs codom, bool implicit=false)
Definition world.h:388
const Def * type_i32()
Definition world.h:637
const Def * insert(const Def *d, u64 i, const Def *val)
Definition world.h:548
const Pi * fn(Defs dom, Defs codom, bool implicit=false)
Definition world.h:404
Lam * mut_lam(const Pi *pi)
Definition world.h:415
const Def * annex()
Get Axm from a plugin.
Definition world.h:309
const Level * type_level()
Definition world.h:319
World::get_loc together with its interned DbgKey, so pushing/popping a Loc never re-interns it.
Definition world.h:46
Definition ast.h:16
u64 nat_t
Definition types.h:37
u8 sub_t
Definition types.h:42
u64 flags_t
Definition types.h:39
fe::View< const Def * > Defs
Definition def.h:96
u64 level_t
Definition types.h:36
GIDMap< const Def *, To > DefMap
Definition def.h:93
TExt< true > Top
Definition union.h:40
fe::Vector< const Def * > DefVec
Definition def.h:98
const Def *(*)(const Def *, const Def *, const Def *) NormalizeFn
Definition def.h:118
u64 plugin_t
Definition types.h:40
uint32_t u32
Definition types.h:27
TExt< false > Bot
Definition union.h:39
uint64_t u64
Definition types.h:27
u8 tag_t
Definition types.h:41
uint8_t u8
Definition types.h:27
@ Arr
Definition def.h:125
@ Variant
Definition def.h:125
@ Single
Definition def.h:125
@ Sigma
Definition def.h:125
@ App
Definition def.h:125
@ LMax
Definition def.h:125
uint16_t u16
Definition types.h:27
Options for Def::dot, World::dot, and Nest::dot.
Definition def.h:241
static constexpr flags_t flags(plugin_t p, tag_t t, sub_t s=0)
Assembles the full flags from its plugin, tag, and sub fields.
Definition plugin.h:266
static constexpr plugin_t Global_Plugin
Definition plugin.h:214
static consteval flags_t base()
Definition plugin.h:276
Compiler switches that must be saved and looked up in later phases of compilation.
Definition flags.h:11
friend void swap(State &s1, State &s2) noexcept
Definition world.h:72
ankerl::unordered_dense::set< uint32_t > watchpoints
Definition world.h:70
ankerl::unordered_dense::set< uint32_t > breakpoints
Definition world.h:69
State(Sym name)
Definition world.h:55
struct mim::World::State::POD pod
Plain Old Data
Definition world.h:59