blob: d8d70d4248a7e5e87fcd0dce8f9793787683eca1 [file] [log] [blame]
/*
* Copyright 2021 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/sksl/SkSLErrorReporter.h"
#include "src/sksl/SkSLProgramSettings.h"
#include "src/sksl/ir/SkSLConstructorArray.h"
#include "src/sksl/ir/SkSLConstructorArrayCast.h"
namespace SkSL {
std::unique_ptr<Expression> ConstructorArray::Convert(const Context& context,
Position pos,
const Type& type,
ExpressionArray args) {
SkASSERTF(type.isArray() && type.columns() > 0, "%s", type.description().c_str());
// ES2 doesn't support first-class array types.
if (context.fConfig->strictES2Mode()) {
context.fErrors->error(pos, "construction of array type '" + type.displayName() +
"' is not supported");
return nullptr;
}
// If there is a single argument containing an array of matching size and the types are
// coercible, this is actually a cast. i.e., `half[10](myFloat10Array)`. This isn't a GLSL
// feature, but the Pipeline stage code generator needs this functionality so that code which
// was originally compiled with "allow narrowing conversions" enabled can be later recompiled
// without narrowing conversions (we patch over these conversions with an explicit cast).
if (args.size() == 1) {
const Expression& expr = *args.front();
const Type& exprType = expr.type();
if (exprType.isArray() && exprType.canCoerceTo(type, /*allowNarrowing=*/true)) {
return ConstructorArrayCast::Make(context, pos, type, std::move(args.front()));
}
}
// Check that the number of constructor arguments matches the array size.
if (type.columns() != args.count()) {
context.fErrors->error(pos, String::printf("invalid arguments to '%s' constructor "
"(expected %d elements, but found %d)", type.displayName().c_str(), type.columns(),
args.count()));
return nullptr;
}
// Convert each constructor argument to the array's component type.
const Type& baseType = type.componentType();
for (std::unique_ptr<Expression>& argument : args) {
argument = baseType.coerceExpression(std::move(argument), context);
if (!argument) {
return nullptr;
}
}
return ConstructorArray::Make(context, pos, type, std::move(args));
}
std::unique_ptr<Expression> ConstructorArray::Make(const Context& context,
Position pos,
const Type& type,
ExpressionArray args) {
SkASSERT(!context.fConfig->strictES2Mode());
SkASSERT(type.isAllowedInES2(context));
SkASSERT(type.columns() == args.count());
SkASSERT(std::all_of(args.begin(), args.end(), [&](const std::unique_ptr<Expression>& arg) {
return type.componentType().matches(arg->type());
}));
return std::make_unique<ConstructorArray>(pos, type, std::move(args));
}
} // namespace SkSL