11#include <llvm/Support/Casting.h>
12#include <llvm/Support/ErrorHandling.h>
13#include <llvm/Support/raw_ostream.h>
36 if (m_base->m_known_ptr ==
nullptr)
37 m_base->m_known_ptr = std::make_unique<Ptr>(m_base->base_name(), *
this, qual);
39 return {m_base->m_known_ptr.get()};
41 if (m_base->m_known_meta ==
nullptr)
42 m_base->m_known_meta = std::make_unique<Meta>(this->base());
44 return {m_base->m_known_meta.get()};
46 if (m_base->m_known_opaque_self ==
nullptr)
47 m_base->m_known_opaque_self = std::make_unique<OpaqueSelf>(this->base());
49 return {m_base->m_known_opaque_self.get()};
59 return visit_subs(*a_ptr_base, *b_ptr_base, sub);
74 a_st_ty !=
nullptr && b_st_ty !=
nullptr) {
75 if (a_st_ty->base_name() == b_st_ty->base_name()) {
77 auto a_ty_mapping = a_st_ty->subs()->type_mappings();
78 const auto* b_subs = b_st_ty->subs();
79 for (
auto [a_key, a_sub] : a_ty_mapping) {
80 const auto* b_mapping = b_subs->mapping_ref_or_null({a_key});
81 if (b_mapping !=
nullptr && b_mapping->unassigned())
82 sub.try_emplace(a_key, a_sub);
97 YUME_ASSERT(generic.is_generic(),
"Cannot substitute generics in a non-generic type");
99 auto clean_subs = subs;
100 std::unordered_map<string, ty::Type> replacements{};
103 for (
auto [k, v] : subs.mapping()) {
104 if (!k->holds_type())
107 auto iter = replacements.find(k->name);
108 if (iter == replacements.end()) {
113 auto new_v = iter->second;
115 if (v->unassigned()) {
117 clean_subs.associate(*k, new_v);
121 auto existing_v = v->as_type();
122 auto intersection = new_v.intersect(existing_v);
124 if (!intersection.has_value()) {
129 clean_subs.associate(*k, *intersection);
136 if (*
this == other) {
143 if (this->is_mut() && other.is_unqualified()) {
144 compat.conv.dereference =
true;
145 compat = ensure_mut_base().compatibility(other, compat);
150 if (
const auto this_int = base_dyn_cast<Int>(), other_int = other.base_dyn_cast<
Int>();
151 (this_int !=
nullptr) && (other_int !=
nullptr)) {
152 if (this_int->is_signed() == other_int->is_signed() && this_int->size() == other_int->size()) {
159 if ((this_int->is_signed() == other_int->is_signed() && this_int->size() <= other_int->size()) ||
160 (!this_int->is_signed() && other_int->is_signed() && this_int->size() * 2 <= other_int->size())) {
162 compat.conv.kind = Conv::Int;
169 if (
const auto this_fn = base_dyn_cast<Function>(), other_fn = other.base_dyn_cast<
Function>();
170 (this_fn !=
nullptr) && (other_fn !=
nullptr)) {
171 if (this_fn->m_args == other_fn->m_args && this_fn->m_ret == other_fn->m_ret && other_fn->m_closure.empty() &&
172 this_fn->m_fn_ptr == other_fn->m_fn_ptr) {
176 if (this_fn->m_args == other_fn->m_args && this_fn->m_ret == other_fn->m_ret && this_fn->m_closure.empty() &&
177 !this_fn->m_fn_ptr && other_fn->m_fn_ptr) {
179 compat.conv.kind = Conv::FnPtr;
184 const auto* this_st = base_dyn_cast<Struct>();
185 const auto* other_st = other.base_dyn_cast<
Struct>();
187 if ((this_st !=
nullptr) && (other_st !=
nullptr) && (other_st->is_interface()) &&
188 (this_st->implements().has_value()) && (this_st->implements()->ensure_ty() == other.m_base) &&
189 (this->is_mut() == other.is_mut()) && (this->is_ref() == other.is_ref())) {
191 compat.conv.
kind = Conv::Virtual;
196 if (
const auto* other_opaque = other.base_dyn_cast<
OpaqueSelf>();
197 (this_st !=
nullptr) && (other_opaque !=
nullptr) && (this_st->is_interface()) && (!this->is_opaque_self()) &&
198 (this_st == other_opaque->indirect()) && (this->is_mut() == other.is_mut()) &&
199 (this->is_ref() == other.is_ref())) {
209 if (
const auto* this_opaque = this->base_dyn_cast<OpaqueSelf>();
210 (this_opaque !=
nullptr) && (other_st !=
nullptr) && (!other_st->is_interface()) && (!other.is_opaque_self()) &&
211 (other_st == this_opaque->indirect()) && (this->is_unqualified()) && (other.is_unqualified())) {
213 compat.conv.dereference =
true;
222 if (base_isa<Generic>())
228 if (base_isa<Meta>())
231 if (
const auto* fn_base = base_dyn_cast<Function>(); fn_base !=
nullptr) {
232 auto ret = fn_base->ret();
233 return std::ranges::any_of(fn_base->args(), &
Type::is_generic) || (ret.has_value() && ret->is_generic());
236 if (
const auto* struct_ty = base_dyn_cast<Struct>())
237 return !struct_ty->subs()->fully_substituted();
243 if (
const auto*
base = base_dyn_cast<Struct>())
254 if (base_isa<ty::Int>() || base_isa<ty::Ptr>() || base_isa<ty::Function>() || base_isa<ty::Nil>())
260 if (
const auto* struct_type = base_dyn_cast<ty::Struct>()) {
261 return std::ranges::all_of(
266 throw std::logic_error(
"Cannot check if "s +
name() +
" is trivially destructible");
274 if (
const auto* ptr_base = base_dyn_cast<Ptr>(); ptr_base)
275 return ptr_base->has_qualifier(qual);
283 if (
const auto* generic_this = base_dyn_cast<Generic>()) {
284 if (
auto mapped = sub.find_type(generic_this->name()); mapped.has_value())
285 return Type{mapped->
base(), mapped->is_mut() || m_mut, mapped->is_ref() || m_ref};
288 if (
const auto* ptr_this = base_dyn_cast<Ptr>())
289 return ensure_ptr_base().apply_generic_substitution(sub).known_qual(ptr_this->qualifier());
292 return without_meta().apply_generic_substitution(sub).known_meta();
294 if (
const auto* st_this = base_dyn_cast<Struct>())
295 return Type{&st_this->get_or_create_instantiation(sub), m_mut, m_ref};
297 if (
const auto* fn_this = base_dyn_cast<Function>())
298 return Type{&fn_this->get_or_create_instantiation(sub), m_mut, m_ref};
301 llvm::raw_string_ostream os{dump};
303 throw std::logic_error(
"Cannot apply generic substitution (" + dump +
") to type `" + name() +
"'");
316 if (m_parent !=
nullptr)
324 if (m_subs !=
nullptr && sub == *m_subs)
327 auto existing = m_instantiations.find(sub);
328 if (existing == m_instantiations.end()) {
330 auto [iter, ok] = m_instantiations.emplace(move(sub), make_unique<Struct>(base_name(), m_fields, m_decl,
nullptr));
331 iter->second->m_subs = &iter->first;
332 iter->second->m_parent =
this;
334 return *iter->second;
336 return *existing->second;
349 if (m_parent !=
nullptr)
352 auto existing = m_instantiations.find(sub);
353 if (existing == m_instantiations.end()) {
356 auto args = vector<ty::Type>{};
357 auto ret = optional<ty::Type>{};
359 for (
const auto& arg : m_args)
360 args.push_back(arg.apply_generic_substitution(sub));
362 if (m_ret.has_value())
363 ret = m_ret->apply_generic_substitution(sub);
366 YUME_ASSERT(m_closure.empty(),
"Cannot substitute function type with closure.");
368 auto [iter, ok] = m_instantiations.emplace(
369 move(sub), make_unique<Function>(base_name(), move(args), ret, m_closure, m_fn_ptr, m_c_varargs));
370 iter->second->m_parent =
this;
372 return *iter->second;
374 return *existing->second;
390 throw std::logic_error(
"Tried calling ensure_mut_base on a type that isn't a mutable reference");
394 if (
const auto* ptr = base_dyn_cast<Ptr>())
395 return ptr->pointee();
400 if (
const auto* ptr = base_dyn_cast<Ptr>())
401 return ptr->pointee();
402 throw std::logic_error(
"Tried calling ensure_ptr_base on a type that isn't a pointer-like type");
408 if (m_mut && !other.m_mut && m_base == other.m_base)
410 if (other.m_mut && !m_mut && other.m_base == m_base)
419 if (m_mut && !other.m_mut && m_base == other.m_base)
421 if (other.m_mut && !m_mut && other.m_base == m_base)
430 if (
const auto* opaque_self = base_dyn_cast<OpaqueSelf>(); opaque_self !=
nullptr)
431 return {opaque_self->indirect()};
436 if (
const auto* meta = base_dyn_cast<Meta>(); meta !=
nullptr)
437 return {meta->indirect()};
442 if (
const auto* st = base_dyn_cast<Struct>(); st !=
nullptr) {
443 auto primary_generic = st->decl()->get_self_ty();
444 YUME_ASSERT(primary_generic.has_value(),
"Generic type doesn't have a known primary unsubstituted type");
445 return {*primary_generic};
451 auto name = m_base->name();
463 if (m_subs ==
nullptr || m_subs->empty())
466 auto ss = stringstream{};
468 for (
const auto& i : llvm::enumerate(m_subs->mapping())) {
469 auto [key, mapping] = i.value();
472 ss << (mapping->unassigned() ? key->name : mapping->name());
480 auto ss = stringstream{};
482 if (!m_closure.empty()) {
484 for (
const auto& i : llvm::enumerate(m_closure)) {
487 ss << i.value().name();
491 for (
const auto& i : llvm::enumerate(m_args)) {
494 ss << i.value().name();
499 if (m_ret.has_value())
507 return *
this == other || (this->is_opaque_self() && other.is_opaque_self());
519 using SIntType =
typename std::make_signed<UIntType>::type;
521 return {std::numeric_limits<UIntType>::min(), std::numeric_limits<UIntType>::max(),
522 std::numeric_limits<SIntType>::min(), std::numeric_limits<SIntType>::max()};
527 case 8:
return minmax_for_bits<uint8_t>();
528 case 16:
return minmax_for_bits<uint16_t>();
529 case 32:
return minmax_for_bits<uint32_t>();
530 case 64:
return minmax_for_bits<uint64_t>();
531 default:
throw std::logic_error(
"Integer type must be 8, 16, 32, or 64 bits, not "s + std::to_string(bits));
537 if (num < 0 && !m_signed)
541 return num >= min_max.s_min && num <= min_max.s_max;
542 return static_cast<uint64_t
>(num) >= min_max.u_min &&
static_cast<uint64_t
>(num) <= min_max.u_max;
auto ensure_ty() const -> ty::Type
auto kind() const -> Kind
auto base_name() const -> string
auto name() const -> string override
auto get_or_create_instantiation(Substitutions sub) const -> const Function &
An unsubstituted generic type variable, usually something like T.
auto name() const -> string override
A built-in integral type, such as I32 or Bool.
auto in_range(int64_t num) const -> bool
The "self" type of abstract or overriding functions. An extra layer of indirection is introduced for ...
A "qualified" type, with a stackable qualifier, i.e. ptr.
auto qualifier() const -> Qualifier
auto name() const -> string override
An user-defined struct type with associated fields.
auto name() const -> string override
auto implements() const -> const ast::OptionalType &
auto get_or_create_instantiation(Substitutions sub) const -> const Struct &
auto is_interface() const -> bool
A "qualified" type, with a non-stackable qualifier, i.e. mut.
auto apply_generic_substitution(const Substitutions &sub) const -> Type
auto is_slice() const noexcept -> bool
auto ensure_mut_base() const noexcept(false) -> Type
If this type is a mutable reference, return the base of it (T mut -> T)
auto is_mut() const noexcept -> bool
auto mut_base() const noexcept -> optional< Type >
If this type is a mutable reference, return the base of it (T mut -> T)
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.
auto is_opaque_self() const noexcept -> bool
auto is_trivially_destructible() const -> bool
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.
auto generic_base() const noexcept -> Type
auto determine_generic_subs(Type generic, const Substitutions &subs) const -> optional< Substitutions >
auto ensure_ptr_base() const noexcept(false) -> Type
If this type is a pointer type, return the base of it (T ptr -> T)
auto ptr_base() const noexcept -> optional< Type >
If this type is a pointer type, return the base of it (T ptr -> T)
auto has_qualifier(Qualifier qual) const -> bool
auto is_meta() const noexcept -> bool
auto base_isa() const noexcept -> bool
auto without_meta() const noexcept -> Type
auto base_name() const -> string
auto base_cast() const noexcept -> nonnull< const T * >
auto is_generic() const noexcept -> bool
auto base_dyn_cast() const noexcept -> nullable< const T * >
auto name() const -> string
auto without_mut() const noexcept -> Type
If this type is a mutable reference, return the base of it, otherwise return itself.
auto opaque_equal(const Type &other) const noexcept -> bool
auto base() const noexcept -> nonnull< const BaseType * >
auto known_qual(Qualifier qual) const -> Type
Get this type with a given qualifier applied.
auto compatibility(Type other, Compat compat=Compat()) const -> Compat
auto without_opaque() const noexcept -> Type
If this type is a opaque wrapper type, return the wrapper type, otherwise return itself.
Type(nonnull< const BaseType * > base, bool mut, bool ref) noexcept
OptionalAnyBase< Type > OptionalType
consteval auto minmax_for_bits() -> MinMax
static void visit_subs(Type a, Type b, std::unordered_map< string, ty::Type > &sub)
static auto qual_suffix(Qualifier qual) -> string
@ Opaque
Opaque self types.
static constexpr auto BUILTIN_TYPE_SLICE
The compatibility between two types, for overload selection.
#define YUME_ASSERT(assertion, message)