18bool is_shape(
const Def* s) {
19 if (
s->isa<
Nat>())
return true;
20 if (
auto arr =
s->isa<
Arr>())
return arr->body()->zonk()->isa<
Nat>();
21 if (
auto sig =
s->isa_imm<
Sigma>())
22 return std::ranges::all_of(sig->ops(), [](
const Def* op) { return op->isa<Nat>(); });
32 def->external_ =
true;
38 def->external_ =
false;
39 auto num = sym2mut_.erase(def->
sym());
40 assert_unused(num == 1);
46 if (
driver().is_loaded(plugin)) {
59#if (!defined(_MSC_VER) && defined(NDEBUG))
60bool World::Lock::guard_ =
false;
75 data_.sigma = unify<Sigma>(
type(),
Defs{})->as<Sigma>();
76 data_.tuple = unify<Tuple>(
sigma(),
Defs{})->as<Tuple>();
82 data_.lit_idx_1_0 =
lit_idx(1, 0);
84 data_.lit_bool[0] =
lit_idx(2, 0_u64);
85 data_.lit_bool[1] =
lit_idx(2, 1_u64);
93 for (
auto def : move_.defs)
113 if (!level)
return nullptr;
114 level = level->
zonk();
117 error(level->
loc(),
"argument `{}` to `Type` must be of type `Univ` but is of type `{}`", level, level->
type());
119 return unify<Type>(level)->as<
Type>();
125 if (!op->type()->isa<
Univ>())
126 error(op->loc(),
"operand '{}' of a universe increment must be of type `Univ` but is of type `{}`", op,
130 return unify<UInc>(op, offset);
134 if (
auto umax = def->isa<
UMax>())
135 for (
auto op : umax->ops())
138 ops.emplace_back(def);
144 for (
auto op : ops_) {
147 if constexpr (sort ==
UMax::Term) op = op->unfold_type();
148 if constexpr (sort >=
UMax::Type) op = op->unfold_type();
153 error(op->loc(),
"operand '{}' must be a Type of some level", op);
161 for (
auto op : ops) {
162 if (!op->type()->isa<
Univ>())
163 error(op->loc(),
"operand '{}' of a universe max must be of type 'Univ' but is of type '{}'", op,
167 lvl = std::max(lvl, *l);
169 res.emplace_back(op);
174 if (lvl > 0) res.emplace_back(l);
176 std::ranges::sort(res, [](
auto op1,
auto op2) {
return op1->gid() < op2->gid(); });
177 res.erase(std::unique(res.begin(), res.end()), res.end());
178 const Def*
umax = unify<UMax>(*
this, res);
185 if (
auto var = mut->var_)
return var;
187 if (
auto var_type = mut->
var_type()) {
190 }
else if (
auto s = var_type->isa<
Sigma>(); s && s->num_ops() == 0)
194 return mut->var_ = unify<Var>(mut);
197template<
bool Normalize>
204template<
bool Normalize>
206 callee = callee->
zonk();
209 auto pi = callee->
type()->isa<
Pi>();
212 .
error(callee->
loc(),
"called expression not of function type")
213 .
error(callee->
loc(),
"'{}' <--- callee type", callee->
type());
218 .
error(arg->
loc(),
"cannot apply argument to callee")
219 .
note(callee->
loc(),
"callee: '{}'", callee)
220 .
note(arg->
loc(),
"argument: '{}'", arg)
221 .
note(callee->
loc(),
"vvv domain type vvv\n'{}'\n'{}'",
pi->dom(), arg->
type())
222 .
note(arg->
loc(),
"^^^ argument type ^^^");
225 arg = new_arg->
zonk();
226 callee = callee->
zonk();
230 if (
auto imm = callee->
isa_imm<
Lam>())
return imm->body();
233 auto var =
lam->has_var();
237 if (
var && arg ==
var)
return lam->body();
243 }
else if (
auto i = move_.substs.find({var, arg}); i != move_.substs.end()) {
245 auto [
filter, body] = i->second->defs<2>();
252 DLOG(
"partial evaluate: {} ({})",
lam, arg);
253 auto body = rw.rewrite(
lam->body());
254 auto size =
sizeof(Reduct) + 2 *
sizeof(
const Def*);
255 auto buf = move_.arena.substs.allocate(size,
alignof(
const Def*));
256 auto reduct =
new (buf) Reduct(2);
257 reduct->defs_[0] =
filter;
258 reduct->defs_[1] = body;
266 auto type =
pi->reduce(arg)->zonk();
267 callee = callee->
zonk();
270 curry = curry == 0 ? trip : curry;
273 if (
auto normalizer =
axm->normalizer(); Normalize && normalizer && curry == 0)
274 if (
auto norm = normalizer(
type, callee, arg))
return norm;
282 callee = callee->
zonk();
287 curry = curry == 0 ? trip : curry;
295 return unify<App>(
axm, curry, trip,
type, callee, arg);
300 if (n == 0)
return sigma();
301 if (n == 1)
return ops[0]->zonk();
310 if (n == 0)
return tuple();
311 if (n == 1)
return ops[0]->zonk();
318 error(t->loc(),
"cannot assign tuple '{}' of type '{}' to incompatible tuple type '{}'", t, t->type(),
sigma);
330 if (n == 0)
return tuple();
331 if (n == 1)
return ops[0];
338 if (
auto extract = ops[0]->isa<Extract>()) {
340 bool eta = tup->type() ==
type;
341 for (
size_t i = 0; i != n && eta; ++i) {
342 if (
auto extract = ops[i]->isa<Extract>()) {
344 if (eta &=
u64(i) == *index) {
345 eta &=
extract->tuple() == tup;
357 return unify<Tuple>(
type, ops);
362 std::ranges::transform(
sym, std::back_inserter(defs), [
this](
auto c) {
return lit_i8(c); });
368 if (
auto sigma = def->isa<
Sigma>())
return std::ranges::all_of(sigma->ops(), [](
auto op) { return Idx::isa(op); });
369 if (
auto arr = def->isa<
Arr>())
return Idx::isa(arr->body());
374 if (!d || !index)
return nullptr;
376 index = index->zonk();
379 error(index->loc(),
"index '{}' is not of Idx type but of type '{}'", index, index->type());
382 for (
auto op :
tuple->ops())
385 }
else if (
auto pack = index->isa<
Pack>()) {
386 if (
auto a =
Lit::isa(index->arity())) {
387 for (
nat_t i = 0, e = *a; i != e; ++i) {
395 auto size =
Idx::isa(index->type());
396 auto type = d->unfold_type();
399 if (
auto l =
Lit::isa(size); l && *l == 1) {
400 if (
auto l =
Lit::isa(index); !l || *l != 0)
WLOG(
"unknown Idx of size 1: {}", index);
410 error(index->loc(),
"index '{}' does not fit within arity '{}'", index,
type->arity());
415 return pack->reduce(index);
426 if (
auto hole = d->isa_mut<
Hole>()) d = hole->tuplefy(
Idx::as_lit(index->type()));
438 return unify<Extract>(t, d, index);
441 return unify<Extract>(
sigma->op(*i), d, index);
447 elem_t =
arr->reduce(index);
451 if (index->isa<
Top>()) {
454 hole->set(
pack(size, elem_hole));
460 return unify<Extract>(elem_t, d, index);
465 index = index->zonk();
468 auto type = d->unfold_type();
469 auto size =
Idx::isa(index->type());
472 if (!size)
error(d->loc(),
"index '{}' must be of type 'Idx' but is of type '{}'", index, index->type());
475 error(index->loc(),
"index '{}' does not fit within arity '{}'", index,
type->arity());
478 auto elem_type =
type->proj(*lidx);
482 .
error(val->
loc(),
"value to be inserted not assignable to element")
483 .
note(val->
loc(),
"vvv value type vvv \n'{}'\n'{}'", val->
type(), elem_type)
484 .
note(val->
loc(),
"^^^ element type ^^^", elem_type);
489 if (
auto l =
Lit::isa(size); l && *l == 1)
490 return tuple(d, {val});
493 if (
auto t = d->isa<
Tuple>(); t && lidx)
return t->refine(*lidx, val);
499 new_ops[*lidx] = val;
509 return unify<Insert>(d, index, val);
513 arity = arity->
zonk();
517 if (!is_shape(arity_ty))
error(arity->
loc(),
"expected arity but got `{}` of type `{}`", arity, arity_ty);
520 if (*a == 0)
return unit(term);
521 if (*a == 1)
return body;
526 if (
auto arr_arity = arity->
type()->isa<
Seq>())
527 if (
auto lit_arity_arity =
Lit::isa(arr_arity->arity())) {
528 DefVec inner_arity(*lit_arity_arity - 1, [&](
u64 i) {
return arity->
proj(*lit_arity_arity, i + 1); });
529 return seq(term, arity->
proj(*lit_arity_arity, 0),
seq(term,
tuple(inner_arity), body));
534 return unify<Pack>(
type, body);
536 return unify<Arr>(body->
unfold_type(), arity, body);
541 if (shape.empty())
return body;
542 return seq(term, shape.rsubspan(1),
seq(term, shape.back(), body));
546 if (!
type)
return nullptr;
550 if (size->isa<
Top>()) {
552 }
else if (
auto s =
Lit::isa(size)) {
553 if (*s != 0 && val >= *s)
error(
type->loc(),
"index '{}' does not fit within arity '{}'", size, val);
554 }
else if (val != 0) {
555 error(
type->loc(),
"cannot create literal '{}' of 'Idx {}' as size is unknown", val, size);
559 return unify<Lit>(
type, val);
573 return unify<TExt<Up>>(
type);
579 for (
size_t i = 0, e = ops_.size(); i != e; ++i) {
580 auto op = ops_[i]->zonk();
581 if (!op->isa<
TExt<!Up>>()) ops.emplace_back(op);
587 if (std::ranges::any_of(ops, [&](
const Def* op) ->
bool {
return op->isa<
TExt<Up>>(); }))
return ext<Up>(kind);
591 ops.resize(std::distance(ops.begin(), std::unique(ops.begin(), ops.end())));
593 if (ops.size() == 0)
return ext<!Up>(kind);
594 if (ops.size() == 1)
return ops[0];
597 return unify<TBound<Up>>(kind, ops);
605 auto types =
DefVec(ops.size(), [&](
size_t i) { return ops[i]->type(); });
606 return unify<Merge>(
meet(types), ops);
609 assert(ops.size() == 1);
620 value = value->
zonk();
628 value = value->
zonk();
630 return unify<Split>(
type, value);
635 if (ops.size() == 1)
return ops.front();
637 auto scrutinee = ops.front();
638 auto arms = ops.span().subspan(1);
639 auto join = scrutinee->type()->isa<
Join>();
641 if (!
join)
error(scrutinee->loc(),
"scrutinee of a test expression must be of union type");
643 if (arms.size() !=
join->num_ops())
644 error(scrutinee->loc(),
"test expression has {} arms but union type has {} cases", arms.size(),
647 for (
auto arm : arms)
648 if (!arm->type()->isa<
Pi>())
649 error(arm->loc(),
"arm of test expression does not have a function type but is of type '{}'", arm->type());
651 std::ranges::sort(arms, [](
const Def* arm1,
const Def* arm2) {
656 for (
size_t i = 0, e = arms.size(); i != e; ++i) {
658 auto pi = arm->type()->as<
Pi>();
661 "domain type '{}' of arm in a test expression does not match case type '{}' in union type",
pi->dom(),
666 return unify<Match>(
type, ops);
670 inhabitant = inhabitant->
zonk();
675 auto name = symbol.str();
677 auto pos =
name.find(suffix);
678 if (pos != std::string::npos) {
679 auto num =
name.substr(pos + suffix.size());
684 num = std::to_string(std::stoi(num) + 1);
685 name =
name.substr(0, pos + suffix.size()) +
"_" + num;
695 auto mut =
var->binder();
696 auto offset = mut->reduction_offset();
697 auto size = mut->num_ops() - offset;
699 if (
auto i = move_.substs.find({var, arg}); i != move_.substs.end())
return i->second->defs();
701 auto buf = move_.arena.substs.allocate(
sizeof(Reduct) + size *
sizeof(
const Def*),
alignof(
const Def*));
702 auto reduct =
new (buf) Reduct(size);
704 for (
size_t i = 0; i != size; ++i)
705 reduct->defs_[i] = rw.rewrite(mut->op(i + offset));
707 return reduct->defs();
715 std::vector<Def*>
muts;
716 while (!queue.
empty()) {
717 auto mut = queue.
pop();
718 if (mut && mut->is_closed() && (!elide_empty || mut->is_set()))
muts.push_back(mut);
720 for (
auto op : mut->deps())
721 for (
auto mut : op->local_muts())
732 for (
auto* mut : schedule)
735 for (
auto* mut :
muts)
744#ifdef MIM_ENABLE_CHECKS
750 auto i = std::ranges::find_if(move_.defs, [=](
auto def) { return def->gid() == gid; });
751 if (i == move_.defs.end())
return nullptr;
757 assert(mut->is_closed() && mut->is_set());
758 for (
auto anx :
annexes().defs())
759 assert(anx->is_closed());
A (possibly paramterized) Array.
static constexpr u8 Trip_End
static std::tuple< const Axm *, u8, u8 > get(const Def *def)
Yields currying counter of def.
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?
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.
const Def * zonk() const
If Holes have been filled, reconstruct the program without them.
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 * 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).
bool is_external() const noexcept
const Def * var_type()
If this is a binder, compute the type of its Variable.
constexpr u32 gid() const noexcept
Global id - unique number for this Def.
const T * isa_imm() const
bool is_closed() const
Has no free_vars()?
Some "global" variables needed all over the place.
Error & error(Loc loc, std::format_string< Args... > s, Args &&... args)
Error & note(Loc loc, std::format_string< Args... > s, Args &&... args)
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.
static std::optional< T > isa(const Def *def)
Facility to log what you are doing.
Builds a nesting tree for all mutables/binders.
A (possibly paramterized) Tuple.
A dependent function type.
static Pi * isa_implicit(const Def *d)
Is d an Pi::is_implicit (mutable) Pi?
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)
Extends Rewriter for variable substitution.
const Def * rewrite(const Def *) final
A variable introduced by a binder (mutable).
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 Driver & driver() const
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.
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)
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)
#define DLOG(...)
Vaporizes to nothingness in Debug build.
Vector< const Def * > DefVec
auto assert_emplace(C &container, Args &&... args)
Invokes emplace on container, asserts that insertion actually happened, and returns the iterator.
TBound< true > Join
AKA union.
static void flatten_umax(DefVec &ops, const Def *def)
void error(Loc loc, std::format_string< Args... > f, Args &&... args)
bool isa_indicies(const Def *def)
TBound< false > Meet
AKA intersection.
static Sym demangle(Driver &, plugin_t plugin)
Reverts an Axm::mangled string to a Sym.
Compiler switches that must be saved and looked up in later phases of compilation.