tint/ast: Remove ast::StorageTexture

Instead use ast::TypeName.

Also improve the validation and diagnostics around providing template
arguments to types that do not accept them.

Bug: tint:1810
Change-Id: I4241d50ce0425ab721157686889e918993482876
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/119284
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@chromium.org>
This commit is contained in:
Ben Clayton 2023-02-10 19:24:24 +00:00 committed by Dawn LUCI CQ
parent c66b5e6922
commit 1131d31761
30 changed files with 709 additions and 617 deletions

View File

@ -301,7 +301,6 @@ libtint_source_set("libtint_syntax_tree_src") {
"ast/sampled_texture.h", "ast/sampled_texture.h",
"ast/stage_attribute.h", "ast/stage_attribute.h",
"ast/statement.h", "ast/statement.h",
"ast/storage_texture.h",
"ast/stride_attribute.h", "ast/stride_attribute.h",
"ast/struct.h", "ast/struct.h",
"ast/struct_member.h", "ast/struct_member.h",
@ -665,8 +664,6 @@ libtint_source_set("libtint_ast_src") {
"ast/stage_attribute.h", "ast/stage_attribute.h",
"ast/statement.cc", "ast/statement.cc",
"ast/statement.h", "ast/statement.h",
"ast/storage_texture.cc",
"ast/storage_texture.h",
"ast/stride_attribute.cc", "ast/stride_attribute.cc",
"ast/stride_attribute.h", "ast/stride_attribute.h",
"ast/struct.cc", "ast/struct.cc",
@ -1279,6 +1276,18 @@ if (tint_build_unittests) {
} }
} }
tint_unittests_source_set("libtint_unittests_ast_helper") {
sources = [
"ast/test_helper.h",
"ast/test_helper_test.cc",
]
deps = [
":libtint_ast_src",
":libtint_base_src",
":libtint_syntax_tree_src",
]
}
tint_unittests_source_set("tint_unittests_ast_src") { tint_unittests_source_set("tint_unittests_ast_src") {
sources = [ sources = [
"ast/alias_test.cc", "ast/alias_test.cc",
@ -1333,7 +1342,6 @@ if (tint_build_unittests) {
"ast/return_statement_test.cc", "ast/return_statement_test.cc",
"ast/sampled_texture_test.cc", "ast/sampled_texture_test.cc",
"ast/stage_attribute_test.cc", "ast/stage_attribute_test.cc",
"ast/storage_texture_test.cc",
"ast/stride_attribute_test.cc", "ast/stride_attribute_test.cc",
"ast/struct_member_align_attribute_test.cc", "ast/struct_member_align_attribute_test.cc",
"ast/struct_member_offset_attribute_test.cc", "ast/struct_member_offset_attribute_test.cc",
@ -1342,8 +1350,6 @@ if (tint_build_unittests) {
"ast/struct_test.cc", "ast/struct_test.cc",
"ast/switch_statement_test.cc", "ast/switch_statement_test.cc",
"ast/templated_identifier_test.cc", "ast/templated_identifier_test.cc",
"ast/test_helper.h",
"ast/test_helper_test.cc",
"ast/texture_test.cc", "ast/texture_test.cc",
"ast/traverse_expressions_test.cc", "ast/traverse_expressions_test.cc",
"ast/type_name_test.cc", "ast/type_name_test.cc",
@ -1358,6 +1364,7 @@ if (tint_build_unittests) {
":libtint_ast_src", ":libtint_ast_src",
":libtint_base_src", ":libtint_base_src",
":libtint_transform_src", ":libtint_transform_src",
":libtint_unittests_ast_helper",
] ]
if (tint_build_wgsl_reader && tint_build_wgsl_writer) { if (tint_build_wgsl_reader && tint_build_wgsl_writer) {
@ -1797,6 +1804,7 @@ if (tint_build_unittests) {
deps = [ deps = [
":libtint_base_src", ":libtint_base_src",
":libtint_unittests_ast_helper",
":libtint_wgsl_reader_src", ":libtint_wgsl_reader_src",
] ]
} }
@ -1993,6 +2001,7 @@ if (tint_build_unittests) {
deps = [ deps = [
":libtint_base_src", ":libtint_base_src",
":libtint_unittests_ast_helper",
":tint_unittests_ast_src", ":tint_unittests_ast_src",
] ]
} }

View File

@ -201,8 +201,6 @@ list(APPEND TINT_LIB_SRCS
ast/stage_attribute.h ast/stage_attribute.h
ast/statement.cc ast/statement.cc
ast/statement.h ast/statement.h
ast/storage_texture.cc
ast/storage_texture.h
ast/stride_attribute.cc ast/stride_attribute.cc
ast/stride_attribute.h ast/stride_attribute.h
ast/struct_member_align_attribute.cc ast/struct_member_align_attribute.cc
@ -856,7 +854,6 @@ if(TINT_BUILD_TESTS)
ast/return_statement_test.cc ast/return_statement_test.cc
ast/sampled_texture_test.cc ast/sampled_texture_test.cc
ast/stage_attribute_test.cc ast/stage_attribute_test.cc
ast/storage_texture_test.cc
ast/stride_attribute_test.cc ast/stride_attribute_test.cc
ast/struct_member_align_attribute_test.cc ast/struct_member_align_attribute_test.cc
ast/struct_member_offset_attribute_test.cc ast/struct_member_offset_attribute_test.cc

View File

@ -19,7 +19,6 @@
#include "src/tint/ast/matrix.h" #include "src/tint/ast/matrix.h"
#include "src/tint/ast/pointer.h" #include "src/tint/ast/pointer.h"
#include "src/tint/ast/sampled_texture.h" #include "src/tint/ast/sampled_texture.h"
#include "src/tint/ast/storage_texture.h"
#include "src/tint/ast/struct.h" #include "src/tint/ast/struct.h"
#include "src/tint/ast/test_helper.h" #include "src/tint/ast/test_helper.h"
#include "src/tint/ast/texture.h" #include "src/tint/ast/texture.h"
@ -35,7 +34,6 @@ TEST_F(AstMultisampledTextureTest, IsTexture) {
Texture* t = create<MultisampledTexture>(type::TextureDimension::kCube, ty.f32()); Texture* t = create<MultisampledTexture>(type::TextureDimension::kCube, ty.f32());
EXPECT_TRUE(t->Is<MultisampledTexture>()); EXPECT_TRUE(t->Is<MultisampledTexture>());
EXPECT_FALSE(t->Is<SampledTexture>()); EXPECT_FALSE(t->Is<SampledTexture>());
EXPECT_FALSE(t->Is<StorageTexture>());
} }
TEST_F(AstMultisampledTextureTest, Dim) { TEST_F(AstMultisampledTextureTest, Dim) {

View File

@ -24,7 +24,6 @@ using AstSampledTextureTest = TestHelper;
TEST_F(AstSampledTextureTest, IsTexture) { TEST_F(AstSampledTextureTest, IsTexture) {
Texture* t = create<SampledTexture>(type::TextureDimension::kCube, ty.f32()); Texture* t = create<SampledTexture>(type::TextureDimension::kCube, ty.f32());
EXPECT_TRUE(t->Is<SampledTexture>()); EXPECT_TRUE(t->Is<SampledTexture>());
EXPECT_FALSE(t->Is<StorageTexture>());
} }
TEST_F(AstSampledTextureTest, Dim) { TEST_F(AstSampledTextureTest, Dim) {

View File

@ -1,84 +0,0 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/tint/ast/storage_texture.h"
#include "src/tint/program_builder.h"
TINT_INSTANTIATE_TYPEINFO(tint::ast::StorageTexture);
namespace tint::ast {
StorageTexture::StorageTexture(ProgramID pid,
NodeID nid,
const Source& src,
type::TextureDimension d,
type::TexelFormat fmt,
const Type* subtype,
type::Access ac)
: Base(pid, nid, src, d), format(fmt), type(subtype), access(ac) {}
StorageTexture::StorageTexture(StorageTexture&&) = default;
StorageTexture::~StorageTexture() = default;
std::string StorageTexture::FriendlyName(const SymbolTable&) const {
std::ostringstream out;
out << "texture_storage_" << dim << "<" << format << ", " << access << ">";
return out.str();
}
const StorageTexture* StorageTexture::Clone(CloneContext* ctx) const {
// Clone arguments outside of create() call to have deterministic ordering
auto src = ctx->Clone(source);
auto* ty = ctx->Clone(type);
return ctx->dst->create<StorageTexture>(src, dim, format, ty, access);
}
const Type* StorageTexture::SubtypeFor(type::TexelFormat format, ProgramBuilder& builder) {
switch (format) {
case type::TexelFormat::kR32Uint:
case type::TexelFormat::kRgba8Uint:
case type::TexelFormat::kRg32Uint:
case type::TexelFormat::kRgba16Uint:
case type::TexelFormat::kRgba32Uint: {
return builder.ty.u32();
}
case type::TexelFormat::kR32Sint:
case type::TexelFormat::kRgba8Sint:
case type::TexelFormat::kRg32Sint:
case type::TexelFormat::kRgba16Sint:
case type::TexelFormat::kRgba32Sint: {
return builder.ty.i32();
}
case type::TexelFormat::kBgra8Unorm:
case type::TexelFormat::kRgba8Unorm:
case type::TexelFormat::kRgba8Snorm:
case type::TexelFormat::kR32Float:
case type::TexelFormat::kRg32Float:
case type::TexelFormat::kRgba16Float:
case type::TexelFormat::kRgba32Float: {
return builder.ty.f32();
}
case type::TexelFormat::kUndefined:
break;
}
return nullptr;
}
} // namespace tint::ast

View File

@ -1,77 +0,0 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_TINT_AST_STORAGE_TEXTURE_H_
#define SRC_TINT_AST_STORAGE_TEXTURE_H_
#include <string>
#include "src/tint/ast/texture.h"
#include "src/tint/type/access.h"
#include "src/tint/type/texel_format.h"
#include "src/tint/type/texture_dimension.h"
namespace tint::ast {
/// A storage texture type.
class StorageTexture final : public Castable<StorageTexture, Texture> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
/// @param nid the unique node identifier
/// @param src the source of this node
/// @param dim the dimensionality of the texture
/// @param format the image format of the texture
/// @param subtype the storage subtype. Use SubtypeFor() to calculate this.
/// @param access_control the access control for the texture.
StorageTexture(ProgramID pid,
NodeID nid,
const Source& src,
type::TextureDimension dim,
type::TexelFormat format,
const Type* subtype,
type::Access access_control);
/// Move constructor
StorageTexture(StorageTexture&&);
~StorageTexture() override;
/// @param symbols the program's symbol table
/// @returns the name for this type that closely resembles how it would be
/// declared in WGSL.
std::string FriendlyName(const SymbolTable& symbols) const override;
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
/// @param ctx the clone context
/// @return the newly cloned type
const StorageTexture* Clone(CloneContext* ctx) const override;
/// @param format the storage texture image format
/// @param builder the ProgramBuilder used to build the returned type
/// @returns the storage texture subtype for the given TexelFormat
static const Type* SubtypeFor(type::TexelFormat format, ProgramBuilder& builder);
/// The image format
const type::TexelFormat format;
/// The storage subtype
const Type* const type;
/// The access control
const type::Access access;
};
} // namespace tint::ast
#endif // SRC_TINT_AST_STORAGE_TEXTURE_H_

View File

@ -1,91 +0,0 @@
// Copyright 2020 The Tint Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/tint/ast/storage_texture.h"
#include "src/tint/ast/test_helper.h"
namespace tint::ast {
namespace {
using AstStorageTextureTest = TestHelper;
TEST_F(AstStorageTextureTest, IsTexture) {
auto* subtype = StorageTexture::SubtypeFor(type::TexelFormat::kRgba32Float, *this);
Texture* ty =
create<StorageTexture>(type::TextureDimension::k2dArray, type::TexelFormat::kRgba32Float,
subtype, type::Access::kRead);
EXPECT_FALSE(ty->Is<SampledTexture>());
EXPECT_TRUE(ty->Is<StorageTexture>());
}
TEST_F(AstStorageTextureTest, Dim) {
auto* subtype = StorageTexture::SubtypeFor(type::TexelFormat::kRgba32Float, *this);
auto* s = create<StorageTexture>(type::TextureDimension::k2dArray,
type::TexelFormat::kRgba32Float, subtype, type::Access::kRead);
EXPECT_EQ(s->dim, type::TextureDimension::k2dArray);
}
TEST_F(AstStorageTextureTest, Format) {
auto* subtype = StorageTexture::SubtypeFor(type::TexelFormat::kRgba32Float, *this);
auto* s = create<StorageTexture>(type::TextureDimension::k2dArray,
type::TexelFormat::kRgba32Float, subtype, type::Access::kRead);
EXPECT_EQ(s->format, type::TexelFormat::kRgba32Float);
}
TEST_F(AstStorageTextureTest, FriendlyName) {
auto* subtype = StorageTexture::SubtypeFor(type::TexelFormat::kRgba32Float, *this);
auto* s = create<StorageTexture>(type::TextureDimension::k2dArray,
type::TexelFormat::kRgba32Float, subtype, type::Access::kRead);
EXPECT_EQ(s->FriendlyName(Symbols()), "texture_storage_2d_array<rgba32float, read>");
}
TEST_F(AstStorageTextureTest, F32) {
auto* subtype = StorageTexture::SubtypeFor(type::TexelFormat::kRgba32Float, *this);
Type* s = create<StorageTexture>(type::TextureDimension::k2dArray,
type::TexelFormat::kRgba32Float, subtype, type::Access::kRead);
ASSERT_TRUE(s->Is<Texture>());
ASSERT_TRUE(s->Is<StorageTexture>());
ASSERT_TRUE(s->As<StorageTexture>()->type->Is<ast::TypeName>());
EXPECT_EQ(Symbols().NameFor(s->As<StorageTexture>()->type->As<ast::TypeName>()->name->symbol),
"f32");
}
TEST_F(AstStorageTextureTest, U32) {
auto* subtype = StorageTexture::SubtypeFor(type::TexelFormat::kRg32Uint, *this);
Type* s = create<StorageTexture>(type::TextureDimension::k2dArray, type::TexelFormat::kRg32Uint,
subtype, type::Access::kRead);
ASSERT_TRUE(s->Is<Texture>());
ASSERT_TRUE(s->Is<StorageTexture>());
ASSERT_TRUE(s->As<StorageTexture>()->type->Is<ast::TypeName>());
EXPECT_EQ(Symbols().NameFor(s->As<StorageTexture>()->type->As<ast::TypeName>()->name->symbol),
"u32");
}
TEST_F(AstStorageTextureTest, I32) {
auto* subtype = StorageTexture::SubtypeFor(type::TexelFormat::kRgba32Sint, *this);
Type* s = create<StorageTexture>(type::TextureDimension::k2dArray,
type::TexelFormat::kRgba32Sint, subtype, type::Access::kRead);
ASSERT_TRUE(s->Is<Texture>());
ASSERT_TRUE(s->Is<StorageTexture>());
ASSERT_TRUE(s->As<StorageTexture>()->type->Is<ast::TypeName>());
EXPECT_EQ(Symbols().NameFor(s->As<StorageTexture>()->type->As<ast::TypeName>()->name->symbol),
"i32");
}
} // namespace
} // namespace tint::ast

View File

@ -17,7 +17,7 @@
#include <cstdint> #include <cstdint>
#include "src/tint/ast/storage_texture.h" #include "src/tint/type/texel_format.h"
#include "src/tint/type/texture_dimension.h" #include "src/tint/type/texture_dimension.h"
#include "src/tint/type/type.h" #include "src/tint/type/type.h"

View File

@ -176,6 +176,11 @@ enum builtin_type {
texture_depth_cube texture_depth_cube
texture_depth_cube_array texture_depth_cube_array
texture_depth_multisampled_2d texture_depth_multisampled_2d
// https://www.w3.org/TR/WGSL/#texture-storage
texture_storage_1d
texture_storage_2d
texture_storage_2d_array
texture_storage_3d
// https://www.w3.org/TR/WGSL/#external-texture-type // https://www.w3.org/TR/WGSL/#external-texture-type
texture_external texture_external
} }

View File

@ -68,7 +68,6 @@
#include "src/tint/ast/return_statement.h" #include "src/tint/ast/return_statement.h"
#include "src/tint/ast/sampled_texture.h" #include "src/tint/ast/sampled_texture.h"
#include "src/tint/ast/stage_attribute.h" #include "src/tint/ast/stage_attribute.h"
#include "src/tint/ast/storage_texture.h"
#include "src/tint/ast/stride_attribute.h" #include "src/tint/ast/stride_attribute.h"
#include "src/tint/ast/struct_member_align_attribute.h" #include "src/tint/ast/struct_member_align_attribute.h"
#include "src/tint/ast/struct_member_offset_attribute.h" #include "src/tint/ast/struct_member_offset_attribute.h"
@ -1063,25 +1062,41 @@ class ProgramBuilder {
/// @param dims the dimensionality of the texture /// @param dims the dimensionality of the texture
/// @param format the texel format of the texture /// @param format the texel format of the texture
/// @param access the access control of the texture /// @param access the access control of the texture
/// @returns the storage texture /// @returns the storage texture typename
const ast::StorageTexture* storage_texture(type::TextureDimension dims, const ast::TypeName* storage_texture(type::TextureDimension dims,
type::TexelFormat format, type::TexelFormat format,
type::Access access) const { type::Access access) const {
auto* subtype = ast::StorageTexture::SubtypeFor(format, *builder); return storage_texture(builder->source_, dims, format, access);
return builder->create<ast::StorageTexture>(dims, format, subtype, access);
} }
/// @param source the Source of the node /// @param source the Source of the node
/// @param dims the dimensionality of the texture /// @param dims the dimensionality of the texture
/// @param format the texel format of the texture /// @param format the texel format of the texture
/// @param access the access control of the texture /// @param access the access control of the texture
/// @returns the storage texture /// @returns the storage texture typename
const ast::StorageTexture* storage_texture(const Source& source, const ast::TypeName* storage_texture(const Source& source,
type::TextureDimension dims, type::TextureDimension dims,
type::TexelFormat format, type::TexelFormat format,
type::Access access) const { type::Access access) const {
auto* subtype = ast::StorageTexture::SubtypeFor(format, *builder); switch (dims) {
return builder->create<ast::StorageTexture>(source, dims, format, subtype, access); case type::TextureDimension::k1d:
return (*this)(source, "texture_storage_1d", utils::ToString(format),
utils::ToString(access));
case type::TextureDimension::k2d:
return (*this)(source, "texture_storage_2d", utils::ToString(format),
utils::ToString(access));
case type::TextureDimension::k2dArray:
return (*this)(source, "texture_storage_2d_array", utils::ToString(format),
utils::ToString(access));
case type::TextureDimension::k3d:
return (*this)(source, "texture_storage_3d", utils::ToString(format),
utils::ToString(access));
default:
break;
}
TINT_ICE(ProgramBuilder, builder->Diagnostics())
<< "invalid sampled_texture dimensions: " << dims;
return nullptr;
} }
/// @returns the external texture /// @returns the external texture

View File

@ -19,11 +19,12 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "src/tint/ast/storage_texture.h"
#include "src/tint/castable.h" #include "src/tint/castable.h"
#include "src/tint/symbol.h"
#include "src/tint/type/access.h" #include "src/tint/type/access.h"
#include "src/tint/type/address_space.h" #include "src/tint/type/address_space.h"
#include "src/tint/type/sampler_kind.h" #include "src/tint/type/sampler_kind.h"
#include "src/tint/type/texel_format.h"
#include "src/tint/type/texture_dimension.h" #include "src/tint/type/texture_dimension.h"
#include "src/tint/utils/block_allocator.h" #include "src/tint/utils/block_allocator.h"

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "src/tint/ast/test_helper.h"
#include "src/tint/reader/wgsl/parser_impl_test_helper.h" #include "src/tint/reader/wgsl/parser_impl_test_helper.h"
#include "src/tint/type/depth_texture.h" #include "src/tint/type/depth_texture.h"
#include "src/tint/type/multisampled_texture.h" #include "src/tint/type/multisampled_texture.h"
@ -195,11 +196,8 @@ TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Readonly1dRg32Float) {
EXPECT_FALSE(t.errored); EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr); ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t->Is<ast::Texture>()); ast::CheckIdentifier(p->builder().Symbols(), t->As<ast::TypeName>()->name,
ASSERT_TRUE(t->Is<ast::StorageTexture>()); ast::Template("texture_storage_1d", "rg32float", "read"));
EXPECT_EQ(t->As<ast::StorageTexture>()->format, type::TexelFormat::kRg32Float);
EXPECT_EQ(t->As<ast::StorageTexture>()->access, type::Access::kRead);
EXPECT_EQ(t->As<ast::Texture>()->dim, type::TextureDimension::k1d);
EXPECT_EQ(t->source.range, (Source::Range{{1u, 1u}, {1u, 36u}})); EXPECT_EQ(t->source.range, (Source::Range{{1u, 1u}, {1u, 36u}}));
} }
@ -211,11 +209,8 @@ TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR32Uint) {
EXPECT_FALSE(t.errored); EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr); ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t->Is<ast::Texture>()); ast::CheckIdentifier(p->builder().Symbols(), t->As<ast::TypeName>()->name,
ASSERT_TRUE(t->Is<ast::StorageTexture>()); ast::Template("texture_storage_2d", "r32uint", "write"));
EXPECT_EQ(t->As<ast::StorageTexture>()->format, type::TexelFormat::kR32Uint);
EXPECT_EQ(t->As<ast::StorageTexture>()->access, type::Access::kWrite);
EXPECT_EQ(t->As<ast::Texture>()->dim, type::TextureDimension::k2d);
EXPECT_EQ(t->source.range, (Source::Range{{1u, 1u}, {1u, 35u}})); EXPECT_EQ(t->source.range, (Source::Range{{1u, 1u}, {1u, 35u}}));
} }

