tint/ast: Change TypeDecl::name to an ast::Identifier.

The goal here is to have all AST nodes use an identifier instead of
symbols directly. This will greatly simplify the renamer transform,
and gives the symbol a Source location, which is helpful for
diagnostics and tooling.

Change-Id: I8b3e05d05886c6caa16513a5cfb45d30f7a8d720
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/119283
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/ast/alias.cc b/src/tint/ast/alias.cc
index 8a23e8f..2672667 100644
--- a/src/tint/ast/alias.cc
+++ b/src/tint/ast/alias.cc
@@ -20,7 +20,7 @@
 
 namespace tint::ast {
 
-Alias::Alias(ProgramID pid, NodeID nid, const Source& src, const Symbol& n, const Type* subtype)
+Alias::Alias(ProgramID pid, NodeID nid, const Source& src, const Identifier* n, const Type* subtype)
     : Base(pid, nid, src, n), type(subtype) {
     TINT_ASSERT(AST, type);
 }
diff --git a/src/tint/ast/alias.h b/src/tint/ast/alias.h
index 74d91b0..971d46b 100644
--- a/src/tint/ast/alias.h
+++ b/src/tint/ast/alias.h
@@ -19,6 +19,11 @@
 
 #include "src/tint/ast/type_decl.h"
 
+// Forward declarations
+namespace tint::ast {
+class Type;
+}  // namespace tint::ast
+
 namespace tint::ast {
 
 /// A type alias type. Holds a name and pointer to another type.
@@ -30,7 +35,11 @@
     /// @param src the source of this node
     /// @param name the symbol for the alias
     /// @param subtype the alias'd type
-    Alias(ProgramID pid, NodeID nid, const Source& src, const Symbol& name, const Type* subtype);
+    Alias(ProgramID pid,
+          NodeID nid,
+          const Source& src,
+          const Identifier* name,
+          const Type* subtype);
     /// Move constructor
     Alias(Alias&&);
     /// Destructor
diff --git a/src/tint/ast/alias_test.cc b/src/tint/ast/alias_test.cc
index 20a9c5d..faedff7 100644
--- a/src/tint/ast/alias_test.cc
+++ b/src/tint/ast/alias_test.cc
@@ -35,7 +35,7 @@
 TEST_F(AstAliasTest, Create) {
     auto* u32 = create<U32>();
     auto* a = Alias("a_type", u32);
-    EXPECT_EQ(a->name, Symbol(1, ID()));
+    EXPECT_EQ(a->name->symbol, Symbol(1, ID()));
     EXPECT_EQ(a->type, u32);
 }
 
diff --git a/src/tint/ast/module.cc b/src/tint/ast/module.cc
index 835c87a..cbebab4 100644
--- a/src/tint/ast/module.cc
+++ b/src/tint/ast/module.cc
@@ -43,7 +43,7 @@
 
 const ast::TypeDecl* Module::LookupType(Symbol name) const {
     for (auto* ty : TypeDecls()) {
-        if (ty->name == name) {
+        if (ty->name->symbol == name) {
             return ty;
         }
     }
diff --git a/src/tint/ast/module_test.cc b/src/tint/ast/module_test.cc
index 1a57fbb..cd03781 100644
--- a/src/tint/ast/module_test.cc
+++ b/src/tint/ast/module_test.cc
@@ -126,9 +126,12 @@
     ASSERT_TRUE(decls[2]->Is<ast::Alias>());
     ASSERT_TRUE(decls[4]->Is<ast::Alias>());
 
-    ASSERT_EQ(cloned.Symbols().NameFor(decls[0]->As<ast::Alias>()->name), "inserted_before_F");
-    ASSERT_EQ(cloned.Symbols().NameFor(decls[2]->As<ast::Alias>()->name), "inserted_before_A");
-    ASSERT_EQ(cloned.Symbols().NameFor(decls[4]->As<ast::Alias>()->name), "inserted_before_V");
+    ASSERT_EQ(cloned.Symbols().NameFor(decls[0]->As<ast::Alias>()->name->symbol),
+              "inserted_before_F");
+    ASSERT_EQ(cloned.Symbols().NameFor(decls[2]->As<ast::Alias>()->name->symbol),
+              "inserted_before_A");
+    ASSERT_EQ(cloned.Symbols().NameFor(decls[4]->As<ast::Alias>()->name->symbol),
+              "inserted_before_V");
 }
 
 TEST_F(ModuleTest, Directives) {
diff --git a/src/tint/ast/struct.cc b/src/tint/ast/struct.cc
index c2d9002..2757c4e 100644
--- a/src/tint/ast/struct.cc
+++ b/src/tint/ast/struct.cc
@@ -25,7 +25,7 @@
 Struct::Struct(ProgramID pid,
                NodeID nid,
                const Source& src,
-               Symbol n,
+               const Identifier* n,
                utils::VectorRef<const ast::StructMember*> m,
                utils::VectorRef<const ast::Attribute*> attrs)
     : Base(pid, nid, src, n), members(std::move(m)), attributes(std::move(attrs)) {
diff --git a/src/tint/ast/struct.h b/src/tint/ast/struct.h
index 3e3e5cf..9668db1 100644
--- a/src/tint/ast/struct.h
+++ b/src/tint/ast/struct.h
@@ -38,7 +38,7 @@
     Struct(ProgramID pid,
            NodeID nid,
            const Source& src,
-           Symbol name,
+           const Identifier* name,
            utils::VectorRef<const ast::StructMember*> members,
            utils::VectorRef<const ast::Attribute*> attributes);
     /// Move constructor
diff --git a/src/tint/ast/struct_test.cc b/src/tint/ast/struct_test.cc
index 29b9e9a..b1f7293 100644
--- a/src/tint/ast/struct_test.cc
+++ b/src/tint/ast/struct_test.cc
@@ -36,8 +36,8 @@
 
 TEST_F(AstStructTest, Creation) {
     auto name = Sym("s");
-    auto* s = create<Struct>(name, utils::Vector{Member("a", ty.i32())}, utils::Empty);
-    EXPECT_EQ(s->name, name);
+    auto* s = Structure(name, utils::Vector{Member("a", ty.i32())});
+    EXPECT_EQ(s->name->symbol, name);
     EXPECT_EQ(s->members.Length(), 1u);
     EXPECT_TRUE(s->attributes.IsEmpty());
     EXPECT_EQ(s->source.range.begin.line, 0u);
@@ -49,11 +49,11 @@
 TEST_F(AstStructTest, Creation_WithAttributes) {
     auto name = Sym("s");
 
-    auto* s = create<Struct>(name, utils::Vector{Member("a", ty.i32())},
-                             utils::Vector{
-                                 ASTNodes().Create<BlockAttribute>(ID(), AllocateNodeID()),
-                             });
-    EXPECT_EQ(s->name, name);
+    auto* s = Structure(name, utils::Vector{Member("a", ty.i32())},
+                        utils::Vector{
+                            ASTNodes().Create<BlockAttribute>(ID(), AllocateNodeID()),
+                        });
+    EXPECT_EQ(s->name->symbol, name);
     EXPECT_EQ(s->members.Length(), 1u);
     ASSERT_EQ(s->attributes.Length(), 1u);
     EXPECT_TRUE(s->attributes[0]->Is<BlockAttribute>());
@@ -65,11 +65,10 @@
 
 TEST_F(AstStructTest, CreationWithSourceAndAttributes) {
     auto name = Sym("s");
-    auto* s =
-        create<Struct>(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 8}}},
-                       name, utils::Vector{Member("a", ty.i32())},
-                       utils::Vector{ASTNodes().Create<BlockAttribute>(ID(), AllocateNodeID())});
-    EXPECT_EQ(s->name, name);
+    auto* s = Structure(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 8}}},
+                        name, utils::Vector{Member("a", ty.i32())},
+                        utils::Vector{ASTNodes().Create<BlockAttribute>(ID(), AllocateNodeID())});
+    EXPECT_EQ(s->name->symbol, name);
     EXPECT_EQ(s->members.Length(), 1u);
     ASSERT_EQ(s->attributes.Length(), 1u);
     EXPECT_TRUE(s->attributes[0]->Is<BlockAttribute>());
@@ -83,8 +82,8 @@
     EXPECT_FATAL_FAILURE(
         {
             ProgramBuilder b;
-            b.create<Struct>(b.Sym("S"), utils::Vector{b.Member("a", b.ty.i32()), nullptr},
-                             utils::Empty);
+            b.Structure(b.Sym("S"), utils::Vector{b.Member("a", b.ty.i32()), nullptr},
+                        utils::Empty);
         },
         "internal compiler error");
 }
@@ -93,8 +92,8 @@
     EXPECT_FATAL_FAILURE(
         {
             ProgramBuilder b;
-            b.create<Struct>(b.Sym("S"), utils::Vector{b.Member("a", b.ty.i32())},
-                             utils::Vector<const ast::Attribute*, 1>{nullptr});
+            b.Structure(b.Sym("S"), utils::Vector{b.Member("a", b.ty.i32())},
+                        utils::Vector<const ast::Attribute*, 1>{nullptr});
         },
         "internal compiler error");
 }
