Add sem::Module

Holds `DependencyOrderedDeclarations()`, which will hold the
sorted dependency-graph ordered list of global declarations.

Bug: tint:1266
Change-Id: I9840fae8689abd214973ea4785f71c3ae2587bbc
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/79766
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/BUILD.gn b/src/BUILD.gn
index 4f4b25b..7e67660 100644
--- a/src/BUILD.gn
+++ b/src/BUILD.gn
@@ -398,6 +398,7 @@
     "sem/info.h",
     "sem/loop_statement.h",
     "sem/matrix_type.h",
+    "sem/module.h",
     "sem/multisampled_texture_type.h",
     "sem/node.h",
     "sem/parameter_usage.h",
@@ -574,6 +575,8 @@
     "sem/matrix_type.cc",
     "sem/matrix_type.h",
     "sem/member_accessor_expression.cc",
+    "sem/module.cc",
+    "sem/module.h",
     "sem/multisampled_texture_type.cc",
     "sem/multisampled_texture_type.h",
     "sem/node.cc",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a5bc183..0e6f289 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -285,6 +285,8 @@
   sem/pipeline_stage_set.h
   sem/node.cc
   sem/node.h
+  sem/module.cc
+  sem/module.h
   sem/sampler_texture_pair.h
   sem/statement.cc
   sem/struct.cc
diff --git a/src/ast/module.cc b/src/ast/module.cc
index 3f06a31..bde9967 100644
--- a/src/ast/module.cc
+++ b/src/ast/module.cc
@@ -34,16 +34,8 @@
     if (decl == nullptr) {
       continue;
     }
-
-    Switch(
-        decl,  //
-        [&](const ast::TypeDecl* type) { type_decls_.push_back(type); },
-        [&](const Function* func) { functions_.push_back(func); },
-        [&](const Variable* var) { global_variables_.push_back(var); },
-        [&](Default) {
-          diag::List diagnostics;
-          TINT_ICE(AST, diagnostics) << "Unknown global declaration type";
-        });
+    diag::List diags;
+    BinGlobalDeclaration(decl, diags);
   }
 }
 
@@ -58,6 +50,33 @@
   return nullptr;
 }
 
+void Module::AddGlobalDeclaration(const tint::ast::Node* decl) {
+  diag::List diags;
+  BinGlobalDeclaration(decl, diags);
+  global_declarations_.emplace_back(decl);
+}
+
+void Module::BinGlobalDeclaration(const tint::ast::Node* decl,
+                                  diag::List& diags) {
+  Switch(
+      decl,  //
+      [&](const ast::TypeDecl* type) {
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id);
+        type_decls_.push_back(type);
+      },
+      [&](const Function* func) {
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, func, program_id);
+        functions_.push_back(func);
+      },
+      [&](const Variable* var) {
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, var, program_id);
+        global_variables_.push_back(var);
+      },
+      [&](Default) {
+        TINT_ICE(AST, diags) << "Unknown global declaration type";
+      });
+}
+
 void Module::AddGlobalVariable(const ast::Variable* var) {
   TINT_ASSERT(AST, var);
   TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, var, program_id);
@@ -100,24 +119,7 @@
           << "src global declaration was nullptr";
       continue;
     }
-    Switch(
-        decl,
-        [&](const ast::TypeDecl* type) {
-          TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id);
-          type_decls_.push_back(type);
-        },
-        [&](const Function* func) {
-          TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, func, program_id);
-          functions_.push_back(func);
-        },
-        [&](const Variable* var) {
-          TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, var, program_id);
-          global_variables_.push_back(var);
-        },
-        [&](Default) {
-          TINT_ICE(AST, ctx->dst->Diagnostics())
-              << "Unknown global declaration type";
-        });
+    BinGlobalDeclaration(decl, ctx->dst->Diagnostics());
   }
 }
 
diff --git a/src/ast/module.h b/src/ast/module.h
index 012a73d..5a1d8e8 100644
--- a/src/ast/module.h
+++ b/src/ast/module.h
@@ -47,7 +47,7 @@
   /// Destructor
   ~Module() override;
 
-  /// @returns the ordered global declarations for the translation unit
+  /// @returns the declaration-ordered global declarations for the module
   const std::vector<const Node*>& GlobalDeclarations() const {
     return global_declarations_;
   }
