From b17f101cfc75565f9991c856ec62f1e17b0ab104 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Sun, 18 Oct 2026 06:09:01 +0000 Subject: feat(operators): add member and unary overloads with explicit calls Select member and global candidates together, enforce private access, and reuse argument marshalling. Materialize temporary receivers for chaining and register them for the existing object cleanup mechanism. Co-Authored-By: Claude Opus 5.5 --- lib/CodeGen/OperatorGen.cc | 71 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 4 deletions(-) (limited to 'lib/CodeGen/OperatorGen.cc') diff --git a/lib/CodeGen/OperatorGen.cc b/lib/CodeGen/OperatorGen.cc index 83c515b..d340ed7 100644 --- a/lib/CodeGen/OperatorGen.cc +++ b/lib/CodeGen/OperatorGen.cc @@ -1,7 +1,9 @@ #include "cps/CodeGen.h" #include "cps/Operator.h" +#include "cps/TypeAST.h" using namespace cps; +using namespace llvm; // Probing candidates must not evaluate operands or diagnose absent overloads: // both static typing and emission use this same selection. @@ -9,12 +11,73 @@ CodeGen::OperatorResolution CodeGen::resolveOperator( int Op, const TypeInfo *Left, const TypeInfo *Right) { OperatorResolution Result; if (!Left) return Result; - for (const FuncSig *Sig : FuncGen->getOverloads(operatorName(Op))) { - if (Sig->Prototype->getOperator() != Op || Sig->Params.size() != (Right ? 2u : 1u)) continue; - if (!Left->sameType(resolveType(Sig->Params[0].TypeName))) continue; - if (Right && !Right->sameType(resolveType(Sig->Params[1].TypeName))) continue; + auto Candidates = FuncGen->getOverloads(operatorName(Op)); + if (Left->IsClass) { + auto Members = FuncGen->getOverloads(Left->Name + "." + operatorName(Op)); + Candidates.insert(Candidates.end(), Members.begin(), Members.end()); + } + for (const FuncSig *Sig : Candidates) { + bool Member = !Sig->Prototype->getOwnerClass().empty(); + if (Sig->Prototype->getOperator() != Op || Sig->Params.size() != (Right ? 2u : 1u) - Member) continue; + if (!Member && !Left->sameType(resolveType(Sig->Params[0].TypeName))) continue; + if (Right && !Right->sameType(resolveType(Sig->Params[Member ? 0 : 1].TypeName))) continue; if (Result.Signature) Result.Ambiguous = true; else Result.Signature = Sig; } return Result; } + +bool CodeGen::checkOperatorAccess(const FuncSig &Signature) { + const PrototypeAST *Proto = Signature.Prototype; + if (!Proto->getOwnerClass().empty() && !Proto->isPublic() && + !sameIdentifier(CurrentClass, Proto->getOwnerClass())) { + reportError("Cannot access private method %s of type %s", + Proto->getName().c_str(), Proto->getOwnerClass().c_str()); + return false; + } + return true; +} + +Value *CodeGen::materializeOperatorReceiver(Value *Val, const TypeInfo *Type) { + if (!Val || !Type) return nullptr; + auto *Storage = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(), + Type->LLVMType, "operator_receiver"); + size_t Object = registerStackObject(Storage, Type->Name, DiagnosticLine, false, true); + Builder->CreateStore(Val, Storage); + activateStackObject(Object); + return Storage; +} + +Value *CodeGen::emitOperatorCall(const FuncSig &Signature, ExprAST *Left, ExprAST *Right) { + if (!checkOperatorAccess(Signature)) return nullptr; + std::vector Args; + std::vector Explicit; + if (Signature.Prototype->getOwnerClass().empty()) { + Explicit.push_back(Left); + } else { + Value *Receiver = nullptr; + if (dynamic_cast(Left) || dynamic_cast(Left) || + dynamic_cast(Left)) { + LValueInfo LV; + if (!emitLValue(Left, LV)) return nullptr; + Receiver = LV.Addr; + } else { + Receiver = materializeOperatorReceiver(emitExpr(Left), getExprTypeInfo(Left)); + } + if (!Receiver) return nullptr; + Args.push_back(Receiver); + } + if (Right) Explicit.push_back(Right); + if (!marshalCallArgs(Signature, Explicit, DiagnosticLine, Args)) return nullptr; + return FuncGen->emitCall(Signature, Args); +} + +// CASE has already evaluated and captured its selector and label values. +Value *CodeGen::emitOperatorValues(const FuncSig &Signature, Value *Left, + const TypeInfo *LeftType, Value *Right) { + if (!checkOperatorAccess(Signature)) return nullptr; + if (!Signature.Prototype->getOwnerClass().empty()) + Left = materializeOperatorReceiver(Left, LeftType); + if (!Left) return nullptr; + return FuncGen->emitCall(Signature, {Left, Right}); +} -- cgit v1.3.1-4-g156e