From 2cdf134b2b74119f1527755f20522c12cd8dea22 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Fri, 3 Feb 2023 13:24:18 +0000 Subject: [PATCH] tint: Add ast::TemplatedIdentifier Will be used to replace all type identifiers that take templated arguments. Bug: tint:1810 Change-Id: I31ad8dc4826375a783143cc33f336d8a4860613c Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/117893 Reviewed-by: Dan Sinclair Commit-Queue: Ben Clayton Reviewed-by: James Price Kokoro: Ben Clayton Kokoro: Kokoro --- src/tint/BUILD.gn | 4 + src/tint/CMakeLists.txt | 3 + src/tint/ast/diagnostic_control.cc | 13 ++ src/tint/ast/diagnostic_control.cc.tmpl | 13 ++ src/tint/ast/diagnostic_control.h | 3 +- src/tint/ast/diagnostic_control.h.tmpl | 3 +- src/tint/ast/diagnostic_control_test.cc | 11 ++ src/tint/ast/diagnostic_control_test.cc.tmpl | 14 +- src/tint/ast/identifier.h | 2 +- src/tint/ast/identifier_expression.cc | 4 + src/tint/ast/identifier_expression_test.cc | 9 ++ src/tint/ast/member_accessor_expression.cc | 5 + .../ast/member_accessor_expression_test.cc | 10 ++ src/tint/ast/templated_identifier.cc | 48 +++++++ src/tint/ast/templated_identifier.h | 56 ++++++++ src/tint/ast/templated_identifier_test.cc | 80 +++++++++++ src/tint/ast/type_name_test.cc | 11 ++ src/tint/program_builder.h | 124 +++++++++++------- src/tint/resolver/dependency_graph.cc | 1 + src/tint/resolver/resolver.cc | 4 + src/tint/traits.h | 11 ++ src/tint/traits_test.cc | 19 +++ 22 files changed, 391 insertions(+), 57 deletions(-) create mode 100644 src/tint/ast/templated_identifier.cc create mode 100644 src/tint/ast/templated_identifier.h create mode 100644 src/tint/ast/templated_identifier_test.cc diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn index f7e4854116..481c2671be 100644 --- a/src/tint/BUILD.gn +++ b/src/tint/BUILD.gn @@ -315,6 +315,7 @@ libtint_source_set("libtint_syntax_tree_src") { "ast/struct_member_offset_attribute.h", "ast/struct_member_size_attribute.h", "ast/switch_statement.h", + "ast/templated_identifier.h", "ast/texture.h", "ast/traverse_expressions.h", "ast/type.h", @@ -697,6 +698,8 @@ libtint_source_set("libtint_ast_src") { "ast/struct_member_size_attribute.h", "ast/switch_statement.cc", "ast/switch_statement.h", + "ast/templated_identifier.cc", + "ast/templated_identifier.h", "ast/texture.cc", "ast/texture.h", "ast/traverse_expressions.h", @@ -1358,6 +1361,7 @@ if (tint_build_unittests) { "ast/struct_member_test.cc", "ast/struct_test.cc", "ast/switch_statement_test.cc", + "ast/templated_identifier_test.cc", "ast/test_helper.h", "ast/texture_test.cc", "ast/traverse_expressions_test.cc", diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt index 2223d7d80b..bdb1bbf9f5 100644 --- a/src/tint/CMakeLists.txt +++ b/src/tint/CMakeLists.txt @@ -227,6 +227,8 @@ list(APPEND TINT_LIB_SRCS ast/struct.h ast/switch_statement.cc ast/switch_statement.h + ast/templated_identifier.cc + ast/templated_identifier.h ast/texture.cc ast/texture.h ast/traverse_expressions.h @@ -880,6 +882,7 @@ if(TINT_BUILD_TESTS) ast/struct_test.cc ast/switch_statement_test.cc ast/test_helper.h + ast/templated_identifier_test.cc ast/texture_test.cc ast/traverse_expressions_test.cc ast/type_name_test.cc diff --git a/src/tint/ast/diagnostic_control.cc b/src/tint/ast/diagnostic_control.cc index a814d5820c..6d6ed09f6a 100644 --- a/src/tint/ast/diagnostic_control.cc +++ b/src/tint/ast/diagnostic_control.cc @@ -30,6 +30,19 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::DiagnosticControl); namespace tint::ast { +DiagnosticControl::DiagnosticControl(ProgramID pid, + NodeID nid, + const Source& src, + DiagnosticSeverity sev, + const Identifier* rule) + : Base(pid, nid, src), severity(sev), rule_name(rule) { + TINT_ASSERT(AST, rule != nullptr); + if (rule) { + // It is invalid for a diagnostic rule name to be templated + TINT_ASSERT(AST, !rule->Is()); + } +} + DiagnosticControl::~DiagnosticControl() = default; const DiagnosticControl* DiagnosticControl::Clone(CloneContext* ctx) const { diff --git a/src/tint/ast/diagnostic_control.cc.tmpl b/src/tint/ast/diagnostic_control.cc.tmpl index c6dc463e78..c7ca2b84bc 100644 --- a/src/tint/ast/diagnostic_control.cc.tmpl +++ b/src/tint/ast/diagnostic_control.cc.tmpl @@ -20,6 +20,19 @@ TINT_INSTANTIATE_TYPEINFO(tint::ast::DiagnosticControl); namespace tint::ast { +DiagnosticControl::DiagnosticControl(ProgramID pid, + NodeID nid, + const Source& src, + DiagnosticSeverity sev, + const Identifier* rule) + : Base(pid, nid, src), severity(sev), rule_name(rule) { + TINT_ASSERT(AST, rule != nullptr); + if (rule) { + // It is invalid for a diagnostic rule name to be templated + TINT_ASSERT(AST, !rule->Is()); + } +} + DiagnosticControl::~DiagnosticControl() = default; const DiagnosticControl* DiagnosticControl::Clone(CloneContext* ctx) const { diff --git a/src/tint/ast/diagnostic_control.h b/src/tint/ast/diagnostic_control.h index d1df3298c7..6cf27b9d96 100644 --- a/src/tint/ast/diagnostic_control.h +++ b/src/tint/ast/diagnostic_control.h @@ -103,8 +103,7 @@ class DiagnosticControl : public Castable { NodeID nid, const Source& src, DiagnosticSeverity sev, - const Identifier* rule) - : Base(pid, nid, src), severity(sev), rule_name(rule) {} + const Identifier* rule); ~DiagnosticControl() override; diff --git a/src/tint/ast/diagnostic_control.h.tmpl b/src/tint/ast/diagnostic_control.h.tmpl index c106a3e6d3..9b8f1fee4d 100644 --- a/src/tint/ast/diagnostic_control.h.tmpl +++ b/src/tint/ast/diagnostic_control.h.tmpl @@ -51,8 +51,7 @@ class DiagnosticControl : public Castable { NodeID nid, const Source& src, DiagnosticSeverity sev, - const Identifier* rule) - : Base(pid, nid, src), severity(sev), rule_name(rule) {} + const Identifier* rule); ~DiagnosticControl() override; diff --git a/src/tint/ast/diagnostic_control_test.cc b/src/tint/ast/diagnostic_control_test.cc index 798d187ab5..742bee39da 100644 --- a/src/tint/ast/diagnostic_control_test.cc +++ b/src/tint/ast/diagnostic_control_test.cc @@ -22,6 +22,7 @@ #include +#include "gtest/gtest-spi.h" #include "src/tint/ast/diagnostic_control.h" #include "src/tint/ast/test_helper.h" @@ -44,6 +45,16 @@ TEST_F(DiagnosticControlTest, Creation) { EXPECT_EQ(control->rule_name, name); } +TEST_F(DiagnosticControlTest, Assert_RuleNotTemplated) { + EXPECT_FATAL_FAILURE( + { + ProgramBuilder b; + b.create(DiagnosticSeverity::kWarning, + b.Ident("name", "a", "b", "c")); + }, + "internal compiler error"); +} + namespace diagnostic_severity_tests { namespace parse_print_tests { diff --git a/src/tint/ast/diagnostic_control_test.cc.tmpl b/src/tint/ast/diagnostic_control_test.cc.tmpl index 74ff73e457..2eebba387b 100644 --- a/src/tint/ast/diagnostic_control_test.cc.tmpl +++ b/src/tint/ast/diagnostic_control_test.cc.tmpl @@ -12,6 +12,7 @@ See: #include +#include "gtest/gtest-spi.h" #include "src/tint/ast/diagnostic_control.h" #include "src/tint/ast/test_helper.h" @@ -25,8 +26,7 @@ TEST_F(DiagnosticControlTest, Creation) { Source source; source.range.begin = Source::Location{20, 2}; source.range.end = Source::Location{20, 5}; - auto* control = create(source, - DiagnosticSeverity::kWarning, name); + auto* control = create(source, DiagnosticSeverity::kWarning, name); EXPECT_EQ(control->source.range.begin.line, 20u); EXPECT_EQ(control->source.range.begin.column, 2u); EXPECT_EQ(control->source.range.end.line, 20u); @@ -35,6 +35,16 @@ TEST_F(DiagnosticControlTest, Creation) { EXPECT_EQ(control->rule_name, name); } +TEST_F(DiagnosticControlTest, Assert_RuleNotTemplated) { + EXPECT_FATAL_FAILURE( + { + ProgramBuilder b; + b.create(DiagnosticSeverity::kWarning, + b.Ident("name", "a", "b", "c")); + }, + "internal compiler error"); +} + namespace diagnostic_severity_tests { {{ Eval "TestParsePrintEnum" (Sem.Enum "diagnostic_severity")}} diff --git a/src/tint/ast/identifier.h b/src/tint/ast/identifier.h index 9176403c9a..0d99b00012 100644 --- a/src/tint/ast/identifier.h +++ b/src/tint/ast/identifier.h @@ -20,7 +20,7 @@ namespace tint::ast { /// An identifier -class Identifier final : public Castable { +class Identifier : public Castable { public: /// Constructor /// @param pid the identifier of the program that owns this node diff --git a/src/tint/ast/identifier_expression.cc b/src/tint/ast/identifier_expression.cc index ca4e0cb99f..1f86d9f308 100644 --- a/src/tint/ast/identifier_expression.cc +++ b/src/tint/ast/identifier_expression.cc @@ -27,6 +27,10 @@ IdentifierExpression::IdentifierExpression(ProgramID pid, : Base(pid, nid, src), identifier(ident) { TINT_ASSERT(AST, identifier != nullptr); TINT_ASSERT_PROGRAM_IDS_EQUAL(AST, identifier, program_id); + + // It is currently invalid for a templated identifier expression to be used as an identifier + // expression, as this should parse as a ast::TypeName. + TINT_ASSERT(AST, !ident->Is()); } IdentifierExpression::IdentifierExpression(IdentifierExpression&&) = default; diff --git a/src/tint/ast/identifier_expression_test.cc b/src/tint/ast/identifier_expression_test.cc index 3bef4ca3cb..80742a2f1f 100644 --- a/src/tint/ast/identifier_expression_test.cc +++ b/src/tint/ast/identifier_expression_test.cc @@ -57,5 +57,14 @@ TEST_F(IdentifierExpressionTest, Assert_DifferentProgramID_Symbol) { "internal compiler error"); } +TEST_F(IdentifierExpressionTest, Assert_IdentifierNotTemplated) { + EXPECT_FATAL_FAILURE( + { + ProgramBuilder b; + b.create(b.Ident("ident", "a", "b", "c")); + }, + "internal compiler error"); +} + } // namespace } // namespace tint::ast diff --git a/src/tint/ast/member_accessor_expression.cc b/src/tint/ast/member_accessor_expression.cc index f414f0ddcb..81ef085ec1 100644 --- a/src/tint/ast/member_accessor_expression.cc +++ b/src/tint/ast/member_accessor_expression.cc @@ -30,6 +30,11 @@ MemberAccessorExpression::MemberAccessorExpression(ProgramID pid, TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, structure, program_id); TINT_ASSERT(AST, member); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, member, program_id); + + // It is currently invalid for a structure to hold a templated member + if (member) { + TINT_ASSERT(AST, !member->Is()); + } } MemberAccessorExpression::MemberAccessorExpression(MemberAccessorExpression&&) = default; diff --git a/src/tint/ast/member_accessor_expression_test.cc b/src/tint/ast/member_accessor_expression_test.cc index bfc7218cae..1b05eeba12 100644 --- a/src/tint/ast/member_accessor_expression_test.cc +++ b/src/tint/ast/member_accessor_expression_test.cc @@ -80,5 +80,15 @@ TEST_F(MemberAccessorExpressionTest, Assert_DifferentProgramID_Member) { "internal compiler error"); } +TEST_F(MemberAccessorExpressionTest, Assert_MemberNotTemplated) { + EXPECT_FATAL_FAILURE( + { + ProgramBuilder b; + b.create(b.Expr("structure"), + b.Ident("member", "a", "b", "c")); + }, + "internal compiler error"); +} + } // namespace } // namespace tint::ast diff --git a/src/tint/ast/templated_identifier.cc b/src/tint/ast/templated_identifier.cc new file mode 100644 index 0000000000..756b183db6 --- /dev/null +++ b/src/tint/ast/templated_identifier.cc @@ -0,0 +1,48 @@ +// Copyright 2023 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/templated_identifier.h" + +#include + +#include "src/tint/program_builder.h" + +TINT_INSTANTIATE_TYPEINFO(tint::ast::TemplatedIdentifier); + +namespace tint::ast { + +TemplatedIdentifier::TemplatedIdentifier(ProgramID pid, + NodeID nid, + const Source& src, + const Symbol& sym, + utils::VectorRef args) + : Base(pid, nid, src, sym), arguments(std::move(args)) { + for (auto* arg : arguments) { + TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, arg, program_id); + } +} + +TemplatedIdentifier::TemplatedIdentifier(TemplatedIdentifier&&) = default; + +TemplatedIdentifier::~TemplatedIdentifier() = default; + +const TemplatedIdentifier* TemplatedIdentifier::Clone(CloneContext* ctx) const { + // Clone arguments outside of create() call to have deterministic ordering + auto src = ctx->Clone(source); + auto sym = ctx->Clone(symbol); + auto args = ctx->Clone(arguments); + return ctx->dst->create(src, sym, args); +} + +} // namespace tint::ast diff --git a/src/tint/ast/templated_identifier.h b/src/tint/ast/templated_identifier.h new file mode 100644 index 0000000000..7a49c051a7 --- /dev/null +++ b/src/tint/ast/templated_identifier.h @@ -0,0 +1,56 @@ +// Copyright 2023 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_TEMPLATED_IDENTIFIER_H_ +#define SRC_TINT_AST_TEMPLATED_IDENTIFIER_H_ + +#include "src/tint/ast/identifier.h" + +// Forward declarations +namespace tint::ast { +class Expression; +} // namespace tint::ast + +namespace tint::ast { + +/// A templated identifier expression +class TemplatedIdentifier final : public Castable { + 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 sym the symbol for the identifier + /// @param args the template arguments + TemplatedIdentifier(ProgramID pid, + NodeID nid, + const Source& src, + const Symbol& sym, + utils::VectorRef args); + /// Move constructor + TemplatedIdentifier(TemplatedIdentifier&&); + ~TemplatedIdentifier() override; + + /// Clones this node and all transitive child nodes using the `CloneContext` `ctx`. + /// @param ctx the clone context + /// @return the newly cloned node + const TemplatedIdentifier* Clone(CloneContext* ctx) const override; + + /// The templated arguments + const utils::Vector arguments; +}; + +} // namespace tint::ast + +#endif // SRC_TINT_AST_TEMPLATED_IDENTIFIER_H_ diff --git a/src/tint/ast/templated_identifier_test.cc b/src/tint/ast/templated_identifier_test.cc new file mode 100644 index 0000000000..648c3349ad --- /dev/null +++ b/src/tint/ast/templated_identifier_test.cc @@ -0,0 +1,80 @@ +// Copyright 2023 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 "gtest/gtest-spi.h" + +#include "src/tint/ast/test_helper.h" + +namespace tint::ast { +namespace { + +using namespace tint::number_suffixes; // NOLINT + +using TemplatedIdentifierTest = TestHelper; + +TEST_F(TemplatedIdentifierTest, Creation) { + auto* i = Ident("ident", 1_a, Add("x", "y"), false, "x"); + EXPECT_EQ(i->symbol, Symbols().Get("ident")); + ASSERT_EQ(i->arguments.Length(), 4u); + EXPECT_TRUE(i->arguments[0]->Is()); + EXPECT_TRUE(i->arguments[1]->Is()); + EXPECT_TRUE(i->arguments[2]->Is()); + EXPECT_TRUE(i->arguments[3]->Is()); +} + +TEST_F(TemplatedIdentifierTest, Creation_WithSource) { + auto* i = Ident(Source{{20, 2}}, "ident", 1_a, Add("x", "y"), false, "x"); + EXPECT_EQ(i->symbol, Symbols().Get("ident")); + ASSERT_EQ(i->arguments.Length(), 4u); + EXPECT_TRUE(i->arguments[0]->Is()); + EXPECT_TRUE(i->arguments[1]->Is()); + EXPECT_TRUE(i->arguments[2]->Is()); + EXPECT_TRUE(i->arguments[3]->Is()); + + auto src = i->source; + EXPECT_EQ(src.range.begin.line, 20u); + EXPECT_EQ(src.range.begin.column, 2u); +} + +TEST_F(TemplatedIdentifierTest, Assert_InvalidSymbol) { + EXPECT_FATAL_FAILURE( + { + ProgramBuilder b; + b.Expr(""); + }, + "internal compiler error"); +} + +TEST_F(TemplatedIdentifierTest, Assert_DifferentProgramID_Symbol) { + EXPECT_FATAL_FAILURE( + { + ProgramBuilder b1; + ProgramBuilder b2; + b1.Ident(b2.Sym("b2"), b1.Expr(1_i)); + }, + "internal compiler error"); +} + +TEST_F(TemplatedIdentifierTest, Assert_DifferentProgramID_TemplateArg) { + EXPECT_FATAL_FAILURE( + { + ProgramBuilder b1; + ProgramBuilder b2; + b1.Ident("b1", b2.Expr(1_i)); + }, + "internal compiler error"); +} + +} // namespace +} // namespace tint::ast diff --git a/src/tint/ast/type_name_test.cc b/src/tint/ast/type_name_test.cc index 803dad3000..9e01f0ca9e 100644 --- a/src/tint/ast/type_name_test.cc +++ b/src/tint/ast/type_name_test.cc @@ -28,6 +28,17 @@ TEST_F(TypeNameTest, Creation_NonTemplated) { EXPECT_EQ(t->name->symbol, Symbols().Get("ty")); } +TEST_F(TypeNameTest, Creation_Templated) { + auto* t = ty.type_name("ty", 1_a, 2._a, false); + auto* name = As(t->name); + ASSERT_NE(name, nullptr); + EXPECT_EQ(name->symbol, Symbols().Get("ty")); + ASSERT_EQ(name->arguments.Length(), 3u); + EXPECT_TRUE(name->arguments[0]->Is()); + EXPECT_TRUE(name->arguments[1]->Is()); + EXPECT_TRUE(name->arguments[2]->Is()); +} + TEST_F(TypeNameTest, Creation_WithSource) { auto* t = ty.type_name(Source{{20, 2}}, "ty"); ASSERT_NE(t->name, nullptr); diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h index 7954a41d6b..dc3560a1a4 100644 --- a/src/tint/program_builder.h +++ b/src/tint/program_builder.h @@ -81,6 +81,7 @@ #include "src/tint/ast/struct_member_offset_attribute.h" #include "src/tint/ast/struct_member_size_attribute.h" #include "src/tint/ast/switch_statement.h" +#include "src/tint/ast/templated_identifier.h" #include "src/tint/ast/type_name.h" #include "src/tint/ast/u32.h" #include "src/tint/ast/unary_op_expression.h" @@ -204,9 +205,7 @@ class ProgramBuilder { template explicit LetOptions(ARGS&&... args) { static constexpr bool has_init = - (traits::IsTypeOrDerived>, - ast::Expression> || - ...); + (traits::IsTypeOrDerived, ast::Expression> || ...); static_assert(has_init, "Let() must be constructed with an initializer expression"); (Set(std::forward(args)), ...); } @@ -229,9 +228,7 @@ class ProgramBuilder { template explicit ConstOptions(ARGS&&... args) { static constexpr bool has_init = - (traits::IsTypeOrDerived>, - ast::Expression> || - ...); + (traits::IsTypeOrDerived, ast::Expression> || ...); static_assert(has_init, "Const() must be constructed with an initializer expression"); (Set(std::forward(args)), ...); } @@ -904,19 +901,23 @@ class ProgramBuilder { /// Creates a type name /// @param name the name + /// @param args the optional template arguments /// @returns the type name - template - const ast::TypeName* type_name(NAME&& name) const { - return builder->create(builder->Ident(std::forward(name))); + template > + const ast::TypeName* type_name(NAME&& name, ARGS&&... args) const { + return builder->create( + builder->Ident(std::forward(name), std::forward(args)...)); } /// Creates a type name /// @param source the Source of the node /// @param name the name + /// @param args the optional template arguments /// @returns the type name - template - const ast::TypeName* type_name(const Source& source, NAME&& name) const { - return builder->create(source, builder->Ident(std::forward(name))); + template + const ast::TypeName* type_name(const Source& source, NAME&& name, ARGS&&... args) const { + return builder->create( + source, builder->Ident(std::forward(name), std::forward(args)...)); } /// Creates an alias type @@ -1150,22 +1151,30 @@ class ProgramBuilder { /// @param source the source information /// @param identifier the identifier symbol + /// @param args optional templated identifier arguments /// @return an ast::Identifier with the given symbol - template - const ast::Identifier* Ident(const Source& source, IDENTIFIER&& identifier) { - return create(source, Sym(std::forward(identifier))); + template + const auto* Ident(const Source& source, IDENTIFIER&& identifier, ARGS&&... args) { + Symbol sym = Sym(std::forward(identifier)); + if constexpr (sizeof...(args) > 0) { + return create(source, sym, + ExprList(std::forward(args)...)); + } else { + return create(source, sym); + } } /// @param identifier the identifier symbol + /// @param args optional templated identifier arguments /// @return an ast::Identifier with the given symbol - template - const ast::Identifier* Ident(IDENTIFIER&& identifier) { - if constexpr (traits::IsTypeOrDerived< - std::decay_t>>, - ast::Identifier>) { + template > + const auto* Ident(IDENTIFIER&& identifier, ARGS&&... args) { + if constexpr (traits::IsTypeOrDerived, ast::Identifier>) { + static_assert(sizeof...(args) == 0); return identifier; // Pass-through } else { - return create(Sym(std::forward(identifier))); + return Ident(source_, std::forward(identifier), + std::forward(args)...); } } @@ -1232,6 +1241,16 @@ class ProgramBuilder { return create(Ident(variable->symbol)); } + /// @param ident the identifier + /// @return an ast::IdentifierExpression with the given identifier + template > + const ast::IdentifierExpression* Expr(const IDENTIFIER* ident) { + static_assert(!traits::IsType, + "it is currently invalid for a templated identifier expression to be used as " + "an identifier expression, as this should parse as an ast::TypeName"); + return create(ident); + } + /// @param source the source information /// @param value the boolean value /// @return a Scalar constructor for the given value @@ -2347,43 +2366,46 @@ class ProgramBuilder { } /// @param source the source information - /// @param obj the object for the index accessor expression - /// @param idx the index argument for the index accessor expression - /// @returns a `ast::IndexAccessorExpression` that indexes `arr` with `idx` - template - const ast::IndexAccessorExpression* IndexAccessor(const Source& source, OBJ&& obj, IDX&& idx) { - return create(source, Expr(std::forward(obj)), - Expr(std::forward(idx))); + /// @param object the object for the index accessor expression + /// @param index the index argument for the index accessor expression + /// @returns a `ast::IndexAccessorExpression` that indexes @p object with @p index + template + const ast::IndexAccessorExpression* IndexAccessor(const Source& source, + OBJECT&& object, + INDEX&& index) { + return create(source, Expr(std::forward(object)), + Expr(std::forward(index))); } - /// @param obj the object for the index accessor expression - /// @param idx the index argument for the index accessor expression - /// @returns a `ast::IndexAccessorExpression` that indexes `arr` with `idx` - template - const ast::IndexAccessorExpression* IndexAccessor(OBJ&& obj, IDX&& idx) { - return create(Expr(std::forward(obj)), - Expr(std::forward(idx))); + /// @param object the object for the index accessor expression + /// @param index the index argument for the index accessor expression + /// @returns a `ast::IndexAccessorExpression` that indexes @p object with @p index + template + const ast::IndexAccessorExpression* IndexAccessor(OBJECT&& object, INDEX&& index) { + return create(Expr(std::forward(object)), + Expr(std::forward(index))); } /// @param source the source information - /// @param obj the object for the member accessor expression - /// @param idx the index argument for the member accessor expression - /// @returns a `ast::MemberAccessorExpression` that indexes `obj` with `idx` - template + /// @param object the object for the member accessor expression + /// @param member the member argument for the member accessor expression + /// @returns a `ast::MemberAccessorExpression` that indexes @p object with @p member + template const ast::MemberAccessorExpression* MemberAccessor(const Source& source, - OBJ&& obj, - IDX&& idx) { - return create(source, Expr(std::forward(obj)), - Ident(std::forward(idx))); + OBJECT&& object, + MEMBER&& member) { + static_assert(!traits::IsType, ast::TemplatedIdentifier>, + "it is currently invalid for a structure to hold a templated member"); + return create(source, Expr(std::forward(object)), + Ident(std::forward(member))); } - /// @param obj the object for the member accessor expression - /// @param idx the index argument for the member accessor expression - /// @returns a `ast::MemberAccessorExpression` that indexes `obj` with `idx` - template - const ast::MemberAccessorExpression* MemberAccessor(OBJ&& obj, IDX&& idx) { - return create(Expr(std::forward(obj)), - Ident(std::forward(idx))); + /// @param object the object for the member accessor expression + /// @param member the member argument for the member accessor expression + /// @returns a `ast::MemberAccessorExpression` that indexes @p object with @p member + template + const ast::MemberAccessorExpression* MemberAccessor(OBJECT&& object, MEMBER&& member) { + return MemberAccessor(source_, std::forward(object), std::forward(member)); } /// Creates a ast::StructMemberOffsetAttribute @@ -3284,6 +3306,8 @@ class ProgramBuilder { const ast::DiagnosticAttribute* DiagnosticAttribute(const Source& source, ast::DiagnosticSeverity severity, NAME&& rule_name) { + static_assert(!traits::IsType, ast::TemplatedIdentifier>, + "it is invalid for a diagnostic rule name to be templated"); return create( source, DiagnosticControl(source, severity, std::forward(rule_name))); } diff --git a/src/tint/resolver/dependency_graph.cc b/src/tint/resolver/dependency_graph.cc index 6dc111ef68..d09a7e3924 100644 --- a/src/tint/resolver/dependency_graph.cc +++ b/src/tint/resolver/dependency_graph.cc @@ -61,6 +61,7 @@ #include "src/tint/ast/struct_member_offset_attribute.h" #include "src/tint/ast/struct_member_size_attribute.h" #include "src/tint/ast/switch_statement.h" +#include "src/tint/ast/templated_identifier.h" #include "src/tint/ast/traverse_expressions.h" #include "src/tint/ast/type_name.h" #include "src/tint/ast/u32.h" diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc index 36f9da8fc6..16306423a5 100644 --- a/src/tint/resolver/resolver.cc +++ b/src/tint/resolver/resolver.cc @@ -321,6 +321,10 @@ type::Type* Resolver::Type(const ast::Type* ty) { [&](const ast::TypeName* t) -> type::Type* { Mark(t->name); + if (t->name->Is()) { + TINT_UNREACHABLE(Resolver, builder_->Diagnostics()) << "TODO(crbug.com/tint/1810)"; + } + auto* resolved = sem_.ResolvedSymbol(t); if (resolved == nullptr) { if (IsBuiltin(t->name->symbol)) { diff --git a/src/tint/traits.h b/src/tint/traits.h index f6dac27984..1d0c2f6e94 100644 --- a/src/tint/traits.h +++ b/src/tint/traits.h @@ -15,6 +15,7 @@ #ifndef SRC_TINT_TRAITS_H_ #define SRC_TINT_TRAITS_H_ +#include #include #include #include @@ -177,6 +178,16 @@ struct IsTypeIn> : std::disjunction. template static constexpr bool IsTypeIn = detail::IsTypeIn::value; +/// Evaluates to the decayed pointer element type, or the decayed type T if T is not a pointer. +template +using PtrElTy = Decay>>; + +/// Evaluates to true if `T` decayed is a `std::string`, `std::string_view` or `const char*` +template +static constexpr bool IsStringLike = + std::is_same_v, std::string> || std::is_same_v, std::string_view> || + std::is_same_v, const char*>; + } // namespace tint::traits #endif // SRC_TINT_TRAITS_H_ diff --git a/src/tint/traits_test.cc b/src/tint/traits_test.cc index c10010786d..e86e389d69 100644 --- a/src/tint/traits_test.cc +++ b/src/tint/traits_test.cc @@ -19,6 +19,25 @@ namespace tint::traits { namespace { + +static_assert(std::is_same_v, int>); +static_assert(std::is_same_v, int>); +static_assert(std::is_same_v, int>); +static_assert(std::is_same_v, int>); +static_assert(std::is_same_v, int>); +static_assert(std::is_same_v, int>); +static_assert(std::is_same_v, int>); + +static_assert(IsStringLike); +static_assert(IsStringLike); +static_assert(IsStringLike); +static_assert(IsStringLike); +static_assert(IsStringLike); +static_assert(IsStringLike); +static_assert(!IsStringLike); +static_assert(!IsStringLike); +static_assert(!IsStringLike); + struct S {}; void F1(S) {} void F3(int, S, float) {}