summaryrefslogtreecommitdiff
path: root/source/slang/slang-check-overload.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-check-overload.cpp')
-rw-r--r--source/slang/slang-check-overload.cpp116
1 files changed, 97 insertions, 19 deletions
diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp
index 2c17a6380..f949e2632 100644
--- a/source/slang/slang-check-overload.cpp
+++ b/source/slang/slang-check-overload.cpp
@@ -2065,6 +2065,94 @@ void SemanticsVisitor::AddCtorOverloadCandidate(
AddOverloadCandidate(context, candidate, baseCost);
}
+void SemanticsVisitor::maybeExpandArgList(List<Expr*>& args)
+{
+ bool needExpansion = false;
+ for (auto expr : args)
+ {
+ while (auto paren = as<ParenExpr>(expr))
+ expr = paren->base;
+
+ if (auto expand = as<ExpandExpr>(expr))
+ {
+ auto exprType = expand->type.type;
+ if (auto typeType = as<TypeType>(exprType))
+ exprType = typeType->getType();
+ if (as<ConcreteTypePack>(exprType))
+ {
+ needExpansion = true;
+ }
+ }
+ }
+ // Fast path without creating list copies.
+ if (!needExpansion)
+ return;
+ List<Expr*> result;
+ for (auto expr : args)
+ {
+ while (auto paren = as<ParenExpr>(expr))
+ expr = paren->base;
+ auto processExpr = [&]()
+ {
+ auto expand = as<ExpandExpr>(expr);
+ if (!expand)
+ return false;
+ auto type = expand->type.type;
+ if (auto typeType = as<TypeType>(type))
+ {
+ auto typePack = as<ConcreteTypePack>(typeType->getType());
+ if (!typePack)
+ return false;
+ for (Index i = 0; i < typePack->getTypeCount(); i++)
+ {
+ auto expandArg = m_astBuilder->create<SharedTypeExpr>();
+ expandArg->loc = expr->loc;
+ expandArg->type = m_astBuilder->getTypeType(typePack->getElementType(i));
+ result.add(expandArg);
+ }
+ return true;
+ }
+ else if (auto typePack = as<ConcreteTypePack>(type))
+ {
+ auto localScope = getExprLocalScope();
+ SLANG_ASSERT(localScope);
+
+ VarDecl* varDecl = m_astBuilder->create<VarDecl>();
+ varDecl->parentDecl = nullptr;
+ if (m_outerScope && m_outerScope->containerDecl)
+ m_outerScope->containerDecl->addMember(varDecl);
+ addModifier(varDecl, m_astBuilder->create<LocalTempVarModifier>());
+ varDecl->checkState = DeclCheckState::DefinitionChecked;
+ varDecl->nameAndLoc.loc = expr->loc;
+ varDecl->initExpr = expr;
+ varDecl->type.type = expr->type.type;
+ LetExpr* letExpr = m_astBuilder->create<LetExpr>();
+ letExpr->decl = varDecl;
+ localScope->addBinding(letExpr);
+ auto varExpr = m_astBuilder->create<VarExpr>();
+ varExpr->declRef = varDecl;
+ varExpr->type = expr->type.type;
+ varExpr->type.isLeftValue = false;
+ for (Index i = 0; i < typePack->getTypeCount(); i++)
+ {
+ auto expandedArg = m_astBuilder->create<SwizzleExpr>();
+ expandedArg->base = varExpr;
+ expandedArg->type = typePack->getElementType(i);
+ expandedArg->type.isLeftValue = false;
+ expandedArg->elementIndices.add((uint32_t)i);
+ result.add(expandedArg);
+ }
+ return true;
+ }
+ return false;
+ };
+
+ if (!processExpr())
+ result.add(expr);
+ }
+ args.swapWith(result);
+}
+
bool SemanticsVisitor::OverloadResolveContext::matchArgumentsToParams(
SemanticsVisitor* semantics,
const List<QualType>& params,
@@ -2102,7 +2190,8 @@ bool SemanticsVisitor::OverloadResolveContext::matchArgumentsToParams(
}
// Try to match the variadic part.
- // Is the corresponding argument a expand expr? If so it will map 1:1 to the type pack param.
+ // Is the corresponding argument a expand expr? If so it will map 1:1 to the type pack
+ // param.
auto astBuilder = semantics->getASTBuilder();
if (remainingArgCount <= 0)
@@ -2655,22 +2744,8 @@ Expr* SemanticsVisitor::ResolveInvoke(InvokeExpr* expr)
{
return CreateErrorExpr(expr);
}
- // If any of the arguments is an error, then we should bail out, to avoid
- // cascading errors where we successfully pick an overload, but not the one
- // the user meant.
- for (auto arg : expr->arguments)
- {
- if (IsErrorExpr(arg))
- return CreateErrorExpr(expr);
- // If this argument is itself an overloaded value without a type
- // then we can't sensibly continue
- if (!arg->type && (as<OverloadedExpr>(arg) || as<OverloadedExpr2>(arg)))
- {
- getSink()->diagnose(expr->loc, Diagnostics::overloadedParameterToHigherOrderFunction);
- return CreateErrorExpr(expr);
- }
- }
+ maybeExpandArgList(expr->arguments);
for (auto& arg : expr->arguments)
{
@@ -2700,7 +2775,8 @@ Expr* SemanticsVisitor::ResolveInvoke(InvokeExpr* expr)
if (typeCheckingCache->resolvedOperatorOverloadCache.tryGetValue(key, candidate))
{
// We should only use the cached candidate if it is persistent direct declref
- // created from GlobalSession's ASTBuilder, or it is created in the current Linkage.
+ // created from GlobalSession's ASTBuilder, or it is created in the current
+ // Linkage.
if (candidate.cacheVersion == typeCheckingCache->version ||
findNextOuterGeneric(candidate.decl) == nullptr)
{
@@ -2910,8 +2986,8 @@ Expr* SemanticsVisitor::ResolveInvoke(InvokeExpr* expr)
}
}
- // Now that we have resolved the overload candidate, we need to undo an `openExistential`
- // operation that was applied to `out` arguments.
+ // Now that we have resolved the overload candidate, we need to undo an
+ // `openExistential` operation that was applied to `out` arguments.
//
auto funcType = context.bestCandidate->funcType;
ShortList<ParameterDirection> paramDirections;
@@ -3087,6 +3163,7 @@ Expr* SemanticsVisitor::checkGenericAppWithCheckedArgs(GenericAppExpr* genericAp
auto& baseExpr = genericAppExpr->functionExpr;
auto& args = genericAppExpr->arguments;
+ maybeExpandArgList(args);
// If there was an error in the base expression, or in any of
// the arguments, then just bail.
@@ -3138,6 +3215,7 @@ Expr* SemanticsVisitor::checkGenericAppWithCheckedArgs(GenericAppExpr* genericAp
// to complete all of them and create an overloaded expression as a result.
auto overloadedExpr = m_astBuilder->create<OverloadedExpr2>();
+ overloadedExpr->type = m_astBuilder->getOverloadedType();
overloadedExpr->base = context.baseExpr;
for (auto candidate : context.bestCandidates)
{