From 7cd8130e1a3dbcca8746e0577fb8df3bf2975bf8 Mon Sep 17 00:00:00 2001 From: Yong He Date: Thu, 7 Aug 2025 08:10:02 -0700 Subject: Support `expand` on concrete tuple values. (#8106) Closes #8061. Along with the fix, also enhanced coercion/overload resolution to filter candidates based on the target type, allowing `tests\language-feature\higher-order-functions\overloaded.slang` to pass. --- source/slang/slang-check-overload.cpp | 116 ++++++++++++++++++++++++++++------ 1 file changed, 97 insertions(+), 19 deletions(-) (limited to 'source/slang/slang-check-overload.cpp') 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& args) +{ + bool needExpansion = false; + for (auto expr : args) + { + while (auto paren = as(expr)) + expr = paren->base; + + if (auto expand = as(expr)) + { + auto exprType = expand->type.type; + if (auto typeType = as(exprType)) + exprType = typeType->getType(); + if (as(exprType)) + { + needExpansion = true; + } + } + } + // Fast path without creating list copies. + if (!needExpansion) + return; + List result; + for (auto expr : args) + { + while (auto paren = as(expr)) + expr = paren->base; + auto processExpr = [&]() + { + auto expand = as(expr); + if (!expand) + return false; + auto type = expand->type.type; + if (auto typeType = as(type)) + { + auto typePack = as(typeType->getType()); + if (!typePack) + return false; + for (Index i = 0; i < typePack->getTypeCount(); i++) + { + auto expandArg = m_astBuilder->create(); + expandArg->loc = expr->loc; + expandArg->type = m_astBuilder->getTypeType(typePack->getElementType(i)); + result.add(expandArg); + } + return true; + } + else if (auto typePack = as(type)) + { + auto localScope = getExprLocalScope(); + SLANG_ASSERT(localScope); + + VarDecl* varDecl = m_astBuilder->create(); + varDecl->parentDecl = nullptr; + if (m_outerScope && m_outerScope->containerDecl) + m_outerScope->containerDecl->addMember(varDecl); + addModifier(varDecl, m_astBuilder->create()); + varDecl->checkState = DeclCheckState::DefinitionChecked; + varDecl->nameAndLoc.loc = expr->loc; + varDecl->initExpr = expr; + varDecl->type.type = expr->type.type; + LetExpr* letExpr = m_astBuilder->create(); + letExpr->decl = varDecl; + localScope->addBinding(letExpr); + auto varExpr = m_astBuilder->create(); + 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(); + 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& 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(arg) || as(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 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(); + overloadedExpr->type = m_astBuilder->getOverloadedType(); overloadedExpr->base = context.baseExpr; for (auto candidate : context.bestCandidates) { -- cgit v1.2.3