Split TIntermBlock from TIntermAggregate

The new TIntermBlock node class replaces TIntermAggregate nodes with
the EOpSequence op. It represents the root node of the tree which is
a list of declarations and function definitions, and any code blocks
that can be denoted by curly braces. These include function and loop
bodies, and if-else branches.

This change enables a bunch of more compile-time type checking, and
makes the AST code easier to understand and less error-prone.

The PostProcess step that used to be done to ensure that the root node
is TIntermAggregate is removed in favor of making sure that the root
node is a TIntermBlock in the glslang.y parsing code.

Intermediate output formatting is improved to print the EOpNull error
in a clearer way.

After this patch, TIntermAggregate is still used for function
definitions, function prototypes, function parameter lists, function
calls, variable and invariant declarations and the comma (sequence)
operator.

BUG=angleproject:1490
TEST=angle_unittests, angle_end2end_tests

Change-Id: I04044affff979a11577bc1fe75d747e538b799c8
Reviewed-on: https://chromium-review.googlesource.com/393726
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/compiler/translator/AddDefaultReturnStatements.cpp b/src/compiler/translator/AddDefaultReturnStatements.cpp
index 25493a5..7261641 100644
--- a/src/compiler/translator/AddDefaultReturnStatements.cpp
+++ b/src/compiler/translator/AddDefaultReturnStatements.cpp
@@ -39,7 +39,7 @@
             return false;
         }
 
-        TIntermAggregate *bodyNode = node->getSequence()->back()->getAsAggregate();
+        TIntermBlock *bodyNode = node->getSequence()->back()->getAsBlock();
         ASSERT(bodyNode);
         TIntermBranch *returnNode = bodyNode->getSequence()->back()->getAsBranchNode();
         if (returnNode != nullptr && returnNode->getFlowOp() == EOpReturn)
@@ -58,7 +58,7 @@
             TIntermBranch *branch =
                 new TIntermBranch(EOpReturn, TIntermTyped::CreateZero(returnType));
 
-            TIntermAggregate *bodyNode = node->getSequence()->back()->getAsAggregate();
+            TIntermBlock *bodyNode = node->getSequence()->back()->getAsBlock();
             bodyNode->getSequence()->push_back(branch);
 
             return false;
diff --git a/src/compiler/translator/ArrayReturnValueToOutParameter.cpp b/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
index 562d53d..7d223a5 100644
--- a/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
+++ b/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
@@ -136,15 +136,16 @@
                 // Cases 2 to 4 are already converted to simpler cases by SeparateExpressionsReturningArrays, so we
                 // only need to worry about the case where a function call returning an array forms an expression by
                 // itself.
-                TIntermAggregate *parentAgg = getParentNode()->getAsAggregate();
-                if (parentAgg != nullptr && parentAgg->getOp() == EOpSequence)
+                TIntermBlock *parentBlock = getParentNode()->getAsBlock();
+                if (parentBlock)
                 {
                     nextTemporaryIndex();
                     TIntermSequence replacements;
                     replacements.push_back(createTempDeclaration(node->getType()));
                     TIntermSymbol *returnSymbol = createTempSymbol(node->getType());
                     replacements.push_back(CreateReplacementCall(node, returnSymbol));
-                    mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, replacements));
+                    mMultiReplacements.push_back(
+                        NodeReplaceWithMultipleEntry(parentBlock, node, replacements));
                 }
                 return false;
             }
@@ -179,7 +180,8 @@
         replacementBranch->setLine(node->getLine());
         replacements.push_back(replacementBranch);
 
-        mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(getParentNode()->getAsAggregate(), node, replacements));
+        mMultiReplacements.push_back(
+            NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), node, replacements));
     }
     return false;
 }
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 547c09b..2ac8528 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -232,16 +232,16 @@
     return true;
 }
 
-TIntermNode *TCompiler::compileTreeForTesting(const char *const shaderStrings[],
-                                              size_t numStrings,
-                                              ShCompileOptions compileOptions)
+TIntermBlock *TCompiler::compileTreeForTesting(const char *const shaderStrings[],
+                                               size_t numStrings,
+                                               ShCompileOptions compileOptions)
 {
     return compileTreeImpl(shaderStrings, numStrings, compileOptions);
 }
 
-TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
-                                        size_t numStrings,
-                                        const ShCompileOptions compileOptions)
+TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
+                                         size_t numStrings,
+                                         const ShCompileOptions compileOptions)
 {
     clearResults();
 
@@ -282,7 +282,7 @@
         success = false;
     }
 
-    TIntermNode *root = nullptr;
+    TIntermBlock *root = nullptr;
 
     if (success)
     {
@@ -293,7 +293,6 @@
         mComputeShaderLocalSize         = parseContext.getComputeShaderLocalSize();
 
         root = parseContext.getTreeRoot();
-        root = TIntermediate::PostProcess(root);
 
         // Highp might have been auto-enabled based on shader version
         fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh();
@@ -473,7 +472,7 @@
     }
 
     TScopedPoolAllocator scopedAlloc(&allocator);
-    TIntermNode *root = compileTreeImpl(shaderStrings, numStrings, compileOptions);
+    TIntermBlock *root = compileTreeImpl(shaderStrings, numStrings, compileOptions);
 
     if (root)
     {
@@ -787,13 +786,10 @@
     const std::vector<FunctionMetadata> *mMetadatas;
 };
 
-bool TCompiler::pruneUnusedFunctions(TIntermNode *root)
+bool TCompiler::pruneUnusedFunctions(TIntermBlock *root)
 {
-    TIntermAggregate *rootNode = root->getAsAggregate();
-    ASSERT(rootNode != nullptr);
-
     UnusedPredicate isUnused(&mCallDag, &functionMetadata);
-    TIntermSequence *sequence = rootNode->getSequence();
+    TIntermSequence *sequence = root->getSequence();
 
     if (!sequence->empty())
     {
diff --git a/src/compiler/translator/Compiler.h b/src/compiler/translator/Compiler.h
index ace1abb..be314ac 100644
--- a/src/compiler/translator/Compiler.h
+++ b/src/compiler/translator/Compiler.h
@@ -72,10 +72,10 @@
 
     // compileTreeForTesting should be used only when tests require access to
     // the AST. Users of this function need to manually manage the global pool
-    // allocator. Returns NULL whenever there are compilation errors.
-    TIntermNode *compileTreeForTesting(const char *const shaderStrings[],
-                                       size_t numStrings,
-                                       ShCompileOptions compileOptions);
+    // allocator. Returns nullptr whenever there are compilation errors.
+    TIntermBlock *compileTreeForTesting(const char *const shaderStrings[],
+                                        size_t numStrings,
+                                        ShCompileOptions compileOptions);
 
     bool compile(const char *const shaderStrings[],
                  size_t numStrings,
@@ -181,11 +181,11 @@
 
     // Removes unused function declarations and prototypes from the AST
     class UnusedPredicate;
-    bool pruneUnusedFunctions(TIntermNode *root);
+    bool pruneUnusedFunctions(TIntermBlock *root);
 
-    TIntermNode *compileTreeImpl(const char *const shaderStrings[],
-                                 size_t numStrings,
-                                 const ShCompileOptions compileOptions);
+    TIntermBlock *compileTreeImpl(const char *const shaderStrings[],
+                                  size_t numStrings,
+                                  const ShCompileOptions compileOptions);
 
     sh::GLenum shaderType;
     ShShaderSpec shaderSpec;
diff --git a/src/compiler/translator/DeferGlobalInitializers.cpp b/src/compiler/translator/DeferGlobalInitializers.cpp
index 285aa18..598eac0 100644
--- a/src/compiler/translator/DeferGlobalInitializers.cpp
+++ b/src/compiler/translator/DeferGlobalInitializers.cpp
@@ -39,7 +39,7 @@
 }
 
 TIntermAggregate *CreateFunctionDefinitionNode(const char *name,
-                                               TIntermAggregate *functionBody,
+                                               TIntermBlock *functionBody,
                                                const int functionId)
 {
     TIntermAggregate *functionNode = new TIntermAggregate(EOpFunction);
@@ -73,7 +73,7 @@
 
     bool visitBinary(Visit visit, TIntermBinary *node) override;
 
-    void insertInitFunction(TIntermNode *root);
+    void insertInitFunction(TIntermBlock *root);
 
   private:
     TIntermSequence mDeferredInitializers;
@@ -134,25 +134,23 @@
     return false;
 }
 
-void DeferGlobalInitializersTraverser::insertInitFunction(TIntermNode *root)
+void DeferGlobalInitializersTraverser::insertInitFunction(TIntermBlock *root)
 {
     if (mDeferredInitializers.empty())
     {
         return;
     }
     const int initFunctionId  = TSymbolTable::nextUniqueId();
-    TIntermAggregate *rootAgg = root->getAsAggregate();
-    ASSERT(rootAgg != nullptr && rootAgg->getOp() == EOpSequence);
 
     const char *functionName = "initializeDeferredGlobals";
 
     // Add function prototype to the beginning of the shader
     TIntermAggregate *functionPrototypeNode =
         CreateFunctionPrototypeNode(functionName, initFunctionId);
-    rootAgg->getSequence()->insert(rootAgg->getSequence()->begin(), functionPrototypeNode);
+    root->getSequence()->insert(root->getSequence()->begin(), functionPrototypeNode);
 
     // Add function definition to the end of the shader
-    TIntermAggregate *functionBodyNode = new TIntermAggregate(EOpSequence);
+    TIntermBlock *functionBodyNode = new TIntermBlock();
     TIntermSequence *functionBody = functionBodyNode->getSequence();
     for (const auto &deferredInit : mDeferredInitializers)
     {
@@ -160,10 +158,10 @@
     }
     TIntermAggregate *functionDefinition =
         CreateFunctionDefinitionNode(functionName, functionBodyNode, initFunctionId);
-    rootAgg->getSequence()->push_back(functionDefinition);
+    root->getSequence()->push_back(functionDefinition);
 
     // Insert call into main function
-    for (TIntermNode *node : *rootAgg->getSequence())
+    for (TIntermNode *node : *root->getSequence())
     {
         TIntermAggregate *nodeAgg = node->getAsAggregate();
         if (nodeAgg != nullptr && nodeAgg->getOp() == EOpFunction &&
@@ -172,18 +170,18 @@
             TIntermAggregate *functionCallNode =
                 CreateFunctionCallNode(functionName, initFunctionId);
 
-            TIntermNode *mainBody         = nodeAgg->getSequence()->back();
-            TIntermAggregate *mainBodyAgg = mainBody->getAsAggregate();
-            ASSERT(mainBodyAgg != nullptr && mainBodyAgg->getOp() == EOpSequence);
-            mainBodyAgg->getSequence()->insert(mainBodyAgg->getSequence()->begin(),
-                                               functionCallNode);
+            TIntermNode *mainBody       = nodeAgg->getSequence()->back();
+            TIntermBlock *mainBodyBlock = mainBody->getAsBlock();
+            ASSERT(mainBodyBlock != nullptr);
+            mainBodyBlock->getSequence()->insert(mainBodyBlock->getSequence()->begin(),
+                                                 functionCallNode);
         }
     }
 }
 
 }  // namespace
 
-void DeferGlobalInitializers(TIntermNode *root)
+void DeferGlobalInitializers(TIntermBlock *root)
 {
     DeferGlobalInitializersTraverser traverser;
     root->traverse(&traverser);
diff --git a/src/compiler/translator/DeferGlobalInitializers.h b/src/compiler/translator/DeferGlobalInitializers.h
index 14f2553..85e55d9 100644
--- a/src/compiler/translator/DeferGlobalInitializers.h
+++ b/src/compiler/translator/DeferGlobalInitializers.h
@@ -13,8 +13,8 @@
 #ifndef COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
 #define COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
 
-class TIntermNode;
+class TIntermBlock;
 
-void DeferGlobalInitializers(TIntermNode *root);
+void DeferGlobalInitializers(TIntermBlock *root);
 
 #endif  // COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
diff --git a/src/compiler/translator/EmulateGLFragColorBroadcast.cpp b/src/compiler/translator/EmulateGLFragColorBroadcast.cpp
index 431a326..2e2a19e 100644
--- a/src/compiler/translator/EmulateGLFragColorBroadcast.cpp
+++ b/src/compiler/translator/EmulateGLFragColorBroadcast.cpp
@@ -85,7 +85,7 @@
             {
                 TIntermSequence *sequence = node->getSequence();
                 ASSERT(sequence->size() == 2);
-                TIntermAggregate *body = (*sequence)[1]->getAsAggregate();
+                TIntermBlock *body = (*sequence)[1]->getAsBlock();
                 ASSERT(body);
                 mMainSequence = body->getSequence();
             }
diff --git a/src/compiler/translator/EmulatePrecision.cpp b/src/compiler/translator/EmulatePrecision.cpp
index a3025f0..cc80717 100644
--- a/src/compiler/translator/EmulatePrecision.cpp
+++ b/src/compiler/translator/EmulatePrecision.cpp
@@ -467,14 +467,15 @@
         return false;
     }
 
-    TIntermAggregate *aggParent = parent->getAsAggregate();
-    // If the parent's op is EOpSequence, the result is not assigned anywhere,
+    TIntermBlock *blockParent = parent->getAsBlock();
+    // If the parent is a block, the result is not assigned anywhere,
     // so rounding it is not needed. In particular, this can avoid a lot of
     // unnecessary rounding of unused return values of assignment.
-    if (aggParent && aggParent->getOp() == EOpSequence)
+    if (blockParent)
     {
         return false;
     }
+    TIntermAggregate *aggParent = parent->getAsAggregate();
     if (aggParent && aggParent->getOp() == EOpComma && (aggParent->getSequence()->back() != node))
     {
         return false;
@@ -602,7 +603,6 @@
     bool visitChildren = true;
     switch (node->getOp())
     {
-      case EOpSequence:
       case EOpConstructStruct:
       case EOpFunction:
         break;
diff --git a/src/compiler/translator/InitializeVariables.cpp b/src/compiler/translator/InitializeVariables.cpp
index 235f498..d44f2fa 100644
--- a/src/compiler/translator/InitializeVariables.cpp
+++ b/src/compiler/translator/InitializeVariables.cpp
@@ -45,8 +45,6 @@
     bool visitChildren = !mCodeInserted;
     switch (node->getOp())
     {
-      case EOpSequence:
-        break;
       case EOpFunction:
       {
         // Function definition.
@@ -55,7 +53,7 @@
         {
             TIntermSequence *sequence = node->getSequence();
             ASSERT(sequence->size() == 2);
-            TIntermAggregate *body = (*sequence)[1]->getAsAggregate();
+            TIntermBlock *body = (*sequence)[1]->getAsBlock();
             ASSERT(body);
             insertInitCode(body->getSequence());
             mCodeInserted = true;
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index 09bc972..4f09fac 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -170,7 +170,7 @@
     REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
     REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
     REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
-    REPLACE_IF_IS(mBody, TIntermAggregate, original, replacement);
+    REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
     return false;
 }
 
@@ -207,35 +207,47 @@
 bool TIntermAggregate::replaceChildNode(
     TIntermNode *original, TIntermNode *replacement)
 {
-    for (size_t ii = 0; ii < mSequence.size(); ++ii)
+    return replaceChildNodeInternal(original, replacement);
+}
+
+bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+    return replaceChildNodeInternal(original, replacement);
+}
+
+bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
+{
+    for (size_t ii = 0; ii < getSequence()->size(); ++ii)
     {
-        REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
+        REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
     }
     return false;
 }
 
-bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
+bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
+                                                        const TIntermSequence &replacements)
 {
-    for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
+    for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
     {
         if (*it == original)
         {
-            it = mSequence.erase(it);
-            mSequence.insert(it, replacements.begin(), replacements.end());
+            it = getSequence()->erase(it);
+            getSequence()->insert(it, replacements.begin(), replacements.end());
             return true;
         }
     }
     return false;
 }
 
-bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
+bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
+                                            const TIntermSequence &insertions)
 {
-    if (position > mSequence.size())
+    if (position > getSequence()->size())
     {
         return false;
     }
-    auto it = mSequence.begin() + position;
-    mSequence.insert(it, insertions.begin(), insertions.end());
+    auto it = getSequence()->begin() + position;
+    getSequence()->insert(it, insertions.begin(), insertions.end());
     return true;
 }
 
@@ -299,6 +311,14 @@
         mType.setPrecision(precision);
 }
 
+void TIntermBlock::appendStatement(TIntermNode *statement)
+{
+    if (statement != nullptr)
+    {
+        mStatements.push_back(statement);
+    }
+}
+
 bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
 {
     REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
@@ -310,8 +330,8 @@
 bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
 {
     REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
-    REPLACE_IF_IS(mTrueBlock, TIntermAggregate, original, replacement);
-    REPLACE_IF_IS(mFalseBlock, TIntermAggregate, original, replacement);
+    REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
+    REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
     return false;
 }
 
@@ -319,7 +339,7 @@
     TIntermNode *original, TIntermNode *replacement)
 {
     REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
-    REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
+    REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
     return false;
 }
 
diff --git a/src/compiler/translator/IntermNode.h b/src/compiler/translator/IntermNode.h
index f261e76..0a04941 100644
--- a/src/compiler/translator/IntermNode.h
+++ b/src/compiler/translator/IntermNode.h
@@ -31,6 +31,7 @@
 
 class TIntermTraverser;
 class TIntermAggregate;
+class TIntermBlock;
 class TIntermSwizzle;
 class TIntermBinary;
 class TIntermUnary;
@@ -93,6 +94,7 @@
     virtual TIntermTyped *getAsTyped() { return 0; }
     virtual TIntermConstantUnion *getAsConstantUnion() { return 0; }
     virtual TIntermAggregate *getAsAggregate() { return 0; }
+    virtual TIntermBlock *getAsBlock() { return nullptr; }
     virtual TIntermSwizzle *getAsSwizzleNode() { return nullptr; }
     virtual TIntermBinary *getAsBinaryNode() { return 0; }
     virtual TIntermUnary *getAsUnaryNode() { return 0; }
@@ -189,7 +191,7 @@
                 TIntermNode *init,
                 TIntermTyped *cond,
                 TIntermTyped *expr,
-                TIntermAggregate *body)
+                TIntermBlock *body)
         : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body), mUnrollFlag(false)
     {
     }
