mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-16 00:17:03 +00:00
Allow array size to be a module-scope constant
Change ast::Array to use an ast::Expression for its `size` field. The WGSL frontend now parses the array size as an `primary_expression`, and the Resolver is responsible for validating the expression is a signed or unsigned integer, and either a literal or a non-overridable module-scope constant. The Resolver evaluates the constant value of the size expression, and so the resolved sem::Array type still has a constant size as before. Fixed: tint:1068 Fixed: tint:1117 Change-Id: Icfa141482ea1e47ea8c21a25e9eb48221f176e9a Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/63061 Auto-Submit: James Price <jrprice@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: James Price <jrprice@google.com> Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
committed by
Tint LUCI CQ
parent
69ce5f74ed
commit
4cc4315d6c
@@ -187,7 +187,11 @@ Array::Array(const Type* t, uint32_t sz, uint32_t st)
|
||||
Array::Array(const Array&) = default;
|
||||
|
||||
ast::Type* Array::Build(ProgramBuilder& b) const {
|
||||
return b.ty.array(type->Build(b), size, stride);
|
||||
if (size > 0) {
|
||||
return b.ty.array(type->Build(b), size, stride);
|
||||
} else {
|
||||
return b.ty.array(type->Build(b), nullptr, stride);
|
||||
}
|
||||
}
|
||||
|
||||
Sampler::Sampler(ast::SamplerKind k) : kind(k) {}
|
||||
|
||||
@@ -1187,7 +1187,7 @@ Expect<ast::Type*> ParserImpl::expect_type_decl_array(
|
||||
ast::DecorationList decos) {
|
||||
const char* use = "array declaration";
|
||||
|
||||
uint32_t size = 0;
|
||||
ast::Expression* size = nullptr;
|
||||
|
||||
auto subtype = expect_lt_gt_block(use, [&]() -> Expect<ast::Type*> {
|
||||
auto type = expect_type(use);
|
||||
@@ -1195,10 +1195,14 @@ Expect<ast::Type*> ParserImpl::expect_type_decl_array(
|
||||
return Failure::kErrored;
|
||||
|
||||
if (match(Token::Type::kComma)) {
|
||||
auto val = expect_nonzero_positive_sint("array size");
|
||||
if (val.errored)
|
||||
auto expr = primary_expression();
|
||||
if (expr.errored) {
|
||||
return Failure::kErrored;
|
||||
size = val.value;
|
||||
} else if (!expr.matched) {
|
||||
return add_error(peek(), "expected array size expression");
|
||||
}
|
||||
|
||||
size = std::move(expr.value);
|
||||
}
|
||||
|
||||
return type.value;
|
||||
|
||||
@@ -862,19 +862,18 @@ TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingType) {
|
||||
" ^\n");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayInvalidSize) {
|
||||
EXPECT(
|
||||
"var i : array<u32, x>;",
|
||||
"test.wgsl:1:20 error: expected signed integer literal for array size\n"
|
||||
"var i : array<u32, x>;\n"
|
||||
" ^\n");
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingSize) {
|
||||
EXPECT("var i : array<u32, >;",
|
||||
"test.wgsl:1:20 error: expected array size expression\n"
|
||||
"var i : array<u32, >;\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayNegativeSize) {
|
||||
EXPECT("var i : array<u32, -3>;",
|
||||
"test.wgsl:1:20 error: array size must be greater than 0\n"
|
||||
"var i : array<u32, -3>;\n"
|
||||
" ^^\n");
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclVarArrayInvalidSize) {
|
||||
EXPECT("var i : array<u32, !>;",
|
||||
"test.wgsl:1:20 error: expected array size expression\n"
|
||||
"var i : array<u32, !>;\n"
|
||||
" ^\n");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplErrorTest, GlobalDeclVarDecoListEmpty) {
|
||||
|
||||
@@ -440,7 +440,7 @@ TEST_F(ParserImplTest, TypeDecl_Atomic_MissingType) {
|
||||
ASSERT_EQ(p->error(), "1:8: invalid type for atomic declaration");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array) {
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_SintLiteralSize) {
|
||||
auto p = parser("array<f32, 5>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.matched);
|
||||
@@ -451,10 +451,57 @@ TEST_F(ParserImplTest, TypeDecl_Array) {
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_FALSE(a->IsRuntimeArray());
|
||||
ASSERT_EQ(a->size(), 5u);
|
||||
ASSERT_TRUE(a->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(a->decorations().size(), 0u);
|
||||
EXPECT_EQ(t.value->source().range, (Source::Range{{1u, 1u}, {1u, 14u}}));
|
||||
|
||||
auto* size_expr = a->Size()->As<ast::ScalarConstructorExpression>();
|
||||
ASSERT_NE(size_expr, nullptr);
|
||||
auto* size = size_expr->literal()->As<ast::SintLiteral>();
|
||||
ASSERT_NE(size, nullptr);
|
||||
EXPECT_EQ(size->value_as_i32(), 5);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_UintLiteralSize) {
|
||||
auto p = parser("array<f32, 5u>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_FALSE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(a->decorations().size(), 0u);
|
||||
EXPECT_EQ(t.value->source().range, (Source::Range{{1u, 1u}, {1u, 15u}}));
|
||||
|
||||
auto* size_expr = a->Size()->As<ast::ScalarConstructorExpression>();
|
||||
ASSERT_NE(size_expr, nullptr);
|
||||
auto* size = size_expr->literal()->As<ast::UintLiteral>();
|
||||
ASSERT_NE(size, nullptr);
|
||||
EXPECT_EQ(size->value_as_u32(), 5u);
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_ConstantSize) {
|
||||
auto p = parser("array<f32, size>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.matched);
|
||||
EXPECT_FALSE(t.errored);
|
||||
ASSERT_NE(t.value, nullptr) << p->error();
|
||||
ASSERT_FALSE(p->has_error());
|
||||
ASSERT_TRUE(t.value->Is<ast::Array>());
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_FALSE(a->IsRuntimeArray());
|
||||
ASSERT_TRUE(a->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(a->decorations().size(), 0u);
|
||||
EXPECT_EQ(t.value->source().range, (Source::Range{{1u, 1u}, {1u, 17u}}));
|
||||
|
||||
auto* size_expr = a->Size()->As<ast::IdentifierExpression>();
|
||||
ASSERT_NE(size_expr, nullptr);
|
||||
EXPECT_EQ(p->builder().Symbols().NameFor(size_expr->symbol()), "size");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_Stride) {
|
||||
@@ -468,9 +515,14 @@ TEST_F(ParserImplTest, TypeDecl_Array_Stride) {
|
||||
|
||||
auto* a = t.value->As<ast::Array>();
|
||||
ASSERT_FALSE(a->IsRuntimeArray());
|
||||
ASSERT_EQ(a->size(), 5u);
|
||||
ASSERT_TRUE(a->type()->Is<ast::F32>());
|
||||
|
||||
auto* size_expr = a->Size()->As<ast::ScalarConstructorExpression>();
|
||||
ASSERT_NE(size_expr, nullptr);
|
||||
auto* size = size_expr->literal()->As<ast::SintLiteral>();
|
||||
ASSERT_NE(size, nullptr);
|
||||
EXPECT_EQ(size->value_as_i32(), 5);
|
||||
|
||||
ASSERT_EQ(a->decorations().size(), 1u);
|
||||
auto* stride = a->decorations()[0];
|
||||
ASSERT_TRUE(stride->Is<ast::StrideDecoration>());
|
||||
@@ -664,34 +716,24 @@ TEST_F(ParserImplTest, TypeDecl_Array_BadType) {
|
||||
ASSERT_EQ(p->error(), "1:7: unknown type 'unknown'");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_ZeroSize) {
|
||||
auto p = parser("array<f32, 0>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:12: array size must be greater than 0");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_NegativeSize) {
|
||||
auto p = parser("array<f32, -1>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:12: array size must be greater than 0");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_BadSize) {
|
||||
auto p = parser("array<f32, invalid>");
|
||||
auto p = parser("array<f32, !>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:12: expected signed integer literal for array size");
|
||||
ASSERT_EQ(p->error(), "1:12: expected array size expression");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_MissingSize) {
|
||||
auto p = parser("array<f32,>");
|
||||
auto t = p->type_decl();
|
||||
EXPECT_TRUE(t.errored);
|
||||
EXPECT_FALSE(t.matched);
|
||||
ASSERT_EQ(t.value, nullptr);
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_EQ(p->error(), "1:11: expected array size expression");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, TypeDecl_Array_MissingLessThan) {
|
||||
|
||||
Reference in New Issue
Block a user