MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
tuple.h
Go to the documentation of this file.
1#pragma once
2
3#include <span>
4
5#include "mim/def.h"
6
7namespace mim {
8
9/// Base class for Sigma and Tuple.
10class Prod : public Def, public Setters<Prod> {
11protected:
12 using Def::Def;
13
14public:
15 ~Prod() override;
16
17 static constexpr size_t Num_Ops = std::dynamic_extent;
18};
19
20/// A [dependent tuple type](https://en.wikipedia.org/wiki/Dependent_type#%CE%A3_type).
21/// @see Tuple, Arr, Pack, Prod
22class Sigma : public Prod, public Setters<Sigma> {
23private:
24 Sigma(const Def* type, Defs ops)
25 : Prod(Node, type, ops, 0) {} ///< Constructor for an *immutable* Sigma.
26 Sigma(const Def* type, size_t size)
27 : Prod(Node, type, size, 0) {} ///< Constructor for a *mutable* Sigma.
28
29public:
30 /// @name Setters
31 /// @see @ref set_ops "Setting Ops"
32 ///@{
33 using Setters<Sigma>::set;
34 Sigma* set(size_t i, const Def* def) { return Def::set(i, def)->as<Sigma>(); }
35 Sigma* set(Defs ops) { return Def::set(ops)->as<Sigma>(); }
36 Sigma* unset() { return Def::unset()->as<Sigma>(); }
37 ///@}
38
39 /// @name Rebuild
40 ///@{
41 const Def* immutabilize() final;
42 Sigma* stub(const Def* type) { return stub_(world(), type)->set(dbg()); }
43
44 /// @note Technically, it would make sense to have an offset of 1 as the first element can't be reduced.
45 /// For example, in `[n: Nat, F n]` `n` only occurs free in the second element.
46 /// However, this would cause a lot of confusion and special code to cope with the first element,
47 /// So we just keep it.
48 constexpr size_t reduction_offset() const noexcept final { return 0; }
49 ///@}
50
51 /// @name Type Checking
52 ///@{
53 const Def* check(size_t, const Def*) final;
54 const Def* check() final;
55 static const Def* infer(World&, Defs);
56 const Def* arity() const final;
57 ///@}
58
59 static constexpr auto Node = mim::Node::Sigma;
60
61private:
62 const Def* rebuild_(World&, const Def*, Defs) const final;
63 Sigma* stub_(World&, const Def*) final;
64
65 friend class World;
66};
67
68/// Data constructor for a Sigma.
69/// @see Sigma, Arr, Pack, Prod
70class Tuple : public Prod, public Setters<Tuple> {
71public:
72 using Setters<Tuple>::set;
73 static const Def* infer(World&, Defs);
74 static constexpr auto Node = mim::Node::Tuple;
75
76private:
77 Tuple(const Def* type, Defs args)
78 : Prod(Node, type, args, 0) {}
79
80 const Def* rebuild_(World&, const Def*, Defs) const final;
81
82 friend class World;
83};
84
85/// Base class for Arr and Pack.
86class Seq : public Def, public Setters<Seq> {
87protected:
88 using Def::Def;
89
90public:
91 ~Seq() override;
92
93 /// @name ops
94 ///@{
95 const Def* body() const { return ops().back(); }
96 ///@}
97
98 /// @name Setters
99 /// @see @ref set_ops "Setting Ops"
100 ///@{
101 using Setters<Seq>::set;
102
103 /// Common setter for Pack%s and Arr%ays.
104 /// @p arity will be ignored, if it's a Pack.
105 Seq* set(const Def* arity, const Def* body) {
106 return (node() == Node::Arr ? Def::set({arity, body}) : Def::set({body}))->as<Seq>();
107 }
108 Seq* unset() { return Def::unset()->as<Seq>(); }
109 ///@}
110
111 /// @name Rebuild
112 ///@{
113 Seq* stub(World& w, const Def* type) { return Def::stub(w, type)->as<Seq>(); }
114 virtual const Def* reduce(const Def* arg) const = 0;
115 ///@}
116};
117
118/// A (possibly paramterized) Arr%ay.
119/// Arr%ays are usually homogenous but they can be *inhomogenous* as well: `«i: N; T#i»`
120/// @see Sigma, Tuple, Pack
121class Arr : public Seq, public Setters<Arr> {
122private:
123 Arr(const Def* type, const Def* arity, const Def* body)
124 : Seq(Node, type, {arity, body}, 0) {} ///< Constructor for an *immutable* Arr.
125 Arr(const Def* type)
126 : Seq(Node, type, 2, 0) {} ///< Constructor for a *mutable* Arr.
127
128public:
129 /// @name ops
130 ///@{
131 const Def* arity() const final { return op(0); }
132 ///@}
133
134 /// @name Setters
135 /// @see @ref set_ops "Setting Ops"
136 ///@{
137 using Setters<Arr>::set;
138 Arr* set_arity(const Def* arity) { return Def::set(0, arity)->as<Arr>(); }
139 Arr* set_body(const Def* body) { return Def::set(1, body)->as<Arr>(); }
140 Arr* set(const Def* arity, const Def* body) { return set_arity(arity)->set_body(body); }
141 Arr* unset() { return Def::unset()->as<Arr>(); }
142 ///@}
143
144 /// @name Rebuild
145 ///@{
146 Arr* stub(const Def* type) { return stub_(world(), type)->set(dbg()); }
147 const Def* immutabilize() final;
148 const Def* reduce(const Def* arg) const final { return Def::reduce(arg).front(); }
149 constexpr size_t reduction_offset() const noexcept final { return 1; }
150 ///@}
151
152 /// @name Type Checking
153 ///@{
154 const Def* check(size_t, const Def*) final;
155 const Def* check() final;
156 ///@}
157
158 static constexpr auto Node = mim::Node::Arr;
159 static constexpr size_t Num_Ops = 2;
160
161private:
162 const Def* rebuild_(World&, const Def*, Defs) const final;
163 Arr* stub_(World&, const Def*) final;
164
165 friend class World;
166};
167
168/// A (possibly paramterized) Tuple.
169/// @see Sigma, Tuple, Arr
170class Pack : public Seq, public Setters<Pack> {
171private:
172 Pack(const Def* type, const Def* body)
173 : Seq(Node, type, {body}, 0) {} ///< Constructor for an *immutable* Pack.
174 Pack(const Def* type)
175 : Seq(Node, type, 1, 0) {} ///< Constructor for a *mutable* Pack.
176
177public:
178 /// @name ops
179 ///@{
180 const Def* arity() const final;
181 ///@}
182
183 /// @name Setters
184 /// @see @ref set_ops "Setting Ops"
185 ///@{
186 using Setters<Pack>::set;
187 Pack* set(const Def* body) { return Def::set({body})->as<Pack>(); }
188 Pack* unset() { return Def::unset()->as<Pack>(); }
189 ///@}
190
191 /// @name Rebuild
192 ///@{
193 Pack* stub(const Def* type) { return stub_(world(), type)->set(dbg()); }
194 const Def* immutabilize() final;
195 const Def* reduce(const Def* arg) const final { return Def::reduce(arg).front(); }
196 constexpr size_t reduction_offset() const noexcept final { return 0; }
197 ///@}
198
199 static constexpr auto Node = mim::Node::Pack;
200 static constexpr size_t Num_Ops = 1;
201
202private:
203 const Def* rebuild_(World&, const Def*, Defs) const final;
204 Pack* stub_(World&, const Def*) final;
205
206 friend class World;
207};
208
209/// Extracts from a Sigma or Arr%ay-typed Extract::tuple the element at position Extract::index.
210class Extract : public Def, public Setters<Extract> {
211private:
212 Extract(const Def* type, const Def* tuple, const Def* index)
213 : Def(Node, type, {tuple, index}, 0) {}
214
215public:
216 using Setters<Extract>::set;
217
218 /// @name ops
219 ///@{
220 const Def* tuple() const { return op(0); }
221 const Def* index() const { return op(1); }
222 ///@}
223
224 static constexpr auto Node = mim::Node::Extract;
225 static constexpr size_t Num_Ops = 2;
226
227private:
228 const Def* rebuild_(World&, const Def*, Defs) const final;
229
230 friend class World;
231};
232
233/// Creates a new Tuple / Pack by inserting Insert::value at position Insert::index into Insert::tuple.
234/// @attention This is a *functional* Insert.
235/// The Insert::tuple itself remains untouched.
236/// The Insert itself is a *new* Tuple / Pack which contains the inserted Insert::value.
237class Insert : public Def, public Setters<Insert> {
238private:
239 Insert(const Def* tuple, const Def* index, const Def* value)
240 : Def(Node, tuple->type(), {tuple, index, value}, 0) {}
241
242public:
243 using Setters<Insert>::set;
244
245 /// @name ops
246 ///@{
247 const Def* tuple() const { return op(0); }
248 const Def* index() const { return op(1); }
249 const Def* value() const { return op(2); }
250 ///@}
251
252 static constexpr auto Node = mim::Node::Insert;
253 static constexpr size_t Num_Ops = 3;
254
255private:
256 const Def* rebuild_(World&, const Def*, Defs) const final;
257
258 friend class World;
259};
260
261/// Matches `(ff, tt)#cond` - where `cond` is **not** a Lit%eral.
262/// @note If `cond` is a Lit%eral, either
263/// * `(x, y)#lit` would have been folded to `x`/`y` anyway, or
264/// * we have something like this: `pair#0_2`
265class Select {
266public:
267 Select(const Def*);
268
269 explicit operator bool() const noexcept { return extract_; }
270
271 const Extract* extract() const { return extract_; }
272 const Def* pair() const { return extract()->tuple(); }
273 const Def* cond() const { return extract()->index(); }
274 const Def* tt() const { return pair()->proj(2, 1); }
275 const Def* ff() const { return pair()->proj(2, 0); }
276
277private:
278 const Extract* extract_ = nullptr;
279};
280
281/// Matches `(ff, tt)#cond arg` where `cond` is **not** a Lit%eral.
282/// `(ff, tt)#cond` is matched as a Select.
283class Branch : public Select {
284public:
285 Branch(const Def*);
286
287 explicit operator bool() const noexcept { return app_; }
288
289 const App* app() const { return app_; }
290 const Def* callee() const;
291 const Def* arg() const;
292
293private:
294 const App* app_ = nullptr;
295};
296
297/// Matches a dispatch through a jump table of the form:
298/// `(target_0, target_1, ...)#index arg` where `index` is **not** a Lit%eral.
299/// @note Subsumes Branch.
300/// If you want to deal with Branch separately, match Branch first:
301/// ```
302/// if (auto branch = Branch(def)) {
303/// // special case first
304/// } else if (auto dispatch = Dispatch(def)) {
305/// // now, the generic case
306/// }
307/// ```
308class Dispatch {
309public:
310 Dispatch(const Def*);
311
312 explicit operator bool() const noexcept { return app_; }
313
314 const App* app() const { return app_; }
315 const Def* callee() const;
316 const Def* arg() const;
317
318 const Extract* extract() const { return extract_; }
319 const Def* tuple() const { return extract()->tuple(); }
320 const Def* index() const { return extract()->index(); }
321
322 size_t num_targets() const { return Lit::as(extract()->tuple()->arity()); }
323 const Def* target(size_t i) const { return tuple()->proj(i); }
324
325private:
326 const App* app_ = nullptr;
327 const Extract* extract_ = nullptr;
328};
329
330/// @name Helpers to work with Tuples/Sigmas/Arrays/Packs
331///@{
332bool is_unit(const Def*);
333std::string tuple2str(const Def*);
334
335const Def* tuple_of_types(const Def* t);
336///@}
337
338/// @name Concatenation
339/// Works for Tuple%s, Pack%s, Sigma%s, and Arr%ays alike.
340///@{
341DefVec cat(Defs, Defs);
342inline DefVec cat(const Def* a, Defs bs) { return cat(Defs{a}, bs); }
343inline DefVec cat(Defs as, const Def* b) { return cat(as, Defs{b}); }
344
345DefVec cat(nat_t n, nat_t m, const Def* a, const Def* b);
346
347const Def* cat_tuple(nat_t n, nat_t m, const Def* a, const Def* b);
348const Def* cat_sigma(nat_t n, nat_t m, const Def* a, const Def* b);
349
350const Def* cat_tuple(World&, Defs, Defs);
351const Def* cat_sigma(World&, Defs, Defs);
352
353inline const Def* cat_tuple(const Def* a, Defs bs) { return cat_tuple(a->world(), Defs{a}, bs); }
354inline const Def* cat_tuple(Defs as, const Def* b) { return cat_tuple(b->world(), as, Defs{b}); }
355inline const Def* cat_sigma(const Def* a, Defs bs) { return cat_sigma(a->world(), Defs{a}, bs); }
356inline const Def* cat_sigma(Defs as, const Def* b) { return cat_sigma(b->world(), as, Defs{b}); }
357///@}
358
359} // namespace mim
A (possibly paramterized) Array.
Definition tuple.h:121
const Def * arity() const final
Number of elements available to Extract / Insert (may be dynamic).
Definition tuple.h:131
static constexpr auto Node
Definition tuple.h:158
Arr * unset()
Definition tuple.h:141
constexpr size_t reduction_offset() const noexcept final
First Def::op that needs to be dealt with during reduction; e.g.
Definition tuple.h:149
Arr * set(const Def *arity, const Def *body)
Definition tuple.h:140
static constexpr size_t Num_Ops
Definition tuple.h:159
Arr * set_body(const Def *body)
Definition tuple.h:139
const Def * reduce(const Def *arg) const final
Definition tuple.h:148
friend class World
Definition tuple.h:165
Arr * set_arity(const Def *arity)
Definition tuple.h:138
Arr * stub_(World &, const Def *) final
Definition def.cpp:160
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:125
Arr * stub(const Def *type)
Definition tuple.h:146
const App * app() const
Definition tuple.h:289
Branch(const Def *)
Definition tuple.cpp:33
Base class for all Defs.
Definition def.h:261
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
World & world() const noexcept
Definition def.cpp:483
constexpr auto ops() const noexcept
Definition def.h:317
const Def * op(size_t i) const noexcept
Definition def.h:320
friend class World
Definition def.h:746
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.cpp:491
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
constexpr auto reduce(const Def *arg) const
Definition def.h:614
Dbg dbg() const
Definition def.h:556
Def * stub(World &w, const Def *type)
Definition def.h:595
const Def * index() const
Definition tuple.h:320
Dispatch(const Def *)
Definition tuple.cpp:41
size_t num_targets() const
Definition tuple.h:322
const Def * target(size_t i) const
Definition tuple.h:323
const Extract * extract() const
Definition tuple.h:318
const App * app() const
Definition tuple.h:314
const Def * tuple() const
Definition tuple.h:319
Extracts from a Sigma or Array-typed Extract::tuple the element at position Extract::index.
Definition tuple.h:210
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:126
const Def * tuple() const
Definition tuple.h:220
friend class World
Definition tuple.h:230
static constexpr size_t Num_Ops
Definition tuple.h:225
static constexpr auto Node
Definition tuple.h:224
const Def * index() const
Definition tuple.h:221
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:128
static constexpr auto Node
Definition tuple.h:252
const Def * tuple() const
Definition tuple.h:247
friend class World
Definition tuple.h:258
const Def * index() const
Definition tuple.h:248
static constexpr size_t Num_Ops
Definition tuple.h:253
const Def * value() const
Definition tuple.h:249
static T as(const Def *def)
Definition def.h:884
Pack * stub_(World &, const Def *) final
Definition def.cpp:164
const Def * arity() const final
Number of elements available to Extract / Insert (may be dynamic).
Definition tuple.cpp:19
static constexpr size_t Num_Ops
Definition tuple.h:200
Pack * unset()
Definition tuple.h:188
friend class World
Definition tuple.h:206
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:132
const Def * reduce(const Def *arg) const final
Definition tuple.h:195
static constexpr auto Node
Definition tuple.h:199
Pack * set(const Def *body)
Definition tuple.h:187
Pack * stub(const Def *type)
Definition tuple.h:193
constexpr size_t reduction_offset() const noexcept final
First Def::op that needs to be dealt with during reduction; e.g.
Definition tuple.h:196
Base class for Sigma and Tuple.
Definition tuple.h:10
~Prod() override
static constexpr size_t Num_Ops
Definition tuple.h:17
Def(World *, Node, const Def *type, Defs ops, flags_t flags)
Constructor for an immutable Def.
Definition def.cpp:24
const Def * cond() const
Definition tuple.h:273
const Def * pair() const
Definition tuple.h:272
const Def * tt() const
Definition tuple.h:274
const Def * ff() const
Definition tuple.h:275
const Extract * extract() const
Definition tuple.h:271
Select(const Def *)
Definition tuple.cpp:25
Base class for Arr and Pack.
Definition tuple.h:86
Seq * set(const Def *arity, const Def *body)
Common setter for Packs and Arrays.
Definition tuple.h:105
virtual const Def * reduce(const Def *arg) const =0
~Seq() override
const Def * body() const
Definition tuple.h:95
Seq * unset()
Definition tuple.h:108
Seq * stub(World &w, const Def *type)
Definition tuple.h:113
Def(World *, Node, const Def *type, Defs ops, flags_t flags)
Constructor for an immutable Def.
Definition def.cpp:24
CRTP-based mixin to declare setters for Def::loc & Def::name using a covariant return type.
Definition def.h:193
const Tuple * set(Loc l) const
Definition def.h:200
Sigma * unset()
Definition tuple.h:36
Sigma * stub(const Def *type)
Definition tuple.h:42
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:137
Sigma * set(Defs ops)
Definition tuple.h:35
constexpr size_t reduction_offset() const noexcept final
Definition tuple.h:48
friend class World
Definition tuple.h:65
const Def * immutabilize() final
Tries to make an immutable from a mutable.
Definition def.cpp:208
const Def * check() final
After all Def::ops have been Def::set, this method will be invoked to check the type of this mutable.
Definition check.cpp:309
Sigma * stub_(World &, const Def *) final
Definition def.cpp:167
static const Def * infer(World &, Defs)
Definition check.cpp:300
static constexpr auto Node
Definition tuple.h:59
const Def * arity() const final
Number of elements available to Extract / Insert (may be dynamic).
Definition tuple.cpp:13
Sigma * set(size_t i, const Def *def)
Definition tuple.h:34
friend class World
Definition tuple.h:82
static constexpr auto Node
Definition tuple.h:74
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:36
Definition ast.h:14
View< const Def * > Defs
Definition def.h:78
Vector< const Def * > DefVec
Definition def.h:79
const Def * cat_tuple(nat_t n, nat_t m, const Def *a, const Def *b)
Definition tuple.cpp:100
const Def * cat_sigma(nat_t n, nat_t m, const Def *a, const Def *b)
Definition tuple.cpp:101
DefVec cat(Defs, Defs)
Definition tuple.cpp:81
@ Arr
Definition def.h:109
@ Pack
Definition def.h:109
@ Extract
Definition def.h:109
@ Insert
Definition def.h:109
@ Tuple
Definition def.h:109