Remove simple Intermediate.h functions

Most of the functions were just simple wrappers around node
constructors. Dropping this extra redirection makes the code simpler.

The fold() functions of node types are simplified, so that if the node
can't be folded the pointer to the node itself is returned. This makes
the code in ParseContext more straightforward.

The few remaining functions in Intermediate are a bit more complex so
they should be handled separately, but they'll be removed eventually
as well.

BUG=angleproject:1490
TEST=angle_unittests

Change-Id: I85e11919d1f62358cfba9c011b841e32bc25402f
Reviewed-on: https://chromium-review.googlesource.com/563393
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index 4c6db97..aac5c25 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -1043,6 +1043,24 @@
     return EvqTemporary;
 }
 
+TIntermTyped *TIntermTernary::fold()
+{
+    if (mCondition->getAsConstantUnion())
+    {
+        if (mCondition->getAsConstantUnion()->getBConst(0))
+        {
+            mTrueExpression->getTypePointer()->setQualifier(mType.getQualifier());
+            return mTrueExpression;
+        }
+        else
+        {
+            mFalseExpression->getTypePointer()->setQualifier(mType.getQualifier());
+            return mFalseExpression;
+        }
+    }
+    return this;
+}
+
 void TIntermSwizzle::promote()
 {
     TQualifier resultQualifier = EvqTemporary;
@@ -1116,7 +1134,8 @@
     ASSERT(!isMultiplication() ||
            mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
 
-    // Comma is handled as a special case.
+    // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
+    // version and so is not being set here.
     if (mOp == EOpComma)
     {
         setType(mRight->getType());
@@ -1351,7 +1370,7 @@
     TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
     if (operandConstant == nullptr)
     {
-        return nullptr;
+        return this;
     }
 
     TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
@@ -1368,22 +1387,35 @@
     TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
     switch (mOp)
     {
+        case EOpComma:
+        {
+            if (mLeft->hasSideEffects())
+            {
+                return this;
+            }
+            mRight->getTypePointer()->setQualifier(mType.getQualifier());
+            return mRight;
+        }
         case EOpIndexDirect:
         {
             if (leftConstant == nullptr || rightConstant == nullptr)
             {
-                return nullptr;
+                return this;
             }
             int index = rightConstant->getIConst(0);
 
             const TConstantUnion *constArray = leftConstant->foldIndexing(index);
+            if (!constArray)
+            {
+                return this;
+            }
             return CreateFoldedNode(constArray, this, mType.getQualifier());
         }
         case EOpIndexDirectStruct:
         {
             if (leftConstant == nullptr || rightConstant == nullptr)
             {
-                return nullptr;
+                return this;
             }
             const TFieldList &fields = mLeft->getType().getStruct()->fields();
             size_t index             = static_cast<size_t>(rightConstant->getIConst(0));
@@ -1400,15 +1432,19 @@
         case EOpIndexIndirect:
         case EOpIndexDirectInterfaceBlock:
             // Can never be constant folded.
-            return nullptr;
+            return this;
         default:
         {
             if (leftConstant == nullptr || rightConstant == nullptr)
             {
-                return nullptr;
+                return this;
             }
             TConstantUnion *constArray =
                 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
+            if (!constArray)
+            {
+                return this;
+            }
 
             // Nodes may be constant folded without being qualified as constant.
             return CreateFoldedNode(constArray, this, mType.getQualifier());
@@ -1421,7 +1457,7 @@
     TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
     if (operandConstant == nullptr)
     {
-        return nullptr;
+        return this;
     }
 
     TConstantUnion *constArray = nullptr;
@@ -1449,6 +1485,10 @@
             constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
             break;
     }
+    if (constArray == nullptr)
+    {
+        return this;
+    }
 
     // Nodes may be constant folded without being qualified as constant.
     return CreateFoldedNode(constArray, this, mType.getQualifier());
@@ -1461,7 +1501,7 @@
     {
         if (param->getAsConstantUnion() == nullptr)
         {
-            return nullptr;
+            return this;
         }
     }
     TConstantUnion *constArray = nullptr;
@@ -2617,6 +2657,42 @@
     return resultArray;
 }
 
+bool TIntermAggregate::CanFoldAggregateBuiltInOp(TOperator op)
+{
+    switch (op)
+    {
+        case EOpAtan:
+        case EOpPow:
+        case EOpMod:
+        case EOpMin:
+        case EOpMax:
+        case EOpClamp:
+        case EOpMix:
+        case EOpStep:
+        case EOpSmoothStep:
+        case EOpLdexp:
+        case EOpMulMatrixComponentWise:
+        case EOpOuterProduct:
+        case EOpEqualComponentWise:
+        case EOpNotEqualComponentWise:
+        case EOpLessThanComponentWise:
+        case EOpLessThanEqualComponentWise:
+        case EOpGreaterThanComponentWise:
+        case EOpGreaterThanEqualComponentWise:
+        case EOpDistance:
+        case EOpDot:
+        case EOpCross:
+        case EOpFaceforward:
+        case EOpReflect:
+        case EOpRefract:
+        case EOpBitfieldExtract:
+        case EOpBitfieldInsert:
+            return true;
+        default:
+            return false;
+    }
+}
+
 // static
 TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
                                                            TDiagnostics *diagnostics)
diff --git a/src/compiler/translator/IntermNode.h b/src/compiler/translator/IntermNode.h
index e48d683..19bab3d 100644
--- a/src/compiler/translator/IntermNode.h
+++ b/src/compiler/translator/IntermNode.h
@@ -630,6 +630,7 @@
 
     bool hasSideEffects() const override;
 
+    static bool CanFoldAggregateBuiltInOp(TOperator op);
     TIntermTyped *fold(TDiagnostics *diagnostics);
 
     TIntermSequence *getSequence() override { return &mArguments; }
@@ -831,13 +832,15 @@
                mFalseExpression->hasSideEffects();
     }
 
-    static TQualifier DetermineQualifier(TIntermTyped *cond,
-                                         TIntermTyped *trueExpression,
-                                         TIntermTyped *falseExpression);
+    TIntermTyped *fold();
 
   private:
     TIntermTernary(const TIntermTernary &node);  // Note: not deleted, just private!
 
+    static TQualifier DetermineQualifier(TIntermTyped *cond,
+                                         TIntermTyped *trueExpression,
+                                         TIntermTyped *falseExpression);
+
     TIntermTyped *mCondition;
     TIntermTyped *mTrueExpression;
     TIntermTyped *mFalseExpression;
diff --git a/src/compiler/translator/Intermediate.cpp b/src/compiler/translator/Intermediate.cpp
index ada090a..c0facf3 100644
--- a/src/compiler/translator/Intermediate.cpp
+++ b/src/compiler/translator/Intermediate.cpp
@@ -26,47 +26,6 @@
 //
 /////////////////////////////////////////////////////////////////////////////
 
-//
-// Add a terminal node for an identifier in an expression.
-//
-// Returns the added node.
-//
-TIntermSymbol *TIntermediate::addSymbol(int id,
-                                        const TString &name,
-                                        const TType &type,
-                                        const TSourceLoc &line)
-{
-    TIntermSymbol *node = new TIntermSymbol(id, name, type);
-    node->setLine(line);
-
-    return node;
-}
-
-//
-// Connect two nodes through an index operator, where the left node is the base
-// of an array or struct, and the right node is a direct or indirect offset.
-//
-// Returns the added node.
-// The caller should set the type of the returned node.
-//
-TIntermTyped *TIntermediate::addIndex(TOperator op,
-                                      TIntermTyped *base,
-                                      TIntermTyped *index,
-                                      const TSourceLoc &line,
-                                      TDiagnostics *diagnostics)
-{
-    TIntermBinary *node = new TIntermBinary(op, base, index);
-    node->setLine(line);
-
-    TIntermTyped *folded = node->fold(diagnostics);
-    if (folded)
-    {
-        return folded;
-    }
-
-    return node;
-}
-
 // If the input node is nullptr, return nullptr.
 // If the input node is a block node, return it.
 // If the input node is not a block node, put it inside a block node and return that.
@@ -84,80 +43,6 @@
     return blockNode;
 }
 
-TIntermTyped *TIntermediate::AddComma(TIntermTyped *left,
-                                      TIntermTyped *right,
-                                      const TSourceLoc &line,
-                                      int shaderVersion)
-{
-    TIntermTyped *commaNode = nullptr;
-    if (!left->hasSideEffects())
-    {
-        commaNode = right;
-    }
-    else
-    {
-        commaNode = new TIntermBinary(EOpComma, left, right);
-        commaNode->setLine(line);
-    }
-    TQualifier resultQualifier = TIntermBinary::GetCommaQualifier(shaderVersion, left, right);
-    commaNode->getTypePointer()->setQualifier(resultQualifier);
-    return commaNode;
-}
-
-// For "?:" test nodes.  There are three children; a condition,
-// a true path, and a false path.  The two paths are specified
-// as separate parameters.
-//
-// Returns the ternary node created, or one of trueExpression and falseExpression if the expression
-// could be folded.
-TIntermTyped *TIntermediate::AddTernarySelection(TIntermTyped *cond,
-                                                 TIntermTyped *trueExpression,
-                                                 TIntermTyped *falseExpression,
-                                                 const TSourceLoc &line)
-{
-    // Note that the node resulting from here can be a constant union without being qualified as
-    // constant.
-    if (cond->getAsConstantUnion())
-    {
-        TQualifier resultQualifier =
-            TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression);
-        if (cond->getAsConstantUnion()->getBConst(0))
-        {
-            trueExpression->getTypePointer()->setQualifier(resultQualifier);
-            return trueExpression;
-        }
-        else
-        {
-            falseExpression->getTypePointer()->setQualifier(resultQualifier);
-            return falseExpression;
-        }
-    }
-
-    // Make a ternary node.
-    TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression);
-    node->setLine(line);
-
-    return node;
-}
-
-TIntermSwitch *TIntermediate::addSwitch(TIntermTyped *init,
-                                        TIntermBlock *statementList,
-                                        const TSourceLoc &line)
-{
-    TIntermSwitch *node = new TIntermSwitch(init, statementList);
-    node->setLine(line);
-
-    return node;
-}
-
-TIntermCase *TIntermediate::addCase(TIntermTyped *condition, const TSourceLoc &line)
-{
-    TIntermCase *node = new TIntermCase(condition);
-    node->setLine(line);
-
-    return node;
-}
-
 //
 // Constant terminal nodes.  Has a union that contains bool, float or int constants
 //