@@ -202,11 +204,11 @@
     TIntermNode *getInit() { return mInit; }
     TIntermTyped *getCondition() { return mCond; }
     TIntermTyped *getExpression() { return mExpr; }
-    TIntermAggregate *getBody() { return mBody; }
+    TIntermBlock *getBody() { return mBody; }
 
     void setCondition(TIntermTyped *condition) { mCond = condition; }
     void setExpression(TIntermTyped *expression) { mExpr = expression; }
-    void setBody(TIntermAggregate *body) { mBody = body; }
+    void setBody(TIntermBlock *body) { mBody = body; }
 
     void setUnrollFlag(bool flag) { mUnrollFlag = flag; }
     bool getUnrollFlag() const { return mUnrollFlag; }
@@ -216,7 +218,7 @@
     TIntermNode *mInit;  // for-loop initialization
     TIntermTyped *mCond; // loop exit condition
     TIntermTyped *mExpr; // for-loop expression
-    TIntermAggregate *mBody;  // loop body
+    TIntermBlock *mBody;  // loop body
 
     bool mUnrollFlag; // Whether the loop should be unrolled or not.
 };
@@ -525,10 +527,26 @@
 typedef TVector<TIntermNode *> TIntermSequence;
 typedef TVector<int> TQualifierList;
 
+// Interface for node classes that have an arbitrarily sized set of children.
+class TIntermAggregateBase
+{
+  public:
+    virtual TIntermSequence *getSequence()             = 0;
+    virtual const TIntermSequence *getSequence() const = 0;
+
+    bool replaceChildNodeWithMultiple(TIntermNode *original, const TIntermSequence &replacements);
+    bool insertChildNodes(TIntermSequence::size_type position, const TIntermSequence &insertions);
+
+  protected:
+    TIntermAggregateBase() {}
+
+    bool replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement);
+};
+
 //
 // Nodes that operate on an arbitrary sized set of children.
 //
-class TIntermAggregate : public TIntermOperator
+class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase
 {
   public:
     TIntermAggregate()
@@ -557,8 +575,7 @@
     TIntermAggregate *getAsAggregate() override { return this; }
     void traverse(TIntermTraverser *it) override;
     bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
-    bool replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements);
-    bool insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions);
+
     // Conservatively assume function calls and other aggregate operators have side-effects
     bool hasSideEffects() const override { return true; }
     TIntermTyped *fold(TDiagnostics *diagnostics);
@@ -604,6 +621,28 @@
     TIntermAggregate(const TIntermAggregate &node);  // note: not deleted, just private!
 };
 
+// A list of statements. Either the root node which contains declarations and function definitions,
+// or a block that can be marked with curly braces {}.
+class TIntermBlock : public TIntermNode, public TIntermAggregateBase
+{
+  public:
+    TIntermBlock() : TIntermNode() {}
+    ~TIntermBlock() {}
+
+    TIntermBlock *getAsBlock() override { return this; }
+    void traverse(TIntermTraverser *it) override;
+    bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+    // Only intended for initially building the block.
+    void appendStatement(TIntermNode *statement);
+
+    TIntermSequence *getSequence() override { return &mStatements; }
+    const TIntermSequence *getSequence() const override { return &mStatements; }
+
+  protected:
+    TIntermSequence mStatements;
+};
+
 // For ternary operators like a ? b : c.
 class TIntermTernary : public TIntermTyped
 {
@@ -641,7 +680,7 @@
 class TIntermIfElse : public TIntermNode
 {
   public:
-    TIntermIfElse(TIntermTyped *cond, TIntermAggregate *trueB, TIntermAggregate *falseB)
+    TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
         : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
     {
     }
@@ -650,14 +689,14 @@
     bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
 
     TIntermTyped *getCondition() const { return mCondition; }
-    TIntermAggregate *getTrueBlock() const { return mTrueBlock; }
-    TIntermAggregate *getFalseBlock() const { return mFalseBlock; }
+    TIntermBlock *getTrueBlock() const { return mTrueBlock; }
+    TIntermBlock *getFalseBlock() const { return mFalseBlock; }
     TIntermIfElse *getAsIfElseNode() override { return this; }
 
   protected:
     TIntermTyped *mCondition;
-    TIntermAggregate *mTrueBlock;
-    TIntermAggregate *mFalseBlock;
+    TIntermBlock *mTrueBlock;
+    TIntermBlock *mFalseBlock;
 };
 
 //
@@ -666,10 +705,8 @@
 class TIntermSwitch : public TIntermNode
 {
   public:
-    TIntermSwitch(TIntermTyped *init, TIntermAggregate *statementList)
-        : TIntermNode(),
-          mInit(init),
-          mStatementList(statementList)
+    TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
+        : TIntermNode(), mInit(init), mStatementList(statementList)
     {
     }
 
@@ -680,12 +717,12 @@
     TIntermSwitch *getAsSwitchNode() override { return this; }
 
     TIntermTyped *getInit() { return mInit; }
-    TIntermAggregate *getStatementList() { return mStatementList; }
-    void setStatementList(TIntermAggregate *statementList) { mStatementList = statementList; }
+    TIntermBlock *getStatementList() { return mStatementList; }
+    void setStatementList(TIntermBlock *statementList) { mStatementList = statementList; }
 
   protected:
     TIntermTyped *mInit;
-    TIntermAggregate *mStatementList;
+    TIntermBlock *mStatementList;
 };
 
 //
@@ -749,6 +786,7 @@
     virtual bool visitSwitch(Visit visit, TIntermSwitch *node) { return true; }
     virtual bool visitCase(Visit visit, TIntermCase *node) { return true; }
     virtual bool visitAggregate(Visit visit, TIntermAggregate *node) { return true; }
+    virtual bool visitBlock(Visit visit, TIntermBlock *node) { return true; }
     virtual bool visitLoop(Visit visit, TIntermLoop *node) { return true; }
     virtual bool visitBranch(Visit visit, TIntermBranch *node) { return true; }
 
@@ -766,6 +804,7 @@
     virtual void traverseSwitch(TIntermSwitch *node);
     virtual void traverseCase(TIntermCase *node);
     virtual void traverseAggregate(TIntermAggregate *node);
+    virtual void traverseBlock(TIntermBlock *node);
     virtual void traverseLoop(TIntermLoop *node);
     virtual void traverseBranch(TIntermBranch *node);
 
@@ -812,7 +851,7 @@
         return nullptr;
     }
 
