Produce constructors instead of conversions.

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

BUG=380353

Change-Id: Id871c34750191dac431bf72aac9afed7b0db7f8e
Reviewed-on: https://chromium-review.googlesource.com/203452
Reviewed-by: Shannon Woods <shannonwoods@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Nicolas Capens <nicolascapens@chromium.org>
diff --git a/src/compiler/translator/Intermediate.cpp b/src/compiler/translator/Intermediate.cpp
index 9df2afc..f4f35f3 100644
--- a/src/compiler/translator/Intermediate.cpp
+++ b/src/compiler/translator/Intermediate.cpp
@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
@@ -188,23 +188,9 @@
         default: break;
     }
 
-    //
-    // First try converting the children to compatible types.
-    //
-    if (left->getType().getStruct() && right->getType().getStruct()) {
-        if (left->getType() != right->getType())
-            return 0;
-    } else {
-        TIntermTyped* child = addConversion(op, left->getType(), right);
-        if (child)
-            right = child;
-        else {
-            child = addConversion(op, right->getType(), left);
-            if (child)
-                left = child;
-            else
-                return 0;
-        }
+    if (left->getBasicType() != right->getBasicType())
+    {
+        return 0;
     }
 
     //
@@ -241,19 +227,19 @@
 //
 TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line)
 {
-    //
-    // Like adding binary math, except the conversion can only go
-    // from right to left.
-    //
+    if (left->getType().getStruct() || right->getType().getStruct())
+    {
+        if (left->getType() != right->getType())
+        {
+            return 0;
+        }
+    }
+
     TIntermBinary* node = new TIntermBinary(op);
     node->setLine(line);
 
-    TIntermTyped* child = addConversion(op, left->getType(), right);
-    if (child == 0)
-        return 0;
-
     node->setLeft(left);
-    node->setRight(child);
+    node->setRight(right);
     if (! node->promote(infoSink))
         return 0;
 
@@ -311,42 +297,6 @@
         default: break;
     }
 
-    //
-    // Do we need to promote the operand?
-    //
-    // Note: Implicit promotions were removed from the language.
-    //
-    TBasicType newType = EbtVoid;
-    switch (op) {
-        case EOpConstructInt:   newType = EbtInt;   break;
-        case EOpConstructUInt:  newType = EbtUInt;  break;
-        case EOpConstructBool:  newType = EbtBool;  break;
-        case EOpConstructFloat: newType = EbtFloat; break;
-        default: break;
-    }
-
-    if (newType != EbtVoid) {
-        child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary,
-            child->getNominalSize(),
-            child->getSecondarySize(),
-            child->isArray()),
-            child);
-        if (child == 0)
-            return 0;
-    }
-
-    //
-    // For constructors, we are now done, it's all in the conversion.
-    //
-    switch (op) {
-        case EOpConstructInt:
-        case EOpConstructUInt:
-        case EOpConstructBool:
-        case EOpConstructFloat:
-            return child;
-        default: break;
-    }
-
     TIntermConstantUnion *childTempConstant = 0;
     if (child->getAsConstantUnion())
         childTempConstant = child->getAsConstantUnion();
@@ -640,18 +590,9 @@
 //
 TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& line)
 {
-    //
-    // Get compatible types.
-    //
-    TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock);
-    if (child)
-        falseBlock = child;
-    else {
-        child = addConversion(EOpSequence, falseBlock->getType(), trueBlock);
-        if (child)
-            trueBlock = child;
-        else
-            return 0;
+    if (trueBlock->getType() != falseBlock->getType())
+    {
+        return 0;
     }
 
     //
@@ -1043,7 +984,9 @@
     // GLSL ES 2.0 does not support implicit type casting.
     // So the basic type should always match.
     if (left->getBasicType() != right->getBasicType())
+    {
         return false;
+    }
 
     //
     // Base assumption:  just make the type the same as the left
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index f900966..52aced6 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
@@ -1531,81 +1531,40 @@
 //
 // 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, const TSourceLoc& line)
+TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments, const TType *type, TOperator op, TFunction *fnCall, const TSourceLoc &line)
 {
-    if (node == 0)
-        return 0;
+    TIntermAggregate *aggregateArguments = arguments->getAsAggregate();
 
-    TIntermAggregate* aggrNode = node->getAsAggregate();
-    
-    TFieldList::const_iterator memberTypes;
+    if (!aggregateArguments)
+    {
+        aggregateArguments = new TIntermAggregate;
+        aggregateArguments->getSequence().push_back(arguments);
+    }
+
     if (op == EOpConstructStruct)
-        memberTypes = type->getStruct()->fields().begin();
-    
-    TType elementType = *type;
-    if (type->isArray())
-        elementType.clearArrayness();
+    {
+        const TFieldList &fields = type->getStruct()->fields();
+        TIntermSequence &args = aggregateArguments->getSequence();
 
-    bool singleArg;
-    if (aggrNode) {
-        if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1)
-            singleArg = true;
-        else
-            singleArg = false;
-    } else
-        singleArg = true;
+        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();
 
-    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;
-    }
-    
-    //
-    // 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;
+                return 0;
+            }
         }
     }
 
-    TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, line);
-    TIntermTyped* constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type);
+    // 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;
 }