aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-21 06:00:55 +0000
committer_ov4 <ov4@ov4.org>2026-10-21 06:00:55 +0000
commitbfe020bfa91640e7a6f1a516dc752fa754249088 (patch)
treefd82055133f45fdeaacddd4e62b210f4b63e0c03 /lib
parentc56877035d6600b463a9cbf0e339f7548c0b46fd (diff)
feat(codegen): support explicit template arguments
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/CodeGen/CodeGen.cc33
-rw-r--r--lib/CodeGen/ExpressionGen.cc11
-rw-r--r--lib/CodeGen/StatementGen.cc4
-rw-r--r--lib/CodeGen/ValueTypeGen.cc6
4 files changed, 46 insertions, 8 deletions
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index 3e5b890..4844ece 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -5,6 +5,7 @@
#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"
@@ -501,9 +502,15 @@ Value *CodeGen::emitVariadicArgument(ExprAST *Expr, const std::string &Callee, s
// 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::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;
@@ -529,6 +536,7 @@ const FuncSig *CodeGen::resolveCall(const std::string &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) {
@@ -560,6 +568,16 @@ const FuncSig *CodeGen::resolveCall(const std::string &Name,
IdentifierMap<std::vector<std::string>> Bindings;
for (const auto &Param : Definition.Decl->getParams()) Bindings.emplace(Param.Name, std::vector<std::string>{});
bool Match = true;
+ if (HasExplicit) {
+ const auto &TemplateParams = Definition.Decl->getParams();
+ if (Explicit->size() > TemplateParams.size()) continue;
+ for (size_t I = 0; I < Explicit->size(); ++I) {
+ const TypeInfo *Type = resolveType((*Explicit)[I]);
+ if (!Type || Type->isVoid()) { Match = false; break; }
+ Bindings.at(TemplateParams[I].Name).push_back(Type->Name);
+ }
+ }
+ if (!Match) continue;
for (size_t I = 0; I < Actual.size(); ++I) {
const auto &P = Params[I];
const TypeInfo *Type = Actual[I].Type;
@@ -568,10 +586,21 @@ const FuncSig *CodeGen::resolveCall(const std::string &Name,
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; }
- } else if (!Type->sameType(resolveType(P.TypeName))) { Match = false; break; }
+ }
}
for (const auto &[Param, Types] : Bindings) if (Types.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 < Actual.size(); ++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;
diff --git a/lib/CodeGen/ExpressionGen.cc b/lib/CodeGen/ExpressionGen.cc
index 15d0fe3..3377a39 100644
--- a/lib/CodeGen/ExpressionGen.cc
+++ b/lib/CodeGen/ExpressionGen.cc
@@ -150,7 +150,7 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
return emitMemberCall(Call);
if (auto *Call = dynamic_cast<CallExprAST*>(Expr))
- return emitCall(Call->getCallee(), Call->getArgs(), Call->getLine());
+ return emitCall(Call->getCallee(), Call->getArgs(), Call->getLine(), &Call->getTemplateArgs());
if (auto *D = dynamic_cast<DesignatorExprAST*>(Expr)) {
LValueInfo LV;
@@ -192,10 +192,15 @@ Value *CodeGen::emitBinaryOp(int Op, Value *L, const TypeInfo *LT,
}
Value *CodeGen::emitCall(const std::string &Callee,
- const std::vector<std::unique_ptr<ExprAST>> &ArgExprs, int Line) {
+ const std::vector<std::unique_ptr<ExprAST>> &ArgExprs, int Line,
+ const std::vector<std::string> *Explicit) {
SaveAndRestore<int> Location(DiagnosticLine, Line ? Line : DiagnosticLine);
std::string Name = Callee;
if (const BuiltinInfo *B = findBuiltin(Name)) {
+ if (Explicit && !Explicit->empty()) {
+ reportError("Explicit template arguments are not allowed on builtin %s", B->Name);
+ return nullptr;
+ }
Name = B->Name;
if (ArgExprs.size() != B->Arity) {
reportError("%s expects %u arg%s", B->Name, B->Arity, B->Arity == 1 ? "" : "s");
@@ -230,7 +235,7 @@ Value *CodeGen::emitCall(const std::string &Callee,
}
std::vector<Value*> Args;
- const FuncSig *Sig = resolveCall(Name, ArgExprs);
+ const FuncSig *Sig = resolveCall(Name, ArgExprs, Explicit);
if (!Sig || !marshalCallArgs(*Sig, ArgExprs, Line, Args)) return nullptr;
return FuncGen->emitCall(*Sig, Args);
}
diff --git a/lib/CodeGen/StatementGen.cc b/lib/CodeGen/StatementGen.cc
index 2186aa0..7a73e51 100644
--- a/lib/CodeGen/StatementGen.cc
+++ b/lib/CodeGen/StatementGen.cc
@@ -104,9 +104,9 @@ void CodeGen::emitStmtImpl(StmtAST *Stmt) {
}
if (auto *Call = dynamic_cast<CallStmtAST*>(Stmt)) {
- Value *Result = emitCall(Call->getCallee(), Call->getArgs(), Call->getLine());
+ Value *Result = emitCall(Call->getCallee(), Call->getArgs(), Call->getLine(), &Call->getTemplateArgs());
const FuncSig *Sig = hasCallable(Call->getCallee())
- ? resolveCall(Call->getCallee(), Call->getArgs()) : nullptr;
+ ? resolveCall(Call->getCallee(), Call->getArgs(), &Call->getTemplateArgs()) : nullptr;
const TypeInfo *Type = Sig ? resolveType(Sig->ReturnTypeName) : nullptr;
if (Result && Type && (Type->IsClass || containsString(Type))) materializeOperatorReceiver(Result, Type);
return;
diff --git a/lib/CodeGen/ValueTypeGen.cc b/lib/CodeGen/ValueTypeGen.cc
index 487d61d..1079b14 100644
--- a/lib/CodeGen/ValueTypeGen.cc
+++ b/lib/CodeGen/ValueTypeGen.cc
@@ -136,9 +136,13 @@ const TypeInfo *CodeGen::getExprTypeInfo(ExprAST *Expr) {
if (auto *Call = dynamic_cast<CallExprAST*>(Expr)) {
const std::string &Name = Call->getCallee();
if (const BuiltinInfo *B = findBuiltin(Name)) {
+ if (!Call->getTemplateArgs().empty()) {
+ reportError("Explicit template arguments are not allowed on builtin %s", B->Name);
+ return nullptr;
+ }
return resolveType(B->ReturnTypeName);
}
- if (const FuncSig *Sig = resolveCall(Name, Call->getArgs())) {
+ if (const FuncSig *Sig = resolveCall(Name, Call->getArgs(), &Call->getTemplateArgs())) {
return resolveType(Sig->ReturnTypeName);
}