@@ -174,68 +59,4 @@
     return node;
 }
 
-TIntermTyped *TIntermediate::AddSwizzle(TIntermTyped *baseExpression,
-                                        const TVectorFields &fields,
-                                        const TSourceLoc &dotLocation)
-{
-    TVector<int> fieldsVector;
-    for (int i = 0; i < fields.num; ++i)
-    {
-        fieldsVector.push_back(fields.offsets[i]);
-    }
-    TIntermSwizzle *node = new TIntermSwizzle(baseExpression, fieldsVector);
-    node->setLine(dotLocation);
-
-    TIntermTyped *folded = node->fold();
-    if (folded)
-    {
-        return folded;
-    }
-
-    return node;
-}
-
-TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate,
-                                                  TDiagnostics *diagnostics)
-{
-    switch (aggregate->getOp())
-    {
-        case EOpAtan:
-        case EOpPow:
-        case EOpMod:
-        case EOpMin:
-        case EOpMax:
-        case EOpClamp:
-        case EOpMix:
-        case EOpStep:
-        case EOpSmoothStep:
-        case EOpLdexp:
-        case EOpMulMatrixComponentWise:
-        case EOpOuterProduct:
-        case EOpEqualComponentWise:
-        case EOpNotEqualComponentWise:
-        case EOpLessThanComponentWise:
-        case EOpLessThanEqualComponentWise:
-        case EOpGreaterThanComponentWise:
-        case EOpGreaterThanEqualComponentWise:
-        case EOpDistance:
-        case EOpDot:
-        case EOpCross:
-        case EOpFaceforward:
-        case EOpReflect:
-        case EOpRefract:
-        case EOpBitfieldExtract:
-        case EOpBitfieldInsert:
-            return aggregate->fold(diagnostics);
-        default:
-            // TODO: Add support for folding array constructors
-            if (aggregate->isConstructor() && !aggregate->isArray())
-            {
-                return aggregate->fold(diagnostics);
-            }
-            // Constant folding not supported for the built-in.
-            return nullptr;
-    }
-}
-
 }  // namespace sh
