Resolver: Generate mapping for ast::Type -> sem::Type

Currently untestable as nothing currently calls Type(const ast::Type* ty).

Bug: tint:724
Change-Id: I92dd772acd758b0960a7e9a19f15c91414ab505c
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/49527
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/program.cc b/src/program.cc
index a0703e8..9029bb5 100644
--- a/src/program.cc
+++ b/src/program.cc
@@ -107,6 +107,10 @@
   return sem ? sem->Type() : nullptr;
 }
 
+const sem::Type* Program::TypeOf(const ast::Type* type) const {
+  return Sem().Get(type);
+}
+
 std::string Program::to_str(bool demangle) const {
   AssertNotMoved();
   auto str = ast_->to_str(Sem());
diff --git a/src/program.h b/src/program.h
index 3cdc081..c321e35 100644
--- a/src/program.h
+++ b/src/program.h
@@ -131,6 +131,12 @@
   /// expression has no resolved type.
   sem::Type* TypeOf(const ast::Expression* expr) const;
 
+  /// Helper for returning the resolved semantic type of the AST type `type`.
+  /// @param expr the AST type
+  /// @return the resolved semantic type for the type, or nullptr if the type
+  /// has no resolved type.
+  const sem::Type* TypeOf(const ast::Type* expr) const;
+
   /// @param demangle whether to automatically demangle the symbols in the
   /// returned string
   /// @returns a string describing this program.
diff --git a/src/program_builder.cc b/src/program_builder.cc
index c16f878..47dbd99 100644
--- a/src/program_builder.cc
+++ b/src/program_builder.cc
@@ -86,11 +86,15 @@
   }
 }
 