View File

@ -48,7 +48,6 @@
#include "src/tint/ast/return_statement.h" #include "src/tint/ast/return_statement.h"
#include "src/tint/ast/sampled_texture.h" #include "src/tint/ast/sampled_texture.h"
#include "src/tint/ast/stage_attribute.h" #include "src/tint/ast/stage_attribute.h"
#include "src/tint/ast/storage_texture.h"
#include "src/tint/ast/stride_attribute.h" #include "src/tint/ast/stride_attribute.h"
#include "src/tint/ast/struct.h" #include "src/tint/ast/struct.h"
#include "src/tint/ast/struct_member_align_attribute.h" #include "src/tint/ast/struct_member_align_attribute.h"
@ -338,31 +337,44 @@ class DependencyScanner {
} }
} }
/// Traverses the expression, performing symbol resolution and determining /// Traverses the expression, performing symbol resolution and determining global dependencies.
/// global dependencies.
void TraverseExpression(const ast::Expression* root) { void TraverseExpression(const ast::Expression* root) {
if (!root) { if (!root) {
return; return;
} }
ast::TraverseExpressions(root, diagnostics_, [&](const ast::Expression* expr) { utils::Vector<const ast::Expression*, 8> pending{root};
Switch( while (!pending.IsEmpty()) {
expr, ast::TraverseExpressions(pending.Pop(), diagnostics_, [&](const ast::Expression* expr) {
[&](const ast::IdentifierExpression* ident) { Switch(
AddDependency(ident->identifier, ident->identifier->symbol, "identifier", expr,
"references"); [&](const ast::IdentifierExpression* e) {
}, AddDependency(e->identifier, e->identifier->symbol, "identifier",
[&](const ast::CallExpression* call) { "references");
if (call->target.name) { if (auto* tmpl_ident = e->identifier->As<ast::TemplatedIdentifier>()) {
AddDependency(call->target.name, call->target.name->symbol, "function", for (auto* arg : tmpl_ident->arguments) {
"calls"); pending.Push(arg);
} }
if (call->target.type) { }
TraverseType(call->target.type); },
} [&](const ast::CallExpression* call) {
}, if (call->target.name) {
[&](const ast::BitcastExpression* cast) { TraverseType(cast->type); }); AddDependency(call->target.name, call->target.name->symbol, "function",
return ast::TraverseAction::Descend; "calls");
}); if (auto* tmpl_ident =
call->target.name->As<ast::TemplatedIdentifier>()) {
for (auto* arg : tmpl_ident->arguments) {
pending.Push(arg);
}
}
}
if (call->target.type) {
TraverseType(call->target.type);
}
},
[&](const ast::BitcastExpression* cast) { TraverseType(cast->type); });
return ast::TraverseAction::Descend;
});
}
} }
/// Traverses the type node, performing symbol resolution and determining /// Traverses the type node, performing symbol resolution and determining
@ -388,6 +400,11 @@ class DependencyScanner {
}, },
[&](const ast::TypeName* tn) { // [&](const ast::TypeName* tn) { //
AddDependency(tn->name, tn->name->symbol, "type", "references"); AddDependency(tn->name, tn->name->symbol, "type", "references");
if (auto* tmpl_ident = tn->name->As<ast::TemplatedIdentifier>()) {
for (auto* arg : tmpl_ident->arguments) {
TraverseExpression(arg);
}
}
}, },
[&](const ast::Vector* vec) { // [&](const ast::Vector* vec) { //
TraverseType(vec->type); TraverseType(vec->type);
@ -398,9 +415,6 @@ class DependencyScanner {
[&](const ast::MultisampledTexture* tex) { // [&](const ast::MultisampledTexture* tex) { //
TraverseType(tex->type); TraverseType(tex->type);
}, },
[&](const ast::StorageTexture* tex) { //
TraverseType(tex->type);
},
[&](Default) { UnhandledNode(diagnostics_, ty); }); [&](Default) { UnhandledNode(diagnostics_, ty); });
} }

