aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/CallGen.cc277
-rw-r--r--lib/CodeGen/CodeGen.cc259
2 files changed, 277 insertions, 259 deletions
diff --git a/lib/CodeGen/CallGen.cc b/lib/CodeGen/CallGen.cc
new file mode 100644
index 0000000..dfe89d6
--- /dev/null
+++ b/lib/CodeGen/CallGen.cc
@@ -0,0 +1,277 @@
+#include "cps/Diagnostics.h"
+#include "cps/CodeGen.h"
+#include "cps/ArrayHandler.h"
+#include "cps/FileHandler.h"
+#include "cps/MemoryHandler.h"
+#include "cps/ExceptionHandler.h"
+#include "Builtins.h"
+#include "TemplateClone.h"
+#include "cps/TypeAST.h"
+#include "cps/TemplateAST.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Verifier.h"
+#include <algorithm>
+#include <cstdarg>
+
+using namespace llvm;
+using namespace cps;
+
+
+// Collects the arguments for a call to a user FUNCTION/PROCEDURE, dispatching
+// on the *declared* signature: BYREF parameters take the variable's alloca,
+// BYVAL parameters are evaluated and coerced to the declared parameter type.
+bool CodeGen::marshalCallArgs(const FuncSig &Signature,
+ const std::vector<std::unique_ptr<ExprAST>> &ArgExprs,
+ int Line,
+ std::vector<Value*> &Out) {
+ std::vector<ExprAST*> Args;
+ for (const auto &Arg : ArgExprs) Args.push_back(Arg.get());
+ return marshalCallArgs(Signature, Args, Line, Out);
+}
+
+bool CodeGen::marshalCallArgs(const FuncSig &Signature,
+ const std::vector<ExprAST*> &ArgExprs,
+ int Line, std::vector<Value*> &Out) {
+ SaveAndRestore<int> Location(DiagnosticLine, Line ? Line : DiagnosticLine);
+ const FuncSig *Sig = &Signature;
+ const std::string &Callee = Sig->Name;
+ if (Sig->IsVariadic ? ArgExprs.size() < Sig->Params.size() : ArgExprs.size() != Sig->Params.size()) {
+ reportError("Incorrect # arguments passed to %s", Callee.c_str());
+ return false;
+ }
+
+ std::vector<size_t> Transfers;
+ for (size_t i = 0; i < ArgExprs.size(); ++i) {
+ if (i >= Sig->Params.size()) {
+ Value *V = emitVariadicArgument(ArgExprs[i], Callee, i + 1);
+ if (!V) return false;
+ Out.push_back(V);
+ continue;
+ }
+ const ParamSig &P = Sig->Params[i];
+ const std::string &TypeName = P.TypeName;
+ bool IsByRef = P.IsByRef;
+ ExprAST *ArgExpr = ArgExprs[i];
+
+ if (P.IsArray) {
+ if (!Arrays->emitArrayArgument(ArgExpr, P.TypeName, P.Rank, P.DeclaredBounds,
+ Callee, Line, *this, Out)) {
+ return false;
+ }
+ continue;
+ }
+
+ // A whole-array argument against a scalar parameter is always a user
+ // error (and would smash the data pointer if let through).
+ if (auto *Var = dynamic_cast<VariableExprAST*>(ArgExpr)) {
+ const SymbolInfo *Info = getSymbolInfo(Var->getName());
+ if (Info && Info->IsArray) {
+ reportError("Cannot pass whole array %s to %s; the parameter is not an array (declare it ARRAY OF %s)",
+ Var->getName().c_str(), Callee.c_str(), TypeName.c_str());
+ return false;
+ }
+ }
+
+ if (IsByRef) {
+ auto *Var = dynamic_cast<VariableExprAST*>(ArgExpr);
+ bool InternalBinding = Signature.Prototype &&
+ (sameIdentifier(Signature.Prototype->getName(), "NEW") ||
+ Signature.Prototype->getOperator() == tok_assign);
+ if (!Var && InternalBinding) {
+ const TypeInfo *Actual = getExprTypeInfo(ArgExpr);
+ if (!Actual || !Actual->sameType(resolveType(TypeName))) {
+ reportError("BYREF argument to %s has an incompatible type", Callee.c_str());
+ return false;
+ }
+ if (isObjectLValue(ArgExpr)) {
+ LValueInfo LV;
+ if (!emitLValue(ArgExpr, LV)) return false;
+ Out.push_back(LV.Addr);
+ } else {
+ Value *Storage = materializeOperatorReceiver(emitExpr(ArgExpr), Actual);
+ if (!Storage) return false;
+ Out.push_back(Storage);
+ }
+ continue;
+ }
+ if (!Var) {
+ reportError("BYREF argument to %s must be a variable", Callee.c_str());
+ return false;
+ }
+ const SymbolInfo *Info = getSymbolInfo(Var->getName());
+ if (!Info) {
+ reportError("Unknown variable %s in BYREF call", Var->getName().c_str());
+ return false;
+ }
+ const TypeInfo *ParameterType = resolveType(TypeName);
+ if (!(InternalBinding && ParameterType && ParameterType->isString()) &&
+ !requireWritable(*Info, Var->getName())) return false;
+ // BYREF aliases the storage, so the types must match exactly.
+ if (!Types->sameType(Info->TypeName, TypeName)) {
+ reportError("BYREF argument %s to %s must be of type %s (got %s)",
+ Var->getName().c_str(), Callee.c_str(),
+ TypeName.c_str(), Info->TypeName.c_str());
+ return false;
+ }
+ Out.push_back(symbolAddress(*Info));
+ } else {
+ Value *V = emitOwnedValue(ArgExpr, resolveType(TypeName), Transfers);
+ if (!V) return false;
+ Out.push_back(V);
+ }
+ }
+ transferObjects(Transfers);
+ return true;
+}
+
+// C default argument promotions for the variadic part of an EXTERN call; only
+// C values are accepted, matching the explicit-cast rule for C/pseudocode.
+Value *CodeGen::emitVariadicArgument(ExprAST *Expr, const std::string &Callee, size_t Position) {
+ const TypeInfo *Info = isWholeArrayVar(Expr) ? nullptr : getExprTypeInfo(Expr);
+ if (!Info || !Info->isC() || Info->isVoid()) {
+ reportError("Variadic argument %zu to %s must be a C value; cast it to a C type", Position, Callee.c_str());
+ return nullptr;
+ }
+ Value *V = emitExpr(Expr);
+ if (!V || Info->Kind != TypeKind::CScalar) return V;
+ if (Info->isReal()) {
+ const TypeInfo *Double = resolveType("C_DOUBLE");
+ return Info->CRank < Double->CRank ? convertNumericValue(V, Info, Double) : V;
+ }
+ return convertNumericValue(V, Info, Types->promoteCScalar(Info));
+}
+
+// Resolve using static source types only; argument evaluation belongs to marshalling.
+const FuncSig *CodeGen::resolveCall(const std::string &Name,
+ const std::vector<std::unique_ptr<ExprAST>> &Args,
+ const std::vector<std::string> *Explicit) {
+ auto Overloads = FuncGen->getOverloads(Name);
+ bool HasTemplates = hasFunctionTemplate(Name);
+ bool HasExplicit = Explicit && !Explicit->empty();
+ if (HasExplicit && !HasTemplates) {
+ reportError("Explicit template arguments require a function template: %s", Name.c_str());
+ return nullptr;
+ }
+ if (Overloads.empty() && !HasTemplates) {
+ reportError("Call to undefined function %s", Name.c_str());
+ return nullptr;
+ }
+ if (!HasTemplates && Overloads.size() == 1 && !Overloads.front()->IsOverload) return Overloads.front();
+ // Visible EXTERN redeclarations are identical by construction.
+ if (!HasTemplates && Overloads.front()->IsExternal) return Overloads.front();
+ struct ArgumentType { const TypeInfo *Type; int Rank; };
+ std::vector<ArgumentType> Actual;
+ std::string Key;
+ for (const auto &Arg : Args) {
+ const ArrayMetadata *Array = nullptr;
+ if (auto *Var = dynamic_cast<VariableExprAST *>(Arg.get())) {
+ const SymbolInfo *Symbol = getSymbolInfo(Var->getName());
+ if (Symbol && Symbol->IsArray) Array = Arrays->getMetadata(Var->getName());
+ }
+ const TypeInfo *Type = Array ? Types->resolve(Array->ElementTypeName) : getExprTypeInfo(Arg.get());
+ int Rank = Array ? Array->Rank : 0;
+ Actual.push_back({Type, Rank});
+ if (!Key.empty()) Key += ", ";
+ if (Rank) Key += "ARRAY" + std::to_string(Rank) + " OF ";
+ Key += Type ? Type->Name : "?";
+ }
+ const FuncSig *Ordinary = nullptr;
+ for (const FuncSig *Sig : Overloads) {
+ if (HasExplicit) break;
+ if (Sig->Params.size() != Actual.size()) continue;
+ bool Match = true;
+ for (size_t I = 0; I < Actual.size(); ++I) {
+ const ParamSig &P = Sig->Params[I];
+ if (Actual[I].Rank != (P.IsArray ? P.Rank : 0) || !Actual[I].Type ||
+ !Actual[I].Type->sameType(Types->resolve(P.TypeName))) {
+ Match = false;
+ break;
+ }
+ }
+ if (Match) {
+ if (Ordinary && HasTemplates) {
+ reportError("Ambiguous call to %s(%s)", Name.c_str(), Key.c_str());
+ return nullptr;
+ }
+ Ordinary = Sig;
+ if (!HasTemplates) return Sig;
+ }
+ }
+ if (Ordinary) return Ordinary;
+ if (HasTemplates) {
+ // A matching non-variadic template wins before any variadic candidate.
+ for (bool Variadic : {false, true}) {
+ const TemplateDefinition *Selected = nullptr;
+ detail::TemplateBindings SelectedBindings;
+ for (const auto &Definition : Templates.at(Name)) {
+ auto *Function = Definition.Decl->getFunction();
+ if (!Function || Definition.Decl->isVariadic() != Variadic || !isVisible(Definition.OwnerUnit)) continue;
+ const auto &Params = Function->getProto()->getParams();
+ const auto &TemplateParams = Definition.Decl->getParams();
+ bool HasPackParam = !Params.empty() && Params.back().IsPack;
+ size_t FixedCount = Params.size() - HasPackParam;
+ if (HasPackParam ? Actual.size() < FixedCount : Actual.size() != FixedCount) continue;
+ detail::TemplateBindings Bindings;
+ for (const auto &Param : TemplateParams) Bindings.emplace(Param.Name, std::vector<std::string>{});
+ SaveAndRestore<bool> Speculation(SpeculativeTemplateResolution, true);
+ bool Match = true;
+ if (HasExplicit) {
+ size_t FixedTypes = TemplateParams.size() - Variadic;
+ if (!Variadic && Explicit->size() > FixedTypes) continue;
+ for (size_t I = 0; I < Explicit->size(); ++I) {
+ auto Type = canonicalTemplateArgument((*Explicit)[I]);
+ if (!Type) { Match = false; break; }
+ Bindings.at(TemplateParams[std::min(I, FixedTypes)].Name).push_back(*Type);
+ }
+ }
+ if (!Match) continue;
+ for (size_t I = 0; I < FixedCount; ++I) {
+ const auto &P = Params[I];
+ const TypeInfo *Type = Actual[I].Type;
+ if (!Type || Type->isVoid() || Actual[I].Rank != (P.IsArray ? P.Rank : 0)) { Match = false; break; }
+ auto Binding = Bindings.find(P.TypeName);
+ if (Binding != Bindings.end()) {
+ if (Binding->second.empty()) Binding->second.push_back(Type->Name);
+ else if (!Type->sameType(resolveType(Binding->second.front()))) { Match = false; break; }
+ }
+ }
+ if (HasPackParam) {
+ auto &Pack = Bindings.at(Params.back().TypeName);
+ // Explicit pack types constrain a prefix; deduction fills the rest.
+ if (Pack.size() > Actual.size() - FixedCount) Match = false;
+ for (size_t I = FixedCount; Match && I < Actual.size(); ++I) {
+ const TypeInfo *Type = Actual[I].Type;
+ size_t Index = I - FixedCount;
+ if (!Type || Type->isVoid() || Actual[I].Rank) { Match = false; break; }
+ if (Index < Pack.size()) {
+ if (!Type->sameType(resolveType(Pack[Index]))) Match = false;
+ } else Pack.push_back(Type->Name);
+ }
+ }
+ for (const auto &Param : TemplateParams)
+ if (!Param.IsPack && Bindings.at(Param.Name).empty()) Match = false;
+ if (!Match) continue;
+ // Composite parameter types can use bindings deduced at later positions,
+ // but do not themselves contribute deductions.
+ detail::TemplateClone Substitute(Bindings, [&](int, const std::string &) { Match = false; });
+ for (size_t I = 0; I < FixedCount; ++I) {
+ const auto &TypeName = Params[I].TypeName;
+ auto Binding = Bindings.find(TypeName);
+ std::string Expected = Binding != Bindings.end() ? Binding->second.front()
+ : TypeName.find('<') != std::string::npos ? Substitute.type(TypeName) : TypeName;
+ if (!Match || !Actual[I].Type->sameType(resolveType(Expected))) { Match = false; break; }
+ }
+ if (!Match) continue;
+ if (Selected) {
+ reportError("Ambiguous call to %s(%s)", Name.c_str(), Key.c_str());
+ return nullptr;
+ }
+ Selected = &Definition;
+ SelectedBindings = std::move(Bindings);
+ }
+ if (Selected) return instantiateFunction(*Selected, SelectedBindings);
+ }
+ }
+ reportError("No matching overload for %s(%s)", Name.c_str(), Key.c_str());
+ return nullptr;
+}
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index 4137761..d81c4ff 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -373,262 +373,3 @@ void CodeGen::compile(const std::vector<SourceUnit> &Sources) {
void CodeGen::print(raw_ostream &Output) {
TheModule->print(Output, nullptr);
}
-
-// Collects the arguments for a call to a user FUNCTION/PROCEDURE, dispatching
-// on the *declared* signature: BYREF parameters take the variable's alloca,
-// BYVAL parameters are evaluated and coerced to the declared parameter type.
-bool CodeGen::marshalCallArgs(const FuncSig &Signature,
- const std::vector<std::unique_ptr<ExprAST>> &ArgExprs,
- int Line,
- std::vector<Value*> &Out) {
- std::vector<ExprAST*> Args;
- for (const auto &Arg : ArgExprs) Args.push_back(Arg.get());
- return marshalCallArgs(Signature, Args, Line, Out);
-}
-
-bool CodeGen::marshalCallArgs(const FuncSig &Signature,
- const std::vector<ExprAST*> &ArgExprs,
- int Line, std::vector<Value*> &Out) {
- SaveAndRestore<int> Location(DiagnosticLine, Line ? Line : DiagnosticLine);
- const FuncSig *Sig = &Signature;
- const std::string &Callee = Sig->Name;
- if (Sig->IsVariadic ? ArgExprs.size() < Sig->Params.size() : ArgExprs.size() != Sig->Params.size()) {
- reportError("Incorrect # arguments passed to %s", Callee.c_str());
- return false;
- }
-
- std::vector<size_t> Transfers;
- for (size_t i = 0; i < ArgExprs.size(); ++i) {
- if (i >= Sig->Params.size()) {
- Value *V = emitVariadicArgument(ArgExprs[i], Callee, i + 1);
- if (!V) return false;
- Out.push_back(V);
- continue;
- }
- const ParamSig &P = Sig->Params[i];
- const std::string &TypeName = P.TypeName;
- bool IsByRef = P.IsByRef;
- ExprAST *ArgExpr = ArgExprs[i];
-
- if (P.IsArray) {
- if (!Arrays->emitArrayArgument(ArgExpr, P.TypeName, P.Rank, P.DeclaredBounds,
- Callee, Line, *this, Out)) {
- return false;
- }
- continue;
- }
-
- // A whole-array argument against a scalar parameter is always a user
- // error (and would smash the data pointer if let through).
- if (auto *Var = dynamic_cast<VariableExprAST*>(ArgExpr)) {
- const SymbolInfo *Info = getSymbolInfo(Var->getName());
- if (Info && Info->IsArray) {
- reportError("Cannot pass whole array %s to %s; the parameter is not an array (declare it ARRAY OF %s)",
- Var->getName().c_str(), Callee.c_str(), TypeName.c_str());
- return false;
- }
- }
-
- if (IsByRef) {
- auto *Var = dynamic_cast<VariableExprAST*>(ArgExpr);
- bool InternalBinding = Signature.Prototype &&
- (sameIdentifier(Signature.Prototype->getName(), "NEW") ||
- Signature.Prototype->getOperator() == tok_assign);
- if (!Var && InternalBinding) {
- const TypeInfo *Actual = getExprTypeInfo(ArgExpr);
- if (!Actual || !Actual->sameType(resolveType(TypeName))) {
- reportError("BYREF argument to %s has an incompatible type", Callee.c_str());
- return false;
- }
- if (isObjectLValue(ArgExpr)) {
- LValueInfo LV;
- if (!emitLValue(ArgExpr, LV)) return false;
- Out.push_back(LV.Addr);
- } else {
- Value *Storage = materializeOperatorReceiver(emitExpr(ArgExpr), Actual);
- if (!Storage) return false;
- Out.push_back(Storage);
- }
- continue;
- }
- if (!Var) {
- reportError("BYREF argument to %s must be a variable", Callee.c_str());
- return false;
- }
- const SymbolInfo *Info = getSymbolInfo(Var->getName());
- if (!Info) {
- reportError("Unknown variable %s in BYREF call", Var->getName().c_str());
- return false;
- }
- const TypeInfo *ParameterType = resolveType(TypeName);
- if (!(InternalBinding && ParameterType && ParameterType->isString()) &&
- !requireWritable(*Info, Var->getName())) return false;
- // BYREF aliases the storage, so the types must match exactly.
- if (!Types->sameType(Info->TypeName, TypeName)) {
- reportError("BYREF argument %s to %s must be of type %s (got %s)",
- Var->getName().c_str(), Callee.c_str(),
- TypeName.c_str(), Info->TypeName.c_str());
- return false;
- }
- Out.push_back(symbolAddress(*Info));
- } else {
- Value *V = emitOwnedValue(ArgExpr, resolveType(TypeName), Transfers);
- if (!V) return false;
- Out.push_back(V);
- }
- }
- transferObjects(Transfers);
- return true;
-}
-
-// C default argument promotions for the variadic part of an EXTERN call; only
-// C values are accepted, matching the explicit-cast rule for C/pseudocode.
-Value *CodeGen::emitVariadicArgument(ExprAST *Expr, const std::string &Callee, size_t Position) {
- const TypeInfo *Info = isWholeArrayVar(Expr) ? nullptr : getExprTypeInfo(Expr);
- if (!Info || !Info->isC() || Info->isVoid()) {
- reportError("Variadic argument %zu to %s must be a C value; cast it to a C type", Position, Callee.c_str());
- return nullptr;
- }
- Value *V = emitExpr(Expr);
- if (!V || Info->Kind != TypeKind::CScalar) return V;
- if (Info->isReal()) {
- const TypeInfo *Double = resolveType("C_DOUBLE");
- return Info->CRank < Double->CRank ? convertNumericValue(V, Info, Double) : V;
- }
- return convertNumericValue(V, Info, Types->promoteCScalar(Info));
-}
-
-// Resolve using static source types only; argument evaluation belongs to marshalling.
-const FuncSig *CodeGen::resolveCall(const std::string &Name,
- const std::vector<std::unique_ptr<ExprAST>> &Args,
- const std::vector<std::string> *Explicit) {
- auto Overloads = FuncGen->getOverloads(Name);
- bool HasTemplates = hasFunctionTemplate(Name);
- bool HasExplicit = Explicit && !Explicit->empty();
- if (HasExplicit && !HasTemplates) {
- reportError("Explicit template arguments require a function template: %s", Name.c_str());
- return nullptr;
- }
- if (Overloads.empty() && !HasTemplates) {
- reportError("Call to undefined function %s", Name.c_str());
- return nullptr;
- }
- if (!HasTemplates && Overloads.size() == 1 && !Overloads.front()->IsOverload) return Overloads.front();
- // Visible EXTERN redeclarations are identical by construction.
- if (!HasTemplates && Overloads.front()->IsExternal) return Overloads.front();
- struct ArgumentType { const TypeInfo *Type; int Rank; };
- std::vector<ArgumentType> Actual;
- std::string Key;
- for (const auto &Arg : Args) {
- const ArrayMetadata *Array = nullptr;
- if (auto *Var = dynamic_cast<VariableExprAST *>(Arg.get())) {
- const SymbolInfo *Symbol = getSymbolInfo(Var->getName());
- if (Symbol && Symbol->IsArray) Array = Arrays->getMetadata(Var->getName());
- }
- const TypeInfo *Type = Array ? Types->resolve(Array->ElementTypeName) : getExprTypeInfo(Arg.get());
- int Rank = Array ? Array->Rank : 0;
- Actual.push_back({Type, Rank});
- if (!Key.empty()) Key += ", ";
- if (Rank) Key += "ARRAY" + std::to_string(Rank) + " OF ";
- Key += Type ? Type->Name : "?";
- }
- const FuncSig *Ordinary = nullptr;
- for (const FuncSig *Sig : Overloads) {
- if (HasExplicit) break;
- if (Sig->Params.size() != Actual.size()) continue;
- bool Match = true;
- for (size_t I = 0; I < Actual.size(); ++I) {
- const ParamSig &P = Sig->Params[I];
- if (Actual[I].Rank != (P.IsArray ? P.Rank : 0) || !Actual[I].Type ||
- !Actual[I].Type->sameType(Types->resolve(P.TypeName))) {
- Match = false;
- break;
- }
- }
- if (Match) {
- if (Ordinary && HasTemplates) {
- reportError("Ambiguous call to %s(%s)", Name.c_str(), Key.c_str());
- return nullptr;
- }
- Ordinary = Sig;
- if (!HasTemplates) return Sig;
- }
- }
- if (Ordinary) return Ordinary;
- if (HasTemplates) {
- // A matching non-variadic template wins before any variadic candidate.
- for (bool Variadic : {false, true}) {
- const TemplateDefinition *Selected = nullptr;
- detail::TemplateBindings SelectedBindings;
- for (const auto &Definition : Templates.at(Name)) {
- auto *Function = Definition.Decl->getFunction();
- if (!Function || Definition.Decl->isVariadic() != Variadic || !isVisible(Definition.OwnerUnit)) continue;
- const auto &Params = Function->getProto()->getParams();
- const auto &TemplateParams = Definition.Decl->getParams();
- bool HasPackParam = !Params.empty() && Params.back().IsPack;
- size_t FixedCount = Params.size() - HasPackParam;
- if (HasPackParam ? Actual.size() < FixedCount : Actual.size() != FixedCount) continue;
- detail::TemplateBindings Bindings;
- for (const auto &Param : TemplateParams) Bindings.emplace(Param.Name, std::vector<std::string>{});
- SaveAndRestore<bool> Speculation(SpeculativeTemplateResolution, true);
- bool Match = true;
- if (HasExplicit) {
- size_t FixedTypes = TemplateParams.size() - Variadic;
- if (!Variadic && Explicit->size() > FixedTypes) continue;
- for (size_t I = 0; I < Explicit->size(); ++I) {
- auto Type = canonicalTemplateArgument((*Explicit)[I]);
- if (!Type) { Match = false; break; }
- Bindings.at(TemplateParams[std::min(I, FixedTypes)].Name).push_back(*Type);
- }
- }
- if (!Match) continue;
- for (size_t I = 0; I < FixedCount; ++I) {
- const auto &P = Params[I];
- const TypeInfo *Type = Actual[I].Type;
- if (!Type || Type->isVoid() || Actual[I].Rank != (P.IsArray ? P.Rank : 0)) { Match = false; break; }
- auto Binding = Bindings.find(P.TypeName);
- if (Binding != Bindings.end()) {
- if (Binding->second.empty()) Binding->second.push_back(Type->Name);
- else if (!Type->sameType(resolveType(Binding->second.front()))) { Match = false; break; }
- }
- }
- if (HasPackParam) {
- auto &Pack = Bindings.at(Params.back().TypeName);
- // Explicit pack types constrain a prefix; deduction fills the rest.
- if (Pack.size() > Actual.size() - FixedCount) Match = false;
- for (size_t I = FixedCount; Match && I < Actual.size(); ++I) {
- const TypeInfo *Type = Actual[I].Type;
- size_t Index = I - FixedCount;
- if (!Type || Type->isVoid() || Actual[I].Rank) { Match = false; break; }
- if (Index < Pack.size()) {
- if (!Type->sameType(resolveType(Pack[Index]))) Match = false;
- } else Pack.push_back(Type->Name);
- }
- }
- for (const auto &Param : TemplateParams)
- if (!Param.IsPack && Bindings.at(Param.Name).empty()) Match = false;
- if (!Match) continue;
- // Composite parameter types can use bindings deduced at later positions,
- // but do not themselves contribute deductions.
- detail::TemplateClone Substitute(Bindings, [&](int, const std::string &) { Match = false; });
- for (size_t I = 0; I < FixedCount; ++I) {
- const auto &TypeName = Params[I].TypeName;
- auto Binding = Bindings.find(TypeName);
- std::string Expected = Binding != Bindings.end() ? Binding->second.front()
- : TypeName.find('<') != std::string::npos ? Substitute.type(TypeName) : TypeName;
- if (!Match || !Actual[I].Type->sameType(resolveType(Expected))) { Match = false; break; }
- }
- if (!Match) continue;
- if (Selected) {
- reportError("Ambiguous call to %s(%s)", Name.c_str(), Key.c_str());
- return nullptr;
- }
- Selected = &Definition;
- SelectedBindings = std::move(Bindings);
- }
- if (Selected) return instantiateFunction(*Selected, SelectedBindings);
- }
- }
- reportError("No matching overload for %s(%s)", Name.c_str(), Key.c_str());
- return nullptr;
-}