ProgramBuilder: New helpers,change WrapInStatement

Add AddressOf() and Deref()
Add overloads of Expr() that take a source
Change WrapInStatement() to create a `let`. Unlike `var`, `let` can be
used to hold pointers.

Bug: tint:727
Change-Id: Ib2cd7ab7a7056862e064943dea04387f7e466212
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/51183
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/program_builder.cc b/src/program_builder.cc
index a59b03a..6cf5eac 100644
--- a/src/program_builder.cc
+++ b/src/program_builder.cc
@@ -20,6 +20,7 @@
 #include "src/debug.h"
 #include "src/demangler.h"
 #include "src/sem/expression.h"
+#include "src/sem/variable.h"
 
 namespace tint {
 
@@ -90,6 +91,11 @@
   return sem ? sem->Type() : nullptr;
 }
 
+sem::Type* ProgramBuilder::TypeOf(const ast::Variable* var) const {
+  auto* sem = Sem().Get(var);
+  return sem ? sem->Type() : nullptr;
+}
+
 const sem::Type* ProgramBuilder::TypeOf(const ast::Type* type) const {
   return Sem().Get(type);
 }
@@ -162,8 +168,11 @@
 }
 
 ast::Statement* ProgramBuilder::WrapInStatement(ast::Expression* expr) {
+  if (auto* ce = expr->As<ast::CallExpression>()) {
+    return create<ast::CallStatement>(ce);
+  }
   // Create a temporary variable of inferred type from expr.
-  return Decl(Var(symbols_.New(), nullptr, ast::StorageClass::kFunction, expr));
+  return Decl(Const(symbols_.New(), nullptr, expr));
 }
 
 ast::VariableDeclStatement* ProgramBuilder::WrapInStatement(ast::Variable* v) {
diff --git a/src/program_builder.h b/src/program_builder.h
index 42375a9..74367bc 100644
--- a/src/program_builder.h
+++ b/src/program_builder.h
@@ -55,6 +55,7 @@
 #include "src/ast/type_name.h"
 #include "src/ast/u32.h"
 #include "src/ast/uint_literal.h"
+#include "src/ast/unary_op_expression.h"
 #include "src/ast/variable_decl_statement.h"
 #include "src/ast/vector.h"
 #include "src/ast/void.h"
@@ -920,10 +921,11 @@
   /// @return nullptr
   ast::IdentifierExpression* Expr(std::nullptr_t) { return nullptr; }
 
-  /// @param name the identifier name
-  /// @return an ast::IdentifierExpression with the given name
-  ast::IdentifierExpression* Expr(const std::string& name) {
-    return create<ast::IdentifierExpression>(Symbols().Register(name));
+  /// @param source the source information
+  /// @param symbol the identifier symbol
+  /// @return an ast::IdentifierExpression with the given symbol
+  ast::IdentifierExpression* Expr(const Source& source, Symbol symbol) {
+    return create<ast::IdentifierExpression>(source, symbol);
   }
 
   /// @param symbol the identifier symbol
@@ -932,6 +934,14 @@
     return create<ast::IdentifierExpression>(symbol);
   }
 
+  /// @param source the source information
+  /// @param variable the AST variable
+  /// @return an ast::IdentifierExpression with the variable's symbol
+  ast::IdentifierExpression* Expr(const Source& source,
+                                  ast::Variable* variable) {
+    return create<ast::IdentifierExpression>(source, variable->symbol());
+  }
+
   /// @param variable the AST variable
   /// @return an ast::IdentifierExpression with the variable's symbol
   ast::IdentifierExpression* Expr(ast::Variable* variable) {
@@ -941,6 +951,19 @@
   /// @param source the source information
   /// @param name the identifier name
   /// @return an ast::IdentifierExpression with the given name
+  ast::IdentifierExpression* Expr(const Source& source, const char* name) {
+    return create<ast::IdentifierExpression>(source, Symbols().Register(name));
+  }
+
+  /// @param name the identifier name
+  /// @return an ast::IdentifierExpression with the given name
+  ast::IdentifierExpression* Expr(const char* name) {
+    return create<ast::IdentifierExpression>(Symbols().Register(name));
+  }
+
+  /// @param source the source information
+  /// @param name the identifier name
+  /// @return an ast::IdentifierExpression with the given name
   ast::IdentifierExpression* Expr(const Source& source,
                                   const std::string& name) {
     return create<ast::IdentifierExpression>(source, Symbols().Register(name));
@@ -948,28 +971,56 @@
 
   /// @param name the identifier name
   /// @return an ast::IdentifierExpression with the given name
-  ast::IdentifierExpression* Expr(const char* name) {
+  ast::IdentifierExpression* Expr(const std::string& name) {
     return create<ast::IdentifierExpression>(Symbols().Register(name));
   }
 
+  /// @param source the source information
+  /// @param value the boolean value
+  /// @return a Scalar constructor for the given value
+  ast::ScalarConstructorExpression* Expr(const Source& source, bool value) {
+    return create<ast::ScalarConstructorExpression>(source, Literal(value));
+  }
+
   /// @param value the boolean value
   /// @return a Scalar constructor for the given value
   ast::ScalarConstructorExpression* Expr(bool value) {
     return create<ast::ScalarConstructorExpression>(Literal(value));
   }
 
+  /// @param source the source information
+  /// @param value the float value
+  /// @return a Scalar constructor for the given value
+  ast::ScalarConstructorExpression* Expr(const Source& source, f32 value) {
+    return create<ast::ScalarConstructorExpression>(source, Literal(value));
+  }
+
   /// @param value the float value
   /// @return a Scalar constructor for the given value
   ast::ScalarConstructorExpression* Expr(f32 value) {
     return create<ast::ScalarConstructorExpression>(Literal(value));
   }
 
+  /// @param source the source information
+  /// @param value the integer value
+  /// @return a Scalar constructor for the given value
+  ast::ScalarConstructorExpression* Expr(const Source& source, i32 value) {
+    return create<ast::ScalarConstructorExpression>(source, Literal(value));
+  }
+
   /// @param value the integer value
   /// @return a Scalar constructor for the given value
   ast::ScalarConstructorExpression* Expr(i32 value) {
     return create<ast::ScalarConstructorExpression>(Literal(value));
   }
 
+  /// @param source the source information
+  /// @param value the unsigned int value
+  /// @return a Scalar constructor for the given value
+  ast::ScalarConstructorExpression* Expr(const Source& source, u32 value) {
+    return create<ast::ScalarConstructorExpression>(source, Literal(value));
+  }
+
   /// @param value the unsigned int value
   /// @return a Scalar constructor for the given value
   ast::ScalarConstructorExpression* Expr(u32 value) {
@@ -1354,6 +1405,40 @@
     return var;
   }
 
+  /// @param source the source information
+  /// @param expr the expression to take the address of
+  /// @return an ast::UnaryOpExpression that takes the address of `expr`
+  template <typename EXPR>
+  ast::UnaryOpExpression* AddressOf(const Source& source, EXPR&& expr) {
+    return create<ast::UnaryOpExpression>(source, ast::UnaryOp::kAddressOf,
+                                          Expr(std::forward<EXPR>(expr)));
+  }
+
+  /// @param expr the expression to take the address of
+  /// @return an ast::UnaryOpExpression that takes the address of `expr`
+  template <typename EXPR>
+  ast::UnaryOpExpression* AddressOf(EXPR&& expr) {
+    return create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf,
+                                          Expr(std::forward<EXPR>(expr)));
+  }
+
+  /// @param source the source information
+  /// @param expr the expression to perform an indirection on
+  /// @return an ast::UnaryOpExpression that dereferences the pointer `expr`
+  template <typename EXPR>
+  ast::UnaryOpExpression* Deref(const Source& source, EXPR&& expr) {
+    return create<ast::UnaryOpExpression>(source, ast::UnaryOp::kIndirection,
+                                          Expr(std::forward<EXPR>(expr)));
+  }
+
+  /// @param expr the expression to perform an indirection on
+  /// @return an ast::UnaryOpExpression that dereferences the pointer `expr`
+  template <typename EXPR>
+  ast::UnaryOpExpression* Deref(EXPR&& expr) {
+    return create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection,
+                                          Expr(std::forward<EXPR>(expr)));
+  }
+
   /// @param func the function name
   /// @param args the function call arguments
   /// @returns a `ast::CallExpression` to the function `func`, with the
@@ -1845,6 +1930,14 @@
   /// expression has no resolved type.
   sem::Type* TypeOf(const ast::Expression* expr) const;
 
+  /// Helper for returning the resolved semantic type of the variable `var`.
+  /// @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 var the AST variable
+  /// @return the resolved semantic type for the variable, or nullptr if the
+  /// variable has no resolved type.
+  sem::Type* TypeOf(const ast::Variable* var) 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.
diff --git a/src/writer/hlsl/generator_impl_member_accessor_test.cc b/src/writer/hlsl/generator_impl_member_accessor_test.cc
index 8f0d658..423a046 100644
--- a/src/writer/hlsl/generator_impl_member_accessor_test.cc
+++ b/src/writer/hlsl/generator_impl_member_accessor_test.cc
@@ -128,7 +128,7 @@
   Global("str", s, ast::StorageClass::kPrivate);
 
   auto* expr = MemberAccessor("str", "mem");
-  WrapInFunction(expr);
+  WrapInFunction(Var("expr", ty.f32(), ast::StorageClass::kNone, expr));
 
   GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -141,7 +141,7 @@
 
 [numthreads(1, 1, 1)]
 void test_function() {
-  float tint_symbol = str.mem;
+  float expr = str.mem;
   return;
 }