@@ -104,8 +103,7 @@
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
-            b1.create<Struct>(b1.Sym("S"), utils::Vector{b2.Member("a", b2.ty.i32())},
-                              utils::Empty);
+            b1.Structure(b1.Sym("S"), utils::Vector{b2.Member("a", b2.ty.i32())});
         },
         "internal compiler error");
 }
@@ -115,7 +113,7 @@
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
-            b1.create<Struct>(
+            b1.Structure(
                 b1.Sym("S"), utils::Vector{b1.Member("a", b1.ty.i32())},
                 utils::Vector{b2.ASTNodes().Create<BlockAttribute>(b2.ID(), b2.AllocateNodeID())});
         },
diff --git a/src/tint/ast/type_decl.cc b/src/tint/ast/type_decl.cc
index 0b76524..2319b19 100644
--- a/src/tint/ast/type_decl.cc
+++ b/src/tint/ast/type_decl.cc
@@ -14,15 +14,18 @@
 
 #include "src/tint/ast/type_decl.h"
 
-#include "src/tint/program_builder.h"
+#include "src/tint/ast/templated_identifier.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ast::TypeDecl);
 
 namespace tint::ast {
 
-TypeDecl::TypeDecl(ProgramID pid, NodeID nid, const Source& src, Symbol n)
+TypeDecl::TypeDecl(ProgramID pid, NodeID nid, const Source& src, const Identifier* n)
     : Base(pid, nid, src), name(n) {
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, name, program_id);
+    TINT_ASSERT(AST, name);
+    if (name) {
+        TINT_ASSERT(AST, !name->Is<TemplatedIdentifier>());
+    }
 }
 
 TypeDecl::TypeDecl(TypeDecl&&) = default;
