Resolves: tdf#133260 Propagate ForceArrayReturn from inline arrays
... and functions returning array/matrix.
Same as for TRANSPOSE() and FREQUENCY() but not mentioned in
ECMA-376-1:2016 OOXML.
Change-Id: I1e9f1151b2bc0b7de892f4f3d9f91b9a6b86b67f
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/104249
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Jenkins
diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx
index e969ecb..3829ffe 100644
--- a/formula/source/core/api/FormulaCompiler.cxx
+++ b/formula/source/core/api/FormulaCompiler.cxx
@@ -2714,9 +2714,41 @@ void FormulaCompiler::ForceArrayOperator( FormulaTokenRef const & rCurr )
// CheckSetForceArrayParameter() and later PutCode().
return;
if (!(rCurr->GetOpCode() != ocPush && (rCurr->GetType() == svByte || rCurr->GetType() == svJump)))
const OpCode eOp = rCurr->GetOpCode();
const StackVar eType = rCurr->GetType();
bool bInlineArray = false;
if (!(eOp != ocPush && (eType == svByte || eType == svJump))
&& !(bInlineArray = (eOp == ocPush && eType == svMatrix)))
return;
// Return class for inline arrays and functions returning array/matrix.
// It's somewhat unclear what Excel actually does there and in
// ECMA-376-1:2016 OOXML mentions "call to ... shall be an array formula"
// only for FREQUENCY() and TRANSPOSE() but not for any other function
// returning array/matrix or inline arrays, though for the latter has one
// example in 18.17.2 Syntax:
// "SUM(SQRT({1,2,3,4})) returns 6.14 when entered normally". However,
// these need to be treated similar but not as ParamClass::ForceArray
// (which would contradict the example in
// https://bugs.documentfoundation.org/show_bug.cgi?id=122301#c19 and A6 of
// https://bugs.documentfoundation.org/show_bug.cgi?id=133260#c10 ).
// See also
// commit d0ded163d8e93dc5b10d7a7c9bdab1d0a6a50bac
// commit 5413c8871dec08eff19f514f5f391b946a45c86c
constexpr ParamClass eArrayReturn = ParamClass::ForceArrayReturn;
if (bInlineArray)
{
// rCurr->SetInForceArray() can not be used with ocPush.
if (pCurrentFactorToken && pCurrentFactorToken->GetInForceArray() == ParamClass::Unknown)
{
// Propagate to caller as if a function returning an array/matrix
// was called (see also below).
pCurrentFactorToken->SetInForceArray( eArrayReturn);
}
return;
}
if (!pCurrentFactorToken || (pCurrentFactorToken.get() == rCurr.get()))
{
if (!pCurrentFactorToken && mbMatrixFlag)
@@ -2760,14 +2792,14 @@ void FormulaCompiler::ForceArrayOperator( FormulaTokenRef const & rCurr )
return;
// Actual current parameter's class.
const formula::ParamClass eType = GetForceArrayParameter(
const formula::ParamClass eParamType = GetForceArrayParameter(
pCurrentFactorToken.get(), static_cast<sal_uInt16>(nCurrentFactorParam - 1));
if (eType == ParamClass::ForceArray)
rCurr->SetInForceArray( eType);
else if (eType == ParamClass::ReferenceOrForceArray)
if (eParamType == ParamClass::ForceArray)
rCurr->SetInForceArray( eParamType);
else if (eParamType == ParamClass::ReferenceOrForceArray)
{
if (GetForceArrayParameter( rCurr.get(), SAL_MAX_UINT16) != ParamClass::Reference)
rCurr->SetInForceArray( eType);
rCurr->SetInForceArray( eParamType);
else
rCurr->SetInForceArray( formula::ParamClass::SuppressedReferenceOrForceArray);
}
@@ -2775,9 +2807,13 @@ void FormulaCompiler::ForceArrayOperator( FormulaTokenRef const & rCurr )
// Propagate a ForceArrayReturn to caller if the called function
// returns one and the caller so far does not have a stronger array
// mode set.
if (pCurrentFactorToken->GetInForceArray() == ParamClass::Unknown
&& GetForceArrayParameter( rCurr.get(), SAL_MAX_UINT16) == ParamClass::ForceArrayReturn)
pCurrentFactorToken->SetInForceArray( ParamClass::ForceArrayReturn);
if (pCurrentFactorToken->GetInForceArray() == ParamClass::Unknown)
{
if (IsMatrixFunction( eOp))
pCurrentFactorToken->SetInForceArray( eArrayReturn);
else if (GetForceArrayParameter( rCurr.get(), SAL_MAX_UINT16) == ParamClass::ForceArrayReturn)
pCurrentFactorToken->SetInForceArray( ParamClass::ForceArrayReturn);
}
}
void FormulaCompiler::CheckSetForceArrayParameter( FormulaTokenRef const & rCurr, sal_uInt8 nParam )