@@ -67,10 +67,14 @@
     return false;
   }
 
-  /// @returns the global variables for the translation unit
+  /// Adds a global declaration to the Builder.
+  /// @param decl the declaration to add
+  void AddGlobalDeclaration(const tint::ast::Node* decl);
+
+  /// @returns the global variables for the module
   const VariableList& GlobalVariables() const { return global_variables_; }
 
-  /// @returns the global variables for the translation unit
+  /// @returns the global variables for the module
   VariableList& GlobalVariables() { return global_variables_; }
 
   /// Adds a type declaration to the Builder.
@@ -81,14 +85,14 @@
   /// @param name the name of the type to search for
   const TypeDecl* LookupType(Symbol name) const;
 
-  /// @returns the declared types in the translation unit
+  /// @returns the declared types in the module
   const std::vector<const TypeDecl*>& TypeDecls() const { return type_decls_; }
 
   /// Add a function to the Builder
   /// @param func the function to add
   void AddFunction(const Function* func);
 
-  /// @returns the functions declared in the translation unit
+  /// @returns the functions declared in the module
   const FunctionList& Functions() const { return functions_; }
 
   /// Clones this node and all transitive child nodes using the `CloneContext`
@@ -103,6 +107,12 @@
   void Copy(CloneContext* ctx, const Module* src);
 
  private:
+  /// Adds `decl` to either:
+  /// * #global_declarations_
+  /// * #type_decls_
+  /// * #functions_
+  void BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags);
+
   std::vector<const Node*> global_declarations_;
   std::vector<const TypeDecl*> type_decls_;
   FunctionList functions_;
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index 05246ee..2a77c96 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -60,6 +60,7 @@
 #include "src/sem/if_statement.h"
 #include "src/sem/loop_statement.h"
 #include "src/sem/member_accessor_expression.h"
+#include "src/sem/module.h"
 #include "src/sem/multisampled_texture_type.h"
 #include "src/sem/pointer_type.h"
 #include "src/sem/reference_type.h"
@@ -99,6 +100,10 @@
     return false;
   }
 
+  // Create the semantic module
+  builder_->Sem().SetModule(
+      builder_->create<sem::Module>(dependencies_.ordered_globals));
+
   bool result = ResolveInternal();
 
   if (!result && !diagnostics_.contains_errors()) {
diff --git a/src/resolver/resolver_test.cc b/src/resolver/resolver_test.cc
index 239a77a..ba2add0 100644
--- a/src/resolver/resolver_test.cc
+++ b/src/resolver/resolver_test.cc
@@ -39,6 +39,7 @@
 #include "src/sem/call.h"
 #include "src/sem/function.h"
 #include "src/sem/member_accessor_expression.h"
+#include "src/sem/module.h"
 #include "src/sem/reference_type.h"
 #include "src/sem/sampled_texture_type.h"
 #include "src/sem/statement.h"
@@ -2161,6 +2162,28 @@
   EXPECT_TRUE(pairs[0].first != nullptr);
   EXPECT_TRUE(pairs[0].second == nullptr);
 }
+
+TEST_F(ResolverTest, ModuleDependencyOrderedDeclarations) {
+  auto* f0 = Func("f0", {}, ty.void_(), {});
+  auto* v0 = Global("v0", ty.i32(), ast::StorageClass::kPrivate);
+  auto* a0 = Alias("a0", ty.i32());
+  auto* s0 = Structure("s0", {Member("m", ty.i32())});
+  auto* f1 = Func("f1", {}, ty.void_(), {});
+  auto* v1 = Global("v1", ty.i32(), ast::StorageClass::kPrivate);
+  auto* a1 = Alias("a1", ty.i32());
+  auto* s1 = Structure("s1", {Member("m", ty.i32())});
+  auto* f2 = Func("f2", {}, ty.void_(), {});
+  auto* v2 = Global("v2", ty.i32(), ast::StorageClass::kPrivate);
+  auto* a2 = Alias("a2", ty.i32());
+  auto* s2 = Structure("s2", {Member("m", ty.i32())});
+
+  EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+  ASSERT_NE(Sem().Module(), nullptr);
+  EXPECT_THAT(Sem().Module()->DependencyOrderedDeclarations(),
+              ElementsAre(f0, v0, a0, s0, f1, v1, a1, s1, f2, v2, a2, s2));
+}
+
 }  // namespace
 }  // namespace resolver
 }  // namespace tint
