Yume
type.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "ast/ast.hpp"
4#include "qualifier.hpp"
5#include "ty/substitution.hpp"
6#include "ty/type_base.hpp"
7#include "util.hpp"
8#include <array>
9#include <cstdint>
10#include <llvm/IR/Type.h>
11#include <map>
12#include <memory>
13#include <string>
14#include <utility>
15#include <vector>
16
17namespace llvm {
18class StructType;
19class FunctionType;
20} // namespace llvm
21namespace yume {
22class Compiler;
23struct Instantiation;
24struct Struct;
25namespace ast {
26struct TypeName;
27class Type;
28} // namespace ast
29} // namespace yume
30
31namespace yume::ty {
32class Type;
33
34/// A built-in integral type, such as I32 or Bool.
35class Int final : public BaseType {
36 int m_size;
37 bool m_signed;
38
39public:
40 Int(string name, int size, bool is_signed) : BaseType(K_Int, move(name)), m_size(size), m_signed(is_signed) {}
41 [[nodiscard]] auto size() const -> int { return m_size; }
42 [[nodiscard]] auto is_signed() const -> bool { return m_signed; }
43 [[nodiscard]] auto name() const -> string override { return base_name(); };
44 [[nodiscard]] auto in_range(int64_t num) const -> bool;
45 static auto classof(const BaseType* a) -> bool { return a->kind() == K_Int; }
46};
47
48/// The null type, Nil.
49class Nil final : public BaseType {
50public:
51 constexpr static const auto nil_name = "Nil"; // TODO(rymiel): Magic value?
52
54 [[nodiscard]] auto name() const -> string override { return nil_name; };
55 static auto classof(const BaseType* a) -> bool { return a->kind() == K_Nil; }
56};
57
58/// A "qualified" type, with a stackable qualifier, \e i.e. `ptr`.
59class Ptr : public BaseType {
60 // TODO(rymiel): why are these here?
61 friend BaseType;
62
63private:
64 Type m_base;
65 // TODO(rymiel): redundant?
66 Qualifier m_qual;
67
68public:
69 Ptr(string name, Type base, Qualifier qual) : BaseType(K_Ptr, move(name)), m_base(base), m_qual(qual) {}
70 [[nodiscard]] auto pointee() const -> Type { return m_base; }
71 [[nodiscard]] auto qualifier() const -> Qualifier { return m_qual; }
72 [[nodiscard]] auto has_qualifier(Qualifier qual) const -> bool { return m_qual == qual; }
73 [[nodiscard]] auto name() const -> string override;
74 static auto classof(const BaseType* a) -> bool { return a->kind() == K_Ptr; }
75};
76
77/// An user-defined struct type with associated fields.
78class Struct final : public BaseType {
79 vector<ast::TypeName*> m_fields;
81 // TODO(rymiel): This could probably be removed, it is currently only used to redirect instantiations to the primary
82 // definition, if `get_or_create_instantiation` would be called on something which is already an instantiation.
83 // However, I don't think that ever even happens, and doing so would probably mean something is wrong. Furthermore,
84 // the primary generic could probably be lookup up via `m_decl`, if really needed.
85 nullable<const Struct*> m_parent{};
87
88 // TODO(rymiel): There isn't actually anything different about these instances, merely the different address for
89 // making the pointers not equal, and the m_subs fields, which isn't really used for much.
90 // All the differences, as in, the actual substituted types of the fields, are swapped out by the compiler in a
91 // convoluted chain going from `get_or_create_instantiation` -> TypeWalker's decl_queue -> Compiler's `create_struct`.
92 // Considering that `get_or_create_instantiation` sets the new instantiation up to follow this chain, but doesn't
93 // guarantee that it actually happens, is probably problematic.
94 // For this case, since we have access to `m_decl`, we can use it to store instantiations, which would happen
95 // anyway, however, this would only work for struct types. Function types need a similar treatment, as they are also
96 // "structural", as in, containing multiple fields. Since function types have no decl to "call back to", all of its
97 // instantiation logic, including substitution, needs to happen in-place.
98 // The difference with Function and Struct, is that Struct uses ast::TypeName, whereas Function uses ty::Type, which
99 // are a lot easier to substitute
100 mutable std::unordered_map<Substitutions, unique_ptr<Struct>> m_instantiations{};
101 mutable llvm::Type* m_memo{};
102
103 // TODO(rymiel): why are these here?
104 friend Compiler;
105 friend BaseType;
106 friend Type;
107
108public:
110 : BaseType(K_Struct, move(name)), m_fields(move(fields)), m_subs(subs), m_decl(decl) {}
111 [[nodiscard]] auto fields() const -> const auto& { return m_fields; }
112 [[nodiscard]] auto fields() -> auto& { return m_fields; }
113 [[nodiscard]] auto subs() const -> const auto* { return m_subs; }
114 [[nodiscard]] auto subs() -> auto* { return m_subs; }
115 [[nodiscard]] auto decl() const -> nonnull<yume::Struct*> { return m_decl; }
116 [[nodiscard]] auto is_interface() const -> bool;
117 [[nodiscard]] auto implements() const -> const ast::OptionalType&;
118 [[nodiscard]] auto name() const -> string override;
119
120 [[nodiscard]] auto memo() const -> auto* { return m_memo; }
121 void memo(Compiler& /* key */, llvm::Type* memo) const { m_memo = memo; }
122
123 [[nodiscard]] auto get_or_create_instantiation(Substitutions sub) const -> const Struct&;
124
125 static auto classof(const BaseType* a) -> bool { return a->kind() == K_Struct; }
126};
127
128/// A function pointer type
129class Function : public BaseType {
130 vector<Type> m_args;
131 optional<Type> m_ret;
132 vector<Type> m_closure;
133 bool m_fn_ptr;
134 bool m_c_varargs;
135
136 nullable<const Function*> m_parent{};
137 mutable std::unordered_map<Substitutions, unique_ptr<Function>> m_instantiations{};
138
139 mutable llvm::FunctionType* m_fn_memo{};
140 mutable llvm::StructType* m_closure_memo{};
141 mutable llvm::Type* m_memo{};
142
143 // TODO(rymiel): why are these here?
144 friend Compiler;
145 friend BaseType;
146 friend Type;
147
148public:
149 Function(string name, vector<Type> args, optional<Type> ret, vector<Type> closure, bool fn_ptr,
150 bool c_varargs = false)
151 : BaseType(K_Function, move(name)), m_args(move(args)), m_ret(ret), m_closure(move(closure)), m_fn_ptr(fn_ptr),
152 m_c_varargs(c_varargs) {}
153 [[nodiscard]] auto args() const -> const auto& { return m_args; }
154 [[nodiscard]] auto args() -> auto& { return m_args; }
155 [[nodiscard]] auto closure() const -> const auto& { return m_closure; }
156 [[nodiscard]] auto closure() -> auto& { return m_closure; }
157 [[nodiscard]] auto ret() const -> const auto& { return m_ret; }
158 [[nodiscard]] auto is_fn_ptr() const { return m_fn_ptr; }
159 [[nodiscard]] auto is_c_varargs() const { return m_c_varargs; }
160 [[nodiscard]] auto name() const -> string override;
161
162 [[nodiscard]] auto fn_memo() const -> auto* { return m_fn_memo; }
163 [[nodiscard]] auto closure_memo() const -> auto* { return m_closure_memo; }
164 [[nodiscard]] auto memo() const -> auto* { return m_memo; }
165
166 void fn_memo(Compiler& /* key */, llvm::FunctionType* memo) const { m_fn_memo = memo; }
167 void closure_memo(Compiler& /* key */, llvm::StructType* memo) const { m_closure_memo = memo; }
168 void memo(Compiler& /* key */, llvm::Type* memo) const { m_memo = memo; }
169
170 [[nodiscard]] auto get_or_create_instantiation(Substitutions sub) const -> const Function&;
171
172 static auto classof(const BaseType* a) -> bool { return a->kind() == K_Function; }
173};
174
175/// An unsubstituted generic type variable, usually something like `T`.
176///
177/// Note that two different functions with the same name for a type variable use two different instances of `Generic`.
178class Generic final : public BaseType {
179public:
180 explicit Generic(string name) : BaseType(K_Generic, move(name)) {}
181 [[nodiscard]] auto name() const -> string override { return base_name(); };
182 static auto classof(const BaseType* a) -> bool { return a->kind() == K_Generic; }
183};
184
185/// The "self" type of abstract or overriding functions. An extra layer of indirection is introduced for type erasure
186class OpaqueSelf final : public BaseType {
187private:
188 const BaseType* m_indirect;
189
190public:
191 explicit OpaqueSelf(const BaseType* indirect) : BaseType(K_OpaqueSelf, indirect->name()), m_indirect(indirect) {}
192 [[nodiscard]] auto name() const -> string override { return base_name() + " opaque"; };
193 [[nodiscard]] auto indirect() const -> const BaseType* { return m_indirect; };
194 static auto classof(const BaseType* a) -> bool { return a->kind() == K_OpaqueSelf; }
195};
196
197/// A metatype, that is, a type referring to a type.
198class Meta final : public BaseType {
199private:
200 const BaseType* m_indirect;
201
202public:
203 explicit Meta(const BaseType* indirect) : BaseType(K_Meta, indirect->name()), m_indirect(indirect) {}
204 [[nodiscard]] auto name() const -> string override { return base_name() + " type"; };
205 [[nodiscard]] auto indirect() const -> const BaseType* { return m_indirect; };
206 static auto classof(const BaseType* a) -> bool { return a->kind() == K_Meta; }
207};
208} // namespace yume::ty
The Compiler the the primary top-level type during compilation. A single instance is created during t...
Definition: compiler.hpp:45
Represents a type in the type system. NOTE: that this isn't the class to use for type introspection,...
Definition: type_base.hpp:42
auto kind() const -> Kind
Definition: type_base.hpp:57
auto base_name() const -> string
Definition: type_base.hpp:58
A function pointer type.
Definition: type.hpp:129
auto name() const -> string override
Definition: type.cpp:479
auto closure() -> auto &
Definition: type.hpp:156
Function(string name, vector< Type > args, optional< Type > ret, vector< Type > closure, bool fn_ptr, bool c_varargs=false)
Definition: type.hpp:149
auto args() -> auto &
Definition: type.hpp:154
void fn_memo(Compiler &, llvm::FunctionType *memo) const
Definition: type.hpp:166
auto is_fn_ptr() const
Definition: type.hpp:158
auto args() const -> const auto &
Definition: type.hpp:153
void closure_memo(Compiler &, llvm::StructType *memo) const
Definition: type.hpp:167
auto is_c_varargs() const
Definition: type.hpp:159
auto ret() const -> const auto &
Definition: type.hpp:157
auto get_or_create_instantiation(Substitutions sub) const -> const Function &
Definition: type.cpp:339
auto closure_memo() const -> auto *
Definition: type.hpp:163
auto closure() const -> const auto &
Definition: type.hpp:155
auto fn_memo() const -> auto *
Definition: type.hpp:162
void memo(Compiler &, llvm::Type *memo) const
Definition: type.hpp:168
auto memo() const -> auto *
Definition: type.hpp:164
An unsubstituted generic type variable, usually something like T.
Definition: type.hpp:178
auto name() const -> string override
Definition: type.hpp:181
Generic(string name)
Definition: type.hpp:180
A built-in integral type, such as I32 or Bool.
Definition: type.hpp:35
auto size() const -> int
Definition: type.hpp:41
auto name() const -> string override
Definition: type.hpp:43
Int(string name, int size, bool is_signed)
Definition: type.hpp:40
auto in_range(int64_t num) const -> bool
Definition: type.cpp:536
auto is_signed() const -> bool
Definition: type.hpp:42
A metatype, that is, a type referring to a type.
Definition: type.hpp:198
auto name() const -> string override
Definition: type.hpp:204
Meta(const BaseType *indirect)
Definition: type.hpp:203
auto indirect() const -> const BaseType *
Definition: type.hpp:205
The null type, Nil.
Definition: type.hpp:49
auto name() const -> string override
Definition: type.hpp:54
static constexpr const auto nil_name
Definition: type.hpp:51
The "self" type of abstract or overriding functions. An extra layer of indirection is introduced for ...
Definition: type.hpp:186
OpaqueSelf(const BaseType *indirect)
Definition: type.hpp:191
auto indirect() const -> const BaseType *
Definition: type.hpp:193
auto name() const -> string override
Definition: type.hpp:192
A "qualified" type, with a stackable qualifier, i.e. ptr.
Definition: type.hpp:59
auto has_qualifier(Qualifier qual) const -> bool
Definition: type.hpp:72
auto pointee() const -> Type
Definition: type.hpp:70
auto qualifier() const -> Qualifier
Definition: type.hpp:71
auto name() const -> string override
Definition: type.cpp:460
Ptr(string name, Type base, Qualifier qual)
Definition: type.hpp:69
An user-defined struct type with associated fields.
Definition: type.hpp:78
auto memo() const -> auto *
Definition: type.hpp:120
Struct(string name, vector< ast::TypeName * > fields, nonnull< yume::Struct * > decl, nullable< const Substitutions * > subs)
Definition: type.hpp:109
auto subs() const -> const auto *
Definition: type.hpp:113
void memo(Compiler &, llvm::Type *memo) const
Definition: type.hpp:121
auto fields() const -> const auto &
Definition: type.hpp:111
auto name() const -> string override
Definition: type.cpp:462
auto fields() -> auto &
Definition: type.hpp:112
auto subs() -> auto *
Definition: type.hpp:114
auto implements() const -> const ast::OptionalType &
Definition: type.cpp:379
auto get_or_create_instantiation(Substitutions sub) const -> const Struct &
Definition: type.cpp:306
auto decl() const -> nonnull< yume::Struct * >
Definition: type.hpp:115
auto is_interface() const -> bool
Definition: type.cpp:377
A "qualified" type, with a non-stackable qualifier, i.e. mut.
Definition: type_base.hpp:66
Definition: ast.hpp:20
OptionalAnyBase< Type > OptionalType
Definition: ast.hpp:325
@ 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_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
T nullable
Definition: util.hpp:72
T nonnull
Definition: util.hpp:73