diff --git a/src/typechecker/typechecker.cpp b/src/typechecker/typechecker.cpp index 2f9db90..b94db37 100644 --- a/src/typechecker/typechecker.cpp +++ b/src/typechecker/typechecker.cpp @@ -395,7 +395,7 @@ namespace Solstice { } - void TypeChecker::checkFunctionCallNodeType(Node& node) { + void TypeChecker::narrowFunctionCallNode(Node& node) { // get function auto name = node.children[0].getIdentifier(); if (!name.has_value()) { @@ -408,23 +408,34 @@ namespace Solstice { auto& function = functions[*name]; - // get types we are calling with - std::vector args; + std::vector args; + + // narrow types based on function for (auto& child : node.children[1].children) { checkNodeType(child); - auto childType = child.ptype.getOnlyType(); - if (!childType.has_value()) { - throw std::runtime_error("cannot call function with ambiguous type"); + args.push_back(child.ptype); + } + + // get all possible combinations + auto sets = doCartesianProductOnTypeSets(args); + + bool found = false; + for (const auto& set : sets) { + if (function.returnTypes.find(set) != function.returnTypes.end()) { + if (found) { + throw std::runtime_error("conflicting function definitions"); + } + found = true; + node.ptype = {{function.returnTypes[set]}}; } - args.push_back(*childType); } - - // find argument type - if (function.returnTypes.find(args) == function.returnTypes.end()) { - throw std::runtime_error("no matching function call to " + *name); + if (!found) { + throw std::runtime_error("no matching overload found for function " + *name); } + } - node.ptype = {{function.returnTypes[args]}}; + void TypeChecker::checkFunctionCallNodeType(Node& node) { + narrowFunctionCallNode(node); } void TypeChecker::checkSetNodeType(Node& node) {