-    void pushParentBlock(TIntermAggregate *node);
+    void pushParentBlock(TIntermBlock *node);
     void incrementParentBlockPos();
     void popParentBlock();
 
@@ -824,14 +863,14 @@
     // To replace a single node with multiple nodes on the parent aggregate node
     struct NodeReplaceWithMultipleEntry
     {
-        NodeReplaceWithMultipleEntry(TIntermAggregate *_parent, TIntermNode *_original, TIntermSequence _replacements)
-            : parent(_parent),
-              original(_original),
-              replacements(_replacements)
+        NodeReplaceWithMultipleEntry(TIntermAggregateBase *_parent,
+                                     TIntermNode *_original,
+                                     TIntermSequence _replacements)
+            : parent(_parent), original(_original), replacements(_replacements)
         {
         }
 
-        TIntermAggregate *parent;
+        TIntermAggregateBase *parent;
         TIntermNode *original;
         TIntermSequence replacements;
     };
@@ -839,7 +878,7 @@
     // To insert multiple nodes on the parent aggregate node
     struct NodeInsertMultipleEntry
     {
-        NodeInsertMultipleEntry(TIntermAggregate *_parent,
+        NodeInsertMultipleEntry(TIntermBlock *_parent,
                                 TIntermSequence::size_type _position,
                                 TIntermSequence _insertionsBefore,
                                 TIntermSequence _insertionsAfter)
@@ -850,7 +889,7 @@
         {
         }
 
-        TIntermAggregate *parent;
+        TIntermBlock *parent;
         TIntermSequence::size_type position;
         TIntermSequence insertionsBefore;
         TIntermSequence insertionsAfter;
@@ -942,13 +981,12 @@
 
     struct ParentBlock
     {
-        ParentBlock(TIntermAggregate *nodeIn, TIntermSequence::size_type posIn)
-            : node(nodeIn),
-              pos(posIn)
+        ParentBlock(TIntermBlock *nodeIn, TIntermSequence::size_type posIn)
+            : node(nodeIn), pos(posIn)
         {
         }
 
-        TIntermAggregate *node;
+        TIntermBlock *node;
         TIntermSequence::size_type pos;
     };
 
@@ -1052,6 +1090,7 @@
     bool visitTernary(Visit, TIntermTernary *) override { return depthCheck(); }
     bool visitIfElse(Visit, TIntermIfElse *) override { return depthCheck(); }
     bool visitAggregate(Visit, TIntermAggregate *) override { return depthCheck(); }
+    bool visitBlock(Visit, TIntermBlock *) override { return depthCheck(); }
     bool visitLoop(Visit, TIntermLoop *) override { return depthCheck(); }
     bool visitBranch(Visit, TIntermBranch *) override { return depthCheck(); }
 
diff --git a/src/compiler/translator/IntermNodePatternMatcher.cpp b/src/compiler/translator/IntermNodePatternMatcher.cpp
index 6307563..4177b05 100644
--- a/src/compiler/translator/IntermNodePatternMatcher.cpp
+++ b/src/compiler/translator/IntermNodePatternMatcher.cpp
@@ -12,17 +12,6 @@
 
 #include "compiler/translator/IntermNode.h"
 
-namespace
-{
-
-bool IsNodeBlock(TIntermNode *node)
-{
-    ASSERT(node != nullptr);
-    return (node->getAsAggregate() && node->getAsAggregate()->getOp() == EOpSequence);
-}
-
-}  // anonymous namespace
-
 IntermNodePatternMatcher::IntermNodePatternMatcher(const unsigned int mask) : mMask(mask)
 {
 }
@@ -39,7 +28,7 @@
     if ((mMask & kExpressionReturningArray) != 0)
     {
         if (node->isArray() && node->getOp() == EOpAssign && parentNode != nullptr &&
-            !IsNodeBlock(parentNode))
+            !parentNode->getAsBlock())
         {
             return true;
         }
@@ -96,7 +85,7 @@
 
             if (node->getType().isArray() && !parentIsAssignment &&
                 (node->isConstructor() || node->getOp() == EOpFunctionCall) &&
-                !IsNodeBlock(parentNode))
+                !parentNode->getAsBlock())
             {
                 return true;
             }
diff --git a/src/compiler/translator/IntermTraverse.cpp b/src/compiler/translator/IntermTraverse.cpp
index 89a9a52..e094414 100644
--- a/src/compiler/translator/IntermTraverse.cpp
+++ b/src/compiler/translator/IntermTraverse.cpp
@@ -58,6 +58,11 @@
     it->traverseCase(this);
 }
 
+void TIntermBlock::traverse(TIntermTraverser *it)
+{
+    it->traverseBlock(this);
+}
+
 void TIntermAggregate::traverse(TIntermTraverser *it)
 {
     it->traverseAggregate(this);
@@ -88,7 +93,7 @@
 {
 }
 
-void TIntermTraverser::pushParentBlock(TIntermAggregate *node)
+void TIntermTraverser::pushParentBlock(TIntermBlock *node)
 {
     mParentBlockStack.push_back(ParentBlock(node, 0));
 }
@@ -418,9 +423,42 @@
         visitUnary(PostVisit, node);
 }
 
-//
+// Traverse a block node.
+void TIntermTraverser::traverseBlock(TIntermBlock *node)
+{
+    bool visit = true;
+
+    TIntermSequence *sequence = node->getSequence();
+
+    if (preVisit)
+        visit = visitBlock(PreVisit, node);
+
+    if (visit)
+    {
+        incrementDepth(node);
+        pushParentBlock(node);
+
+        for (auto *child : *sequence)
+        {
+            child->traverse(this);
+            if (visit && inVisit)
+            {
+                if (child != sequence->back())
+                    visit = visitBlock(InVisit, node);
+            }
+
+            incrementParentBlockPos();
+        }
+
+        popParentBlock();
+        decrementDepth();
+    }
+
+    if (visit && postVisit)
+        visitBlock(PostVisit, node);
+}
+
 // Traverse an aggregate node.  Same comments in binary node apply here.
-//
 void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
 {
     bool visit = true;
@@ -434,9 +472,7 @@
     {
         incrementDepth(node);
 
-        if (node->getOp() == EOpSequence)
-            pushParentBlock(node);
-        else if (node->getOp() == EOpFunction)
+        if (node->getOp() == EOpFunction)
             mInGlobalScope = false;
 
         for (auto *child : *sequence)
@@ -447,14 +483,9 @@
                 if (child != sequence->back())
                     visit = visitAggregate(InVisit, node);
             }
-
-            if (node->getOp() == EOpSequence)
-                incrementParentBlockPos();
         }
 
-        if (node->getOp() == EOpSequence)
-            popParentBlock();
-        else if (node->getOp() == EOpFunction)
+        if (node->getOp() == EOpFunction)
             mInGlobalScope = true;
 
         decrementDepth();
@@ -529,9 +560,7 @@
         }
         else
         {
-            if (node->getOp() == EOpSequence)
-                pushParentBlock(node);
-            else if (node->getOp() == EOpFunction)
+            if (node->getOp() == EOpFunction)
                 mInGlobalScope = false;
 
             // Find the built-in function corresponding to this op so that we can determine the
@@ -575,17 +604,12 @@
                         visit = visitAggregate(InVisit, node);
                 }
 
-                if (node->getOp() == EOpSequence)
-                    incrementParentBlockPos();
-
                 ++paramIndex;
             }
 
             setInFunctionCallOutParameter(false);
 
-            if (node->getOp() == EOpSequence)
-                popParentBlock();
-            else if (node->getOp() == EOpFunction)
+            if (node->getOp() == EOpFunction)
                 mInGlobalScope = true;
         }
 
diff --git a/src/compiler/translator/Intermediate.cpp b/src/compiler/translator/Intermediate.cpp
index 57d53bf..bb75d9a 100644
--- a/src/compiler/translator/Intermediate.cpp
+++ b/src/compiler/translator/Intermediate.cpp
@@ -62,16 +62,12 @@
     return node;
 }
 
-//
 // This is the safe way to change the operator on an aggregate, as it
 // does lots of error checking and fixing.  Especially for establishing
-// a function call's operation on it's set of parameters.  Sequences
-// of instructions are also aggregates, but they just direnctly set
-// their operator to EOpSequence.
+// a function call's operation on it's set of parameters.
 //
 // Returns an aggregate node, which could be the one passed in if
 // it was already an aggregate but no operator was set.
-//
 TIntermAggregate *TIntermediate::setAggregateOperator(
     TIntermNode *node, TOperator op, const TSourceLoc &line)
 {
@@ -156,19 +152,20 @@
 }
 
 // If the input node is nullptr, return nullptr.
-// If the input node is a sequence (block) node, return it.
-// If the input node is not a sequence node, put it inside a sequence node and return that.
-TIntermAggregate *TIntermediate::EnsureSequence(TIntermNode *node)
+// 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.
+TIntermBlock *TIntermediate::EnsureBlock(TIntermNode *node)
 {
     if (node == nullptr)
         return nullptr;
-    TIntermAggregate *aggNode = node->getAsAggregate();
-    if (aggNode != nullptr && aggNode->getOp() == EOpSequence)
-        return aggNode;
+    TIntermBlock *blockNode = node->getAsBlock();
+    if (blockNode != nullptr)
+        return blockNode;
 
-    aggNode = MakeAggregate(node, node->getLine());
-    aggNode->setOp(EOpSequence);
-    return aggNode;
+    blockNode = new TIntermBlock();
+    blockNode->setLine(node->getLine());
+    blockNode->getSequence()->push_back(node);
+    return blockNode;
 }
 
 // For "if" test nodes.  There are three children; a condition,
@@ -186,20 +183,16 @@
     {
         if (cond->getAsConstantUnion()->getBConst(0) == true)
         {
-            return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence,
-                                                         nodePair.node1->getLine())
-                                  : nullptr;
+            return EnsureBlock(nodePair.node1);
         }
         else
         {
-            return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence,
-                                                         nodePair.node2->getLine())
-                                  : nullptr;
+            return EnsureBlock(nodePair.node2);
         }
     }
 
     TIntermIfElse *node =
-        new TIntermIfElse(cond, EnsureSequence(nodePair.node1), EnsureSequence(nodePair.node2));
+        new TIntermIfElse(cond, EnsureBlock(nodePair.node1), EnsureBlock(nodePair.node2));
     node->setLine(line);
 
     return node;
@@ -269,8 +262,9 @@
     return node;
 }
 
-TIntermSwitch *TIntermediate::addSwitch(
-    TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line)
+TIntermSwitch *TIntermediate::addSwitch(TIntermTyped *init,
+                                        TIntermBlock *statementList,
+                                        const TSourceLoc &line)
 {
     TIntermSwitch *node = new TIntermSwitch(init, statementList);
     node->setLine(line);
@@ -331,7 +325,7 @@
     TLoopType type, TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr,
     TIntermNode *body, const TSourceLoc &line)
 {
-    TIntermNode *node = new TIntermLoop(type, init, cond, expr, EnsureSequence(body));
+    TIntermNode *node = new TIntermLoop(type, init, cond, expr, EnsureBlock(body));
     node->setLine(line);
 
     return node;
@@ -355,33 +349,6 @@
     return node;
 }
 
