diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-21 06:00:55 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-21 06:00:55 +0000 |
| commit | bfe020bfa91640e7a6f1a516dc752fa754249088 (patch) | |
| tree | fd82055133f45fdeaacddd4e62b210f4b63e0c03 /lib | |
| parent | c56877035d6600b463a9cbf0e339f7548c0b46fd (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.cc | 33 | ||||
| -rw-r--r-- | lib/CodeGen/ExpressionGen.cc | 11 | ||||
| -rw-r--r-- | lib/CodeGen/StatementGen.cc | 4 | ||||
| -rw-r--r-- | lib/CodeGen/ValueTypeGen.cc | 6 |
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); } |
