Produce constructors instead of conversions.

GLSL only supports explicit conversion through constructors. Therefore the conversion
nodes are redundant.

BUG=15415045

Change-Id: Ia6bd93c9c4a69d013a4ec82f81826e6ff5c18eb2
Reviewed-on: https://swiftshader-review.googlesource.com/1113
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/GLES2/compiler/ParseHelper.cpp b/src/GLES2/compiler/ParseHelper.cpp
index 21a3fe7..cf46305 100644
--- a/src/GLES2/compiler/ParseHelper.cpp
+++ b/src/GLES2/compiler/ParseHelper.cpp
@@ -38,11 +38,11 @@
 
     for (int i = 0; i < fields.num; ++i) {
         switch (compString[i])  {
-        case 'x': 
+        case 'x':
             fields.offsets[i] = 0;
             fieldSet[i] = exyzw;
             break;
-        case 'r': 
+        case 'r':
             fields.offsets[i] = 0;
             fieldSet[i] = ergba;
             break;
@@ -50,11 +50,11 @@
             fields.offsets[i] = 0;
             fieldSet[i] = estpq;
             break;
-        case 'y': 
+        case 'y':
             fields.offsets[i] = 1;
             fieldSet[i] = exyzw;
             break;
-        case 'g': 
+        case 'g':
             fields.offsets[i] = 1;
             fieldSet[i] = ergba;
             break;
@@ -62,11 +62,11 @@
             fields.offsets[i] = 1;
             fieldSet[i] = estpq;
             break;
-        case 'z': 
+        case 'z':
             fields.offsets[i] = 2;
             fieldSet[i] = exyzw;
             break;
-        case 'b': 
+        case 'b':
             fields.offsets[i] = 2;
             fieldSet[i] = ergba;
             break;
@@ -74,12 +74,11 @@
             fields.offsets[i] = 2;
             fieldSet[i] = estpq;
             break;
-        
-        case 'w': 
+        case 'w':
             fields.offsets[i] = 3;
             fieldSet[i] = exyzw;
             break;
-        case 'a': 
+        case 'a':
             fields.offsets[i] = 3;
             fieldSet[i] = ergba;
             break;
@@ -176,7 +175,7 @@
 // Used by flex/bison to output all syntax and parsing errors.
 //
 void TParseContext::error(TSourceLoc loc,
-                          const char* reason, const char* token, 
+                          const char* reason, const char* token,
                           const char* extraInfo)
 {
     pp::SourceLocation srcLoc;
@@ -217,7 +216,7 @@
 void TParseContext::unaryOpError(int line, const char* op, TString operand)
 {
     std::stringstream extraInfoStream;
-    extraInfoStream << "no operation '" << op << "' exists that takes an operand of type " << operand 
+    extraInfoStream << "no operation '" << op << "' exists that takes an operand of type " << operand
                     << " (or there is no acceptable conversion)";
     std::string extraInfo = extraInfoStream.str();
     error(line, " wrong operand type", op, extraInfo.c_str());
@@ -232,7 +231,7 @@
     extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left 
                     << "' and a right operand of type '" << right << "' (or there is no acceptable conversion)";
     std::string extraInfo = extraInfoStream.str();
-    error(line, " wrong operand types ", op, extraInfo.c_str()); 
+    error(line, " wrong operand types ", op, extraInfo.c_str());
 }
 
 bool TParseContext::precisionErrorCheck(int line, TPrecision precision, TBasicType type){
@@ -283,21 +282,21 @@
 
                 TIntermTyped* rightNode = binaryNode->getRight();
                 TIntermAggregate *aggrNode = rightNode->getAsAggregate();
-                
-                for (TIntermSequence::iterator p = aggrNode->getSequence().begin(); 
+
+                for (TIntermSequence::iterator p = aggrNode->getSequence().begin();
                                                p != aggrNode->getSequence().end(); p++) {
                     int value = (*p)->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->getIConst();
-                    offset[value]++;     
+                    offset[value]++;
                     if (offset[value] > 1) {
                         error(line, " l-value of swizzle cannot have duplicate components", op);
 
                         return true;
                     }
                 }
-            } 
+            }
 
             return errorReturn;
-        default: 
+        default:
             break;
         }
         error(line, " l-value required", op);
@@ -470,7 +469,7 @@
     case EOpConstructMat4:
         constructingMatrix = true;
         break;
-    default: 
+    default:
         break;
     }
 
@@ -489,7 +488,7 @@
     for (int i = 0; i < function.getParamCount(); ++i) {
         const TParameter& param = function.getParam(i);
         size += param.type->getObjectSize();
-        
+
         if (constructingMatrix && param.type->isMatrix())
             matrixInMatrix = true;
         if (full)
@@ -501,7 +500,7 @@
         if (param.type->isArray())
             arrayArg = true;
     }
-    
+
     if (constType)
         type->setQualifier(EvqConst);
 
@@ -526,7 +525,7 @@
         error(line, "too many arguments", "constructor");
         return true;
     }
