[tint][ir] Gracefully handle Type() returning null in disassembler

Adds in a `NameOf()` implementation for `type::Type*` that handles
nulls. This is used to replace a bunch of potentially invalid
calls when building output text.

Also:
-Adds in some missing checks for loop initializer and continuing
blocks.
- Adds some missing null checks for usage of `Foo()->` pattern.

Fixes: 356297569
Change-Id: I3c8ae43cdefdd41ab1cf4954af100fbb4fa8fb47
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/200654
Auto-Submit: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: dan sinclair <dsinclair@google.com>
Commit-Queue: Ryan Harrison <rharrison@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 c6f4bac..ac1fba4 100644
--- a/src/tint/lang/core/ir/disassembler.cc
+++ b/src/tint/lang/core/ir/disassembler.cc
@@ -182,7 +182,7 @@
                     EmitValue(p);
                     psm.Store(p);
                 }
-                out_ << ":" << StyleType(p->Type()->FriendlyName());
+                out_ << ":" << NameOf(p->Type());
             }
             out_ << ")";
         }
@@ -338,12 +338,12 @@
             out_ << ", ";
         }
         SourceMarker sm(this);
-        out_ << NameOf(p) << ":" << StyleType(p->Type() ? p->Type()->FriendlyName() : "undef");
+        out_ << NameOf(p) << ":" << NameOf(p->Type());
         sm.Store(p);
 
         EmitParamAttributes(p);
     }
-    out_ << "):" << StyleType(func->ReturnType()->FriendlyName());
+    out_ << "):" << NameOf(func->ReturnType());
 
     EmitReturnAttributes(func);
 
@@ -388,12 +388,7 @@
 void Disassembler::EmitValueWithType(const Value* val) {
     EmitValue(val);
     if (val) {
-        out_ << ":";
-        if (val->Type()) {
-            out_ << StyleType(val->Type()->FriendlyName());
-        } else {
-            out_ << StyleType("null");
-        }
+        out_ << ":" << NameOf(val->Type());
     }
 }
 