-//
-// This is to be executed once the final root is put on top by the parsing
-// process.
-//
-TIntermAggregate *TIntermediate::PostProcess(TIntermNode *root)
-{
-    if (root == nullptr)
-        return nullptr;
-
-    //
-    // Finish off the top level sequence, if any
-    //
-    TIntermAggregate *aggRoot = root->getAsAggregate();
-    if (aggRoot != nullptr && aggRoot->getOp() == EOpNull)
-    {
-        aggRoot->setOp(EOpSequence);
-    }
-    else if (aggRoot == nullptr || aggRoot->getOp() != EOpSequence)
-    {
-        aggRoot = new TIntermAggregate(EOpSequence);
-        aggRoot->setLine(root->getLine());
-        aggRoot->getSequence()->push_back(root);
-    }
-
-    return aggRoot;
-}
-
 TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate,
                                                   TDiagnostics *diagnostics)
 {
diff --git a/src/compiler/translator/Intermediate.h b/src/compiler/translator/Intermediate.h
index c4a21d8..f5878bd 100644
--- a/src/compiler/translator/Intermediate.h
+++ b/src/compiler/translator/Intermediate.h
@@ -36,15 +36,16 @@
     TIntermAggregate *growAggregate(
         TIntermNode *left, TIntermNode *right, const TSourceLoc &);
     static TIntermAggregate *MakeAggregate(TIntermNode *node, const TSourceLoc &line);
-    static TIntermAggregate *EnsureSequence(TIntermNode *node);
+    static TIntermBlock *EnsureBlock(TIntermNode *node);
     TIntermAggregate *setAggregateOperator(TIntermNode *, TOperator, const TSourceLoc &);
     TIntermNode *addIfElse(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &line);
     static TIntermTyped *AddTernarySelection(TIntermTyped *cond,
                                              TIntermTyped *trueExpression,
                                              TIntermTyped *falseExpression,
                                              const TSourceLoc &line);
-    TIntermSwitch *addSwitch(
-        TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line);
+    TIntermSwitch *addSwitch(TIntermTyped *init,
+                             TIntermBlock *statementList,
+                             const TSourceLoc &line);
     TIntermCase *addCase(
         TIntermTyped *condition, const TSourceLoc &line);
     TIntermTyped *addComma(TIntermTyped *left,
@@ -61,7 +62,6 @@
     static TIntermTyped *AddSwizzle(TIntermTyped *baseExpression,
                                     const TVectorFields &fields,
                                     const TSourceLoc &dotLocation);
-    static TIntermAggregate *PostProcess(TIntermNode *root);
 
     static void outputTree(TIntermNode *, TInfoSinkBase &);
 
diff --git a/src/compiler/translator/Operator.h b/src/compiler/translator/Operator.h
index 4793721..2080666 100644
--- a/src/compiler/translator/Operator.h
+++ b/src/compiler/translator/Operator.h
@@ -13,7 +13,6 @@
 enum TOperator
 {
     EOpNull,            // if in a node, should only mean a node is still being built
-    EOpSequence,        // denotes a list of statements, or parameters, etc.
     EOpFunctionCall,
     EOpFunction,        // For function definition
     EOpParameters,      // an aggregate listing the parameters to a function
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index 32db9de..ecd47fa 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -24,8 +24,11 @@
 {
     if (const TIntermAggregate *aggregate = node->getAsAggregate())
     {
-        return (aggregate->getOp() != EOpFunction) &&
-               (aggregate->getOp() != EOpSequence);
+        return (aggregate->getOp() != EOpFunction);
+    }
+    else if (node->getAsBlock())
+    {
+        return false;
     }
     else if (node->getAsIfElseNode())
     {
@@ -753,6 +756,36 @@
     }
 }
 
+bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
+{
+    TInfoSinkBase &out = objSink();
+    // Scope the blocks except when at the global scope.
+    if (mDepth > 0)
+    {
+        out << "{\n";
+    }
+
+    incrementDepth(node);
+    for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
+         iter != node->getSequence()->end(); ++iter)
+    {
+        TIntermNode *curNode = *iter;
+        ASSERT(curNode != nullptr);
+        curNode->traverse(this);
+
+        if (isSingleStatement(curNode))
+            out << ";\n";
+    }
+    decrementDepth();
+
+    // Scope the blocks except when at the global scope.
+    if (mDepth > 0)
+    {
+        out << "}\n";
+    }
+    return false;
+}
+
 bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
 {
     bool visitChildren = true;
@@ -760,33 +793,6 @@
     bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
     switch (node->getOp())
     {
-      case EOpSequence:
-        // Scope the sequences except when at the global scope.
-        if (mDepth > 0)
-        {
-            out << "{\n";
-        }
-
-        incrementDepth(node);
-        for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
-             iter != node->getSequence()->end(); ++iter)
-        {
-            TIntermNode *curNode = *iter;
-            ASSERT(curNode != NULL);
-            curNode->traverse(this);
-
-            if (isSingleStatement(curNode))
-                out << ";\n";
-        }
-        decrementDepth();
-
-        // Scope the sequences except when at the global scope.
-        if (mDepth > 0)
-        {
-            out << "}\n";
-        }
-        visitChildren = false;
-        break;
       case EOpPrototype:
         // Function declaration.
         ASSERT(visit == PreVisit);
@@ -830,7 +836,7 @@
         params->traverse(this);
 
         // Traverse function body.
-        TIntermAggregate *body = sequence[1]->getAsAggregate();
+        TIntermBlock *body = sequence[1]->getAsBlock();
         visitCodeBlock(body);
         decrementDepth();
 
@@ -1106,7 +1112,7 @@
     return true;
 }
 
-void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
+void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
 {
     TInfoSinkBase &out = objSink();
     if (node != NULL)
diff --git a/src/compiler/translator/OutputGLSLBase.h b/src/compiler/translator/OutputGLSLBase.h
index f8df0cd..b95952f 100644
--- a/src/compiler/translator/OutputGLSLBase.h
+++ b/src/compiler/translator/OutputGLSLBase.h
@@ -50,10 +50,11 @@
     bool visitSwitch(Visit visit, TIntermSwitch *node) override;
     bool visitCase(Visit visit, TIntermCase *node) override;
     bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+    bool visitBlock(Visit visit, TIntermBlock *node) override;
     bool visitLoop(Visit visit, TIntermLoop *node) override;
     bool visitBranch(Visit visit, TIntermBranch *node) override;
 
-    void visitCodeBlock(TIntermNode *node);
+    void visitCodeBlock(TIntermBlock *node);
 
     // Return the original name if hash function pointer is NULL;
     // otherwise return the hashed name.
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 47c3894..f3f59e3 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -31,11 +31,6 @@
 namespace
 {
 
-bool IsSequence(TIntermNode *node)
-{
-    return node->getAsAggregate() != nullptr && node->getAsAggregate()->getOp() == EOpSequence;
-}
-
 void WriteSingleConstant(TInfoSinkBase &out, const TConstantUnion *const constUnion)
 {
     ASSERT(constUnion != nullptr);
@@ -1418,44 +1413,48 @@
     }
 }
 
+bool OutputHLSL::visitBlock(Visit visit, TIntermBlock *node)
+{
+    TInfoSinkBase &out = getInfoSink();
+
+    if (mInsideFunction)
+    {
+        outputLineDirective(out, node->getLine().first_line);
+        out << "{\n";
+    }
+
+    for (TIntermSequence::iterator sit = node->getSequence()->begin();
+         sit != node->getSequence()->end(); sit++)
+    {
+        outputLineDirective(out, (*sit)->getLine().first_line);
+
+        (*sit)->traverse(this);
+
+        // Don't output ; after case labels, they're terminated by :
+        // This is needed especially since outputting a ; after a case statement would turn empty
+        // case statements into non-empty case statements, disallowing fall-through from them.
+        // Also no need to output ; after if statements or sequences. This is done just for
+        // code clarity.
+        if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsIfElseNode() == nullptr &&
+            (*sit)->getAsBlock() == nullptr)
+            out << ";\n";
+    }
+
+    if (mInsideFunction)
+    {
+        outputLineDirective(out, node->getLine().last_line);
+        out << "}\n";
+    }
+
+    return false;
+}
+
 bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
 {
     TInfoSinkBase &out = getInfoSink();
 
     switch (node->getOp())
     {
-        case EOpSequence:
-        {
-            if (mInsideFunction)
-            {
-                outputLineDirective(out, node->getLine().first_line);
-                out << "{\n";
-            }
-
-            for (TIntermSequence::iterator sit = node->getSequence()->begin(); sit != node->getSequence()->end(); sit++)
-            {
-                outputLineDirective(out, (*sit)->getLine().first_line);
-
-                (*sit)->traverse(this);
-
-                // Don't output ; after case labels, they're terminated by :
-                // This is needed especially since outputting a ; after a case statement would turn empty
-                // case statements into non-empty case statements, disallowing fall-through from them.
-                // Also no need to output ; after if statements or sequences. This is done just for
-                // code clarity.
-                if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsIfElseNode() == nullptr &&
-                    !IsSequence(*sit))
-                    out << ";\n";
-            }
-
-            if (mInsideFunction)
-            {
-                outputLineDirective(out, node->getLine().last_line);
-                out << "}\n";
-            }
-
-            return false;
-        }
         case EOpDeclaration:
             if (visit == PreVisit)
             {
@@ -1629,7 +1628,7 @@
             ASSERT(sequence->size() == 2);
             TIntermNode *body = (*sequence)[1];
             // The function body node will output braces.
-            ASSERT(IsSequence(body));
+            ASSERT(body->getAsBlock() != nullptr);
             body->traverse(this);
             mInsideFunction = false;
 
@@ -1928,8 +1927,6 @@
     if (node->getTrueBlock())
     {
         // The trueBlock child node will output braces.
-        ASSERT(IsSequence(node->getTrueBlock()));
-
         node->getTrueBlock()->traverse(this);
 
         // Detect true discard
@@ -1951,8 +1948,6 @@
         outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
 
         // The falseBlock child node will output braces.
-        ASSERT(IsSequence(node->getFalseBlock()));
-
         node->getFalseBlock()->traverse(this);
 
         outputLineDirective(out, node->getFalseBlock()->getLine().first_line);
@@ -2092,7 +2087,6 @@
     if (node->getBody())
     {
         // The loop body node will output braces.
-        ASSERT(IsSequence(node->getBody()));
         node->getBody()->traverse(this);
     }
     else
@@ -2182,15 +2176,15 @@
 
 bool OutputHLSL::isSingleStatement(TIntermNode *node)
 {
-    TIntermAggregate *aggregate = node->getAsAggregate();
+    if (node->getAsBlock())
+    {
+        return false;
+    }
 
+    TIntermAggregate *aggregate = node->getAsAggregate();
     if (aggregate)
     {
-        if (aggregate->getOp() == EOpSequence)
-        {
-            return false;
-        }
-        else if (aggregate->getOp() == EOpDeclaration)
+        if (aggregate->getOp() == EOpDeclaration)
         {
             // Declaring multiple comma-separated variables must be considered multiple statements
             // because each individual declaration has side effects which are visible in the next.
diff --git a/src/compiler/translator/OutputHLSL.h b/src/compiler/translator/OutputHLSL.h
index ab4f9b3..b76062e 100644
--- a/src/compiler/translator/OutputHLSL.h
+++ b/src/compiler/translator/OutputHLSL.h
@@ -67,6 +67,7 @@
     bool visitSwitch(Visit visit, TIntermSwitch *);
     bool visitCase(Visit visit, TIntermCase *);
     bool visitAggregate(Visit visit, TIntermAggregate*);
+    bool visitBlock(Visit visit, TIntermBlock *node);
     bool visitLoop(Visit visit, TIntermLoop*);
     bool visitBranch(Visit visit, TIntermBranch*);
 
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 99d6968..36a2d84 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -2060,7 +2060,7 @@
 
 TIntermAggregate *TParseContext::addFunctionDefinition(const TFunction &function,
                                                        TIntermAggregate *functionPrototype,
-                                                       TIntermAggregate *functionBody,
+                                                       TIntermBlock *functionBody,
                                                        const TSourceLoc &location)
 {
     // Check that non-void functions have at least one return statement.
@@ -2077,7 +2077,7 @@
 
     if (functionBody == nullptr)
     {
-        functionBody = new TIntermAggregate(EOpSequence);
+        functionBody = new TIntermBlock();
         functionBody->setLine(location);
     }
     functionNode->getSequence()->push_back(functionBody);
@@ -3085,7 +3085,7 @@
 }
 
 TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init,
-                                        TIntermAggregate *statementList,
+                                        TIntermBlock *statementList,
                                         const TSourceLoc &loc)
 {
     TBasicType switchType = init->getBasicType();
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
index c2c4bf2..aeb901c 100644
--- a/src/compiler/translator/ParseContext.h
+++ b/src/compiler/translator/ParseContext.h
@@ -94,8 +94,8 @@
                          const char *token,
                          const char *extraInfo = "");
 
-    TIntermNode *getTreeRoot() const { return mTreeRoot; }
-    void setTreeRoot(TIntermNode *treeRoot) { mTreeRoot = treeRoot; }
+    TIntermBlock *getTreeRoot() const { return mTreeRoot; }
+    void setTreeRoot(TIntermBlock *treeRoot) { mTreeRoot = treeRoot; }
 
     bool getFragmentPrecisionHigh() const
     {
@@ -268,7 +268,7 @@
                                                       const TSourceLoc &location);
     TIntermAggregate *addFunctionDefinition(const TFunction &function,
                                             TIntermAggregate *functionPrototype,
-                                            TIntermAggregate *functionBody,
+                                            TIntermBlock *functionBody,
                                             const TSourceLoc &location);
     void parseFunctionPrototype(const TSourceLoc &location,
                                 TFunction *function,
@@ -335,7 +335,9 @@
 
     void checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field);
 
-    TIntermSwitch *addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc);
+    TIntermSwitch *addSwitch(TIntermTyped *init,
+                             TIntermBlock *statementList,
+                             const TSourceLoc &loc);
     TIntermCase *addCase(TIntermTyped *condition, const TSourceLoc &loc);
     TIntermCase *addDefault(const TSourceLoc &loc);
 
@@ -410,7 +412,7 @@
     ShShaderSpec mShaderSpec;  // The language specification compiler conforms to - GLES2 or WebGL.
     ShCompileOptions mCompileOptions;  // Options passed to TCompiler
     int mShaderVersion;
-    TIntermNode *mTreeRoot;      // root of parse tree being created
+    TIntermBlock *mTreeRoot;     // root of parse tree being created
     int mLoopNestingLevel;       // 0 if outside all loops
     int mStructNestingLevel;     // incremented while parsing a struct declaration
     int mSwitchNestingLevel;     // 0 if outside all switch statements
diff --git a/src/compiler/translator/PruneEmptyDeclarations.cpp b/src/compiler/translator/PruneEmptyDeclarations.cpp
index 8cbeb7d..695aa58 100644
--- a/src/compiler/translator/PruneEmptyDeclarations.cpp
+++ b/src/compiler/translator/PruneEmptyDeclarations.cpp
@@ -62,9 +62,10 @@
                     // declaration that will be pruned:
                     // float;
                     TIntermSequence emptyReplacement;
-                    TIntermAggregate *parentAgg = getParentNode()->getAsAggregate();
-                    ASSERT(parentAgg != nullptr);
-                    mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, emptyReplacement));
+                    TIntermBlock *parentAsBlock = getParentNode()->getAsBlock();
+                    ASSERT(parentAsBlock != nullptr);
+                    mMultiReplacements.push_back(
+                        NodeReplaceWithMultipleEntry(parentAsBlock, node, emptyReplacement));
                 }
                 else if (sym->getType().getQualifier() != EvqGlobal &&
                          sym->getType().getQualifier() != EvqTemporary)
diff --git a/src/compiler/translator/RecordConstantPrecision.cpp b/src/compiler/translator/RecordConstantPrecision.cpp
index facf424..6eca229 100644
--- a/src/compiler/translator/RecordConstantPrecision.cpp
+++ b/src/compiler/translator/RecordConstantPrecision.cpp
@@ -45,7 +45,7 @@
 
 bool RecordConstantPrecisionTraverser::operandAffectsParentOperationPrecision(TIntermTyped *operand)
 {
-    if (getParentNode()->getAsCaseNode())
+    if (getParentNode()->getAsCaseNode() || getParentNode()->getAsBlock())
     {
         return false;
     }
diff --git a/src/compiler/translator/RegenerateStructNames.cpp b/src/compiler/translator/RegenerateStructNames.cpp
index 5e0db2a..1a7d8aa 100644
--- a/src/compiler/translator/RegenerateStructNames.cpp
+++ b/src/compiler/translator/RegenerateStructNames.cpp
@@ -58,25 +58,14 @@
     userType->setName(tmp);
 }
 
-bool RegenerateStructNames::visitAggregate(Visit, TIntermAggregate *aggregate)
+bool RegenerateStructNames::visitBlock(Visit, TIntermBlock *block)
 {
-    ASSERT(aggregate);
-    switch (aggregate->getOp())
+    ++mScopeDepth;
+    TIntermSequence &sequence = *(block->getSequence());
+    for (TIntermNode *node : sequence)
     {
-      case EOpSequence:
-        ++mScopeDepth;
-        {
-            TIntermSequence &sequence = *(aggregate->getSequence());
-            for (size_t ii = 0; ii < sequence.size(); ++ii)
-            {
-                TIntermNode *node = sequence[ii];
-                ASSERT(node != NULL);
-                node->traverse(this);
-            }
-        }
-        --mScopeDepth;
-        return false;
-      default:
-        return true;
+        node->traverse(this);
     }
+    --mScopeDepth;
+    return false;
 }
diff --git a/src/compiler/translator/RegenerateStructNames.h b/src/compiler/translator/RegenerateStructNames.h
index 3b98e5d..a910135 100644
--- a/src/compiler/translator/RegenerateStructNames.h
+++ b/src/compiler/translator/RegenerateStructNames.h
@@ -24,7 +24,7 @@
 
   protected:
     void visitSymbol(TIntermSymbol *) override;
-    bool visitAggregate(Visit, TIntermAggregate *) override;
+    bool visitBlock(Visit, TIntermBlock *block) override;
 
   private:
     const TSymbolTable &mSymbolTable;
diff --git a/src/compiler/translator/RemoveDynamicIndexing.cpp b/src/compiler/translator/RemoveDynamicIndexing.cpp
index 4ac3e9f..3da4bcc 100644
--- a/src/compiler/translator/RemoveDynamicIndexing.cpp
+++ b/src/compiler/translator/RemoveDynamicIndexing.cpp
@@ -217,7 +217,7 @@
     }
     indexingFunction->getSequence()->push_back(paramsNode);
 
-    TIntermAggregate *statementList = new TIntermAggregate(EOpSequence);
+    TIntermBlock *statementList = new TIntermBlock();
     for (int i = 0; i < numCases; ++i)
     {
         TIntermCase *caseNode = new TIntermCase(CreateIntConstantNode(i));
@@ -247,7 +247,7 @@
 
     TIntermSwitch *switchNode = new TIntermSwitch(CreateIndexSymbol(), statementList);
 
-    TIntermAggregate *bodyNode = new TIntermAggregate(EOpSequence);
+    TIntermBlock *bodyNode = new TIntermBlock();
     bodyNode->getSequence()->push_back(switchNode);
 
     TIntermBinary *cond =
@@ -256,8 +256,8 @@
 
     // Two blocks: one accesses (either reads or writes) the first element and returns,
     // the other accesses the last element.
-    TIntermAggregate *useFirstBlock = new TIntermAggregate(EOpSequence);
-    TIntermAggregate *useLastBlock = new TIntermAggregate(EOpSequence);
+    TIntermBlock *useFirstBlock = new TIntermBlock();
+    TIntermBlock *useLastBlock  = new TIntermBlock();
     TIntermBinary *indexFirstNode =
         CreateIndexDirectBaseSymbolNode(type, fieldType, 0, baseQualifier);
     TIntermBinary *indexLastNode =
@@ -327,8 +327,8 @@
 
 void RemoveDynamicIndexingTraverser::insertHelperDefinitions(TIntermNode *root)
 {
-    TIntermAggregate *rootAgg = root->getAsAggregate();
-    ASSERT(rootAgg != nullptr && rootAgg->getOp() == EOpSequence);
+    TIntermBlock *rootBlock = root->getAsBlock();
+    ASSERT(rootBlock != nullptr);
     TIntermSequence insertions;
     for (TType type : mIndexedVecAndMatrixTypes)
     {
@@ -338,7 +338,7 @@
     {
         insertions.push_back(GetIndexFunctionDefinition(type, true));
     }
-    mInsertions.push_back(NodeInsertMultipleEntry(rootAgg, 0, insertions, TIntermSequence()));
+    mInsertions.push_back(NodeInsertMultipleEntry(rootBlock, 0, insertions, TIntermSequence()));
 }
 
 // Create a call to dyn_index_*() based on an indirect indexing op node
diff --git a/src/compiler/translator/RemoveSwitchFallThrough.cpp b/src/compiler/translator/RemoveSwitchFallThrough.cpp
index 521cbeb..df8ce1e 100644
--- a/src/compiler/translator/RemoveSwitchFallThrough.cpp
+++ b/src/compiler/translator/RemoveSwitchFallThrough.cpp
@@ -6,7 +6,7 @@
 
 #include "compiler/translator/RemoveSwitchFallThrough.h"
 
-TIntermAggregate *RemoveSwitchFallThrough::removeFallThrough(TIntermAggregate *statementList)
+TIntermBlock *RemoveSwitchFallThrough::removeFallThrough(TIntermBlock *statementList)
 {
     RemoveSwitchFallThrough rm(statementList);
     ASSERT(statementList);
@@ -22,14 +22,13 @@
     return rm.mStatementListOut;
 }
 
-RemoveSwitchFallThrough::RemoveSwitchFallThrough(TIntermAggregate *statementList)
+RemoveSwitchFallThrough::RemoveSwitchFallThrough(TIntermBlock *statementList)
     : TIntermTraverser(true, false, false),
       mStatementList(statementList),
       mLastStatementWasBreak(false),
       mPreviousCase(nullptr)
 {
-    mStatementListOut = new TIntermAggregate();
-    mStatementListOut->setOp(EOpSequence);
+    mStatementListOut = new TIntermBlock();
 }
 
 void RemoveSwitchFallThrough::visitSymbol(TIntermSymbol *node)
@@ -130,8 +129,7 @@
 bool RemoveSwitchFallThrough::visitCase(Visit, TIntermCase *node)
 {
     handlePreviousCase();
-    mPreviousCase = new TIntermAggregate();
-    mPreviousCase->setOp(EOpSequence);
+    mPreviousCase = new TIntermBlock();
     mPreviousCase->getSequence()->push_back(node);
     // Don't traverse the condition of the case statement
     return false;
@@ -139,6 +137,13 @@
 
 bool RemoveSwitchFallThrough::visitAggregate(Visit, TIntermAggregate *node)
 {
+    mPreviousCase->getSequence()->push_back(node);
+    mLastStatementWasBreak = false;
+    return false;
+}
+
+bool RemoveSwitchFallThrough::visitBlock(Visit, TIntermBlock *node)
+{
     if (node != mStatementList)
     {
         mPreviousCase->getSequence()->push_back(node);
diff --git a/src/compiler/translator/RemoveSwitchFallThrough.h b/src/compiler/translator/RemoveSwitchFallThrough.h
index fc73da7..171c51b 100644
--- a/src/compiler/translator/RemoveSwitchFallThrough.h
+++ b/src/compiler/translator/RemoveSwitchFallThrough.h
@@ -14,10 +14,10 @@
   public:
     // When given a statementList from a switch AST node, return an updated
     // statementList that has fall-through removed.
-    static TIntermAggregate *removeFallThrough(TIntermAggregate *statementList);
+    static TIntermBlock *removeFallThrough(TIntermBlock *statementList);
 
   private:
-    RemoveSwitchFallThrough(TIntermAggregate *statementList);
+    RemoveSwitchFallThrough(TIntermBlock *statementList);
 
     void visitSymbol(TIntermSymbol *node) override;
     void visitConstantUnion(TIntermConstantUnion *node) override;
@@ -28,17 +28,18 @@
     bool visitSwitch(Visit, TIntermSwitch *node) override;
     bool visitCase(Visit, TIntermCase *node) override;
     bool visitAggregate(Visit, TIntermAggregate *node) override;
+    bool visitBlock(Visit, TIntermBlock *node) override;
     bool visitLoop(Visit, TIntermLoop *node) override;
     bool visitBranch(Visit, TIntermBranch *node) override;
 
     void outputSequence(TIntermSequence *sequence, size_t startIndex);
     void handlePreviousCase();
 
-    TIntermAggregate *mStatementList;
-    TIntermAggregate *mStatementListOut;
+    TIntermBlock *mStatementList;
+    TIntermBlock *mStatementListOut;
     bool mLastStatementWasBreak;
-    TIntermAggregate *mPreviousCase;
-    std::vector<TIntermAggregate *> mCasesSharingBreak;
+    TIntermBlock *mPreviousCase;
+    std::vector<TIntermBlock *> mCasesSharingBreak;
 };
 
 #endif // COMPILER_TRANSLATOR_REMOVESWITCHFALLTHROUGH_H_
diff --git a/src/compiler/translator/RewriteDoWhile.cpp b/src/compiler/translator/RewriteDoWhile.cpp
index 3a62de2..9cc551b 100644
--- a/src/compiler/translator/RewriteDoWhile.cpp
+++ b/src/compiler/translator/RewriteDoWhile.cpp
@@ -43,15 +43,11 @@
   public:
     DoWhileRewriter() : TIntermTraverser(true, false, false) {}
 
-    bool visitAggregate(Visit, TIntermAggregate *node) override
+    bool visitBlock(Visit, TIntermBlock *node) override
     {
-        // A well-formed AST can only have do-while in EOpSequence which represent lists of
-        // statements. By doing a prefix traversal we are able to replace the do-while in the
-        // sequence directly as the content of the do-while will be traversed later.
-        if (node->getOp() != EOpSequence)
-        {
-            return true;
-        }
+        // A well-formed AST can only have do-while inside TIntermBlock. By doing a prefix traversal
+        // we are able to replace the do-while in the sequence directly as the content of the
+        // do-while will be traversed later.
 
         TIntermSequence *statements = node->getSequence();
 
@@ -99,7 +95,7 @@
             {
                 TIntermBranch *breakStatement = new TIntermBranch(EOpBreak, nullptr);
 
-                TIntermAggregate *breakBlock = new TIntermAggregate(EOpSequence);
+                TIntermBlock *breakBlock = new TIntermBlock();
                 breakBlock->getSequence()->push_back(breakStatement);
 
                 TIntermUnary *negatedCondition =
@@ -107,7 +103,7 @@
 
                 TIntermIfElse *innerIf = new TIntermIfElse(negatedCondition, breakBlock, nullptr);
 
-                TIntermAggregate *innerIfBlock = new TIntermAggregate(EOpSequence);
+                TIntermBlock *innerIfBlock = new TIntermBlock();
                 innerIfBlock->getSequence()->push_back(innerIf);
 
                 breakIf = new TIntermIfElse(createTempSymbol(boolType), innerIfBlock, nullptr);
@@ -121,14 +117,10 @@
                 trueConstant->setBConst(true);
                 TIntermTyped *trueValue = new TIntermConstantUnion(trueConstant, boolType);
 
-                TIntermAggregate *body = nullptr;
-                if (loop->getBody() != nullptr)
+                TIntermBlock *body = loop->getBody();
+                if (body == nullptr)
                 {
-                    body = loop->getBody()->getAsAggregate();
-                }
-                else
-                {
-                    body = new TIntermAggregate(EOpSequence);
+                    body = new TIntermBlock();
                 }
                 auto sequence = body->getSequence();
                 sequence->insert(sequence->begin(), assignTrue);
diff --git a/src/compiler/translator/RewriteElseBlocks.cpp b/src/compiler/translator/RewriteElseBlocks.cpp
index 13d71c7..c9427e2 100644
--- a/src/compiler/translator/RewriteElseBlocks.cpp
+++ b/src/compiler/translator/RewriteElseBlocks.cpp
@@ -26,6 +26,7 @@
 
   protected:
     bool visitAggregate(Visit visit, TIntermAggregate *aggregate) override;
+    bool visitBlock(Visit visit, TIntermBlock *block) override;
 
   private:
     const TType *mFunctionType;
@@ -40,31 +41,29 @@
 
 bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node)
 {
-    switch (node->getOp())
+    if (node->getOp() == EOpFunction)
     {
-      case EOpSequence:
-        if (visit == PostVisit)
+        // Store the current function context (see comment below)
+        mFunctionType = ((visit == PreVisit) ? &node->getType() : nullptr);
+    }
+    return true;
+}
+
+bool ElseBlockRewriter::visitBlock(Visit visit, TIntermBlock *node)
+{
+    if (visit == PostVisit)
+    {
+        for (size_t statementIndex = 0; statementIndex != node->getSequence()->size();
+             statementIndex++)
         {
-            for (size_t statementIndex = 0; statementIndex != node->getSequence()->size(); statementIndex++)
+            TIntermNode *statement = (*node->getSequence())[statementIndex];
+            TIntermIfElse *ifElse  = statement->getAsIfElseNode();
+            if (ifElse && ifElse->getFalseBlock() != nullptr)
             {
-                TIntermNode *statement = (*node->getSequence())[statementIndex];
-                TIntermIfElse *ifElse  = statement->getAsIfElseNode();
-                if (ifElse && ifElse->getFalseBlock() != nullptr)
-                {
-                    (*node->getSequence())[statementIndex] = rewriteIfElse(ifElse);
-                }
+                (*node->getSequence())[statementIndex] = rewriteIfElse(ifElse);
             }
         }
-        break;
-
-      case EOpFunction:
-        // Store the current function context (see comment below)
-        mFunctionType = ((visit == PreVisit) ? &node->getType() : NULL);
-        break;
-
-      default: break;
     }
-
     return true;
 }
 
@@ -77,13 +76,13 @@
     TIntermTyped *typedCondition     = ifElse->getCondition()->getAsTyped();
     TIntermAggregate *storeCondition = createTempInitDeclaration(typedCondition);
 
-    TIntermAggregate *falseBlock = nullptr;
+    TIntermBlock *falseBlock = nullptr;
 
     TType boolType(EbtBool, EbpUndefined, EvqTemporary);
 
     if (ifElse->getFalseBlock())
     {
-        TIntermAggregate *negatedElse = nullptr;
+        TIntermBlock *negatedElse = nullptr;
         // crbug.com/346463
         // D3D generates error messages claiming a function has no return value, when rewriting
         // an if-else clause that returns something non-void in a function. By appending dummy
@@ -94,7 +93,7 @@
                 mFunctionType->getBasicString();
             TString rawText = "return (" + typeString + ")0";
             TIntermRaw *returnNode = new TIntermRaw(*mFunctionType, rawText);
-            negatedElse = new TIntermAggregate(EOpSequence);
+            negatedElse            = new TIntermBlock();
             negatedElse->getSequence()->push_back(returnNode);
         }
 
@@ -102,14 +101,14 @@
         TIntermUnary *negatedCondition     = new TIntermUnary(EOpLogicalNot, conditionSymbolElse);
         TIntermIfElse *falseIfElse =
             new TIntermIfElse(negatedCondition, ifElse->getFalseBlock(), negatedElse);
-        falseBlock = TIntermediate::EnsureSequence(falseIfElse);
+        falseBlock = TIntermediate::EnsureBlock(falseIfElse);
     }
 
     TIntermSymbol *conditionSymbolSel = createTempSymbol(boolType);
     TIntermIfElse *newIfElse =
         new TIntermIfElse(conditionSymbolSel, ifElse->getTrueBlock(), falseBlock);
 
-    TIntermAggregate *block = new TIntermAggregate(EOpSequence);
+    TIntermBlock *block = new TIntermBlock();
     block->getSequence()->push_back(storeCondition);
     block->getSequence()->push_back(newIfElse);
 
diff --git a/src/compiler/translator/RewriteTexelFetchOffset.cpp b/src/compiler/translator/RewriteTexelFetchOffset.cpp
index bcd0bb5..bf89dda 100644
--- a/src/compiler/translator/RewriteTexelFetchOffset.cpp
+++ b/src/compiler/translator/RewriteTexelFetchOffset.cpp
@@ -96,21 +96,20 @@
     int uniqueId = texelFetchSymbol->getUniqueId();
 
     // Create new node that represents the call of function texelFetch.
+    // Its argument list will be: texelFetch(sampler, Position+offset, lod).
     TIntermAggregate *texelFetchNode = new TIntermAggregate(EOpFunctionCall);
     texelFetchNode->setName(newName);
     texelFetchNode->setFunctionId(uniqueId);
     texelFetchNode->setType(node->getType());
     texelFetchNode->setLine(node->getLine());
 
-    // Create argument List of texelFetch(sampler, Position+offset, lod).
-    TIntermSequence newsequence;
-
     // sampler
-    newsequence.push_back(sequence->at(0));
+    texelFetchNode->getSequence()->push_back(sequence->at(0));
 
     // Position
     TIntermTyped *texCoordNode = sequence->at(1)->getAsTyped();
     ASSERT(texCoordNode);
+
     // offset
     TIntermTyped *offsetNode = nullptr;
     ASSERT(sequence->at(3)->getAsTyped());
@@ -122,16 +121,14 @@
         constructIVec3Node->setLine(texCoordNode->getLine());
         constructIVec3Node->setType(texCoordNode->getType());
 
-        TIntermSequence ivec3Sequence;
-        ivec3Sequence.push_back(sequence->at(3)->getAsTyped());
+        constructIVec3Node->getSequence()->push_back(sequence->at(3)->getAsTyped());
 
         TConstantUnion *zero = new TConstantUnion();
         zero->setIConst(0);
         TType *intType = new TType(EbtInt);
 
         TIntermConstantUnion *zeroNode = new TIntermConstantUnion(zero, *intType);
-        ivec3Sequence.push_back(zeroNode);
-        constructIVec3Node->insertChildNodes(0, ivec3Sequence);
+        constructIVec3Node->getSequence()->push_back(zeroNode);
 
         offsetNode = constructIVec3Node;
     }
@@ -143,11 +140,12 @@
     // Position+offset
     TIntermBinary *add = new TIntermBinary(EOpAdd, texCoordNode, offsetNode);
     add->setLine(texCoordNode->getLine());
-    newsequence.push_back(add);
+    texelFetchNode->getSequence()->push_back(add);
 
     // lod
-    newsequence.push_back(sequence->at(2));
-    texelFetchNode->insertChildNodes(0, newsequence);
+    texelFetchNode->getSequence()->push_back(sequence->at(2));
+
+    ASSERT(texelFetchNode->getSequence()->size() == 3u);
 
     // Replace the old node by this new node.
     queueReplacement(node, texelFetchNode, OriginalNode::IS_DROPPED);
diff --git a/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp b/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp
index cb69059..96789bd 100644
--- a/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp
+++ b/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp
@@ -60,25 +60,6 @@
     {
         switch (node->getOp())
         {
-          case EOpSequence:
-            mSequenceStack.push_back(TIntermSequence());
-            {
-                for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
-                     iter != node->getSequence()->end(); ++iter)
-                {
-                    TIntermNode *child = *iter;
-                    ASSERT(child != NULL);
-                    child->traverse(this);
-                    mSequenceStack.back().push_back(child);
-                }
-            }
-            if (mSequenceStack.back().size() > node->getSequence()->size())
-            {
-                node->getSequence()->clear();
-                *(node->getSequence()) = mSequenceStack.back();
-            }
-            mSequenceStack.pop_back();
-            return false;
           case EOpConstructVec2:
           case EOpConstructVec3:
           case EOpConstructVec4:
@@ -110,6 +91,26 @@
     return true;
 }
 
+bool ScalarizeVecAndMatConstructorArgs::visitBlock(Visit visit, TIntermBlock *node)
+{
+    mBlockStack.push_back(TIntermSequence());
+    {
+        for (TIntermNode *child : *node->getSequence())
+        {
+            ASSERT(child != nullptr);
+            child->traverse(this);
+            mBlockStack.back().push_back(child);
+        }
+    }
+    if (mBlockStack.back().size() > node->getSequence()->size())
+    {
+        node->getSequence()->clear();
+        *(node->getSequence()) = mBlockStack.back();
+    }
+    mBlockStack.pop_back();
+    return false;
+}
+
 void ScalarizeVecAndMatConstructorArgs::scalarizeArgs(
     TIntermAggregate *aggregate, bool scalarizeVector, bool scalarizeMatrix)
 {
@@ -267,8 +268,8 @@
     TIntermAggregate *decl = new TIntermAggregate(EOpDeclaration);
     decl->getSequence()->push_back(init);
 
-    ASSERT(mSequenceStack.size() > 0);
-    TIntermSequence &sequence = mSequenceStack.back();
+    ASSERT(mBlockStack.size() > 0);
+    TIntermSequence &sequence = mBlockStack.back();
     sequence.push_back(decl);
 
     return tempVarName;
diff --git a/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h b/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h
index d7553be..eac6125 100644
--- a/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h
+++ b/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h
@@ -21,6 +21,7 @@
 
   protected:
     bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+    bool visitBlock(Visit visit, TIntermBlock *node) override;
 
   private:
     void scalarizeArgs(TIntermAggregate *aggregate,
@@ -38,7 +39,7 @@
     // Return the temporary variable name.
     TString createTempVariable(TIntermTyped *original);
 
-    std::vector<TIntermSequence> mSequenceStack;
+    std::vector<TIntermSequence> mBlockStack;
     int mTempVarCount;
 
     sh::GLenum mShaderType;
diff --git a/src/compiler/translator/SeparateArrayInitialization.cpp b/src/compiler/translator/SeparateArrayInitialization.cpp
index e166eac..8cd1fa1 100644
--- a/src/compiler/translator/SeparateArrayInitialization.cpp
+++ b/src/compiler/translator/SeparateArrayInitialization.cpp
@@ -58,8 +58,8 @@
                 // We rely on that array declarations have been isolated to single declarations.
                 ASSERT(sequence->size() == 1);
                 TIntermTyped *symbol = initNode->getLeft();
-                TIntermAggregate *parentAgg = getParentNode()->getAsAggregate();
-                ASSERT(parentAgg != nullptr);
+                TIntermBlock *parentBlock = getParentNode()->getAsBlock();
+                ASSERT(parentBlock != nullptr);
 
                 TIntermSequence replacements;
 
@@ -74,7 +74,8 @@
                 replacementAssignment->setLine(symbol->getLine());
                 replacements.push_back(replacementAssignment);
 
-                mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, replacements));
+                mMultiReplacements.push_back(
+                    NodeReplaceWithMultipleEntry(parentBlock, node, replacements));
             }
         }
         return false;
diff --git a/src/compiler/translator/SeparateDeclarations.cpp b/src/compiler/translator/SeparateDeclarations.cpp
index d33747f..cc339ea 100644
--- a/src/compiler/translator/SeparateDeclarations.cpp
+++ b/src/compiler/translator/SeparateDeclarations.cpp
@@ -48,8 +48,8 @@
         TIntermSequence *sequence = node->getSequence();
         if (sequence->size() > 1)
         {
-            TIntermAggregate *parentAgg = getParentNode()->getAsAggregate();
-            ASSERT(parentAgg != nullptr);
+            TIntermBlock *parentBlock = getParentNode()->getAsBlock();
+            ASSERT(parentBlock != nullptr);
 
             TIntermSequence replacementDeclarations;
             for (size_t ii = 0; ii < sequence->size(); ++ii)
@@ -62,7 +62,8 @@
                 replacementDeclarations.push_back(replacementDeclaration);
             }
 
-            mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, replacementDeclarations));
+            mMultiReplacements.push_back(
+                NodeReplaceWithMultipleEntry(parentBlock, node, replacementDeclarations));
         }
         return false;
     }