diff --git a/src/sem/info.h b/src/sem/info.h
index 72e2d3e..232d252 100644
--- a/src/sem/info.h
+++ b/src/sem/info.h
@@ -22,8 +22,10 @@
 #include "src/sem/node.h"
 #include "src/sem/type_mappings.h"
 
-namespace tint {
-namespace sem {
+namespace tint::sem {
+
+// Forward declarations
+class Module;
 
 /// Info holds all the resolved semantic information for a Program.
 class Info {
@@ -60,8 +62,8 @@
             typename AST_OR_TYPE = CastableBase,
             typename RESULT = GetResultType<SEM, AST_OR_TYPE>>
   const RESULT* Get(const AST_OR_TYPE* node) const {
-    auto it = map.find(node);
-    if (it == map.end()) {
+    auto it = map_.find(node);
+    if (it == map_.end()) {
       return nullptr;
     }
     return As<RESULT>(it->second);
@@ -76,7 +78,7 @@
            const SemanticNodeTypeFor<AST_OR_TYPE>* sem_node) {
     // Check there's no semantic info already existing for the node
     TINT_ASSERT(Semantic, Get(node) == nullptr);
-    map.emplace(node, sem_node);
+    map_.emplace(node, sem_node);
   }
 
   /// Wrap returns a new Info created with the contents of `inner`.
@@ -88,17 +90,26 @@
   /// @return the Info that wraps `inner`
   static Info Wrap(const Info& inner) {
     Info out;
-    out.map = inner.map;
+    out.map_ = inner.map_;
+    out.module_ = inner.module_;
     return out;
   }
 
+  /// Assigns the semantic module.
+  /// @param module the module to assign.
+  void SetModule(sem::Module* module) { module_ = module; }
+
+  /// @returns the semantic module.
+  const sem::Module* Module() const { return module_; }
+
  private:
   // TODO(crbug.com/tint/724): Once finished, this map should be:
   // std::unordered_map<const ast::Node*, const sem::Node*>
-  std::unordered_map<const CastableBase*, const CastableBase*> map;
+  std::unordered_map<const CastableBase*, const CastableBase*> map_;
+  // The semantic module
+  sem::Module* module_ = nullptr;
 };
 
-}  // namespace sem
-}  // namespace tint
+}  // namespace tint::sem
 
 #endif  // SRC_SEM_INFO_H_
diff --git a/src/sem/module.cc b/src/sem/module.cc
new file mode 100644
index 0000000..48c348f
--- /dev/null
+++ b/src/sem/module.cc
@@ -0,0 +1,29 @@
+// Copyright 2022 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/sem/module.h"
+
+#include <utility>
+#include <vector>
+
+TINT_INSTANTIATE_TYPEINFO(tint::sem::Module);
+
+namespace tint::sem {
+
+Module::Module(std::vector<const ast::Node*> dep_ordered_decls)
+    : dep_ordered_decls_(std::move(dep_ordered_decls)) {}
+
+Module::~Module() = default;
+
+}  // namespace tint::sem
diff --git a/src/sem/module.h b/src/sem/module.h
new file mode 100644
index 0000000..07d7903
--- /dev/null
+++ b/src/sem/module.h
@@ -0,0 +1,52 @@
+// Copyright 2022 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_SEM_MODULE_H_
+#define SRC_SEM_MODULE_H_
+
+#include <vector>
+
+#include "src/sem/node.h"
+
+// Forward declarations
+namespace tint::ast {
+class Node;
+class Module;
+}  // namespace tint::ast
+
+namespace tint::sem {
+
+/// Module holds the top-level semantic types, functions and global variables
+/// used by a Program.
+class Module : public Castable<Module, Node> {
+ public:
+  /// Constructor
+  /// @param dep_ordered_decls the dependency-ordered module-scope declarations
+  explicit Module(std::vector<const ast::Node*> dep_ordered_decls);
+
+  /// Destructor
+  ~Module() override;
+
+  /// @returns the dependency-ordered global declarations for the module
+  const std::vector<const ast::Node*>& DependencyOrderedDeclarations() const {
+    return dep_ordered_decls_;
+  }
+
+ private:
+  const std::vector<const ast::Node*> dep_ordered_decls_;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_SEM_MODULE_H_