-    
+
     if (op == EOpConstructStruct && !type->isArray() && int(type->getStruct()->size()) != function.getParamCount()) {
         error(line, "Number of constructor parameters does not match the number of structure fields", "constructor");
         return true;
@@ -566,7 +565,7 @@
     if (pubType.type == EbtVoid) {
         error(line, "illegal use of type 'void'", identifier.c_str());
         return true;
-    } 
+    }
 
     return false;
 }
@@ -580,7 +579,7 @@
     if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) {
         error(line, "boolean expression expected", "");
         return true;
-    } 
+    }
 
     return false;
 }
@@ -594,7 +593,7 @@
     if (pType.type != EbtBool || pType.array || pType.matrix || (pType.size > 1)) {
         error(line, "boolean expression expected", "");
         return true;
-    } 
+    }
 
     return false;
 }
@@ -604,10 +603,10 @@
     if (pType.type == EbtStruct) {
         if (containsSampler(*pType.userDef)) {
             error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
-        
+
             return true;
         }
-        
+
         return false;
     } else if (IsSampler(pType.type)) {
         error(line, reason, getBasicString(pType.type));
@@ -623,7 +622,7 @@
     if ((pType.qualifier == EvqVaryingIn || pType.qualifier == EvqVaryingOut || pType.qualifier == EvqAttribute) &&
         pType.type == EbtStruct) {
         error(line, "cannot be used with a structure", getQualifierString(pType.qualifier));
-        
+
         return true;
     }
 
@@ -635,7 +634,7 @@
 
 bool TParseContext::parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type)
 {
-    if ((qualifier == EvqOut || qualifier == EvqInOut) && 
+    if ((qualifier == EvqOut || qualifier == EvqInOut) &&
              type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) {
         error(line, "samplers cannot be output parameters", type.getBasicString());
         return true;
@@ -718,7 +717,7 @@
 }
 
 //
-// Do all the semantic checking for declaring an array, with and 
+// Do all the semantic checking for declaring an array, with and
 // without a size, and make the right changes to the symbol table.
 //
 // size == 0 means no specified size.
@@ -732,13 +731,13 @@
     // because reserved arrays can be redeclared.
     //
 
-    bool builtIn = false; 
+    bool builtIn = false;
     bool sameScope = false;
     TSymbol* symbol = symbolTable.find(identifier, &builtIn, &sameScope);
     if (symbol == 0 || !sameScope) {
         if (reservedErrorCheck(line, identifier))
             return true;
-        
+
         variable = new TVariable(&identifier, TType(type));
 
         if (type.arraySize)
@@ -764,7 +763,7 @@
             error(line, "redeclaration of array with size", identifier.c_str());
             return true;
         }
-        
+
         if (! variable->getType().sameElementType(TType(type))) {
             error(line, "redeclaration of array with a different type", identifier.c_str());
             return true;
@@ -782,7 +781,7 @@
 
         if (type.arraySize)
             variable->getType().setArraySize(type.arraySize);
-    } 
+    }
 
     if (voidErrorCheck(line, identifier, type))
         return true;
@@ -816,7 +815,7 @@
         }
     }
 
-    // we dont want to update the maxArraySize when this flag is not set, we just want to include this 
+    // we dont want to update the maxArraySize when this flag is not set, we just want to include this
     // node type in the chain of node types so that its updated when a higher maxArraySize comes in.
     if (!updateFlag)
         return false;
@@ -845,7 +844,7 @@
     {
         // Make the qualifier make sense.
         type.qualifier = EvqTemporary;
-        
+
         if (array)
         {
             error(line, "arrays may not be declared constant since they cannot be initialized", identifier.c_str());
@@ -892,7 +891,7 @@
 }
 
 bool TParseContext::paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type)