View File

@ -121,7 +121,7 @@ TEST_P(ResolverExpressionKindTest, Test) {
Symbol sym; Symbol sym;
switch (GetParam().def) { switch (GetParam().def) {
case Def::kAccess: case Def::kAccess:
sym = Sym("read_write"); sym = Sym("write");
break; break;
case Def::kAddressSpace: case Def::kAddressSpace:
sym = Sym("workgroup"); sym = Sym("workgroup");
@ -155,7 +155,8 @@ TEST_P(ResolverExpressionKindTest, Test) {
switch (GetParam().use) { switch (GetParam().use) {
case Use::kAccess: case Use::kAccess:
return; // TODO(crbug.com/tint/1810) GlobalVar("v", ty("texture_storage_2d", "rgba8unorm", sym), Group(0_u), Binding(0_u));
break;
case Use::kAddressSpace: case Use::kAddressSpace:
return; // TODO(crbug.com/tint/1810) return; // TODO(crbug.com/tint/1810)
case Use::kCallExpr: case Use::kCallExpr:
@ -174,7 +175,8 @@ TEST_P(ResolverExpressionKindTest, Test) {
Structure("s", utils::Vector{Member("m", ty(kUseSource, sym))}); Structure("s", utils::Vector{Member("m", ty(kUseSource, sym))});
break; break;
case Use::kTexelFormat: case Use::kTexelFormat:
return; // TODO(crbug.com/tint/1810) GlobalVar("v", ty("texture_storage_2d", sym, "write"), Group(0_u), Binding(0_u));
break;
case Use::kValueExpression: case Use::kValueExpression:
GlobalVar("v", type::AddressSpace::kPrivate, Expr(kUseSource, sym)); GlobalVar("v", type::AddressSpace::kPrivate, Expr(kUseSource, sym));
break; break;
@ -201,21 +203,18 @@ INSTANTIATE_TEST_SUITE_P(
testing::ValuesIn(std::vector<Case>{ testing::ValuesIn(std::vector<Case>{
{Def::kAccess, Use::kAccess, kPass}, {Def::kAccess, Use::kAccess, kPass},
{Def::kAccess, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"}, {Def::kAccess, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"},
{Def::kAccess, Use::kBinaryOp, R"(5:6 error: cannot use access 'read_write' as value)"}, {Def::kAccess, Use::kBinaryOp, R"(5:6 error: cannot use access 'write' as value)"},
{Def::kAccess, Use::kCallExpr, {Def::kAccess, Use::kCallExpr, R"(5:6 error: cannot use access 'write' as call target)"},
R"(5:6 error: cannot use access 'read_write' as call target)"}, {Def::kAccess, Use::kCallStmt, R"(5:6 error: cannot use access 'write' as call target)"},
{Def::kAccess, Use::kCallStmt, {Def::kAccess, Use::kFunctionReturnType, R"(5:6 error: cannot use access 'write' as type)"},
R"(5:6 error: cannot use access 'read_write' as call target)"}, {Def::kAccess, Use::kMemberType, R"(5:6 error: cannot use access 'write' as type)"},
{Def::kAccess, Use::kFunctionReturnType, {Def::kAccess, Use::kTexelFormat, R"(error: cannot use access 'write' as texel format)"},
R"(5:6 error: cannot use access 'read_write' as type)"}, {Def::kAccess, Use::kValueExpression, R"(5:6 error: cannot use access 'write' as value)"},
{Def::kAccess, Use::kMemberType, R"(5:6 error: cannot use access 'read_write' as type)"}, {Def::kAccess, Use::kVariableType, R"(5:6 error: cannot use access 'write' as type)"},
{Def::kAccess, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"}, {Def::kAccess, Use::kUnaryOp, R"(5:6 error: cannot use access 'write' as value)"},
{Def::kAccess, Use::kValueExpression,
R"(5:6 error: cannot use access 'read_write' as value)"},
{Def::kAccess, Use::kVariableType, R"(5:6 error: cannot use access 'read_write' as type)"},
{Def::kAccess, Use::kUnaryOp, R"(5:6 error: cannot use access 'read_write' as value)"},
{Def::kAddressSpace, Use::kAccess, R"(TODO(crbug.com/tint/1810))"}, {Def::kAddressSpace, Use::kAccess,
R"(error: cannot use address space 'workgroup' as access)"},
{Def::kAddressSpace, Use::kAddressSpace, kPass}, {Def::kAddressSpace, Use::kAddressSpace, kPass},
{Def::kAddressSpace, Use::kBinaryOp, {Def::kAddressSpace, Use::kBinaryOp,
R"(5:6 error: cannot use address space 'workgroup' as value)"}, R"(5:6 error: cannot use address space 'workgroup' as value)"},
@ -227,7 +226,8 @@ INSTANTIATE_TEST_SUITE_P(
R"(5:6 error: cannot use address space 'workgroup' as type)"}, R"(5:6 error: cannot use address space 'workgroup' as type)"},
{Def::kAddressSpace, Use::kMemberType, {Def::kAddressSpace, Use::kMemberType,
R"(5:6 error: cannot use address space 'workgroup' as type)"}, R"(5:6 error: cannot use address space 'workgroup' as type)"},
{Def::kAddressSpace, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"}, {Def::kAddressSpace, Use::kTexelFormat,
R"(error: cannot use address space 'workgroup' as texel format)"},
{Def::kAddressSpace, Use::kValueExpression, {Def::kAddressSpace, Use::kValueExpression,
R"(5:6 error: cannot use address space 'workgroup' as value)"}, R"(5:6 error: cannot use address space 'workgroup' as value)"},
{Def::kAddressSpace, Use::kVariableType, {Def::kAddressSpace, Use::kVariableType,
@ -235,7 +235,7 @@ INSTANTIATE_TEST_SUITE_P(
{Def::kAddressSpace, Use::kUnaryOp, {Def::kAddressSpace, Use::kUnaryOp,
R"(5:6 error: cannot use address space 'workgroup' as value)"}, R"(5:6 error: cannot use address space 'workgroup' as value)"},
{Def::kBuiltinFunction, Use::kAccess, R"(TODO(crbug.com/tint/1810))"}, {Def::kBuiltinFunction, Use::kAccess, R"(error: missing '(' for builtin function call)"},
{Def::kBuiltinFunction, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"}, {Def::kBuiltinFunction, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"},
{Def::kBuiltinFunction, Use::kBinaryOp, {Def::kBuiltinFunction, Use::kBinaryOp,
R"(7:8 error: missing '(' for builtin function call)"}, R"(7:8 error: missing '(' for builtin function call)"},
@ -244,7 +244,8 @@ INSTANTIATE_TEST_SUITE_P(
R"(5:6 error: cannot use builtin function 'workgroupBarrier' as type)"}, R"(5:6 error: cannot use builtin function 'workgroupBarrier' as type)"},
{Def::kBuiltinFunction, Use::kMemberType, {Def::kBuiltinFunction, Use::kMemberType,
R"(5:6 error: cannot use builtin function 'workgroupBarrier' as type)"}, R"(5:6 error: cannot use builtin function 'workgroupBarrier' as type)"},
{Def::kBuiltinFunction, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"}, {Def::kBuiltinFunction, Use::kTexelFormat,
R"(error: missing '(' for builtin function call)"},
{Def::kBuiltinFunction, Use::kValueExpression, {Def::kBuiltinFunction, Use::kValueExpression,
R"(7:8 error: missing '(' for builtin function call)"}, R"(7:8 error: missing '(' for builtin function call)"},
{Def::kBuiltinFunction, Use::kVariableType, {Def::kBuiltinFunction, Use::kVariableType,
@ -252,7 +253,7 @@ INSTANTIATE_TEST_SUITE_P(
{Def::kBuiltinFunction, Use::kUnaryOp, {Def::kBuiltinFunction, Use::kUnaryOp,
R"(7:8 error: missing '(' for builtin function call)"}, R"(7:8 error: missing '(' for builtin function call)"},
{Def::kBuiltinType, Use::kAccess, kPass}, {Def::kBuiltinType, Use::kAccess, R"(error: cannot use type 'vec4<f32>' as access)"},
{Def::kBuiltinType, Use::kAddressSpace, kPass}, {Def::kBuiltinType, Use::kAddressSpace, kPass},
{Def::kBuiltinType, Use::kBinaryOp, {Def::kBuiltinType, Use::kBinaryOp,
R"(5:6 error: cannot use type 'vec4<f32>' as value R"(5:6 error: cannot use type 'vec4<f32>' as value
@ -260,7 +261,8 @@ INSTANTIATE_TEST_SUITE_P(
{Def::kBuiltinType, Use::kCallExpr, kPass}, {Def::kBuiltinType, Use::kCallExpr, kPass},
{Def::kBuiltinType, Use::kFunctionReturnType, kPass}, {Def::kBuiltinType, Use::kFunctionReturnType, kPass},
{Def::kBuiltinType, Use::kMemberType, kPass}, {Def::kBuiltinType, Use::kMemberType, kPass},
{Def::kBuiltinType, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"}, {Def::kBuiltinType, Use::kTexelFormat,
R"(error: cannot use type 'vec4<f32>' as texel format)"},
{Def::kBuiltinType, Use::kValueExpression, {Def::kBuiltinType, Use::kValueExpression,
R"(5:6 error: cannot use type 'vec4<f32>' as value R"(5:6 error: cannot use type 'vec4<f32>' as value
7:8 note: are you missing '()' for type initializer?)"}, 7:8 note: are you missing '()' for type initializer?)"},
@ -269,43 +271,44 @@ INSTANTIATE_TEST_SUITE_P(
R"(5:6 error: cannot use type 'vec4<f32>' as value R"(5:6 error: cannot use type 'vec4<f32>' as value
7:8 note: are you missing '()' for type initializer?)"}, 7:8 note: are you missing '()' for type initializer?)"},
{Def::kFunction, Use::kAccess, R"(TODO(crbug.com/tint/1810))"}, {Def::kFunction, Use::kAccess, R"(error: missing '(' for function call)"},
{Def::kFunction, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"}, {Def::kFunction, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"},
{Def::kFunction, Use::kBinaryOp, R"(7:8 error: missing '(' for function call)"}, {Def::kFunction, Use::kBinaryOp, R"(7:8 error: missing '(' for function call)"},
{Def::kFunction, Use::kCallExpr, kPass}, {Def::kFunction, Use::kCallExpr, kPass},
{Def::kFunction, Use::kCallStmt, kPass}, {Def::kFunction, Use::kCallStmt, kPass},
{Def::kFunction, Use::kFunctionReturnType, {Def::kFunction, Use::kFunctionReturnType,
R"(5:6 error: cannot use function 'FUNCTION' as type R"(5:6 error: cannot use function 'FUNCTION' as type
1:2 note: 'FUNCTION' declared here)"}, 1:2 note: function 'FUNCTION' declared here)"},
{Def::kFunction, Use::kMemberType, {Def::kFunction, Use::kMemberType,
R"(5:6 error: cannot use function 'FUNCTION' as type R"(5:6 error: cannot use function 'FUNCTION' as type
1:2 note: 'FUNCTION' declared here)"}, 1:2 note: function 'FUNCTION' declared here)"},
{Def::kFunction, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"}, {Def::kFunction, Use::kTexelFormat, R"(error: missing '(' for function call)"},
{Def::kFunction, Use::kValueExpression, R"(7:8 error: missing '(' for function call)"}, {Def::kFunction, Use::kValueExpression, R"(7:8 error: missing '(' for function call)"},
{Def::kFunction, Use::kVariableType, {Def::kFunction, Use::kVariableType,
R"(5:6 error: cannot use function 'FUNCTION' as type R"(5:6 error: cannot use function 'FUNCTION' as type
1:2 note: 'FUNCTION' declared here)"}, 1:2 note: function 'FUNCTION' declared here)"},
{Def::kFunction, Use::kUnaryOp, R"(7:8 error: missing '(' for function call)"}, {Def::kFunction, Use::kUnaryOp, R"(7:8 error: missing '(' for function call)"},
{Def::kStruct, Use::kAccess, R"(TODO(crbug.com/tint/1810))"}, {Def::kStruct, Use::kAccess, R"(error: cannot use type 'STRUCT' as access)"},
{Def::kStruct, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"}, {Def::kStruct, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"},
{Def::kStruct, Use::kBinaryOp, R"(5:6 error: cannot use type 'STRUCT' as value {Def::kStruct, Use::kBinaryOp, R"(5:6 error: cannot use type 'STRUCT' as value
7:8 note: are you missing '()' for type initializer? 7:8 note: are you missing '()' for type initializer?
1:2 note: 'STRUCT' declared here)"}, 1:2 note: struct 'STRUCT' declared here)"},
{Def::kStruct, Use::kFunctionReturnType, kPass}, {Def::kStruct, Use::kFunctionReturnType, kPass},
{Def::kStruct, Use::kMemberType, kPass}, {Def::kStruct, Use::kMemberType, kPass},
{Def::kStruct, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"}, {Def::kStruct, Use::kTexelFormat, R"(error: cannot use type 'STRUCT' as texel format)"},
{Def::kStruct, Use::kValueExpression, {Def::kStruct, Use::kValueExpression,
R"(5:6 error: cannot use type 'STRUCT' as value R"(5:6 error: cannot use type 'STRUCT' as value
7:8 note: are you missing '()' for type initializer? 7:8 note: are you missing '()' for type initializer?
1:2 note: 'STRUCT' declared here)"}, 1:2 note: struct 'STRUCT' declared here)"},
{Def::kStruct, Use::kVariableType, kPass}, {Def::kStruct, Use::kVariableType, kPass},
{Def::kStruct, Use::kUnaryOp, {Def::kStruct, Use::kUnaryOp,
R"(5:6 error: cannot use type 'STRUCT' as value R"(5:6 error: cannot use type 'STRUCT' as value
7:8 note: are you missing '()' for type initializer? 7:8 note: are you missing '()' for type initializer?
1:2 note: 'STRUCT' declared here)"}, 1:2 note: struct 'STRUCT' declared here)"},
{Def::kTexelFormat, Use::kAccess, R"(TODO(crbug.com/tint/1810))"}, {Def::kTexelFormat, Use::kAccess,
R"(error: cannot use texel format 'rgba8unorm' as access)"},
{Def::kTexelFormat, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"}, {Def::kTexelFormat, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"},
{Def::kTexelFormat, Use::kBinaryOp, {Def::kTexelFormat, Use::kBinaryOp,
R"(5:6 error: cannot use texel format 'rgba8unorm' as value)"}, R"(5:6 error: cannot use texel format 'rgba8unorm' as value)"},
@ -325,7 +328,7 @@ INSTANTIATE_TEST_SUITE_P(
{Def::kTexelFormat, Use::kUnaryOp, {Def::kTexelFormat, Use::kUnaryOp,
R"(5:6 error: cannot use texel format 'rgba8unorm' as value)"}, R"(5:6 error: cannot use texel format 'rgba8unorm' as value)"},
{Def::kTypeAlias, Use::kAccess, R"(TODO(crbug.com/tint/1810))"}, {Def::kTypeAlias, Use::kAccess, R"(error: cannot use type 'i32' as access)"},
{Def::kTypeAlias, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"}, {Def::kTypeAlias, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"},
{Def::kTypeAlias, Use::kBinaryOp, {Def::kTypeAlias, Use::kBinaryOp,
R"(5:6 error: cannot use type 'i32' as value R"(5:6 error: cannot use type 'i32' as value
@ -333,7 +336,7 @@ INSTANTIATE_TEST_SUITE_P(
{Def::kTypeAlias, Use::kCallExpr, kPass}, {Def::kTypeAlias, Use::kCallExpr, kPass},
{Def::kTypeAlias, Use::kFunctionReturnType, kPass}, {Def::kTypeAlias, Use::kFunctionReturnType, kPass},
{Def::kTypeAlias, Use::kMemberType, kPass}, {Def::kTypeAlias, Use::kMemberType, kPass},
{Def::kTypeAlias, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"}, {Def::kTypeAlias, Use::kTexelFormat, R"(error: cannot use type 'i32' as texel format)"},
{Def::kTypeAlias, Use::kValueExpression, {Def::kTypeAlias, Use::kValueExpression,
R"(5:6 error: cannot use type 'i32' as value R"(5:6 error: cannot use type 'i32' as value
7:8 note: are you missing '()' for type initializer?)"}, 7:8 note: are you missing '()' for type initializer?)"},
@ -342,26 +345,27 @@ INSTANTIATE_TEST_SUITE_P(
R"(5:6 error: cannot use type 'i32' as value R"(5:6 error: cannot use type 'i32' as value
7:8 note: are you missing '()' for type initializer?)"}, 7:8 note: are you missing '()' for type initializer?)"},
{Def::kVariable, Use::kAccess, R"(TODO(crbug.com/tint/1810))"}, {Def::kVariable, Use::kAccess, R"(error: cannot use 'VARIABLE' of type 'i32' as access)"},
{Def::kVariable, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"}, {Def::kVariable, Use::kAddressSpace, R"(TODO(crbug.com/tint/1810))"},
{Def::kVariable, Use::kBinaryOp, kPass}, {Def::kVariable, Use::kBinaryOp, kPass},
{Def::kVariable, Use::kCallStmt, {Def::kVariable, Use::kCallStmt,
R"(5:6 error: cannot use const 'VARIABLE' as call target R"(5:6 error: cannot use const 'VARIABLE' as call target
1:2 note: 'VARIABLE' declared here)"}, 1:2 note: const 'VARIABLE' declared here)"},
{Def::kVariable, Use::kCallExpr, {Def::kVariable, Use::kCallExpr,
R"(5:6 error: cannot use const 'VARIABLE' as call target R"(5:6 error: cannot use const 'VARIABLE' as call target
1:2 note: 'VARIABLE' declared here)"}, 1:2 note: const 'VARIABLE' declared here)"},
{Def::kVariable, Use::kFunctionReturnType, {Def::kVariable, Use::kFunctionReturnType,
R"(5:6 error: cannot use const 'VARIABLE' as type R"(5:6 error: cannot use const 'VARIABLE' as type
1:2 note: 'VARIABLE' declared here)"}, 1:2 note: const 'VARIABLE' declared here)"},
{Def::kVariable, Use::kMemberType, {Def::kVariable, Use::kMemberType,
R"(5:6 error: cannot use const 'VARIABLE' as type R"(5:6 error: cannot use const 'VARIABLE' as type
1:2 note: 'VARIABLE' declared here)"}, 1:2 note: const 'VARIABLE' declared here)"},
{Def::kVariable, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"}, {Def::kVariable, Use::kTexelFormat,
R"(error: cannot use 'VARIABLE' of type 'i32' as texel format)"},
{Def::kVariable, Use::kValueExpression, kPass}, {Def::kVariable, Use::kValueExpression, kPass},
{Def::kVariable, Use::kVariableType, {Def::kVariable, Use::kVariableType,
R"(5:6 error: cannot use const 'VARIABLE' as type R"(5:6 error: cannot use const 'VARIABLE' as type
1:2 note: 'VARIABLE' declared here)"}, 1:2 note: const 'VARIABLE' declared here)"},
{Def::kVariable, Use::kUnaryOp, kPass}, {Def::kVariable, Use::kUnaryOp, kPass},
})); }));

View File

@ -40,7 +40,6 @@
#include "src/tint/ast/pointer.h" #include "src/tint/ast/pointer.h"
#include "src/tint/ast/return_statement.h" #include "src/tint/ast/return_statement.h"
#include "src/tint/ast/sampled_texture.h" #include "src/tint/ast/sampled_texture.h"
#include "src/tint/ast/storage_texture.h"
#include "src/tint/ast/switch_statement.h" #include "src/tint/ast/switch_statement.h"
#include "src/tint/ast/traverse_expressions.h" #include "src/tint/ast/traverse_expressions.h"
#include "src/tint/ast/type_name.h" #include "src/tint/ast/type_name.h"
@ -308,22 +307,9 @@ type::Type* Resolver::Type(const ast::Type* ty) {
} }
return nullptr; return nullptr;
}, },
[&](const ast::StorageTexture* t) -> type::StorageTexture* {
if (auto* el = Type(t->type)) {
if (!validator_.StorageTexture(t)) {
return nullptr;
}
return builder_->create<type::StorageTexture>(t->dim, t->format, t->access, el);
}
return nullptr;
},
[&](const ast::TypeName* t) -> type::Type* { [&](const ast::TypeName* t) -> type::Type* {
Mark(t->name); Mark(t->name);
if (t->name->Is<ast::TemplatedIdentifier>()) {
TINT_UNREACHABLE(Resolver, diagnostics_) << "TODO(crbug.com/tint/1810)";
}
auto resolved = dependencies_.resolved_identifiers.Get(t->name); auto resolved = dependencies_.resolved_identifiers.Get(t->name);
if (!resolved) { if (!resolved) {
TINT_ICE(Resolver, diagnostics_) TINT_ICE(Resolver, diagnostics_)
@ -338,6 +324,15 @@ type::Type* Resolver::Type(const ast::Type* ty) {
ErrorMismatchedResolvedIdentifier(t->source, *resolved, "type"); ErrorMismatchedResolvedIdentifier(t->source, *resolved, "type");
return nullptr; return nullptr;
} }
if (TINT_UNLIKELY(t->name->Is<ast::TemplatedIdentifier>())) {
AddError("type '" + builder_->Symbols().NameFor(t->name->symbol) +
"' does not take template arguments",
t->source);
NoteDeclarationSource(ast_node);
return nullptr;
}
return type; return type;
} }
if (auto b = resolved->BuiltinType(); b != type::Builtin::kUndefined) { if (auto b = resolved->BuiltinType(); b != type::Builtin::kUndefined) {
@ -2431,9 +2426,18 @@ sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
return call; return call;
} }
type::Type* Resolver::BuiltinType(type::Builtin builtin_ty, const ast::Identifier* ident) const { type::Type* Resolver::BuiltinType(type::Builtin builtin_ty, const ast::Identifier* ident) {
auto& b = *builder_; auto& b = *builder_;
auto check_no_tmpl_args = [&](type::Type* ty) -> type::Type* {
if (TINT_UNLIKELY(ident->Is<ast::TemplatedIdentifier>())) {
AddError("type '" + b.Symbols().NameFor(ident->symbol) +
"' does not take template arguments",
ident->source);
return nullptr;
}
return ty;
};
auto f32 = [&] { return b.create<type::F32>(); }; auto f32 = [&] { return b.create<type::F32>(); };
auto i32 = [&] { return b.create<type::I32>(); }; auto i32 = [&] { return b.create<type::I32>(); };
auto u32 = [&] { return b.create<type::U32>(); }; auto u32 = [&] { return b.create<type::U32>(); };
@ -2446,94 +2450,143 @@ type::Type* Resolver::BuiltinType(type::Builtin builtin_ty, const ast::Identifie
auto mat = [&](type::Type* el, uint32_t num_columns, uint32_t num_rows) { auto mat = [&](type::Type* el, uint32_t num_columns, uint32_t num_rows) {
return el ? b.create<type::Matrix>(vec(el, num_rows), num_columns) : nullptr; return el ? b.create<type::Matrix>(vec(el, num_rows), num_columns) : nullptr;
}; };
auto templated_identifier = [&](size_t num_args) -> const ast::TemplatedIdentifier* {
auto* tmpl_ident = ident->As<ast::TemplatedIdentifier>();
if (TINT_UNLIKELY(!tmpl_ident)) {
AddError("expected '<' for '" + b.Symbols().NameFor(ident->symbol) + "'",
Source{ident->source.range.end});
return nullptr;
}
if (TINT_UNLIKELY(tmpl_ident->arguments.Length() != num_args)) {
AddError("'" + b.Symbols().NameFor(ident->symbol) + "' requires " +
std::to_string(num_args) + " template arguments",
ident->source);
return nullptr;
}
return tmpl_ident;
};
auto storage_texture = [&](type::TextureDimension dim) -> type::StorageTexture* {
auto* tmpl_ident = templated_identifier(2);
if (TINT_UNLIKELY(!tmpl_ident)) {
return nullptr;
}
auto* format = sem_.AsTexelFormat(Expression(tmpl_ident->arguments[0]));
if (TINT_UNLIKELY(!format)) {
return nullptr;
}
auto* access = sem_.AsAccess(Expression(tmpl_ident->arguments[1]));
if (TINT_UNLIKELY(!access)) {
return nullptr;
}
auto* subtype = type::StorageTexture::SubtypeFor(format->Value(), builder_->Types());
auto* tex = b.create<type::StorageTexture>(dim, format->Value(), access->Value(), subtype);
if (!validator_.StorageTexture(tex, ident->source)) {
return nullptr;
}
return tex;
};
switch (builtin_ty) { switch (builtin_ty) {
case type::Builtin::kBool: case type::Builtin::kBool:
return b.create<type::Bool>(); return check_no_tmpl_args(b.create<type::Bool>());
case type::Builtin::kI32: case type::Builtin::kI32:
return i32(); return check_no_tmpl_args(i32());
case type::Builtin::kU32: case type::Builtin::kU32:
return u32(); return check_no_tmpl_args(u32());
case type::Builtin::kF16: case type::Builtin::kF16:
return f16(); return check_no_tmpl_args(f16());
case type::Builtin::kF32: case type::Builtin::kF32:
return b.create<type::F32>(); return check_no_tmpl_args(b.create<type::F32>());
case type::Builtin::kMat2X2F: case type::Builtin::kMat2X2F:
return mat(f32(), 2u, 2u); return check_no_tmpl_args(mat(f32(), 2u, 2u));
case type::Builtin::kMat2X3F: case type::Builtin::kMat2X3F:
return mat(f32(), 2u, 3u); return check_no_tmpl_args(mat(f32(), 2u, 3u));
case type::Builtin::kMat2X4F: case type::Builtin::kMat2X4F:
return mat(f32(), 2u, 4u); return check_no_tmpl_args(mat(f32(), 2u, 4u));
case type::Builtin::kMat3X2F: case type::Builtin::kMat3X2F:
return mat(f32(), 3u, 2u); return check_no_tmpl_args(mat(f32(), 3u, 2u));
case type::Builtin::kMat3X3F: case type::Builtin::kMat3X3F:
return mat(f32(), 3u, 3u); return check_no_tmpl_args(mat(f32(), 3u, 3u));
case type::Builtin::kMat3X4F: case type::Builtin::kMat3X4F:
return mat(f32(), 3u, 4u); return check_no_tmpl_args(mat(f32(), 3u, 4u));
case type::Builtin::kMat4X2F: case type::Builtin::kMat4X2F:
return mat(f32(), 4u, 2u); return check_no_tmpl_args(mat(f32(), 4u, 2u));
case type::Builtin::kMat4X3F: case type::Builtin::kMat4X3F:
return mat(f32(), 4u, 3u); return check_no_tmpl_args(mat(f32(), 4u, 3u));
case type::Builtin::kMat4X4F: case type::Builtin::kMat4X4F:
return mat(f32(), 4u, 4u); return check_no_tmpl_args(mat(f32(), 4u, 4u));
case type::Builtin::kMat2X2H: case type::Builtin::kMat2X2H:
return mat(f16(), 2u, 2u); return check_no_tmpl_args(mat(f16(), 2u, 2u));
case type::Builtin::kMat2X3H: case type::Builtin::kMat2X3H:
return mat(f16(), 2u, 3u); return check_no_tmpl_args(mat(f16(), 2u, 3u));
case type::Builtin::kMat2X4H: case type::Builtin::kMat2X4H:
return mat(f16(), 2u, 4u); return check_no_tmpl_args(mat(f16(), 2u, 4u));
case type::Builtin::kMat3X2H: case type::Builtin::kMat3X2H:
return mat(f16(), 3u, 2u); return check_no_tmpl_args(mat(f16(), 3u, 2u));
case type::Builtin::kMat3X3H: case type::Builtin::kMat3X3H:
return mat(f16(), 3u, 3u); return check_no_tmpl_args(mat(f16(), 3u, 3u));
case type::Builtin::kMat3X4H: case type::Builtin::kMat3X4H:
return mat(f16(), 3u, 4u); return check_no_tmpl_args(mat(f16(), 3u, 4u));
case type::Builtin::kMat4X2H: case type::Builtin::kMat4X2H:
return mat(f16(), 4u, 2u); return check_no_tmpl_args(mat(f16(), 4u, 2u));
case type::Builtin::kMat4X3H: case type::Builtin::kMat4X3H:
return mat(f16(), 4u, 3u); return check_no_tmpl_args(mat(f16(), 4u, 3u));
case type::Builtin::kMat4X4H: case type::Builtin::kMat4X4H:
return mat(f16(), 4u, 4u); return check_no_tmpl_args(mat(f16(), 4u, 4u));
case type::Builtin::kVec2F: case type::Builtin::kVec2F:
return vec(f32(), 2u); return check_no_tmpl_args(vec(f32(), 2u));
case type::Builtin::kVec3F: case type::Builtin::kVec3F:
return vec(f32(), 3u); return check_no_tmpl_args(vec(f32(), 3u));
case type::Builtin::kVec4F: case type::Builtin::kVec4F:
return vec(f32(), 4u); return check_no_tmpl_args(vec(f32(), 4u));
case type::Builtin::kVec2H: case type::Builtin::kVec2H:
return vec(f16(), 2u); return check_no_tmpl_args(vec(f16(), 2u));
case type::Builtin::kVec3H: case type::Builtin::kVec3H:
return vec(f16(), 3u); return check_no_tmpl_args(vec(f16(), 3u));
case type::Builtin::kVec4H: case type::Builtin::kVec4H:
return vec(f16(), 4u); return check_no_tmpl_args(vec(f16(), 4u));
case type::Builtin::kVec2I: case type::Builtin::kVec2I:
return vec(i32(), 2u); return check_no_tmpl_args(vec(i32(), 2u));
case type::Builtin::kVec3I: case type::Builtin::kVec3I:
return vec(i32(), 3u); return check_no_tmpl_args(vec(i32(), 3u));
case type::Builtin::kVec4I: case type::Builtin::kVec4I:
return vec(i32(), 4u); return check_no_tmpl_args(vec(i32(), 4u));
case type::Builtin::kVec2U: case type::Builtin::kVec2U:
return vec(u32(), 2u); return check_no_tmpl_args(vec(u32(), 2u));
case type::Builtin::kVec3U: case type::Builtin::kVec3U:
return vec(u32(), 3u); return check_no_tmpl_args(vec(u32(), 3u));
case type::Builtin::kVec4U: case type::Builtin::kVec4U:
return vec(u32(), 4u); return check_no_tmpl_args(vec(u32(), 4u));
case type::Builtin::kSampler: case type::Builtin::kSampler:
return builder_->create<type::Sampler>(type::SamplerKind::kSampler); return check_no_tmpl_args(builder_->create<type::Sampler>(type::SamplerKind::kSampler));
case type::Builtin::kSamplerComparison: case type::Builtin::kSamplerComparison:
return builder_->create<type::Sampler>(type::SamplerKind::kComparisonSampler); return check_no_tmpl_args(
builder_->create<type::Sampler>(type::SamplerKind::kComparisonSampler));
case type::Builtin::kTextureDepth2D: case type::Builtin::kTextureDepth2D:
return builder_->create<type::DepthTexture>(type::TextureDimension::k2d); return check_no_tmpl_args(
builder_->create<type::DepthTexture>(type::TextureDimension::k2d));
case type::Builtin::kTextureDepth2DArray: case type::Builtin::kTextureDepth2DArray:
return builder_->create<type::DepthTexture>(type::TextureDimension::k2dArray); return check_no_tmpl_args(
builder_->create<type::DepthTexture>(type::TextureDimension::k2dArray));
case type::Builtin::kTextureDepthCube: case type::Builtin::kTextureDepthCube:
return builder_->create<type::DepthTexture>(type::TextureDimension::kCube); return check_no_tmpl_args(
builder_->create<type::DepthTexture>(type::TextureDimension::kCube));
case type::Builtin::kTextureDepthCubeArray: case type::Builtin::kTextureDepthCubeArray:
return builder_->create<type::DepthTexture>(type::TextureDimension::kCubeArray); return check_no_tmpl_args(
builder_->create<type::DepthTexture>(type::TextureDimension::kCubeArray));
case type::Builtin::kTextureDepthMultisampled2D: case type::Builtin::kTextureDepthMultisampled2D:
return builder_->create<type::DepthMultisampledTexture>(type::TextureDimension::k2d); return check_no_tmpl_args(
builder_->create<type::DepthMultisampledTexture>(type::TextureDimension::k2d));
case type::Builtin::kTextureExternal: case type::Builtin::kTextureExternal:
return builder_->create<type::ExternalTexture>(); return check_no_tmpl_args(builder_->create<type::ExternalTexture>());
case type::Builtin::kTextureStorage1D:
return storage_texture(type::TextureDimension::k1d);
case type::Builtin::kTextureStorage2D:
return storage_texture(type::TextureDimension::k2d);
case type::Builtin::kTextureStorage2DArray:
return storage_texture(type::TextureDimension::k2dArray);
case type::Builtin::kTextureStorage3D:
return storage_texture(type::TextureDimension::k3d);
case type::Builtin::kUndefined: case type::Builtin::kUndefined:
break; break;
} }
@ -4021,19 +4074,43 @@ void Resolver::ErrorMismatchedResolvedIdentifier(const Source& source,
AddError("cannot use " + resolved.String(builder_->Symbols(), diagnostics_) + " as " + AddError("cannot use " + resolved.String(builder_->Symbols(), diagnostics_) + " as " +
std::string(wanted), std::string(wanted),
source); source);
NoteDeclarationSource(resolved.Node());
}
void Resolver::NoteDeclarationSource(const ast::Node* node) {
Switch( Switch(
resolved.Node(), node,
[&](const ast::TypeDecl* n) { [&](const ast::Struct* n) {
AddNote("'" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", AddNote("struct '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here",
n->source); n->source);
}, },
[&](const ast::Variable* n) { [&](const ast::Alias* n) {
AddNote("'" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", AddNote("alias '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here",
n->source); n->source);
}, },
[&](const ast::Var* n) {
AddNote("var '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here",
n->source);
},
[&](const ast::Let* n) {
AddNote("let '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here",
n->source);
},
[&](const ast::Override* n) {
AddNote("override '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here",
n->source);
},
[&](const ast::Const* n) {
AddNote("const '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here",
n->source);
},
[&](const ast::Parameter* n) {
AddNote(
"parameter '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here",
n->source);
},
[&](const ast::Function* n) { [&](const ast::Function* n) {
AddNote("'" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", AddNote("function '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here",
n->source); n->source);
}); });
} }

View File

@ -432,6 +432,11 @@ class Resolver {
const ResolvedIdentifier& resolved, const ResolvedIdentifier& resolved,
std::string_view wanted); std::string_view wanted);
/// If @p node is a module-scope type, variable or function declaration, then appends a note
/// diagnostic where this declaration was declared, otherwise the function does nothing.
/// @param node the AST node.
void NoteDeclarationSource(const ast::Node* node);
/// Adds the given error message to the diagnostics /// Adds the given error message to the diagnostics
void AddError(const std::string& msg, const Source& source) const; void AddError(const std::string& msg, const Source& source) const;
@ -443,7 +448,7 @@ class Resolver {
/// @returns the type::Type for the builtin type @p builtin_ty with the identifier @p ident /// @returns the type::Type for the builtin type @p builtin_ty with the identifier @p ident
/// @note: Will raise an ICE if @p symbol is not a builtin type. /// @note: Will raise an ICE if @p symbol is not a builtin type.
type::Type* BuiltinType(type::Builtin builtin_ty, const ast::Identifier* ident) const; type::Type* BuiltinType(type::Builtin builtin_ty, const ast::Identifier* ident);
// ArrayInitializerSig represents a unique array initializer signature. // ArrayInitializerSig represents a unique array initializer signature.
// It is a tuple of the array type, number of arguments provided and earliest evaluation stage. // It is a tuple of the array type, number of arguments provided and earliest evaluation stage.

View File

@ -37,30 +37,40 @@ type::Type* SemHelper::TypeOf(const ast::Expression* expr) const {
return sem ? const_cast<type::Type*>(sem->Type()) : nullptr; return sem ? const_cast<type::Type*>(sem->Type()) : nullptr;
} }
void SemHelper::ErrorExpectedValueExpr(const sem::Expression* expr) const { void SemHelper::ErrorUnexpectedExprKind(const sem::Expression* expr,
std::string_view wanted) const {
Switch( Switch(
expr, // expr, //
[&](const sem::VariableUser* var_expr) {
auto name =
builder_->Symbols().NameFor(var_expr->Variable()->Declaration()->name->symbol);
auto type = var_expr->Type()->FriendlyName(builder_->Symbols());
AddError("cannot use '" + name + "' of type '" + type + "' as " + std::string(wanted),
var_expr->Declaration()->source);
},
[&](const sem::ValueExpression* val_expr) {
auto type = val_expr->Type()->FriendlyName(builder_->Symbols());
AddError("cannot use expression of type '" + type + "' as " + std::string(wanted),
val_expr->Declaration()->source);
},
[&](const sem::TypeExpression* ty_expr) { [&](const sem::TypeExpression* ty_expr) {
auto name = ty_expr->Type()->FriendlyName(builder_->Symbols()); auto name = ty_expr->Type()->FriendlyName(builder_->Symbols());
AddError("cannot use type '" + name + "' as value", ty_expr->Declaration()->source); AddError("cannot use type '" + name + "' as " + std::string(wanted),
if (auto* ident = ty_expr->Declaration()->As<ast::IdentifierExpression>()) { ty_expr->Declaration()->source);
AddNote("are you missing '()' for type initializer?",
Source{{ident->source.range.end}});
}
if (auto* str = ty_expr->Type()->As<type::Struct>()) {
AddNote("'" + name + "' declared here", str->Source());
}
}, },
[&](const sem::BuiltinEnumExpression<type::Access>* access) { [&](const sem::BuiltinEnumExpression<type::Access>* access) {
AddError("cannot use access '" + utils::ToString(access->Value()) + "' as value", AddError("cannot use access '" + utils::ToString(access->Value()) + "' as " +
std::string(wanted),
access->Declaration()->source); access->Declaration()->source);
}, },
[&](const sem::BuiltinEnumExpression<type::AddressSpace>* addr) { [&](const sem::BuiltinEnumExpression<type::AddressSpace>* addr) {
AddError("cannot use address space '" + utils::ToString(addr->Value()) + "' as value", AddError("cannot use address space '" + utils::ToString(addr->Value()) + "' as " +
std::string(wanted),
addr->Declaration()->source); addr->Declaration()->source);
}, },
[&](const sem::BuiltinEnumExpression<type::TexelFormat>* fmt) { [&](const sem::BuiltinEnumExpression<type::TexelFormat>* fmt) {
AddError("cannot use texel format '" + utils::ToString(fmt->Value()) + "' as value", AddError("cannot use texel format '" + utils::ToString(fmt->Value()) + "' as " +
std::string(wanted),
fmt->Declaration()->source); fmt->Declaration()->source);
}, },
[&](Default) { [&](Default) {
@ -69,6 +79,20 @@ void SemHelper::ErrorExpectedValueExpr(const sem::Expression* expr) const {
}); });
} }
void SemHelper::ErrorExpectedValueExpr(const sem::Expression* expr) const {
ErrorUnexpectedExprKind(expr, "value");
if (auto* ty_expr = expr->As<sem::TypeExpression>()) {
if (auto* ident = ty_expr->Declaration()->As<ast::IdentifierExpression>()) {
AddNote("are you missing '()' for type initializer?",
Source{{ident->source.range.end}});
}
if (auto* str = ty_expr->Type()->As<type::Struct>()) {
AddNote("struct '" + str->FriendlyName(builder_->Symbols()) + "' declared here",
str->Source());
}
}
}
void SemHelper::AddError(const std::string& msg, const Source& source) const { void SemHelper::AddError(const std::string& msg, const Source& source) const {
builder_->Diagnostics().add_error(diag::System::Resolver, msg, source); builder_->Diagnostics().add_error(diag::System::Resolver, msg, source);
} }

View File

@ -20,6 +20,7 @@
#include "src/tint/diagnostic/diagnostic.h" #include "src/tint/diagnostic/diagnostic.h"
#include "src/tint/program_builder.h" #include "src/tint/program_builder.h"
#include "src/tint/resolver/dependency_graph.h" #include "src/tint/resolver/dependency_graph.h"
#include "src/tint/sem/builtin_enum_expression.h"
#include "src/tint/utils/map.h" #include "src/tint/utils/map.h"
namespace tint::resolver { namespace tint::resolver {
@ -61,25 +62,46 @@ class SemHelper {
} }
/// @param expr the semantic node /// @param expr the semantic node
/// @returns one of: /// @returns nullptr if @p expr is nullptr, or @p expr cast to sem::ValueExpression if the cast
/// * nullptr if @p expr is nullptr /// is successful, otherwise an error diagnostic is raised.
/// * @p expr if the static pointer type already derives from sem::ValueExpression sem::ValueExpression* AsValue(sem::Expression* expr) const {
/// * @p expr cast to sem::ValueExpression if the cast is successful if (TINT_LIKELY(expr)) {
/// * nullptr if @p expr is not a sem::ValueExpression. In this case an error diagnostic is if (auto* val = expr->As<sem::ValueExpression>(); TINT_LIKELY(val)) {
/// raised. return val;
template <typename EXPR>
auto* AsValue(EXPR* expr) const {
if constexpr (traits::IsTypeOrDerived<EXPR, sem::ValueExpression>) {
return expr;
} else {
if (TINT_LIKELY(expr)) {
if (auto* val = expr->template As<sem::ValueExpression>(); TINT_LIKELY(val)) {
return val;
}
ErrorExpectedValueExpr(expr);
} }
return static_cast<sem::ValueExpression*>(nullptr); ErrorExpectedValueExpr(expr);
} }
return nullptr;
}
/// @param expr the semantic node
/// @returns nullptr if @p expr is nullptr, or @p expr cast to
/// sem::BuiltinEnumExpression<type::TexelFormat> if the cast is successful, otherwise an error
/// diagnostic is raised.
sem::BuiltinEnumExpression<type::TexelFormat>* AsTexelFormat(sem::Expression* expr) const {
if (TINT_LIKELY(expr)) {
if (auto* val = expr->As<sem::BuiltinEnumExpression<type::TexelFormat>>();
TINT_LIKELY(val)) {
return val;
}
ErrorUnexpectedExprKind(expr, "texel format");
}
return nullptr;
}
/// @param expr the semantic node
/// @returns nullptr if @p expr is nullptr, or @p expr cast to
/// sem::BuiltinEnumExpression<type::Access> if the cast is successful, otherwise an error
/// diagnostic is raised.
sem::BuiltinEnumExpression<type::Access>* AsAccess(sem::Expression* expr) const {
if (TINT_LIKELY(expr)) {
if (auto* val = expr->As<sem::BuiltinEnumExpression<type::Access>>();
TINT_LIKELY(val)) {
return val;
}
ErrorUnexpectedExprKind(expr, "access");
}
return nullptr;
} }
/// @returns the resolved type of the ast::Expression @p expr /// @returns the resolved type of the ast::Expression @p expr
@ -100,6 +122,10 @@ class SemHelper {
void ErrorExpectedValueExpr(const sem::Expression* expr) const; void ErrorExpectedValueExpr(const sem::Expression* expr) const;
private: private:
/// Raises an error diagnostic that the expression @p got was not of the kind @p wanted.
/// @param expr the expression
void ErrorUnexpectedExprKind(const sem::Expression* expr, std::string_view wanted) const;
/// Adds the given error message to the diagnostics /// Adds the given error message to the diagnostics
void AddError(const std::string& msg, const Source& source) const; void AddError(const std::string& msg, const Source& source) const;

View File

@ -1064,26 +1064,26 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
namespace StorageTextureTests { namespace StorageTextureTests {
struct DimensionParams { struct DimensionParams {
type::TextureDimension dim; const char* name;
bool is_valid; bool is_valid;
}; };
static constexpr DimensionParams Dimension_cases[] = { static constexpr DimensionParams Dimension_cases[] = {
DimensionParams{type::TextureDimension::k1d, true}, DimensionParams{"texture_storage_1d", true},
DimensionParams{type::TextureDimension::k2d, true}, DimensionParams{"texture_storage_2d", true},
DimensionParams{type::TextureDimension::k2dArray, true}, DimensionParams{"texture_storage_2d_array", true},
DimensionParams{type::TextureDimension::k3d, true}, DimensionParams{"texture_storage_3d", true},
DimensionParams{type::TextureDimension::kCube, false}, DimensionParams{"texture_storage_cube", false},
DimensionParams{type::TextureDimension::kCubeArray, false}}; DimensionParams{"texture_storage_cube_array", false}};
using StorageTextureDimensionTest = ResolverTestWithParam<DimensionParams>; using StorageTextureDimensionTest = ResolverTestWithParam<DimensionParams>;
TEST_P(StorageTextureDimensionTest, All) { TEST_P(StorageTextureDimensionTest, All) {
// @group(0) @binding(0) // @group(0) @binding(0)
// var a : texture_storage_*<ru32int, write>; // var a : texture_storage_*<r32uint, write>;
auto& params = GetParam(); auto& params = GetParam();
auto* st = ty.storage_texture(Source{{12, 34}}, params.dim, type::TexelFormat::kR32Uint, auto* st = ty(Source{{12, 34}}, params.name, utils::ToString(type::TexelFormat::kR32Uint),
type::Access::kWrite); utils::ToString(type::Access::kWrite));
GlobalVar("a", st, Group(0_a), Binding(0_a)); GlobalVar("a", st, Group(0_a), Binding(0_a));
@ -1091,8 +1091,7 @@ TEST_P(StorageTextureDimensionTest, All) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
} else { } else {
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), EXPECT_EQ(r()->error(), "12:34 error: unknown type: '" + std::string(params.name) + "'");
"12:34 error: cube dimensions for storage textures are not supported");
} }
} }
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest, INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
@ -1165,22 +1164,33 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
using StorageTextureAccessTest = ResolverTest; using StorageTextureAccessTest = ResolverTest;
TEST_F(StorageTextureAccessTest, MissingAccess_Fail) { TEST_F(StorageTextureAccessTest, MissingTemplates) {
// @group(0) @binding(0) // @group(0) @binding(0)
// var a : texture_storage_1d<ru32int>; // var a : texture_storage_1d<r32uint>;
auto* st = ty.storage_texture(Source{{12, 34}}, type::TextureDimension::k1d, auto* st = ty(Source{{12, 34}}, "texture_storage_1d");
type::TexelFormat::kR32Uint, type::Access::kUndefined);
GlobalVar("a", st, Group(0_a), Binding(0_a)); GlobalVar("a", st, Group(0_a), Binding(0_a));
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: storage texture missing access control"); EXPECT_EQ(r()->error(), "12:34 error: expected '<' for 'texture_storage_1d'");
}
TEST_F(StorageTextureAccessTest, MissingAccess_Fail) {
// @group(0) @binding(0)
// var a : texture_storage_1d<r32uint>;
auto* st = ty(Source{{12, 34}}, "texture_storage_1d", "r32uint");
GlobalVar("a", st, Group(0_a), Binding(0_a));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(12:34 error: 'texture_storage_1d' requires 2 template arguments)");
} }
TEST_F(StorageTextureAccessTest, RWAccess_Fail) { TEST_F(StorageTextureAccessTest, RWAccess_Fail) {
// @group(0) @binding(0) // @group(0) @binding(0)
// var a : texture_storage_1d<ru32int, read_write>; // var a : texture_storage_1d<r32uint, read_write>;
auto* st = ty.storage_texture(Source{{12, 34}}, type::TextureDimension::k1d, auto* st = ty.storage_texture(Source{{12, 34}}, type::TextureDimension::k1d,
type::TexelFormat::kR32Uint, type::Access::kReadWrite); type::TexelFormat::kR32Uint, type::Access::kReadWrite);
@ -1194,7 +1204,7 @@ TEST_F(StorageTextureAccessTest, RWAccess_Fail) {
TEST_F(StorageTextureAccessTest, ReadOnlyAccess_Fail) { TEST_F(StorageTextureAccessTest, ReadOnlyAccess_Fail) {
// @group(0) @binding(0) // @group(0) @binding(0)
// var a : texture_storage_1d<ru32int, read>; // var a : texture_storage_1d<r32uint, read>;
auto* st = ty.storage_texture(Source{{12, 34}}, type::TextureDimension::k1d, auto* st = ty.storage_texture(Source{{12, 34}}, type::TextureDimension::k1d,
type::TexelFormat::kR32Uint, type::Access::kRead); type::TexelFormat::kR32Uint, type::Access::kRead);
@ -1208,7 +1218,7 @@ TEST_F(StorageTextureAccessTest, ReadOnlyAccess_Fail) {
TEST_F(StorageTextureAccessTest, WriteOnlyAccess_Pass) { TEST_F(StorageTextureAccessTest, WriteOnlyAccess_Pass) {
// @group(0) @binding(0) // @group(0) @binding(0)
// var a : texture_storage_1d<ru32int, write>; // var a : texture_storage_1d<r32uint, write>;
auto* st = ty.storage_texture(type::TextureDimension::k1d, type::TexelFormat::kR32Uint, auto* st = ty.storage_texture(type::TextureDimension::k1d, type::TexelFormat::kR32Uint,
type::Access::kWrite); type::Access::kWrite);
@ -1445,5 +1455,91 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
} // namespace BuiltinTypeAliasTests } // namespace BuiltinTypeAliasTests
namespace TypeDoesNotTakeTemplateArgs {
using ResolverUntemplatedTypeUsedWithTemplateArgs = ResolverTestWithParam<const char*>;
TEST_P(ResolverUntemplatedTypeUsedWithTemplateArgs, Builtin_UseWithTemplateArgs) {
// enable f16;
// var<private> v : f32<true>;
Enable(ast::Extension::kF16);
GlobalVar("v", type::AddressSpace::kPrivate, ty(Source{{12, 34}}, GetParam(), true));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: type '" + std::string(GetParam()) +
"' does not take template arguments");
}
TEST_P(ResolverUntemplatedTypeUsedWithTemplateArgs, BuiltinAlias_UseWithTemplateArgs) {
// enable f16;
// alias A = f32;
// var<private> v : S<true>;
Enable(ast::Extension::kF16);
Alias(Source{{56, 78}}, "A", ty(GetParam()));
GlobalVar("v", type::AddressSpace::kPrivate, ty(Source{{12, 34}}, "A", true));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(12:34 error: type 'A' does not take template arguments
56:78 note: alias 'A' declared here)");
}
INSTANTIATE_TEST_SUITE_P(BuiltinTypes,
ResolverUntemplatedTypeUsedWithTemplateArgs,
testing::Values("bool",
"f16",
"f32",
"i32",
"u32",
"mat2x2f",
"mat2x2h",
"mat2x3f",
"mat2x3h",
"mat2x4f",
"mat2x4h",
"mat3x2f",
"mat3x2h",
"mat3x3f",
"mat3x3h",
"mat3x4f",
"mat3x4h",
"mat4x2f",
"mat4x2h",
"mat4x3f",
"mat4x3h",
"mat4x4f",
"mat4x4h",
"vec2f",
"vec2h",
"vec2i",
"vec2u",
"vec3f",
"vec3h",
"vec3i",
"vec3u",
"vec4f",
"vec4h",
"vec4i",
"vec4u"));
TEST_F(ResolverUntemplatedTypeUsedWithTemplateArgs, Struct_UseWithTemplateArgs) {
// struct S {
// i: i32;
// };
// var<private> v : S<true>;
Structure(Source{{56, 78}}, "S", utils::Vector{Member("i", ty.i32())});
GlobalVar("v", type::AddressSpace::kPrivate, ty(Source{{12, 34}}, "S", true));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(12:34 error: type 'S' does not take template arguments
56:78 note: struct 'S' declared here)");
}
} // namespace TypeDoesNotTakeTemplateArgs
} // namespace } // namespace
} // namespace tint::resolver } // namespace tint::resolver

View File

@ -37,7 +37,6 @@
#include "src/tint/ast/pointer.h" #include "src/tint/ast/pointer.h"
#include "src/tint/ast/return_statement.h" #include "src/tint/ast/return_statement.h"
#include "src/tint/ast/sampled_texture.h" #include "src/tint/ast/sampled_texture.h"
#include "src/tint/ast/storage_texture.h"
#include "src/tint/ast/switch_statement.h" #include "src/tint/ast/switch_statement.h"
#include "src/tint/ast/traverse_expressions.h" #include "src/tint/ast/traverse_expressions.h"
#include "src/tint/ast/type_name.h" #include "src/tint/ast/type_name.h"
@ -316,28 +315,28 @@ bool Validator::Pointer(const ast::Pointer* a, const type::Pointer* s) const {
a->source); a->source);
} }
bool Validator::StorageTexture(const ast::StorageTexture* t) const { bool Validator::StorageTexture(const type::StorageTexture* t, const Source& source) const {
switch (t->access) { switch (t->access()) {
case type::Access::kWrite: case type::Access::kWrite:
break; break;
case type::Access::kUndefined: case type::Access::kUndefined:
AddError("storage texture missing access control", t->source); AddError("storage texture missing access control", source);
return false; return false;
default: default:
AddError("storage textures currently only support 'write' access control", t->source); AddError("storage textures currently only support 'write' access control", source);
return false; return false;
} }
if (!IsValidStorageTextureDimension(t->dim)) { if (!IsValidStorageTextureDimension(t->dim())) {
AddError("cube dimensions for storage textures are not supported", t->source); AddError("cube dimensions for storage textures are not supported", source);
return false; return false;
} }
if (!IsValidStorageTextureTexelFormat(t->format)) { if (!IsValidStorageTextureTexelFormat(t->texel_format())) {
AddError( AddError(
"image format must be one of the texel formats specified for storage " "image format must be one of the texel formats specified for storage "
"textues in https://gpuweb.github.io/gpuweb/wgsl/#texel-formats", "textues in https://gpuweb.github.io/gpuweb/wgsl/#texel-formats",
t->source); source);
return false; return false;
} }
return true; return true;

View File

@ -372,8 +372,9 @@ class Validator {
/// Validates a storage texture /// Validates a storage texture
/// @param t the texture to validate /// @param t the texture to validate
/// @param source the source of the texture
/// @returns true on success, false otherwise /// @returns true on success, false otherwise
bool StorageTexture(const ast::StorageTexture* t) const; bool StorageTexture(const type::StorageTexture* t, const Source& source) const;
/// Validates a sampled texture /// Validates a sampled texture
/// @param t the texture to validate /// @param t the texture to validate

View File

@ -22,6 +22,8 @@
#include "src/tint/program_builder.h" #include "src/tint/program_builder.h"
#include "src/tint/sem/builtin.h" #include "src/tint/sem/builtin.h"
#include "src/tint/sem/call.h" #include "src/tint/sem/call.h"
#include "src/tint/sem/type_expression.h"
#include "src/tint/type/storage_texture.h"
#include "src/tint/type/texture_dimension.h" #include "src/tint/type/texture_dimension.h"
#include "src/tint/utils/map.h" #include "src/tint/utils/map.h"
@ -1065,13 +1067,17 @@ Transform::ApplyResult BuiltinPolyfill::Apply(const Program* src,
break; break;
} }
}, },
[&](const ast::StorageTexture* tex) { [&](const ast::TypeName* type_name) {
if (polyfill.bgra8unorm && tex->format == type::TexelFormat::kBgra8Unorm) { if (polyfill.bgra8unorm) {
ctx.Replace(tex, [&ctx, tex] { if (auto* tex = src->Sem().Get<type::StorageTexture>(type_name)) {
return ctx.dst->ty.storage_texture(tex->dim, type::TexelFormat::kRgba8Unorm, if (tex->texel_format() == type::TexelFormat::kBgra8Unorm) {
tex->access); ctx.Replace(type_name, [&ctx, tex] {
}); return ctx.dst->ty.storage_texture(
made_changes = true; tex->dim(), type::TexelFormat::kRgba8Unorm, tex->access());
});
made_changes = true;
}
}
} }
}); });
} }

View File

@ -83,7 +83,8 @@ struct Texture1DTo2D::State {
return SkipTransform; return SkipTransform;
} }
auto create_var = [&](const ast::Variable* v, ast::Type* type) -> const ast::Variable* { auto create_var = [&](const ast::Variable* v,
const ast::Type* type) -> const ast::Variable* {
if (v->As<ast::Parameter>()) { if (v->As<ast::Parameter>()) {
return ctx.dst->Param(ctx.Clone(v->name->symbol), type, ctx.Clone(v->attributes)); return ctx.dst->Param(ctx.Clone(v->name->symbol), type, ctx.Clone(v->attributes));
} else { } else {
@ -105,9 +106,9 @@ struct Texture1DTo2D::State {
}, },
[&](const type::StorageTexture* storage_tex) -> const ast::Variable* { [&](const type::StorageTexture* storage_tex) -> const ast::Variable* {
if (storage_tex->dim() == type::TextureDimension::k1d) { if (storage_tex->dim() == type::TextureDimension::k1d) {
auto* type = ctx.dst->create<ast::StorageTexture>( auto* type = ctx.dst->ty.storage_texture(type::TextureDimension::k2d,
type::TextureDimension::k2d, storage_tex->texel_format(), storage_tex->texel_format(),
CreateASTTypeFor(ctx, storage_tex->type()), storage_tex->access()); storage_tex->access());
return create_var(v, type); return create_var(v, type);
} else { } else {
return nullptr; return nullptr;

View File

@ -163,8 +163,7 @@ const ast::Type* Transform::CreateASTTypeFor(CloneContext& ctx, const type::Type
return ctx.dst->create<ast::SampledTexture>(t->dim(), CreateASTTypeFor(ctx, t->type())); return ctx.dst->create<ast::SampledTexture>(t->dim(), CreateASTTypeFor(ctx, t->type()));
} }
if (auto* t = ty->As<type::StorageTexture>()) { if (auto* t = ty->As<type::StorageTexture>()) {
return ctx.dst->create<ast::StorageTexture>(t->dim(), t->texel_format(), return ctx.dst->ty.storage_texture(t->dim(), t->texel_format(), t->access());
CreateASTTypeFor(ctx, t->type()), t->access());
} }
if (auto* s = ty->As<type::Sampler>()) { if (auto* s = ty->As<type::Sampler>()) {
return ctx.dst->ty.sampler(s->kind()); return ctx.dst->ty.sampler(s->kind());

View File

@ -118,6 +118,18 @@ Builtin ParseBuiltin(std::string_view str) {
if (str == "texture_external") { if (str == "texture_external") {
return Builtin::kTextureExternal; return Builtin::kTextureExternal;
} }
if (str == "texture_storage_1d") {
return Builtin::kTextureStorage1D;
}
if (str == "texture_storage_2d") {
return Builtin::kTextureStorage2D;
}
if (str == "texture_storage_2d_array") {
return Builtin::kTextureStorage2DArray;
}
if (str == "texture_storage_3d") {
return Builtin::kTextureStorage3D;
}
if (str == "u32") { if (str == "u32") {
return Builtin::kU32; return Builtin::kU32;
} }
@ -224,6 +236,14 @@ std::ostream& operator<<(std::ostream& out, Builtin value) {
return out << "texture_depth_multisampled_2d"; return out << "texture_depth_multisampled_2d";
case Builtin::kTextureExternal: case Builtin::kTextureExternal:
return out << "texture_external"; return out << "texture_external";
case Builtin::kTextureStorage1D:
return out << "texture_storage_1d";
case Builtin::kTextureStorage2D:
return out << "texture_storage_2d";
case Builtin::kTextureStorage2DArray:
return out << "texture_storage_2d_array";
case Builtin::kTextureStorage3D:
return out << "texture_storage_3d";
case Builtin::kU32: case Builtin::kU32:
return out << "u32"; return out << "u32";
case Builtin::kVec2F: case Builtin::kVec2F:

View File

@ -60,6 +60,10 @@ enum class Builtin {
kTextureDepthCubeArray, kTextureDepthCubeArray,
kTextureDepthMultisampled2D, kTextureDepthMultisampled2D,
kTextureExternal, kTextureExternal,
kTextureStorage1D,
kTextureStorage2D,
kTextureStorage2DArray,
kTextureStorage3D,
kU32, kU32,
kVec2F, kVec2F,
kVec2H, kVec2H,
@ -116,6 +120,10 @@ constexpr const char* kBuiltinStrings[] = {
"texture_depth_cube_array", "texture_depth_cube_array",
"texture_depth_multisampled_2d", "texture_depth_multisampled_2d",
"texture_external", "texture_external",
"texture_storage_1d",
"texture_storage_2d",
"texture_storage_2d_array",
"texture_storage_3d",
"u32", "u32",
"vec2f", "vec2f",
"vec2h", "vec2h",

View File

@ -241,97 +241,125 @@ void BuiltinParser(::benchmark::State& state) {
"textuXe_ZZxtJJrnal", "textuXe_ZZxtJJrnal",
"textuPPe_eternal", "textuPPe_eternal",
"texturc_external", "texturc_external",
"ull62", "tllxture_storage_P6d",
"93yy", "tex99ure_yytorag_1d",
"u3KK", "textuKKe_storage_1d",
"texture_storage_1d",
"texture__xorage_d",
"yxKur_storage_1d",
"textureVstorkge_1z",
"texKure_Storqge_2d",
"texture_storage_d",
"teture_storage_VVd",
"texture_storage_2d",
"textureIstoraAUe_2d",
"jextre_storaR_2d",
"extue44storYYge_2",
"textre_storage_2d_array",
"tex9ur_stor11ge_d_xxrray",
"tmmxture_storJe_2d_arrcc",
"texture_storage_2d_array",
"tJJxture_storage_2_array",
"DDCCltufe_storaUe_2d_array",
"tegture_storage_2d_array",
"exture_srageCC3d",
"txture_storage_3d",
"textuIe_sto__age_3d",
"texture_storage_3d",
"texttte_PPorage_3d",
"texture_stora3de_3d",
"exture_Ktoragyy_3d",
"",
"03nn",
"uCnuu",
"u32", "u32",
"x_", "3Xl",
"K", "pp3o",
"kVz", "uww",
"veKSf",
"vc2f",
"ec2VV",
"vec2f",
"IAAc2f",
"jbR",
"veY4",
"ec2h",
"vc911",
"mmcch",
"vec2h",
"vJJch",
"lDDcUfC",
"vec2g",
"CCe",
"ec2i",
"vIc__i",
"vec2i",
"ePPtt",
"v3dc2i",
"vcyyi",
"u2",
"v03nnu",
"Cuuecnv",
"vec2u",
"vX2ll",
"vocppu",
"vwwc2",
"veuug", "veuug",
"vaac", "vaac",
"TRZcccf", "TRZcccf",
"vec3f", "vec2f",
"vTc3O8", "vTc2O8",
"vem03f", "vem02f",
"meBB3f", "meBB2f",
"Mpp3", "Mpp2",
"OOe3h", "OOe2h",
"veG3G", "veG2G",
"vec3h", "vec2h",
"11eHH3h", "11eHH2h",
"veFFe6", "veFFe6",
"ve3", "ve2",
"vKii3l", "vKii2l",
"ec3i", "ec2i",
"v993IIv", "v992IIv",
"vec3i", "vec2i",
"veci", "veci",
"vechi", "vechi",
"vczllPi", "vczllPi",
"u", "u",
"vffqq3", "vffqq2",
"vJdd3u", "vJdd2u",
"vec3u", "vec2u",
"vecXX", "vecXX",
"ve32", "ve22",
"Nyyc3u", "Nyyc2u",
"vO4", "vO3",
"PEruZ", "PEruZ",
"vlc2edd", "vlc2edd",
"vec4f", "vec3f",
"ec9f", "ec9f",
"ve1II", "ve1II",
"veb4f", "veb3f",
"vi7", "vi7",
"oec4ii", "oec3ii",
"ec4", "ec3",
"vec4h", "vec3h",
"veci", "veci",
"22ec", "22ec",
"vGc4C", "vGc3C",
"ffec48", "ffec38",
"c4i", "c3i",
"JJecSSi", "JJecSSi",
"vec4i", "vec3i",
"94i", "93i",
"vbbJJ4TT", "vbbJJ3TT",
"e66i", "e66i",
"u664u", "u663u",
"vW4u", "vW3u",
"v4u", "v3u",
"vec4u", "vec3u",
"vecu", "vecu",
"rec4u", "rec3u",
"2ec4B", "2ec3B",
"vcBBf",
"vRc4f",
"v4LL0",
"vec4f",
"vKOOf",
"vgwcf",
"vLphf",
"eiiEh",
"ec4h",
"UU884",
"vec4h",
"rrecvvh",
"ecmm",
"vec4j",
"vec4X",
"vec48",
"vecvEE",
"vec4i",
"z99ci",
"GGeJJA4i",
"vess4i",
"vPcKu",
"tpc4u",
"vec",
"vec4u",
"MMec4u",
"vJJc40",
"8c",
}; };
for (auto _ : state) { for (auto _ : state) {
for (auto* str : kStrings) { for (auto* str : kStrings) {

View File

@ -73,6 +73,10 @@ static constexpr Case kValidCases[] = {
{"texture_depth_cube_array", Builtin::kTextureDepthCubeArray}, {"texture_depth_cube_array", Builtin::kTextureDepthCubeArray},
{"texture_depth_multisampled_2d", Builtin::kTextureDepthMultisampled2D}, {"texture_depth_multisampled_2d", Builtin::kTextureDepthMultisampled2D},
{"texture_external", Builtin::kTextureExternal}, {"texture_external", Builtin::kTextureExternal},
{"texture_storage_1d", Builtin::kTextureStorage1D},
{"texture_storage_2d", Builtin::kTextureStorage2D},
{"texture_storage_2d_array", Builtin::kTextureStorage2DArray},
{"texture_storage_3d", Builtin::kTextureStorage3D},
{"u32", Builtin::kU32}, {"u32", Builtin::kU32},
{"vec2f", Builtin::kVec2F}, {"vec2f", Builtin::kVec2F},
{"vec2h", Builtin::kVec2H}, {"vec2h", Builtin::kVec2H},
@ -179,45 +183,57 @@ static constexpr Case kInvalidCases[] = {
{"texture_exernss77", Builtin::kUndefined}, {"texture_exernss77", Builtin::kUndefined},
{"texture_bbxternRRl", Builtin::kUndefined}, {"texture_bbxternRRl", Builtin::kUndefined},
{"textureXXexternal", Builtin::kUndefined}, {"textureXXexternal", Builtin::kUndefined},
{"qOOO2", Builtin::kUndefined}, {"CCextOOre_stoage_qOd", Builtin::kUndefined},
{"us", Builtin::kUndefined}, {"txtsre_sturage_1L", Builtin::kUndefined},
{"u3X", Builtin::kUndefined}, {"texture_stoXage_1d", Builtin::kUndefined},
{"ve2f", Builtin::kUndefined}, {"textue_storage_2d", Builtin::kUndefined},
{"qq2", Builtin::kUndefined}, {"teuresOorageqq2d", Builtin::kUndefined},
{"vec222", Builtin::kUndefined}, {"texture_sto22age_2d", Builtin::kUndefined},
{"vezzXy", Builtin::kUndefined}, {"exture_syora0e_2d_Xzzrray", Builtin::kUndefined},
{"ieVVP", Builtin::kUndefined}, {"texiVVr_storageP2d_array", Builtin::kUndefined},
{"venCh", Builtin::kUndefined}, {"texturestorage_2nn_arCay", Builtin::kUndefined},
{"vHc2Aq", Builtin::kUndefined}, {"texturHHstorAAe_qqd", Builtin::kUndefined},
{"ve2i", Builtin::kUndefined}, {"textur_storage_3d", Builtin::kUndefined},
{"vefK", Builtin::kUndefined}, {"texure_sfKorage3d", Builtin::kUndefined},
{"vgg2", Builtin::kUndefined}, {"gg", Builtin::kUndefined},
{"vecu", Builtin::kUndefined}, {"u3", Builtin::kUndefined},
{"4TNc2u", Builtin::kUndefined}, {"NT42", Builtin::kUndefined},
{"ppec7l", Builtin::kUndefined}, {"ppec7l", Builtin::kUndefined},
{"zNe3f", Builtin::kUndefined}, {"zNe2f", Builtin::kUndefined},
{"uXXb3f", Builtin::kUndefined}, {"uXXb2f", Builtin::kUndefined},
{"vec3", Builtin::kUndefined}, {"vec2", Builtin::kUndefined},
{"883K", Builtin::kUndefined}, {"882K", Builtin::kUndefined},
{"vq9h", Builtin::kUndefined}, {"vq9h", Builtin::kUndefined},
{"vec311", Builtin::kUndefined}, {"vec211", Builtin::kUndefined},
{"22ciii", Builtin::kUndefined}, {"22ciii", Builtin::kUndefined},
{"ec77i", Builtin::kUndefined}, {"ec77i", Builtin::kUndefined},
{"NN23u", Builtin::kUndefined}, {"NN22u", Builtin::kUndefined},
{"vVVc3u", Builtin::kUndefined}, {"vVVc2u", Builtin::kUndefined},
{"WW11w3u", Builtin::kUndefined}, {"WW11w2u", Builtin::kUndefined},
{"vcwwf", Builtin::kUndefined}, {"vcwwf", Builtin::kUndefined},
{"vDc4f", Builtin::kUndefined}, {"vDc3f", Builtin::kUndefined},
{"vecK", Builtin::kUndefined}, {"vecK", Builtin::kUndefined},
{"f11r4PP", Builtin::kUndefined}, {"f11r3PP", Builtin::kUndefined},
{"ve4h", Builtin::kUndefined}, {"ve3h", Builtin::kUndefined},
{"vec4YY", Builtin::kUndefined}, {"vec3YY", Builtin::kUndefined},
{"vkktHH", Builtin::kUndefined}, {"vkktHH", Builtin::kUndefined},
{"rrec4i", Builtin::kUndefined}, {"rrec3i", Builtin::kUndefined},
{"vWWssi", Builtin::kUndefined}, {"vWWssi", Builtin::kUndefined},
{"veYu", Builtin::kUndefined}, {"veYu", Builtin::kUndefined},
{"eq4f", Builtin::kUndefined}, {"eq3f", Builtin::kUndefined},
{"u22ec4u", Builtin::kUndefined}, {"u22ec3u", Builtin::kUndefined},
{"c4f", Builtin::kUndefined},
{"vec4", Builtin::kUndefined},
{"vYyc47E", Builtin::kUndefined},
{"veMoh", Builtin::kUndefined},
{"ve4MM", Builtin::kUndefined},
{"55ec4h", Builtin::kUndefined},
{"N4i", Builtin::kUndefined},
{"ve33i", Builtin::kUndefined},
{"3ec4i", Builtin::kUndefined},
{"mecI", Builtin::kUndefined},
{"vrnK4u", Builtin::kUndefined},
{"v4", Builtin::kUndefined},
}; };
using BuiltinParseTest = testing::TestWithParam<Case>; using BuiltinParseTest = testing::TestWithParam<Case>;

View File

@ -32,7 +32,6 @@
#include "src/tint/ast/pointer.h" #include "src/tint/ast/pointer.h"
#include "src/tint/ast/sampled_texture.h" #include "src/tint/ast/sampled_texture.h"
#include "src/tint/ast/stage_attribute.h" #include "src/tint/ast/stage_attribute.h"
#include "src/tint/ast/storage_texture.h"
#include "src/tint/ast/stride_attribute.h" #include "src/tint/ast/stride_attribute.h"
#include "src/tint/ast/struct_member_align_attribute.h" #include "src/tint/ast/struct_member_align_attribute.h"
#include "src/tint/ast/struct_member_offset_attribute.h" #include "src/tint/ast/struct_member_offset_attribute.h"
@ -290,7 +289,23 @@ bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression*
} }
bool GeneratorImpl::EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr) { bool GeneratorImpl::EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr) {
out << program_->Symbols().NameFor(expr->identifier->symbol); return EmitIdentifier(out, expr->identifier);
}
bool GeneratorImpl::EmitIdentifier(std::ostream& out, const ast::Identifier* ident) {
out << program_->Symbols().NameFor(ident->symbol);
if (auto* tmpl_ident = ident->As<ast::TemplatedIdentifier>()) {
out << "<";
TINT_DEFER(out << ">");
for (auto* expr : tmpl_ident->arguments) {
if (expr != tmpl_ident->arguments.Front()) {
out << ", ";
}
if (!EmitExpression(out, expr)) {
return false;
}
}
}
return true; return true;
} }
@ -462,10 +477,6 @@ bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) {
out << "multisampled_"; out << "multisampled_";
return true; return true;
}, },
[&](const ast::StorageTexture*) { //
out << "storage_";
return true;
},
[&](Default) { // [&](Default) { //
diagnostics_.add_error(diag::System::Writer, "unknown texture type"); diagnostics_.add_error(diag::System::Writer, "unknown texture type");
return false; return false;
@ -516,18 +527,6 @@ bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) {
out << ">"; out << ">";
return true; return true;
}, },
[&](const ast::StorageTexture* storage) { //
out << "<";
if (!EmitImageFormat(out, storage->format)) {
return false;
}
out << ", ";
if (!EmitAccess(out, storage->access)) {
return false;
}
out << ">";
return true;
},
[&](Default) { // [&](Default) { //
return true; return true;
}); });
@ -543,10 +542,7 @@ bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) {
} }
return true; return true;
}, },
[&](const ast::TypeName* tn) { [&](const ast::TypeName* tn) { return EmitIdentifier(out, tn->name); },
out << program_->Symbols().NameFor(tn->name->symbol);
return true;
},
[&](Default) { [&](Default) {
diagnostics_.add_error(diag::System::Writer, diagnostics_.add_error(diag::System::Writer,
"unknown type in EmitType: " + std::string(ty->TypeInfo().name)); "unknown type in EmitType: " + std::string(ty->TypeInfo().name));

View File

@ -142,6 +142,11 @@ class GeneratorImpl : public TextGenerator {
/// @param expr the identifier expression /// @param expr the identifier expression
/// @returns true if the identifier was emitted /// @returns true if the identifier was emitted
bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr); bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr);
/// Handles generating an identifier
/// @param out the output of the expression stream
/// @param ident the identifier
/// @returns true if the identifier was emitted
bool EmitIdentifier(std::ostream& out, const ast::Identifier* ident);
/// Handles an if statement /// Handles an if statement
/// @param stmt the statement to emit /// @param stmt the statement to emit
/// @returns true if the statement was successfully emitted /// @returns true if the statement was successfully emitted