12class Zonker :
public Rewriter {
18 Ref rewrite_mut(Def* mut)
override {
return mut; }
34 for (
auto infer = res->isa_mut<
Infer>(); infer && infer->
op(); infer = res->
isa_mut<
Infer>()) res = infer->
op();
43 assert((!res->isa<
Infer>() || res != res->
op(0)) &&
"an Infer shouldn't point to itself");
55 for (
size_t i = 1; i != n; ++i) {
56 rw.map(sigma->var(n, i - 1), infers[i - 1]);
74#ifdef MIM_ENABLE_CHECKS
75template<Checker::Mode mode>
bool Checker::fail() {
76 if (mode ==
Check &&
world().flags().break_on_alpha) fe::breakpoint();
81 if (
world().flags().break_on_alpha) fe::breakpoint();
86template<Checker::Mode mode>
bool Checker::alpha_(Ref r1, Ref r2) {
90 if (!d1 && !d2)
return true;
91 if (!d1 || !d2)
return fail<mode>();
96 if (!d1->has_dep(
Dep::Var) && !d2->has_dep(
Dep::Var) && d1 == d2)
return true;
98 auto i1 = d1->isa_mut<
Infer>();
99 auto i2 = d2->isa_mut<
Infer>();
101 if ((!i1 && !d1->is_set()) || (!i2 && !d2->is_set()))
return fail<mode>();
106 if (i1->rank() < i2->rank()) std::swap(i1, i2);
108 if (i1->rank() == i2->rank()) ++i1->rank();
119 auto mut1 = d1->isa_mut();
120 auto mut2 = d2->isa_mut();
121 if (mut1 && mut2 && mut1 == mut2)
return true;
124 if (d1->isa<Global>() || d2->isa<Global>())
return false;
127 if (
auto [i, ins] = binders_.emplace(mut1, d2); !ins)
return i->second == d2;
130 if (
auto [i, ins] = binders_.emplace(mut2, d1); !ins)
return i->second == d1;
134 if ((d1->isa<Lit>() && !d2->isa<Lit>())
135 || (!d1->isa<UMax>() && d2->isa<UMax>())
136 || (!d1->isa<Extract>() && d2->isa<Extract>()))
139 return alpha_internal<mode>(d1, d2);
142template<Checker::Mode mode>
bool Checker::alpha_internal(Ref d1, Ref d2) {
143 if (!alpha_<mode>(d1->type(), d2->type()))
return fail<mode>();
145 if (mode ==
Test && (d1->isa_mut<
Infer>() || d2->isa_mut<
Infer>()))
return fail<mode>();
146 if (!alpha_<mode>(d1->arity(), d2->arity()))
return fail<mode>();
148 if (
auto ts = d1->isa<Tuple, Sigma>()) {
149 size_t a = ts->num_ops();
150 for (
size_t i = 0; i !=
a; ++i)
151 if (!alpha_<mode>(ts->op(i), d2->proj(a, i)))
return fail<mode>();
153 }
else if (
auto pa = d1->isa<Pack, Arr>()) {
154 if (pa->node() == d2->node())
return alpha_<mode>(pa->ops().back(), d2->ops().back());
155 if (
auto a = pa->isa_lit_arity()) {
156 for (
size_t i = 0; i != *
a; ++i)
157 if (!alpha_<mode>(pa->proj(*a, i), d2->proj(*a, i)))
return fail<mode>();
160 }
else if (
auto umax = d1->isa<UMax>(); umax &&
umax->has_dep(
Dep::Infer) && !d2->isa<UMax>()) {
162 for (
auto op :
umax->ops())
163 if (
auto inf =
op->
isa_mut<
Infer>(); inf && !inf->is_set()) inf->set(d2);
167 if (d1->node() != d2->node() || d1->flags() != d2->flags() || d1->num_ops() != d2->num_ops())
return fail<mode>();
169 if (
auto var1 = d1->isa<
Var>()) {
170 auto var2 = d2->as<
Var>();
171 if (
auto i = binders_.find(var1->mut()); i != binders_.end())
return i->second == var2->mut();
172 if (
auto i = binders_.find(var2->mut()); i != binders_.end())
return fail<mode>();
177 for (
size_t i = 0, e = d1->num_ops(); i != e; ++i)
178 if (!alpha_<mode>(d1->op(i), d2->op(i)))
return fail<mode>();
182Ref Checker::assignable_(Ref type, Ref val) {
184 if (type == val_ty)
return val;
186 if (
auto sigma = type->isa<Sigma>()) {
187 if (!alpha_<Check>(type->arity(), val_ty->arity()))
return fail();
189 size_t a = sigma->num_ops();
190 auto red = sigma->reduce(val);
191 auto new_ops =
DefVec(red.size());
192 for (
size_t i = 0; i !=
a; ++i) {
193 auto new_val = assignable_(red[i], val->proj(a, i));
195 new_ops[i] = new_val;
200 }
else if (
auto arr = type->isa<Arr>()) {
201 if (!alpha_<Check>(type->arity(), val_ty->arity()))
return fail();
204 if (
auto a =
Lit::isa(arr->arity())) {
205 auto new_ops =
DefVec(*a);
206 for (
size_t i = 0; i != *
a; ++i) {
207 auto new_val = assignable_(arr->proj(*a, i), val->proj(*a, i));
209 new_ops[i] = new_val;
215 }
else if (
auto vel = val->isa<Vel>()) {
216 if (
auto new_val = assignable_(type, vel->value()))
return world().
vel(type, new_val);
218 }
else if (
auto uniq = val->type()->isa<Uniq>()) {
219 if (
auto new_val =
assignable(type, uniq->inhabitant()))
return new_val;
223 return alpha_<Check>(type, val_ty) ? val : fail();
227 if (defs.empty())
return nullptr;
228 auto first = defs.front();
229 for (
size_t i = 1, e = defs.size(); i != e; ++i)
243 error(
type()->
loc(),
"declared sort '{}' of array does not match inferred one '{}'",
type(), t);
248 if (
ops.size() == 0)
return w.type<1>();
249 auto kinds =
DefVec(
ops.size(), [
ops](
size_t i) { return ops[i]->unfold_type(); });
263 "incorrect type '{}' for '{}'. Correct one would be: '{}'. I'll keep this one nevertheless due to "
275 throw Error().
error(
filter()->
loc(),
"filter '{}' of lambda is of type '{}' but must be of type 'Bool'",
280 .
error(def->
loc(),
"body of function is not assignable to declared codomain")
281 .
note(def->
loc(),
"body: '{}'", def)
298 error(
type()->
loc(),
"declared sort '{}' of function type does not match inferred one '{}'",
type(), t);
303template bool Checker::alpha_<Checker::Check>(
Ref,
Ref);
304template bool Checker::alpha_<Checker::Test>(
Ref,
Ref);
@ Test
In Mode::Test, no type inference is happening and Infers will not be touched.
@ Check
In Mode::Check, type inference is happening and Infers will be resolved, if possible.
static Ref is_uniform(Defs defs)
Yields defs.front(), if all defs are Check::alpha-equivalent (Mode::Test) and nullptr otherwise.
static bool alpha(Ref d1, Ref d2)
static Ref assignable(Ref type, Ref value)
Can value be assigned to sth of type?
bool is_set() const
Yields true if empty or the last op is set.
Ref op(size_t i) const noexcept
Ref var()
Not necessarily a Var: E.g., if the return type is [], this will yield ().
World & world() const noexcept
constexpr auto ops() const noexcept
Ref unfold_type() const
Yields the type of this Def and builds a new Type (UInc n) if necessary.
T * isa_mut() const
If this is *mut*able, it will cast constness away and perform a dynamic_cast to T.
Def * reset(size_t i, Ref def)
Successively reset from left to right.
Ref type() const noexcept
Yields the raw type of this Def, i.e. maybe nullptr.
std::optional< nat_t > isa_lit_arity() const
Ref 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.
const Var * has_var()
Only returns not nullptr, if Var of this mutable has ever been created.
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.
Ref tuplefy()
If unset, explode to Tuple.
static const Def * find(const Def *)
Union-Find to unify Infer nodes.
Infer * set(const Def *op)
static std::optional< T > isa(Ref def)
static Ref infer(Ref dom, Ref codom)
Helper class to retrieve Infer::arg if present.
const Def * def() const
Retrieve wrapped Def without Infer::refering.
static const Def * refer(const Def *def)
Same as Infer::find but does nothing if def is nullptr.
static Ref infer(World &, Defs)
This is a thin wrapper for std::span<T, N> with the following additional features:
The World represents the whole program and manages creation of MimIR nodes (Defs).
Infer * mut_infer(Ref type)
Ref vel(Ref type, Ref value)
Ref op(trait o, Ref type)
Vector< const Def * > DefVec
void error(Loc loc, const char *f, Args &&... args)