resolver: Fix for-loop conditional validation

It wasn't unwrapping the reference before type checking

Change-Id: I4bfc038c468c32c2a164bbcbef0a97a3e385d5ba
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/60210
Auto-Submit: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index 6c8341c..a1ad4ae 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -1447,105 +1447,105 @@
                                                     Source source,
                                                     ParamOrRetType param_or_ret,
                                                     bool is_struct_member) {
-    // Scan decorations for pipeline IO attributes.
-    // Check for overlap with attributes that have been seen previously.
-    ast::Decoration* pipeline_io_attribute = nullptr;
-    ast::InvariantDecoration* invariant_attribute = nullptr;
-    for (auto* deco : decos) {
-      auto is_invalid_compute_shader_decoration = false;
-      if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
-        if (pipeline_io_attribute) {
-          AddError("multiple entry point IO attributes", deco->source());
+        // Scan decorations for pipeline IO attributes.
+        // Check for overlap with attributes that have been seen previously.
+        ast::Decoration* pipeline_io_attribute = nullptr;
+        ast::InvariantDecoration* invariant_attribute = nullptr;
+        for (auto* deco : decos) {
+          auto is_invalid_compute_shader_decoration = false;
+          if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
+            if (pipeline_io_attribute) {
+              AddError("multiple entry point IO attributes", deco->source());
           AddNote("previously consumed " + deco_to_str(pipeline_io_attribute),
                   pipeline_io_attribute->source());
-          return false;
-        }
-        pipeline_io_attribute = deco;
+              return false;
+            }
+            pipeline_io_attribute = deco;
 
-        if (builtins.count(builtin->value())) {
+            if (builtins.count(builtin->value())) {
           AddError(deco_to_str(builtin) +
-                       " attribute appears multiple times as pipeline " +
-                       (param_or_ret == ParamOrRetType::kParameter ? "input"
-                                                                   : "output"),
-                   func->source());
-          return false;
-        }
+                      " attribute appears multiple times as pipeline " +
+                      (param_or_ret == ParamOrRetType::kParameter ? "input"
+                                                                  : "output"),
+                  func->source());
+              return false;
+            }
 
-        if (!ValidateBuiltinDecoration(
-                builtin, ty,
-                /* is_input */ param_or_ret == ParamOrRetType::kParameter,
-                /* is_struct_member */ is_struct_member)) {
-          return false;
-        }
-        builtins.emplace(builtin->value());
-      } else if (auto* location = deco->As<ast::LocationDecoration>()) {
-        if (pipeline_io_attribute) {
-          AddError("multiple entry point IO attributes", deco->source());
+            if (!ValidateBuiltinDecoration(
+                    builtin, ty,
+                    /* is_input */ param_or_ret == ParamOrRetType::kParameter,
+                    /* is_struct_member */ is_struct_member)) {
+              return false;
+            }
+            builtins.emplace(builtin->value());
+          } else if (auto* location = deco->As<ast::LocationDecoration>()) {
+            if (pipeline_io_attribute) {
+              AddError("multiple entry point IO attributes", deco->source());
           AddNote("previously consumed " + deco_to_str(pipeline_io_attribute),
                   pipeline_io_attribute->source());
-          return false;
-        }
-        pipeline_io_attribute = deco;
+              return false;
+            }
+            pipeline_io_attribute = deco;
 
-        bool is_input = param_or_ret == ParamOrRetType::kParameter;
-        if (!ValidateLocationDecoration(location, ty, locations, source,
-                                        is_input)) {
-          return false;
-        }
+            bool is_input = param_or_ret == ParamOrRetType::kParameter;
+            if (!ValidateLocationDecoration(location, ty, locations, source,
+                                            is_input)) {
+              return false;
+            }
       } else if (auto* interpolate = deco->As<ast::InterpolateDecoration>()) {
-        if (func->pipeline_stage() == ast::PipelineStage::kCompute) {
-          is_invalid_compute_shader_decoration = true;
-        } else if (!ValidateInterpolateDecoration(interpolate, ty)) {
-          return false;
-        }
-      } else if (auto* invariant = deco->As<ast::InvariantDecoration>()) {
-        if (func->pipeline_stage() == ast::PipelineStage::kCompute) {
-          is_invalid_compute_shader_decoration = true;
-        }
-        invariant_attribute = invariant;
-      }
-      if (is_invalid_compute_shader_decoration) {
-        std::string input_or_output =
+            if (func->pipeline_stage() == ast::PipelineStage::kCompute) {
+              is_invalid_compute_shader_decoration = true;
+            } else if (!ValidateInterpolateDecoration(interpolate, ty)) {
+              return false;
+            }
+          } else if (auto* invariant = deco->As<ast::InvariantDecoration>()) {
+            if (func->pipeline_stage() == ast::PipelineStage::kCompute) {
+              is_invalid_compute_shader_decoration = true;
+            }
+            invariant_attribute = invariant;
+          }
+          if (is_invalid_compute_shader_decoration) {
+            std::string input_or_output =
             param_or_ret == ParamOrRetType::kParameter ? "inputs" : "output";
-        AddError(
-            "decoration is not valid for compute shader " + input_or_output,
-            deco->source());
-        return false;
-      }
-    }
+            AddError(
+                "decoration is not valid for compute shader " + input_or_output,
+                deco->source());
+            return false;
+          }
+        }
 
     if (IsValidationEnabled(decos,
                             ast::DisabledValidation::kEntryPointParameter)) {
-      if (!ty->Is<sem::Struct>() && !pipeline_io_attribute) {
-        std::string err = "missing entry point IO attribute";
-        if (!is_struct_member) {
+          if (!ty->Is<sem::Struct>() && !pipeline_io_attribute) {
+            std::string err = "missing entry point IO attribute";
+            if (!is_struct_member) {
           err +=
               (param_or_ret == ParamOrRetType::kParameter ? " on parameter"
-                                                          : " on return type");
-        }
-        AddError(err, source);
-        return false;
-      }
+                          : " on return type");
+            }
+            AddError(err, source);
+            return false;
+          }
 