diff --git a/src/tint/ast/type_decl.h b/src/tint/ast/type_decl.h
index e3266c6..fb8958f 100644
--- a/src/tint/ast/type_decl.h
+++ b/src/tint/ast/type_decl.h
@@ -15,9 +15,12 @@
 #ifndef SRC_TINT_AST_TYPE_DECL_H_
 #define SRC_TINT_AST_TYPE_DECL_H_
 
-#include <string>
+#include "src/tint/ast/node.h"
 
-#include "src/tint/ast/type.h"
+// Forward declarations
+namespace tint::ast {
+class Identifier;
+}  // namespace tint::ast
 
 namespace tint::ast {
 
@@ -28,15 +31,15 @@
     /// @param pid the identifier of the program that owns this node
     /// @param nid the unique node identifier
     /// @param src the source of this node for the import statement
-    /// @param name The name of the structure
-    TypeDecl(ProgramID pid, NodeID nid, const Source& src, Symbol name);
+    /// @param name The name of the type
+    TypeDecl(ProgramID pid, NodeID nid, const Source& src, const Identifier* name);
     /// Move constructor
     TypeDecl(TypeDecl&&);
 
     ~TypeDecl() override;
 
     /// The name of the type declaration
-    const Symbol name;
+    const Identifier* const name;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/program_builder.cc b/src/tint/program_builder.cc
index 0ce8f0b..a847e00 100644
--- a/src/tint/program_builder.cc
+++ b/src/tint/program_builder.cc
@@ -128,7 +128,7 @@
 }
 
 const ast::TypeName* ProgramBuilder::TypesBuilder::Of(const ast::TypeDecl* decl) const {
-    return (*this)(decl->name);
+    return (*this)(decl->name->symbol);
 }
 
 ProgramBuilder::TypesBuilder::TypesBuilder(ProgramBuilder* pb) : builder(pb) {}
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index d5516af..228be2d 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -900,8 +900,7 @@
         /// @returns the alias pointer
         template <typename NAME>
         const ast::Alias* alias(NAME&& name, const ast::Type* type) const {
-            auto sym = builder->Sym(std::forward<NAME>(name));
-            return builder->create<ast::Alias>(sym, type);
+            return alias(builder->source_, std::forward<NAME>(name), type);
         }
 
         /// Creates an alias type
@@ -911,8 +910,8 @@
         /// @returns the alias pointer
         template <typename NAME>
         const ast::Alias* alias(const Source& source, NAME&& name, const ast::Type* type) const {
-            auto sym = builder->Sym(std::forward<NAME>(name));
-            return builder->create<ast::Alias>(source, sym, type);
+            return builder->create<ast::Alias>(source, builder->Ident(std::forward<NAME>(name)),
+                                               type);
         }
 
         /// @param type the type of the pointer
@@ -2581,6 +2580,15 @@
     const ast::DiscardStatement* Discard() { return create<ast::DiscardStatement>(); }
 
     /// Creates a ast::Alias registering it with the AST().TypeDecls().
+    /// @param name the alias name
+    /// @param type the alias target type
+    /// @returns the alias type
+    template <typename NAME>
+    const ast::Alias* Alias(NAME&& name, const ast::Type* type) {
+        return Alias(source_, std::forward<NAME>(name), type);
+    }
+
+    /// Creates a ast::Alias registering it with the AST().TypeDecls().
     /// @param source the source information
     /// @param name the alias name
     /// @param type the alias target type
@@ -2592,40 +2600,34 @@
         return out;
     }
 
-    /// Creates a ast::Alias registering it with the AST().TypeDecls().
-    /// @param name the alias name
-    /// @param type the alias target type
-    /// @returns the alias type
+    /// Creates a ast::Struct registering it with the AST().TypeDecls().
+    /// @param name the struct name
+    /// @param members the struct members
+    /// @param attributes the optional struct attributes
+    /// @returns the struct type
     template <typename NAME>
