|
6 | 6 | #include "interp/type.h"
|
7 | 7 | #include "interp/interp.h"
|
8 | 8 | #include "interp/polymorph.h"
|
| 9 | +#include "interp/overload_resolution.h" |
9 | 10 |
|
10 | 11 | namespace sap::interp::polymorph
|
11 | 12 | {
|
| 13 | + using PSOItem = cst::PartiallyResolvedOverloadSet::Item; |
| 14 | + |
| 15 | + static std::pair<PSOItem, bool> match_generic_arguments(Typechecker* ts, |
| 16 | + const Type* infer, |
| 17 | + const cst::Declaration* decl, |
| 18 | + const ast::FunctionDefn* fn, |
| 19 | + const std::vector<ast::FunctionCall::Arg>& explicit_args) |
| 20 | + { |
| 21 | + bool failed = false; |
| 22 | + PSOItem item { .decl = decl }; |
| 23 | + |
| 24 | +#define _fail_with(loc, msg, ...) \ |
| 25 | + __extension__({ \ |
| 26 | + failed = true; \ |
| 27 | + item.exclusion_reason.addInfo((loc), zpr::sprint((msg) __VA_OPT__(, ) __VA_ARGS__)); \ |
| 28 | + continue; \ |
| 29 | + }) |
| 30 | + |
| 31 | + util::hashset<size_t> seen_param_indices {}; |
| 32 | + util::hashmap<std::string, size_t> expected_arg_names {}; |
| 33 | + for(size_t i = 0; i < fn->generic_params.size(); i++) |
| 34 | + expected_arg_names[fn->generic_params[i].name] = i; |
| 35 | + |
| 36 | + bool saw_named_arg = false; |
| 37 | + size_t positional_param_idx = 0; |
| 38 | + for(auto& arg : explicit_args) |
| 39 | + { |
| 40 | + if(arg.name.has_value()) |
| 41 | + { |
| 42 | + saw_named_arg = true; |
| 43 | + |
| 44 | + const auto it = expected_arg_names.find(*arg.name); |
| 45 | + if(it == expected_arg_names.end()) |
| 46 | + _fail_with(arg.value->loc(), "Entity has no parameter named '{}'", *arg.name); |
| 47 | + |
| 48 | + const size_t param_idx = it->second; |
| 49 | + if(seen_param_indices.contains(param_idx)) |
| 50 | + _fail_with(arg.value->loc(), "Duplicate argument for paramter '{}'", *arg.name); |
| 51 | + |
| 52 | + seen_param_indices.insert(param_idx); |
| 53 | + |
| 54 | + auto te = arg.value->typecheck(ts); |
| 55 | + if(te.is_err()) |
| 56 | + _fail_with(arg.value->loc(), "{}", te.error().string()); |
| 57 | + |
| 58 | + item.applied_types[*arg.name] = te->type(); |
| 59 | + } |
| 60 | + else |
| 61 | + { |
| 62 | + if(saw_named_arg) |
| 63 | + _fail_with(arg.value->loc(), "Positional arguments are not allowed after named ones"); |
| 64 | + |
| 65 | + if(positional_param_idx > expected_arg_names.size()) |
| 66 | + { |
| 67 | + _fail_with(arg.value->loc(), "too many argumentss provided; expected at most {}", |
| 68 | + expected_arg_names.size()); |
| 69 | + } |
| 70 | + |
| 71 | + const auto param_idx = positional_param_idx++; |
| 72 | + seen_param_indices.insert(param_idx); |
| 73 | + |
| 74 | + auto te = arg.value->typecheck(ts); |
| 75 | + if(te.is_err()) |
| 76 | + _fail_with(arg.value->loc(), "{}", te.error().string()); |
| 77 | + |
| 78 | + item.applied_types[fn->generic_params[param_idx].name] = te->type(); |
| 79 | + } |
| 80 | + } |
| 81 | + |
| 82 | + return { std::move(item), not failed }; |
| 83 | + |
| 84 | +#undef _fail_with |
| 85 | + } |
| 86 | + |
| 87 | + |
12 | 88 | ErrorOr<TCResult> tryInstantiateGenericFunction(Typechecker* ts,
|
13 | 89 | const Type* infer,
|
| 90 | + const QualifiedId& name, |
14 | 91 | std::vector<const cst::Declaration*> declarations,
|
15 | 92 | const std::vector<ast::FunctionCall::Arg>& explicit_args)
|
16 | 93 | {
|
17 |
| - return ErrMsg(ts, "hello"); |
| 94 | + auto set = std::make_unique<cst::PartiallyResolvedOverloadSet>(ts->loc(), name); |
| 95 | + |
| 96 | + for(const auto* decl : declarations) |
| 97 | + { |
| 98 | + if(decl->generic_func) |
| 99 | + { |
| 100 | + auto [item, ok] = match_generic_arguments(ts, infer, decl, decl->generic_func, explicit_args); |
| 101 | + if(ok) |
| 102 | + set->items.push_back(std::move(item)); |
| 103 | + else |
| 104 | + set->excluded_items.push_back(std::move(item)); |
| 105 | + } |
| 106 | + else |
| 107 | + { |
| 108 | + set->excluded_items.push_back(PSOItem { |
| 109 | + .decl = decl, |
| 110 | + .exclusion_reason = ErrorMessage(decl->location, |
| 111 | + zpr::sprint("is not a generic function and does not accept type arguments", decl->name)), |
| 112 | + }); |
| 113 | + } |
| 114 | + } |
| 115 | + |
| 116 | + if(set->items.empty()) |
| 117 | + { |
| 118 | + auto e = ErrorMessage(ts->loc(), zpr::sprint("Failed to resolve reference to generic entity '{}'", name)); |
| 119 | + for(auto& f : set->excluded_items) |
| 120 | + e.addInfo(f.decl->location, zpr::sprint("Candidate failed: {}", f.exclusion_reason.string())); |
| 121 | + |
| 122 | + return Err(std::move(e)); |
| 123 | + } |
| 124 | + |
| 125 | + return TCResult::ofRValue(std::move(set)); |
18 | 126 | }
|
19 | 127 | }
|
0 commit comments