-sem::Type* ProgramBuilder::TypeOf(ast::Expression* expr) const {
+sem::Type* ProgramBuilder::TypeOf(const ast::Expression* expr) const {
   auto* sem = Sem().Get(expr);
   return sem ? sem->Type() : nullptr;
 }
 
+const sem::Type* ProgramBuilder::TypeOf(const ast::Type* type) const {
+  return Sem().Get(type);
+}
+
 ast::ConstructorExpression* ProgramBuilder::ConstructValueFilledWith(
     typ::Type type,
     int elem_value) {
diff --git a/src/program_builder.h b/src/program_builder.h
index 4a18623..1805696 100644
--- a/src/program_builder.h
+++ b/src/program_builder.h
@@ -1788,7 +1788,15 @@
   /// @param expr the AST expression
   /// @return the resolved semantic type for the expression, or nullptr if the
   /// expression has no resolved type.
-  sem::Type* TypeOf(ast::Expression* expr) const;
+  sem::Type* TypeOf(const ast::Expression* expr) const;
+
+  /// Helper for returning the resolved semantic type of the AST type `type`.
+  /// @note As the Resolver is run when the Program is built, this will only be
+  /// useful for the Resolver itself and tests that use their own Resolver.
+  /// @param expr the AST type
+  /// @return the resolved semantic type for the type, or nullptr if the type
+  /// has no resolved type.
+  const sem::Type* TypeOf(const ast::Type* expr) const;
 
   /// Wraps the ast::Literal in a statement. This is used by tests that
   /// construct a partial AST and require the Resolver to reach these
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index f767c86..0dfea86 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -274,69 +274,116 @@
   return true;
 }
 
-sem::Type* Resolver::Type(const ast::Type* ty) {
+const sem::Type* Resolver::Type(const ast::Type* ty) {
   Mark(ty);
-  sem::Type* s = nullptr;
-  if (ty->Is<ast::Void>()) {
-    s = builder_->create<sem::Void>();
-  } else if (ty->Is<ast::Bool>()) {
-    s = builder_->create<sem::Bool>();
-  } else if (ty->Is<ast::I32>()) {
-    s = builder_->create<sem::I32>();
-  } else if (ty->Is<ast::U32>()) {
-    s = builder_->create<sem::U32>();
-  } else if (ty->Is<ast::F32>()) {
-    s = builder_->create<sem::F32>();
-  } else if (auto* alias = ty->As<ast::Alias>()) {
-    auto* el = Type(alias->type());
-    s = builder_->create<sem::Alias>(alias->symbol(), el);
-  } else if (auto* access = ty->As<ast::AccessControl>()) {
-    auto* el = Type(access->type());
-    s = builder_->create<sem::AccessControl>(access->access_control(), el);
-  } else if (auto* vec = ty->As<ast::Vector>()) {
-    auto* el = Type(vec->type());
-    s = builder_->create<sem::Vector>(el, vec->size());
-  } else if (auto* mat = ty->As<ast::Matrix>()) {
-    auto* el = Type(mat->type());
-    s = builder_->create<sem::Matrix>(el, mat->rows(), mat->columns());
-  } else if (auto* arr = ty->As<ast::Array>()) {
-    auto* el = Type(arr->type());
-    s = builder_->create<sem::ArrayType>(el, arr->size(), arr->decorations());
-  } else if (auto* ptr = ty->As<ast::Pointer>()) {
-    auto* el = Type(ptr->type());
-    s = builder_->create<sem::Pointer>(el, ptr->storage_class());
-  } else if (auto* str = ty->As<ast::Struct>()) {
-    s = builder_->create<sem::StructType>(const_cast<ast::Struct*>(str));
-  } else if (auto* sampler = ty->As<ast::Sampler>()) {
-    s = builder_->create<sem::Sampler>(sampler->kind());
-  } else if (auto* sampled_tex = ty->As<ast::SampledTexture>()) {
-    auto* el = Type(sampled_tex->type());
-    s = builder_->create<sem::SampledTexture>(sampled_tex->dim(), el);
-  } else if (auto* depth_tex = ty->As<ast::DepthTexture>()) {
-    s = builder_->create<sem::DepthTexture>(depth_tex->dim());
-  } else if (auto* storage_tex = ty->As<ast::StorageTexture>()) {
-    auto* el = Type(storage_tex->type());
-    s = builder_->create<sem::StorageTexture>(storage_tex->dim(),
-                                              storage_tex->image_format(), el);
-  }
+  auto* s = [&]() -> const sem::Type* {
+    if (ty->Is<ast::Void>()) {
+      return builder_->create<sem::Void>();
+    }
+    if (ty->Is<ast::Bool>()) {
+      return builder_->create<sem::Bool>();
+    }
+    if (ty->Is<ast::I32>()) {
+      return builder_->create<sem::I32>();
+    }
+    if (ty->Is<ast::U32>()) {
+      return builder_->create<sem::U32>();
+    }
+    if (ty->Is<ast::F32>()) {
+      return builder_->create<sem::F32>();
+    }
+    if (auto* t = ty->As<ast::Alias>()) {
+      return Type(t->type());
+    }
+    if (auto* t = ty->As<ast::AccessControl>()) {
+      if (auto* el = Type(t->type())) {
+        return builder_->create<sem::AccessControl>(t->access_control(),
+                                                    const_cast<sem::Type*>(el));
+      }
+      return nullptr;
+    }
+    if (auto* t = ty->As<ast::Vector>()) {
+      if (auto* el = Type(t->type())) {
+        return builder_->create<sem::Vector>(const_cast<sem::Type*>(el),
+                                             t->size());
+      }
+      return nullptr;
+    }
+    if (auto* t = ty->As<ast::Matrix>()) {
+      if (auto* el = Type(t->type())) {
+        return builder_->create<sem::Matrix>(const_cast<sem::Type*>(el),
+                                             t->rows(), t->columns());
+      }
+      return nullptr;
+    }
+    if (auto* t = ty->As<ast::Array>()) {
+      if (auto* el = Type(t->type())) {
+        return builder_->create<sem::ArrayType>(const_cast<sem::Type*>(el),
+                                                t->size(), t->decorations());
+      }
+      return nullptr;
+    }
+    if (auto* t = ty->As<ast::Pointer>()) {
+      if (auto* el = Type(t->type())) {
+        return builder_->create<sem::Pointer>(const_cast<sem::Type*>(el),
+                                              t->storage_class());
+      }
+      return nullptr;
+    }
+    if (auto* t = ty->As<ast::Struct>()) {
+      return builder_->create<sem::StructType>(const_cast<ast::Struct*>(t));
+    }
+    if (auto* t = ty->As<ast::Sampler>()) {
+      return builder_->create<sem::Sampler>(t->kind());
+    }
+    if (auto* t = ty->As<ast::SampledTexture>()) {
+      if (auto* el = Type(t->type())) {
+        return builder_->create<sem::SampledTexture>(
+            t->dim(), const_cast<sem::Type*>(el));
+      }
+      return nullptr;
+    }
+    if (auto* t = ty->As<ast::MultisampledTexture>()) {
+      if (auto* el = Type(t->type())) {
+        return builder_->create<sem::MultisampledTexture>(
+            t->dim(), const_cast<sem::Type*>(el));
+      }
+      return nullptr;
+    }
+    if (auto* t = ty->As<ast::DepthTexture>()) {
+      return builder_->create<sem::DepthTexture>(t->dim());
+    }
+    if (auto* t = ty->As<ast::StorageTexture>()) {
+      if (auto* el = Type(t->type())) {
+        return builder_->create<sem::StorageTexture>(
+            t->dim(), t->image_format(), const_cast<sem::Type*>(el));
+      }
+      return nullptr;
+    }
+    TINT_UNREACHABLE(diagnostics_)
+        << "Unhandled ast::Type: " << ty->TypeInfo().name;
+    return nullptr;
+  }();
+
   if (s == nullptr) {
     return nullptr;
   }
-  if (!Type(s)) {
+  if (!Type(s, ty->source())) {
     return nullptr;
   }
+  builder_->Sem().Add(ty, s);
   return s;
 }
 
-// TODO(crbug.com/tint/724): This method should be replaced by Type(ast::Type*)
-bool Resolver::Type(sem::Type* ty) {
+// TODO(crbug.com/tint/724): This method should be merged into Type(ast::Type*)
+bool Resolver::Type(const sem::Type* ty, const Source& source /* = {} */) {
   ty = ty->UnwrapAliasIfNeeded();
   if (auto* str = ty->As<sem::StructType>()) {
     if (!Structure(str)) {
       return false;
     }
   } else if (auto* arr = ty->As<sem::ArrayType>()) {
-    if (!Array(arr, Source{})) {
+    if (!Array(arr, source)) {
       return false;
     }
   }
diff --git a/src/resolver/resolver.h b/src/resolver/resolver.h
index ad2635c..823361b 100644
--- a/src/resolver/resolver.h
+++ b/src/resolver/resolver.h
@@ -236,7 +236,7 @@
   bool Statement(ast::Statement*);
   bool Statements(const ast::StatementList&);
   bool Switch(ast::SwitchStatement* s);
-  bool Type(sem::Type* ty);
+  bool Type(const sem::Type* ty, const Source& source = {});
   bool UnaryOp(ast::UnaryOpExpression*);
   bool VariableDeclStatement(const ast::VariableDeclStatement*);
 
@@ -268,7 +268,7 @@
   /// hasn't been constructed already. If an error is raised, nullptr is
   /// returned.
   /// @param ty the ast::Type
-  sem::Type* Type(const ast::Type* ty);
+  const sem::Type* Type(const ast::Type* ty);
 
   /// @returns the semantic information for the array `arr`, building it if it
   /// hasn't been constructed already. If an error is raised, nullptr is
diff --git a/src/sem/info.h b/src/sem/info.h
index b442df2..dfb26f2 100644
--- a/src/sem/info.h
+++ b/src/sem/info.h
@@ -88,7 +88,9 @@
   }
 
  private:
-  std::unordered_map<const CastableBase*, const sem::Node*> map;
+  // 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;
 };
 
 }  // namespace sem
diff --git a/src/sem/type_mappings.h b/src/sem/type_mappings.h
index 52a1abd..94bda9b 100644
--- a/src/sem/type_mappings.h
+++ b/src/sem/type_mappings.h
@@ -27,6 +27,7 @@
 class MemberAccessorExpression;
 class Statement;
 class StructMember;
+class Type;
 class Variable;
 }  // namespace ast
 
@@ -42,6 +43,7 @@
 class Struct;
 class StructType;
 class StructMember;
+class Type;
 class Variable;
 
 /// TypeMappings is a struct that holds undefined `operator()` methods that's
@@ -58,6 +60,7 @@
   Statement* operator()(ast::Statement*);
   Struct* operator()(sem::StructType*);
   StructMember* operator()(ast::StructMember*);
+  Type* operator()(ast::Type*);
   Variable* operator()(ast::Variable*);
   //! @endcond
 };