aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CallGen.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/CallGen.cc')
-rw-r--r--lib/CodeGen/CallGen.cc186
1 files changed, 96 insertions, 90 deletions
diff --git a/lib/CodeGen/CallGen.cc b/lib/CodeGen/CallGen.cc
index 0741763..f5f1eda 100644
--- a/lib/CodeGen/CallGen.cc
+++ b/lib/CodeGen/CallGen.cc
@@ -210,10 +210,9 @@ const FuncSig *CodeGen::resolveCall(const std::string &Name,
const TypeInfo *Ret = resolveType(Sig->ReturnTypeName);
return Ret && Ret->sameType(Context->Type);
};
- auto Scalar = [](const TypeInfo *T) { return T && (T->Kind == TypeKind::Char || T->isString()); };
bool ParamMatched = false;
int Count = 0;
- // One layer of parameter matching. Lenient adds CHAR/STRING conversions;
+ // One layer of parameter matching. Lenient admits implicit constructors;
// FilterReturn keeps only candidates whose result is the wanted type.
auto Scan = [&](bool Lenient, bool FilterReturn) -> const FuncSig * {
const FuncSig *First = nullptr;
@@ -230,7 +229,7 @@ const FuncSig *CodeGen::resolveCall(const std::string &Name,
bool Same = SameRank && Actual[I].Type && Actual[I].Type->sameType(Formal);
Match = Same ||
(Lenient && SameRank && Actual[I].Type && !P.IsByRef && !P.IsArray &&
- Scalar(Actual[I].Type) && Scalar(Formal));
+ canImplicitlyConvert(Actual[I].Type, Formal));
}
if (!Match) continue;
ParamMatched = true;
@@ -254,106 +253,113 @@ const FuncSig *CodeGen::resolveCall(const std::string &Name,
reportError("Ambiguous call to %s(%s); the return type cannot be determined from context",
Name.c_str(), Key.c_str());
};
- // Exact parameters first, then CHAR/STRING conversions.
bool Ambiguous = false;
+ bool AllowConversions = false;
auto Try = [&](bool FilterReturn, const FuncSig *&Selected) {
- Selected = Scan(false, FilterReturn);
- if (Count > 1) {
- ReportAmbiguous(FilterReturn);
- Ambiguous = true;
- return;
- }
- if (Selected || HasTemplates || HasExplicit) return;
- Selected = Scan(true, FilterReturn);
+ Selected = Scan(AllowConversions, FilterReturn);
if (Count > 1) {
ReportAmbiguous(FilterReturn);
Ambiguous = true;
}
};
- const FuncSig *Selected = nullptr;
- if (PreferResult) {
- Try(true, Selected);
- if (Ambiguous) return nullptr;
- if (Selected) return Selected;
- }
- if (!Context || !Context->Exact) {
- Try(false, Selected);
- if (Ambiguous) return nullptr;
- if (Selected) return Selected;
- }
- 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; }
+ // Exhaust exact ordinary/template candidates before considering conversions.
+ for (bool ConversionLayer : {false, true}) {
+ AllowConversions = ConversionLayer;
+ const FuncSig *Selected = nullptr;
+ if (PreferResult) {
+ Try(true, Selected);
+ if (Ambiguous) return nullptr;
+ if (Selected) return Selected;
+ }
+ if (!Context || !Context->Exact) {
+ Try(false, Selected);
+ if (Ambiguous) return nullptr;
+ if (Selected) return Selected;
+ }
+ 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 (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) {
+ if (!Match) continue;
+ for (size_t I = 0; I < FixedCount; ++I) {
+ const auto &P = Params[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);
+ 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())) &&
+ !(AllowConversions && P.Mode == PassMode::ByVal && !P.IsArray &&
+ canImplicitlyConvert(Type, 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])) &&
+ !(AllowConversions && Params.back().Mode == PassMode::ByVal &&
+ canImplicitlyConvert(Type, 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)) &&
+ !(AllowConversions && Params[I].Mode == PassMode::ByVal && !Params[I].IsArray &&
+ canImplicitlyConvert(Actual[I].Type, 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);
}
- 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);
}
- if (Selected) return instantiateFunction(*Selected, SelectedBindings);
}
}
if (Context && Context->Exact && ParamMatched) {