
class Declaration;

/** Interface for HILTI declarations. */
class Concept : public hilti::util::type_erasure::ConceptBase {
public:
    Concept() = default;
    Concept(const Concept&) = default;
    Concept(Concept&&) = default;
    virtual ~Concept() = default;
    /** Returns the declaration's ID. */
    virtual ID id() const = 0;
    /** Returns the declaration's linkage. */
    virtual Linkage linkage() const = 0;
    /**
* Returns true if one cannot assign to what this declaration defines.
*/
    virtual bool isConstant() const = 0;
    /**
* Returns the canonical ID associated with the declaration. Canonical IDs
* are automatically computed during AST processing and guaranteed to be
* globally unique and stable across runs.
*/
    virtual const ID& canonicalID() const = 0;
    /**
* Associates a canonical ID with the declaration. To be called from AST
* processing.
*/
    virtual void setCanonicalID(ID id)  = 0;
    /**
* Returns a user-friendly name for the type of object the declaration
* refers to. This is used in error messages.
*/
    virtual std::string displayName() const = 0;
    /** Returns the documentation associated with the declaration, if any. */
    virtual const std::optional<DocString>& documentation() const = 0;
    /** Sets the documentation associated with the declaration. */
    virtual void setDocumentation(DocString doc)  = 0;
    /**
* Returns true if the declaration is equivalent to another one in HILTI
* semantics.
*/
    virtual bool isEqual(const hilti::Declaration& other) const = 0;
    /** Implements the `Node` interface. */
    virtual hilti::node::Properties properties() const = 0;
    /** Implements the `Node` interface. */
    virtual const std::vector<hilti::Node>& children() const = 0;
    /** Implements the `Node` interface. */
    virtual std::vector<hilti::Node>& children()  = 0;
    /** Implements the `Node` interface. */
    virtual const Meta& meta() const = 0;
    /** Implements the `Node` interface. */
    virtual void setMeta(Meta m)  = 0;
    /** Implements the `Node` interface. */
    virtual bool pruneWalk() const = 0;
    Concept& operator=(const Concept&) = default;
    Concept& operator=(Concept&&) = default;
    virtual Declaration _clone() const = 0;
    virtual hilti::IntrusivePtr<Concept> _clone_ptr() const = 0;
private:
    
};

template<typename T>
using ModelBase = hilti::util::type_erasure::ModelBase<T, Concept>;

template<class T>
class Model : public ModelBase<T> {
public:
    using ModelBase<T>::ModelBase;
    using ModelBase<T>::data;

    ID id() const final;
    Linkage linkage() const final;
    bool isConstant() const final;
    const ID& canonicalID() const final;
    void setCanonicalID(ID id)  final;
    std::string displayName() const final;
    const std::optional<DocString>& documentation() const final;
    void setDocumentation(DocString doc)  final;
    bool isEqual(const hilti::Declaration& other) const final;
    hilti::node::Properties properties() const final;
    const std::vector<hilti::Node>& children() const final;
    std::vector<hilti::Node>& children()  final;
    const Meta& meta() const final;
    void setMeta(Meta m)  final;
    bool pruneWalk() const final;
    Declaration _clone() const final;
    hilti::IntrusivePtr<Concept> _clone_ptr() const final;
};

using ErasedBase = hilti::util::type_erasure::ErasedBase<trait::isDeclaration, Concept, Model>;

class Declaration : public ErasedBase, public trait::isNode {
public:
    using ErasedBase::ErasedBase;

    Declaration() noexcept = default;
    Declaration(Declaration&&) noexcept = default;
    Declaration& operator=(Declaration&&) = default;
    ~Declaration() override = default;
    Declaration(const Declaration& other) = default;
    Declaration& operator=(const Declaration& other) = default;

    ID id() const;
    Linkage linkage() const;
    bool isConstant() const;
    const ID& canonicalID() const;
    void setCanonicalID(ID id) ;
    std::string displayName() const;
    const std::optional<DocString>& documentation() const;
    void setDocumentation(DocString doc) ;
    bool isEqual(const hilti::Declaration& other) const;
    hilti::node::Properties properties() const;
    const std::vector<hilti::Node>& children() const;
    std::vector<hilti::Node>& children() ;
    const Meta& meta() const;
    void setMeta(Meta m) ;
    bool pruneWalk() const;
    Declaration _clone() const;

    hilti::IntrusivePtr<Concept> _clone_ptr() const;

protected:
    
};

template<typename T>
ID Model<T>::id() const { return data().id(); }

template<typename T>
Linkage Model<T>::linkage() const { return data().linkage(); }

template<typename T>
bool Model<T>::isConstant() const { return data().isConstant(); }

template<typename T>
const ID& Model<T>::canonicalID() const { return data().canonicalID(); }

template<typename T>
void Model<T>::setCanonicalID(ID id)  { return data().setCanonicalID(id); }

template<typename T>
std::string Model<T>::displayName() const { return data().displayName(); }

template<typename T>
const std::optional<DocString>& Model<T>::documentation() const { return data().documentation(); }

template<typename T>
void Model<T>::setDocumentation(DocString doc)  { return data().setDocumentation(doc); }

template<typename T>
bool Model<T>::isEqual(const hilti::Declaration& other) const { return data().isEqual(other); }

template<typename T>
hilti::node::Properties Model<T>::properties() const { return data().properties(); }

template<typename T>
const std::vector<hilti::Node>& Model<T>::children() const { return data().children(); }

template<typename T>
std::vector<hilti::Node>& Model<T>::children()  { return data().children(); }

template<typename T>
const Meta& Model<T>::meta() const { return data().meta(); }

template<typename T>
void Model<T>::setMeta(Meta m)  { return data().setMeta(m); }

template<typename T>
bool Model<T>::pruneWalk() const { return data().pruneWalk(); }

template<typename T>
Declaration Model<T>::_clone() const { return T(data()); }

template<typename T>
hilti::IntrusivePtr<Concept> Model<T>::_clone_ptr() const {
    if constexpr ( std::is_base_of<hilti::util::type_erasure::trait::Singleton, T>::value )
        return nullptr;
    else
        return hilti::make_intrusive<Model>(T(data()));
}

inline ID Declaration::id() const { return data()->id(); }

inline Linkage Declaration::linkage() const { return data()->linkage(); }

inline bool Declaration::isConstant() const { return data()->isConstant(); }

inline const ID& Declaration::canonicalID() const { return data()->canonicalID(); }

inline void Declaration::setCanonicalID(ID id)  { return data()->setCanonicalID(std::move(id)); }

inline std::string Declaration::displayName() const { return data()->displayName(); }

inline const std::optional<DocString>& Declaration::documentation() const { return data()->documentation(); }

inline void Declaration::setDocumentation(DocString doc)  { return data()->setDocumentation(std::move(doc)); }

inline bool Declaration::isEqual(const hilti::Declaration& other) const { return data()->isEqual(other); }

inline hilti::node::Properties Declaration::properties() const { return data()->properties(); }

inline const std::vector<hilti::Node>& Declaration::children() const { return data()->children(); }

inline std::vector<hilti::Node>& Declaration::children()  { return data()->children(); }

inline const Meta& Declaration::meta() const { return data()->meta(); }

inline void Declaration::setMeta(Meta m)  { return data()->setMeta(std::move(m)); }

inline bool Declaration::pruneWalk() const { return data()->pruneWalk(); }

inline Declaration Declaration::_clone() const { return data() ? data()->_clone() : Declaration(); }

inline hilti::IntrusivePtr<Concept> Declaration::_clone_ptr() const {
    if ( data() )
        return data()->_clone_ptr();
    else
        return nullptr;
}