-{    
+{
     if (qualifier != EvqConst && qualifier != EvqTemporary) {
         error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier));
         return true;
@@ -989,7 +988,7 @@
 // Initializers show up in several places in the grammar.  Have one set of
 // code to handle them here.
 //
-bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType, 
+bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
                                        TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
 {
     TType type = TType(pType);
@@ -1008,7 +1007,7 @@
         if (! symbolTable.insert(*variable)) {
             error(line, "redefinition", variable->getName().c_str());
             return true;
-            // don't delete variable, it's used by error recovery, and the pool 
+            // don't delete variable, it's used by error recovery, and the pool
             // pop will take care of the memory
         }
     }
@@ -1035,12 +1034,12 @@
             return true;
         }
         if (type != initializer->getType()) {
-            error(line, " non-matching types for const initializer ", 
+            error(line, " non-matching types for const initializer ",
                 variable->getType().getQualifierString());
             variable->getType().setQualifier(EvqTemporary);
             return true;
         }
-        if (initializer->getAsConstantUnion()) { 
+        if (initializer->getAsConstantUnion()) {
             ConstantUnion* unionArray = variable->getConstPointer();
 
             if (type.getObjectSize() == 1 && type.getBasicType() != EbtStruct) {
@@ -1063,7 +1062,7 @@
             return true;
         }
     }
- 
+
     if (qualifier != EvqConst) {
         TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
         intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line);
@@ -1071,7 +1070,7 @@
             assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
             return true;
         }
-    } else 
+    } else
         intermNode = 0;
 
     return false;
@@ -1085,7 +1084,7 @@
 
     bool allConstant = true;
 
-    // check if all the child nodes are constants so that they can be inserted into 
+    // check if all the child nodes are constants so that they can be inserted into
     // the parent node
     TIntermSequence &sequence = aggrNode->getSequence() ;
     for (TIntermSequence::iterator p = sequence.begin(); p != sequence.end(); ++p) {
@@ -1097,85 +1096,44 @@
 }
 
 // This function is used to test for the correctness of the parameters passed to various constructor functions
-// and also convert them to the right datatype if it is allowed and required. 
+// and also convert them to the right datatype if it is allowed and required.
 //
 // Returns 0 for an error or the constructed node (aggregate or typed) for no error.
 //
-TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType* type, TOperator op, TFunction* fnCall, TSourceLoc line)
+TIntermTyped* TParseContext::addConstructor(TIntermNode* arguments, const TType* type, TOperator op, TFunction* fnCall, TSourceLoc line)
 {
-    if (node == 0)
-        return 0;
+    TIntermAggregate *aggregateArguments = arguments->getAsAggregate();
 
-    TIntermAggregate* aggrNode = node->getAsAggregate();
-    
-    TTypeList::const_iterator memberTypes;
-    if (op == EOpConstructStruct)
-        memberTypes = type->getStruct()->begin();
-    
-    TType elementType = *type;
-    if (type->isArray())
-        elementType.clearArrayness();
-
-    bool singleArg;
-    if (aggrNode) {
-        if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1)
-            singleArg = true;
-        else
-            singleArg = false;
-    } else
-        singleArg = true;
-
-    TIntermTyped *newNode;
-    if (singleArg) {
-        // If structure constructor or array constructor is being called 
-        // for only one parameter inside the structure, we need to call constructStruct function once.
-        if (type->isArray())
-            newNode = constructStruct(node, &elementType, 1, node->getLine(), false);
-        else if (op == EOpConstructStruct)
-            newNode = constructStruct(node, (*memberTypes).type, 1, node->getLine(), false);
-        else
-            newNode = constructBuiltIn(type, op, node, node->getLine(), false);
-
-        if (newNode && newNode->getAsAggregate()) {
-            TIntermTyped* constConstructor = foldConstConstructor(newNode->getAsAggregate(), *type);
-            if (constConstructor)
-                return constConstructor;
-        }
-
-        return newNode;
+    if(!aggregateArguments)
+    {
+        aggregateArguments = new TIntermAggregate;
+        aggregateArguments->getSequence().push_back(arguments);
     }
-    
-    //
-    // Handle list of arguments.
-    //
-    TIntermSequence &sequenceVector = aggrNode->getSequence() ;    // Stores the information about the parameter to the constructor
-    // if the structure constructor contains more than one parameter, then construct
-    // each parameter
-    
-    int paramCount = 0;  // keeps a track of the constructor parameter number being checked    
-    
-    // for each parameter to the constructor call, check to see if the right type is passed or convert them 
-    // to the right type if possible (and allowed).
-    // for structure constructors, just check if the right type is passed, no conversion is allowed.
-    
-    for (TIntermSequence::iterator p = sequenceVector.begin(); 
-                                   p != sequenceVector.end(); p++, paramCount++) {
-        if (type->isArray())
-            newNode = constructStruct(*p, &elementType, paramCount+1, node->getLine(), true);
-        else if (op == EOpConstructStruct)
-            newNode = constructStruct(*p, (memberTypes[paramCount]).type, paramCount+1, node->getLine(), true);
-        else
-            newNode = constructBuiltIn(type, op, *p, node->getLine(), true);
-        
-        if (newNode) {
-            *p = newNode;
+
+    if(op == EOpConstructStruct)
+    {
+        TTypeList &fields = *type->getStruct();
+        TIntermSequence &args = aggregateArguments->getSequence();
+
+        for(size_t i = 0; i < fields.size(); i++)
+        {
+            if(args[i]->getAsTyped()->getType() != *fields[i].type)
+            {
+                error(line, "Structure constructor arguments do not match structure fields", "Error");
+                recover();
+
+                return 0;
+            }
         }
     }
 
-    TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, line);
-    TIntermTyped* constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type);
-    if (constConstructor)
+    // Turn the argument list itself into a constructor
+    TIntermTyped *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line);
+    TIntermTyped *constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type);
+    if(constConstructor)
+    {
         return constConstructor;
+    }
 
     return constructor;
 }