diff --git a/src/compiler/translator/Intermediate.h b/src/compiler/translator/Intermediate.h
index d2c4390..07074d1 100644
--- a/src/compiler/translator/Intermediate.h
+++ b/src/compiler/translator/Intermediate.h
@@ -12,12 +12,6 @@
 namespace sh
 {
 
-struct TVectorFields
-{
-    int offsets[4];
-    int num;
-};
-
 //
 // Set of helper functions to help build the tree.
 //
@@ -27,35 +21,11 @@
     POOL_ALLOCATOR_NEW_DELETE();
     TIntermediate() {}
 
-    TIntermSymbol *addSymbol(int id, const TString &, const TType &, const TSourceLoc &);
-    TIntermTyped *addIndex(TOperator op,
-                           TIntermTyped *base,
-                           TIntermTyped *index,
-                           const TSourceLoc &line,
-                           TDiagnostics *diagnostics);
     static TIntermBlock *EnsureBlock(TIntermNode *node);
-    static TIntermTyped *AddTernarySelection(TIntermTyped *cond,
-                                             TIntermTyped *trueExpression,
-                                             TIntermTyped *falseExpression,
-                                             const TSourceLoc &line);
-    TIntermSwitch *addSwitch(TIntermTyped *init,
-                             TIntermBlock *statementList,
-                             const TSourceLoc &line);
-    TIntermCase *addCase(TIntermTyped *condition, const TSourceLoc &line);
-    static TIntermTyped *AddComma(TIntermTyped *left,
-                                  TIntermTyped *right,
-                                  const TSourceLoc &line,
-                                  int shaderVersion);
     TIntermConstantUnion *addConstantUnion(const TConstantUnion *constantUnion,
                                            const TType &type,
                                            const TSourceLoc &line);
 
-    static TIntermTyped *AddSwizzle(TIntermTyped *baseExpression,
-                                    const TVectorFields &fields,
-                                    const TSourceLoc &dotLocation);
-
-    TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate, TDiagnostics *diagnostics);
-
   private:
     void operator=(TIntermediate &);  // prevent assignments
 };
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index c1e8f3e..8b04ae2 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -176,21 +176,19 @@
 {
 }
 
