MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
check.h
Go to the documentation of this file.
1#pragma once
2
3#include <ankerl/unordered_dense.h>
4
5#include "mim/def.h"
6
7namespace mim {
8
9class Prod;
10class Seq;
11
12/// This node is a hole in the IR that is inferred by its context later on.
13/// It is modelled as a *mutable* Def.
14/// If inference was successful, it's Hole::op will be set to the inferred Def.
15/// @note Hole%s are not type-checked as they are used during type-checking - causing a chicken-and-egg problem.
16class Hole : public Def, public Setters<Hole> {
17private:
18 Hole(const Def* type)
19 : Def(Node, type, 1, 0) {}
20
21public:
22 using Setters<Hole>::set;
23
24 /// @name op
25 ///@{
26 const Def* op() const { return Def::op(0); }
27
28 /// Transitively walks up Hole%s until the last one while path-compressing everything.
29 /// @returns the final Hole in the chain and final op() (if any).
30 std::pair<Hole*, const Def*> find();
31 ///@}
32
33 /// @name set/unset
34 ///@{
35 Hole* set(const Def* op) {
36 assert(op != this);
37 return Def::set({op})->as<Hole>();
38 }
39 Hole* unset() { return Def::unset()->as<Hole>(); }
40 ///@}
41
42 /// If unset, explode to Tuple.
43 /// @returns the new Tuple, or `this` if unsuccessful.
44 const Def* tuplefy(nat_t);
45
46 /// @name isa
47 ///@{
48 static const Def* isa_set(const Def* def) {
49 if (auto hole = def->isa<Hole>(); hole && hole->is_set()) return hole->op();
50 return nullptr;
51 }
52
53 static Hole* isa_unset(const Def* def) {
54 if (auto hole = def->isa_mut<Hole>(); hole && !hole->is_set()) return hole;
55 return nullptr;
56 }
57
58 /// If @p def is a Hole, find last in chain, otherwise yields @p def again.
59 static const Def* find(const Def* def) {
60 if (auto hole = def->isa_mut<Hole>()) {
61 auto [last, op] = hole->find();
62 return op ? op : last;
63 }
64 return def;
65 }
66 ///@}
67
68 static constexpr auto Node = mim::Node::Hole;
69 static constexpr size_t Num_Ops = 1;
70
71private:
72 friend class World;
73 friend class Check;
74};
75
76class Check {
77public:
78 explicit Check(World& world)
79 : world_(world) {}
80
81 World& world() { return world_; }
82
83 enum Mode {
84 /// In Mode::Check, type inference is happening and Hole%s will be resolved, if possible.
85 /// Also, two *free* but *different* Var%s **are** considered α-equivalent.
87 /// In Mode::Test, no type inference is happening and Hole%s will not be touched.
88 /// Also, Two *free* but *different* Var%s are **not** considered α-equivalent.
90 };
91
92 template<Mode mode = C>
93 static bool alpha(const Def* d1, const Def* d2) {
94 if (d1 == d2) return true;
95 auto checker = Check(d1->world());
96 if (!checker.alpha_<mode>(d1, d2)) return false;
97 checker.commit();
98 return true;
99 }
100
101 static bool test_alpha(const Def* d1, const Def* d2) { return alpha<T>(d1, d2); }
102
103 /// Can @p value be assigned to sth of @p type?
104 /// @note This is different from `equiv(type, value->type())` since @p type may be dependent.
105 [[nodiscard]] static const Def* coerce(const Def* type, const Def* value) {
106 if (type == value->type()) return value;
107 auto checker = Check(type->world());
108 auto res = checker.coerce_(type, value);
109 if (res) checker.commit();
110 return res;
111 }
112
113 /// Yields `defs.front()`, if all @p defs are Check::alpha-equivalent (`Mode::Test`) and `nullptr` otherwise.
114 static const Def* is_uniform(Defs defs);
115
116private:
117#ifdef MIM_ENABLE_CHECKS
118 template<Mode>
119 bool fail();
120 const Def* fail();
121#else
122 template<Mode>
123 bool fail() {
124 return false;
125 }
126 const Def* fail() { return {}; }
127#endif
128
129 [[nodiscard]] const Def* coerce_(const Def* type, const Def* value);
130 template<Mode>
131 [[nodiscard]] bool alpha_(const Def* d1, const Def* d2);
132 template<Mode>
133 [[nodiscard]] bool alpha_impl_(const Def* d1, const Def* d2);
134
135 /// Fast path for alpha_ that needs neither binders_ nor memo_ and hence doesn't allocate.
136 /// @returns `std::nullopt`, if the full alpha_impl_ machinery is needed.
137 template<Mode>
138 [[nodiscard]] std::optional<bool> try_alpha_(const Def* d1, const Def* d2);
139
140 template<Mode>
141 [[nodiscard]] bool check(const Prod*, const Def*);
142 template<Mode>
143 [[nodiscard]] bool check(const Seq*, const Seq*);
144 [[nodiscard]] bool check(Hole*, const Def*);
145 [[nodiscard]] bool check_rank(const Seq*, Hole* rank, const Def*);
146 [[nodiscard]] bool check1(const Seq*, const Def*);
147 [[nodiscard]] bool check(Seq*, const Seq*);
148 [[nodiscard]] bool check(const LMax*, const Def*);
149 [[nodiscard]] bool check(const LSucc*, const Def*);
150 void commit(); ///< Hands deferred_ over to World::postpone once the whole check has succeeded.
151
152 /// Symmetric key for the alpha_ memo: the two gids packed into one u64, smaller first.
153 /// Canonicalizing by gid is what lets alpha_ get away with a single probe.
154 static constexpr u64 memo_key(const Def* d1, const Def* d2) noexcept {
155 auto g1 = u64(d1->gid()), g2 = u64(d2->gid());
156 return g1 < g2 ? g1 << 32 | g2 : g2 << 32 | g1;
157 }
158
159 using Binders = MutMap<const Def*>;
160 std::pair<Binders::iterator, bool> bind(Def* mut, const Def* d);
161
162 World& world_;
163 Binders binders_;
164 Vars bound_; ///< Var%s of all binders_; these are the Var%s subject to renaming.
165 std::array<ankerl::unordered_dense::set<u64>, 2> memo_;
166 fe::Vector<std::pair<const LMax*, const Def*>> deferred_;
167};
168
169} // namespace mim
static const Def * is_uniform(Defs defs)
Yields defs.front(), if all defs are Check::alpha-equivalent (Mode::Test) and nullptr otherwise.
Definition check.cpp:120
World & world()
Definition check.h:81
Check(World &world)
Definition check.h:78
static const Def * coerce(const Def *type, const Def *value)
Can value be assigned to sth of type?
Definition check.h:105
static bool test_alpha(const Def *d1, const Def *d2)
Definition check.h:101
@ C
In Mode::Check, type inference is happening and Holes will be resolved, if possible.
Definition check.h:86
@ T
In Mode::Test, no type inference is happening and Holes will not be touched.
Definition check.h:89
static bool alpha(const Def *d1, const Def *d2)
Definition check.h:93
Base class for all Defs.
Definition def.h:289
bool is_set() const
Definition def.h:396
Def * set(size_t i, const Def *)
Successively set from left to right.
Definition def.cpp:188
World & world() const noexcept
Definition def.h:1105
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
Definition def.h:588
const Def * op(size_t i) const noexcept
Definition def.h:377
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.h:1119
Def * unset()
Unsets all Def::ops; works even, if not set at all or only partially set.
Definition def.cpp:205
static constexpr size_t Num_Ops
Definition check.h:69
std::pair< Hole *, const Def * > find()
Transitively walks up Holes until the last one while path-compressing everything.
Definition check.cpp:58
const Def * op() const
Definition check.h:26
Hole * set(const Def *op)
Definition check.h:35
static const Def * find(const Def *def)
If def is a Hole, find last in chain, otherwise yields def again.
Definition check.h:59
friend class Check
Definition check.h:73
const Def * tuplefy(nat_t)
If unset, explode to Tuple.
Definition check.cpp:81
static constexpr auto Node
Definition check.h:68
friend class World
Definition check.h:72
static Hole * isa_unset(const Def *def)
Definition check.h:53
Hole * unset()
Definition check.h:39
static const Def * isa_set(const Def *def)
Definition check.h:48
Base class for Sigma and Tuple.
Definition tuple.h:13
Base class for Arr and Pack.
Definition tuple.h:267
CRTP-based mixin to declare setters for Def::loc & Def::name using a covariant return type.
Definition def.h:220
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:43
Definition ast.h:16
u64 nat_t
Definition types.h:37
fe::View< const Def * > Defs
Definition def.h:96
fe::Patricia< const Var, DefKey >::Set Vars
Definition def.h:115
uint64_t u64
Definition types.h:27
@ Hole
Definition def.h:125