@@ -1204,7 +1162,7 @@
 
 // Function for constructor implementation. Calls addUnaryMath with appropriate EOp value
 // for the parameter to the constructor (passed to this function). Essentially, it converts
-// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a 
+// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a
 // float, then float is converted to int.
 //
 // Returns 0 for an error or the constructed node.
@@ -1257,7 +1215,7 @@
     //
     // Now, if there still isn't an operation to do the construction, and we need one, add one.
     //
-    
+
     // Otherwise, skip out early.
     if (subset || (newNode != node && newNode->getType() == *type))
         return newNode;
@@ -1280,7 +1238,7 @@
             return intermediate.setAggregateOperator(node->getAsTyped(), EOpConstructStruct, line);
     } else {
         std::stringstream extraInfoStream;
-        extraInfoStream << "cannot convert parameter " << paramCount 
+        extraInfoStream << "cannot convert parameter " << paramCount
                         << " from '" << node->getAsTyped()->getType().getBasicString()
                         << "' to '" << type->getBasicString() << "'";
         std::string extraInfo = extraInfoStream.str();
@@ -1329,18 +1287,18 @@
             recover();
             fields.offsets[i] = 0;
         }
-        
+
         constArray[i] = unionArray[fields.offsets[i]];
 
-    } 
+    }
     typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
     return typedNode;
 }
 
 //
 // This function returns the column being accessed from a constant matrix. The values are retrieved from
-// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input 
-// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a 
+// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input
+// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a
 // constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure)
 //
 TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, TSourceLoc line)
@@ -1374,8 +1332,8 @@
 
 //
 // This function returns an element of an array accessed from a constant array. The values are retrieved from
-// the symbol table and parse-tree is built for the type of the element. The input 
-// to the function could either be a symbol node (a[0] where a is a constant array)that represents a 
+// the symbol table and parse-tree is built for the type of the element. The input
+// to the function could either be a symbol node (a[0] where a is a constant array)that represents a
 // constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure)
 //
 TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line)
@@ -1411,7 +1369,7 @@
 
 
 //
-// This function returns the value of a particular field inside a constant structure from the symbol table. 
+// This function returns the value of a particular field inside a constant structure from the symbol table.
 // If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr
 // function and returns the parse-tree with the values of the embedded/nested struct.
 //
@@ -1485,7 +1443,7 @@
     // one to the field's struct nesting.
     if (1 + fieldType.getDeepestStructNesting() > kWebGLMaxStructNesting) {
         std::stringstream extraInfoStream;
-        extraInfoStream << "Reference of struct type " << fieldType.getTypeName() 
+        extraInfoStream << "Reference of struct type " << fieldType.getTypeName()
                         << " exceeds maximum struct nesting of " << kWebGLMaxStructNesting;
         std::string extraInfo = extraInfoStream.str();
         error(line, "", "", extraInfo.c_str());