-      if (invariant_attribute) {
-        bool has_position = false;
-        if (pipeline_io_attribute) {
-          if (auto* builtin =
-                  pipeline_io_attribute->As<ast::BuiltinDecoration>()) {
-            has_position = (builtin->value() == ast::Builtin::kPosition);
+          if (invariant_attribute) {
+            bool has_position = false;
+            if (pipeline_io_attribute) {
+              if (auto* builtin =
+                      pipeline_io_attribute->As<ast::BuiltinDecoration>()) {
+                has_position = (builtin->value() == ast::Builtin::kPosition);
+              }
+            }
+            if (!has_position) {
+              AddError(
+                  "invariant attribute must only be applied to a position "
+                  "builtin",
+                  invariant_attribute->source());
+              return false;
+            }
           }
         }
-        if (!has_position) {
-          AddError(
-              "invariant attribute must only be applied to a position "
-              "builtin",
-              invariant_attribute->source());
-          return false;
-        }
-      }
-    }
-    return true;
-  };
+        return true;
+      };
 
   // Outer lambda for validating the entry point decorations for a type.
   auto validate_entry_point_decorations = [&](const ast::DecorationList& decos,
@@ -2155,7 +2155,7 @@
         return false;
       }
 
-      if (!TypeOf(condition)->Is<sem::Bool>()) {
+      if (!TypeOf(condition)->UnwrapRef()->Is<sem::Bool>()) {
         AddError(
             "for-loop condition must be bool, got " + TypeNameOf(condition),
             condition->source());
diff --git a/src/resolver/validation_test.cc b/src/resolver/validation_test.cc
index eb00dcd..1b88cc3 100644
--- a/src/resolver/validation_test.cc
+++ b/src/resolver/validation_test.cc
@@ -768,6 +768,16 @@
   EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
+TEST_F(ResolverTest, Stmt_ForLoop_CondIsBoolRef) {
+  // var cond : bool = true;
+  // for (; cond; ) {
+  // }
+
+  auto* cond = Var("cond", ty.bool_(), Expr(true));
+  WrapInFunction(Decl(cond), For(nullptr, "cond", nullptr, Block()));
+  EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
 TEST_F(ResolverTest, Stmt_ForLoop_CondIsNotBool) {
   // for (; 1.0f; ) {
   // }