From ec4818e6ae594da212701523aa1f0ef52d1ce726 Mon Sep 17 00:00:00 2001 From: mehmetbatuhaneryilmaz Date: Thu, 12 Jun 2025 15:20:59 +0300 Subject: [PATCH] fix: No CTE when array type cannot be determined Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICBYTO Reason: Type of the array literal cannot be inferred but there is no CTE. Description: Necessary implementations are made so the CTE is thrown. Tests: No new tests, old tests passing succesfully. Signed-off-by: mehmetbatuhaneryilmaz --- ets2panda/checker/ets/function.cpp | 70 +++++++++++++++++++++++++++--- ets2panda/checker/ets/helpers.cpp | 3 ++ 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index ea80a961c3..f5118d6c1a 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -420,6 +420,29 @@ static bool CheckArrowFunctionParamIfNeeded(ETSChecker *checker, Signature *subs return true; } +// Helper function to recursively check for empty array literals at any nesting level +static bool ContainsEmptyArrayLiteral(ir::Expression *expr) +{ + if (!expr->IsArrayExpression()) { + return false; + } + + auto *arrayExpr = expr->AsArrayExpression(); + if (arrayExpr->Elements().empty()) { + return true; // Found an empty array literal + } + + // Recursively check each element + // Case of [[[]]], [[], []], [[], [], []], etc. + for (auto *element : arrayExpr->Elements()) { + if (ContainsEmptyArrayLiteral(element)) { + return true; + } + } + + return false; +} + // CC-OFFNXT(huge_method[C++], G.FUN.01-CPP, G.FUD.05) solid logic bool ETSChecker::ValidateSignatureRequiredParams(Signature *substitutedSig, const ArenaVector &arguments, TypeRelationFlag flags, @@ -434,6 +457,18 @@ bool ETSChecker::ValidateSignatureRequiredParams(Signature *substitutedSig, // #22952: infer optional parameter heuristics auto const paramType = GetNonNullishType(substitutedSig->Params()[index]->TsType()); + + // Check for empty array literals (including nested ones) but only when param is a union type + // where type inference is ambiguous. + if (argument->IsArrayExpression() && paramType->IsETSUnionType()) { + if (ContainsEmptyArrayLiteral(argument)) { + if (reportError) { + LogError(diagnostic::UNRESOLVABLE_ARRAY, {}, argument->Start()); + } + return false; + } + } + if (argument->IsObjectExpression()) { if (!paramType->IsETSObjectType()) { return false; @@ -502,13 +537,24 @@ bool ETSChecker::ValidateSignatureInvocationContext(Signature *substitutedSig, i bool ETSChecker::IsValidRestArgument(ir::Expression *const argument, Signature *const substitutedSig, const TypeRelationFlag flags, const std::size_t index) { - auto *restParamType = substitutedSig->RestVar()->TsType(); if (argument->IsObjectExpression()) { - argument->SetPreferredType(GetElementTypeOfArray(restParamType)); // Object literals should be checked separately afterwards after call resolution return true; } + if (argument->IsArrayExpression()) { + auto *restParamType = substitutedSig->RestVar()->TsType(); + auto targetType = GetElementTypeOfArray(restParamType); + + // Check for empty array literals (including nested ones) but only when the target element type is a union. + if (targetType != nullptr && targetType->IsETSUnionType()) { + if (ContainsEmptyArrayLiteral(argument)) { + LogError(diagnostic::UNRESOLVABLE_ARRAY, {}, argument->Start()); + return false; + } + } + } + // Set preferred type for array expressions before checking, similar to spread elements if (argument->IsArrayExpression()) { if (!SetPreferredTypeForArrayArgument(argument->AsArrayExpression(), substitutedSig)) { @@ -517,14 +563,14 @@ bool ETSChecker::IsValidRestArgument(ir::Expression *const argument, Signature * } const auto argumentType = argument->Check(this); - if (restParamType->IsETSTupleType()) { + if (substitutedSig->RestVar()->TsType()->IsETSTupleType()) { return false; } if (argument->HasAstNodeFlags(ir::AstNodeFlags::RESIZABLE_REST)) { return true; } - auto targetType = GetElementTypeOfArray(restParamType); + auto targetType = GetElementTypeOfArray(substitutedSig->RestVar()->TsType()); if (substitutedSig->OwnerVar() == nullptr) { targetType = MaybeBoxType(targetType); } @@ -595,7 +641,19 @@ bool ETSChecker::ValidateSignatureRestParams(Signature *substitutedSig, const Ar Type *targetType = substitutedSig->RestVar()->TsType(); // backing out of check that results in a signature mismatch would be difficult // so only attempt it if there is only one candidate signature - restArgument->SetPreferredType(targetType); + if (restArgument->IsArrayExpression()) { + if (targetType->IsETSUnionType()) { + // Check for empty array literals (including nested ones) in spread elements but only when the target + // element type is a union. + if (ContainsEmptyArrayLiteral(restArgument)) { + if (reportError) { + LogError(diagnostic::UNRESOLVABLE_ARRAY, {}, restArgument->Start()); + } + return false; + } + } + restArgument->AsArrayExpression()->SetPreferredType(targetType); + } auto const argumentType = restArgument->Check(this); auto const invocationCtx = checker::InvocationContext( @@ -2484,4 +2542,4 @@ bool ETSChecker::HasSameAssemblySignatures(ETSFunctionType const *const func1, return false; } -} // namespace ark::es2panda::checker +} // namespace ark::es2panda::checker \ No newline at end of file diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 553abd66e2..3ea313adfd 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -688,6 +688,9 @@ bool ETSChecker::CheckInit(ir::Identifier *ident, ir::TypeNode *typeAnnotation, { if (typeAnnotation == nullptr) { if (init->IsArrayExpression()) { + if (init->AsArrayExpression()->Elements().empty()) { + LogError(diagnostic::UNRESOLVABLE_ARRAY, {}, ident->Start()); + } annotationType = CheckArrayElements(init->AsArrayExpression()); } else if (init->IsETSNewArrayInstanceExpression()) { annotationType = init->AsETSNewArrayInstanceExpression()->TypeReference()->GetType(this); -- Gitee