Refactor GLSL array length method parsing

This prepares for accepting arbitrary expressions as the "this" node
of the array length method.

BUG=angleproject:2142
TEST=angle_unittests

Change-Id: I728adb6e76d2779dedbabfaeec7d096872e0d00d
Reviewed-on: https://chromium-review.googlesource.com/633945
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index bf2b8c7..925e73a 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -803,6 +803,13 @@
 //
 void TIntermUnary::promote()
 {
+    if (mOp == EOpArrayLength)
+    {
+        // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
+        setType(TType(EbtInt, EbpUndefined, EvqConst));
+        return;
+    }
+
     TQualifier resultQualifier = EvqTemporary;
     if (mOperand->getQualifier() == EvqConst)
         resultQualifier = EvqConst;
@@ -1355,36 +1362,49 @@
 
 TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
 {
-    TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
-    if (operandConstant == nullptr)
-    {
-        return this;
-    }
-
     TConstantUnion *constArray = nullptr;
-    switch (mOp)
+
+    if (mOp == EOpArrayLength)
     {
-        case EOpAny:
-        case EOpAll:
-        case EOpLength:
-        case EOpTranspose:
-        case EOpDeterminant:
-        case EOpInverse:
-        case EOpPackSnorm2x16:
-        case EOpUnpackSnorm2x16:
-        case EOpPackUnorm2x16:
-        case EOpUnpackUnorm2x16:
-        case EOpPackHalf2x16:
-        case EOpUnpackHalf2x16:
-        case EOpPackUnorm4x8:
-        case EOpPackSnorm4x8:
-        case EOpUnpackUnorm4x8:
-        case EOpUnpackSnorm4x8:
-            constArray = operandConstant->foldUnaryNonComponentWise(mOp);
-            break;
-        default:
-            constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
-            break;
+        if (mOperand->hasSideEffects())
+        {
+            return this;
+        }
+        constArray = new TConstantUnion[1];
+        constArray->setIConst(mOperand->getOutermostArraySize());
+    }
+    else
+    {
+        TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
+        if (operandConstant == nullptr)
+        {
+            return this;
+        }
+
+        switch (mOp)
+        {
+            case EOpAny:
+            case EOpAll:
+            case EOpLength:
+            case EOpTranspose:
+            case EOpDeterminant:
+            case EOpInverse:
+            case EOpPackSnorm2x16:
+            case EOpUnpackSnorm2x16:
+            case EOpPackUnorm2x16:
+            case EOpUnpackUnorm2x16:
+            case EOpPackHalf2x16:
+            case EOpUnpackHalf2x16:
+            case EOpPackUnorm4x8:
+            case EOpPackSnorm4x8:
+            case EOpUnpackUnorm4x8:
+            case EOpUnpackSnorm4x8:
+                constArray = operandConstant->foldUnaryNonComponentWise(mOp);
+                break;
+            default:
+                constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
+                break;
+        }
     }
     if (constArray == nullptr)
     {