1/* 2 * Copyright 2021 Google LLC 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "include/sksl/SkSLErrorReporter.h" 9#include "src/sksl/SkSLProgramSettings.h" 10#include "src/sksl/ir/SkSLConstructorArray.h" 11#include "src/sksl/ir/SkSLConstructorArrayCast.h" 12 13namespace SkSL { 14 15std::unique_ptr<Expression> ConstructorArray::Convert(const Context& context, 16 int line, 17 const Type& type, 18 ExpressionArray args) { 19 SkASSERTF(type.isArray() && type.columns() > 0, "%s", type.description().c_str()); 20 21 // ES2 doesn't support first-class array types. 22 if (context.fConfig->strictES2Mode()) { 23 context.fErrors->error(line, "construction of array type '" + type.displayName() + 24 "' is not supported"); 25 return nullptr; 26 } 27 28 // If there is a single argument containing an array of matching size and the types are 29 // coercible, this is actually a cast. i.e., `half[10](myFloat10Array)`. This isn't a GLSL 30 // feature, but the Pipeline stage code generator needs this functionality so that code which 31 // was originally compiled with "allow narrowing conversions" enabled can be later recompiled 32 // without narrowing conversions (we patch over these conversions with an explicit cast). 33 if (args.size() == 1) { 34 const Expression& expr = *args.front(); 35 const Type& exprType = expr.type(); 36 37 if (exprType.isArray() && exprType.canCoerceTo(type, /*allowNarrowing=*/true)) { 38 return ConstructorArrayCast::Make(context, line, type, std::move(args.front())); 39 } 40 } 41 42 // Check that the number of constructor arguments matches the array size. 43 if (type.columns() != args.count()) { 44 context.fErrors->error(line, String::printf("invalid arguments to '%s' constructor " 45 "(expected %d elements, but found %d)", 46 type.displayName().c_str(), type.columns(), 47 args.count())); 48 return nullptr; 49 } 50 51 // Convert each constructor argument to the array's component type. 52 const Type& baseType = type.componentType(); 53 for (std::unique_ptr<Expression>& argument : args) { 54 argument = baseType.coerceExpression(std::move(argument), context); 55 if (!argument) { 56 return nullptr; 57 } 58 } 59 60 return ConstructorArray::Make(context, line, type, std::move(args)); 61} 62 63std::unique_ptr<Expression> ConstructorArray::Make(const Context& context, 64 int line, 65 const Type& type, 66 ExpressionArray args) { 67 SkASSERT(!context.fConfig->strictES2Mode()); 68 SkASSERT(type.isAllowedInES2(context)); 69 SkASSERT(type.columns() == args.count()); 70 SkASSERT(std::all_of(args.begin(), args.end(), [&](const std::unique_ptr<Expression>& arg) { 71 return type.componentType() == arg->type(); 72 })); 73 74 return std::make_unique<ConstructorArray>(line, type, std::move(args)); 75} 76 77} // namespace SkSL 78