-//
-// Look at a '.' field selector string and change it into offsets
-// for a vector.
-//
-bool TParseContext::parseVectorFields(const TString &compString,
+bool TParseContext::parseVectorFields(const TSourceLoc &line,
+                                      const TString &compString,
                                       int vecSize,
-                                      TVectorFields &fields,
-                                      const TSourceLoc &line)
+                                      TVector<int> *fieldOffsets)
 {
-    fields.num = (int)compString.size();
-    if (fields.num > 4)
+    ASSERT(fieldOffsets);
+    size_t fieldCount = compString.size();
+    if (fieldCount > 4u)
     {
         error(line, "illegal vector field selection", compString.c_str());
         return false;
     }
+    fieldOffsets->resize(fieldCount);
 
     enum
     {
@@ -199,57 +197,57 @@
         estpq
     } fieldSet[4];
 
-    for (int i = 0; i < fields.num; ++i)
+    for (unsigned int i = 0u; i < fieldOffsets->size(); ++i)
     {
         switch (compString[i])
         {
             case 'x':
-                fields.offsets[i] = 0;
+                (*fieldOffsets)[i] = 0;
                 fieldSet[i]       = exyzw;
                 break;
             case 'r':
-                fields.offsets[i] = 0;
+                (*fieldOffsets)[i] = 0;
                 fieldSet[i]       = ergba;
                 break;
             case 's':
-                fields.offsets[i] = 0;
+                (*fieldOffsets)[i] = 0;
                 fieldSet[i]       = estpq;
                 break;
             case 'y':
-                fields.offsets[i] = 1;
+                (*fieldOffsets)[i] = 1;
                 fieldSet[i]       = exyzw;
                 break;
             case 'g':
-                fields.offsets[i] = 1;
+                (*fieldOffsets)[i] = 1;
                 fieldSet[i]       = ergba;
                 break;
             case 't':
-                fields.offsets[i] = 1;
+                (*fieldOffsets)[i] = 1;
                 fieldSet[i]       = estpq;
                 break;
             case 'z':
-                fields.offsets[i] = 2;
+                (*fieldOffsets)[i] = 2;
                 fieldSet[i]       = exyzw;
                 break;
             case 'b':
-                fields.offsets[i] = 2;
+                (*fieldOffsets)[i] = 2;
                 fieldSet[i]       = ergba;
                 break;
             case 'p':
-                fields.offsets[i] = 2;
+                (*fieldOffsets)[i] = 2;
                 fieldSet[i]       = estpq;
                 break;
 
             case 'w':
-                fields.offsets[i] = 3;
+                (*fieldOffsets)[i] = 3;
                 fieldSet[i]       = exyzw;
                 break;
             case 'a':
-                fields.offsets[i] = 3;
+                (*fieldOffsets)[i] = 3;
                 fieldSet[i]       = ergba;
                 break;
             case 'q':
-                fields.offsets[i] = 3;
+                (*fieldOffsets)[i] = 3;
                 fieldSet[i]       = estpq;
                 break;
             default:
@@ -258,9 +256,9 @@
         }
     }
 
-    for (int i = 0; i < fields.num; ++i)
+    for (unsigned int i = 0u; i < fieldOffsets->size(); ++i)
     {
-        if (fields.offsets[i] >= vecSize)
+        if ((*fieldOffsets)[i] >= vecSize)
         {
             error(line, "vector field selection out of range", compString.c_str());
             return false;
@@ -1682,8 +1680,10 @@
     }
     else
     {
-        return intermediate.addSymbol(variable->getUniqueId(), variable->getName(),
-                                      variable->getType(), location);
+        TIntermSymbol *symbolNode =
+            new TIntermSymbol(variable->getUniqueId(), variable->getName(), variable->getType());
+        symbolNode->setLine(location);
+        return symbolNode;
     }
 }
 
@@ -1800,8 +1800,9 @@
         }
     }
 
