28 auto [last,
op] = hole->find();
32 if (
auto t = last->type())
33 if (
auto new_t = t->zonk_mut(); new_t != t) last->set_type(new_t);
37 if (!
is_set())
return this;
40 for (
auto def :
deps())
43 if (
auto imm = mut->immutabilize())
return imm;
51 return DefVec(defs, [](
const Def* def) {
return def->
zonk(); });
63 auto h = def->isa_mut<Hole>();
69 auto root = def ? def : last;
72 for (
auto h =
this; h != last;) {
73 auto next = h->op()->as_mut<Hole>();
88 holes[0] = w.mut_hole(sigma->op(0));
89 for (
size_t i = 1; i != n; ++i) {
90 rw.map(sigma->var(n, i - 1), holes[i - 1]);
91 holes[i] = w.mut_hole(rw.rewrite(sigma->op(i)));
94 for (
size_t i = 0; i != n; ++i)
95 holes[i] = w.mut_hole(
type()->
proj(n, i));
98 auto tuple = w.tuple(holes);
107#ifdef MIM_ENABLE_CHECKS
108template<Check::Mode mode>
110 if (mode ==
C &&
world().flags().break_on_alpha) fe::breakpoint();
114const Def* Check::fail() {
115 if (
world().flags().break_on_alpha) fe::breakpoint();
121 if (defs.empty())
return nullptr;
122 auto first = defs.front();
123 auto same = [first](
const Def* def) {
return alpha<T>(first, def); };
124 return std::ranges::all_of(defs.subspan(1), same) ? first :
nullptr;
127const Def* Check::coerce_(
const Def* type,
const Def* val) {
129 if (!val_t)
return fail();
130 auto val_ty = val_t->zonk();
131 if (type == val_ty)
return val;
142 val = w.implicit_holes(val);
144 if (type == val_ty)
return val;
147 if (
auto sigma = type->isa<Sigma>()) {
148 if (!alpha_<C>(type->arity(), val_ty->arity()))
return fail();
150 size_t a = sigma->num_ops();
151 auto new_ops =
DefVec(a, [&](
size_t i) {
return val->
proj(a, i); });
152 for (
size_t i = 0; i !=
a; ++i) {
154 auto new_val = coerce_(
w.component(sigma, new_ops, a, i), new_ops[i]);
155 if (!new_val)
return fail();
156 new_ops[i] = new_val;
158 return w.tuple(new_ops);
162 if (
auto extract = val->isa<Extract>();
164 auto tuple = extract->tuple();
165 if (
auto sigma = tuple->unfold_type()->zonk()->isa_imm<Sigma>()) {
166 auto n = sigma->num_ops();
168 for (
size_t i = 0; i != n; ++i)
169 if (!(new_ops[i] = coerce_(type, tuple->proj(n, i))))
return fail();
170 return w.extract(
w.tuple(new_ops), extract->index());
174 auto num_deferred = deferred_.size();
175 if (alpha_<C>(type, val_ty))
return val;
177 if (
auto bot = val_ty->isa<
Bot>(); bot &&
bot->type()->isa<Type>()) {
178 deferred_.resize(num_deferred);
184std::pair<Check::Binders::iterator, bool> Check::bind(
Def* mut,
const Def* d) {
185 if (!mut)
return {binders_.end(),
true};
187 auto res = binders_.emplace(mut, d);
190 for (
auto& memo : memo_)
193 if (
auto var = mut->has_var()) bound_ =
world().
vars().insert(bound_, var);
201 if (
auto seq = def->
zonk_mut()->isa<
Seq>())
return seq->shape().rank();
210 if (
auto arr = shape->type()->zonk_mut()->isa<
Arr>())
return Hole::isa_unset(arr->arity()->zonk_mut());
218 auto n = def->
node();
222template<Check::Mode mode>
223std::optional<bool> Check::try_alpha_(
const Def* d1,
const Def* d2) {
225 if (d1 == d2 && (d1->isa_mut() || bound_.empty() || !d1->has_free_vars_in(bound_)))
return true;
228 if ((d1->node() != d2->node() || d1->flags() != d2->flags()) && d1->is_ground() && d2->is_ground() && !
is_flex(d1)
235template<Check::Mode mode>
236bool Check::alpha_(
const Def* d1,
const Def* d2) {
237 if (
auto res = try_alpha_<mode>(d1, d2))
return *res;
239 auto& memo = memo_[
mode];
240 auto key = memo_key(d1, d2);
241 if (memo.contains(key))
return true;
242 if (!alpha_impl_<mode>(d1, d2))
return false;
247template<Check::Mode mode>
248bool Check::alpha_impl_(
const Def* d1,
const Def* d2) {
249 for (
bool todo =
true; todo;) {
255 if (
auto res = try_alpha_<mode>(d1, d2); res.has_value())
return *res;
257 auto h1 = d1->isa_mut<
Hole>();
258 auto h2 = d2->isa_mut<
Hole>();
260 if constexpr (
mode ==
C) {
261 if (h1)
return check(h1, d2);
262 if (h2)
return check(h2, d1);
266 if (!d1->is_set() || !d2->is_set())
return fail<mode>();
268 auto mut1 = d1->isa_mut();
269 auto mut2 = d2->isa_mut();
271 if (mut1 && mut2 && mut1 == mut2)
return true;
273 if (
auto [i, ins] = bind(mut1, d2); !ins)
return i->second == d2;
274 if (
auto [i, ins] = bind(mut2, d1); !ins)
return i->second == d1;
276 auto t1 = d1->type();
277 auto t2 = d2->type();
278 if (t1 && t2 && !alpha_<mode>(t1, t2))
return fail<mode>();
281 if constexpr (
mode ==
C) {
285 if (!check_rank(d1->as<Seq>(), rank, d2))
return fail<C>();
290 if (!check_rank(d2->as<Seq>(), rank, d1))
return fail<C>();
296 if (!alpha_<mode>(d1->arity(), d2->arity()))
return fail<mode>();
298 auto new_d1 = d1->zonk_mut();
299 auto new_d2 = d2->zonk_mut();
300 if (new_d1 != d1 || new_d2 != d2) {
307 auto seq1 = d1->isa<Seq>();
308 auto seq2 = d2->isa<Seq>();
310 if constexpr (
mode ==
C) {
311 if (
auto lmax = d1->isa<LMax>())
return check(lmax, d2);
312 if (
auto lmax = d2->isa<LMax>())
return check(lmax, d1);
313 if (
auto inc = d1->isa<LSucc>())
return check(inc, d2);
314 if (
auto inc = d2->isa<LSucc>())
return check(inc, d1);
316 if (seq1 && !seq1->shape().is_fused() && seq1->arity() ==
world().lit_nat_1() && !seq2)
return check1(seq1, d2);
317 if (seq2 && !seq2->shape().is_fused() && seq2->arity() ==
world().lit_nat_1() && !seq1)
return check1(seq2, d1);
320 if (
auto mut_seq = seq1->isa_mut<Seq>(); mut_seq && seq2->isa_imm())
return check(mut_seq, seq2);
321 if (
auto mut_seq = seq2->isa_mut<Seq>(); mut_seq && seq1->isa_imm())
return check(mut_seq, seq1);
325 if (
auto prod = d1->isa<Prod>())
return check<mode>(prod, d2);
326 if (
auto prod = d2->isa<Prod>())
return check<mode>(prod, d1);
327 if (seq1 && seq2)
return check<mode>(seq1, seq2);
329 if (d1->node() != d2->node() || d1->flags() != d2->flags())
return fail<mode>();
331 if (
auto var1 = d1->isa<Var>()) {
332 auto var2 = d2->as<
Var>();
333 if (
auto i = binders_.find(var1->binder()); i != binders_.end())
return i->second == var2->binder();
334 if (binders_.contains(var2->binder()))
return fail<mode>();
336 return var1 == var2 ||
mode ==
C;
339 for (
size_t i = 0, e = d1->num_ops(); i != e; ++i)
340 if (!alpha_<mode>(d1->op(i), d2->op(i)))
return fail<mode>();
344template<Check::Mode mode>
345bool Check::check(
const Prod* prod,
const Def* def) {
346 size_t a = prod->num_ops();
347 for (
size_t i = 0; i !=
a; ++i)
348 if (!alpha_<mode>(prod->op(i), def->proj(a, i)))
return fail<mode>();
354 auto lmax = def->isa<
LMax>();
355 if (!lmax)
return def;
358 for (
auto op : lmax->ops())
359 if (op->zonk_mut() != hole) ops.emplace_back(op);
361 return ops.size() == lmax->num_ops() ? def : hole->
world().
lmax(ops);
365bool Check::check(Hole* hole,
const Def* def) {
368 if (def->unfold_type()) {
369 if (
auto new_def = coerce_(hole->type(), def))
374 return hole->set(def),
true;
379bool Check::check_rank(
const Seq* seq,
Hole* rank,
const Def* def) {
381 if (!r)
return fail<C>();
384 auto body = seq->body()->zonk_mut();
386 if (
auto bseq = body->isa<Seq>())
387 if (
auto q = bseq->shape().rank(); q && *q <= *r) n = *
r - *q;
388 if (n == 0)
return fail<C>();
390 rank->set(
world().lit_nat(n));
397template<Check::Mode mode>
398bool Check::check(
const Seq* seq1,
const Seq* seq2) {
399 auto r1 = seq1->shape().rank();
400 auto r2 = seq2->shape().rank();
401 if (r1 && r2 && *r1 != *r2) {
402 auto k = std::min(*r1, *r2);
405 if (!rest1 || !rest2)
return fail<mode>();
406 for (
size_t i = 0; i != k; ++i)
407 if (!alpha_<mode>(seq1->shape()[i], seq2->shape()[i]))
return fail<mode>();
408 return alpha_<mode>(rest1, rest2);
411 return alpha_<mode>(*seq1->shape(), *seq2->shape()) && alpha_<mode>(seq1->body(), seq2->body());
415bool Check::check1(
const Seq* seq,
const Def* def) {
416 auto body = seq->reduce(
world().lit_idx_1_0());
417 if (!alpha_<C>(body, def))
return fail<C>();
418 if (
auto mut_seq = seq->isa_mut<Seq>()) mut_seq->set(
world().lit_nat_1(), body->zonk());
424bool Check::check(
Seq* mut_seq,
const Seq* imm_seq) {
427 auto r = mut_seq->shape().rank();
428 auto rest =
r ?
world().
drop(imm_seq, *r) :
nullptr;
430 if (!rest)
return fail<C>();
432 auto mut_body = mut_seq->reduce(
world().
top(
world().type_indices(mut_seq->shape())));
433 if (!alpha_<C>(mut_body, rest))
return fail<C>();
435 mut_seq->set(*mut_seq->shape(), mut_body->zonk());
440bool Check::check(
const LMax* lmax,
const Def* def) {
444 for (
auto op : lmax->ops())
450 if (c > *l)
return fail<C>();
451 if (*l == 0 || (c < *l && xs.size() == 1)) {
453 if (!alpha_<C>(x, def))
return fail<C>();
458 deferred_.emplace_back(lmax, def);
463bool Check::check(
const LSucc* inc,
const Def* def) {
464 auto k = inc->offset();
465 if (
auto l =
Lit::isa(def))
return *
l >= k && alpha_<C>(inc->op(),
world().lit_level(*l - k));
466 if (
auto other = def->isa<LSucc>()) {
467 auto j = other->offset();
468 return j >= k ? alpha_<C>(inc->op(),
world().lsucc(other->op(), j - k))
469 : alpha_<
C>(
world().lsucc(inc->
op(), k - j), other->
op());
474void Check::commit() {
475 for (
auto [lmax, level] : deferred_)
480template bool Check::alpha_<Check::C>(
const Def*,
const Def*);
481template bool Check::alpha_<Check::T>(
const Def*,
const Def*);
489 return w.sigma(
DefVec(
ops, [](
const Def*
op) {
return op->unfold_type(); }));
498 return w.type(w.level({dom, codom}));
508 auto lam = isa<Lam>();
509 if (!lam)
return def;
513 def->
blame(
"filter of a lambda is of type `{}` but must be of type `Bool`",
type_of(def)).bail();
516 if (
auto body =
Check::coerce(lam->codom(), def))
return body;
517 auto codom = lam->codom();
518 auto& err = def->
blame(
"function body is not assignable to its declared codomain")
519 .n(
"expected `{}`, got `{}`", codom,
type_of(def));
520 if (codom->isa_mut() || codom->isa<
Var>()) err.n(codom->loc(),
"codomain `{}` declared here", codom);
526 bool pending =
type() == w.type_pending();
531 auto t =
Pi::infer(pi->dom(), pi->codom());
533 type()->blame(
"declared sort of function type does not match inferred sort `{}`", t).bail();
537 auto t = as<Arr>()->body()->unfold_type();
539 type()->blame(
"declared sort of array does not match inferred sort `{}`", t).bail();
545 w.log().w(
"expected type {} for {} but keeping the declared {} due to clos-conv bugs", t,
this,
type());
551 type()->blame(
"declared sort of variant does not match inferred sort `{}`", t).bail();
555 auto rule = as<Rule>();
556 auto t1 = rule->lhs()->unfold_type();
557 auto t2 = rule->rhs()->unfold_type();
560 ->blame(
"type mismatch between rule sides: lhs has type `{}` but rhs has type `{}`", t1, t2)
564 ->blame(
"condition of a rewrite rule is of type `{}` but must be of type `Bool`",
A (possibly paramterized) Array.
static const Def * is_uniform(Defs defs)
Yields defs.front(), if all defs are Check::alpha-equivalent (Mode::Test) and nullptr otherwise.
static const Def * coerce(const Def *type, const Def *value)
Can value be assigned to sth of type?
@ C
In Mode::Check, type inference is happening and Holes will be resolved, if possible.
static bool alpha(const Def *d1, const Def *d2)
const Def * zonk_mut() const
If mutable, zonk()s all ops and tries to immutabilize it; otherwise just zonk.
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.
constexpr Node node() const noexcept
Defs deps() const noexcept
const Def * zonk() const
If Holes have been filled, reconstruct the program without them.
World & world() const noexcept
constexpr auto ops() const noexcept
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
std::pair< D *, const Var * > isa_binder() const
Is this a mutable that introduces a Var?
const Def * var(nat_t a, nat_t i) noexcept
const Def * unfold_type() const
Yields the type of this Def and builds a new Type (LSucc n) if necessary.
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).
fe::Error & blame(fe::cite_string< Args... > s, Args &&... args) const
Reports an error that blames this; chain Error::n for Notes and Error::bail to throw.
constexpr MutNode mut_node() const noexcept
node() of a Def whose Node may be mutable, whether this one is or not; see MutNode.
const T * isa_imm() const
bool needs_zonk() const
Yields true, if Def::local_muts() contain a Hole that is set.
bool has_hole() const noexcept
Is this a Hole or does it reach one through Def::deps() up to (and excluding) the next mutable?
const Def * check()
After all Def::ops have been Def::set, this method will be invoked to check the type of this mutable.
This node is a hole in the IR that is inferred by its context later on.
std::pair< Hole *, const Def * > find()
Transitively walks up Holes until the last one while path-compressing everything.
Hole * set(const Def *op)
const Def * tuplefy(nat_t)
If unset, explode to Tuple.
static Hole * isa_unset(const Def *def)
static const Def * isa_set(const Def *def)
static std::optional< T > isa(const Def *def)
A dependent function type.
static const Def * infer(const Def *dom, const Def *codom)
const Def * codom() const
static const Pi * isa_implicit(const Def *d)
Is d an Pi::is_implicit Pi?
Base class for Sigma and Tuple.
static constexpr bool isa_node(mim::Node n) noexcept
Prod groups Sigma and Tuple; see fe::NodeSetable.
Def(World *, Node, const Def *type, Defs ops, flags_t flags)
Constructor for an immutable Def.
Base class for Arr and Pack.
static constexpr bool isa_node(mim::Node n) noexcept
Seq groups Arr and Pack; see fe::NodeSetable.
static const Def * infer(World &, Defs)
static const Def * infer(World &, Defs)
VarRewriter(World &world)
A variable introduced by a binder (mutable).
static const Def * infer(World &, Defs)
void postpone(const LMax *lmax, const Def *level)
Postpones lmax = level as it does not determine the level Holes of lmax yet.
const Def * lmax(Defs levels)
const Def * drop(const Seq *s, nat_t k)
s without its leading k axes - its body once k covers all of them; nullptr if that isn't a type.
const Def * rewire_mut(Def *)
const Def * rewrite(const Def *) final
@ bot
Alias for Mode::fast.
static Hole * isa_flex_rank(const Def *def)
The rank of «s; T» with s: «r; Nat» is unknown as long as r is, and so is Def::arity.
static const Def * drop_self(Hole *hole, const Def *def)
fe::View< const Def * > Defs
fe::Vector< const Def * > DefVec
static std::optional< nat_t > known_rank(const Def *def)
The statically known rank of def: 0 if it isn't a Seq at all, nullopt if its own rank is dynamic.
auto type_of(const Def *def)
Def::unfold_type of def for a diagnostic - Level is the one Def that has no type at all.
static bool is_flex(const Def *def)