3#include <absl/container/fixed_array.h>
13static bool needs_zonk(
const Def* def) {
15 for (
auto mut : def->local_muts())
16 if (
auto infer = mut->isa<
Hole>(); infer && infer->
is_set())
return true;
27 const Def* rewrite(
const Def* def)
override {
37 return needs_zonk(def) ? Zonker(
world()).rewrite(def) : def;
47 for (
auto hole = res->isa_mut<Hole>(); hole && hole->op(); hole = res->isa_mut<Hole>()) res = hole->
op();
51 for (
auto hole = def->
isa_mut<Hole>(); hole && hole->op(); hole = def->
isa_mut<Hole>()) {
63 auto infers = absl::FixedArray<const Def*>(n);
65 auto var = sigma->has_var();
67 infers[0] = w.mut_hole(sigma->op(0));
68 for (
size_t i = 1; i != n; ++i) {
69 rw.map(sigma->var(n, i - 1), infers[i - 1]);
70 infers[i] = w.mut_hole(rw.rewrite(sigma->op(i)));
73 for (
size_t i = 0; i != n; ++i) infers[i] = w.mut_hole(
type()->
proj(n, i));
76 auto tuple = w.tuple(infers);
87#ifdef MIM_ENABLE_CHECKS
88template<Checker::Mode mode>
bool Checker::fail() {
89 if (mode ==
Check &&
world().flags().break_on_alpha) fe::breakpoint();
93const Def* Checker::fail() {
94 if (
world().flags().break_on_alpha) fe::breakpoint();
99template<Checker::Mode mode>
bool Checker::alpha_(
const Def* d1,
const Def* d2) {
103 if (!d1 && !d2)
return true;
104 if (!d1 || !d2)
return fail<mode>();
109 if (!d1->has_dep(
Dep::Var) && !d2->has_dep(
Dep::Var) && d1 == d2)
return true;
111 auto h1 = d1->isa_mut<
Hole>();
112 auto h2 = d2->isa_mut<
Hole>();
114 if ((!h1 && !d1->is_set()) || (!h2 && !d2->is_set()))
return fail<mode>();
119 if (h1->rank() < h2->rank()) std::swap(h1, h2);
121 if (h1->rank() == h2->rank()) ++h1->rank();
132 auto mut1 = d1->isa_mut();
133 auto mut2 = d2->isa_mut();
134 if (mut1 && mut2 && mut1 == mut2)
return true;
137 if (d1->isa<
Global>() || d2->isa<
Global>())
return false;
140 if (
auto [i, ins] = binders_.emplace(mut1, d2); !ins)
return i->second == d2;
143 if (
auto [i, ins] = binders_.emplace(mut2, d1); !ins)
return i->second == d1;
147 if ((d1->isa<
Lit>() && !d2->isa<
Lit>())
148 || (!d1->isa<
UMax>() && d2->isa<
UMax>())
152 return alpha_internal<mode>(d1, d2);
155template<Checker::Mode mode>
bool Checker::alpha_internal(
const Def* d1,
const Def* d2) {
156 if (d1->type() && d2->type() && !alpha_<mode>(d1->type(), d2->type()))
return fail<mode>();
158 if (mode ==
Test && (d1->isa_mut<
Hole>() || d2->isa_mut<
Hole>()))
return fail<mode>();
159 if (!alpha_<mode>(d1->arity(), d2->arity()))
return fail<mode>();
162 size_t a = ts->num_ops();
163 for (
size_t i = 0; i !=
a; ++i)
164 if (!alpha_<mode>(ts->op(i), d2->proj(a, i)))
return fail<mode>();
166 }
else if (
auto pa = d1->isa<
Pack,
Arr>()) {
167 if (pa->node() == d2->node())
return alpha_<mode>(pa->ops().back(), d2->ops().back());
168 if (
auto a = pa->isa_lit_arity()) {
169 for (
size_t i = 0; i != *
a; ++i)
170 if (!alpha_<mode>(pa->proj(*a, i), d2->proj(*a, i)))
return fail<mode>();
175 for (
auto op :
umax->ops())
176 if (
auto inf =
op->
isa_mut<
Hole>(); inf && !inf->is_set()) inf->set(d2);
180 if (d1->node() != d2->node() || d1->flags() != d2->flags() || d1->num_ops() != d2->num_ops())
return fail<mode>();
182 if (
auto var1 = d1->isa<
Var>()) {
183 auto var2 = d2->as<
Var>();
184 if (
auto i = binders_.find(var1->mut()); i != binders_.end())
return i->second == var2->mut();
185 if (
auto i = binders_.find(var2->mut()); i != binders_.end())
return fail<mode>();
190 for (
size_t i = 0, e = d1->num_ops(); i != e; ++i)
191 if (!alpha_<mode>(d1->op(i), d2->op(i)))
return fail<mode>();
195const Def* Checker::assignable_(
const Def* type,
const Def* val) {
197 if (type == val_ty)
return val;
200 if (
auto sigma = type->isa<
Sigma>()) {
201 if (!alpha_<Check>(type->arity(), val_ty->arity()))
return fail();
203 size_t a = sigma->num_ops();
204 auto red = sigma->reduce(val);
205 auto new_ops = absl::FixedArray<const Def*>(red.size());
206 for (
size_t i = 0; i !=
a; ++i) {
207 auto new_val = assignable_(red[i], val->proj(a, i));
209 new_ops[i] = new_val;
213 return w.tuple(new_ops);
214 }
else if (
auto arr = type->isa<
Arr>()) {
215 if (!alpha_<Check>(type->arity(), val_ty->arity()))
return fail();
218 if (
auto a =
Lit::isa(arr->arity())) {
219 auto new_ops = absl::FixedArray<const Def*>(*a);
220 for (
size_t i = 0; i != *
a; ++i) {
221 auto new_val = assignable_(arr->proj(*a, i), val->proj(*a, i));
223 new_ops[i] = new_val;
227 return w.tuple(new_ops);
229 }
else if (
auto inj = val->isa<
Inj>()) {
230 if (
auto new_val = assignable_(type, inj->value()))
return w.inj(type, new_val);
232 }
else if (
auto uniq = val->type()->isa<
Uniq>()) {
233 if (
auto new_val =
assignable(type, uniq->inhabitant()))
return new_val;
237 return alpha_<Check>(type, val_ty) ? val : fail();
241 if (defs.empty())
return nullptr;
242 auto first = defs.front();
243 for (
size_t i = 1, e = defs.size(); i != e; ++i)
257 error(
type()->
loc(),
"declared sort '{}' of array does not match inferred one '{}'",
type(), t);
262 auto elems = absl::FixedArray<const Def*>(
ops.size());
263 for (
size_t i = 0, e =
ops.size(); i != e; ++i) elems[i] =
ops[i]->type();
264 return world.sigma(elems);
268 auto elems = absl::FixedArray<const Def*>(
ops.size());
269 for (
size_t i = 0, e =
ops.size(); i != e; ++i) elems[i] =
ops[i]->unfold_type();
283 "incorrect type '{}' for '{}'. Correct one would be: '{}'. I'll keep this one nevertheless due to "
293 auto& w =
dom->world();
297const Def*
Pi::check(
size_t,
const Def* def) {
return def; }
302 error(
type()->
loc(),
"declared sort '{}' of function type does not match inferred one '{}'",
type(), t);
309 throw Error().
error(
filter()->
loc(),
"filter '{}' of lambda is of type '{}' but must be of type 'Bool'",
314 .
error(def->
loc(),
"body of function is not assignable to declared codomain")
315 .
note(def->
loc(),
"body: '{}'", def)
323template bool Checker::alpha_<Checker::Check>(
const Def*,
const Def*);
324template bool Checker::alpha_<Checker::Test>(
const Def*,
const Def*);
const Def * check() override
static const Def * is_uniform(Defs defs)
Yields defs.front(), if all defs are Check::alpha-equivalent (Mode::Test) and nullptr otherwise.
static bool alpha(const Def *d1, const Def *d2)
@ Test
In Mode::Test, no type inference is happening and Holes will not be touched.
@ Check
In Mode::Check, type inference is happening and Holes will be resolved, if possible.
static const Def * assignable(const Def *type, const Def *value)
Can value be assigned to sth of type?
bool is_set() const
Yields true if empty or the last op is set.
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.
World & world() const noexcept
virtual const Def * check()
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
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 (UInc n) if necessary.
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
std::optional< nat_t > isa_lit_arity() const
Def * reset(size_t i, const Def *def)
Successively reset from left to right.
Error & error(Loc loc, const char *s, Args &&... args)
Error & note(Loc loc, const char *s, Args &&... args)
This node is a hole in the IR that is inferred by its context later on.
Hole * set(const Def *op)
const Def * tuplefy()
If unset, explode to Tuple.
static const Def * find(const Def *)
Union-Find to unify Holes.
const Def * filter() const
const Def * codom() const
static std::optional< T > isa(const Def *def)
static const Def * infer(const Def *dom, const Def *codom)
const Def * codom() const
const Def * check() override
Recurseivly rebuilds part of a program into the provided World w.r.t. Rewriter::map.
virtual const Def * rewrite(const Def *)
static const Def * infer(World &, Defs)
const Def * check() override
static const Def * infer(World &, Defs)
const Def * op(trait o, const Def *type)
void error(Loc loc, const char *f, Args &&... args)