From 808946b047dc02f5b2568317de5234f2309ec00a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Mon, 21 Oct 2024 00:49:09 +0200 Subject: [PATCH 1/7] removed Macro magic --- docs/Doxyfile.in | 5 +- include/mim/axiom.h | 11 ++- include/mim/check.h | 12 ++- include/mim/def.h | 186 +++++++++++++++++++++++++++++------------- include/mim/lam.h | 33 ++++++-- include/mim/lattice.h | 61 ++++++++++---- include/mim/tuple.h | 85 ++++++++++++++----- include/mim/world.h | 2 +- src/mim/def.cpp | 2 - 9 files changed, 289 insertions(+), 108 deletions(-) diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index ffc09683e3..71774214a4 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -2538,10 +2538,7 @@ EXPAND_AS_DEFINED = CODE \ MIM_CONV \ MIM_TRAIT \ MIM_ACC \ - MIM_PE \ - MIM_SETTERS \ - MIM_SETTERS_ \ - MIM_DEF_MIXIN + MIM_PE # If the SKIP_FUNCTION_MACROS tag is set to YES then Doxygen's preprocessor will # remove all references to function-like macros that are alone on a line, have diff --git a/include/mim/axiom.h b/include/mim/axiom.h index c69c8180cb..86bf138b19 100644 --- a/include/mim/axiom.h +++ b/include/mim/axiom.h @@ -6,11 +6,13 @@ namespace mim { -class Axiom : public Def { +class Axiom : public Def, public Setters { private: Axiom(NormalizeFn, u8 curry, u8 trip, const Def* type, plugin_t, tag_t, sub_t); public: + using Setters::set; + /// @name Normalization /// @anchor normalization /// For a curried App of an Axiom, you only want to trigger normalization at specific spots. @@ -58,7 +60,12 @@ class Axiom : public Def { using type = App; }; - MIM_DEF_MIXIN(Axiom) + static constexpr auto Node = Node::Axiom; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; // clang-format off diff --git a/include/mim/check.h b/include/mim/check.h index c153f63719..d269603cb2 100644 --- a/include/mim/check.h +++ b/include/mim/check.h @@ -9,12 +9,14 @@ namespace mim { /// This node is a hole in the IR that is inferred by its context later on. /// It is modelled as a *mut*able Def. /// If inference was successful, it's Infer::op will be set to the inferred Def. -class Infer : public Def { +class Infer : public Def, public Setters { private: Infer(const Def* type) : Def(Node, type, 1, 0) {} public: + using Setters::set; + /// @name op ///@{ const Def* op() const { return Def::op(0); } @@ -35,12 +37,16 @@ class Infer : public Def { Infer* stub(Ref type) { return stub_(world(), type)->set(dbg()); } + static constexpr auto Node = Node::Infer; + private: - Infer* stub_(World&, Ref) override; flags_t rank() const { return flags(); } flags_t& rank() { return flags_; } - MIM_DEF_MIXIN(Infer) + Ref rebuild_(World&, Ref, Defs) const override; + Infer* stub_(World&, Ref) override; + + friend class World; friend class Check; }; diff --git a/include/mim/def.h b/include/mim/def.h index 6cbc1ecdc0..18604f10fc 100644 --- a/include/mim/def.h +++ b/include/mim/def.h @@ -14,7 +14,7 @@ #include "mim/util/vector.h" // clang-format off -#define MIM_NODE(m) \ +#define MIM_NODE(m) \ m(Type, type) m(Univ, univ) m(UMax, umax) m(UInc, uinc) \ m(Pi, pi) m(Lam, lam) m(App, app) \ m(Sigma, sigma) m(Tuple, tuple) m(Extract, extract) m(Insert, insert) \ @@ -169,38 +169,30 @@ MIM_ENUM_OPERATORS(Dep) template auto NAME##s(nat_t a, F f) CONST { return ((const Def*)NAME())->projs(a, f); } \ auto NAME##s(nat_t a) CONST { return ((const Def*)NAME())->projs(a); } -// clang-format off -/// Use as mixin to declare setters for Def::loc \& Def::name using a *covariant* return type. -#define MIM_SETTERS_(T) \ -public: \ - template const T* set(Loc l ) const { if (Ow || !dbg_.loc()) dbg_.set(l); return this; } \ - template T* set(Loc l ) { if (Ow || !dbg_.loc()) dbg_.set(l); return this; } \ - template const T* set( Sym s ) const { if (Ow || !dbg_.sym()) dbg_.set(s); return this; } \ - template T* set( Sym s ) { if (Ow || !dbg_.sym()) dbg_.set(s); return this; } \ - template const T* set( std::string s) const { set(sym(std::move(s))); return this; } \ - template T* set( std::string s) { set(sym(std::move(s))); return this; } \ - template const T* set(Loc l, Sym s ) const { set(l); set(s); return this; } \ - template T* set(Loc l, Sym s ) { set(l); set(s); return this; } \ - template const T* set(Loc l, std::string s) const { set(l); set(sym(std::move(s))); return this; } \ - template T* set(Loc l, std::string s) { set(l); set(sym(std::move(s))); return this; } \ - template const T* set(Dbg d) const { set(d.loc(), d.sym()); return this; } \ - template T* set(Dbg d) { set(d.loc(), d.sym()); return this; } -// clang-format on - -#ifdef DOXYGEN -# define MIM_SETTERS(T) public: // Don't spam each and every sub class of Def with basically the same docs. -#else -# define MIM_SETTERS(T) MIM_SETTERS_(T) -#endif +/// CRTP-based Mixin to declare setters for Def::loc \& Def::name using a *covariant* return type. +template class Setters { +private: + P* super() { return static_cast(this); } + const P* super() const { return static_cast(this); } + Def* def() { return (Def*)this; } + const Def* def() const { return (const Def*)this; } -#define MIM_DEF_MIXIN(T) \ -public: \ - MIM_SETTERS(T) \ - static constexpr auto Node = Node::T; \ - \ -private: \ - Ref rebuild_(World&, Ref, Defs) const override; \ - friend class World; +public: + // clang-format off + template const P* set(Loc l ) const { def()->template set(l); return super(); } + template P* set(Loc l ) { def()->template set(l); return super(); } + template const P* set( Sym s ) const { def()->template set(s); return super(); } + template P* set( Sym s ) { def()->template set(s); return super(); } + template const P* set( std::string s) const { def()->template set(std::move(s)); return super(); } + template P* set( std::string s) { def()->template set(std::move(s)); return super(); } + template const P* set(Loc l, Sym s ) const { def()->template set(l, s); return super(); } + template P* set(Loc l, Sym s ) { def()->template set(l, s); return super(); } + template const P* set(Loc l, std::string s) const { def()->template set(l, std::move(s)); return super(); } + template P* set(Loc l, std::string s) { def()->template set(l, std::move(s)); return super(); } + template const P* set(Dbg d ) const { def()->template set(d); return super(); } + template P* set(Dbg d ) { def()->template set(d); return super(); } + // clang-format on +}; /// Base class for all Def%s. /// The data layout (see World::alloc and Def::partial_ops) looks like this: @@ -217,7 +209,7 @@ private: \ /// ``` /// @attention This means that any subclass of Def **must not** introduce additional members. /// @see @ref mut -class Def : public fe::RuntimeCast { +class Def : public fe::RuntimeCast, public Setters { private: Def& operator=(const Def&) = delete; Def(const Def&) = delete; @@ -467,9 +459,22 @@ class Def : public fe::RuntimeCast { ///@} /// @name Dbg Setters - /// Every subclass `S` of Def has the same setters that return `S*`/`const S*` but will not show up in Doxygen. + /// Every subclass `S` of Def has the same setters that return `S*`/`const S*` via the mixin Setters. ///@{ - MIM_SETTERS_(Def) + // clang-format off + template const Def* set(Loc l) const { if (Ow || !dbg_.loc()) dbg_.set(l); return this; } + template Def* set(Loc l) { if (Ow || !dbg_.loc()) dbg_.set(l); return this; } + template const Def* set(Sym s) const { if (Ow || !dbg_.sym()) dbg_.set(s); return this; } + template Def* set(Sym s) { if (Ow || !dbg_.sym()) dbg_.set(s); return this; } + template const Def* set( std::string s) const { set(sym(std::move(s))); return this; } + template Def* set( std::string s) { set(sym(std::move(s))); return this; } + template const Def* set(Loc l, Sym s ) const { set(l); set(s); return this; } + template Def* set(Loc l, Sym s ) { set(l); set(s); return this; } + template const Def* set(Loc l, std::string s) const { set(l); set(sym(std::move(s))); return this; } + template Def* set(Loc l, std::string s) { set(l); set(sym(std::move(s))); return this; } + template const Def* set(Dbg d) const { set(d.loc(), d.sym()); return this; } + template Def* set(Dbg d) { set(d.loc(), d.sym()); return this; } + // clang-format on ///@} /// @name debug_prefix/suffix @@ -631,70 +636,105 @@ template using DefDefMap = absl::flat_hash_map; ///@} -class Var : public Def { +class Var : public Def, public Setters { private: Var(const Def* type, Def* mut) : Def(Node, type, Defs{mut}, 0) {} public: + using Setters::set; + /// @name ops ///@{ Def* mut() const { return op(0)->as_mut(); } ///@} - MIM_DEF_MIXIN(Var) + static constexpr auto Node = Node::Var; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; -class Univ : public Def { +class Univ : public Def, public Setters { +public: + using Setters::set; + static constexpr auto Node = Node::Univ; + private: Univ(World& world) : Def(&world, Node, nullptr, Defs{}, 0) {} - MIM_DEF_MIXIN(Univ) + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; -class UMax : public Def { +class UMax : public Def, public Setters { +public: + using Setters::set; + static constexpr auto Node = Node::UMax; + private: UMax(World&, Defs ops); - MIM_DEF_MIXIN(UMax) + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; -class UInc : public Def { +class UInc : public Def, public Setters { private: UInc(const Def* op, level_t offset) : Def(Node, op->type()->as(), {op}, offset) {} public: + using Setters::set; + /// @name ops ///@{ const Def* op() const { return Def::op(0); } level_t offset() const { return flags(); } ///@} - MIM_DEF_MIXIN(UInc) + static constexpr auto Node = Node::UInc; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; -class Type : public Def { +class Type : public Def, public Setters { private: Type(const Def* level) : Def(Node, nullptr, {level}, 0) {} public: + using Setters::set; + /// @name ops ///@{ const Def* level() const { return op(0); } ///@} - MIM_DEF_MIXIN(Type) + static constexpr auto Node = Node::Type; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; -class Lit : public Def { +class Lit : public Def, public Setters { private: Lit(const Def* type, flags_t val) : Def(Node, type, Defs{}, val) {} public: + using Setters::set; + /// @name Get actual Constant ///@{ template T get() const { @@ -717,23 +757,36 @@ class Lit : public Def { template static T as(Ref def) { return def->as()->get(); } ///@} - MIM_DEF_MIXIN(Lit) + static constexpr auto Node = Node::Lit; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; -class Nat : public Def { +class Nat : public Def, public Setters { +public: + using Setters::set; + static constexpr auto Node = Node::Nat; + private: Nat(World& world); - MIM_DEF_MIXIN(Nat) + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; /// A built-in constant of type `Nat -> *`. -class Idx : public Def { +class Idx : public Def, public Setters { private: Idx(const Def* type) : Def(Node, type, Defs{}, 0) {} public: + using Setters::set; + /// Checks if @p def is a `Idx s` and returns `s` or `nullptr` otherwise. static Ref size(Ref def); @@ -746,33 +799,47 @@ class Idx : public Def { static std::optional size2bitwidth(const Def* size); ///@} - MIM_DEF_MIXIN(Idx) + static constexpr auto Node = Node::Idx; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; -class Proxy : public Def { +class Proxy : public Def, public Setters { private: Proxy(const Def* type, Defs ops, u32 pass, u32 tag) : Def(Node, type, ops, (u64(pass) << 32_u64) | u64(tag)) {} public: + using Setters::set; + /// @name Getters ///@{ u32 pass() const { return u32(flags() >> 32_u64); } ///< IPass::index within PassMan. u32 tag() const { return u32(flags()); } ///@} - MIM_DEF_MIXIN(Proxy) + static constexpr auto Node = Node::Proxy; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; /// @deprecated A global variable in the data segment. /// A Global may be mutable or immutable. -/// @attention WILL BE REMOVED. -class Global : public Def { +/// @deprecated Will be removed. +class Global : public Def, public Setters { private: Global(const Def* type, bool is_mutable) : Def(Node, type, 1, is_mutable) {} public: + using Setters::set; + /// @name ops ///@{ const Def* init() const { return op(0); } @@ -790,11 +857,18 @@ class Global : public Def { bool is_mutable() const { return flags(); } ///@} + /// @name Rebuild + ///@{ Global* stub(Ref type) { return stub_(world(), type)->set(dbg()); } - MIM_DEF_MIXIN(Global) + ///@} + + static constexpr auto Node = Node::Global; private: + Ref rebuild_(World&, Ref, Defs) const override; Global* stub_(World&, Ref) override; + + friend class World; }; hash_t UseHash::operator()(Use use) const { return hash_combine(hash_begin(u16(use.index())), hash_t(use->gid())); } diff --git a/include/mim/lam.h b/include/mim/lam.h index 90f917383f..0d8ef9a1e7 100644 --- a/include/mim/lam.h +++ b/include/mim/lam.h @@ -8,7 +8,7 @@ namespace mim { /// A [dependent function type](https://en.wikipedia.org/wiki/Dependent_type#%CE%A0_type). /// @see Lam -class Pi : public Def { +class Pi : public Def, public Setters { protected: /// Constructor for an *immutable* Pi. Pi(const Def* type, const Def* dom, const Def* codom, bool implicit) @@ -69,6 +69,7 @@ class Pi : public Def { /// @name Setters /// @see @ref set_ops "Setting Ops" ///@{ + using Setters::set; Pi* set(Ref dom, Ref codom) { return set_dom(dom)->set_codom(codom); } Pi* set_dom(Ref dom) { return Def::set(0, dom)->as(); } Pi* set_dom(Defs doms); @@ -82,18 +83,25 @@ class Pi : public Def { static Ref infer(Ref dom, Ref codom); ///@} - const Pi* immutabilize() override; + /// @name Rebuild + ///@{ Pi* stub(Ref type) { return stub_(world(), type)->set(dbg()); } + const Pi* immutabilize() override; + ///@} - MIM_DEF_MIXIN(Pi) + static constexpr auto Node = Node::Pi; private: + Ref rebuild_(World&, Ref, Defs) const override; Pi* stub_(World&, Ref) override; + ; + + friend class World; }; /// A function. /// @see Pi -class Lam : public Def { +class Lam : public Def, public Setters { private: Lam(const Pi* pi, const Def* filter, const Def* body) : Def(Node, pi, {filter, body}, 0) {} @@ -154,6 +162,7 @@ class Lam : public Def { /// ``` /// @see @ref set_ops "Setting Ops" ///@{ + using Setters::set; using Filter = std::variant; Lam* set(Filter filter, const Def* body) { return set_filter(filter)->set_body(body); } Lam* set_filter(Filter); ///< Set filter first. @@ -176,10 +185,13 @@ class Lam : public Def { void check() override; ///@} - MIM_DEF_MIXIN(Lam) + static constexpr auto Node = Node::Lam; private: + Ref rebuild_(World&, Ref, Defs) const override; Lam* stub_(World&, Ref) override; + + friend class World; }; /// @name Lam @@ -190,7 +202,7 @@ using LamSet = GIDSet; using Lam2Lam = LamMap; ///@} -class App : public Def { +class App : public Def, public Setters { private: App(const Axiom* axiom, u8 curry, u8 trip, const Def* type, const Def* callee, const Def* arg) : Def(Node, type, {callee, arg}, 0) { @@ -200,6 +212,8 @@ class App : public Def { } public: + using Setters::set; + /// @name callee ///@{ const Def* callee() const { return op(0); } @@ -222,7 +236,12 @@ class App : public Def { u8 trip() const { return trip_; } ///@} - MIM_DEF_MIXIN(App) + static constexpr auto Node = Node::App; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; /// @name Helpers to work with Functions diff --git a/include/mim/lattice.h b/include/mim/lattice.h index e3848a61d0..0af1240d55 100644 --- a/include/mim/lattice.h +++ b/include/mim/lattice.h @@ -28,7 +28,7 @@ class Bound : public Def { /// [lattice](https://en.wikipedia.org/wiki/Lattice_(order)) while a [Meet](@ref mim::Meet) descends. /// * @p Up = `true`: [Join](@ref mim::Join) (aka least Upper bound/supremum/union) /// * @p Up = `false`: [Meet](@ref mim::Meet) (aka greatest lower bound/infimum/intersection) -template class TBound : public Bound { +template class TBound : public Bound, public Setters> { private: TBound(const Def* type, Defs ops) : Bound(Node, type, ops) {} ///< Constructor for an *immutable* Bound. @@ -36,7 +36,7 @@ template class TBound : public Bound { : Bound(Node, type, size) {} ///< Constructor for a *mutable* Bound. public: - MIM_SETTERS(TBound) + using Setters>::set; TBound* stub(Ref type) { return stub_(world(), type)->set(dbg()); } @@ -51,43 +51,63 @@ template class TBound : public Bound { /// Constructs a [Meet](@ref mim::Meet) **value**. /// @remark [Ac](https://en.wikipedia.org/wiki/Wedge_(symbol)) is Latin and means *and*. -class Ac : public Def { +class Ac : public Def, public Setters { +public: + using Setters::set; + static constexpr auto Node = Node::Ac; + private: Ac(const Def* type, Defs defs) : Def(Node, type, defs, 0) {} - MIM_DEF_MIXIN(Ac) + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; /// Constructs a [Join](@ref mim::Join) **value**. /// @remark [Vel](https://en.wikipedia.org/wiki/Wedge_(symbol)) is Latin and means *or*. -class Vel : public Def { +class Vel : public Def, public Setters { private: Vel(const Def* type, const Def* value) : Def(Node, type, {value}, 0) {} public: + using Setters::set; + /// @name ops ///@{ const Def* value() const { return op(0); } ///@} - MIM_DEF_MIXIN(Vel) + static constexpr auto Node = Node::Vel; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; /// Picks the aspect of a Meet [value](Pick::value) by its [type](Def::type). -class Pick : public Def { +class Pick : public Def, public Setters { private: Pick(const Def* type, const Def* value) : Def(Node, type, {value}, 0) {} public: + using Setters::set; + /// @name ops ///@{ const Def* value() const { return op(0); } ///@} - MIM_DEF_MIXIN(Pick) + static constexpr auto Node = Node::Pick; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; /// Test whether Test::value currently holds **type** Test::probe: @@ -102,12 +122,15 @@ class Pick : public Def { /// * Test::match must be of type `A -> B`. /// * Test::clash must be of type `[A, probe] -> C`. /// @remark This operation is usually known as `case` but named `Test` since `case` is a keyword in C++. -class Test : public Def { +class Test : public Def, public Setters { private: Test(const Def* type, const Def* value, const Def* probe, const Def* match, const Def* clash) : Def(Node, type, {value, probe, match, clash}, 0) {} public: + using Setters::set; + static constexpr auto Node = Node::Test; + /// @name ops ///@{ const Def* value() const { return op(0); } @@ -116,7 +139,10 @@ class Test : public Def { const Def* clash() const { return op(3); } ///@} - MIM_DEF_MIXIN(Test) +private: + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; /// Common base for TExt%remum. @@ -127,13 +153,13 @@ class Ext : public Def { }; /// Ext%remum. Either Top (@p Up) or Bot%tom. -template class TExt : public Ext { +template class TExt : public Ext, public Setters> { private: TExt(const Def* type) : Ext(Node, type) {} public: - MIM_SETTERS(TExt) + using Setters>::set; TExt* stub(Ref type) { return stub_(world(), type)->set(dbg()); } @@ -157,18 +183,25 @@ using Join = TBound; /// A singleton wraps a type into a higher order type. /// Therefore any type can be the only inhabitant of a singleton. /// Use in conjunction with @ref mim::Join. -class Singleton : public Def { +class Singleton : public Def, public Setters { private: Singleton(const Def* type, const Def* inner_type) : Def(Node, type, {inner_type}, 0) {} public: + using Setters::set; + /// @name ops ///@{ const Def* inhabitant() const { return op(0); } ///@} - MIM_DEF_MIXIN(Singleton) + static constexpr auto Node = Node::Singleton; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; } // namespace mim diff --git a/include/mim/tuple.h b/include/mim/tuple.h index edd87a56d7..5ce5519ffc 100644 --- a/include/mim/tuple.h +++ b/include/mim/tuple.h @@ -6,7 +6,7 @@ namespace mim { /// A [dependent tuple type](https://en.wikipedia.org/wiki/Dependent_type#%CE%A3_type). /// @see Tuple, Arr, Pack -class Sigma : public Def { +class Sigma : public Def, public Setters { private: Sigma(const Def* type, Defs ops) : Def(Node, type, ops, 0) {} ///< Constructor for an *immutable* Sigma. @@ -17,14 +17,17 @@ class Sigma : public Def { /// @name Setters /// @see @ref set_ops "Setting Ops" ///@{ + using Setters::set; Sigma* set(size_t i, const Def* def) { return Def::set(i, def)->as(); } Sigma* set(Defs ops) { return Def::set(ops)->as(); } Sigma* unset() { return Def::unset()->as(); } ///@} + /// @name Rebuild + ///@{ const Def* immutabilize() override; - Sigma* stub_(World&, Ref) override; Sigma* stub(Ref type) { return stub_(world(), type)->set(dbg()); } + ///@} /// @name Type Checking ///@{ @@ -32,23 +35,35 @@ class Sigma : public Def { static Ref infer(World&, Defs); ///@} - MIM_DEF_MIXIN(Sigma) + static constexpr auto Node = Node::Sigma; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + Sigma* stub_(World&, Ref) override; + + friend class World; }; /// Data constructor for a Sigma. /// @see Sigma, Arr, Pack -class Tuple : public Def { +class Tuple : public Def, public Setters { +public: + using Setters::set; + static constexpr auto Node = Node::Tuple; + private: Tuple(const Def* type, Defs args) : Def(Node, type, args, 0) {} - MIM_DEF_MIXIN(Tuple) + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; /// A (possibly paramterized) Arr%ay. /// Arr%ays are usually homogenous but they can be *inhomogenous* as well: `«i: N; T#i»` /// @see Sigma, Tuple, Pack -class Arr : public Def { +class Arr : public Def, public Setters { private: Arr(const Def* type, const Def* shape, const Def* body) : Def(Node, type, {shape, body}, 0) {} ///< Constructor for an *immutable* Arr. @@ -63,29 +78,38 @@ class Arr : public Def { ///@} /// @name Setters - ///@{ /// @see @ref set_ops "Setting Ops" + ///@{ + using Setters::set; Arr* set_shape(const Def* shape) { return Def::set(0, shape)->as(); } Arr* set_body(const Def* body) { return Def::set(1, body)->as(); } Arr* unset() { return Def::unset()->as(); } ///@} - const Def* immutabilize() override; - Arr* stub_(World&, Ref) override; - Arr* stub(Ref type) { return stub_(world(), type)->set(dbg()); } + /// @name Rebuild + ///@{ const Def* reduce(const Def* arg) const; + Arr* stub(Ref type) { return stub_(world(), type)->set(dbg()); } + const Def* immutabilize() override; + ///@} /// @name Type Checking ///@{ void check() override; ///@} - MIM_DEF_MIXIN(Arr) + static constexpr auto Node = Node::Arr; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + Arr* stub_(World&, Ref) override; + + friend class World; }; /// A (possibly paramterized) Tuple. /// @see Sigma, Tuple, Arr -class Pack : public Def { +class Pack : public Def, public Setters { private: Pack(const Def* type, const Def* body) : Def(Node, type, {body}, 0) {} ///< Constructor for an *immutable* Pack. @@ -102,45 +126,63 @@ class Pack : public Def { /// @name Setters /// @see @ref set_ops "Setting Ops" ///@{ + using Setters::set; Pack* set(const Def* body) { return Def::set(0, body)->as(); } Pack* reset(const Def* body) { return unset()->set(body); } Pack* unset() { return Def::unset()->as(); } ///@} + /// @name Rebuild + ///@{ + const Def* reduce(const Def* arg) const; + Pack* stub(Ref type) { return stub_(world(), type)->set(dbg()); } const Def* immutabilize() override; + ///@} + + static constexpr auto Node = Node::Pack; + +private: + Ref rebuild_(World&, Ref, Defs) const override; Pack* stub_(World&, Ref) override; - Pack* stub(Ref type) { return stub_(world(), type)->set(dbg()); } - const Def* reduce(const Def* arg) const; - MIM_DEF_MIXIN(Pack) + friend class World; }; /// Extracts from a Sigma or Arr%ay-typed Extract::tuple the element at position Extract::index. -class Extract : public Def { +class Extract : public Def, public Setters { private: Extract(const Def* type, const Def* tuple, const Def* index) : Def(Node, type, {tuple, index}, 0) {} public: + using Setters::set; + /// @name ops ///@{ const Def* tuple() const { return op(0); } const Def* index() const { return op(1); } ///@} - MIM_DEF_MIXIN(Extract) + static constexpr auto Node = Node::Extract; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; /// Creates a new Tuple / Pack by inserting Insert::value at position Insert::index into Insert::tuple. /// @attention This is a *functional* Insert. /// The Insert::tuple itself remains untouched. /// The Insert itself is a *new* Tuple / Pack which contains the inserted Insert::value. -class Insert : public Def { +class Insert : public Def, public Setters { private: Insert(const Def* tuple, const Def* index, const Def* value) : Def(Node, tuple->type(), {tuple, index, value}, 0) {} public: + using Setters::set; + /// @name ops ///@{ const Def* tuple() const { return op(0); } @@ -148,7 +190,12 @@ class Insert : public Def { const Def* value() const { return op(2); } ///@} - MIM_DEF_MIXIN(Insert) + static constexpr auto Node = Node::Insert; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + + friend class World; }; /// @name Helpers to work with Tulpes/Sigmas/Arrays/Packs diff --git a/include/mim/world.h b/include/mim/world.h index 7b7619f60b..c1b27b7d07 100644 --- a/include/mim/world.h +++ b/include/mim/world.h @@ -457,7 +457,7 @@ class World { ///@} /// @name Globals - /// @deprecated { will be removed } + /// @deprecated Will be removed. ///@{ Global* global(Ref type, bool is_mutable = true) { return insert(1, type, is_mutable); } ///@} diff --git a/src/mim/def.cpp b/src/mim/def.cpp index 2ff8a76bee..6fc40af409 100644 --- a/src/mim/def.cpp +++ b/src/mim/def.cpp @@ -86,7 +86,6 @@ UMax::UMax(World& world, Defs ops) * rebuild */ -#ifndef DOXYGEN // TODO Doxygen doesn't expand MIM_DEF_MIXIN Ref Infer ::rebuild_(World&, Ref, Defs ) const { fe::unreachable(); } Ref Global ::rebuild_(World&, Ref, Defs ) const { fe::unreachable(); } Ref Idx ::rebuild_(World& w, Ref , Defs ) const { return w.type_idx(); } @@ -121,7 +120,6 @@ Ref Axiom ::rebuild_(World& w, Ref t, Defs ) const { template Ref TExt ::rebuild_(World& w, Ref t, Defs ) const { return w.ext (t)->set(dbg()); } template Ref TBound::rebuild_(World& w, Ref , Defs o) const { return w.bound(o)->set(dbg()); } -#endif /* * stub From 18504121893f55f3690a0c49407ec45f6fef81a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Mon, 21 Oct 2024 02:16:10 +0200 Subject: [PATCH 2/7] remove MIM_ENUM_OPERATORS macro magic in favor of fe::BitEnum --- docs/Doxyfile.in | 1 - external/fe | 2 +- include/mim/def.h | 18 +++++++++++++++--- include/mim/plug/core/core.h | 6 ++++-- include/mim/plug/math/math.h | 6 ++++-- include/mim/util/util.h | 20 -------------------- src/mim/ast/ast.cpp | 20 +++++++++++++++----- 7 files changed, 39 insertions(+), 34 deletions(-) diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 71774214a4..18d098791f 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -2518,7 +2518,6 @@ EXPAND_AS_DEFINED = CODE \ CODE2 \ CODE3 \ CODE4 \ - MIM_ENUM_OPERATORS \ MIM_1_8_16_32_64 \ MIM_8_16_32_64 \ MIM_16_32_64 \ diff --git a/external/fe b/external/fe index 528a0db8f1..edc9985cbf 160000 --- a/external/fe +++ b/external/fe @@ -1 +1 @@ -Subproject commit 528a0db8f1810cd58f996cb34ec0b7dd8f16bc6e +Subproject commit edc9985cbf2c718a5364f4f2dc6b69324978c0c4 diff --git a/include/mim/def.h b/include/mim/def.h index 18604f10fc..8807d0dc99 100644 --- a/include/mim/def.h +++ b/include/mim/def.h @@ -4,6 +4,7 @@ #include #include +#include #include "mim/config.h" @@ -77,7 +78,7 @@ template using VarMap = GIDMap; using VarSet = GIDSet; using Var2Var = VarMap; using Vars = PooledSet; -///@{ +///@} //------------------------------------------------------------------------------ @@ -139,6 +140,12 @@ enum class Sort { Term, Type, Kind, Space, Univ, Level }; //------------------------------------------------------------------------------ +using fe::operator&; +using fe::operator|; +using fe::operator^; +using fe::operator<=>; +using fe::operator==; + /// @name Dep ///@{ enum class Dep : unsigned { @@ -149,10 +156,15 @@ enum class Dep : unsigned { Proxy = 1 << 3, Var = 1 << 4, }; - -MIM_ENUM_OPERATORS(Dep) ///@} +} // namespace mim +#ifndef DOXYGEN +template<> struct fe::is_bit_enum : std::true_type {}; +#endif + +namespace mim { + /// Use as mixin to wrap all kind of Def::proj and Def::projs variants. #define MIM_PROJ(NAME, CONST) \ nat_t num_##NAME##s() CONST { return ((const Def*)NAME())->num_projs(); } \ diff --git a/include/mim/plug/core/core.h b/include/mim/plug/core/core.h index 99aca813ec..5f3b667d48 100644 --- a/include/mim/plug/core/core.h +++ b/include/mim/plug/core/core.h @@ -17,8 +17,6 @@ enum class Mode : nat_t { nusw = nuw | nsw, }; -MIM_ENUM_OPERATORS(Mode) - /// Give Mode as mim::plug::math::Mode, mim::nat_t or Ref. using VMode = std::variant; @@ -129,3 +127,7 @@ constexpr bool is_associative(plug::core::wrap id) { return is_commutative(id); ///@} } // namespace mim + +#ifndef DOXYGEN +template<> struct fe::is_bit_enum : std::true_type {}; +#endif diff --git a/include/mim/plug/math/math.h b/include/mim/plug/math/math.h index c6455057db..796f3cfb64 100644 --- a/include/mim/plug/math/math.h +++ b/include/mim/plug/math/math.h @@ -39,8 +39,6 @@ enum class Mode : nat_t { }; // clang-format on -MIM_ENUM_OPERATORS(Mode) - /// Give Mode as mim::plug::math::Mode, mim::nat_t or Ref. using VMode = std::variant; @@ -132,3 +130,7 @@ constexpr bool is_associative(plug::math::arith id) { return is_commutative(id); ///@} } // namespace mim + +#ifndef DOXYGEN +template<> struct fe::is_bit_enum : std::true_type {}; +#endif diff --git a/include/mim/util/util.h b/include/mim/util/util.h index 40ef7fbe71..4562d257e2 100644 --- a/include/mim/util/util.h +++ b/include/mim/util/util.h @@ -182,24 +182,4 @@ template using GIDNodeMap = absl::node_hash_map using GIDNodeSet = absl::node_hash_set, GIDEq>; ///@} -/// Use this to declare all kind of bit and comparison operators for an `enum` @p E. -/// Note that the bit operators return @p E's underlying type and not the original `enum` @p E. -/// This is because the result may not be a valid `enum` value. -/// For the same reason, it doesn't make sense to declare operators such as `&=`. -#define MIM_ENUM_OPERATORS(E) \ - constexpr auto operator&( E x, E y) { return std::underlying_type_t(x) & std::underlying_type_t(y); } \ - constexpr auto operator&(std::underlying_type_t x, E y) { return x & std::underlying_type_t(y); } \ - constexpr auto operator&( E x, std::underlying_type_t y) { return std::underlying_type_t(x) & y ; } \ - constexpr auto operator|( E x, E y) { return std::underlying_type_t(x) | std::underlying_type_t(y); } \ - constexpr auto operator|(std::underlying_type_t x, E y) { return x | std::underlying_type_t(y); } \ - constexpr auto operator|( E x, std::underlying_type_t y) { return std::underlying_type_t(x) | y ; } \ - constexpr auto operator^( E x, E y) { return std::underlying_type_t(x) ^ std::underlying_type_t(y); } \ - constexpr auto operator^(std::underlying_type_t x, E y) { return x ^ std::underlying_type_t(y); } \ - constexpr auto operator^( E x, std::underlying_type_t y) { return std::underlying_type_t(x) ^ y ; } \ - constexpr std::strong_ordering operator<=>(std::underlying_type_t x, E y) { return x <=> std::underlying_type_t(y); } \ - constexpr std::strong_ordering operator<=>(E x, std::underlying_type_t y) { return std::underlying_type_t(x) <=> y; } \ - constexpr bool operator==(std::underlying_type_t x, E y) { return x == std::underlying_type_t(y); } \ - constexpr bool operator==(E x, std::underlying_type_t y) { return std::underlying_type_t(x) == y; } -// clang-format on - } // namespace mim diff --git a/src/mim/ast/ast.cpp b/src/mim/ast/ast.cpp index de0d15a0a4..a7f165d112 100644 --- a/src/mim/ast/ast.cpp +++ b/src/mim/ast/ast.cpp @@ -99,7 +99,6 @@ void AST::bootstrap(Sym plugin, std::ostream& h) { --tab; tab.print(h, "}};\n\n"); - if (!annex.subs.empty()) tab.print(h, "MIM_ENUM_OPERATORS({})\n", sym.tag); print(outer_namespace.emplace_back(), "template<> constexpr size_t Annex::Num = {};\n", plugin, sym.tag, annex.subs.size()); if (auto norm = annex.normalizer) { @@ -127,19 +126,30 @@ void AST::bootstrap(Sym plugin, std::ostream& h) { tab.print(h, "}} // namespace plug::{}\n\n", plugin); - tab.print(h, "#ifndef DOXYGEN // don't include in Doxygen documentation\n"); + tab.print(h, "#ifndef DOXYGEN // don't include in Doxygen documentation\n\n"); for (const auto& line : outer_namespace) tab.print(h, "{}", line.str()); tab.print(h, "\n"); // emit helpers for non-function axiom for (const auto& [tag, ax] : infos) { - const auto& sym = ax.sym; + auto sym = ax.sym; if (ax.is_pi() || sym.plugin != plugin) continue; // from function or other plugin? tab.print(h, "template<> struct Axiom::Match {{ using type = Axiom; }};\n", sym.plugin, sym.tag); } - tab.print(h, "#endif\n"); - tab.print(h, "}} // namespace mim\n"); + tab.print(h, "\n#endif\n"); + tab.print(h, "}} // namespace mim\n\n"); + + tab.print(h, "#ifndef DOXYGEN // don't include in Doxygen documentation\n\n"); + for (const auto& [key, annex] : infos) { + if (!annex.subs.empty()) { + auto sym = annex.sym; + tab.print(h, "template<> struct fe::is_bit_enum : std::true_type {{}};\n", sym.plugin, + sym.tag); + } + } + + tab.print(h, "\n#endif\n"); } /* From 17c32e5dd4d8f8c9a9ec7f645d6daf00157e3f15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Mon, 21 Oct 2024 22:17:03 +0200 Subject: [PATCH 3/7] Setters: remove unsafe cast to (Def*) --- include/mim/def.h | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/include/mim/def.h b/include/mim/def.h index 8807d0dc99..71cdb0fecc 100644 --- a/include/mim/def.h +++ b/include/mim/def.h @@ -182,27 +182,25 @@ namespace mim { auto NAME##s(nat_t a) CONST { return ((const Def*)NAME())->projs(a); } /// CRTP-based Mixin to declare setters for Def::loc \& Def::name using a *covariant* return type. -template class Setters { +template class Setters { // D is only needed to make the resolution `D::template set` lazy private: P* super() { return static_cast(this); } const P* super() const { return static_cast(this); } - Def* def() { return (Def*)this; } - const Def* def() const { return (const Def*)this; } public: // clang-format off - template const P* set(Loc l ) const { def()->template set(l); return super(); } - template P* set(Loc l ) { def()->template set(l); return super(); } - template const P* set( Sym s ) const { def()->template set(s); return super(); } - template P* set( Sym s ) { def()->template set(s); return super(); } - template const P* set( std::string s) const { def()->template set(std::move(s)); return super(); } - template P* set( std::string s) { def()->template set(std::move(s)); return super(); } - template const P* set(Loc l, Sym s ) const { def()->template set(l, s); return super(); } - template P* set(Loc l, Sym s ) { def()->template set(l, s); return super(); } - template const P* set(Loc l, std::string s) const { def()->template set(l, std::move(s)); return super(); } - template P* set(Loc l, std::string s) { def()->template set(l, std::move(s)); return super(); } - template const P* set(Dbg d ) const { def()->template set(d); return super(); } - template P* set(Dbg d ) { def()->template set(d); return super(); } + template const P* set(Loc l ) const { super()->D::template set(l); return super(); } + template P* set(Loc l ) { super()->D::template set(l); return super(); } + template const P* set( Sym s ) const { super()->D::template set(s); return super(); } + template P* set( Sym s ) { super()->D::template set(s); return super(); } + template const P* set( std::string s) const { super()->D::template set(std::move(s)); return super(); } + template P* set( std::string s) { super()->D::template set(std::move(s)); return super(); } + template const P* set(Loc l, Sym s ) const { super()->D::template set(l, s); return super(); } + template P* set(Loc l, Sym s ) { super()->D::template set(l, s); return super(); } + template const P* set(Loc l, std::string s) const { super()->D::template set(l, std::move(s)); return super(); } + template P* set(Loc l, std::string s) { super()->D::template set(l, std::move(s)); return super(); } + template const P* set(Dbg d ) const { super()->D::template set(d); return super(); } + template P* set(Dbg d ) { super()->D::template set(d); return super(); } // clang-format on }; @@ -221,7 +219,7 @@ template class Setters { /// ``` /// @attention This means that any subclass of Def **must not** introduce additional members. /// @see @ref mut -class Def : public fe::RuntimeCast, public Setters { +class Def : public fe::RuntimeCast { private: Def& operator=(const Def&) = delete; Def(const Def&) = delete; From 78957e6d6982891e620b639a9cae7d7773a9da89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Mon, 21 Oct 2024 23:19:50 +0200 Subject: [PATCH 4/7] fe: version bump for enum --- external/fe | 2 +- include/mim/lam.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/external/fe b/external/fe index edc9985cbf..634ec3ea35 160000 --- a/external/fe +++ b/external/fe @@ -1 +1 @@ -Subproject commit edc9985cbf2c718a5364f4f2dc6b69324978c0c4 +Subproject commit 634ec3ea350683b1d9de12831016350722210e51 diff --git a/include/mim/lam.h b/include/mim/lam.h index 0d8ef9a1e7..545c09b8cb 100644 --- a/include/mim/lam.h +++ b/include/mim/lam.h @@ -94,7 +94,6 @@ class Pi : public Def, public Setters { private: Ref rebuild_(World&, Ref, Defs) const override; Pi* stub_(World&, Ref) override; - ; friend class World; }; From 80792e14fc4200490abd2ef4c248466bda862163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Mon, 21 Oct 2024 23:28:34 +0200 Subject: [PATCH 5/7] fe: bump --- external/fe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/fe b/external/fe index 634ec3ea35..59b1152701 160000 --- a/external/fe +++ b/external/fe @@ -1 +1 @@ -Subproject commit 634ec3ea350683b1d9de12831016350722210e51 +Subproject commit 59b11527013753bdc0d8c203ccfc86ec3299cb7c From dca5ceb64d5f2070e01e3b13361c05465d11687f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Mon, 21 Oct 2024 23:43:59 +0200 Subject: [PATCH 6/7] missing using fe::operator!= --- external/fe | 2 +- include/mim/def.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/external/fe b/external/fe index 59b1152701..5b02c51066 160000 --- a/external/fe +++ b/external/fe @@ -1 +1 @@ -Subproject commit 59b11527013753bdc0d8c203ccfc86ec3299cb7c +Subproject commit 5b02c51066c3f42c1822afb54c0e4aa738df6f07 diff --git a/include/mim/def.h b/include/mim/def.h index 71cdb0fecc..913bae4fee 100644 --- a/include/mim/def.h +++ b/include/mim/def.h @@ -145,6 +145,7 @@ using fe::operator|; using fe::operator^; using fe::operator<=>; using fe::operator==; +using fe::operator!=; /// @name Dep ///@{ From 678c714b760729222b9980bb70c69709f40ac2d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 22 Oct 2024 00:03:04 +0200 Subject: [PATCH 7/7] fe: bug fix bump --- external/fe | 2 +- lit/autodiff/multiply_autodiff_cond.mim | 1 - lit/fun.mim | 11 ++++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/external/fe b/external/fe index 5b02c51066..f2a13d1194 160000 --- a/external/fe +++ b/external/fe @@ -1 +1 @@ -Subproject commit 5b02c51066c3f42c1822afb54c0e4aa738df6f07 +Subproject commit f2a13d119423709fc9f22469e28b95281bea0846 diff --git a/lit/autodiff/multiply_autodiff_cond.mim b/lit/autodiff/multiply_autodiff_cond.mim index 9b3a8374e4..a768dc23e0 100644 --- a/lit/autodiff/multiply_autodiff_cond.mim +++ b/lit/autodiff/multiply_autodiff_cond.mim @@ -4,7 +4,6 @@ plugin core; plugin autodiff; - fun f(a: I32): I32 = let cmp = %core.icmp.sle (a,5I32); (twice,thrice)#cmp () diff --git a/lit/fun.mim b/lit/fun.mim index 81b50de9d3..f202710a5c 100644 --- a/lit/fun.mim +++ b/lit/fun.mim @@ -15,15 +15,15 @@ fun extern main(mem: %mem.M, argc: I32, argv: Ptr (Ptr I8)): [%mem.M, I32] = lam f1(T: *)((x y: T), return: T → ⊥): ⊥ = return x; con f2(T: *)((x y: T), return: Cn T) = return x; -fun f3(T: *) (x y: T) = return x; +fun f3(T: *) (x y: T) = return x; let g1 = lm (T: *)((x y: T), return: T → ⊥): ⊥ = return x; -let g2 = cn (T: *)((x y: T), return: Cn T) = return x; -let g3 = fn (T: *) (x y: T) = return x; +let g2 = cn (T: *)((x y: T), return: Cn T) = return x; +let g3 = fn (T: *) (x y: T) = return x; let F1 = [T:*] [T, T] [T → ⊥] → ⊥; -let F2 =Cn [T:*] [T, T] [Cn T]; -let F3 =Fn [T:*] [T, T] → T; +let F2 = Cn [T:*] [T, T] [Cn T]; +let F3 = Fn [T:*] [T, T] → T; fun bar(cond: Bool): Nat = con t() = @@ -32,4 +32,5 @@ fun bar(cond: Bool): Nat = con f() = f1 Nat ((23, 42), cn res: Nat = return res); (f, t)#cond (); + // CHECK-DAG: return{{.*}}48