@@ -425,12 +420,12 @@
                             out_ << StyleLiteral((scalar->ValueAs<bool>() ? "true" : "false"));
                         },
                         [&](const core::constant::Splat* splat) {
-                            out_ << StyleType(splat->Type()->FriendlyName()) << "(";
+                            out_ << NameOf(splat->Type()) << "(";
                             emit(splat->Index(0));
                             out_ << ")";
                         },
                         [&](const core::constant::Composite* composite) {
-                            out_ << StyleType(composite->Type()->FriendlyName()) << "(";
+                            out_ << NameOf(composite->Type()) << "(";
                             bool need_comma = false;
                             for (const auto* elem : composite->elements) {
                                 if (need_comma) {
@@ -641,7 +636,7 @@
     out_ << StyleInstruction("if") << " ";
     EmitOperand(if_, If::kConditionOperandOffset);
 
-    bool has_false = !if_->False()->IsEmpty();
+    bool has_false = if_->False() != nullptr && !if_->False()->IsEmpty();
 
     out_ << " [" << StyleKeyword("t") << ": " << NameOf(if_->True());
     if (has_false) {
@@ -691,14 +686,14 @@
     }
     out_ << StyleInstruction("loop") << " [";
 
-    if (!l->Initializer()->IsEmpty()) {
+    if (l->Initializer() != nullptr && !l->Initializer()->IsEmpty()) {
         out_ << StyleKeyword("i") << ": " << NameOf(l->Initializer());
         out_ << ", ";
     }
 
     out_ << StyleKeyword("b") << ": " << NameOf(l->Body());
 
-    if (!l->Continuing()->IsEmpty()) {
+    if (l->Continuing() != nullptr && !l->Continuing()->IsEmpty()) {
         out_ << ", ";
         out_ << StyleKeyword("c") << ": " << NameOf(l->Continuing());
     }
@@ -709,18 +704,17 @@
     out_ << " {  " << StyleComment("# ", NameOf(l));
     EmitLine();
 
-    if (!l->Initializer()->IsEmpty()) {
+    if (l->Initializer() != nullptr && !l->Initializer()->IsEmpty()) {
         ScopedIndent si(indent_size_);
         EmitBlock(l->Initializer(), "initializer");
     }
 
-    // Loop is assumed to always have a body
-    {
+    if (l->Body() != nullptr) {
         ScopedIndent si(indent_size_);
         EmitBlock(l->Body(), "body");
     }
 
-    if (!l->Continuing()->IsEmpty()) {
+    if (l->Continuing() != nullptr && !l->Continuing()->IsEmpty()) {
         ScopedIndent si(indent_size_);
         EmitBlock(l->Continuing(), "continuing");
     }
@@ -852,7 +846,8 @@
                                  ", f: ", NameOf(bi->Loop() ? bi->Loop()->Body() : nullptr), "]");
         },
         [&](const ir::Continue* c) {
-            out_ << "  " << StyleComment("# -> ", NameOf(c->Loop()->Continuing()));
+            out_ << "  "
+                 << StyleComment("# -> ", NameOf(c->Loop() ? c->Loop()->Continuing() : nullptr));
         },                                                                                  //
         [&](const ir::ExitIf* e) { out_ << "  " << StyleComment("# ", NameOf(e->If())); },  //
         [&](const ir::ExitSwitch* e) {
@@ -892,8 +887,7 @@
     out_ << " {";
     EmitLine();
     for (auto* member : str->Members()) {
-        out_ << "  " << StyleVariable(member->Name().Name()) << ":"
-             << StyleType(member->Type()->FriendlyName());
+        out_ << "  " << StyleVariable(member->Name().Name()) << ":" << NameOf(member->Type());
         out_ << " " << StyleAttribute("@offset") << "(" << StyleLiteral(member->Offset()) << ")";
         if (member->Attributes().invariant) {
             out_ << ", " << StyleAttribute("@invariant");
@@ -925,6 +919,14 @@
     EmitLine();
 }
 
+StyledText Disassembler::NameOf(const type::Type* ty) {
+    if (!ty) {
+        return StyledText{} << StyleError("undef");
+    }
+
+    return StyledText{} << StyleType(ty->FriendlyName());
+}
+
 StyledText Disassembler::NameOf(const Block* node) {
     if (!node) {
         return StyledText{} << StyleError("undef");
diff --git a/src/tint/lang/core/ir/disassembler.h b/src/tint/lang/core/ir/disassembler.h
index b96f496..53e8fcc 100644
--- a/src/tint/lang/core/ir/disassembler.h
+++ b/src/tint/lang/core/ir/disassembler.h
@@ -94,6 +94,9 @@
     /// @returns the disassembly file
     const std::shared_ptr<Source::File>& File() const { return file_; }
 
+    /// @returns the disassembled name for the Type @p ty
+    StyledText NameOf(const type::Type* ty);
+
     /// @returns the disassembled name for the Block @p blk
     StyledText NameOf(const Block* blk);
 
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index 1ba3dcc..2b4a95a 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -2320,8 +2320,8 @@
     ASSERT_NE(res, Success);
     EXPECT_EQ(res.Failure().reason.Str(),
               R"(:4:5 error: load: result type is undefined
-    %3:null = load %i
-    ^^^^^^^
+    %3:undef = load %i
+    ^^^^^^^^
 
 :2:3 note: in block
   $B1: {
@@ -2339,7 +2339,7 @@
 %my_func = func():void {
   $B1: {
     %i:ptr<function, f32, read_write> = var, 0.0f
-    %3:null = load %i
+    %3:undef = load %i
     %j:ptr<function, f32, read_write> = var, %3
     ret
   }
@@ -5781,7 +5781,7 @@
 %my_func = func():void {
   $B1: {
     %2:ptr<function, i32, read_write> = var
-    %3:null = construct 42u
+    %3:undef = construct 42u
     store %2, %3
     ret
   }