diff --git a/src/compiler/translator/SimplifyLoopConditions.cpp b/src/compiler/translator/SimplifyLoopConditions.cpp
index da8da48..071b8b8 100644
--- a/src/compiler/translator/SimplifyLoopConditions.cpp
+++ b/src/compiler/translator/SimplifyLoopConditions.cpp
@@ -94,7 +94,7 @@
 
     // If we're outside a loop condition, we only need to traverse nodes that may contain loops.
     if (!mInsideLoopConditionOrExpression)
-        return (node->getOp() == EOpSequence || node->getOp() == EOpFunction);
+        return (node->getOp() == EOpFunction);
 
     mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode());
     return !mFoundLoopToChange;
@@ -145,10 +145,9 @@
                 tempInitSeq.push_back(createTempInitDeclaration(node->getCondition()->deepCopy()));
                 insertStatementsInParentBlock(tempInitSeq);
 
-                TIntermAggregate *newBody = new TIntermAggregate(EOpSequence);
+                TIntermBlock *newBody = new TIntermBlock();
                 if (node->getBody())
                 {
-                    ASSERT(node->getBody()->getOp() == EOpSequence);
                     newBody->getSequence()->push_back(node->getBody());
                 }
                 newBody->getSequence()->push_back(
@@ -176,10 +175,9 @@
                 tempInitSeq.push_back(createTempInitDeclaration(CreateBoolConstantNode(true)));
                 insertStatementsInParentBlock(tempInitSeq);
 
-                TIntermAggregate *newBody = new TIntermAggregate(EOpSequence);
+                TIntermBlock *newBody = new TIntermBlock();
                 if (node->getBody())
                 {
-                    ASSERT(node->getBody()->getOp() == EOpSequence);
                     newBody->getSequence()->push_back(node->getBody());
                 }
                 newBody->getSequence()->push_back(
@@ -202,7 +200,7 @@
                 //     bool s0 = expr;
                 //     while (s0) { { body; } exprB; s0 = expr; }
                 //   }
-                TIntermAggregate *loopScope = new TIntermAggregate(EOpSequence);
+                TIntermBlock *loopScope = new TIntermBlock();
                 if (node->getInit())
                 {
                     loopScope->getSequence()->push_back(node->getInit());
@@ -210,7 +208,7 @@
                 loopScope->getSequence()->push_back(
                     createTempInitDeclaration(node->getCondition()->deepCopy()));
 
-                TIntermAggregate *whileLoopBody = new TIntermAggregate(EOpSequence);
+                TIntermBlock *whileLoopBody = new TIntermBlock();
                 if (node->getBody())
                 {
                     whileLoopBody->getSequence()->push_back(node->getBody());
@@ -242,8 +240,8 @@
             //   for (init; expr; ) { { body; } exprB; }
             TIntermTyped *loopExpression = node->getExpression();
             node->setExpression(nullptr);
-            TIntermAggregate *oldBody = node->getBody();
-            node->setBody(new TIntermAggregate(EOpSequence));
+            TIntermBlock *oldBody = node->getBody();
+            node->setBody(new TIntermBlock());
             if (oldBody != nullptr)
             {
                 node->getBody()->getSequence()->push_back(oldBody);
diff --git a/src/compiler/translator/UnfoldShortCircuitToIf.cpp b/src/compiler/translator/UnfoldShortCircuitToIf.cpp
index f6e9a2e..712f59a 100644
--- a/src/compiler/translator/UnfoldShortCircuitToIf.cpp
+++ b/src/compiler/translator/UnfoldShortCircuitToIf.cpp
@@ -75,7 +75,7 @@
           ASSERT(node->getLeft()->getType() == boolType);
           insertions.push_back(createTempInitDeclaration(node->getLeft()));
 
-          TIntermAggregate *assignRightBlock = new TIntermAggregate(EOpSequence);
+          TIntermBlock *assignRightBlock = new TIntermBlock();
           ASSERT(node->getRight()->getType() == boolType);
           assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight()));
 
@@ -99,7 +99,7 @@
           ASSERT(node->getLeft()->getType() == boolType);
           insertions.push_back(createTempInitDeclaration(node->getLeft()));
 
-          TIntermAggregate *assignRightBlock = new TIntermAggregate(EOpSequence);
+          TIntermBlock *assignRightBlock = new TIntermBlock();
           ASSERT(node->getRight()->getType() == boolType);
           assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight()));
 
@@ -139,11 +139,11 @@
     tempDeclaration->getSequence()->push_back(tempSymbol);
     insertions.push_back(tempDeclaration);
 
-    TIntermAggregate *trueBlock   = new TIntermAggregate(EOpSequence);
+    TIntermBlock *trueBlock       = new TIntermBlock();
     TIntermBinary *trueAssignment = createTempAssignment(node->getTrueExpression());
     trueBlock->getSequence()->push_back(trueAssignment);
 
-    TIntermAggregate *falseBlock   = new TIntermAggregate(EOpSequence);
+    TIntermBlock *falseBlock       = new TIntermBlock();
     TIntermBinary *falseAssignment = createTempAssignment(node->getFalseExpression());
     falseBlock->getSequence()->push_back(falseAssignment);
 
diff --git a/src/compiler/translator/ValidateSwitch.cpp b/src/compiler/translator/ValidateSwitch.cpp
index 1ebdffd..8fbd832 100644
--- a/src/compiler/translator/ValidateSwitch.cpp
+++ b/src/compiler/translator/ValidateSwitch.cpp
@@ -8,8 +8,10 @@
 
 #include "compiler/translator/ParseContext.h"
 
-bool ValidateSwitch::validate(TBasicType switchType, TParseContext *context,
-    TIntermAggregate *statementList, const TSourceLoc &loc)
+bool ValidateSwitch::validate(TBasicType switchType,
+                              TParseContext *context,
+                              TIntermBlock *statementList,
+                              const TSourceLoc &loc)
 {
     ValidateSwitch validate(switchType, context);
     ASSERT(statementList);
diff --git a/src/compiler/translator/ValidateSwitch.h b/src/compiler/translator/ValidateSwitch.h
index fb6a614..9c6dee2 100644
--- a/src/compiler/translator/ValidateSwitch.h
+++ b/src/compiler/translator/ValidateSwitch.h
@@ -16,8 +16,10 @@
   public:
     // Check for errors and output messages any remaining errors on the context.
     // Returns true if there are no errors.
-    static bool validate(TBasicType switchType, TParseContext *context,
-        TIntermAggregate *statementList, const TSourceLoc &loc);
+    static bool validate(TBasicType switchType,
+                         TParseContext *context,
+                         TIntermBlock *statementList,
+                         const TSourceLoc &loc);
 
     void visitSymbol(TIntermSymbol *) override;
     void visitConstantUnion(TIntermConstantUnion *) override;
diff --git a/src/compiler/translator/VersionGLSL.cpp b/src/compiler/translator/VersionGLSL.cpp
index c8718da..5c0c519 100644
--- a/src/compiler/translator/VersionGLSL.cpp
+++ b/src/compiler/translator/VersionGLSL.cpp
@@ -68,10 +68,6 @@
 
     switch (node->getOp())
     {
-      case EOpSequence:
-        // We need to visit sequence children to get to global or inner scope.
-        visitChildren = true;
-        break;
       case EOpDeclaration:
         {
             const TIntermSequence &sequence = *(node->getSequence());
diff --git a/src/compiler/translator/glslang.y b/src/compiler/translator/glslang.y
index ef2dcaa..b11c7d5 100644
--- a/src/compiler/translator/glslang.y
+++ b/src/compiler/translator/glslang.y
@@ -76,6 +76,7 @@
             TIntermNodePair nodePair;
             TIntermTyped* intermTypedNode;
             TIntermAggregate* intermAggregate;
+            TIntermBlock* intermBlock;
             TIntermSwitch* intermSwitch;
             TIntermCase* intermCase;
         };
@@ -195,9 +196,9 @@
 %type <interm.intermTypedNode> shift_expression and_expression exclusive_or_expression inclusive_or_expression
 %type <interm.intermTypedNode> function_call initializer condition conditionopt
 
-%type <interm.intermNode> translation_unit function_definition
-%type <interm.intermNode> statement simple_statement
-%type <interm.intermAggregate>  statement_list compound_statement compound_statement_no_new_scope
+%type <interm.intermBlock> translation_unit
+%type <interm.intermNode> function_definition statement simple_statement
+%type <interm.intermBlock> statement_list compound_statement compound_statement_no_new_scope
 %type <interm.intermNode> declaration_statement selection_statement expression_statement
 %type <interm.intermNode> declaration external_declaration
 %type <interm.intermNode> for_init_statement
@@ -1286,7 +1287,6 @@
     : LEFT_BRACE RIGHT_BRACE { $$ = 0; }
     | LEFT_BRACE { context->symbolTable.push(); } statement_list { context->symbolTable.pop(); } RIGHT_BRACE {
         if ($3 != 0) {
-            $3->setOp(EOpSequence);
             $3->setLine(@$);
         }
         $$ = $3;
@@ -1310,7 +1310,6 @@
     }
     | LEFT_BRACE statement_list RIGHT_BRACE {
         if ($2) {
-            $2->setOp(EOpSequence);
             $2->setLine(@$);
         }
         $$ = $2;
@@ -1319,10 +1318,13 @@
 
 statement_list
     : statement {
-        $$ = TIntermediate::MakeAggregate($1, @$);
+        $$ = new TIntermBlock();
+        $$->setLine(@$);
+        $$->appendStatement($1);
     }
     | statement_list statement {
-        $$ = context->intermediate.growAggregate($1, $2, @$);
+        $$ = $1;
+        $$->appendStatement($2);
     }
     ;
 
@@ -1454,12 +1456,13 @@
 
 translation_unit
     : external_declaration {
-        $$ = $1;
+        $$ = new TIntermBlock();
+        $$->setLine(@$);
+        $$->appendStatement($1);
         context->setTreeRoot($$);
     }
     | translation_unit external_declaration {
-        $$ = context->intermediate.growAggregate($1, $2, @$);
-        context->setTreeRoot($$);
+        $$->appendStatement($2);
     }
     ;
 
diff --git a/src/compiler/translator/glslang_tab.cpp b/src/compiler/translator/glslang_tab.cpp
index 2d3f170..c0512e2 100644
--- a/src/compiler/translator/glslang_tab.cpp
+++ b/src/compiler/translator/glslang_tab.cpp
@@ -291,6 +291,7 @@
             TIntermNodePair nodePair;
             TIntermTyped* intermTypedNode;
             TIntermAggregate* intermAggregate;
+            TIntermBlock* intermBlock;
             TIntermSwitch* intermSwitch;
             TIntermCase* intermCase;
         };
@@ -713,33 +714,33 @@
   /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   236,   236,   237,   240,   250,   253,   258,   263,   268,
-     273,   279,   282,   285,   288,   291,   294,   300,   307,   318,
-     322,   330,   333,   339,   343,   350,   356,   365,   373,   379,
-     385,   394,   397,   400,   403,   413,   414,   415,   416,   424,
-     425,   428,   431,   438,   439,   442,   448,   449,   453,   460,
-     461,   464,   467,   470,   476,   477,   480,   486,   487,   494,
-     495,   502,   503,   510,   511,   517,   518,   524,   525,   531,
-     532,   538,   539,   546,   547,   548,   549,   553,   554,   555,
-     559,   563,   567,   571,   578,   581,   587,   594,   601,   604,
-     610,   619,   623,   627,   631,   635,   642,   649,   652,   659,
-     667,   687,   697,   705,   730,   734,   738,   742,   749,   756,
-     759,   763,   767,   772,   777,   784,   788,   792,   796,   801,
-     806,   813,   823,   829,   832,   838,   842,   849,   855,   862,
-     866,   869,   872,   881,   887,   895,   898,   918,   937,   944,
-     948,   955,   965,   968,   971,   977,   984,   987,   993,   996,
-     999,  1005,  1008,  1013,  1024,  1027,  1030,  1033,  1036,  1039,
-    1043,  1047,  1051,  1055,  1059,  1063,  1067,  1071,  1075,  1079,
-    1083,  1087,  1091,  1095,  1099,  1103,  1107,  1111,  1115,  1119,
-    1123,  1126,  1129,  1132,  1135,  1138,  1141,  1144,  1147,  1150,
-    1153,  1156,  1159,  1162,  1165,  1168,  1175,  1181,  1184,  1196,
-    1196,  1199,  1199,  1205,  1208,  1223,  1226,  1233,  1237,  1243,
-    1249,  1261,  1265,  1269,  1270,  1276,  1277,  1278,  1279,  1280,
-    1281,  1282,  1286,  1287,  1287,  1287,  1297,  1298,  1302,  1302,
-    1303,  1303,  1308,  1311,  1321,  1324,  1330,  1331,  1335,  1342,
-    1346,  1353,  1353,  1360,  1363,  1370,  1374,  1387,  1387,  1392,
-    1392,  1398,  1398,  1406,  1409,  1415,  1418,  1424,  1428,  1435,
-    1438,  1441,  1444,  1447,  1456,  1460,  1467,  1470,  1476,  1476
+       0,   237,   237,   238,   241,   251,   254,   259,   264,   269,
+     274,   280,   283,   286,   289,   292,   295,   301,   308,   319,
+     323,   331,   334,   340,   344,   351,   357,   366,   374,   380,
+     386,   395,   398,   401,   404,   414,   415,   416,   417,   425,
+     426,   429,   432,   439,   440,   443,   449,   450,   454,   461,
+     462,   465,   468,   471,   477,   478,   481,   487,   488,   495,
+     496,   503,   504,   511,   512,   518,   519,   525,   526,   532,
+     533,   539,   540,   547,   548,   549,   550,   554,   555,   556,
+     560,   564,   568,   572,   579,   582,   588,   595,   602,   605,
+     611,   620,   624,   628,   632,   636,   643,   650,   653,   660,
+     668,   688,   698,   706,   731,   735,   739,   743,   750,   757,
+     760,   764,   768,   773,   778,   785,   789,   793,   797,   802,
+     807,   814,   824,   830,   833,   839,   843,   850,   856,   863,
+     867,   870,   873,   882,   888,   896,   899,   919,   938,   945,
+     949,   956,   966,   969,   972,   978,   985,   988,   994,   997,
+    1000,  1006,  1009,  1014,  1025,  1028,  1031,  1034,  1037,  1040,
+    1044,  1048,  1052,  1056,  1060,  1064,  1068,  1072,  1076,  1080,
+    1084,  1088,  1092,  1096,  1100,  1104,  1108,  1112,  1116,  1120,
+    1124,  1127,  1130,  1133,  1136,  1139,  1142,  1145,  1148,  1151,
+    1154,  1157,  1160,  1163,  1166,  1169,  1176,  1182,  1185,  1197,
+    1197,  1200,  1200,  1206,  1209,  1224,  1227,  1234,  1238,  1244,
+    1250,  1262,  1266,  1270,  1271,  1277,  1278,  1279,  1280,  1281,
+    1282,  1283,  1287,  1288,  1288,  1288,  1297,  1298,  1302,  1302,
+    1303,  1303,  1308,  1311,  1320,  1325,  1332,  1333,  1337,  1344,
+    1348,  1355,  1355,  1362,  1365,  1372,  1376,  1389,  1389,  1394,
+    1394,  1400,  1400,  1408,  1411,  1417,  1420,  1426,  1430,  1437,
+    1440,  1443,  1446,  1449,  1458,  1464,  1470,  1473,  1479,  1479
 };
 #endif
 
@@ -4230,7 +4231,7 @@
 
   case 213:
 
-    { (yyval.interm.intermNode) = (yyvsp[0].interm.intermAggregate); }
+    { (yyval.interm.intermNode) = (yyvsp[0].interm.intermBlock); }
 
     break;
 
@@ -4284,7 +4285,7 @@
 
   case 222:
 
-    { (yyval.interm.intermAggregate) = 0; }
+    { (yyval.interm.intermBlock) = 0; }
 
     break;
 
@@ -4303,18 +4304,17 @@
   case 225:
 
     {
-        if ((yyvsp[-2].interm.intermAggregate) != 0) {
-            (yyvsp[-2].interm.intermAggregate)->setOp(EOpSequence);
-            (yyvsp[-2].interm.intermAggregate)->setLine((yyloc));
+        if ((yyvsp[-2].interm.intermBlock) != 0) {
+            (yyvsp[-2].interm.intermBlock)->setLine((yyloc));
         }
-        (yyval.interm.intermAggregate) = (yyvsp[-2].interm.intermAggregate);
+        (yyval.interm.intermBlock) = (yyvsp[-2].interm.intermBlock);
     }
 
     break;
 
   case 226:
 
-    { (yyval.interm.intermNode) = (yyvsp[0].interm.intermAggregate); }
+    { (yyval.interm.intermNode) = (yyvsp[0].interm.intermBlock); }
 
     break;
 
@@ -4332,7 +4332,7 @@
 
   case 229:
 
-    { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[0].interm.intermAggregate); }
+    { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[0].interm.intermBlock); }
 
     break;
 
@@ -4351,7 +4351,7 @@
   case 232:
 
     {
-        (yyval.interm.intermAggregate) = 0;
+        (yyval.interm.intermBlock) = 0;
     }
 
     break;
@@ -4359,11 +4359,10 @@
   case 233:
 
     {
-        if ((yyvsp[-1].interm.intermAggregate)) {
-            (yyvsp[-1].interm.intermAggregate)->setOp(EOpSequence);
-            (yyvsp[-1].interm.intermAggregate)->setLine((yyloc));
+        if ((yyvsp[-1].interm.intermBlock)) {
+            (yyvsp[-1].interm.intermBlock)->setLine((yyloc));
         }
-        (yyval.interm.intermAggregate) = (yyvsp[-1].interm.intermAggregate);
+        (yyval.interm.intermBlock) = (yyvsp[-1].interm.intermBlock);
     }
 
     break;
@@ -4371,7 +4370,9 @@
   case 234:
 
     {
-        (yyval.interm.intermAggregate) = TIntermediate::MakeAggregate((yyvsp[0].interm.intermNode), (yyloc));
+        (yyval.interm.intermBlock) = new TIntermBlock();
+        (yyval.interm.intermBlock)->setLine((yyloc));
+        (yyval.interm.intermBlock)->appendStatement((yyvsp[0].interm.intermNode));
     }
 
     break;
@@ -4379,7 +4380,8 @@
   case 235:
 
     {
-        (yyval.interm.intermAggregate) = context->intermediate.growAggregate((yyvsp[-1].interm.intermAggregate), (yyvsp[0].interm.intermNode), (yyloc));
+        (yyval.interm.intermBlock) = (yyvsp[-1].interm.intermBlock);
+        (yyval.interm.intermBlock)->appendStatement((yyvsp[0].interm.intermNode));
     }
 
     break;
@@ -4432,7 +4434,7 @@
   case 242:
 
     {
-        (yyval.interm.intermSwitch) = context->addSwitch((yyvsp[-3].interm.intermTypedNode), (yyvsp[0].interm.intermAggregate), (yylsp[-5]));
+        (yyval.interm.intermSwitch) = context->addSwitch((yyvsp[-3].interm.intermTypedNode), (yyvsp[0].interm.intermBlock), (yylsp[-5]));
         context->decrSwitchNestingLevel();
     }
 
@@ -4621,8 +4623,10 @@
   case 264:
 
     {
-        (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode);
-        context->setTreeRoot((yyval.interm.intermNode));
+        (yyval.interm.intermBlock) = new TIntermBlock();
+        (yyval.interm.intermBlock)->setLine((yyloc));
+        (yyval.interm.intermBlock)->appendStatement((yyvsp[0].interm.intermNode));
+        context->setTreeRoot((yyval.interm.intermBlock));
     }
 
     break;
@@ -4630,8 +4634,7 @@
   case 265:
 
     {
-        (yyval.interm.intermNode) = context->intermediate.growAggregate((yyvsp[-1].interm.intermNode), (yyvsp[0].interm.intermNode), (yyloc));
-        context->setTreeRoot((yyval.interm.intermNode));
+        (yyval.interm.intermBlock)->appendStatement((yyvsp[0].interm.intermNode));
     }
 
     break;
@@ -4663,7 +4666,7 @@
   case 269:
 
     {
-        (yyval.interm.intermNode) = context->addFunctionDefinition(*((yyvsp[-2].interm).function), (yyvsp[-2].interm).intermAggregate, (yyvsp[0].interm.intermAggregate), (yylsp[-2]));
+        (yyval.interm.intermNode) = context->addFunctionDefinition(*((yyvsp[-2].interm).function), (yyvsp[-2].interm).intermAggregate, (yyvsp[0].interm.intermBlock), (yylsp[-2]));
     }
 
     break;
diff --git a/src/compiler/translator/intermOut.cpp b/src/compiler/translator/intermOut.cpp
index aed53d4..e3f9a55 100644
--- a/src/compiler/translator/intermOut.cpp
+++ b/src/compiler/translator/intermOut.cpp
@@ -48,6 +48,7 @@
     bool visitTernary(Visit visit, TIntermTernary *node) override;
     bool visitIfElse(Visit visit, TIntermIfElse *node) override;
     bool visitAggregate(Visit visit, TIntermAggregate *) override;
+    bool visitBlock(Visit visit, TIntermBlock *) override;
     bool visitLoop(Visit visit, TIntermLoop *) override;
     bool visitBranch(Visit visit, TIntermBranch *) override;
     // TODO: Add missing visit functions
@@ -374,18 +375,18 @@
 {
     TInfoSinkBase &out = sink;
 
+    OutputTreeText(out, node, mDepth);
+
     if (node->getOp() == EOpNull)
     {
         out.prefix(EPrefixError);
-        out << "node is still EOpNull!";
+        out << "node is still EOpNull!\n";
         return true;
     }
 
-    OutputTreeText(out, node, mDepth);
 
     switch (node->getOp())
     {
-      case EOpSequence:      out << "Sequence\n"; return true;
       case EOpComma:         out << "Comma\n"; return true;
       case EOpFunction:      OutputFunction(out, "Function Definition", node); break;
       case EOpFunctionCall:  OutputFunction(out, "Function Call", node); break;
@@ -457,7 +458,7 @@
         out << "Bad aggregation op";
     }
 
-    if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
+    if (node->getOp() != EOpParameters)
         out << " (" << node->getCompleteString() << ")";
 
     out << "\n";
@@ -465,6 +466,16 @@
     return true;
 }
 
+bool TOutputTraverser::visitBlock(Visit visit, TIntermBlock *node)
+{
+    TInfoSinkBase &out = sink;
+
+    OutputTreeText(out, node, mDepth);
+    out << "Code block\n";
+
+    return true;
+}
+
 bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node)
 {
     TInfoSinkBase &out = sink;