MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
def.h
Go to the documentation of this file.
1#pragma once
2
3#include <format>
4#include <limits>
5#include <optional>
6#include <span>
7
8#include <fe/assert.h>
9#include <fe/cast.h>
10#include <fe/enum.h>
11
12#include "mim/config.h"
13
14#include "mim/util/dbg.h"
15#include "mim/util/sets.h"
16#include "mim/util/util.h"
17#include "mim/util/vector.h"
18
19// clang-format off
20#define MIM_NODE(X) \
21 X(Lit, Judge::Intro) /* keep this first - causes Lit to appear left in Def::less/Def::greater*/ \
22 X(Axm, Judge::Intro) \
23 X(Var, Judge::Intro) \
24 X(Global, Judge::Intro) \
25 X(Proxy, Judge::Intro) \
26 X(Hole, Judge::Hole ) \
27 X(Type, Judge::Meta ) X(Univ, Judge::Meta ) X(UMax, Judge::Meta) X(UInc, (Judge::Meta )) \
28 X(Pi, Judge::Form ) X(Lam, Judge::Intro) X(App, Judge::Elim) \
29 X(Sigma, Judge::Form ) X(Tuple, Judge::Intro) X(Extract, Judge::Elim) X(Insert, (Judge::Intro | Judge::Elim)) \
30 X(Arr, Judge::Form ) X(Pack, Judge::Intro) \
31 X(Join, Judge::Form ) X(Inj, Judge::Intro) X(Match, Judge::Elim) X(Top, (Judge::Intro )) \
32 X(Meet, Judge::Form ) X(Merge, Judge::Intro) X(Split, Judge::Elim) X(Bot, (Judge::Intro )) \
33 X(Reform, Judge::Form ) X(Rule, Judge::Intro) \
34 X(Uniq, Judge::Form ) \
35 X(Nat, Judge::Form ) \
36 X(Idx, Judge::Intro)
37
38#define MIM_IMM_NODE(X) \
39 X(Lit) \
40 X(Axm) \
41 X(Var) \
42 X(Proxy) \
43 X(Type) X(Univ) X(UMax) X(UInc) \
44 X(Pi) X(Lam) X(App) \
45 X(Sigma) X(Tuple) X(Extract) X(Insert) \
46 X(Arr) X(Pack) \
47 X(Join) X(Inj) X(Match) X(Top) \
48 X(Meet) X(Merge) X(Split) X(Bot) \
49 X(Reform) X(Rule) \
50 X(Uniq) \
51 X(Nat) \
52 X(Idx)
53
54#define MIM_MUT_NODE(X) \
55 X(Global) \
56 X(Hole) \
57 X(Pi) X(Lam) \
58 X(Sigma) \
59 X(Arr) X(Pack) \
60 X(Rule)
61// clang-format on
62
63namespace mim {
64
65class App;
66class Axm;
67class Var;
68class Def;
69class World;
70
71/// @name Def
72/// GIDSet / GIDMap keyed by Def::gid of `const Def*`.
73///@{
74template<class To>
80///@}
81
82/// @name Def (Mutable)
83/// GIDSet / GIDMap keyed by Def::gid of `Def*`.
84///@{
85template<class To>
90///@}
91
92/// @name Var
93/// GIDSet / GIDMap keyed by Var::gid of `const Var*`.
94///@{
95template<class To>
100///@}
101
102using NormalizeFn = const Def* (*)(const Def*, const Def*, const Def*);
103
104/// @name Enums that classify certain aspects of Def%s.
105///@{
106
107enum class Node : node_t {
108#define CODE(node, _) node,
110#undef CODE
111};
112
113#define CODE(node, _) +size_t(1)
114static constexpr size_t Num_Nodes = size_t(0) MIM_NODE(CODE);
115#undef CODE
116
117/// Tracks whether a Def transitively depends - through its Def::deps() but only up to (and excluding) the next
118/// *mutable* - on certain kinds of Def%s.
119/// @see Def::has_dep
120enum class Dep : unsigned {
121 None = 0, ///< Depends on nothing of interest.
122 Mut = 1 << 0, ///< Depends on a *mutable*.
123 Var = 1 << 1, ///< Depends on a Var.
124 Hole = 1 << 2, ///< Depends on a Hole.
125 Proxy = 1 << 3, ///< Depends on a Proxy.
126};
127
128/// [Judgement](https://ncatlab.org/nlab/show/judgment).
129enum class Judge : u32 {
130 // clang-format off
131 Form = 1 << 0, ///< [Type Formation](https://ncatlab.org/nlab/show/type+formation) like `T -> T`.
132 Intro = 1 << 1, ///< [Term Introduction](https://ncatlab.org/nlab/show/natural+deduction) like `λ(x: Nat): Nat = x`.
133 Elim = 1 << 2, ///< [Term Elimination](https://ncatlab.org/nlab/show/term+elimination) like `f a`.
134 Meta = 1 << 3, ///< Meta rules for Univ%erse and Type levels.
135 Hole = 1 << 4, ///< Special rule for Hole.
136 // clang-format on
137};
138
139/// Classifies whether a [`Node`](@ref mim::Node) may occur as a *mutable*, an *immutable*, or both.
140/// @see @ref mut
141enum class Mut {
142 // clang-format off
143 Mut = 1 << 0, ///< Node may be mutable.
144 Imm = 1 << 1, ///< Node may be immutable.
145 // clang-format on
146};
147///@}
148
149} // namespace mim
150
151#ifndef DOXYGEN
152// clang-format off
153template<> struct fe::is_bit_enum<mim::Dep> : std::true_type {};
154template<> struct fe::is_bit_enum<mim::Judge> : std::true_type {};
155template<> struct fe::is_bit_enum<mim::Mut> : std::true_type {};
156// clang-format on
157#endif
158
159namespace mim {
160
161/// Use as mixin to wrap all kind of Def::proj and Def::projs variants.
162#define MIM_PROJ(NAME, CONST) \
163 nat_t num_##NAME##s() CONST noexcept { return ((const Def*)NAME())->num_projs(); } \
164 nat_t num_t##NAME##s() CONST noexcept { return ((const Def*)NAME())->num_tprojs(); } \
165 const Def* NAME(nat_t a, nat_t i) CONST noexcept { return ((const Def*)NAME())->proj(a, i); } \
166 const Def* NAME(nat_t i) CONST noexcept { return ((const Def*)NAME())->proj(i); } \
167 const Def* t##NAME(nat_t i) CONST noexcept { return ((const Def*)NAME())->tproj(i); } \
168 template<nat_t A = std::dynamic_extent, class F> \
169 auto NAME##s(F f) CONST noexcept { \
170 return ((const Def*)NAME())->projs<A, F>(f); \
171 } \
172 template<class F> \
173 auto t##NAME##s(F f) CONST noexcept { \
174 return ((const Def*)NAME())->tprojs<F>(f); \
175 } \
176 template<nat_t A = std::dynamic_extent> \
177 auto NAME##s() CONST noexcept { \
178 return ((const Def*)NAME())->projs<A>(); \
179 } \
180 auto t##NAME##s() CONST noexcept { return ((const Def*)NAME())->tprojs(); } \
181 template<class F> \
182 auto NAME##s(nat_t a, F f) CONST noexcept { \
183 return ((const Def*)NAME())->projs<F>(a, f); \
184 } \
185 auto NAME##s(nat_t a) CONST noexcept { return ((const Def*)NAME())->projs(a); }
186
187/// CRTP-based mixin to declare setters for Def::loc \& Def::name using a *covariant* return type.
188template<class P, class D = Def>
189class // D is only needed to make the resolution `D::template set` lazy
190#ifdef _MSC_VER
191 __declspec(empty_bases)
192#endif
193 Setters {
194private:
195 P* super() { return static_cast<P*>(this); }
196 const P* super() const { return static_cast<const P*>(this); }
197
198public:
199 // clang-format off
200 template<bool Ow = false> const P* set(Loc l ) const { super()->D::template set<Ow>(l); return super(); }
201 template<bool Ow = false> P* set(Loc l ) { super()->D::template set<Ow>(l); return super(); }
202 template<bool Ow = false> const P* set( Sym s ) const { super()->D::template set<Ow>(s); return super(); }
203 template<bool Ow = false> P* set( Sym s ) { super()->D::template set<Ow>(s); return super(); }
204 template<bool Ow = false> const P* set( std::string s) const { super()->D::template set<Ow>(std::move(s)); return super(); }
205 template<bool Ow = false> P* set( std::string s) { super()->D::template set<Ow>(std::move(s)); return super(); }
206 template<bool Ow = false> const P* set(Loc l, Sym s ) const { super()->D::template set<Ow>(l, s); return super(); }
207 template<bool Ow = false> P* set(Loc l, Sym s ) { super()->D::template set<Ow>(l, s); return super(); }
208 template<bool Ow = false> const P* set(Loc l, std::string s) const { super()->D::template set<Ow>(l, std::move(s)); return super(); }
209 template<bool Ow = false> P* set(Loc l, std::string s) { super()->D::template set<Ow>(l, std::move(s)); return super(); }
210 template<bool Ow = false> const P* set(Dbg d ) const { super()->D::template set<Ow>(d); return super(); }
211 template<bool Ow = false> P* set(Dbg d ) { super()->D::template set<Ow>(d); return super(); }
212 // clang-format on
213};
214
215/// Options for Def::dot and World::dot.
216/// @note Def::dot and World::dot honor DotConfig::max; World::dot also honors DotConfig::all_annexes.
217struct DotConfig {
218 int max = std::numeric_limits<int>::max(); ///< Maximum recursion depth.
219 bool all_annexes = false; ///< Include all annexes - even if unused (World::dot only).
220 bool follow_types = false; ///< Follow Def::type() dependencies.
221 bool inline_consts = false; ///< Wire up literals, axioms, etc. with normal edges instead of detaching them.
222 bool default_filter = false; ///< Show Lam::filter() even if it has its default value.
223 bool show_hidden = false; ///< Render otherwise-transparent detached edges (Var→binder back-edges,
224 ///< shared literals/axioms, type edges) with a visible color.
225};
226
227/// Base class for all Def%s.
228///
229/// These are the most important subclasses:
230/// | Type Formation | Term Introduction | Term Elimination |
231/// | ----------------- | ----------------- | ----------------- |
232/// | Pi | Lam | App |
233/// | Sigma / Arr | Tuple / Pack | Extract |
234/// | | Insert | Insert |
235/// | Uniq | | |
236/// | Join | Inj | Match |
237/// | Meet | Merge | Split |
238/// | Reform | Rule | |
239/// | Nat | Lit | |
240/// | Idx | Lit | |
241/// In addition there is:
242/// * Var: A variable. Currently the following Def%s may be binders:
243/// * Pi, Lam, Sigma, Arr, Pack
244/// * Axm: To introduce new entities.
245/// * Proxy: Used for intermediate values during optimizations.
246/// * Hole: A metavariable filled in by the type inference (always mutable as holes are filled in later).
247/// * Type, Univ, UMax, UInc: To keep track of type levels.
248///
249/// The data layout (see World::alloc and Def::deps) looks like this:
250/// ```
251/// Def| type | op(0) ... op(num_ops-1) |
252/// |-----------ops-----------|
253/// deps
254/// |--------------------------------| if type() != nullptr && is_set()
255/// |-------------------------| if type() == nullptr && is_set()
256/// |------| if type() != nullptr && !is_set()
257/// || if type() == nullptr && !is_set()
258/// ```
259/// @attention This means that any subclass of Def **must not** introduce additional members.
260/// @see @ref mut
261class Def : public fe::RuntimeCast<Def> {
262private:
263 Def& operator=(const Def&) = delete;
264 Def(const Def&) = delete;
265 Def(Def&&) = delete;
266
267protected:
268 /// @name C'tors and D'tors
269 ///@{
270 Def(World*, Node, const Def* type, Defs ops, flags_t flags); ///< Constructor for an *immutable* Def.
271 Def(Node, const Def* type, Defs ops, flags_t flags); ///< As above but World retrieved from @p type.
272 Def(Node, const Def* type, size_t num_ops, flags_t flags); ///< Constructor for a *mutable* Def.
273 Def(Node, Def* binder); ///< Constructor for a Var; stores its @p binder.
274 virtual ~Def() = default;
275 ///@}
276
277public:
278 /// @name Getters
279 ///@{
280 World& world() const noexcept;
281 constexpr flags_t flags() const noexcept { return flags_; }
282 constexpr u32 gid() const noexcept { return gid_; } ///< Global id - *unique* number for this Def.
283 constexpr u32 tid() const noexcept { return tid_; } ///< Trie id - only used in Trie.
284 constexpr u32 mark() const noexcept { return mark_; } ///< Used internally by free_vars().
285 constexpr size_t hash() const noexcept { return hash_; }
286 constexpr Node node() const noexcept { return node_; }
287 std::string_view node_name() const;
288 ///@}
289
290 /// @name Judgement
291 /// What kind of Judge%ment represents this Def?
292 ///@{
293 Judge judge() const noexcept;
294 // clang-format off
295 bool is_form() const noexcept { return fe::has_flag(judge(), Judge::Form); }
296 bool is_intro() const noexcept { return fe::has_flag(judge(), Judge::Intro); }
297 bool is_elim() const noexcept { return fe::has_flag(judge(), Judge::Elim); }
298 bool is_meta() const noexcept { return fe::has_flag(judge(), Judge::Meta); }
299 // clang-format on
300 ///@}
301
302 /// @name type
303 ///@{
304
305 /// Yields the "raw" type of this Def (maybe `nullptr`).
306 /// @see Def::unfold_type.
307 const Def* type() const noexcept;
308 /// Yields the type of this Def and builds a new `Type (UInc n)` if necessary.
309 const Def* unfold_type() const;
310 bool is_term() const; ///< Is this Def a *term*, i.e. is its type() a Type?
311 virtual const Def* arity() const; ///< Number of elements available to Extract / Insert (may be dynamic).
312 ///@}
313
314 /// @name ops
315 ///@{
316 template<size_t N = std::dynamic_extent>
317 constexpr auto ops() const noexcept {
318 return View<const Def*, N>(ops_ptr(), num_ops_);
319 }
320 const Def* op(size_t i) const noexcept { return ops()[i]; }
321 constexpr size_t num_ops() const noexcept { return num_ops_; }
322 ///@}
323
324 /// @name Setting Ops (Mutables Only)
325 /// @anchor set_ops
326 /// You can set and change the Def::ops of a mutable after construction.
327 /// However, you have to obey the following rules:
328 /// If Def::is_set() is ...
329 /// * `false`, [set](@ref Def::set) the [operands](@ref Def::ops) from left to right.
330 /// * `true`, Def::unset() the operands first and then start over:
331 /// ```
332 /// mut->unset()->set({a, b, c});
333 /// ```
334 ///
335 /// MimIR assumes that a mutable is *final*, when its last operand is set.
336 /// Then, Def::check() will be invoked.
337 ///@{
338 bool is_set() const; ///< Yields `true` if empty or the last op is set.
339 Def* set(size_t i, const Def*); ///< Successively set from left to right.
340 Def* set(Defs ops); ///< Set @p ops all at once (no Def::unset necessary beforehand).
341 Def* unset(); ///< Unsets all Def::ops; works even, if not set at all or only partially set.
342
343 /// Update type.
344 /// @warning Only make type-preserving updates such as removing Hole%s.
345 /// Do this even before updating all other ops()!
346 Def* set_type(const Def*);
347 ///@}
348
349 /// @name deps
350 /// All *dependencies* of a Def and includes:
351 /// * Def::type() (if not `nullptr`) and
352 /// * the other Def::ops() (only included, if Def::is_set()) in this order.
353 ///@{
354 Defs deps() const noexcept;
355 const Def* dep(size_t i) const noexcept { return deps()[i]; }
356 size_t num_deps() const noexcept { return deps().size(); }
357 ///@}
358
359 /// @name has_dep
360 /// Checks whether one Def::deps() contains specific elements defined in Dep.
361 /// This works up to the next *mutable*.
362 /// For example, consider the Tuple `tup`: `(?, lam (x: Nat) = y)`:
363 /// ```
364 /// bool has_hole = tup->has_dep(Dep::Hole); // true
365 /// bool has_mut = tup->has_dep(Dep::Mut); // true
366 /// bool has_var = tup->has_dep(Dep::Var); // false - y is contained in another mutable
367 /// ```
368 ///@{
369 Dep dep() const noexcept { return Dep(dep_); }
370 bool has_dep() const noexcept { return dep_ != 0; }
371 bool has_dep(Dep d) const noexcept { return fe::has_flag(dep(), d); }
372 ///@}
373
374 /// @name proj
375 /// @anchor proj
376 /// Splits this Def via Extract%s or directly accessing the Def::ops in the case of Sigma%s or Arr%ays.
377 /// ```
378 /// std::array<const Def*, 2> ab = def->projs<2>();
379 /// std::array<u64, 2> xy = def->projs<2>([](auto def) { return Lit::as(def); });
380 /// auto [a, b] = def->projs<2>();
381 /// auto [x, y] = def->projs<2>([](auto def) { return Lit::as(def); });
382 /// Vector<const Def*> projs1 = def->projs(); // "projs1" has def->num_projs() many elements
383 /// Vector<const Def*> projs2 = def->projs(n);// "projs2" has n elements - asserts if incorrect
384 /// // same as above but applies Lit::as<nat_t>(def) to each element
385 /// Vector<const Lit*> lits1 = def->projs( [](auto def) { return Lit::as(def); });
386 /// Vector<const Lit*> lits2 = def->projs(n, [](auto def) { return Lit::as(def); });
387 /// ```
388 ///@{
389
390 /// Yields Def::arity(), if it is a Lit, or `1` otherwise.
391 nat_t num_projs() const;
392 nat_t num_tprojs() const; ///< As above but yields 1, if Flags::scalarize_threshold is exceeded.
393
394 /// Similar to World::extract while assuming an arity of @p a, but also works on Sigma%s and Arr%ays.
395 const Def* proj(nat_t a, nat_t i) const;
396 const Def* proj(nat_t i) const { return proj(num_projs(), i); } ///< As above but takes Def::num_projs as arity.
397 const Def* tproj(nat_t i) const { return proj(num_tprojs(), i); } ///< As above but takes Def::num_tprojs.
398
399 /// Splits this Def via Def::proj%ections into an Array (if `A == std::dynamic_extent`) or `std::array` (otherwise).
400 /// Applies @p f to each element.
401 template<nat_t A = std::dynamic_extent, class F>
402 auto projs(F f) const {
403 using R = std::decay_t<decltype(f(this))>;
404 if constexpr (A == std::dynamic_extent) {
405 return projs(num_projs(), f);
406 } else {
407 std::array<R, A> array;
408 for (nat_t i = 0; i != A; ++i)
409 array[i] = f(proj(A, i));
410 return array;
411 }
412 }
413
414 template<class F>
415 auto tprojs(F f) const {
416 return projs(num_tprojs(), f);
417 }
418
419 template<class F>
420 auto projs(nat_t a, F f) const {
421 using R = std::decay_t<decltype(f(this))>;
422 return Vector<R>(a, [&](nat_t i) { return f(proj(a, i)); });
423 }
424 template<nat_t A = std::dynamic_extent>
425 auto projs() const {
426 return projs<A>([](const Def* def) { return def; });
427 }
428 auto tprojs() const {
429 return tprojs([](const Def* def) { return def; });
430 }
431 auto projs(nat_t a) const {
432 return projs(a, [](const Def* def) { return def; });
433 }
434 ///@}
435
436 /// @name var
437 /// @anchor var
438 /// Retrieve Var for *mutables*.
439 /// @see @ref proj
440 ///@{
442 const Def* var(); ///< Not necessarily a Var: E.g., if the return type is `[]`, this will yield `()`.
443 const Def* var_type(); ///< If `this` is a binder, compute the type of its Var%iable.
444
445 const Var* has_var() { return var_; } ///< Only returns not `nullptr`, if Var of this mutable has ever been created.
446 /// As above if `this` is a *mutable*.
447 const Var* has_var() const {
448 if (auto mut = isa_mut()) return mut->has_var();
449 return nullptr;
450 }
451
452 /// Is `this` a mutable that introduces a Var?
453 /// @returns `{nullptr, nullptr}` otherwise.
454 template<class D = Def>
455 std::pair<D*, const Var*> isa_binder() const {
456 if (auto mut = isa_mut<D>()) {
457 if (auto var = mut->has_var()) return {mut, var};
458 }
459 return {nullptr, nullptr};
460 }
461 ///@}
462
463 /// @name Free Vars and Muts
464 /// MimIR splits the free-variable analysis into a *local* and a *global* layer:
465 /// * local_muts() / local_vars() only look at the *immutable* fan-out and are cheap, cached, and hash-consed.
466 /// * free_vars() close over the *mutable* boundary as well and are the actual set of free Var%s.
467 /// They are computed on demand via a fixed-point iteration and cached in mutables.
468 /// Mutating a mutable transitively invalidates these caches by following users().
469 ///@{
470
471 /// Mutables reachable by following *immutable* deps(); `mut->local_muts()` is by definition the set `{ mut }`.
472 Muts local_muts() const;
473
474 /// Var%s reachable by following *immutable* deps().
475 /// @note `var->local_vars()` is by definition the set `{ var }`.
476 Vars local_vars() const;
477
478 /// Global set of free Var%s: extends local_vars() by transitively following *mutables* as well.
479 /// @note On a *mutable* this simply forwards to the caching non-`const` overload below.
480 Vars free_vars() const;
481 Vars free_vars(); ///< As above but drives (and caches) the fixed-point iteration for *mutables*.
482 Muts users() { return muts_; } ///< Set of mutables where this mutable is locally referenced.
483 bool is_open() const; ///< Has free_vars()?
484 bool is_closed() const; ///< Has no free_vars()?
485
486 /// Transitively walks up free_vars() till the outermoust binder has been found.
487 /// @returns `nullptr`, if is_closed() and not a mutable.
488 Def* outermost_binder() const;
489
490 /// Does @p this nest @p mut?
491 /// The relation is strict: `f->nests(f)` is `false`.
492 bool nests(Def* mut);
493 /// Does @p this nest @p def?
494 /// Also strict: a @p def that only uses @p this%'s own Var sits at @p this%'s level and is *not* nested.
495 bool nests(const Def* def);
496 ///@}
497
498 /// @name external
499 ///@{
500 bool is_external() const noexcept { return external_; }
501 void externalize();
502 void internalize();
503 void transfer_external(Def* to);
504 bool is_annex() const noexcept { return annex_; }
505 ///@}
506
507 /// @name dirty
508 /// Scratch bit for Phase%s to mark muts that need re-examination.
509 /// @see Phase::taint
510 ///@{
511 bool is_dirty() const noexcept { return dirty_; }
512 void dirty(bool dirty = true) noexcept { dirty_ = dirty; }
513 ///@}
514
515 /// @name Casts
516 /// @see @ref cast_builtin
517 ///@{
518 bool is_mutable() const noexcept { return mut_; }
519
520 // clang-format off
521 template<class T = Def> const T* isa_imm() const { return isa_mut<T, true>(); }
522 template<class T = Def> const T* as_imm() const { return as_mut<T, true>(); }
523 // clang-format on
524
525 /// If `this` is *mutable*, it will cast `const`ness away and perform a `dynamic_cast` to @p T.
526 template<class T = Def, bool invert = false>
527 T* isa_mut() const {
528 if constexpr (std::is_same<T, Def>::value)
529 return mut_ ^ invert ? const_cast<Def*>(this) : nullptr;
530 else
531 return mut_ ^ invert ? const_cast<Def*>(this)->template isa<T>() : nullptr;
532 }
533
534 /// Asserts that `this` is a *mutable*, casts `const`ness away and performs a `static_cast` to @p T.
535 template<class T = Def, bool invert = false>
536 T* as_mut() const {
537 assert(mut_ ^ invert);
538 if constexpr (std::is_same<T, Def>::value)
539 return const_cast<Def*>(this);
540 else
541 return const_cast<Def*>(this)->template as<T>();
542 }
543
544 /// Like Def::as_mut but - instead of merely asserting in `Debug` builds - throws via fe::throwf when the cast
545 /// fails; the mutable counterpart of fe::RuntimeCast::expect (which Def inherits for the general case).
546 /// @p fmt / @p args describe what was expected; a plain string works, as does a format string plus arguments.
547 template<class T = Def, class... Args>
548 T* expect_mut(std::format_string<Args...> fmt, Args&&... args) const {
549 if (auto res = isa_mut<T>()) return res;
550 fe::throwf("expected {}, but got '{}'", std::format(fmt, std::forward<Args>(args)...), this);
551 }
552 ///@}
553
554 /// @name Dbg Getters
555 ///@{
556 Dbg dbg() const { return dbg_; }
557 Loc loc() const { return dbg_.loc(); }
558 Sym sym() const { return dbg_.sym(); }
559 std::string unique_name() const; ///< name + "_" + Def::gid
560 ///@}
561
562 /// @name Dbg Setters
563 /// Every subclass `S` of Def has the same setters that return `S*`/`const S*` via the mixin Setters.
564 ///@{
565 // clang-format off
566 template<bool Ow = false> const Def* set(Loc l) const { if (Ow || !dbg_.loc()) dbg_.set(l); return this; }
567 template<bool Ow = false> Def* set(Loc l) { if (Ow || !dbg_.loc()) dbg_.set(l); return this; }
568 template<bool Ow = false> const Def* set(Sym s) const { if (Ow || !dbg_.sym()) dbg_.set(s); return this; }
569 template<bool Ow = false> Def* set(Sym s) { if (Ow || !dbg_.sym()) dbg_.set(s); return this; }
570 template<bool Ow = false> const Def* set( std::string s) const { set<Ow>(sym(std::move(s))); return this; }
571 template<bool Ow = false> Def* set( std::string s) { set<Ow>(sym(std::move(s))); return this; }
572 template<bool Ow = false> const Def* set(Loc l, Sym s ) const { set<Ow>(l); set<Ow>(s); return this; }
573 template<bool Ow = false> Def* set(Loc l, Sym s ) { set<Ow>(l); set<Ow>(s); return this; }
574 template<bool Ow = false> const Def* set(Loc l, std::string s) const { set<Ow>(l); set<Ow>(sym(std::move(s))); return this; }
575 template<bool Ow = false> Def* set(Loc l, std::string s) { set<Ow>(l); set<Ow>(sym(std::move(s))); return this; }
576 template<bool Ow = false> const Def* set(Dbg d) const { set<Ow>(d.loc(), d.sym()); return this; }
577 template<bool Ow = false> Def* set(Dbg d) { set<Ow>(d.loc(), d.sym()); return this; }
578 // clang-format on
579 ///@}
580
581 /// @name debug_prefix/suffix
582 /// Prepends/Appends a prefix/suffix to Def::name - but only in `Debug` build.
583 ///@{
584#ifndef NDEBUG
585 const Def* debug_prefix(std::string) const;
586 const Def* debug_suffix(std::string) const;
587#else
588 const Def* debug_prefix(std::string) const { return this; }
589 const Def* debug_suffix(std::string) const { return this; }
590#endif
591 ///@}
592
593 /// @name Rebuild
594 ///@{
595 Def* stub(World& w, const Def* type) { return stub_(w, type)->set(dbg()); }
596 Def* stub(const Def* type) { return stub(world(), type); }
597
598 /// Def::rebuild%s this Def while using @p new_op as substitute for its @p i'th Def::op
599 const Def* rebuild(World& w, const Def* type, Defs ops) const {
600 assert(isa_imm());
601 return rebuild_(w, type, ops)->set(dbg());
602 }
603 const Def* rebuild(const Def* type, Defs ops) const { return rebuild(world(), type, ops); }
604
605 /// Tries to make an immutable from a mutable.
606 /// This usually works if the mutable isn't recursive and its var isn't used.
607 virtual const Def* immutabilize() { return nullptr; }
608 bool is_immutabilizable();
609
610 const Def* refine(size_t i, const Def* new_op) const;
611
612 /// @see World::reduce
613 template<size_t N = std::dynamic_extent>
614 constexpr auto reduce(const Def* arg) const {
615 return reduce_(arg).span<N>();
616 }
617
618 /// First Def::op that needs to be dealt with during reduction; e.g. for a Pi we don't reduce the Pi::dom.
619 /// @see World::reduce
620 virtual constexpr size_t reduction_offset() const noexcept { return size_t(-1); }
621 ///@}
622
623 /// @name Type Checking
624 ///@{
625
626 /// Checks whether the `i`th operand can be set to `def`.
627 /// The method returns a possibly updated version of `def` (e.g. where Hole%s have been resolved).
628 /// This is the actual `def` that will be set as the `i`th operand.
629 virtual const Def* check([[maybe_unused]] size_t i, const Def* def) { return def; }
630
631 /// After all Def::ops have been Def::set, this method will be invoked to check the type of this mutable.
632 /// The method returns a possibly updated version of its type (e.g. where Hole%s have been resolved).
633 /// If different from Def::type, it will update its Def::type to a Def::zonk%ed version of that.
634 virtual const Def* check() { return type(); }
635
636 /// Yields `true`, if Def::local_muts() contain a Hole that is set.
637 /// Rewriting (Def::zonk%ing) will resolve the Hole to its operand.
638 bool needs_zonk() const;
639
640 /// If Hole%s have been filled, reconstruct the program without them.
641 /// Only goes up to but excluding other mutables.
642 /// @see https://stackoverflow.com/questions/31889048/what-does-the-ghc-source-mean-by-zonk
643 const Def* zonk() const;
644
645 /// If *mutable*, zonk()%s all ops and tries to immutabilize it; otherwise just zonk.
646 const Def* zonk_mut() const;
647 ///@}
648
649 /// zonk%s all @p defs and returns a new DefVec.
650 static DefVec zonk(Defs defs);
651
652 /// @name dump
653 /// @note While this output uses Mim syntax, it does usually **not** produce programs that can be read back.
654 /// It uses an unscheduled visiting algorithm, and is only meant for debugging purposes.
655 ///@{
656 void dump() const;
657 void dump(int max) const;
658 void write(int max) const;
659 void write(int max, const char* file) const;
660 std::ostream& stream(std::ostream&, int max) const;
661 ///@}
662
663 /// @name Syntactic Comparison
664 /// Establishes an arbitrary but deterministic total order on Def%s that is stable across runs.
665 ///@{
666 enum class Cmp {
667 L, ///< Less
668 G, ///< Greater
669 E, ///< Equal
670 U, ///< Unknown
671 };
672 [[nodiscard]] static Cmp cmp(const Def* a, const Def* b);
673 [[nodiscard]] static bool less(const Def* a, const Def* b);
674 [[nodiscard]] static bool greater(const Def* a, const Def* b);
675 ///@}
676
677 /// @name dot
678 /// Streams dot to @p os, configured via @p cfg (see DotConfig).
679 ///@{
680 void dot(std::ostream& os, DotConfig cfg = {}) const;
681 /// Same as above but write to @p file or `std::cout` if @p file is `nullptr`.
682 void dot(const char* file = nullptr, DotConfig cfg = {}) const;
683 void dot(const std::string& file, DotConfig cfg = {}) const { return dot(file.c_str(), cfg); }
684 ///@}
685
686protected:
687 /// @name Wrappers for World::sym
688 /// These are here to have Def::set%ters inline without including `mim/world.h`.
689 ///@{
690 Sym sym(const char*) const;
691 Sym sym(std::string_view) const;
692 Sym sym(std::string) const;
693 ///@}
694
695private:
696 Defs reduce_(const Def* arg) const;
697 virtual Def* stub_(World&, const Def*) { fe::unreachable(); }
698 virtual const Def* rebuild_(World& w, const Def* type, Defs ops) const = 0;
699
700 template<bool init>
701 Vars free_vars(bool&, uint32_t);
702 void invalidate();
703 const Def** ops_ptr() const {
704 return reinterpret_cast<const Def**>(reinterpret_cast<char*>(const_cast<Def*>(this + 1)));
705 }
706 bool equal(const Def* other) const;
707 bool nests(Def*, MutSet&);
708
709 template<Cmp>
710 [[nodiscard]] static bool cmp_(const Def* a, const Def* b);
711
712protected:
713 mutable Dbg dbg_;
714 union {
715 NormalizeFn normalizer_; ///< Axm only: Axm%s use this member to store their normalizer.
716 const Axm* axm_; ///< App only: Curried App%s of Axm%s use this member to propagate the Axm.
717 const Var* var_; ///< Mutable only: Var of a mutable.
718 Def* binder_; ///< Var only: the binder this Var refers to (*not* an official op).
719 mutable World* world_;
720 };
724
725private:
726 Node node_; // 8
727 bool mut_ : 1;
728 bool external_ : 1;
729 mutable bool annex_ : 1;
730 bool dirty_ : 1;
731 unsigned dep_ : 4;
732 u32 mark_ = 0;
733#ifndef NDEBUG
734 size_t curr_op_ = 0;
735#endif
736 u32 gid_;
737 u32 num_ops_;
738 size_t hash_;
739 Vars vars_; // Mutable: local vars; Immutable: free vars.
740 Muts muts_; // Immutable: local_muts; Mutable: users;
741 mutable u32 tid_ = 0;
742 mutable const Def* type_;
743
744 template<class D, size_t N>
745 friend class Sets;
746 friend class World;
747 friend void swap(World&, World&) noexcept;
748 friend std::ostream& operator<<(std::ostream&, const Def*);
749};
750
751/// A variable introduced by a binder (mutable).
752/// @note Var will keep its type_ field as `nullptr`.
753/// Instead, Def::type() and Var::type() will compute the type via Def::var_type().
754/// The reason is that the type could need a Def::zonk().
755/// But we don't want to have several Var%s that belong to the same binder.
756class Var : public Def, public Setters<Var> {
757private:
758 Var(Def* mut)
759 : Def(Node, mut) {}
760
761public:
762 using Setters<Var>::set;
763
764 /// The binder of this Var.
765 /// It is *not* an official Def::op but stored in Def::binder_, so it is out of the operand graph but still hashed.
766 Def* binder() const { return binder_; }
767 const Def* type() const { return binder()->var_type(); }
768
769 static constexpr auto Node = mim::Node::Var;
770 static constexpr size_t Num_Ops = 0;
771
772private:
773 const Def* rebuild_(World&, const Def*, Defs) const final;
774
775 friend class World;
776};
777
778class Univ : public Def, public Setters<Univ> {
779public:
780 using Setters<Univ>::set;
781 static constexpr auto Node = mim::Node::Univ;
782 static constexpr size_t Num_Ops = 0;
783
784private:
785 Univ(World& world)
786 : Def(&world, Node, nullptr, Defs{}, 0) {}
787
788 const Def* rebuild_(World&, const Def*, Defs) const final;
789
790 friend class World;
791};
792
793class UMax : public Def, public Setters<UMax> {
794public:
795 using Setters<UMax>::set;
796 static constexpr auto Node = mim::Node::UMax;
797 static constexpr size_t Num_Ops = std::dynamic_extent;
798
799 enum Sort { Univ, Kind, Type, Term };
800
801private:
802 UMax(World&, Defs ops);
803
804 const Def* rebuild_(World&, const Def*, Defs) const final;
805
806 friend class World;
807};
808
809class UInc : public Def, public Setters<UInc> {
810private:
811 UInc(const Def* op, level_t offset)
812 : Def(Node, op->type()->as<Univ>(), {op}, offset) {}
813
814public:
815 using Setters<UInc>::set;
816
817 /// @name ops
818 ///@{
819 const Def* op() const { return Def::op(0); }
820 level_t offset() const { return flags(); }
821 ///@}
822
823 static constexpr auto Node = mim::Node::UInc;
824 static constexpr size_t Num_Ops = 1;
825
826private:
827 const Def* rebuild_(World&, const Def*, Defs) const final;
828
829 friend class World;
830};
831
832class Type : public Def, public Setters<Type> {
833private:
834 Type(const Def* level)
835 : Def(Node, nullptr, {level}, 0) {}
836
837public:
838 using Setters<Type>::set;
839
840 /// @name ops
841 ///@{
842 const Def* level() const { return op(0); }
843 ///@}
844
845 static constexpr auto Node = mim::Node::Type;
846 static constexpr size_t Num_Ops = 1;
847
848private:
849 const Def* rebuild_(World&, const Def*, Defs) const final;
850
851 friend class World;
852};
853
854class Lit : public Def, public Setters<Lit> {
855private:
856 Lit(const Def* type, flags_t val)
857 : Def(Node, type, Defs{}, val) {}
858
859public:
860 using Setters<Lit>::set;
861
862 /// @name Get actual Constant
863 ///@{
864 template<class T = flags_t>
865 T get() const {
866 static_assert(sizeof(T) <= 8);
868 }
869 ///@}
870
871 using Def::as;
872 using Def::isa;
873
874 /// @name Casts
875 ///@{
876 /// @see @ref cast_lit
877 template<class T = nat_t>
878 static std::optional<T> isa(const Def* def) {
879 if (!def) return {};
880 if (auto lit = def->isa<Lit>()) return lit->get<T>();
881 return {};
882 }
883 template<class T = nat_t>
884 static T as(const Def* def) {
885 return def->as<Lit>()->get<T>();
886 }
887 /// Like Lit::as but throws a formatted mim::error instead of merely asserting in `Debug`; see Def::expect.
888 template<class T = nat_t, class... Args>
889 static T expect(const Def* def, std::format_string<Args...> fmt, Args&&... args) {
890 if (auto res = isa<T>(def)) return *res;
891 fe::throwf("expected {}, but got '{}'", std::format(fmt, std::forward<Args>(args)...), def);
892 }
893 ///@}
894
895 static constexpr auto Node = mim::Node::Lit;
896 static constexpr size_t Num_Ops = 0;
897
898private:
899 const Def* rebuild_(World&, const Def*, Defs) const final;
900
901 friend class World;
902};
903
904class Nat : public Def, public Setters<Nat> {
905public:
906 using Setters<Nat>::set;
907 static constexpr auto Node = mim::Node::Nat;
908 static constexpr size_t Num_Ops = 0;
909
910private:
911 Nat(World& world);
912
913 const Def* rebuild_(World&, const Def*, Defs) const final;
914
915 friend class World;
916};
917
918/// A built-in constant of type `Nat -> *`.
919class Idx : public Def, public Setters<Idx> {
920private:
921 Idx(const Def* type)
922 : Def(Node, type, Defs{}, 0) {}
923
924public:
925 using Setters<Idx>::set;
926 using Def::as;
927 using Def::isa;
928
929 /// @name isa
930 ///@{
931
932 /// Checks if @p def is a `Idx s` and returns `s` or `nullptr` otherwise.
933 static const Def* isa(const Def* def);
934 static const Def* as(const Def* def) {
935 auto res = isa(def);
936 assert(res);
937 return res;
938 }
939 static std::optional<nat_t> isa_lit(const Def* def);
940 static nat_t as_lit(const Def* def) {
941 auto res = isa_lit(def);
942 assert(res.has_value());
943 return *res;
944 }
945 ///@}
946
947 /// @name Convert between Idx::isa and bitwidth and vice versa
948 ///@{
949 // clang-format off
950 static constexpr nat_t bitwidth2size(nat_t n) { assert(n != 0); return n == 64 ? 0 : (1_n << n); }
951 static constexpr nat_t size2bitwidth(nat_t n) { return n == 0 ? 64 : std::bit_width(n - 1_n); }
952 // clang-format on
953 static std::optional<nat_t> size2bitwidth(const Def* size);
954
955 /// Yields the bit width of the `Idx` @p type or throws a formatted mim::error - instead of yielding
956 /// std::nullopt or dereferencing an unchecked std::optional - if @p type is not an `Idx` of statically known
957 /// size; see Def::expect.
958 template<class... Args>
959 static nat_t expect_bitwidth(const Def* type, std::format_string<Args...> fmt, Args&&... args) {
960 if (auto size = isa(type))
961 if (auto w = size2bitwidth(size)) return *w;
962 fe::throwf("expected {}, but got '{}'", std::format(fmt, std::forward<Args>(args)...), type);
963 }
964 ///@}
965
966 static constexpr auto Node = mim::Node::Idx;
967 static constexpr size_t Num_Ops = 0;
968
969private:
970 const Def* rebuild_(World&, const Def*, Defs) const final;
971
972 friend class World;
973};
974
975class Proxy : public Def, public Setters<Proxy> {
976private:
977 Proxy(const Def* type, flags_t tag, Defs ops)
978 : Def(Node, type, ops, tag) {}
979
980public:
981 using Setters<Proxy>::set;
982
983 /// @name Getters
984 ///@{
985 flags_t tag() const { return flags_; }
986 ///@}
987
988 template<flags_t Tag>
989 static const Proxy* isa(const Def* def) {
990 if (auto proxy = def->isa<Proxy>(); proxy && proxy->tag() == Tag) return proxy;
991 return nullptr;
992 }
993
994 static constexpr auto Node = mim::Node::Proxy;
995 static constexpr size_t Num_Ops = std::dynamic_extent;
996
997private:
998 const Def* rebuild_(World&, const Def*, Defs) const final;
999
1000 friend class World;
1001};
1002
1003/// @deprecated A global variable in the data segment.
1004/// A Global may be mutable or immutable.
1005/// @deprecated Will be removed.
1006class Global : public Def, public Setters<Global> {
1007private:
1008 Global(const Def* type, bool is_mutable)
1009 : Def(Node, type, 1, is_mutable) {}
1010
1011public:
1012 using Setters<Global>::set;
1013
1014 /// @name ops
1015 ///@{
1016 const Def* init() const { return op(0); }
1017 void set(const Def* init) { Def::set(0, init); }
1018 ///@}
1019
1020 /// @name type
1021 ///@{
1022 const App* type() const;
1023 const Def* alloced_type() const;
1024 ///@}
1025
1026 /// @name Getters
1027 ///@{
1028 bool is_mutable() const { return flags(); }
1029 ///@}
1030
1031 /// @name Rebuild
1032 ///@{
1033 Global* stub(const Def* type) { return stub_(world(), type)->set(dbg()); }
1034 ///@}
1035
1036 static constexpr auto Node = mim::Node::Global;
1037 static constexpr size_t Num_Ops = 1;
1038
1039private:
1040 const Def* rebuild_(World&, const Def*, Defs) const final;
1041 Global* stub_(World&, const Def*) final;
1042
1043 friend class World;
1044};
1045
1046} // namespace mim
1047
1048#ifndef DOXYGEN // clang-format off
1049/// Format any pointer to a `mim::Def` (or subclass) via its `operator<<`.
1050template<class T> requires std::derived_from<T, mim::Def> struct std::formatter< T*> : fe::ostream_formatter {};
1051template<class T> requires std::derived_from<T, mim::Def> struct std::formatter<const T*> : fe::ostream_formatter {};
1052template<> struct std::formatter<mim::Muts> : fe::ostream_formatter {};
1053template<> struct std::formatter<mim::Vars> : fe::ostream_formatter {};
1054#endif // clang-format on
Definition axm.h:9
Base class for all Defs.
Definition def.h:261
bool is_set() const
Yields true if empty or the last op is set.
Definition def.cpp:308
size_t num_deps() const noexcept
Definition def.h:356
const Def * zonk_mut() const
If mutable, zonk()s all ops and tries to immutabilize it; otherwise just zonk.
Definition check.cpp:23
const Def * set(Dbg d) const
Definition def.h:576
const Def * proj(nat_t a, nat_t i) const
Similar to World::extract while assuming an arity of a, but also works on Sigmas and Arrays.
Definition def.cpp:635
constexpr Node node() const noexcept
Definition def.h:286
Def * set(size_t i, const Def *)
Successively set from left to right.
Definition def.cpp:276
virtual const Def * check(size_t i, const Def *def)
Checks whether the ith operand can be set to def.
Definition def.h:629
T * as_mut() const
Asserts that this is a mutable, casts constness away and performs a static_cast to T.
Definition def.h:536
const Var * has_var() const
As above if this is a mutable.
Definition def.h:447
void dump() const
Definition dump.cpp:549
void dirty(bool dirty=true) noexcept
Definition def.h:512
bool has_dep() const noexcept
Definition def.h:370
Defs deps() const noexcept
Definition def.cpp:514
auto projs() const
Definition def.h:425
u8 trip_
Definition def.h:723
bool is_elim() const noexcept
Definition def.h:297
nat_t num_tprojs() const
As above but yields 1, if Flags::scalarize_threshold is exceeded.
Definition def.cpp:630
virtual ~Def()=default
const Def * zonk() const
If Holes have been filled, reconstruct the program without them.
Definition check.cpp:21
World & world() const noexcept
Definition def.cpp:483
virtual const Def * check()
After all Def::ops have been Def::set, this method will be invoked to check the type of this mutable.
Definition def.h:634
const Def * refine(size_t i, const Def *new_op) const
Definition def.cpp:242
Def * set_type(const Def *)
Update type.
Definition def.cpp:293
std::string_view node_name() const
Definition def.cpp:504
auto projs(nat_t a, F f) const
Definition def.h:420
bool is_intro() const noexcept
Definition def.h:296
constexpr auto ops() const noexcept
Definition def.h:317
Vars local_vars() const
Vars reachable by following immutable deps().
Definition def.cpp:358
constexpr flags_t flags() const noexcept
Definition def.h:281
Dbg dbg_
Definition def.h:713
virtual Def * stub_(World &, const Def *)
Definition def.h:697
bool has_dep(Dep d) const noexcept
Definition def.h:371
const Def * set(std::string s) const
Definition def.h:570
Dep dep() const noexcept
Definition def.h:369
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
Definition def.h:527
constexpr u32 mark() const noexcept
Used internally by free_vars().
Definition def.h:284
constexpr u32 tid() const noexcept
Trie id - only used in Trie.
Definition def.h:283
auto projs(nat_t a) const
Definition def.h:431
u8 curry_
Definition def.h:722
auto tprojs() const
Definition def.h:428
Judge judge() const noexcept
Definition def.cpp:521
void externalize()
Definition def.cpp:617
friend std::ostream & operator<<(std::ostream &, const Def *)
This will stream def as an operand.
Definition dump.cpp:520
bool is_term() const
Is this Def a term, i.e. is its type() a Type?
Definition def.cpp:531
const Def * debug_prefix(std::string) const
Definition def.cpp:543
const Def * op(size_t i) const noexcept
Definition def.h:320
void dot(std::ostream &os, DotConfig cfg={}) const
Definition dot.cpp:202
bool is_immutabilizable()
Definition def.cpp:186
virtual const Def * rebuild_(World &w, const Def *type, Defs ops) const =0
std::pair< D *, const Var * > isa_binder() const
Is this a mutable that introduces a Var?
Definition def.h:455
const Def * var(nat_t a, nat_t i) noexcept
Definition def.h:441
void transfer_external(Def *to)
Definition def.cpp:620
const Def * unfold_type() const
Yields the type of this Def and builds a new Type (UInc n) if necessary.
Definition def.cpp:496
const Def * proj(nat_t i) const
As above but takes Def::num_projs as arity.
Definition def.h:396
auto projs(F f) const
Splits this Def via Def::projections into an Array (if A == std::dynamic_extent) or std::array (other...
Definition def.h:402
bool is_open() const
Has free_vars()?
Definition def.cpp:436
constexpr size_t hash() const noexcept
Definition def.h:285
friend class World
Definition def.h:746
bool is_dirty() const noexcept
Definition def.h:511
T * expect_mut(std::format_string< Args... > fmt, Args &&... args) const
Like Def::as_mut but - instead of merely asserting in Debug builds - throws via fe::throwf when the c...
Definition def.h:548
virtual const Def * immutabilize()
Tries to make an immutable from a mutable.
Definition def.h:607
bool is_form() const noexcept
Definition def.h:295
Def * set(Dbg d)
Definition def.h:577
Muts local_muts() const
Mutables reachable by following immutable deps(); mut->local_muts() is by definition the set { mut }...
Definition def.cpp:342
Def * set(Sym s)
Definition def.h:569
const Def * debug_suffix(std::string) const
Definition def.cpp:544
const Def * set(Sym s) const
Definition def.h:568
Def * set(Loc l)
Definition def.h:567
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.cpp:491
Def * outermost_binder() const
Transitively walks up free_vars() till the outermoust binder has been found.
Definition def.cpp:441
bool nests(Def *mut)
Does this nest mut?
Definition def.cpp:456
const Def * dep(size_t i) const noexcept
Definition def.h:355
bool is_mutable() const noexcept
Definition def.h:518
bool is_external() const noexcept
Definition def.h:500
const Def * rebuild(World &w, const Def *type, Defs ops) const
Def::rebuilds this Def while using new_op as substitute for its i'th Def::op.
Definition def.h:599
void internalize()
Definition def.cpp:618
const Def * set(Loc l, Sym s) const
Definition def.h:572
static bool less(const Def *a, const Def *b)
Definition def.cpp:593
Def * set(std::string s)
Definition def.h:571
bool is_meta() const noexcept
Definition def.h:298
static bool greater(const Def *a, const Def *b)
Definition def.cpp:594
void dot(const std::string &file, DotConfig cfg={}) const
Definition def.h:683
const Def * set(Loc l) const
Definition def.h:566
Loc loc() const
Definition def.h:557
void write(int max) const
Definition dump.cpp:557
auto tprojs(F f) const
Definition def.h:415
Def * set(Loc l, std::string s)
Definition def.h:575
friend class Sets
Definition def.h:745
const T * as_imm() const
Definition def.h:522
Def * stub(const Def *type)
Definition def.h:596
static Cmp cmp(const Def *a, const Def *b)
Definition def.cpp:551
virtual constexpr size_t reduction_offset() const noexcept
First Def::op that needs to be dealt with during reduction; e.g.
Definition def.h:620
Sym sym() const
Definition def.h:558
nat_t num_projs() const
Yields Def::arity(), if it is a Lit, or 1 otherwise.
Definition def.cpp:628
std::ostream & stream(std::ostream &, int max) const
Definition dump.cpp:529
flags_t flags_
Definition def.h:721
friend void swap(World &, World &) noexcept
const Def * var_type()
If this is a binder, compute the type of its Variable.
Definition def.cpp:325
constexpr u32 gid() const noexcept
Global id - unique number for this Def.
Definition def.h:282
virtual const Def * arity() const
Number of elements available to Extract / Insert (may be dynamic).
Definition def.cpp:597
Def * unset()
Unsets all Def::ops; works even, if not set at all or only partially set.
Definition def.cpp:299
std::string unique_name() const
name + "_" + Def::gid
Definition def.cpp:626
constexpr auto reduce(const Def *arg) const
Definition def.h:614
const Def * set(Loc l, std::string s) const
Definition def.h:574
const T * isa_imm() const
Definition def.h:521
bool needs_zonk() const
Yields true, if Def::local_muts() contain a Hole that is set.
Definition check.cpp:12
Muts users()
Set of mutables where this mutable is locally referenced.
Definition def.h:482
bool is_closed() const
Has no free_vars()?
Definition def.cpp:428
const Def * rebuild(const Def *type, Defs ops) const
Definition def.h:603
Vars free_vars() const
Global set of free Vars: extends local_vars() by transitively following mutables as well.
Definition def.cpp:347
Def * set(Loc l, Sym s)
Definition def.h:573
Dbg dbg() const
Definition def.h:556
Def * stub(World &w, const Def *type)
Definition def.h:595
const Def * tproj(nat_t i) const
As above but takes Def::num_tprojs.
Definition def.h:397
const Var * has_var()
Only returns not nullptr, if Var of this mutable has ever been created.
Definition def.h:445
bool is_annex() const noexcept
Definition def.h:504
constexpr size_t num_ops() const noexcept
Definition def.h:321
@ E
Equal.
Definition def.h:669
@ U
Unknown.
Definition def.h:670
@ L
Less.
Definition def.h:667
@ G
Greater.
Definition def.h:668
const Def * init() const
Definition def.h:1016
void set(const Def *init)
Definition def.h:1017
Global * stub(const Def *type)
Definition def.h:1033
const Def * alloced_type() const
Definition def.cpp:683
friend class World
Definition def.h:1043
bool is_mutable() const
Definition def.h:1028
const App * type() const
Definition def.cpp:682
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:120
static constexpr size_t Num_Ops
Definition def.h:1037
Global * stub_(World &, const Def *) final
Definition def.cpp:161
static constexpr auto Node
Definition def.h:1036
This node is a hole in the IR that is inferred by its context later on.
Definition check.h:16
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:121
static constexpr auto Node
Definition def.h:966
static nat_t as_lit(const Def *def)
Definition def.h:940
static constexpr nat_t size2bitwidth(nat_t n)
Definition def.h:951
static constexpr nat_t bitwidth2size(nat_t n)
Definition def.h:950
static const Def * isa(const Def *def)
Checks if def is a Idx s and returns s or nullptr otherwise.
Definition def.cpp:658
friend class World
Definition def.h:972
static nat_t expect_bitwidth(const Def *type, std::format_string< Args... > fmt, Args &&... args)
Yields the bit width of the Idx type or throws a formatted mim::error - instead of yielding std::null...
Definition def.h:959
static std::optional< nat_t > isa_lit(const Def *def)
Definition def.cpp:666
static constexpr size_t Num_Ops
Definition def.h:967
static const Def * as(const Def *def)
Definition def.h:934
static constexpr auto Node
Definition def.h:895
static std::optional< T > isa(const Def *def)
Definition def.h:878
friend class World
Definition def.h:901
T get() const
Definition def.h:865
static T as(const Def *def)
Definition def.h:884
static constexpr size_t Num_Ops
Definition def.h:896
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:130
static T expect(const Def *def, std::format_string< Args... > fmt, Args &&... args)
Like Lit::as but throws a formatted mim::error instead of merely asserting in Debug; see Def::expect.
Definition def.h:889
friend class World
Definition def.h:915
static constexpr auto Node
Definition def.h:907
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:122
static constexpr size_t Num_Ops
Definition def.h:908
static constexpr size_t Num_Ops
Definition def.h:995
flags_t tag() const
Definition def.h:985
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:134
friend class World
Definition def.h:1000
static constexpr auto Node
Definition def.h:994
static const Proxy * isa(const Def *def)
Definition def.h:989
CRTP-based mixin to declare setters for Def::loc & Def::name using a covariant return type.
Definition def.h:193
P * set(Loc l, Sym s)
Definition def.h:207
P * set(std::string s)
Definition def.h:205
const P * set(Sym s) const
Definition def.h:202
const P * set(Loc l, Sym s) const
Definition def.h:206
const P * set(Loc l) const
Definition def.h:200
P * set(Loc l)
Definition def.h:201
const P * set(Dbg d) const
Definition def.h:210
const P * set(Loc l, std::string s) const
Definition def.h:208
P * set(Sym s)
Definition def.h:203
P * set(Dbg d)
Definition def.h:211
P * set(Loc l, std::string s)
Definition def.h:209
const P * set(std::string s) const
Definition def.h:204
friend class World
Definition def.h:851
static constexpr size_t Num_Ops
Definition def.h:846
static constexpr auto Node
Definition def.h:845
const Def * level() const
Definition def.h:842
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:141
const Def * op() const
Definition def.h:819
static constexpr auto Node
Definition def.h:823
friend class World
Definition def.h:829
level_t offset() const
Definition def.h:820
static constexpr size_t Num_Ops
Definition def.h:824
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:142
@ Type
Definition def.h:799
@ Univ
Definition def.h:799
@ Term
Definition def.h:799
@ Kind
Definition def.h:799
static constexpr auto Node
Definition def.h:796
friend class World
Definition def.h:806
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:143
static constexpr size_t Num_Ops
Definition def.h:797
static constexpr size_t Num_Ops
Definition def.h:782
static constexpr auto Node
Definition def.h:781
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:123
friend class World
Definition def.h:790
A variable introduced by a binder (mutable).
Definition def.h:756
const Def * type() const
Definition def.h:767
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:145
static constexpr auto Node
Definition def.h:769
friend class World
Definition def.h:775
Def * binder() const
The binder of this Var.
Definition def.h:766
static constexpr size_t Num_Ops
Definition def.h:770
This is a thin wrapper for absl::InlinedVector<T, N, A> which is a drop-in replacement for std::vecto...
Definition vector.h:18
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:36
#define MIM_NODE(X)
Definition def.h:20
#define MIM_PROJ(NAME, CONST)
Use as mixin to wrap all kind of Def::proj and Def::projs variants.
Definition def.h:162
Definition ast.h:14
View< const Def * > Defs
Definition def.h:78
u64 nat_t
Definition types.h:37
DefMap< const Def * > Def2Def
Definition def.h:77
Vector< const Def * > DefVec
Definition def.h:79
Dep
Tracks whether a Def transitively depends - through its Def::deps() but only up to (and excluding) th...
Definition def.h:120
@ None
Depends on nothing of interest.
Definition def.h:121
bool follow_types
Follow Def::type() dependencies.
Definition def.h:220
u64 flags_t
Definition types.h:39
bool inline_consts
Wire up literals, axioms, etc. with normal edges instead of detaching them.
Definition def.h:221
u8 node_t
Definition types.h:38
int max
Maximum recursion depth.
Definition def.h:218
Span< const T, N > View
Definition span.h:102
absl::flat_hash_map< K, V, GIDHash< K > > GIDMap
Definition util.h:168
GIDSet< const Var * > VarSet
Definition def.h:97
GIDMap< const Var *, To > VarMap
Definition def.h:96
bool all_annexes
Include all annexes - even if unused (World::dot only).
Definition def.h:219
Sets< Def >::Set Muts
Definition def.h:89
u64 level_t
Definition types.h:36
GIDMap< const Def *, To > DefMap
Definition def.h:75
GIDSet< Def * > MutSet
Definition def.h:87
bool show_hidden
Render otherwise-transparent detached edges (Var→binder back-edges, shared literals/axioms,...
Definition def.h:223
MutMap< Def * > Mut2Mut
Definition def.h:88
GIDSet< const Def * > DefSet
Definition def.h:76
static constexpr size_t Num_Nodes
Definition def.h:114
const Def *(*)(const Def *, const Def *, const Def *) NormalizeFn
Definition def.h:102
Sets< const Var >::Set Vars
Definition def.h:99
uint32_t u32
Definition types.h:27
Mut
Classifies whether a Node may occur as a mutable, an immutable, or both.
Definition def.h:141
@ Imm
Node may be immutable.
Definition def.h:144
Judge
Judgement.
Definition def.h:129
@ Intro
Term Introduction like λ(x: Nat): Nat = x.
Definition def.h:132
@ Meta
Meta rules for Universe and Type levels.
Definition def.h:134
@ Form
Type Formation like T -> T.
Definition def.h:131
@ Elim
Term Elimination like f a.
Definition def.h:133
bool default_filter
Show Lam::filter() even if it has its default value.
Definition def.h:222
absl::flat_hash_set< K, GIDHash< K > > GIDSet
Definition util.h:169
uint8_t u8
Definition types.h:27
constexpr D bitcast_resize(const S &src) noexcept
A bitcast from src of type S to D, supporting different sizes.
Definition util.h:31
Node
Definition def.h:107
@ Nat
Definition def.h:109
@ Univ
Definition def.h:109
@ Idx
Definition def.h:109
@ UInc
Definition def.h:109
@ Global
Definition def.h:109
@ Var
Definition def.h:109
@ Axm
Definition def.h:109
@ Type
Definition def.h:109
@ App
Definition def.h:109
@ Lit
Definition def.h:109
@ Proxy
Definition def.h:109
@ UMax
Definition def.h:109
Vector(I, I, A=A()) -> Vector< typename std::iterator_traits< I >::value_type, Default_Inlined_Size< typename std::iterator_traits< I >::value_type >, A >
GIDMap< Def *, To > MutMap
Definition def.h:86
VarMap< const Var * > Var2Var
Definition def.h:98
Options for Def::dot and World::dot.
Definition def.h:217
Definition span.h:126
#define CODE(name,...)
Definition tok.h:39