3#include <absl/container/fixed_array.h>
18 : ptr_(
std::move(ptr))
19 , world_(ptr_.
get()) {
31 ptr_ = std::move(ptr);
44 return map(old_def, new_tuple);
48 return map(old_tuple, new_def);
53 return map(old_tuple, new_tuple);
57 if (
auto new_def =
lookup(old_def))
return new_def;
60 return new_def->set(old_def->
dbg());
64#define CODE_MUT(N) case Node::N: new_def = rewrite_mut_##N(old_mut->as<N>()); break;
65#define CODE_IMM(N) case Node::N: new_def = rewrite_imm_##N(old_def->as<N>()); break;
70 switch (old_def->
node()) {
72 default: fe::unreachable();
74 return map(old_def, new_def);
79 switch (old_mut->
node()) {
81 default: fe::unreachable();
90 auto new_ops =
DefVec(ops.size());
91 for (
size_t i = 0, e = ops.size(); i != e; ++i)
99const Def* Rewriter::rewrite_imm_Nat (
const Nat* ) {
return world().
type_nat(); }
100const Def* Rewriter::rewrite_imm_Univ (
const Univ* ) {
return world().
univ(); }
121const Def* Rewriter::rewrite_imm_App(
const App* d) {
126 auto new_callee =
rewrite(
d->callee());
127 return world().
app(new_callee, new_arg);
130const Def* Rewriter::rewrite_imm_Inj(
const Inj* d) {
132 auto new_value =
rewrite(
d->value());
133 return world().
inj(new_type, new_value);
136const Def* Rewriter::rewrite_imm_Insert(
const Insert* d) {
137 auto new_tuple =
rewrite(
d->tuple());
138 auto new_index =
rewrite(
d->index());
139 auto new_value =
rewrite(
d->value());
140 return world().
insert(new_tuple, new_index, new_value);
143const Def* Rewriter::rewrite_imm_Lam(
const Lam* d) {
145 auto new_filter =
rewrite(
d->filter());
147 return world().
lam(new_type, new_filter, new_body);
150const Def* Rewriter::rewrite_imm_Merge(
const Merge* d) {
156const Def* Rewriter::rewrite_imm_Pi(
const Pi* d) {
158 auto new_codom =
rewrite(
d->codom());
159 return world().
pi(new_dom, new_codom,
d->is_implicit());
162const Def* Rewriter::rewrite_imm_Proxy(
const Proxy* d) {
168const Def* Rewriter::rewrite_imm_Rule(
const Rule* d) {
172 auto new_guard =
rewrite(
d->guard());
173 return world().
rule(new_type, new_lhs, new_rhs, new_guard);
176const Def* Rewriter::rewrite_imm_Split(
const Split* d) {
178 auto new_value =
rewrite(
d->value());
182const Def* Rewriter::rewrite_imm_Tuple(
const Tuple* d) {
189const Def* Rewriter::rewrite_mut_Pi(
Pi* pi) {
190 if (pi->is_immutabilizable())
return rewrite_imm_Pi(pi);
194const Def* Rewriter::rewrite_mut_Rule(
Rule* d) {
198const Def* Rewriter::rewrite_mut_Sigma(
Sigma* sigma) {
199 if (sigma->is_immutabilizable())
return rewrite_imm_Sigma(sigma);
203const Def* Rewriter::rewrite_mut_Global(
Global* d) {
207const Def* Rewriter::rewrite_imm_Axm(
const Axm* a) {
208 if (&
a->world() != &
world()) {
210 return world().
axm(
a->normalizer(),
a->curry(),
a->trip(), type,
a->plugin(),
a->tag(),
a->sub());
215const Def* Rewriter::rewrite_imm_Extract(
const Extract* ex) {
216 auto new_index =
rewrite(ex->index());
217 if (
auto index =
Lit::isa(new_index)) {
218 if (
auto tuple = ex->tuple()->isa<
Tuple>())
return map(ex,
rewrite(tuple->op(*index)));
219 if (
auto pack = ex->tuple()->isa_imm<
Pack>(); pack && pack->arity()->is_closed())
223 auto new_tuple =
rewrite(ex->tuple());
227const Def* Rewriter::rewrite_mut_Hole(
Hole* hole) {
228 auto [
last,
op] = hole->find();
245 return map(seq, new_seq);
252 if (
auto var = seq->
has_var(); var && l && *l <=
world().flags().scalarize_threshold) {
253 auto new_ops = absl::FixedArray<const Def*>(*l);
254 for (
size_t i = 0, e = *l; i != e; ++i) {
268 map(old_mut, new_mut);
271 auto _ =
enter(old_mut);
272 for (
size_t i = 0, e = old_mut->
num_ops(); i != e; ++i)
278 if (
auto new_imm = new_mut->
immutabilize())
return map(old_mut, new_imm);
289 if (
auto new_def =
lookup(old_def))
return new_def;
291 if (
auto old_mut = old_def->
isa_mut())
292 return has_intersection(old_mut) ?
rewrite_mut(old_mut)->
set(old_mut->dbg()) : old_mut;
296 return has_intersection(old_def) ?
rewrite_imm(old_def)->
set(old_def->
dbg()) : old_def;
300 if (
auto var = mut->
has_var()) {
301 auto& vars = vars_.back();
313 auto repr =
lookup(new_def);
314 if (!repr) repr = new_def;
319 for (
auto& old2new :
old2news_ | std::views::reverse) {
325 if (repr ==
nullptr)
break;
327 path.emplace_back(repr);
328 if (repr == old_def)
break;
333 if (path.empty())
continue;
336 for (
auto def : path)
347 auto [last, op] = hole->find();
348 def = op ? op : last;
357 auto old_type = mut->
type();
358 auto old_ops = absl::FixedArray<const Def*>(mut->
ops().begin(), mut->
ops().end());
362 for (
size_t i = 0, e = mut->
num_ops(); i != e; ++i)
A (possibly paramterized) Array.
bool is_set() const
Yields true if empty or the last op is set.
constexpr Node node() const noexcept
Def * set(size_t i, const Def *)
Successively set from left to right.
T * as_mut() const
Asserts that this is a mutable, casts constness away and performs a static_cast to T.
const Def * zonk() const
If Holes have been filled, reconstruct the program without them.
Def * set_type(const Def *)
Update type.
bool is_intro() const noexcept
constexpr auto ops() const noexcept
Vars local_vars() const
Vars reachable by following immutable deps().
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
const Def * op(size_t i) const noexcept
bool is_immutabilizable()
virtual const Def * immutabilize()
Tries to make an immutable from a mutable.
Muts local_muts() const
Mutables reachable by following immutable deps(); mut->local_muts() is by definition the set { mut }...
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
virtual const Def * arity() const
Number of elements available to Extract / Insert (may be dynamic).
Def * unset()
Unsets all Def::ops; works even, if not set at all or only partially set.
bool needs_zonk() const
Yields true, if Def::local_muts() contain a Hole that is set.
const Var * has_var()
Only returns not nullptr, if Var of this mutable has ever been created.
constexpr size_t num_ops() const noexcept
This node is a hole in the IR that is inferred by its context later on.
A built-in constant of type Nat -> *.
Creates a new Tuple / Pack by inserting Insert::value at position Insert::index into Insert::tuple.
static std::optional< T > isa(const Def *def)
Scrutinize Match::scrutinee() and dispatch to Match::arms.
A (possibly paramterized) Tuple.
A dependent function type.
virtual const Def * rewrite_imm_Seq(const Seq *seq)
virtual const Def * rewrite_mut_Seq(Seq *seq)
virtual const Def * rewrite_mut(Def *)
virtual const Def * rewrite_stub(Def *, Def *)
virtual const Def * map(const Def *old_def, const Def *new_def)
std::deque< Def2Def > old2news_
virtual const Def * rewrite_imm(const Def *)
Rewriter(std::unique_ptr< World > &&ptr)
virtual const Def * rewrite(const Def *)
auto enter(Def *new_mut)
Updates curr_mut() to new_mut and restores it at the end of the scope.
virtual const Def * lookup(const Def *old_def)
Lookup old_def by searching in reverse through the stack of maps.
Base class for Arr and Pack.
constexpr bool empty() const noexcept
Is empty?
Picks the aspect of a Meet [value](Pick::value) by its [type](Def::type).
Data constructor for a Sigma.
A singleton wraps a type into a higher order type.
const Def * rewrite_mut(Def *) final
const Def * rewrite(const Def *) final
A variable introduced by a binder (mutable).
The World represents the whole program and manages creation of MimIR nodes (Defs).
const Def * insert(const Def *d, const Def *i, const Def *val)
const Def * meet(Defs ops)
const Def * uinc(const Def *op, level_t offset=1)
const Lit * lit(const Def *type, u64 val)
const Def * seq(bool is_pack, const Def *arity, const Def *body)
const Type * type(const Def *level)
const Proxy * proxy(const Def *type, Defs ops, flags_t tag)
const Def * sigma(Defs ops)
const Def * app(const Def *callee, const Def *arg)
const Pi * pi(const Def *dom, const Def *codom, bool implicit=false)
const Def * bot(const Def *type)
const Reform * reform(const Def *dom)
const Lam * lam(const Pi *pi, Lam::Filter f, const Def *body)
const Def * tuple(Defs ops)
const Def * inj(const Def *type, const Def *value)
const Axm * axm(NormalizeFn n, u8 curry, u8 trip, const Def *type, plugin_t p, tag_t t, sub_t s)
const Def * extract(const Def *d, const Def *i)
const Def * join(Defs ops)
const Def * var(Def *mut)
const Def * uniq(const Def *inhabitant)
const Def * prod(bool term, Defs ops)
const Def * merge(const Def *type, Defs ops)
const Def * top(const Def *type)
const Def * split(const Def *type, const Def *value)
const Rule * rule(const Reform *type, const Def *lhs, const Def *rhs, const Def *guard)
const Def * rewire_mut(Def *)
const Def * lookup(const Def *old_def) final
Lookup old_def by searching in reverse through the stack of maps.
const Def * rewrite(const Def *) final
const Def * map(const Def *old_def, const Def *new_def) final
Vector< const Def * > DefVec
TBound< true > Join
AKA union.
constexpr decltype(auto) get(Span< T, N > span) noexcept
TBound< false > Meet
AKA intersection.