diff options
Diffstat (limited to 'lib/CodeGen')
| -rw-r--r-- | lib/CodeGen/CallGen.cc | 10 | ||||
| -rw-r--r-- | lib/CodeGen/FunctionGen.cc | 27 | ||||
| -rw-r--r-- | lib/CodeGen/OperatorGen.cc | 8 | ||||
| -rw-r--r-- | lib/CodeGen/TemplateClone.cc | 1 |
4 files changed, 45 insertions, 1 deletions
diff --git a/lib/CodeGen/CallGen.cc b/lib/CodeGen/CallGen.cc index f3a6a9d..0741763 100644 --- a/lib/CodeGen/CallGen.cc +++ b/lib/CodeGen/CallGen.cc @@ -204,7 +204,7 @@ const FuncSig *CodeGen::resolveCall(const std::string &Name, } // A context with a type prefers candidates that return it; a strict // context requires one. Without a context (or after a cast's preference - // finds nothing) selection stays parameter-only. + // finds nothing) a default may resolve return-only ambiguity. const bool PreferResult = Context && Context->Type; auto ReturnsWanted = [&](const FuncSig *Sig) { const TypeInfo *Ret = resolveType(Sig->ReturnTypeName); @@ -217,6 +217,7 @@ const FuncSig *CodeGen::resolveCall(const std::string &Name, // FilterReturn keeps only candidates whose result is the wanted type. auto Scan = [&](bool Lenient, bool FilterReturn) -> const FuncSig * { const FuncSig *First = nullptr; + std::vector<const FuncSig *> Matches; Count = 0; for (const FuncSig *Sig : Overloads) { if (HasExplicit) break; @@ -235,8 +236,15 @@ const FuncSig *CodeGen::resolveCall(const std::string &Name, ParamMatched = true; if (FilterReturn && !ReturnsWanted(Sig)) continue; ++Count; + Matches.push_back(Sig); if (!First) First = Sig; } + if (!FilterReturn && Count > 1) { + if (const FuncSig *Default = FunctionGen::selectDefaultReturn(Matches)) { + Count = 1; + return Default; + } + } return First; }; auto ReportAmbiguous = [&](bool FilterReturn) { diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc index c162b46..a0c520d 100644 --- a/lib/CodeGen/FunctionGen.cc +++ b/lib/CodeGen/FunctionGen.cc @@ -113,9 +113,30 @@ const FuncSig *FunctionGen::getSignatureByLink(const std::string &Name) const { return &Signatures.at(It->second.first)[It->second.second]; } +// Defaults resolve only return-type ambiguity within one parameter signature. +const FuncSig *FunctionGen::selectDefaultReturn(const std::vector<const FuncSig *> &Candidates) { + const FuncSig *Selected = nullptr; + for (const FuncSig *Sig : Candidates) { + if (!sameIdentifier(Sig->Name, Candidates.front()->Name) || + !sameIdentifier(Sig->ParamKey, Candidates.front()->ParamKey)) return nullptr; + if (Sig->IsDefaultReturn) { + if (Selected) return nullptr; + Selected = Sig; + } + } + return Selected; +} + // Copy-constructor, operator, MAIN and name-collision rules for a // FUNCTION/PROCEDURE prototype; reports the first violation. bool FunctionGen::validatePrototype(PrototypeAST *Proto) { + if (Proto->isDefaultReturn()) { + const TypeInfo *Return = Types.resolve(Proto->getReturnType()); + if (!Proto->isOverload() || (Return && Return->isVoid())) { + reportError("DEFAULT requires a non-VOID OVERLOAD FUNCTION"); + return false; + } + } if (!Proto->getOwnerClass().empty() && sameIdentifier(Proto->getName(), "NEW") && Proto->getParams().size() == 1) { const auto &P = Proto->getParams()[0]; @@ -192,6 +213,7 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) { Sig.OwnerUnit = CurrentUnit; Sig.Name = Proto->getLinkName(); Sig.IsOverload = Proto->isOverload(); + Sig.IsDefaultReturn = Proto->isDefaultReturn(); Sig.Prototype = Proto; Sig.ReturnTypeName = Proto->getReturnType(); @@ -247,6 +269,11 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) { return nullptr; } if (sameIdentifier(Existing.ParamKey, Sig.ParamKey) && + Existing.IsDefaultReturn && Sig.IsDefaultReturn) { + reportError("Duplicate DEFAULT return for %s(%s)", Sig.Name.c_str(), Sig.ParamKey.c_str()); + return nullptr; + } + if (sameIdentifier(Existing.ParamKey, Sig.ParamKey) && sameIdentifier(Existing.ReturnKey, Sig.ReturnKey)) { if (Existing.OwnerUnit != CurrentUnit) reportError("Duplicate definition %s in %s and %s", Sig.Name.c_str(), diff --git a/lib/CodeGen/OperatorGen.cc b/lib/CodeGen/OperatorGen.cc index 560b167..7cfac00 100644 --- a/lib/CodeGen/OperatorGen.cc +++ b/lib/CodeGen/OperatorGen.cc @@ -38,6 +38,7 @@ CodeGen::OperatorResolution CodeGen::resolveOperator( if (Lenient && !CanConvert) break; const FuncSig *Selected = nullptr; int Count = 0; + std::vector<const FuncSig *> Matches; for (const FuncSig *Sig : Candidates) { bool Member = !Sig->Prototype->getOwnerClass().empty(); if (Sig->Prototype->getOperator() != Op || @@ -47,8 +48,15 @@ CodeGen::OperatorResolution CodeGen::resolveOperator( ParamMatched = true; if (FilterReturn && !ReturnsWanted(Sig)) continue; ++Count; + Matches.push_back(Sig); if (!Selected) Selected = Sig; } + if (!FilterReturn && Count > 1) { + if (const FuncSig *Default = FunctionGen::selectDefaultReturn(Matches)) { + Selected = Default; + Count = 1; + } + } if (Selected) { Result.Signature = Selected; Result.Ambiguous = Count > 1; diff --git a/lib/CodeGen/TemplateClone.cc b/lib/CodeGen/TemplateClone.cc index 7374ee8..b0aaf0c 100644 --- a/lib/CodeGen/TemplateClone.cc +++ b/lib/CodeGen/TemplateClone.cc @@ -220,6 +220,7 @@ std::unique_ptr<FunctionDefAST> TemplateClone::function(const FunctionDefAST *So auto CopyProto = std::make_unique<PrototypeAST>(Name, std::move(Params), type(Proto->getReturnType()), Proto->isExternal(), OwnerClass, Proto->isPublic(), Proto->isOverload()); CopyProto->setOperator(Proto->getOperator()); + CopyProto->setDefaultReturn(Proto->isDefaultReturn()); CopyProto->setVariadic(Proto->isVariadic()); auto Copy = located(std::make_unique<FunctionDefAST>(std::move(CopyProto), body(Source->getBody())), Source); PackNames = std::move(SavedNames); |
