Yume
type_base.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "qualifier.hpp"
5#include "util.hpp"
6
7namespace yume {
8struct Substitutions;
9} // namespace yume
10
11namespace yume::ty {
12class Type;
13
14enum Kind {
15 K_Unknown, ///< `UnknownType`, default, zero value. Hopefully never encountered!
16 K_Int, ///< `Int`
17 K_Nil, ///< `Nil`
18 K_Ptr, ///< `Ptr`
19 K_Struct, ///< `Struct`
20 K_Function, ///< `Function`
21 K_Generic, ///< `Generic`
22 K_OpaqueSelf, ///< `OpaqueSelf`
23 K_Meta, ///< `Meta`
24};
25
26/// Represents a type in the type system.
27/// NOTE: that this isn't the class to use for type introspection, for that, `Type` should be used instead as it is
28/// fully qualified.
29///
30/// All kinds of types inherit from this class. Similar to `AST` nodes, `Type`s cannot be copied or moved as all special
31/// member functions (aside from the destructor) are `delete`d.
32///
33/// There will always be one instance of a `Type` object for a specific type. This means that comparing if two types are
34/// the same type is simply a pointer equality check.
35///
36/// The single instance of most types is located in `TypeHolder`, however "qualified" types are instead stored in
37/// instances of `Type`. A "qualified" type is, for example, `mut`. These qualifiers do not stack. Getting the "mut"
38/// reference to a mutable reference should be itself.
39///
40/// Also, pointer-like types are also not held in `TypeHolder`, and are instead stored in the `m_known_...` fields
41/// of their pointee type.
42class BaseType {
43 mutable unique_ptr<BaseType> m_known_ptr{};
44 mutable unique_ptr<BaseType> m_known_opaque_self{};
45 mutable unique_ptr<BaseType> m_known_meta{};
46 const Kind m_kind;
47 string m_name;
48
49 friend Type;
50
51public:
52 BaseType(const BaseType&) noexcept = delete;
53 BaseType(BaseType&&) noexcept = delete;
54 auto operator=(const BaseType&) noexcept -> BaseType& = delete;
55 auto operator=(BaseType&&) noexcept -> BaseType& = delete;
56 virtual ~BaseType() = default;
57 [[nodiscard]] auto kind() const -> Kind { return m_kind; };
58 [[nodiscard]] auto base_name() const -> string { return m_name; };
59 [[nodiscard]] virtual auto name() const -> string = 0;
60
61protected:
62 BaseType(Kind kind, string name) : m_kind(kind), m_name(move(name)) {}
63};
64
65/// A "qualified" type, with a non-stackable qualifier, \e i.e. `mut`.
66class Type {
68 bool m_mut{};
69 bool m_ref{};
70
71public:
72 Type(nonnull<const BaseType*> base, bool mut, bool ref) noexcept : m_base(base), m_mut(mut), m_ref(ref) {}
73 Type(nonnull<const BaseType*> base) noexcept : m_base(base) {}
74
75 auto operator<=>(const Type&) const noexcept = default;
76 [[nodiscard]] auto opaque_equal(const Type& other) const noexcept -> bool;
77
78 [[nodiscard]] auto kind() const noexcept -> Kind { return m_base->kind(); };
79 [[nodiscard]] auto base() const noexcept -> nonnull<const BaseType*> { return m_base; }
80 template <typename T> [[nodiscard]] auto base_cast() const noexcept -> nonnull<const T*> { return cast<T>(m_base); }
81 template <typename T> [[nodiscard]] auto base_dyn_cast() const noexcept -> nullable<const T*> {
82 return dyn_cast<T>(m_base);
83 }
84 template <typename T> [[nodiscard]] auto try_as() const noexcept -> optional<Type> {
85 const auto* cast = dyn_cast<T>(m_base);
86 if (cast)
87 return {cast};
88 return std::nullopt;
89 }
90 template <typename T> [[nodiscard]] auto base_isa() const noexcept -> bool { return isa<T>(m_base); }
91 [[nodiscard, deprecated]] auto has_qualifier(Qualifier qual) const -> bool;
92 [[nodiscard]] auto name() const -> string;
93 [[nodiscard]] auto base_name() const -> string;
94
95 [[nodiscard]] auto determine_generic_subs(Type generic, const Substitutions& subs) const -> optional<Substitutions>;
96 [[nodiscard]] auto apply_generic_substitution(const Substitutions& sub) const -> Type;
97 [[nodiscard]] auto compatibility(Type other, Compat compat = Compat()) const -> Compat;
98
99 /// Get this type with a given qualifier applied.
100 [[nodiscard]] auto known_qual(Qualifier qual) const -> Type;
101 [[nodiscard]] auto known_ptr() const -> Type { return known_qual(Qualifier::Ptr); }
102 [[nodiscard]] auto known_mut() const -> Type { return known_qual(Qualifier::Mut); }
103 [[nodiscard]] auto known_ref() const -> Type { return known_qual(Qualifier::Ref); }
104 [[nodiscard]] auto known_meta() const -> Type { return known_qual(Qualifier::Type); }
105 [[nodiscard]] auto known_opaque() const -> Type { return known_qual(Qualifier::Opaque); }
106
107 /// The union of this and `other`. For example, the union of `T` and `T mut` is `T mut`.
108 /// \returns `nullopt` if an union cannot be created.
109 [[nodiscard]] auto coalesce(Type other) const noexcept -> optional<Type>;
110 /// Return the intersection of this and `other`. For example, the intersection of `T` and `T mut` is `T`.
111 /// \returns `nullopt` is there's not intersection between the types.
112 [[nodiscard]] auto intersect(Type other) const noexcept -> optional<Type>;
113
114 [[nodiscard]] auto is_mut() const noexcept -> bool { return m_mut; };
115 [[nodiscard]] auto is_ref() const noexcept -> bool { return m_ref; };
116 [[nodiscard]] auto is_unqualified() const noexcept -> bool { return !m_ref && !m_mut; };
117 [[nodiscard]] auto is_slice() const noexcept -> bool;
118 [[nodiscard]] auto is_generic() const noexcept -> bool;
119 [[nodiscard]] auto is_opaque_self() const noexcept -> bool;
120 [[nodiscard]] auto is_meta() const noexcept -> bool;
121
122 [[nodiscard]] auto is_trivially_destructible() const -> bool;
123
124 /// If this type is a mutable reference, return the base of it (`T mut` -> `T`)
125 /// \returns `nullopt` if this type isn't a mutable reference.
126 [[nodiscard]] auto mut_base() const noexcept -> optional<Type>;
127
128 /// If this type is a mutable reference, return the base of it (`T mut` -> `T`)
129 /// \throws if this type isn't a mutable reference.
130 [[nodiscard]] auto ensure_mut_base() const noexcept(false) -> Type;
131
132 /// If this type is a pointer type, return the base of it (`T ptr` -> `T`)
133 /// \returns `nullopt` if this type isn't a pointer type.
134 [[nodiscard]] auto ptr_base() const noexcept -> optional<Type>;
135
136 /// If this type is a pointer type, return the base of it (`T ptr` -> `T`)
137 /// \throws if this type isn't a pointer type.
138 [[nodiscard]] auto ensure_ptr_base() const noexcept(false) -> Type;
139
140 /// If this type is a mutable reference, return the base of it, otherwise return itself.
141 [[nodiscard]] auto without_mut() const noexcept -> Type;
142
143 /// If this type is a opaque wrapper type, return the wrapper type, otherwise return itself.
144 [[nodiscard]] auto without_opaque() const noexcept -> Type;
145 [[nodiscard]] auto without_meta() const noexcept -> Type;
146
147 [[nodiscard]] auto generic_base() const noexcept -> Type;
148};
149} // namespace yume::ty
Represents a type in the type system. NOTE: that this isn't the class to use for type introspection,...
Definition: type_base.hpp:42
BaseType(const BaseType &) noexcept=delete
virtual auto name() const -> string=0
auto kind() const -> Kind
Definition: type_base.hpp:57
BaseType(BaseType &&) noexcept=delete
auto base_name() const -> string
Definition: type_base.hpp:58
A "qualified" type, with a non-stackable qualifier, i.e. mut.
Definition: type_base.hpp:66
auto apply_generic_substitution(const Substitutions &sub) const -> Type
Definition: type.cpp:279
auto is_slice() const noexcept -> bool
Definition: type.cpp:242
auto operator<=>(const Type &) const noexcept=default
auto ensure_mut_base() const noexcept(false) -> Type
If this type is a mutable reference, return the base of it (T mut -> T)
Definition: type.cpp:387
auto is_mut() const noexcept -> bool
Definition: type_base.hpp:114
auto mut_base() const noexcept -> optional< Type >
If this type is a mutable reference, return the base of it (T mut -> T)
Definition: type.cpp:381
Type(nonnull< const BaseType * > base) noexcept
Definition: type_base.hpp:73
auto is_unqualified() const noexcept -> bool
Definition: type_base.hpp:116
auto try_as() const noexcept -> optional< Type >
Definition: type_base.hpp:84
auto known_ref() const -> Type
Definition: type_base.hpp:103
auto intersect(Type other) const noexcept -> optional< Type >
Return the intersection of this and other. For example, the intersection of T and T mut is T.
Definition: type.cpp:416
auto is_opaque_self() const noexcept -> bool
Definition: type.cpp:249
auto is_trivially_destructible() const -> bool
Definition: type.cpp:253
auto coalesce(Type other) const noexcept -> optional< Type >
The union of this and other. For example, the union of T and T mut is T mut.
Definition: type.cpp:405
auto generic_base() const noexcept -> Type
Definition: type.cpp:441
auto kind() const noexcept -> Kind
Definition: type_base.hpp:78
auto known_meta() const -> Type
Definition: type_base.hpp:104
auto determine_generic_subs(Type generic, const Substitutions &subs) const -> optional< Substitutions >
Definition: type.cpp:96
auto ensure_ptr_base() const noexcept(false) -> Type
If this type is a pointer type, return the base of it (T ptr -> T)
Definition: type.cpp:399
auto known_opaque() const -> Type
Definition: type_base.hpp:105
auto ptr_base() const noexcept -> optional< Type >
If this type is a pointer type, return the base of it (T ptr -> T)
Definition: type.cpp:393
auto known_ptr() const -> Type
Definition: type_base.hpp:101
auto has_qualifier(Qualifier qual) const -> bool
Definition: type.cpp:269
auto is_meta() const noexcept -> bool
Definition: type.cpp:251
auto base_isa() const noexcept -> bool
Definition: type_base.hpp:90
auto without_meta() const noexcept -> Type
Definition: type.cpp:435
auto base_name() const -> string
Definition: type.cpp:458
auto base_cast() const noexcept -> nonnull< const T * >
Definition: type_base.hpp:80
auto is_generic() const noexcept -> bool
Definition: type.cpp:221
auto base_dyn_cast() const noexcept -> nullable< const T * >
Definition: type_base.hpp:81
auto name() const -> string
Definition: type.cpp:450
auto without_mut() const noexcept -> Type
If this type is a mutable reference, return the base of it, otherwise return itself.
Definition: type.cpp:427
auto opaque_equal(const Type &other) const noexcept -> bool
Definition: type.cpp:506
auto is_ref() const noexcept -> bool
Definition: type_base.hpp:115
auto base() const noexcept -> nonnull< const BaseType * >
Definition: type_base.hpp:79
auto known_qual(Qualifier qual) const -> Type
Get this type with a given qualifier applied.
Definition: type.cpp:31
auto compatibility(Type other, Compat compat=Compat()) const -> Compat
Definition: type.cpp:135
auto known_mut() const -> Type
Definition: type_base.hpp:102
auto without_opaque() const noexcept -> Type
If this type is a opaque wrapper type, return the wrapper type, otherwise return itself.
Definition: type.cpp:429
Type(nonnull< const BaseType * > base, bool mut, bool ref) noexcept
Definition: type_base.hpp:72
@ K_Generic
Generic
Definition: type_base.hpp:21
@ K_Int
Int
Definition: type_base.hpp:16
@ K_Struct
Struct
Definition: type_base.hpp:19
@ K_Unknown
UnknownType, default, zero value. Hopefully never encountered!
Definition: type_base.hpp:15
@ K_OpaqueSelf
OpaqueSelf
Definition: type_base.hpp:22
@ K_Function
Function
Definition: type_base.hpp:20
@ K_Ptr
Ptr
Definition: type_base.hpp:18
@ K_Meta
Meta
Definition: type_base.hpp:23
@ K_Nil
Nil
Definition: type_base.hpp:17
Definition: ast.cpp:8
Qualifier
Definition: qualifier.hpp:4
@ Opaque
Opaque self types.
T nullable
Definition: util.hpp:72
T nonnull
Definition: util.hpp:73
The compatibility between two types, for overload selection.