#ifndef TYPES_HPP_INCLUDED #define TYPES_HPP_INCLUDED #include #include "common.hpp" #include "coretypes.hpp" #include "ast/path.hpp" #include #include namespace AST { class ExprNode; class Expr; } class PrettyPrintType { const TypeRef& m_type; public: PrettyPrintType(const TypeRef& ty): m_type(ty) {} void print(::std::ostream& os) const; friend ::std::ostream& operator<<(::std::ostream& os, const PrettyPrintType& v); }; struct TypeArgRef { ::std::string name; unsigned int level; const AST::GenericParams* params; }; struct Type_Function: public Serialisable { bool is_unsafe; ::std::string m_abi; ::std::unique_ptr m_rettype; ::std::vector m_arg_types; Type_Function() {} Type_Function(bool is_unsafe, ::std::string abi, ::std::unique_ptr ret, ::std::vector args): is_unsafe(is_unsafe), m_abi(abi), m_rettype(mv$(ret)), m_arg_types(mv$(args)) {} Type_Function(const Type_Function& other); Ordering ord(const Type_Function& x) const; SERIALISABLE_PROTOTYPES(); }; TAGGED_UNION(TypeData, None, (None, ()), (Any, ()), (Unit, ()), (Primitive, ( enum eCoreType core_type; )), (Function, ( Type_Function info; )), (Tuple, ( ::std::vector inner_types; )), (Borrow, ( bool is_mut; ::std::unique_ptr inner; )), (Pointer, ( bool is_mut; ::std::unique_ptr inner; )), (Array, ( ::std::unique_ptr inner; ::std::shared_ptr size; )), (Generic, ( ::std::string name; unsigned int level; const ::AST::GenericParams* params; )), (Path, ( AST::Path path; )), (TraitObject, ( ::std::vector<::std::string> hrls; ::std::vector traits; )) ); /// A type class TypeRef: public Serialisable { public: TypeData m_data; TypeRef(TypeRef&& other) noexcept: //m_span( mv$(other.m_span) ), m_data( mv$(other.m_data) ) {} TypeRef(const TypeRef& other) { switch( other.m_data.tag() ) { #define _COPY(VAR) case TypeData::TAG_##VAR: m_data = TypeData::make_##VAR(other.m_data.as_##VAR()); break; #define _CLONE(VAR, code...) case TypeData::TAG_##VAR: { auto& old = other.m_data.as_##VAR(); m_data = TypeData::make_##VAR(code); } break; _COPY(None) _COPY(Any) _COPY(Unit) _COPY(Primitive) _COPY(Function) _COPY(Tuple) _CLONE(Borrow, { old.is_mut, box$(TypeRef(*old.inner)) }) _CLONE(Pointer, { old.is_mut, box$(TypeRef(*old.inner)) }) _CLONE(Array, { box$(TypeRef(*old.inner)), old.size }) _COPY(Generic) _COPY(Path) _COPY(TraitObject) #undef _COPY #undef _CLONE } } TypeRef& operator=(const TypeRef& other) { m_data = TypeRef(other).m_data; return *this; } TypeRef(): m_data(TypeData::make_Any({})) {} struct TagInvalid {}; TypeRef(TagInvalid): m_data(TypeData::make_None({})) {} struct TagUnit {}; // unit maps to a zero-length tuple, just easier to type TypeRef(TagUnit): m_data(TypeData::make_Unit({})) {} struct TagPrimitive {}; TypeRef(TagPrimitive, enum eCoreType type): m_data(TypeData::make_Primitive({type})) {} TypeRef(enum eCoreType type): m_data(TypeData::make_Primitive({type})) {} struct TagTuple {}; TypeRef(TagTuple _, ::std::vector inner_types): m_data(TypeData::make_Tuple({::std::move(inner_types)})) {} struct TagFunction {}; TypeRef(TagFunction, ::std::string abi, ::std::vector args, TypeRef ret): m_data(TypeData::make_Function({ Type_Function( false, abi, box$(ret), mv$(args) ) })) {} struct TagReference {}; TypeRef(TagReference _, bool is_mut, TypeRef inner_type): m_data(TypeData::make_Borrow({ is_mut, ::make_unique_ptr(mv$(inner_type)) })) {} struct TagPointer {}; TypeRef(TagPointer _, bool is_mut, TypeRef inner_type): m_data(TypeData::make_Pointer({ is_mut, ::make_unique_ptr(mv$(inner_type)) })) {} struct TagSizedArray {}; TypeRef(TagSizedArray _, TypeRef inner_type, ::std::shared_ptr size): m_data(TypeData::make_Array({ ::make_unique_ptr(mv$(inner_type)), mv$(size) })) {} struct TagUnsizedArray {}; TypeRef(TagUnsizedArray _, TypeRef inner_type): m_data(TypeData::make_Array({ ::make_unique_ptr(mv$(inner_type)), ::std::shared_ptr() })) {} struct TagArg {}; TypeRef(TagArg, ::std::string name): m_data(TypeData::make_Generic({ name, 0, nullptr })) {} TypeRef(TagArg, ::std::string name, const AST::GenericParams& params): m_data(TypeData::make_Generic({ name, 0, ¶ms })) {} TypeRef(::std::string name): TypeRef(TagArg(), ::std::move(name)) {} struct TagPath {}; TypeRef(TagPath, AST::Path path): m_data(TypeData::make_Path({ ::std::move(path) })) {} TypeRef(AST::Path path): TypeRef(TagPath(), ::std::move(path)) {} TypeRef( ::std::vector<::std::string> hrls, ::std::vector traits ): m_data(TypeData::make_TraitObject({ mv$(hrls), ::std::move(traits) })) {} /// Dereference the type (return the result of *type_instance) bool deref(bool is_implicit); /// Merge with another type (combines known aspects, conflitcs cause an exception) void merge_with(const TypeRef& other); /// Replace 'GENERIC' entries with the return value of the closure void resolve_args(::std::function fcn); /// Match 'GENERIC' entries with another type, passing matches to a closure void match_args(const TypeRef& other, ::std::function fcn) const; bool impls_wildcard(const AST::Crate& crate, const AST::Path& trait) const; /// Returns true if the type is fully known (all sub-types are not wildcards) bool is_concrete() const; bool is_unbounded() const { return m_data.is_Any(); } bool is_wildcard() const { return m_data.is_Any(); } bool is_unit() const { return m_data.is_Unit(); } bool is_primitive() const { return m_data.is_Primitive(); } bool is_path() const { return m_data.is_Path(); } const AST::Path& path() const { return m_data.as_Path().path; } AST::Path& path() { return m_data.as_Path().path; } bool is_type_param() const { return m_data.is_Generic(); } const ::std::string& type_param() const { return m_data.as_Generic().name; } void set_type_params_ptr(const AST::GenericParams& p) { m_data.as_Generic().params = &p; }; const AST::GenericParams* type_params_ptr() const { return reinterpret_cast( m_data.as_Generic().params ); } bool is_reference() const { return m_data.is_Borrow(); } bool is_pointer() const { return m_data.is_Pointer(); } bool is_tuple() const { return m_data.is_Tuple(); } //::option as_tuple() const { // switch(m_data.tag()) // { // } //} const TypeRef& inner_type() const { TU_MATCH_DEF(TypeData, (m_data), (e), ( throw ::std::runtime_error("Called inner_type on non-wrapper"); ), (Borrow, return *e.inner; ), (Pointer, return *e.inner; ), (Array, return *e.inner; ) ) } TypeRef& inner_type() { TU_MATCH_DEF(TypeData, (m_data), (e), ( throw ::std::runtime_error("Called inner_type on non-wrapper"); ), (Borrow, return *e.inner; ), (Pointer, return *e.inner; ), (Array, return *e.inner; ) ) } //::std::vector& sub_types() { return m_inner_types; } //const ::std::vector& sub_types() const { return m_inner_types; } //void add_trait(TypeRef trait) { assert(is_wildcard()); m_inner_types.push_back( ::std::move(trait) ); } //const ::std::vector& traits() const { assert(is_wildcard()); return m_inner_types; } /// Returns 0 if types are identical, 1 if TypeRef::TagArg is present in one, and -1 if form differs int equal_no_generic(const TypeRef& x) const; Ordering ord(const TypeRef& x) const; bool operator==(const TypeRef& x) const { return ord(x) == OrdEqual; } bool operator!=(const TypeRef& x) const { return ord(x) != OrdEqual; } bool operator<(const TypeRef& x) const { return ord(x) == OrdLess; }; PrettyPrintType print_pretty() const { return PrettyPrintType(*this); } friend class PrettyPrintType; friend ::std::ostream& operator<<(::std::ostream& os, const TypeRef& tr); static ::std::unique_ptr from_deserialiser(Deserialiser& s); SERIALISABLE_PROTOTYPES(); }; #endif // TYPES_HPP_INCLUDED