[ir] Validate store and value types exist for Store instructions.

When validating store instructions, make sure the value and store types
exist, otherwise we may try to emit an error if they aren't equal and
fail because we can't get the friendly name.

Change-Id: I0a8ead622c944290f98bb6ef3e8c89d9d4ecedd1
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/197498
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/core/ir/disassembler.cc b/src/tint/lang/core/ir/disassembler.cc
index 656d4a9..6e0ee31 100644
--- a/src/tint/lang/core/ir/disassembler.cc
+++ b/src/tint/lang/core/ir/disassembler.cc
@@ -384,7 +384,12 @@
 void Disassembler::EmitValueWithType(const Value* val) {
     EmitValue(val);
     if (val) {
-        out_ << ":" << StyleType(val->Type()->FriendlyName());
+        out_ << ":";
+        if (val->Type()) {
+            out_ << StyleType(val->Type()->FriendlyName());
+        } else {
+            out_ << StyleType("null");
+        }
     }
 }
 
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index 263d192..9a65a25 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -1056,7 +1056,7 @@
         return;
     }
 
-    if (auto* str = construct->Result(0)->Type()->As<type::Struct>()) {
+    if (auto* str = As<type::Struct>(construct->Result(0)->Type())) {
         auto members = str->Members();
         if (args.Length() != str->Members().Length()) {
             AddError(construct) << "structure has " << members.Length()
@@ -1593,14 +1593,21 @@
 
     if (auto* from = s->From()) {
         if (auto* to = s->To()) {
-            auto* mv = to->Type()->As<core::type::MemoryView>();
+            auto* mv = As<core::type::MemoryView>(to->Type());
             if (!mv) {
                 AddError(s, Store::kToOperandOffset) << "store target operand is not a memory view";
                 return;
             }
             auto* value_type = from->Type();
             auto* store_type = mv->StoreType();
-            if (value_type != store_type) {
+
+            if (!store_type) {
+                AddError(s, Store::kToOperandOffset) << "store type must not be null";
+            }
+            if (!value_type) {
+                AddError(s, Store::kFromOperandOffset) << "value type must not be null";
+            }
+            if (store_type && value_type && value_type != store_type) {
                 AddError(s, Store::kFromOperandOffset)
                     << "value type " << style::Type(value_type->FriendlyName())
                     << " does not match store type " << style::Type(store_type->FriendlyName());
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index e4f0865..20106df 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -4797,6 +4797,73 @@
 )");
 }
 
+TEST_F(IR_ValidatorTest, Store_NoStoreType) {
+    auto* f = b.Function("my_func", ty.void_());
+
+    b.Append(f->Block(), [&] {
+        auto* var = b.Var(ty.ptr<function, i32>());
+        var->Result(0)->SetType(nullptr);
+        b.Append(mod.allocators.instructions.Create<ir::Store>(var->Result(0), b.Constant(42_u)));
+        b.Return(f);
+    });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_EQ(res.Failure().reason.Str(),
+              R"(:4:11 error: store: store target operand is not a memory view
+    store %2, 42u
+          ^^
+
+:2:3 note: in block
+  $B1: {
+  ^^^
+
+note: # Disassembly
+%my_func = func():void {
+  $B1: {
+    %2:null = var
+    store %2, 42u
+    ret
+  }
+}
+)");
+}
+
+TEST_F(IR_ValidatorTest, Store_NoValueType) {
+    auto* f = b.Function("my_func", ty.void_());
+
+    b.Append(f->Block(), [&] {
+        auto* var = b.Var(ty.ptr<function, i32>());
+        auto* val = b.Construct(ty.u32(), 42_u);
+        val->Result(0)->SetType(nullptr);
+
+        b.Append(mod.allocators.instructions.Create<ir::Store>(var->Result(0), val->Result(0)));
+        b.Return(f);
+    });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_EQ(res.Failure().reason.Str(),
+              R"(:5:15 error: store: value type must not be null
+    store %2, %3
+              ^^
+
+:2:3 note: in block
+  $B1: {
+  ^^^
+
+note: # Disassembly
+%my_func = func():void {
+  $B1: {
+    %2:ptr<function, i32, read_write> = var
+    %3:null = construct 42u
+    store %2, %3
+    ret
+  }
+}
+)");
+}
+
 TEST_F(IR_ValidatorTest, LoadVectorElement_NullResult) {
     auto* f = b.Function("my_func", ty.void_());