-    TIntermSymbol *intermSymbol = intermediate.addSymbol(
-        variable->getUniqueId(), variable->getName(), variable->getType(), line);
+    TIntermSymbol *intermSymbol =
+        new TIntermSymbol(variable->getUniqueId(), variable->getName(), variable->getType());
+    intermSymbol->setLine(line);
     *initNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
     if (*initNode == nullptr)
     {
@@ -2188,7 +2189,7 @@
         // But if the empty declaration is declaring a struct type, the symbol node will store that.
         if (type.getBasicType() == EbtStruct)
         {
-            symbol = intermediate.addSymbol(0, "", type, identifierOrTypeLocation);
+            symbol = new TIntermSymbol(0, "", type);
         }
         else if (IsAtomicCounter(publicType.getBasicType()))
         {
@@ -2213,8 +2214,7 @@
 
         if (variable)
         {
-            symbol = intermediate.addSymbol(variable->getUniqueId(), identifier, type,
-                                            identifierOrTypeLocation);
+            symbol = new TIntermSymbol(variable->getUniqueId(), identifier, type);
         }
     }
 
@@ -2222,6 +2222,7 @@
     declaration->setLine(identifierOrTypeLocation);
     if (symbol)
     {
+        symbol->setLine(identifierOrTypeLocation);
         declaration->appendDeclarator(symbol);
     }
     return declaration;
@@ -2263,10 +2264,10 @@
     TIntermDeclaration *declaration = new TIntermDeclaration();
     declaration->setLine(identifierLocation);
 
-    TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
-    if (variable && symbol)
+    if (variable)
     {
-        symbol->setId(variable->getUniqueId());
+        TIntermSymbol *symbol = new TIntermSymbol(variable->getUniqueId(), identifier, arrayType);
+        symbol->setLine(identifierLocation);
         declaration->appendDeclarator(symbol);
     }
 
@@ -2394,8 +2395,8 @@
 
     symbolTable.addInvariantVarying(std::string(identifier->c_str()));
 
-    TIntermSymbol *intermSymbol =
-        intermediate.addSymbol(variable->getUniqueId(), *identifier, type, identifierLoc);
+    TIntermSymbol *intermSymbol = new TIntermSymbol(variable->getUniqueId(), *identifier, type);
+    intermSymbol->setLine(identifierLoc);
 
     return new TIntermInvariantDeclaration(intermSymbol, identifierLoc);
 }
