Add semantic::Statement

Add Stmt() accessor on all semantic::Expressions so the owning statement can be retrieved.

Change-Id: I5d584335a6d137fdeab0b8d74a161fcae9b46080
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/41545
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Auto-Submit: Ben Clayton <bclayton@google.com>
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index a127caa..1bb2d4c 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -47,6 +47,7 @@
 #include "src/semantic/function.h"
 #include "src/semantic/intrinsic.h"
 #include "src/semantic/member_accessor_expression.h"
+#include "src/semantic/statement.h"
 #include "src/semantic/variable.h"
 #include "src/type/array_type.h"
 #include "src/type/bool_type.h"
@@ -69,6 +70,23 @@
 
 using IntrinsicType = tint::semantic::IntrinsicType;
 
+// Helper class that temporarily assigns a value to a reference for the scope of
+// the object. Once the ScopedAssignment is destructed, the original value is
+// restored.
+template <typename T>
+class ScopedAssignment {
+ public:
+  ScopedAssignment(T& ref, T val) : ref_(ref) {
+    old_value_ = ref;
+    ref = val;
+  }
+  ~ScopedAssignment() { ref_ = old_value_; }
+
+ private:
+  T& ref_;
+  T old_value_;
+};
+
 }  // namespace
 
 TypeDeterminer::TypeDeterminer(ProgramBuilder* builder)
@@ -171,9 +189,11 @@
 }
 
 bool TypeDeterminer::DetermineFunction(ast::Function* func) {
-  current_function_ = function_infos_.Create<FunctionInfo>(func);
-  symbol_to_function_[func->symbol()] = current_function_;
-  function_to_info_.emplace(func, current_function_);
+  auto* func_info = function_infos_.Create<FunctionInfo>(func);
+  symbol_to_function_[func->symbol()] = func_info;
+  function_to_info_.emplace(func, func_info);
+
+  ScopedAssignment<FunctionInfo*> sa(current_function_, func_info);
 
   variable_stack_.push_scope();
   for (auto* param : func->params()) {
@@ -185,8 +205,6 @@
   }
   variable_stack_.pop_scope();
 
-  current_function_ = nullptr;
-
   return true;
 }
 
@@ -234,6 +252,10 @@
 }
 
 bool TypeDeterminer::DetermineResultType(ast::Statement* stmt) {
+  auto* sem_statement = builder_->create<semantic::Statement>(stmt);
+
+  ScopedAssignment<semantic::Statement*> sa(current_statement_, sem_statement);
+
   if (auto* a = stmt->As<ast::AssignmentStatement>()) {
     return DetermineResultType(a->lhs()) && DetermineResultType(a->rhs());
   }
@@ -451,7 +473,8 @@
     }
 
     auto* function = iter->second;
-    function_calls_.emplace(call, function);
+    function_calls_.emplace(call,
+                            FunctionCallInfo{function, current_statement_});
     SetType(call, function->declaration->return_type());
   }
 
@@ -501,12 +524,14 @@
     }
     auto* intrinsic = builder_->create<semantic::Intrinsic>(intrinsic_type,
                                                             ret_ty, parameters);
-    builder_->Sem().Add(call, builder_->create<semantic::Call>(intrinsic));
+    builder_->Sem().Add(
+        call, builder_->create<semantic::Call>(intrinsic, current_statement_));
     SetType(call, ret_ty);
     return false;
   }
 
-  builder_->Sem().Add(call, builder_->create<semantic::Call>(result.intrinsic));
+  builder_->Sem().Add(call, builder_->create<semantic::Call>(
+                                result.intrinsic, current_statement_));
   SetType(call, result.intrinsic->ReturnType());
   return true;
 }
@@ -791,9 +816,9 @@
     return false;
   }
 
-  builder_->Sem().Add(
-      expr,
-      builder_->create<semantic::MemberAccessorExpression>(ret, is_swizzle));
+  builder_->Sem().Add(expr,
+                      builder_->create<semantic::MemberAccessorExpression>(
+                          ret, current_statement_, is_swizzle));
   SetType(expr, ret);
 
   return true;
@@ -890,16 +915,16 @@
 }
 
 type::Type* TypeDeterminer::TypeOf(ast::Expression* expr) {
-  auto it = expr_types_.find(expr);
-  if (it != expr_types_.end()) {
-    return it->second;
+  auto it = expr_info_.find(expr);
+  if (it != expr_info_.end()) {
+    return it->second.type;
   }
   return nullptr;
 }
 
 void TypeDeterminer::SetType(ast::Expression* expr, type::Type* type) {
-  assert(expr_types_.count(expr) == 0);
-  expr_types_.emplace(expr, type);
+  assert(expr_info_.count(expr) == 0);
+  expr_info_.emplace(expr, ExpressionInfo{type, current_statement_});
 }
 
 void TypeDeterminer::CreateSemanticNodes() const {
@@ -938,20 +963,21 @@
   // Create semantic nodes for all ast::CallExpressions
   for (auto it : function_calls_) {
     auto* call = it.first;
-    auto* func_info = it.second;
-    auto* sem_func = func_info_to_sem_func.at(func_info);
-    sem.Add(call, builder_->create<semantic::Call>(sem_func));
+    auto info = it.second;
+    auto* sem_func = func_info_to_sem_func.at(info.function);
+    sem.Add(call, builder_->create<semantic::Call>(sem_func, info.statement));
   }
 
   // Create semantic nodes for all remaining expression types
-  for (auto it : expr_types_) {
+  for (auto it : expr_info_) {
     auto* expr = it.first;
-    auto* type = it.second;
+    auto& info = it.second;
     if (sem.Get(expr)) {
       // Expression has already been assigned a semantic node
       continue;
     }
-    sem.Add(expr, builder_->create<semantic::Expression>(type));
+    sem.Add(expr,
+            builder_->create<semantic::Expression>(info.type, info.statement));
   }
 }