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

View File

@ -201,8 +201,6 @@ list(APPEND TINT_LIB_SRCS
ast/stage_attribute.h
ast/statement.cc
ast/statement.h
ast/storage_texture.cc
ast/storage_texture.h
ast/stride_attribute.cc
ast/stride_attribute.h
ast/struct_member_align_attribute.cc
@ -856,7 +854,6 @@ if(TINT_BUILD_TESTS)
ast/return_statement_test.cc
ast/sampled_texture_test.cc
ast/stage_attribute_test.cc
ast/storage_texture_test.cc
ast/stride_attribute_test.cc
ast/struct_member_align_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/pointer.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/test_helper.h"
#include "src/tint/ast/texture.h"
@ -35,7 +34,6 @@ TEST_F(AstMultisampledTextureTest, IsTexture) {
Texture* t = create<MultisampledTexture>(type::TextureDimension::kCube, ty.f32());
EXPECT_TRUE(t->Is<MultisampledTexture>());
EXPECT_FALSE(t->Is<SampledTexture>());
EXPECT_FALSE(t->Is<StorageTexture>());
}
TEST_F(AstMultisampledTextureTest, Dim) {

View File

@ -24,7 +24,6 @@ using AstSampledTextureTest = TestHelper;
TEST_F(AstSampledTextureTest, IsTexture) {
Texture* t = create<SampledTexture>(type::TextureDimension::kCube, ty.f32());
EXPECT_TRUE(t->Is<SampledTexture>());
EXPECT_FALSE(t->Is<StorageTexture>());
}
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 "src/tint/ast/storage_texture.h"
#include "src/tint/type/texel_format.h"
#include "src/tint/type/texture_dimension.h"
#include "src/tint/type/type.h"

View File

@ -176,6 +176,11 @@ enum builtin_type {
texture_depth_cube
texture_depth_cube_array
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
texture_external
}

View File

@ -68,7 +68,6 @@
#include "src/tint/ast/return_statement.h"
#include "src/tint/ast/sampled_texture.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/struct_member_align_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 format the texel format of the texture
/// @param access the access control of the texture
/// @returns the storage texture
const ast::StorageTexture* storage_texture(type::TextureDimension dims,
type::TexelFormat format,
type::Access access) const {
auto* subtype = ast::StorageTexture::SubtypeFor(format, *builder);
return builder->create<ast::StorageTexture>(dims, format, subtype, access);
/// @returns the storage texture typename
const ast::TypeName* storage_texture(type::TextureDimension dims,
type::TexelFormat format,
type::Access access) const {
return storage_texture(builder->source_, dims, format, access);
}
/// @param source the Source of the node
/// @param dims the dimensionality of the texture
/// @param format the texel format of the texture
/// @param access the access control of the texture
/// @returns the storage texture
const ast::StorageTexture* storage_texture(const Source& source,
type::TextureDimension dims,
type::TexelFormat format,
type::Access access) const {
auto* subtype = ast::StorageTexture::SubtypeFor(format, *builder);
return builder->create<ast::StorageTexture>(source, dims, format, subtype, access);
/// @returns the storage texture typename
const ast::TypeName* storage_texture(const Source& source,
type::TextureDimension dims,
type::TexelFormat format,
type::Access access) const {
switch (dims) {
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

View File

@ -19,11 +19,12 @@
#include <string>
#include <vector>
#include "src/tint/ast/storage_texture.h"
#include "src/tint/castable.h"
#include "src/tint/symbol.h"
#include "src/tint/type/access.h"
#include "src/tint/type/address_space.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/utils/block_allocator.h"

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/tint/ast/test_helper.h"
#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
#include "src/tint/type/depth_texture.h"
#include "src/tint/type/multisampled_texture.h"
@ -195,11 +196,8 @@ TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Readonly1dRg32Float) {
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t->Is<ast::Texture>());
ASSERT_TRUE(t->Is<ast::StorageTexture>());
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);
ast::CheckIdentifier(p->builder().Symbols(), t->As<ast::TypeName>()->name,
ast::Template("texture_storage_1d", "rg32float", "read"));
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);
ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t->Is<ast::Texture>());
ASSERT_TRUE(t->Is<ast::StorageTexture>());
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);
ast::CheckIdentifier(p->builder().Symbols(), t->As<ast::TypeName>()->name,
ast::Template("texture_storage_2d", "r32uint", "write"));
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/sampled_texture.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/struct.h"
#include "src/tint/ast/struct_member_align_attribute.h"
@ -338,31 +337,44 @@ class DependencyScanner {
}
}
/// Traverses the expression, performing symbol resolution and determining
/// global dependencies.
/// Traverses the expression, performing symbol resolution and determining global dependencies.
void TraverseExpression(const ast::Expression* root) {
if (!root) {
return;
}
ast::TraverseExpressions(root, diagnostics_, [&](const ast::Expression* expr) {
Switch(
expr,
[&](const ast::IdentifierExpression* ident) {
AddDependency(ident->identifier, ident->identifier->symbol, "identifier",
"references");
},
[&](const ast::CallExpression* call) {
if (call->target.name) {
AddDependency(call->target.name, call->target.name->symbol, "function",
"calls");
}
if (call->target.type) {
TraverseType(call->target.type);
}
},
[&](const ast::BitcastExpression* cast) { TraverseType(cast->type); });
return ast::TraverseAction::Descend;
});
utils::Vector<const ast::Expression*, 8> pending{root};
while (!pending.IsEmpty()) {
ast::TraverseExpressions(pending.Pop(), diagnostics_, [&](const ast::Expression* expr) {
Switch(
expr,
[&](const ast::IdentifierExpression* e) {
AddDependency(e->identifier, e->identifier->symbol, "identifier",
"references");
if (auto* tmpl_ident = e->identifier->As<ast::TemplatedIdentifier>()) {
for (auto* arg : tmpl_ident->arguments) {
pending.Push(arg);
}
}
},
[&](const ast::CallExpression* call) {
if (call->target.name) {
AddDependency(call->target.name, call->target.name->symbol, "function",
"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
@ -388,6 +400,11 @@ class DependencyScanner {
},
[&](const ast::TypeName* tn) { //
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) { //
TraverseType(vec->type);
@ -398,9 +415,6 @@ class DependencyScanner {
[&](const ast::MultisampledTexture* tex) { //
TraverseType(tex->type);
},
[&](const ast::StorageTexture* tex) { //
TraverseType(tex->type);
},
[&](Default) { UnhandledNode(diagnostics_, ty); });
}

View File

@ -121,7 +121,7 @@ TEST_P(ResolverExpressionKindTest, Test) {
Symbol sym;
switch (GetParam().def) {
case Def::kAccess:
sym = Sym("read_write");
sym = Sym("write");
break;
case Def::kAddressSpace:
sym = Sym("workgroup");
@ -155,7 +155,8 @@ TEST_P(ResolverExpressionKindTest, Test) {
switch (GetParam().use) {
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:
return; // TODO(crbug.com/tint/1810)
case Use::kCallExpr:
@ -174,7 +175,8 @@ TEST_P(ResolverExpressionKindTest, Test) {
Structure("s", utils::Vector{Member("m", ty(kUseSource, sym))});
break;
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:
GlobalVar("v", type::AddressSpace::kPrivate, Expr(kUseSource, sym));
break;
@ -201,21 +203,18 @@ INSTANTIATE_TEST_SUITE_P(
testing::ValuesIn(std::vector<Case>{
{Def::kAccess, Use::kAccess, kPass},
{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::kCallExpr,
R"(5:6 error: cannot use access 'read_write' as call target)"},
{Def::kAccess, Use::kCallStmt,
R"(5:6 error: cannot use access 'read_write' as call target)"},
{Def::kAccess, Use::kFunctionReturnType,
R"(5:6 error: cannot use access 'read_write' as type)"},
{Def::kAccess, Use::kMemberType, R"(5:6 error: cannot use access 'read_write' as type)"},
{Def::kAccess, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"},
{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::kAccess, Use::kBinaryOp, R"(5:6 error: cannot use access 'write' as value)"},
{Def::kAccess, Use::kCallExpr, R"(5:6 error: cannot use access 'write' as call target)"},
{Def::kAccess, Use::kCallStmt, R"(5:6 error: cannot use access 'write' as call target)"},
{Def::kAccess, Use::kFunctionReturnType, R"(5:6 error: cannot use access 'write' as type)"},
{Def::kAccess, Use::kMemberType, R"(5:6 error: cannot use access 'write' as type)"},
{Def::kAccess, Use::kTexelFormat, R"(error: cannot use access 'write' as texel format)"},
{Def::kAccess, Use::kValueExpression, R"(5:6 error: cannot use access 'write' as value)"},
{Def::kAccess, Use::kVariableType, R"(5:6 error: cannot use access 'write' as type)"},
{Def::kAccess, Use::kUnaryOp, R"(5:6 error: cannot use access '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::kBinaryOp,
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)"},
{Def::kAddressSpace, Use::kMemberType,
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,
R"(5:6 error: cannot use address space 'workgroup' as value)"},
{Def::kAddressSpace, Use::kVariableType,
@ -235,7 +235,7 @@ INSTANTIATE_TEST_SUITE_P(
{Def::kAddressSpace, Use::kUnaryOp,
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::kBinaryOp,
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)"},
{Def::kBuiltinFunction, Use::kMemberType,
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,
R"(7:8 error: missing '(' for builtin function call)"},
{Def::kBuiltinFunction, Use::kVariableType,
@ -252,7 +253,7 @@ INSTANTIATE_TEST_SUITE_P(
{Def::kBuiltinFunction, Use::kUnaryOp,
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::kBinaryOp,
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::kFunctionReturnType, 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,
R"(5:6 error: cannot use type 'vec4<f32>' as value
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
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::kBinaryOp, R"(7:8 error: missing '(' for function call)"},
{Def::kFunction, Use::kCallExpr, kPass},
{Def::kFunction, Use::kCallStmt, kPass},
{Def::kFunction, Use::kFunctionReturnType,
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,
R"(5:6 error: cannot use function 'FUNCTION' as type
1:2 note: 'FUNCTION' declared here)"},
{Def::kFunction, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"},
1:2 note: function 'FUNCTION' declared here)"},
{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::kVariableType,
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::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::kBinaryOp, R"(5:6 error: cannot use type 'STRUCT' as value
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::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,
R"(5:6 error: cannot use type 'STRUCT' as value
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::kUnaryOp,
R"(5:6 error: cannot use type 'STRUCT' as value
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::kBinaryOp,
R"(5:6 error: cannot use texel format 'rgba8unorm' as value)"},
@ -325,7 +328,7 @@ INSTANTIATE_TEST_SUITE_P(
{Def::kTexelFormat, Use::kUnaryOp,
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::kBinaryOp,
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::kFunctionReturnType, 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,
R"(5:6 error: cannot use type 'i32' as value
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
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::kBinaryOp, kPass},
{Def::kVariable, Use::kCallStmt,
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,
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,
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,
R"(5:6 error: cannot use const 'VARIABLE' as type
1:2 note: 'VARIABLE' declared here)"},
{Def::kVariable, Use::kTexelFormat, R"(TODO(crbug.com/tint/1810))"},
1:2 note: const 'VARIABLE' declared here)"},
{Def::kVariable, Use::kTexelFormat,
R"(error: cannot use 'VARIABLE' of type 'i32' as texel format)"},
{Def::kVariable, Use::kValueExpression, kPass},
{Def::kVariable, Use::kVariableType,
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},
}));

View File

@ -40,7 +40,6 @@
#include "src/tint/ast/pointer.h"
#include "src/tint/ast/return_statement.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/traverse_expressions.h"
#include "src/tint/ast/type_name.h"
@ -308,22 +307,9 @@ type::Type* Resolver::Type(const ast::Type* ty) {
}
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* {
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);
if (!resolved) {
TINT_ICE(Resolver, diagnostics_)
@ -338,6 +324,15 @@ type::Type* Resolver::Type(const ast::Type* ty) {
ErrorMismatchedResolvedIdentifier(t->source, *resolved, "type");
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;
}
if (auto b = resolved->BuiltinType(); b != type::Builtin::kUndefined) {
@ -2431,9 +2426,18 @@ sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
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 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 i32 = [&] { return b.create<type::I32>(); };
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) {
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) {
case type::Builtin::kBool:
return b.create<type::Bool>();
return check_no_tmpl_args(b.create<type::Bool>());
case type::Builtin::kI32:
return i32();
return check_no_tmpl_args(i32());
case type::Builtin::kU32:
return u32();
return check_no_tmpl_args(u32());
case type::Builtin::kF16:
return f16();
return check_no_tmpl_args(f16());
case type::Builtin::kF32:
return b.create<type::F32>();
return check_no_tmpl_args(b.create<type::F32>());
case type::Builtin::kMat2X2F:
return mat(f32(), 2u, 2u);
return check_no_tmpl_args(mat(f32(), 2u, 2u));
case type::Builtin::kMat2X3F:
return mat(f32(), 2u, 3u);
return check_no_tmpl_args(mat(f32(), 2u, 3u));
case type::Builtin::kMat2X4F:
return mat(f32(), 2u, 4u);
return check_no_tmpl_args(mat(f32(), 2u, 4u));
case type::Builtin::kMat3X2F:
return mat(f32(), 3u, 2u);
return check_no_tmpl_args(mat(f32(), 3u, 2u));
case type::Builtin::kMat3X3F:
return mat(f32(), 3u, 3u);
return check_no_tmpl_args(mat(f32(), 3u, 3u));
case type::Builtin::kMat3X4F:
return mat(f32(), 3u, 4u);
return check_no_tmpl_args(mat(f32(), 3u, 4u));
case type::Builtin::kMat4X2F:
return mat(f32(), 4u, 2u);
return check_no_tmpl_args(mat(f32(), 4u, 2u));
case type::Builtin::kMat4X3F:
return mat(f32(), 4u, 3u);
return check_no_tmpl_args(mat(f32(), 4u, 3u));
case type::Builtin::kMat4X4F:
return mat(f32(), 4u, 4u);
return check_no_tmpl_args(mat(f32(), 4u, 4u));
case type::Builtin::kMat2X2H:
return mat(f16(), 2u, 2u);
return check_no_tmpl_args(mat(f16(), 2u, 2u));
case type::Builtin::kMat2X3H:
return mat(f16(), 2u, 3u);
return check_no_tmpl_args(mat(f16(), 2u, 3u));
case type::Builtin::kMat2X4H:
return mat(f16(), 2u, 4u);
return check_no_tmpl_args(mat(f16(), 2u, 4u));
case type::Builtin::kMat3X2H:
return mat(f16(), 3u, 2u);
return check_no_tmpl_args(mat(f16(), 3u, 2u));
case type::Builtin::kMat3X3H:
return mat(f16(), 3u, 3u);
return check_no_tmpl_args(mat(f16(), 3u, 3u));
case type::Builtin::kMat3X4H:
return mat(f16(), 3u, 4u);
return check_no_tmpl_args(mat(f16(), 3u, 4u));
case type::Builtin::kMat4X2H:
return mat(f16(), 4u, 2u);
return check_no_tmpl_args(mat(f16(), 4u, 2u));
case type::Builtin::kMat4X3H:
return mat(f16(), 4u, 3u);
return check_no_tmpl_args(mat(f16(), 4u, 3u));
case type::Builtin::kMat4X4H:
return mat(f16(), 4u, 4u);
return check_no_tmpl_args(mat(f16(), 4u, 4u));
case type::Builtin::kVec2F:
return vec(f32(), 2u);
return check_no_tmpl_args(vec(f32(), 2u));
case type::Builtin::kVec3F:
return vec(f32(), 3u);
return check_no_tmpl_args(vec(f32(), 3u));
case type::Builtin::kVec4F:
return vec(f32(), 4u);
return check_no_tmpl_args(vec(f32(), 4u));
case type::Builtin::kVec2H:
return vec(f16(), 2u);
return check_no_tmpl_args(vec(f16(), 2u));
case type::Builtin::kVec3H:
return vec(f16(), 3u);
return check_no_tmpl_args(vec(f16(), 3u));
case type::Builtin::kVec4H:
return vec(f16(), 4u);
return check_no_tmpl_args(vec(f16(), 4u));
case type::Builtin::kVec2I:
return vec(i32(), 2u);
return check_no_tmpl_args(vec(i32(), 2u));
case type::Builtin::kVec3I:
return vec(i32(), 3u);
return check_no_tmpl_args(vec(i32(), 3u));
case type::Builtin::kVec4I:
return vec(i32(), 4u);
return check_no_tmpl_args(vec(i32(), 4u));
case type::Builtin::kVec2U:
return vec(u32(), 2u);
return check_no_tmpl_args(vec(u32(), 2u));
case type::Builtin::kVec3U:
return vec(u32(), 3u);
return check_no_tmpl_args(vec(u32(), 3u));
case type::Builtin::kVec4U:
return vec(u32(), 4u);
return check_no_tmpl_args(vec(u32(), 4u));
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:
return builder_->create<type::Sampler>(type::SamplerKind::kComparisonSampler);
return check_no_tmpl_args(
builder_->create<type::Sampler>(type::SamplerKind::kComparisonSampler));
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:
return builder_->create<type::DepthTexture>(type::TextureDimension::k2dArray);
return check_no_tmpl_args(
builder_->create<type::DepthTexture>(type::TextureDimension::k2dArray));
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:
return builder_->create<type::DepthTexture>(type::TextureDimension::kCubeArray);
return check_no_tmpl_args(
builder_->create<type::DepthTexture>(type::TextureDimension::kCubeArray));
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:
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:
break;
}
@ -4021,19 +4074,43 @@ void Resolver::ErrorMismatchedResolvedIdentifier(const Source& source,
AddError("cannot use " + resolved.String(builder_->Symbols(), diagnostics_) + " as " +
std::string(wanted),
source);
NoteDeclarationSource(resolved.Node());
}
void Resolver::NoteDeclarationSource(const ast::Node* node) {
Switch(
resolved.Node(),
[&](const ast::TypeDecl* n) {
AddNote("'" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here",
node,
[&](const ast::Struct* n) {
AddNote("struct '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here",
n->source);
},
[&](const ast::Variable* n) {
AddNote("'" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here",
[&](const ast::Alias* n) {
AddNote("alias '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here",
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) {
AddNote("'" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here",
AddNote("function '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here",
n->source);
});
}

View File

@ -432,6 +432,11 @@ class Resolver {
const ResolvedIdentifier& resolved,
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
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
/// @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.
// 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;
}
void SemHelper::ErrorExpectedValueExpr(const sem::Expression* expr) const {
void SemHelper::ErrorUnexpectedExprKind(const sem::Expression* expr,
std::string_view wanted) const {
Switch(
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) {
auto name = ty_expr->Type()->FriendlyName(builder_->Symbols());
AddError("cannot use type '" + name + "' as value", ty_expr->Declaration()->source);
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("'" + name + "' declared here", str->Source());
}
AddError("cannot use type '" + name + "' as " + std::string(wanted),
ty_expr->Declaration()->source);
},
[&](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);
},
[&](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);
},
[&](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);
},
[&](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 {
builder_->Diagnostics().add_error(diag::System::Resolver, msg, source);
}

View File

@ -20,6 +20,7 @@
#include "src/tint/diagnostic/diagnostic.h"
#include "src/tint/program_builder.h"
#include "src/tint/resolver/dependency_graph.h"
#include "src/tint/sem/builtin_enum_expression.h"
#include "src/tint/utils/map.h"
namespace tint::resolver {
@ -61,25 +62,46 @@ class SemHelper {
}
/// @param expr the semantic node
/// @returns one of:
/// * nullptr if @p expr is nullptr
/// * @p expr if the static pointer type already derives from sem::ValueExpression
/// * @p expr cast to sem::ValueExpression if the cast is successful
/// * nullptr if @p expr is not a sem::ValueExpression. In this case an error diagnostic is
/// raised.
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);
/// @returns nullptr if @p expr is nullptr, or @p expr cast to sem::ValueExpression if the cast
/// is successful, otherwise an error diagnostic is raised.
sem::ValueExpression* AsValue(sem::Expression* expr) const {
if (TINT_LIKELY(expr)) {
if (auto* val = expr->As<sem::ValueExpression>(); TINT_LIKELY(val)) {
return val;
}
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
@ -100,6 +122,10 @@ class SemHelper {
void ErrorExpectedValueExpr(const sem::Expression* expr) const;
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
void AddError(const std::string& msg, const Source& source) const;

View File

@ -1064,26 +1064,26 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
namespace StorageTextureTests {
struct DimensionParams {
type::TextureDimension dim;
const char* name;
bool is_valid;
};
static constexpr DimensionParams Dimension_cases[] = {
DimensionParams{type::TextureDimension::k1d, true},
DimensionParams{type::TextureDimension::k2d, true},
DimensionParams{type::TextureDimension::k2dArray, true},
DimensionParams{type::TextureDimension::k3d, true},
DimensionParams{type::TextureDimension::kCube, false},
DimensionParams{type::TextureDimension::kCubeArray, false}};
DimensionParams{"texture_storage_1d", true},
DimensionParams{"texture_storage_2d", true},
DimensionParams{"texture_storage_2d_array", true},
DimensionParams{"texture_storage_3d", true},
DimensionParams{"texture_storage_cube", false},
DimensionParams{"texture_storage_cube_array", false}};
using StorageTextureDimensionTest = ResolverTestWithParam<DimensionParams>;
TEST_P(StorageTextureDimensionTest, All) {
// @group(0) @binding(0)
// var a : texture_storage_*<ru32int, write>;
// var a : texture_storage_*<r32uint, write>;
auto& params = GetParam();
auto* st = ty.storage_texture(Source{{12, 34}}, params.dim, type::TexelFormat::kR32Uint,
type::Access::kWrite);
auto* st = ty(Source{{12, 34}}, params.name, utils::ToString(type::TexelFormat::kR32Uint),
utils::ToString(type::Access::kWrite));
GlobalVar("a", st, Group(0_a), Binding(0_a));
@ -1091,8 +1091,7 @@ TEST_P(StorageTextureDimensionTest, All) {
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: cube dimensions for storage textures are not supported");
EXPECT_EQ(r()->error(), "12:34 error: unknown type: '" + std::string(params.name) + "'");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
@ -1165,22 +1164,33 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
using StorageTextureAccessTest = ResolverTest;
TEST_F(StorageTextureAccessTest, MissingAccess_Fail) {
TEST_F(StorageTextureAccessTest, MissingTemplates) {
// @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,
type::TexelFormat::kR32Uint, type::Access::kUndefined);
auto* st = ty(Source{{12, 34}}, "texture_storage_1d");
GlobalVar("a", st, Group(0_a), Binding(0_a));
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) {
// @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,
type::TexelFormat::kR32Uint, type::Access::kReadWrite);
@ -1194,7 +1204,7 @@ TEST_F(StorageTextureAccessTest, RWAccess_Fail) {
TEST_F(StorageTextureAccessTest, ReadOnlyAccess_Fail) {
// @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,
type::TexelFormat::kR32Uint, type::Access::kRead);
@ -1208,7 +1218,7 @@ TEST_F(StorageTextureAccessTest, ReadOnlyAccess_Fail) {
TEST_F(StorageTextureAccessTest, WriteOnlyAccess_Pass) {
// @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,
type::Access::kWrite);
@ -1445,5 +1455,91 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
} // 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 tint::resolver

View File

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

View File

@ -372,8 +372,9 @@ class Validator {
/// Validates a storage texture
/// @param t the texture to validate
/// @param source the source of the texture
/// @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
/// @param t the texture to validate

View File

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

View File

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

View File

@ -118,6 +118,18 @@ Builtin ParseBuiltin(std::string_view str) {
if (str == "texture_external") {
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") {
return Builtin::kU32;
}
@ -224,6 +236,14 @@ std::ostream& operator<<(std::ostream& out, Builtin value) {
return out << "texture_depth_multisampled_2d";
case Builtin::kTextureExternal:
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:
return out << "u32";
case Builtin::kVec2F:

View File

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

View File

@ -241,97 +241,125 @@ void BuiltinParser(::benchmark::State& state) {
"textuXe_ZZxtJJrnal",
"textuPPe_eternal",
"texturc_external",
"ull62",
"93yy",
"u3KK",
"tllxture_storage_P6d",
"tex99ure_yytorag_1d",
"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",
"x_",
"K",
"kVz",
"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",
"3Xl",
"pp3o",
"uww",
"veuug",
"vaac",
"TRZcccf",
"vec3f",
"vTc3O8",
"vem03f",
"meBB3f",
"Mpp3",
"OOe3h",
"veG3G",
"vec3h",
"11eHH3h",
"vec2f",
"vTc2O8",
"vem02f",
"meBB2f",
"Mpp2",
"OOe2h",
"veG2G",
"vec2h",
"11eHH2h",
"veFFe6",
"ve3",
"vKii3l",
"ec3i",
"v993IIv",
"vec3i",
"ve2",
"vKii2l",
"ec2i",
"v992IIv",
"vec2i",
"veci",
"vechi",
"vczllPi",
"u",
"vffqq3",
"vJdd3u",
"vec3u",
"vffqq2",
"vJdd2u",
"vec2u",
"vecXX",
"ve32",
"Nyyc3u",
"vO4",
"ve22",
"Nyyc2u",
"vO3",
"PEruZ",
"vlc2edd",
"vec4f",
"vec3f",
"ec9f",
"ve1II",
"veb4f",
"veb3f",
"vi7",
"oec4ii",
"ec4",
"vec4h",
"oec3ii",
"ec3",
"vec3h",
"veci",
"22ec",
"vGc4C",
"ffec48",
"c4i",
"vGc3C",
"ffec38",
"c3i",
"JJecSSi",
"vec4i",
"94i",
"vbbJJ4TT",
"vec3i",
"93i",
"vbbJJ3TT",
"e66i",
"u664u",
"vW4u",
"v4u",
"vec4u",
"u663u",
"vW3u",
"v3u",
"vec3u",
"vecu",
"rec4u",
"2ec4B",
"rec3u",
"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* str : kStrings) {

View File

@ -73,6 +73,10 @@ static constexpr Case kValidCases[] = {
{"texture_depth_cube_array", Builtin::kTextureDepthCubeArray},
{"texture_depth_multisampled_2d", Builtin::kTextureDepthMultisampled2D},
{"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},
{"vec2f", Builtin::kVec2F},
{"vec2h", Builtin::kVec2H},
@ -179,45 +183,57 @@ static constexpr Case kInvalidCases[] = {
{"texture_exernss77", Builtin::kUndefined},
{"texture_bbxternRRl", Builtin::kUndefined},
{"textureXXexternal", Builtin::kUndefined},
{"qOOO2", Builtin::kUndefined},
{"us", Builtin::kUndefined},
{"u3X", Builtin::kUndefined},
{"ve2f", Builtin::kUndefined},
{"qq2", Builtin::kUndefined},
{"vec222", Builtin::kUndefined},
{"vezzXy", Builtin::kUndefined},
{"ieVVP", Builtin::kUndefined},
{"venCh", Builtin::kUndefined},
{"vHc2Aq", Builtin::kUndefined},
{"ve2i", Builtin::kUndefined},
{"vefK", Builtin::kUndefined},
{"vgg2", Builtin::kUndefined},
{"vecu", Builtin::kUndefined},
{"4TNc2u", Builtin::kUndefined},
{"CCextOOre_stoage_qOd", Builtin::kUndefined},
{"txtsre_sturage_1L", Builtin::kUndefined},
{"texture_stoXage_1d", Builtin::kUndefined},
{"textue_storage_2d", Builtin::kUndefined},
{"teuresOorageqq2d", Builtin::kUndefined},
{"texture_sto22age_2d", Builtin::kUndefined},
{"exture_syora0e_2d_Xzzrray", Builtin::kUndefined},
{"texiVVr_storageP2d_array", Builtin::kUndefined},
{"texturestorage_2nn_arCay", Builtin::kUndefined},
{"texturHHstorAAe_qqd", Builtin::kUndefined},
{"textur_storage_3d", Builtin::kUndefined},
{"texure_sfKorage3d", Builtin::kUndefined},
{"gg", Builtin::kUndefined},
{"u3", Builtin::kUndefined},
{"NT42", Builtin::kUndefined},
{"ppec7l", Builtin::kUndefined},
{"zNe3f", Builtin::kUndefined},
{"uXXb3f", Builtin::kUndefined},
{"vec3", Builtin::kUndefined},
{"883K", Builtin::kUndefined},
{"zNe2f", Builtin::kUndefined},
{"uXXb2f", Builtin::kUndefined},
{"vec2", Builtin::kUndefined},
{"882K", Builtin::kUndefined},
{"vq9h", Builtin::kUndefined},
{"vec311", Builtin::kUndefined},
{"vec211", Builtin::kUndefined},
{"22ciii", Builtin::kUndefined},
{"ec77i", Builtin::kUndefined},
{"NN23u", Builtin::kUndefined},
{"vVVc3u", Builtin::kUndefined},
{"WW11w3u", Builtin::kUndefined},
{"NN22u", Builtin::kUndefined},
{"vVVc2u", Builtin::kUndefined},
{"WW11w2u", Builtin::kUndefined},
{"vcwwf", Builtin::kUndefined},
{"vDc4f", Builtin::kUndefined},
{"vDc3f", Builtin::kUndefined},
{"vecK", Builtin::kUndefined},
{"f11r4PP", Builtin::kUndefined},
{"ve4h", Builtin::kUndefined},
{"vec4YY", Builtin::kUndefined},
{"f11r3PP", Builtin::kUndefined},
{"ve3h", Builtin::kUndefined},
{"vec3YY", Builtin::kUndefined},
{"vkktHH", Builtin::kUndefined},
{"rrec4i", Builtin::kUndefined},
{"rrec3i", Builtin::kUndefined},
{"vWWssi", Builtin::kUndefined},
{"veYu", Builtin::kUndefined},
{"eq4f", Builtin::kUndefined},
{"u22ec4u", Builtin::kUndefined},
{"eq3f", 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>;

View File

@ -32,7 +32,6 @@
#include "src/tint/ast/pointer.h"
#include "src/tint/ast/sampled_texture.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/struct_member_align_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) {
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;
}
@ -462,10 +477,6 @@ bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) {
out << "multisampled_";
return true;
},
[&](const ast::StorageTexture*) { //
out << "storage_";
return true;
},
[&](Default) { //
diagnostics_.add_error(diag::System::Writer, "unknown texture type");
return false;
@ -516,18 +527,6 @@ bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) {
out << ">";
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) { //
return true;
});
@ -543,10 +542,7 @@ bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) {
}
return true;
},
[&](const ast::TypeName* tn) {
out << program_->Symbols().NameFor(tn->name->symbol);
return true;
},
[&](const ast::TypeName* tn) { return EmitIdentifier(out, tn->name); },
[&](Default) {
diagnostics_.add_error(diag::System::Writer,
"unknown type in EmitType: " + std::string(ty->TypeInfo().name));

View File

@ -142,6 +142,11 @@ class GeneratorImpl : public TextGenerator {
/// @param expr the identifier expression
/// @returns true if the identifier was emitted
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
/// @param stmt the statement to emit
/// @returns true if the statement was successfully emitted