@@ -2426,10 +2427,10 @@
     }
     declareVariable(identifierLocation, identifier, type, &variable);
 
-    TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, type, identifierLocation);
-    if (variable && symbol)
+    if (variable)
     {
-        symbol->setId(variable->getUniqueId());
+        TIntermSymbol *symbol = new TIntermSymbol(variable->getUniqueId(), identifier, type);
+        symbol->setLine(identifierLocation);
         declarationOut->appendDeclarator(symbol);
     }
 }
@@ -2468,9 +2469,9 @@
         TVariable *variable = nullptr;
         declareVariable(identifierLocation, identifier, arrayType, &variable);
 
-        TIntermSymbol *symbol =
-            intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
-        if (variable && symbol)
+        TIntermSymbol *symbol = new TIntermSymbol(0, identifier, arrayType);
+        symbol->setLine(identifierLocation);
+        if (variable)
             symbol->setId(variable->getUniqueId());
 
         declarationOut->appendDeclarator(symbol);
@@ -2744,6 +2745,8 @@
     {
         const TConstParameter &param = function.getParam(i);
 
+        TIntermSymbol *symbol = nullptr;
+
         // If the parameter has no name, it's not an error, just don't add it to symbol table (could
         // be used for unused args).
         if (param.name != nullptr)
@@ -2751,20 +2754,27 @@
             TVariable *variable = new TVariable(param.name, *param.type);
 
             // Insert the parameter in the symbol table.
-            if (insertParametersToSymbolTable && !symbolTable.declare(variable))
+            if (insertParametersToSymbolTable)
             {
-                error(location, "redefinition", variable->getName().c_str());
-                prototype->appendParameter(intermediate.addSymbol(0, "", *param.type, location));
-                continue;
+                if (symbolTable.declare(variable))
+                {
+                    symbol = new TIntermSymbol(variable->getUniqueId(), variable->getName(),
+                                               variable->getType());
+                }
+                else
+                {
+                    error(location, "redefinition", variable->getName().c_str());
+                }
             }
-            TIntermSymbol *symbol = intermediate.addSymbol(
-                variable->getUniqueId(), variable->getName(), variable->getType(), location);
-            prototype->appendParameter(symbol);
         }
-        else
+        if (!symbol)
         {
-            prototype->appendParameter(intermediate.addSymbol(0, "", *param.type, location));
+            // The parameter had no name or declaring the symbol failed - either way, add a nameless
+            // symbol.
+            symbol = new TIntermSymbol(0, "", *param.type);
         }
+        symbol->setLine(location);
+        prototype->appendParameter(symbol);
     }
     return prototype;
 }
@@ -3075,13 +3085,11 @@
     TIntermAggregate *constructorNode = TIntermAggregate::CreateConstructor(type, arguments);
     constructorNode->setLine(line);
 
-    TIntermTyped *constConstructor =
-        intermediate.foldAggregateBuiltIn(constructorNode, mDiagnostics);
-    if (constConstructor)
+    // TODO(oetuaho@nvidia.com): Add support for folding array constructors.
+    if (!constructorNode->isArray())
     {
-        return constConstructor;
+        return constructorNode->fold(mDiagnostics);
     }