-    const ast::Alias* Alias(NAME&& name, const ast::Type* type) {
-        auto* out = ty.alias(std::forward<NAME>(name), type);
-        AST().AddTypeDecl(out);
-        return out;
+    const ast::Struct* Structure(
+        NAME&& name,
+        utils::VectorRef<const ast::StructMember*> members,
+        utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
+        return Structure(source_, std::forward<NAME>(name), std::move(members),
+                         std::move(attributes));
     }
 
     /// Creates a ast::Struct registering it with the AST().TypeDecls().
     /// @param source the source information
     /// @param name the struct name
     /// @param members the struct members
+    /// @param attributes the optional struct attributes
     /// @returns the struct type
     template <typename NAME>
-    const ast::Struct* Structure(const Source& source,
-                                 NAME&& name,
-                                 utils::VectorRef<const ast::StructMember*> members) {
-        auto sym = Sym(std::forward<NAME>(name));
-        auto* type = create<ast::Struct>(source, sym, std::move(members), utils::Empty);
-        AST().AddTypeDecl(type);
-        return type;
-    }
-
-    /// Creates a ast::Struct registering it with the AST().TypeDecls().
-    /// @param name the struct name
-    /// @param members the struct members
-    /// @returns the struct type
-    template <typename NAME>
-    const ast::Struct* Structure(NAME&& name, utils::VectorRef<const ast::StructMember*> members) {
-        auto sym = Sym(std::forward<NAME>(name));
-        auto* type = create<ast::Struct>(sym, std::move(members), utils::Empty);
+    const ast::Struct* Structure(
+        const Source& source,
+        NAME&& name,
+        utils::VectorRef<const ast::StructMember*> members,
+        utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
+        auto* type = create<ast::Struct>(source, Ident(std::forward<NAME>(name)),
+                                         std::move(members), std::move(attributes));
         AST().AddTypeDecl(type);
         return type;
     }
diff --git a/src/tint/reader/spirv/function.cc b/src/tint/reader/spirv/function.cc
index 1a61645..c5eb5a4 100644
--- a/src/tint/reader/spirv/function.cc
+++ b/src/tint/reader/spirv/function.cc
@@ -1383,8 +1383,8 @@
             return_type = ty_.Void()->Build(builder_);
         } else {
             // Create and register the result type.
-            auto* str =
-                create<ast::Struct>(Source{}, return_struct_sym, return_members, AttributeList{});
+            auto* str = create<ast::Struct>(Source{}, builder_.Ident(return_struct_sym),
+                                            return_members, AttributeList{});
             parser_impl_.AddTypeDecl(return_struct_sym, str);
             return_type = builder_.ty.Of(str);
 
diff --git a/src/tint/reader/spirv/parser_impl.cc b/src/tint/reader/spirv/parser_impl.cc
index a610039..0b7d30e 100644
--- a/src/tint/reader/spirv/parser_impl.cc
+++ b/src/tint/reader/spirv/parser_impl.cc
@@ -1184,9 +1184,10 @@
 
     // Now make the struct.
     auto sym = builder_.Symbols().Register(name);
-    auto* ast_struct = create<ast::Struct>(Source{}, sym, std::move(ast_members), utils::Empty);
+    auto* ast_struct =
+        create<ast::Struct>(Source{}, builder_.Ident(sym), std::move(ast_members), utils::Empty);
     if (num_non_writable_members == members.size()) {
-        read_only_struct_types_.insert(ast_struct->name);
+        read_only_struct_types_.insert(ast_struct->name->symbol);
     }
     AddTypeDecl(sym, ast_struct);
     const auto* result = ty_.Struct(sym, std::move(ast_member_types));
diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc
index ec7cfb8..3e3e3ca 100644
--- a/src/tint/reader/wgsl/parser_impl.cc
+++ b/src/tint/reader/wgsl/parser_impl.cc
@@ -551,7 +551,6 @@
         errored = true;
     }
     if (str.matched) {
-        builder_.AST().AddTypeDecl(str.value);
         if (!expect_attributes_consumed(attrs.value)) {
             return Failure::kErrored;
         }
@@ -1400,8 +1399,7 @@
         return Failure::kErrored;
     }
 
-    auto sym = builder_.Symbols().Register(name.value);
-    return create<ast::Struct>(t.source(), sym, std::move(body.value), utils::Empty);
+    return builder_.Structure(t.source(), name.value, std::move(body.value));
 }
 
 // struct_body_decl
diff --git a/src/tint/reader/wgsl/parser_impl_global_decl_test.cc b/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
index e27d614..db5db00 100644
--- a/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
@@ -106,7 +106,9 @@
     auto program = p->program();
     ASSERT_EQ(program.AST().TypeDecls().Length(), 1u);
     ASSERT_TRUE(program.AST().TypeDecls()[0]->Is<ast::Alias>());
-    EXPECT_EQ(program.Symbols().NameFor(program.AST().TypeDecls()[0]->As<ast::Alias>()->name), "A");
+    EXPECT_EQ(
+        program.Symbols().NameFor(program.AST().TypeDecls()[0]->As<ast::Alias>()->name->symbol),
+        "A");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_TypeAlias_StructIdent) {
@@ -122,14 +124,14 @@
     ASSERT_EQ(program.AST().TypeDecls().Length(), 2u);
     ASSERT_TRUE(program.AST().TypeDecls()[0]->Is<ast::Struct>());
     auto* str = program.AST().TypeDecls()[0]->As<ast::Struct>();
-    EXPECT_EQ(str->name, program.Symbols().Get("A"));
+    EXPECT_EQ(str->name->symbol, program.Symbols().Get("A"));
 
     ASSERT_TRUE(program.AST().TypeDecls()[1]->Is<ast::Alias>());
     auto* alias = program.AST().TypeDecls()[1]->As<ast::Alias>();
-    EXPECT_EQ(alias->name, program.Symbols().Get("B"));
+    EXPECT_EQ(alias->name->symbol, program.Symbols().Get("B"));
     auto* tn = alias->type->As<ast::TypeName>();
     EXPECT_NE(tn, nullptr);
-    EXPECT_EQ(tn->name->symbol, str->name);
+    EXPECT_EQ(tn->name->symbol, str->name->symbol);
 }
 
 // TODO(crbug.com/tint/1812): DEPRECATED
