5#include <fe/container.h>
6#include <fe/worklist.h>
21bool is_shape(
const Def* s) {
22 if (
s->isa<
Nat>())
return true;
23 if (
auto arr =
s->isa<
Arr>())
return arr->body()->zonk()->isa<
Nat>();
24 if (
auto sig =
s->isa_imm<
Sigma>())
25 return std::ranges::all_of(sig->ops(), [](
const Def* op) { return op->isa<Nat>(); });
31bool isa_indices(
const Def* def) {
32 if (!def)
return false;
34 if (
auto sigma = def->isa<
Sigma>())
return std::ranges::all_of(sigma->ops(), [](
auto op) { return Idx::isa(op); });
35 if (
auto arr = def->isa<
Arr>())
return Idx::isa(arr->body());
40void sort_unique(
DefVec& defs) {
42 defs.erase(std::unique(defs.begin(), defs.end()), defs.end());
50 def->external_ =
true;
51 fe::assert_emplace(sym2mut_, def->
sym(), def);
56 def->external_ =
false;
57 auto num = sym2mut_.erase(def->
sym());
58 assert_unused(num == 1);
65 fe::assert_emplace(sym2flags_,
sym,
flags);
76 if (
auto [i, ins] = sym2flags_.try_emplace(
sym,
flags); !ins) assert(i->second ==
flags);
83#if (!defined(_MSC_VER) && defined(NDEBUG))
84bool World::Lock::guard_ =
false;
99 data_.sigma = unify<Sigma>(
type(),
Defs{})->as<Sigma>();
100 data_.tuple = unify<Tuple>(
sigma(),
Defs{})->as<Tuple>();
106 data_.lit_idx_1_0 =
lit_idx(1, 0);
108 data_.lit_bool[0] =
lit_idx(2, 0_u64);
109 data_.lit_bool[1] =
lit_idx(2, 1_u64);
119static_assert(std::is_trivially_destructible_v<Dbg> && std::is_trivially_destructible_v<Vars>
120 && std::is_trivially_destructible_v<Muts> && std::is_trivially_destructible_v<NormalizeFn>,
121 "a Def member gained a non-trivial destructor: World::~World must destroy Defs again");
141 if (!level)
return nullptr;
142 level = level->
zonk();
145 level->
blame(
"argument `{}` to `Type` must be of type `Univ` but is of type `{}`", level,
type_of(level))
148 return unify<Type>(level)->as<
Type>();
154 if (!op->isa_type<
Univ>())
155 op->blame(
"operand `{}` of a universe increment must be of type `Univ` but is of type `{}`", op,
type_of(op))
159 return unify<UInc>(op, offset);
163 if (
auto umax = def->isa<
UMax>())
164 for (
auto op : umax->ops())
167 ops.emplace_back(def);
173 ops.reserve(ops_.size());
174 for (
auto op : ops_) {
179 if constexpr (sort >=
UMax::Type) op = op->unfold_type();
180 if constexpr (sort ==
UMax::Term) op = op->unfold_type();
185 op->blame(
"operand `{}` must be a `Type` of some universe level", op).bail();
193 res.reserve(ops.size());
194 for (
auto op : ops) {
195 if (!op->isa_type<
Univ>())
196 op->blame(
"operand `{}` of a universe max must be of type `Univ` but is of type `{}`", op,
type_of(op))
200 lvl = std::max(lvl, *l);
202 res.emplace_back(op);
207 if (lvl > 0) res.emplace_back(l);
210 const Def*
umax = unify<UMax>(*
this, res);
217 if (
auto var = mut->var_)
return var;
219 if (
auto var_type = mut->
var_type()) {
222 }
else if (
auto s = var_type->isa<
Sigma>(); s && s->num_ops() == 0)
226 return mut->var_ = unify<Var>(mut);
229template<
bool Normalize>
236template<
bool Normalize>
238 callee = callee->
zonk();
243 callee->
blame(
"callee is not of function type")
244 .n(
"callee `{}` has type `{}`", callee,
type_of(callee))
245 .n(callee->
loc(),
"callee `{}` declared here", callee)
250 arg->
blame(
"argument is not assignable to callee's domain")
252 .n(callee->
loc(),
"callee `{}` declared here", callee)
256 arg = new_arg->
zonk();
257 callee = callee->
zonk();
261 if (
auto imm = callee->
isa_imm<
Lam>())
return imm->body();
274 }
else if (
auto i = move_.substs.find({var, arg}); i != move_.substs.end()) {
276 auto [
filter, body] = i->second->defs<2>();
283 log().d(
"partially evaluate {} ({})",
lam, arg);
284 auto body = rw.rewrite(
lam->
body());
293 callee = callee->
zonk();
297 if (
auto normalizer =
axm->
normalizer(); Normalize && normalizer && curry == 0)
298 if (
auto norm = normalizer(
type, callee, arg))
return norm;
305 callee = callee->
zonk();
313 return unify<App>(
axm, curry, trip,
type, callee, arg);
318 if (n == 0)
return sigma();
319 if (n == 1)
return ops[0]->zonk();
328 if (n == 0)
return tuple();
329 if (n == 1)
return ops[0]->zonk();
336 t->blame(
"tuple `{}` of type `{}` is not assignable to inferred type `{}`", t,
type_of(t),
sigma).bail();
348 if (n == 0)
return tuple();
349 if (n == 1)
return ops[0];
354 if (
auto ex0 = n != 0 ? ops[0]->isa<Extract>() :
nullptr) {
355 auto tup = ex0->tuple();
356 bool eta = tup->type() ==
type;
357 for (
size_t i = 0; i != n && eta; ++i) {
358 auto ex = ops[i]->isa<
Extract>();
359 auto id = ex ?
Lit::isa(ex->index()) : std::nullopt;
360 eta = ex &&
id && *
id ==
u64(i) && ex->tuple() == tup;
366 return unify<Tuple>(
type, ops);
374 if (!d || !index)
return nullptr;
376 index = index->
zonk();
382 if (!size && !isa_indices(index_ty))
383 index->
blame(
"index `{}` must be of `Idx` type but is of type `{}`", index,
type_of(index)).bail();
389 }
else if (
auto pack = index->isa<
Pack>()) {
391 for (
nat_t i = 0, e = *a; i != e; ++i) {
399 auto type = d->unfold_type();
402 if (
auto l =
Lit::isa(size); l && *l == 1) {
403 if (!lidx || *lidx != 0)
log().w(
"index of `Idx 1` is not the literal 0: {}", index);
411 index->
blame(
"index `{}` does not fit within arity `{}`", index,
type->
arity()).bail();
427 if (
auto hole = d->isa_mut<
Hole>()) d = hole->tuplefy(
Idx::as_lit(index_ty));
439 return unify<Extract>(t, d, index);
442 return unify<Extract>(
sigma->
op(*lidx), d, index);
454 const Def* body =
nullptr;
457 auto op_arr = op->zonk()->isa<
Arr>();
458 if (!op_arr || (body && op_arr->body()->
zonk() != body)) {
462 body = op_arr->body()->
zonk();
463 extents.emplace_back(op_arr->arity());
465 if (!extents.empty()) elem_t = this->
arr(
extract(
tuple(extents), index), body);
470 if (index->isa<
Top>()) {
473 hole->set(
pack(size, elem_hole));
479 return unify<Extract>(elem_t, d, index);
484 index = index->
zonk();
487 auto type = d->unfold_type();
491 if (!size) index->
blame(
"index `{}` must be of `Idx` type but is of type `{}`", index,
type_of(index)).bail();
494 index->
blame(
"index `{}` does not fit within arity `{}`", index,
type->
arity()).bail();
500 val->
blame(
"value is not assignable to element type")
501 .n(
"expected `{}`, got `{}`", elem_type,
type_of(val))
502 .n(
"value: `{}`", val)
508 if (
auto l =
Lit::isa(size); l && *l == 1)
509 return tuple(d, {val});
512 if (
auto t = d->isa<
Tuple>(); t && lidx) {
513 auto new_ops =
DefVec(t->ops().begin(), t->ops().end());
514 new_ops[*lidx] = val;
522 new_ops[*lidx] = val;
532 return unify<Insert>(d, index, val);
536 arity = arity->
zonk();
540 if (!is_shape(arity_ty)) arity->
blame(
"expected arity but got `{}` of type `{}`", arity, arity_ty).bail();
543 if (*a == 0)
return unit(is_pack);
544 if (*a == 1)
return body;
549 if (
auto arr_arity = arity_ty->isa<
Seq>())
550 if (
auto n =
Lit::isa(arr_arity->arity())) {
551 auto inner =
DefVec(*n - 1, [&](
u64 i) {
return arity->
proj(*n, i + 1); });
552 return seq(is_pack, arity->
proj(*n, 0),
seq(is_pack,
tuple(inner), body));
555 if (is_pack)
return unify<Pack>(
arr(arity, body->
unfold_type()), body);
556 return unify<Arr>(body->
unfold_type(), arity, body);
560 if (shape.empty())
return body;
561 return seq(is_pack, shape.rsubspan(1),
seq(is_pack, shape.back(), body));
565 if (!
type)
return nullptr;
569 if (size->isa<
Top>()) {
571 }
else if (
auto s =
Lit::isa(size)) {
572 if (*s != 0 && val >= *s)
type->blame(
"index `{}` does not fit within arity `{}`", val, size).bail();
573 }
else if (val != 0) {
574 type->blame(
"cannot create literal `{}` of `Idx {}` as size is unknown", val, size).bail();
578 return unify<Lit>(
type, val);
592 return unify<TExt<Up>>(
type);
598 ops.reserve(ops_.size());
599 for (
auto op_ : ops_) {
600 auto op = op_->zonk();
601 if (!op->isa<
TExt<!Up>>()) ops.emplace_back(op);
607 if (std::ranges::any_of(ops, [](
const Def* op) {
return op->isa<
TExt<Up>>(); }))
return ext<Up>(kind);
611 if (ops.empty())
return ext<!Up>(kind);
612 if (ops.size() == 1)
return ops[0];
615 return unify<TBound<Up>>(kind, ops);
623 auto types =
DefVec(ops.size(), [&](
size_t i) { return ops[i]->unfold_type(); });
624 return unify<Merge>(
meet(types), ops);
627 assert(ops.size() == 1);
638 value = value->
zonk();
646 value = value->
zonk();
648 return unify<Split>(
type, value);
653 if (ops.size() == 1)
return ops.front();
655 auto scrutinee = ops.front();
656 auto arms = ops.span().subspan(1);
661 ->
blame(
"scrutinee `{}` of a test expression must be of union type but has type `{}`", scrutinee,
666 scrutinee->blame(
"test expression has {} arms but union type has {} cases", arms.size(),
join->
num_ops())
669 for (
auto arm : arms)
670 if (!arm->isa_type<
Pi>())
671 arm->blame(
"arm `{}` of test expression does not have a function type but has type `{}`", arm,
type_of(arm))
677 for (
size_t i = 0, e = arms.size(); i != e; ++i) {
681 arm->
blame(
"domain type `{}` of test-expression arm does not match union case type `{}`",
pi->
dom(),
690 if (
auto inj = scrutinee->isa<
Inj>()) {
691 for (
size_t i = 0, e = arms.size(); i != e; ++i)
693 return app(arms[i],
inj->value());
694 scrutinee->blame(
"injected value type `{}` is not a case of union type `{}`",
type_of(
inj->value()),
join)
698 return unify<Match>(
type, ops);
702 inhabitant = inhabitant->
zonk();
705 if (
auto tt = t ? t->unfold_type() :
nullptr)
return unify<Uniq>(tt, inhabitant);
706 inhabitant->
blame(
"`{}` is too high in the universe hierarchy to inhabit a singleton type", inhabitant).bail();
710 auto name = symbol.str();
712 auto pos =
name.find(suffix);
713 if (pos != std::string::npos) {
714 auto num =
name.substr(pos + suffix.size());
719 num = std::to_string(std::stoi(num) + 1);
720 name =
name.substr(0, pos + suffix.size()) +
"_" + num;
730 if (
auto i = move_.substs.find({var, arg}); i != move_.substs.end())
return i->second->defs();
735 auto rewrite = [&](
size_t i) {
return rw.rewrite(mut->op(i + offset)); };
736 return cache_reduct(
var, arg, mut->
num_ops() - offset, rewrite)->defs();
740 fe::BFSWorklist<MutSet> queue;
744 auto muts = fe::Vector<Def*>();
745 while (!queue.empty()) {
746 auto mut = queue.pop();
747 if (mut->is_closed() && (!elide_empty || mut->is_set()))
muts.emplace_back(mut);
749 for (
auto op : mut->deps())
750 for (
auto local_mut : op->local_muts())
751 queue.push(local_mut);
761 for (
auto* mut : schedule)
764 for (
auto* mut :
muts)
773#ifdef MIM_ENABLE_CHECKS
779 auto i = std::ranges::find_if(move_.sea, [=](
auto def) { return def->gid() == gid; });
780 if (i == move_.sea.end())
return nullptr;
786 assert(mut->is_closed() && mut->is_set());
787 for (
auto anx :
annexes().defs())
788 assert(anx->is_closed());
813 auto& curr = state_.pod.curr_loc;
814 if (loc == curr.loc)
return ScopedLoc(curr);
815 return ScopedLoc(curr, {loc, loc ?
driver().dbg(Dbg(loc)) : DbgKey()});
A (possibly paramterized) Array.
static std::tuple< const Axm *, u8, u8 > next(const Def *callee)
Like Axm::get, but advances the counter as one more App is about to be built on top of callee.
NormalizeFn normalizer() const
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)
static const Def * assignable(const Def *type, const Def *value)
Can value be assigned to sth of type?
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.
const Def * zonk() const
If Holes have been filled, reconstruct the program without them.
constexpr auto ops() const noexcept
size_t reduction_offset() const noexcept
First Def::op that needs to be dealt with during reduction; e.g.
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 * unfold_type() const
Yields the type of this Def and builds a new Type (UInc n) if necessary.
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.
bool is_external() const noexcept
const Def * var_type()
If this is a binder, compute the type of its Variable.
const Def * arity() const
Number of elements available to Extract / Insert (may be dynamic).
constexpr auto reduce(const Def *arg) const
const T * isa_imm() const
bool is_closed() const
Same as !has_free_vars().
const Var * has_var()
Only returns not nullptr, if Var of this mutable has ever been created.
const T * isa_type() const
Is Def::unfold_type a T? Yields nullptr for Univ, which has no type at all.
constexpr size_t num_ops() const noexcept
Some "global" variables needed all over the place.
This node is a hole in the IR that is inferred by its context later on.
static Hole * isa_unset(const Def *def)
static nat_t as_lit(const Def *def)
static const Def * isa(const Def *def)
Checks if def is a Idx s and returns s or nullptr otherwise.
Creates a new Tuple / Pack by inserting Insert::value at position Insert::index into Insert::tuple.
const Def * filter() const
static std::optional< T > isa(const Def *def)
A (possibly paramterized) Tuple.
A dependent function type.
const Def * codom() const
static Pi * isa_implicit(const Def *d)
Is d an Pi::is_implicit (mutable) Pi?
const Def * reduce(const Def *arg) const
static Schedule schedule(const Nest &)
Base class for Arr and Pack.
static const Def * infer(World &, Defs)
Extremum. Either Top (Up) or Bottom.
Data constructor for a Sigma.
static const Def * infer(World &, Defs)
const Def * level() const
VarRewriter(World &world)
A variable introduced by a binder (mutable).
Def * binder() const
The binder of this Var.
void attach_alias(flags_t, Sym)
Registers a further Sym for an already attach()ed annex, sharing its flags_t;.
const Def * attach(flags_t, Sym, const Def *)
const Lit * lit_idx(nat_t size, u64 val)
Constructs a Lit of type Idx of size size.
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)
World(Driver *, Sym name)
void watchpoint(u32 gid)
Trigger breakpoint in your debugger when Def::setting a Def with this gid.
const Type * type(const Def *level)
const Def * filter(Lam::Filter filter)
const Def * sigma(Defs ops)
const Def * pack(const Def *arity, const Def *body)
const Def * app(const Def *callee, const Def *arg)
const Pi * pi(const Def *dom, const Def *codom, bool implicit=false)
const Def * unit(bool is_pack)
World & verify()
Verifies that all externals() and annexes() are Def::is_closed(), if MIM_ENABLE_CHECKS.
const fe::Log & log() const
Log via log().e("...", args) etc.; owned by the Driver.
void for_each(bool elide_empty, std::function< void(Def *)>, bool schedule=false)
Hole * mut_hole(const Def *type)
const Lam * lam(const Pi *pi, Lam::Filter f, const Def *body)
const Def * tuple(Defs ops)
const Def * gid2def(u32 gid)
Lookup Def by gid.
Flags & flags()
Retrieve compile Flags.
const Def * implicit_app(const Def *callee, const Def *arg)
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 * arr(const Def *arity, const Def *body)
Sym sym(std::string_view)
const Def * bound(Defs ops)
fe::Restore< CurrLoc > ScopedLoc
const Def * join(Defs ops)
const Def * ext(const Def *type)
Sym append_suffix(Sym name, std::string suffix)
Appends a suffix or an increasing number if the suffix already exists.
const Lit * lit_idx_1_0()
const Lit * lit_univ(u64 level)
const Def * var(Def *mut)
const Tuple * tuple()
the unit value of type []
const Def * uniq(const Def *inhabitant)
const Def * raw_app(const Axm *axm, u8 curry, u8 trip, const Def *type, const Def *callee, const Def *arg)
const Externals & externals() const
const Def * merge(const Def *type, Defs ops)
const Sigma * sigma()
The unit type within Type 0.
const Lit * lit_nat(nat_t a)
const State & state() const
Defs reduce(const Var *var, const Def *arg)
Yields the new body of [mut->var() -> arg]mut.
void breakpoint(u32 gid)
Trigger breakpoint in your debugger when creating a Def with this gid.
const Def * split(const Def *type, const Def *value)
fe::View< const Def * > Defs
TBound< true > Join
AKA union.
fe::Vector< const Def * > DefVec
static void flatten_umax(DefVec &ops, const Def *def)
auto type_of(const Def *def)
Def::unfold_type of def for a diagnostic - Univ is the one Def that has no type at all.
TBound< false > Meet
AKA intersection.
static std::string demangle(plugin_t plugin)
Reverts an Axm::mangled plugin back to its name; never longer than Annex::Max_Plugin_Size.
Compiler switches that must be saved and looked up in later phases of compilation.