-
     return constructorNode;
 }
 
@@ -3259,8 +3267,8 @@
         symbolName = instanceTypeDef->getName();
     }
 
-    TIntermSymbol *blockSymbol =
-        intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line);
+    TIntermSymbol *blockSymbol = new TIntermSymbol(symbolId, symbolName, interfaceBlockType);
+    blockSymbol->setLine(typeQualifier.line);
     TIntermDeclaration *declaration = new TIntermDeclaration();
     declaration->appendDeclarator(blockSymbol);
     declaration->setLine(nameLine);
@@ -3427,13 +3435,16 @@
             indexConstantUnion->replaceConstantUnion(safeConstantUnion);
         }
 
-        return intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location,
-                                     mDiagnostics);
+        TIntermBinary *node = new TIntermBinary(EOpIndexDirect, baseExpression, indexExpression);
+        node->setLine(location);
+        return node->fold(mDiagnostics);
     }
     else
     {
-        return intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location,
-                                     mDiagnostics);
+        TIntermBinary *node = new TIntermBinary(EOpIndexIndirect, baseExpression, indexExpression);
+        node->setLine(location);
+        // Indirect indexing can never be constant folded.
+        return node;
     }
 }
 
@@ -3474,15 +3485,17 @@
 
     if (baseExpression->isVector())
     {
-        TVectorFields fields;
-        if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields,
-                               fieldLocation))
+        TVector<int> fieldOffsets;
+        if (!parseVectorFields(fieldLocation, fieldString, baseExpression->getNominalSize(),
+                               &fieldOffsets))
         {
-            fields.num        = 1;
-            fields.offsets[0] = 0;
+            fieldOffsets.resize(1);
+            fieldOffsets[0] = 0;
         }
+        TIntermSwizzle *node = new TIntermSwizzle(baseExpression, fieldOffsets);
+        node->setLine(dotLocation);
 
-        return TIntermediate::AddSwizzle(baseExpression, fields, dotLocation);
+        return node->fold();
     }
     else if (baseExpression->getBasicType() == EbtStruct)
     {
@@ -3508,8 +3521,10 @@
             {
                 TIntermTyped *index = TIntermTyped::CreateIndexNode(i);
                 index->setLine(fieldLocation);
-                return intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index,
-                                             dotLocation, mDiagnostics);
+                TIntermBinary *node =
+                    new TIntermBinary(EOpIndexDirectStruct, baseExpression, index);
+                node->setLine(dotLocation);
+                return node->fold(mDiagnostics);
             }
             else
             {
@@ -3542,8 +3557,11 @@
             {
                 TIntermTyped *index = TIntermTyped::CreateIndexNode(i);
                 index->setLine(fieldLocation);
-                return intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index,
-                                             dotLocation, mDiagnostics);
+                TIntermBinary *node =
+                    new TIntermBinary(EOpIndexDirectInterfaceBlock, baseExpression, index);
+                node->setLine(dotLocation);
+                // Indexing interface blocks can never be constant folded.
+                return node;
             }
             else
             {
@@ -4065,12 +4083,8 @@
         }
     }
 
-    TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc);
-    if (node == nullptr)
-    {
-        error(loc, "erroneous switch statement", "switch");
-        return nullptr;
-    }
+    TIntermSwitch *node = new TIntermSwitch(init, statementList);
+    node->setLine(loc);
     return node;
 }
 
@@ -4099,12 +4113,8 @@
     {
         error(condition->getLine(), "case label must be constant", "case");
     }
-    TIntermCase *node = intermediate.addCase(condition, loc);
-    if (node == nullptr)
-    {
-        error(loc, "erroneous case statement", "case");
-        return nullptr;
-    }
+    TIntermCase *node = new TIntermCase(condition);
+    node->setLine(loc);
     return node;
 }
 
@@ -4115,12 +4125,8 @@
         error(loc, "default labels need to be inside switch statements", "default");
         return nullptr;
     }