@@ -141,7 +143,9 @@
     auto program = p->program();
     ASSERT_EQ(program.AST().TypeDecls().Length(), 1u);
     ASSERT_TRUE(program.AST().TypeDecls()[0]->Is<ast::Alias>());
-    EXPECT_EQ(program.Symbols().NameFor(program.AST().TypeDecls()[0]->As<ast::Alias>()->name), "A");
+    EXPECT_EQ(
+        program.Symbols().NameFor(program.AST().TypeDecls()[0]->As<ast::Alias>()->name->symbol),
+        "A");
 }
 
 // TODO(crbug.com/tint/1812): DEPRECATED
@@ -158,14 +162,14 @@
     ASSERT_EQ(program.AST().TypeDecls().Length(), 2u);
     ASSERT_TRUE(program.AST().TypeDecls()[0]->Is<ast::Struct>());
     auto* str = program.AST().TypeDecls()[0]->As<ast::Struct>();
-    EXPECT_EQ(str->name, program.Symbols().Get("A"));
+    EXPECT_EQ(str->name->symbol, program.Symbols().Get("A"));
 
     ASSERT_TRUE(program.AST().TypeDecls()[1]->Is<ast::Alias>());
     auto* alias = program.AST().TypeDecls()[1]->As<ast::Alias>();
-    EXPECT_EQ(alias->name, program.Symbols().Get("B"));
+    EXPECT_EQ(alias->name->symbol, program.Symbols().Get("B"));
     auto* tn = alias->type->As<ast::TypeName>();
     EXPECT_NE(tn, nullptr);
-    EXPECT_EQ(tn->name->symbol, str->name);
+    EXPECT_EQ(tn->name->symbol, str->name->symbol);
 }
 
 TEST_F(ParserImplTest, GlobalDecl_TypeAlias_MissingSemicolon) {
@@ -225,7 +229,7 @@
     ASSERT_TRUE(t->Is<ast::Struct>());
 
     auto* str = t->As<ast::Struct>();
-    EXPECT_EQ(str->name, program.Symbols().Get("A"));
+    EXPECT_EQ(str->name->symbol, program.Symbols().Get("A"));
     EXPECT_EQ(str->members.Length(), 2u);
 }
 
diff --git a/src/tint/reader/wgsl/parser_impl_struct_decl_test.cc b/src/tint/reader/wgsl/parser_impl_struct_decl_test.cc
index bce49cd..af417d3 100644
--- a/src/tint/reader/wgsl/parser_impl_struct_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_struct_decl_test.cc
@@ -29,7 +29,7 @@
     EXPECT_FALSE(s.errored);
     EXPECT_TRUE(s.matched);
     ASSERT_NE(s.value, nullptr);
-    ASSERT_EQ(s->name, p->builder().Symbols().Register("S"));
+    ASSERT_EQ(s->name->symbol, p->builder().Symbols().Register("S"));
     ASSERT_EQ(s->members.Length(), 2u);
     EXPECT_EQ(s->members[0]->name->symbol, p->builder().Symbols().Register("a"));
     EXPECT_EQ(s->members[1]->name->symbol, p->builder().Symbols().Register("b"));
@@ -63,7 +63,7 @@
     EXPECT_FALSE(s.errored);
     EXPECT_TRUE(s.matched);
     ASSERT_NE(s.value, nullptr);
-    ASSERT_EQ(s->name, p->builder().Symbols().Register(struct_ident));
+    ASSERT_EQ(s->name->symbol, p->builder().Symbols().Register(struct_ident));
     ASSERT_EQ(s->members.Length(), 2u);
     EXPECT_EQ(s->members[0]->name->symbol, p->builder().Symbols().Register(member_a_ident));
     EXPECT_EQ(s->members[1]->name->symbol, p->builder().Symbols().Register(member_b_ident));
diff --git a/src/tint/reader/wgsl/parser_impl_type_alias_test.cc b/src/tint/reader/wgsl/parser_impl_type_alias_test.cc
index f4c20de..f6b0860 100644
--- a/src/tint/reader/wgsl/parser_impl_type_alias_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_type_alias_test.cc
@@ -42,7 +42,7 @@
     ASSERT_NE(t.value, nullptr);
     ASSERT_TRUE(t.value->Is<ast::Alias>());
     auto* alias = t.value->As<ast::Alias>();
-    EXPECT_EQ(p->builder().Symbols().NameFor(alias->name), "a");
+    EXPECT_EQ(p->builder().Symbols().NameFor(alias->name->symbol), "a");
     EXPECT_TRUE(alias->type->Is<ast::TypeName>());
     EXPECT_EQ(alias->source.range, (Source::Range{{1u, 1u}, {1u, 11u}}));
 }
