8#include <llvm/ADT/STLExtras.h>
9#include <llvm/Support/Casting.h>
10#include <llvm/Support/raw_ostream.h>
21static auto join_args(
const auto& iter,
auto fn, llvm::raw_ostream& stream = errs()) {
22 for (
auto& i : llvm::enumerate(iter)) {
25 stream << fn(i.value())->name();
30 if (
const auto* call = dyn_cast<ast::CallExpr>(ast))
31 return (call->receiver.has_value() ? (call->receiver->ensure_ty().name() +
".") :
""s) + call->name;
32 if (
const auto* ctor = dyn_cast<ast::CtorExpr>(ast))
33 return ctor->ensure_ty().name() +
":new";
35 llvm_unreachable(
"Cannot evaluate overload set against non-call, non-ctor");
39 if (
const auto* call = dyn_cast<ast::CallExpr>(ast))
40 return call->receiver.has_value() ? call->receiver->ensure_ty() : optional<ty::Type>{};
41 if (
const auto* ctor = dyn_cast<ast::CtorExpr>(ast))
42 return ctor->ensure_ty();
44 llvm_unreachable(
"Cannot evaluate overload set against non-call, non-ctor");
48 stream <<
fn->
ast().location().to_string() <<
"\t";
51 stream <<
fn->
name() <<
"(";
61 stream << k->name <<
" = " << v->name();
71 if (hide_invalid && !i_s.viable)
80 if (arg.val_ty() == target_type)
81 return {.
valid =
true};
83 if (isa<ast::NumberExpr>(arg) && target_type.base_isa<
ty::Int>()) {
84 auto& num_arg = cast<ast::NumberExpr>(arg);
85 const auto* int_type = target_type.base_cast<
ty::Int>();
87 if (int_type->size() == 1)
90 auto in_range = int_type->
in_range(num_arg.val);
93 return {.valid =
true, .conv = {.dereference =
false, .kind = ty::Conv::Int}};
100 if (args.size() == fn.arg_count())
104 if (args.size() > fn.arg_count() && fn.varargs())
110static auto generic_base(optional<ty::Type> type) -> optional<ty::Type> {
111 if (type.has_value())
112 return type->generic_base();
117 const auto& fn = *overload.fn;
127 if (!parent.has_value()) {
128 notes->emit(overload.location()) <<
"Overload not considered due to ADL";
129 notes->emit(overload.location()) <<
" Because no receiver was specified";
135 if (std::ranges::none_of(args, [parent](
ast::AST* ast) {
138 notes->emit(overload.location()) <<
"Overload not considered due to ADL";
139 for (
const auto* ast : args) {
140 notes->emit(overload.location()) <<
" Because `" << ast->
ensure_ty().without_mut().without_opaque().name()
141 <<
"' is not `" << parent->name() <<
"'";
149 notes->emit(overload.location()) <<
"Overload not considered due to mismatch in parameter count";
153 if (receiver.has_value() && receiver->base_isa<
ty::Struct>())
154 overload.subs = *receiver->base_cast<
ty::Struct>()->subs();
156 overload.compatibilities.reserve(args.size());
164 for (
const auto& [param_type_r, arg] : llvm::zip_first(fn.arg_types(), args)) {
165 auto arg_type = arg->ensure_ty();
172 notes->emit(overload.location()) <<
"Overload not valid";
173 notes->emit(overload.location()) <<
" Because the generic variables of `" << param_type_r.name()
174 <<
"' weren't able to be determined";
177 overload.subs = *new_subs;
181 if (!overload.subs.fully_substituted()) {
182 notes->emit(overload.location()) <<
"Overload not valid because not all generic parameters could be deduced";
183 overload.subs.dump(*notes->buffer_stream);
193 for (
const auto& [param_type_r, arg] : llvm::zip_first(fn.arg_types(), args)) {
194 auto arg_type = arg->ensure_ty();
200 YUME_ASSERT(!param_type.
is_generic(),
"Generic substitution must produce a fully-substituted type, but `"s +
201 param_type.
name() +
"' is not fully substituted");
218 compat = arg_type.compatibility(param_type);
223 notes->emit(overload.location()) <<
"Overload not valid";
224 notes->emit(overload.location()) <<
" Because `" << arg_type.name() <<
"' is not convertible to `"
225 << param_type.
name() <<
"'";
230 overload.compatibilities.push_back(compat);
234 while (overload.compatibilities.size() < args.size())
235 overload.compatibilities.emplace_back();
247static auto cmp(
bool a,
bool b) -> std::strong_ordering {
return static_cast<int>(a) <=>
static_cast<int>(b); }
250 const auto& equal = std::strong_ordering::equal;
253 if (
auto c =
cmp(a.kind == ty::Conv::None, b.kind == ty::Conv::None); c != equal)
257 if (
auto c =
cmp(!a.dereference, !b.dereference); c != equal)
272 for (
const auto& [self_compat, other_compat] : llvm::zip_first(compatibilities, other.compatibilities)) {
275 if (is_gt(comparison))
277 if (is_lt(comparison))
290 for (
const auto& candidate :
overloads) {
291 if (candidate.viable) {
303 if (best ==
nullptr) {
305 llvm::raw_string_ostream ss{str};
306 ss <<
"No viable overload for " <<
overload_name(
call) <<
" with argument types ";
308 ss <<
"\nNone of the following overloads were suitable:\n";
315 throw std::logic_error(str);
318 vector<const Overload*> ambiguous;
320 for (
const auto& candidate :
overloads) {
321 if (candidate.viable && &candidate != best) {
322 if (!best->better_candidate_than(candidate))
323 ambiguous.push_back(&candidate);
327 if (ambiguous.empty())
330 ambiguous.push_back(best);
333 llvm::raw_string_ostream ss{str};
336 ss <<
"\nCouldn't pick between the following overloads:\n";
337 for (
const auto* i : ambiguous) {
342 throw std::logic_error(str);
All nodes in the AST tree of the program inherit from this class.
auto ensure_ty() const -> ty::Type
A built-in integral type, such as I32 or Bool.
auto in_range(int64_t num) const -> bool
An user-defined struct type with associated fields.
A "qualified" type, with a non-stackable qualifier, i.e. mut.
auto apply_generic_substitution(const Substitutions &sub) const -> Type
auto determine_generic_subs(Type generic, const Substitutions &subs) const -> optional< Substitutions >
auto is_generic() const noexcept -> bool
auto name() const -> string
static auto overload_name(const ast::AST *ast) -> std::string
static auto compare_implicit_conversions(ty::Conv a, ty::Conv b) -> std::weak_ordering
static auto join_args(const auto &iter, auto fn, llvm::raw_ostream &stream=errs())
static constexpr auto get_val_ty
static auto cmp(bool a, bool b) -> std::strong_ordering
static auto literal_cast(ast::AST &arg, ty::Type target_type) -> ty::Compat
static constexpr auto indirect
static auto overload_receiver(const ast::AST *ast) -> optional< ty::Type >
static auto generic_base(optional< ty::Type > type) -> optional< ty::Type >
auto parameter_count_matches(const vector< ast::AST * > &args, const Fn &fn) -> bool
A function declaration in the compiler.
optional< ty::Type > self_ty
If this function is in the body of a struct, this points to its type. Used for the self type.
auto arg_types() const -> vector< ty::Type >
auto ast() const -> const ast::Stmt &
auto name() const noexcept -> string
auto empty() const -> bool
unique_ptr< diagnostic::StringNotesHolder > notes
auto is_valid_overload(Overload &overload) -> bool
void determine_valid_overloads()
vector< Overload > overloads
auto try_best_viable_overload() const -> const Overload *
vector< ast::AST * > args
void dump(llvm::raw_ostream &stream, bool hide_invalid=false) const
auto best_viable_overload() const -> Overload
void dump(llvm::raw_ostream &stream) const
auto better_candidate_than(Overload other) const -> bool
The compatibility between two types, for overload selection.
#define YUME_ASSERT(assertion, message)