-    TIntermCase *node = intermediate.addCase(nullptr, loc);
-    if (node == nullptr)
-    {
-        error(loc, "erroneous default statement", "default");
-        return nullptr;
-    }
+    TIntermCase *node = new TIntermCase(nullptr);
+    node->setLine(loc);
     return node;
 }
 
@@ -4169,11 +4175,7 @@
     TIntermUnary *node = new TIntermUnary(op, child);
     node->setLine(loc);
 
-    TIntermTyped *foldedNode = node->fold(mDiagnostics);
-    if (foldedNode)
-        return foldedNode;
-
-    return node;
+    return node->fold(mDiagnostics);
 }
 
 TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
@@ -4529,11 +4531,7 @@
     node->setLine(loc);
 
     // See if we can fold constants.
-    TIntermTyped *foldedNode = node->fold(mDiagnostics);
-    if (foldedNode)
-        return foldedNode;
-
-    return node;
+    return node->fold(mDiagnostics);
 }
 
 TIntermTyped *TParseContext::addBinaryMath(TOperator op,
@@ -4623,7 +4621,10 @@
               ",");
     }
 
-    return TIntermediate::AddComma(left, right, loc, mShaderVersion);
+    TIntermBinary *commaNode   = new TIntermBinary(EOpComma, left, right);
+    TQualifier resultQualifier = TIntermBinary::GetCommaQualifier(mShaderVersion, left, right);
+    commaNode->getTypePointer()->setQualifier(resultQualifier);
+    return commaNode->fold(mDiagnostics);
 }
 
 TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
@@ -4948,15 +4949,16 @@
                     // Some built-in functions have out parameters too.
                     functionCallLValueErrorCheck(fnCandidate, callNode);
 
-                    // See if we can constant fold a built-in. Note that this may be possible even
-                    // if it is not const-qualified.
-                    TIntermTyped *foldedNode =
-                        intermediate.foldAggregateBuiltIn(callNode, mDiagnostics);
-                    if (foldedNode)
+                    if (TIntermAggregate::CanFoldAggregateBuiltInOp(callNode->getOp()))
                     {
-                        return foldedNode;
+                        // See if we can constant fold a built-in. Note that this may be possible
+                        // even if it is not const-qualified.
+                        return callNode->fold(mDiagnostics);
                     }
-                    return callNode;
+                    else
+                    {
+                        return callNode;
+                    }
                 }
             }
             else
@@ -5002,8 +5004,12 @@
 
     if (trueExpression->getType() != falseExpression->getType())
     {
-        binaryOpError(loc, "?:", trueExpression->getCompleteString(),
-                      falseExpression->getCompleteString());
+        std::stringstream reasonStream;
+        reasonStream << "mismatching ternary operator operand types '"
+                     << trueExpression->getCompleteString() << " and '"
+                     << falseExpression->getCompleteString() << "'";
+        std::string reason = reasonStream.str();
+        error(loc, reason.c_str(), "?:");
         return falseExpression;
     }
     if (IsOpaqueType(trueExpression->getBasicType()))
@@ -5042,7 +5048,12 @@
         return falseExpression;
     }
 
-    return TIntermediate::AddTernarySelection(cond, trueExpression, falseExpression, loc);
+    // Note that the node resulting from here can be a constant union without being qualified as
+    // constant.
+    TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression);
+    node->setLine(loc);
+
+    return node->fold();
 }
 
 //
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
index a7fe95d..be0a156 100644
--- a/src/compiler/translator/ParseContext.h
+++ b/src/compiler/translator/ParseContext.h
@@ -98,7 +98,11 @@
                                           const TString *name,
                                           const TSymbol *symbol);
 
-    bool parseVectorFields(const TString &, int vecSize, TVectorFields &, const TSourceLoc &line);
+    // Look at a '.' field selector string and change it into offsets for a vector.
+    bool parseVectorFields(const TSourceLoc &line,
+                           const TString &compString,
+                           int vecSize,
+                           TVector<int> *fieldOffsets);
 
     void assignError(const TSourceLoc &line, const char *op, TString left, TString right);
     void unaryOpError(const TSourceLoc &line, const char *op, TString operand);