@@ -61,7 +61,7 @@
     ASSERT_NE(t.value, nullptr);
     ASSERT_TRUE(t.value->Is<ast::Alias>());
     auto* alias = t.value->As<ast::Alias>();
-    EXPECT_EQ(p->builder().Symbols().NameFor(alias->name), ident);
+    EXPECT_EQ(p->builder().Symbols().NameFor(alias->name->symbol), ident);
     EXPECT_TRUE(alias->type->Is<ast::I32>());
     EXPECT_EQ(alias->source.range, (Source::Range{{1u, 1u}, {1u, 37u}}));
 }
diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc
index 3030992..196796f 100644
--- a/src/tint/resolver/attribute_validation_test.cc
+++ b/src/tint/resolver/attribute_validation_test.cc
@@ -573,9 +573,8 @@
 TEST_P(StructAttributeTest, IsValid) {
     auto& params = GetParam();
 
-    auto* str = create<ast::Struct>(Sym("mystruct"), utils::Vector{Member("a", ty.f32())},
-                                    createAttributes(Source{{12, 34}}, *this, params.kind));
-    AST().AddGlobalDeclaration(str);
+    Structure("mystruct", utils::Vector{Member("a", ty.f32())},
+              createAttributes(Source{{12, 34}}, *this, params.kind));
 
     if (params.should_pass) {
         EXPECT_TRUE(r()->Resolve()) << r()->error();
diff --git a/src/tint/resolver/dependency_graph.cc b/src/tint/resolver/dependency_graph.cc
index 24d5697..1c207f6 100644
--- a/src/tint/resolver/dependency_graph.cc
+++ b/src/tint/resolver/dependency_graph.cc
@@ -184,14 +184,14 @@
         Switch(
             global->node,
             [&](const ast::Struct* str) {
-                Declare(str->name, str);
+                Declare(str->name->symbol, str);
                 for (auto* member : str->members) {
                     TraverseAttributes(member->attributes);
                     TraverseType(member->type);
                 }
             },
             [&](const ast::Alias* alias) {
-                Declare(alias->name, alias);
+                Declare(alias->name->symbol, alias);
                 TraverseType(alias->type);
             },
             [&](const ast::Function* func) {
@@ -558,7 +558,7 @@
     Symbol SymbolOf(const ast::Node* node) const {
         return Switch(
             node,  //
-            [&](const ast::TypeDecl* td) { return td->name; },
+            [&](const ast::TypeDecl* td) { return td->name->symbol; },
             [&](const ast::Function* func) { return func->name->symbol; },
             [&](const ast::Variable* var) { return var->name->symbol; },
             [&](const ast::DiagnosticDirective*) { return Symbol(); },
diff --git a/src/tint/resolver/inferred_type_test.cc b/src/tint/resolver/inferred_type_test.cc
index e8b5125..eba38ff 100644
--- a/src/tint/resolver/inferred_type_test.cc
+++ b/src/tint/resolver/inferred_type_test.cc
@@ -151,7 +151,7 @@
     auto* str = Structure("S", utils::Vector{member});
 
     auto* expected_type = create<sem::Struct>(
-        str, str->source, str->name,
+        str, str->source, str->name->symbol,
         utils::Vector{create<sem::StructMember>(member, member->source, member->name->symbol,
                                                 create<type::I32>(), 0u, 0u, 0u, 4u, std::nullopt)},
         0u, 4u, 4u);
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index 7648ae7..01bad34 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -3154,6 +3154,8 @@
 }
 
 type::Type* Resolver::TypeDecl(const ast::TypeDecl* named_type) {
+    Mark(named_type->name);
+
     type::Type* result = nullptr;
     if (auto* alias = named_type->As<ast::Alias>()) {
         result = Alias(alias);
@@ -3551,8 +3553,9 @@
     }
 
     auto* out = builder_->create<sem::Struct>(
-        str, str->source, str->name, std::move(sem_members), static_cast<uint32_t>(struct_align),
-        static_cast<uint32_t>(struct_size), static_cast<uint32_t>(size_no_padding));
+        str, str->source, str->name->symbol, std::move(sem_members),
+        static_cast<uint32_t>(struct_align), static_cast<uint32_t>(struct_size),
+        static_cast<uint32_t>(size_no_padding));
 
     for (size_t i = 0; i < sem_members.Length(); i++) {
         auto* mem_type = sem_members[i]->Type();
diff --git a/src/tint/sem/struct_test.cc b/src/tint/sem/struct_test.cc
index b009d55..1686e823 100644
--- a/src/tint/sem/struct_test.cc
+++ b/src/tint/sem/struct_test.cc
@@ -24,10 +24,10 @@
 
 TEST_F(SemStructTest, Creation) {
     auto name = Sym("S");
-    auto* impl = create<ast::Struct>(name, utils::Empty, utils::Empty);
+    auto* impl = create<ast::Struct>(Ident(name), utils::Empty, utils::Empty);
     auto* ptr = impl;
-    auto* s = create<sem::Struct>(impl, impl->source, impl->name, utils::Empty, 4u /* align */,
-                                  8u /* size */, 16u /* size_no_padding */);
+    auto* s = create<sem::Struct>(impl, impl->source, impl->name->symbol, utils::Empty,
+                                  4u /* align */, 8u /* size */, 16u /* size_no_padding */);
     EXPECT_EQ(s->Declaration(), ptr);
     EXPECT_EQ(s->Align(), 4u);
     EXPECT_EQ(s->Size(), 8u);
@@ -35,11 +35,11 @@
 }
 
 TEST_F(SemStructTest, Equals) {
-    auto* a_impl = create<ast::Struct>(Sym("a"), utils::Empty, utils::Empty);
-    auto* a = create<sem::Struct>(a_impl, a_impl->source, a_impl->name, utils::Empty,
+    auto* a_impl = create<ast::Struct>(Ident("a"), utils::Empty, utils::Empty);
+    auto* a = create<sem::Struct>(a_impl, a_impl->source, a_impl->name->symbol, utils::Empty,
                                   4u /* align */, 4u /* size */, 4u /* size_no_padding */);
-    auto* b_impl = create<ast::Struct>(Sym("b"), utils::Empty, utils::Empty);
-    auto* b = create<sem::Struct>(b_impl, b_impl->source, b_impl->name, utils::Empty,
+    auto* b_impl = create<ast::Struct>(Ident("b"), utils::Empty, utils::Empty);
+    auto* b = create<sem::Struct>(b_impl, b_impl->source, b_impl->name->symbol, utils::Empty,
                                   4u /* align */, 4u /* size */, 4u /* size_no_padding */);
 
     EXPECT_TRUE(a->Equals(*a));
@@ -49,9 +49,9 @@
 
 TEST_F(SemStructTest, FriendlyName) {
     auto name = Sym("my_struct");
-    auto* impl = create<ast::Struct>(name, utils::Empty, utils::Empty);
-    auto* s = create<sem::Struct>(impl, impl->source, impl->name, utils::Empty, 4u /* align */,
-                                  4u /* size */, 4u /* size_no_padding */);
+    auto* impl = create<ast::Struct>(Ident(name), utils::Empty, utils::Empty);
+    auto* s = create<sem::Struct>(impl, impl->source, impl->name->symbol, utils::Empty,
+                                  4u /* align */, 4u /* size */, 4u /* size_no_padding */);
     EXPECT_EQ(s->FriendlyName(Symbols()), "my_struct");
 }
 
diff --git a/src/tint/transform/add_block_attribute.cc b/src/tint/transform/add_block_attribute.cc
index f79e120..e2a0c00 100644
--- a/src/tint/transform/add_block_attribute.cc
+++ b/src/tint/transform/add_block_attribute.cc
@@ -72,7 +72,7 @@
                 auto* block = b.ASTNodes().Create<BlockAttribute>(b.ID(), b.AllocateNodeID());
                 auto wrapper_name = src->Symbols().NameFor(global->name->symbol) + "_block";
                 auto* ret = b.create<ast::Struct>(
-                    b.Symbols().New(wrapper_name),
+                    b.Ident(b.Symbols().New(wrapper_name)),
                     utils::Vector{b.Member(kMemberName, CreateASTTypeFor(ctx, ty))},
                     utils::Vector{block});
                 ctx.InsertBefore(src->AST().GlobalDeclarations(), global, ret);
diff --git a/src/tint/transform/canonicalize_entry_point_io.cc b/src/tint/transform/canonicalize_entry_point_io.cc
index c19c9ad..f51d4cc 100644
--- a/src/tint/transform/canonicalize_entry_point_io.cc
+++ b/src/tint/transform/canonicalize_entry_point_io.cc
@@ -455,7 +455,8 @@
 
         // Create the new struct type.
         auto struct_name = ctx.dst->Sym();
-        auto* in_struct = ctx.dst->create<ast::Struct>(struct_name, members, utils::Empty);
+        auto* in_struct = ctx.dst->create<ast::Struct>(ctx.dst->Ident(struct_name),
+                                                       std::move(members), utils::Empty);
         ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), func_ast, in_struct);
 
         // Create a new function parameter using this struct type.
@@ -499,11 +500,12 @@
         }
 
         // Create the new struct type.
-        auto* out_struct = ctx.dst->create<ast::Struct>(ctx.dst->Sym(), members, utils::Empty);
+        auto* out_struct = ctx.dst->create<ast::Struct>(ctx.dst->Ident(ctx.dst->Sym()),
+                                                        std::move(members), utils::Empty);
         ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), func_ast, out_struct);
 
         // Create the output struct object, assign its members, and return it.
-        auto* result_object = ctx.dst->Var(wrapper_result, ctx.dst->ty(out_struct->name));
+        auto* result_object = ctx.dst->Var(wrapper_result, ctx.dst->ty(out_struct->name->symbol));
         wrapper_body.Push(ctx.dst->Decl(result_object));
         for (auto* assignment : assignments) {
             wrapper_body.Push(assignment);
@@ -634,7 +636,9 @@
                 CreateGlobalOutputVariables();
             } else {
                 auto* output_struct = CreateOutputStruct();
-                wrapper_ret_type = [&, output_struct] { return ctx.dst->ty(output_struct->name); };
+                wrapper_ret_type = [&, output_struct] {
+                    return ctx.dst->ty(output_struct->name->symbol);
+                };
             }
         }
 
diff --git a/src/tint/transform/renamer.cc b/src/tint/transform/renamer.cc
index 68807d3..7510520 100644
--- a/src/tint/transform/renamer.cc
+++ b/src/tint/transform/renamer.cc
@@ -1270,7 +1270,7 @@
             // Identifier *looks* like a builtin type, but check that the builtin type isn't being
             // shadowed with a user declared type.
             for (auto* decl : src->AST().TypeDecls()) {
-                if (decl->name == symbol) {
+                if (decl->name->symbol == symbol) {
                     return false;
                 }
             }
diff --git a/src/tint/transform/spirv_atomic.cc b/src/tint/transform/spirv_atomic.cc
index 06f1f7a..afbc5cb 100644
--- a/src/tint/transform/spirv_atomic.cc
+++ b/src/tint/transform/spirv_atomic.cc
@@ -156,7 +156,8 @@
     ForkedStruct& Fork(const ast::Struct* str) {
         auto& forked = forked_structs[str];
         if (!forked.name.IsValid()) {
-            forked.name = b.Symbols().New(ctx.src->Symbols().NameFor(str->name) + "_atomic");
+            forked.name =
+                b.Symbols().New(ctx.src->Symbols().NameFor(str->name->symbol) + "_atomic");
         }
         return forked;
     }
diff --git a/src/tint/transform/std140.cc b/src/tint/transform/std140.cc
index 151a437..825685e 100644
--- a/src/tint/transform/std140.cc
+++ b/src/tint/transform/std140.cc
@@ -335,7 +335,7 @@
                     // Create a new forked structure, and insert it just under the original
                     // structure.
                     auto name = b.Symbols().New(sym.NameFor(str->Name()) + "_std140");
-                    auto* std140 = b.create<ast::Struct>(name, std::move(members),
+                    auto* std140 = b.create<ast::Struct>(b.Ident(name), std::move(members),
                                                          ctx.Clone(str->Declaration()->attributes));
                     ctx.InsertAfter(src->AST().GlobalDeclarations(), global, std140);
                     std140_structs.Add(str, name);
diff --git a/src/tint/transform/transform.cc b/src/tint/transform/transform.cc
index 277d2e3..78b5373 100644
--- a/src/tint/transform/transform.cc
+++ b/src/tint/transform/transform.cc
@@ -122,7 +122,7 @@
                 if (auto* alias = type_decl->As<ast::Alias>()) {
                     if (ty == ctx.src->Sem().Get(alias)) {
                         // Alias found. Use the alias name to ensure types compare equal.
-                        return ctx.dst->ty(ctx.Clone(alias->name));
+                        return ctx.dst->ty(ctx.Clone(alias->name->symbol));
                     }
                 }
             }
@@ -138,7 +138,7 @@
         return ctx.dst->ty.array(el, u32(count.value()), std::move(attrs));
     }
     if (auto* s = ty->As<sem::Struct>()) {
-        return ctx.dst->ty(ctx.Clone(s->Declaration()->name));
+        return ctx.dst->ty(ctx.Clone(s->Declaration()->name->symbol));
     }
     if (auto* s = ty->As<type::Reference>()) {
         return CreateASTTypeFor(ctx, s->StoreType());
diff --git a/src/tint/transform/transform_test.cc b/src/tint/transform/transform_test.cc
index bdb2dc8..66be7c6 100644
--- a/src/tint/transform/transform_test.cc
+++ b/src/tint/transform/transform_test.cc
@@ -122,8 +122,8 @@
 TEST_F(CreateASTTypeForTest, Struct) {
     auto* str = create([](ProgramBuilder& b) {
         auto* decl = b.Structure("S", {});
-        return b.create<sem::Struct>(decl, decl->source, decl->name, utils::Empty, 4u /* align */,
-                                     4u /* size */, 4u /* size_no_padding */);
+        return b.create<sem::Struct>(decl, decl->source, decl->name->symbol, utils::Empty,
+                                     4u /* align */, 4u /* size */, 4u /* size_no_padding */);
     });
     ASSERT_TRUE(str->Is<ast::TypeName>());
     EXPECT_EQ(ast_type_builder.Symbols().NameFor(str->As<ast::TypeName>()->name->symbol), "S");
diff --git a/src/tint/writer/wgsl/generator_impl.cc b/src/tint/writer/wgsl/generator_impl.cc
index f0d3980..16523dc 100644
--- a/src/tint/writer/wgsl/generator_impl.cc
+++ b/src/tint/writer/wgsl/generator_impl.cc
@@ -124,7 +124,7 @@
         ty,
         [&](const ast::Alias* alias) {  //
             auto out = line();
-            out << "alias " << program_->Symbols().NameFor(alias->name) << " = ";
+            out << "alias " << program_->Symbols().NameFor(alias->name->symbol) << " = ";
             if (!EmitType(out, alias->type)) {
                 return false;
             }
@@ -606,7 +606,7 @@
             return false;
         }
     }
-    line() << "struct " << program_->Symbols().NameFor(str->name) << " {";
+    line() << "struct " << program_->Symbols().NameFor(str->name->symbol) << " {";
 
     auto add_padding = [&](uint32_t size) {
         line() << "@size(" << size << ")";