From 48a51628b841a9b69db846326dcaa67239a8559f Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sun, 1 Nov 2026 22:10:48 +0100 Subject: Fix generic inference for a procedure call as a slice base --- boot/symbol.cc | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) (limited to 'boot/symbol.cc') diff --git a/boot/symbol.cc b/boot/symbol.cc index 310ae8a..dcbd460 100644 --- a/boot/symbol.cc +++ b/boot/symbol.cc @@ -700,6 +700,103 @@ namespace elna::boot return subject; } + bool bind_arguments(const std::vector& parameters, std::vector& bindings, + const type& declared, const type& actual) + { + const type left = resolve_aliases(declared); + const type right = resolve_aliases(actual); + + if (const auto parameter = left.get()) + { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + if (parameters[i].get() == parameter && bindings[i].empty()) + { + // The actual type is recorded as it stands, which inside a + // generic body may itself be an abstract parameter. + bindings[i] = actual; + } + } + return true; + } + else if (const auto left_pointer = left.get()) + { + const std::shared_ptr right_pointer = right.get(); + + return right_pointer != nullptr + && bind_arguments(parameters, bindings, left_pointer->base, right_pointer->base); + } + else if (const auto left_slice = left.get()) + { + const std::shared_ptr right_slice = right.get(); + + return right_slice != nullptr + && bind_arguments(parameters, bindings, left_slice->base, right_slice->base); + } + else if (const auto left_array = left.get()) + { + const std::shared_ptr right_array = right.get(); + + return right_array != nullptr + && bind_arguments(parameters, bindings, left_array->base, right_array->base); + } + else if (const auto left_constant = left.get()) + { + const std::shared_ptr right_constant = right.get(); + const type right_unqualified = right_constant != nullptr + ? right_constant->unqualified + : right; + + return bind_arguments(parameters, bindings, left_constant->unqualified, right_unqualified); + } + else if (const auto left_instance = left.get()) + { + for (type candidate = right; !candidate.empty(); candidate = base_of(candidate)) + { + const std::shared_ptr right_instance = + resolve_aliases(candidate).get(); + + if (right_instance == nullptr + || !(left_instance->generic == right_instance->generic) + || left_instance->arguments.size() != right_instance->arguments.size()) + { + continue; + } + for (std::size_t i = 0; i < left_instance->arguments.size(); ++i) + { + if (!bind_arguments(parameters, bindings, + left_instance->arguments.at(i), right_instance->arguments.at(i))) + { + return false; + } + } + return true; + } + return false; + } + else if (const auto left_procedure = left.get()) + { + const std::shared_ptr right_procedure = right.get(); + + if (right_procedure == nullptr + || left_procedure->parameters.size() != right_procedure->parameters.size()) + { + return false; + } + for (std::size_t i = 0; i < left_procedure->parameters.size(); ++i) + { + if (!bind_arguments(parameters, bindings, + left_procedure->parameters.at(i), right_procedure->parameters.at(i))) + { + return false; + } + } + return left_procedure->return_type.empty() + || bind_arguments(parameters, bindings, left_procedure->return_type, right_procedure->return_type); + } + return true; + } + type instantiate(const std::shared_ptr& instance) { std::shared_ptr const generic = unwrap_generic(instance->generic); -- cgit v1.2.3