MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
check.h
Go to the documentation of this file.
1#pragma once
2
3#include "mim/def.h"
4
5namespace mim {
6
7class Prod;
8class Seq;
9
10/// This node is a hole in the IR that is inferred by its context later on.
11/// It is modelled as a *mutable* Def.
12/// If inference was successful, it's Hole::op will be set to the inferred Def.
13/// @note Hole%s are not type-checked as they are used during type-checking - causing a chicken-and-egg problem.
14class Hole : public Def, public Setters<Hole> {
15private:
16 Hole(const Def* type)
17 : Def(Node, type, 1, 0) {}
18
19public:
20 using Setters<Hole>::set;
21
22 /// @name op
23 ///@{
24 const Def* op() const { return Def::op(0); }
25
26 /// Transitively walks up Hole%s until the last one while path-compressing everything.
27 /// @returns the final Hole in the chain and final op() (if any).
28 std::pair<Hole*, const Def*> find();
29 ///@}
30
31 /// @name set/unset
32 ///@{
33 Hole* set(const Def* op) {
34 assert(op != this);
35 return Def::set(0, op)->as<Hole>();
36 }
37 Hole* unset() { return Def::unset()->as<Hole>(); }
38 ///@}
39
40 Hole* stub(const Def* type) { return stub_(world(), type)->set(dbg()); }
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 const Def* rebuild_(World&, const Def*, Defs) const final;
73 Hole* stub_(World&, const Def*) final;
74
75 friend class World;
76 friend class Checker;
77};
78
79class Checker {
80public:
81 explicit Checker(World& world)
82 : world_(world) {}
83
84 World& world() { return world_; }
85
86 enum Mode {
87 /// In Mode::Check, type inference is happening and Hole%s will be resolved, if possible.
88 /// Also, two *free* but *different* Var%s **are** considered α-equivalent.
90 /// In Mode::Test, no type inference is happening and Hole%s will not be touched.
91 /// Also, Two *free* but *different* Var%s are **not** considered α-equivalent.
93 };
94
95 template<Mode mode>
96 static bool alpha(const Def* d1, const Def* d2) {
97 if (d1 == d2) return true;
98 return Checker(d1->world()).alpha_<mode>(d1, d2);
99 }
100
101 /// Can @p value be assigned to sth of @p type?
102 /// @note This is different from `equiv(type, value->type())` since @p type may be dependent.
103 [[nodiscard]] static const Def* assignable(const Def* type, const Def* value) {
104 if (type == value->type()) return value;
105 return Checker(type->world()).assignable_(type, value);
106 }
107
108 /// Yields `defs.front()`, if all @p defs are Check::alpha-equivalent (`Mode::Test`) and `nullptr` otherwise.
109 static const Def* is_uniform(Defs defs);
110
111private:
112#ifdef MIM_ENABLE_CHECKS
113 template<Mode>
114 bool fail();
115 const Def* fail();
116#else
117 template<Mode>
118 bool fail() {
119 return false;
120 }
121 const Def* fail() { return {}; }
122#endif
123
124 [[nodiscard]] const Def* assignable_(const Def* type, const Def* value);
125 template<Mode>
126 [[nodiscard]] bool alpha_(const Def* d1, const Def* d2);
127 template<Mode>
128 [[nodiscard]] bool check(const Prod*, const Def*);
129 template<Mode>
130 [[nodiscard]] bool check(const Seq*, const Def*);
131 [[nodiscard]] bool check1(const Seq*, const Def*);
132 [[nodiscard]] bool check(Seq*, const Seq*);
133 [[nodiscard]] bool check(const UMax*, const Def*);
134
135 auto bind(Def* mut, const Def* d) { return mut ? binders_.emplace(mut, d) : std::pair(binders_.end(), true); }
136 World& world_;
137 MutMap<const Def*> binders_;
138 fe::Arena arena_;
139};
140
141} // 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:161
static bool alpha(const Def *d1, const Def *d2)
Definition check.h:96
Checker(World &world)
Definition check.h:81
World & world()
Definition check.h:84
@ Test
In Mode::Test, no type inference is happening and Holes will not be touched.
Definition check.h:92
@ Check
In Mode::Check, type inference is happening and Holes will be resolved, if possible.
Definition check.h:89
static const Def * assignable(const Def *type, const Def *value)
Can value be assigned to sth of type?
Definition check.h:103
Base class for all Defs.
Definition def.h:216
bool is_set() const
Yields true if empty or the last op is set.
Definition def.cpp:276
Def * set(size_t i, const Def *)
Successively set from left to right.
Definition def.cpp:244
World & world() const noexcept
Definition def.cpp:413
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
Definition def.h:445
const Def * op(size_t i) const noexcept
Definition def.h:273
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.h:260
Def * unset()
Unsets all Def::ops; works even, if not set at all or partially.
Definition def.cpp:267
Dbg dbg() const
Definition def.h:465
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:96
const Def * op() const
Definition check.h:24
Hole * set(const Def *op)
Definition check.h:33
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 Checker
Definition check.h:76
const Def * tuplefy(nat_t)
If unset, explode to Tuple.
Definition check.cpp:121
static constexpr auto Node
Definition check.h:68
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:109
friend class World
Definition check.h:75
static Hole * isa_unset(const Def *def)
Definition check.h:53
Hole * stub(const Def *type)
Definition check.h:40
Hole * unset()
Definition check.h:37
Hole * stub_(World &, const Def *) final
Definition def.cpp:150
static const Def * isa_set(const Def *def)
Definition check.h:48
Base class for Sigma and Tuple.
Definition tuple.h:10
Base class for Arr and Pack.
Definition tuple.h:84
CRTP-based Mixin to declare setters for Def::loc & Def::name using a covariant return type.
Definition def.h:161
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:34
Definition ast.h:14
View< const Def * > Defs
Definition def.h:51
u64 nat_t
Definition types.h:43
@ Hole
Definition def.h:89
@ UMax
Definition def.h:89
GIDMap< Def *, To > MutMap
Definition def.h:59