Revert "Revert "Restored unsized array support to SkSL""

This reverts commit 5270322b46.

Change-Id: If594d04dc657126dce48d69dcc67d1a5e3b0cc8a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/546856
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
Ethan Nicholas 2022-06-03 13:39:06 -04:00 committed by SkCQ
parent 871476a9b2
commit f8c1c459b1
46 changed files with 270 additions and 36 deletions

View File

@ -20,13 +20,29 @@ sksl_error_tests = [
"/sksl/errors/ArraySplitDimensionsInFuncDecl.rts",
"/sksl/errors/ArraySplitDimensionsInStruct.rts",
"/sksl/errors/ArrayTooManyDimensions.rts",
"/sksl/errors/ArrayTooManyDimensionsUnsized1.rts",
"/sksl/errors/ArrayTooManyDimensionsUnsized2.rts",
"/sksl/errors/ArrayTooManyDimensionsInFuncBody.rts",
"/sksl/errors/ArrayTooManyDimensionsInFuncBodyUnsized1.rts",
"/sksl/errors/ArrayTooManyDimensionsInFuncBodyUnsized2.rts",
"/sksl/errors/ArrayTooManyDimensionsInFuncDecl.rts",
"/sksl/errors/ArrayTooManyDimensionsInFuncDeclUnsized1.rts",
"/sksl/errors/ArrayTooManyDimensionsInFuncDeclUnsized2.rts",
"/sksl/errors/ArrayTooManyDimensionsInStruct.rts",
"/sksl/errors/ArrayTooManyDimensionsInStructUnsized1.rts",
"/sksl/errors/ArrayTooManyDimensionsInStructUnsized2.rts",
"/sksl/errors/ArrayTypeTooManyDimensions.rts",
"/sksl/errors/ArrayTypeTooManyDimensionsUnsized1.rts",
"/sksl/errors/ArrayTypeTooManyDimensionsUnsized2.rts",
"/sksl/errors/ArrayTypeTooManyDimensionsInFuncBody.rts",
"/sksl/errors/ArrayTypeTooManyDimensionsInFuncBodyUnsized1.rts",
"/sksl/errors/ArrayTypeTooManyDimensionsInFuncBodyUnsized2.rts",
"/sksl/errors/ArrayTypeTooManyDimensionsInFuncDecl.rts",
"/sksl/errors/ArrayTypeTooManyDimensionsInFuncDeclUnsized1.rts",
"/sksl/errors/ArrayTypeTooManyDimensionsInFuncDeclUnsized2.rts",
"/sksl/errors/ArrayTypeTooManyDimensionsInStruct.rts",
"/sksl/errors/ArrayTypeTooManyDimensionsInStructUnsized1.rts",
"/sksl/errors/ArrayTypeTooManyDimensionsInStructUnsized2.rts",
"/sksl/errors/ArrayUnspecifiedDimensions.rts",
"/sksl/errors/AssignmentTypeMismatch.rts",
"/sksl/errors/BadCaps.sksl",

View File

@ -181,6 +181,7 @@ private:
friend DSLType Array(const DSLType& base, int count, Position pos);
friend DSLType Struct(std::string_view name, SkSpan<DSLField> fields, Position pos);
friend DSLType UnsizedArray(const DSLType& base, Position pos);
friend class DSLCore;
friend class DSLFunction;
friend class DSLVarBase;
@ -228,6 +229,8 @@ MATRIX_TYPE(Half)
DSLType Array(const DSLType& base, int count, Position pos = {});
DSLType UnsizedArray(const DSLType& base, Position pos = {});
class DSLField {
public:
DSLField(const DSLType type, std::string_view name,

View File

@ -43,7 +43,7 @@ array size out of bounds
array size must be an integer
array size must be an integer
array size must be an integer
expected array dimension
unsized arrays are not permitted here
integer is out of range for type 'int': 4000000000
integer is out of range for type 'int': 100000002004087734272
*%%*/

View File

@ -0,0 +1,5 @@
void func() { float x[][2]; }
/*%%*
unsized arrays are not permitted here
*%%*/

View File

@ -0,0 +1,5 @@
void func() { float x[2][]; }
/*%%*
unsized arrays are not permitted here
*%%*/

View File

@ -0,0 +1,5 @@
void func(float x[][2]) {}
/*%%*
unsized arrays are not permitted here
*%%*/

View File

@ -0,0 +1,5 @@
void func(float x[2][]) {}
/*%%*
unsized arrays are not permitted here
*%%*/

View File

@ -0,0 +1,5 @@
struct S { float x[][2]; };
/*%%*
unsized arrays are not permitted here
*%%*/

View File

@ -0,0 +1,5 @@
struct S { float x[2][]; };
/*%%*
unsized arrays are not permitted here
*%%*/

View File

@ -0,0 +1,5 @@
float x[][2];
/*%%*
unsized arrays are not permitted here
*%%*/

View File

@ -0,0 +1,5 @@
float x[2][];
/*%%*
unsized arrays are not permitted here
*%%*/

View File

@ -0,0 +1,5 @@
void func() { float[][2] x; }
/*%%*
unsized arrays are not permitted here
*%%*/

View File

@ -0,0 +1,5 @@
void func() { float[2][] x; }
/*%%*
unsized arrays are not permitted here
*%%*/

View File

@ -0,0 +1,5 @@
void func(float[][2] x) {}
/*%%*
unsized arrays are not permitted here
*%%*/

View File

@ -0,0 +1,5 @@
void func(float[2][] x) {}
/*%%*
unsized arrays are not permitted here
*%%*/

View File

@ -0,0 +1,5 @@
struct S { float[][2] x; };
/*%%*
unsized arrays are not permitted here
*%%*/

View File

@ -0,0 +1,5 @@
struct S { float[2][] x; };
/*%%*
unsized arrays are not permitted here
*%%*/

View File

@ -0,0 +1,5 @@
float[][2] x;
/*%%*
unsized arrays are not permitted here
*%%*/

View File

@ -0,0 +1,5 @@
float[2][] x;
/*%%*
unsized arrays are not permitted here
*%%*/

View File

@ -5,7 +5,7 @@ int arrBool[true];
int unsized_in_expression() { return int[](0)[0]; }
/*%%*
expected array dimension
unsized arrays are not permitted here
array size must be an integer
array size must be an integer
missing index in '[]'

View File

@ -28,6 +28,7 @@
#include "src/sksl/dsl/priv/DSL_priv.h"
#include "src/sksl/ir/SkSLExpression.h"
#include "src/sksl/ir/SkSLProgram.h"
#include "src/sksl/ir/SkSLType.h"
#include <algorithm>
#include <initializer_list>
@ -461,12 +462,17 @@ bool DSLParser::functionDeclarationEnd(Position start,
}
bool DSLParser::arraySize(SKSL_INT* outResult) {
// Start out with a safe value that won't generate any errors downstream
*outResult = 1;
Token next = this->peek();
if (next.fKind == Token::Kind::TK_RBRACKET) {
this->error(this->position(next), "unsized arrays are not permitted here");
return true;
}
DSLExpression sizeExpr = this->expression();
if (!sizeExpr.hasValue()) {
return false;
}
// Start out with a safe value that won't generate any errors downstream
*outResult = 1;
if (sizeExpr.isValid()) {
std::unique_ptr<SkSL::Expression> sizeLiteral = sizeExpr.release();
SKSL_INT size;
@ -492,7 +498,7 @@ bool DSLParser::parseArrayDimensions(Position pos, DSLType* type) {
Token next;
while (this->checkNext(Token::Kind::TK_LBRACKET, &next)) {
if (this->checkNext(Token::Kind::TK_RBRACKET)) {
this->error(this->rangeFrom(next), "expected array dimension");
this->error(this->rangeFrom(pos), "unsized arrays are not permitted here");
} else {
SKSL_INT size;
if (!this->arraySize(&size)) {
@ -967,17 +973,17 @@ DSLType DSLParser::type(DSLModifiers* modifiers) {
return DSLType(nullptr);
}
DSLType result(this->text(type), modifiers, this->position(type));
while (this->checkNext(Token::Kind::TK_LBRACKET)) {
if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
Token bracket;
while (this->checkNext(Token::Kind::TK_LBRACKET, &bracket)) {
if (this->checkNext(Token::Kind::TK_RBRACKET)) {
this->error(this->rangeFrom(bracket), "unsized arrays are not permitted here");
} else {
SKSL_INT size;
if (!this->arraySize(&size)) {
return DSLType(nullptr);
}
this->expect(Token::Kind::TK_RBRACKET, "']'");
result = Array(result, size, this->rangeFrom(type));
} else {
this->error(this->peek(), "expected array dimension");
this->expect(Token::Kind::TK_RBRACKET, "']'");
}
}
return result;
@ -1023,7 +1029,7 @@ bool DSLParser::interfaceBlock(const dsl::DSLModifiers& modifiers) {
}
actualType = Array(std::move(actualType), size, this->position(typeName));
} else {
this->error(sizeToken, "unsized arrays are not permitted");
this->error(sizeToken, "unsized arrays are not permitted here");
}
this->expect(Token::Kind::TK_RBRACKET, "']'");
}

View File

@ -275,6 +275,11 @@ DSLType Array(const DSLType& base, int count, Position pos) {
return DSLType(ThreadContext::SymbolTable()->addArrayDimension(&base.skslType(), count), pos);
}
DSLType UnsizedArray(const DSLType& base, Position pos) {
return ThreadContext::SymbolTable()->addArrayDimension(&base.skslType(),
SkSL::Type::kUnsizedArray);
}
DSLType Struct(std::string_view name, SkSpan<DSLField> fields, Position pos) {
std::vector<SkSL::Type::Field> skslFields;
skslFields.reserve(fields.size());

View File

@ -20,10 +20,13 @@ namespace SkSL {
static bool index_out_of_range(const Context& context, Position pos, SKSL_INT index,
const Expression& base) {
if (index >= 0 && index < base.type().columns()) {
return false;
if (index >= 0) {
if (base.type().columns() == Type::kUnsizedArray) {
return false;
} else if (index < base.type().columns()) {
return false;
}
}
context.fErrors->error(pos, "index " + std::to_string(index) + " out of range for '" +
base.type().displayName() + "'");
return true;

View File

@ -126,8 +126,7 @@ public:
: INHERITED(name, abbrev, kTypeKind)
, fComponentType(componentType)
, fCount(count) {
// Only allow explicitly-sized arrays.
SkASSERT(count > 0);
SkASSERT(count > 0 || count == kUnsizedArray);
// Disallow multi-dimensional arrays.
SkASSERT(!componentType.is<ArrayType>());
}
@ -157,6 +156,7 @@ public:
}
size_t slotCount() const override {
SkASSERT(fCount != kUnsizedArray);
SkASSERT(fCount > 0);
return fCount * fComponentType.slotCount();
}
@ -522,6 +522,9 @@ private:
std::string Type::getArrayName(int arraySize) const {
std::string_view name = this->name();
if (arraySize == kUnsizedArray) {
return String::printf("%.*s[]", (int)name.size(), name.data());
}
return String::printf("%.*s[%d]", (int)name.size(), name.data(), arraySize);
}
@ -965,23 +968,30 @@ bool Type::checkForOutOfRangeLiteral(const Context& context, double value, Posit
return false;
}
bool Type::checkIfUsableInArray(const Context& context, Position arrayPos) const {
if (this->isArray()) {
context.fErrors->error(arrayPos, "multi-dimensional arrays are not supported");
return false;
}
if (this->isVoid()) {
context.fErrors->error(arrayPos, "type 'void' may not be used in an array");
return false;
}
if (this->isOpaque()) {
context.fErrors->error(arrayPos, "opaque type '" + std::string(this->name()) +
"' may not be used in an array");
return false;
}
return true;
}
SKSL_INT Type::convertArraySize(const Context& context, Position arrayPos,
std::unique_ptr<Expression> size) const {
size = context.fTypes.fInt->coerceExpression(std::move(size), context);
if (!size) {
return 0;
}
if (this->isArray()) {
context.fErrors->error(arrayPos, "multi-dimensional arrays are not supported");
return 0;
}
if (this->isVoid()) {
context.fErrors->error(arrayPos, "type 'void' may not be used in an array");
return 0;
}
if (this->isOpaque()) {
context.fErrors->error(arrayPos, "opaque type '" + std::string(this->name()) +
"' may not be used in an array");
if (!this->checkIfUsableInArray(context, arrayPos)) {
return 0;
}
SKSL_INT count;

View File

@ -58,7 +58,8 @@ class Type : public Symbol {
public:
inline static constexpr Kind kSymbolKind = Kind::kType;
inline static constexpr int kMaxAbbrevLength = 3;
// Represents unspecified array dimensions, as in `int[]`.
inline static constexpr int kUnsizedArray = -1;
struct Field {
Field(Position pos, Modifiers modifiers, std::string_view name, const Type* type)
: fPosition(pos)
@ -106,7 +107,7 @@ public:
Type(const Type& other) = delete;
/** Creates an array type. */
/** Creates an array type. `columns` may be kUnsizedArray. */
static std::unique_ptr<Type> MakeArrayType(std::string_view name, const Type& componentType,
int columns);
@ -526,9 +527,14 @@ public:
/** Checks if `value` can fit in this type. The type must be scalar. */
bool checkForOutOfRangeLiteral(const Context& context, double value, Position pos) const;
/**
* Reports errors and returns false if this type cannot be used as the base type for an array.
*/
bool checkIfUsableInArray(const Context& context, Position arrayPos) const;
/**
* Verifies that the expression is a valid constant array size for this type. Returns the array
* size, or zero if the expression isn't a valid literal value.
* size, or reports errors and returns zero if the expression isn't a valid literal value.
*/
SKSL_INT convertArraySize(const Context& context, Position arrayPos,
std::unique_ptr<Expression> size) const;

View File

@ -42,6 +42,9 @@ std::unique_ptr<Variable> Variable::Convert(const Context& context, Position pos
if (!context.fConfig->fIsBuiltinCode && skstd::starts_with(name, '$')) {
context.fErrors->error(namePos, "name '" + std::string(name) + "' is reserved");
}
if (baseType->isArray() && baseType->columns() == Type::kUnsizedArray) {
context.fErrors->error(pos, "unsized arrays are not permitted here");
}
return Make(context, pos, modifiersPos, modifiers, baseType, name, isArray,
std::move(arraySize), storage);

View File

@ -60,9 +60,9 @@ void g2() { float x[false]; }
error: 20: array size must be an integer
void h2() { float x[int2(2, 2)]; }
^^^^^^^^^^
error: 21: expected array dimension
error: 21: unsized arrays are not permitted here
void i2() { float x[]; }
^^
^^^^^^^^^
error: 22: integer is out of range for type 'int': 4000000000
void j2() { float x[int3(4000000000)]; }
^^^^^^^^^^

View File

@ -0,0 +1,6 @@
### Compilation failed:
error: 1: unsized arrays are not permitted here
void func() { float x[][2]; }
^^^^^^^^^
1 error

View File

@ -0,0 +1,6 @@
### Compilation failed:
error: 1: unsized arrays are not permitted here
void func() { float x[2][]; }
^^^^^^^^^^^^
1 error

View File

@ -0,0 +1,6 @@
### Compilation failed:
error: 1: unsized arrays are not permitted here
void func(float x[][2]) {}
^^^^^^^^^
1 error

View File

@ -0,0 +1,6 @@
### Compilation failed:
error: 1: unsized arrays are not permitted here
void func(float x[2][]) {}
^^^^^^^^^^^^
1 error

View File

@ -0,0 +1,9 @@
### Compilation failed:
error: 1: unsized arrays are not permitted here
struct S { float x[][2]; };
^
error: 1: multi-dimensional arrays are not supported
struct S { float x[][2]; };
^^^^^^^^^^^^
2 errors

View File

@ -0,0 +1,9 @@
### Compilation failed:
error: 1: unsized arrays are not permitted here
struct S { float x[2][]; };
^
error: 1: multi-dimensional arrays are not supported
struct S { float x[2][]; };
^^^^^^^^^^^^
2 errors

View File

@ -0,0 +1,6 @@
### Compilation failed:
error: 1: unsized arrays are not permitted here
float x[][2];
^^^^^^^^^
1 error

View File

@ -0,0 +1,6 @@
### Compilation failed:
error: 1: unsized arrays are not permitted here
float x[2][];
^^^^^^^^^^^^
1 error

View File

@ -0,0 +1,6 @@
### Compilation failed:
error: 1: unsized arrays are not permitted here
void func() { float[][2] x; }
^^
1 error

View File

@ -0,0 +1,6 @@
### Compilation failed:
error: 1: unsized arrays are not permitted here
void func() { float[2][] x; }
^^
1 error

View File

@ -0,0 +1,6 @@
### Compilation failed:
error: 1: unsized arrays are not permitted here
void func(float[][2] x) {}
^^
1 error

View File

@ -0,0 +1,6 @@
### Compilation failed:
error: 1: unsized arrays are not permitted here
void func(float[2][] x) {}
^^
1 error

View File

@ -0,0 +1,6 @@
### Compilation failed:
error: 1: unsized arrays are not permitted here
struct S { float[][2] x; };
^^
1 error

View File

@ -0,0 +1,6 @@
### Compilation failed:
error: 1: unsized arrays are not permitted here
struct S { float[2][] x; };
^^
1 error

View File

@ -0,0 +1,6 @@
### Compilation failed:
error: 1: unsized arrays are not permitted here
float[][2] x;
^^
1 error

View File

@ -0,0 +1,6 @@
### Compilation failed:
error: 1: unsized arrays are not permitted here
float[2][] x;
^^
1 error

View File

@ -1,8 +1,8 @@
### Compilation failed:
error: 1: expected array dimension
error: 1: unsized arrays are not permitted here
int arrUnsized[];
^^
^^^^^^^^^^^^^^^^
error: 2: array size must be an integer
int arrFloat[1.];
^^

View File

@ -1,6 +1,6 @@
### Compilation failed:
error: 1: expected expression, but found ']'
error: 1: unsized arrays are not permitted here
T { int x; } f[];
^
1 error

View File

@ -1,6 +1,6 @@
### Compilation failed:
error: 1: expected expression, but found ']'
error: 1: unsized arrays are not permitted here
k{int z;}m[];void main(){}
^
1 error