validation: disallow atomic type constructors

The type of a type constructor must be constructible, which forbids
atomics. Add checks for non-constructible types when validating arrays
and structures, and then error on any type that isn't explicitly
matched in the outer function. Replaces the separate check for
pointers, which is no longer necessary.

This also removes the validation for "an expression must not evaluate
to an atomic type". The only test that we had for this is no longer
valid (since the type constructor it used is now rejected). There are
no other ways of hitting this particular error, since other validation
rules will always kick in first.

Change-Id: I2172b57ee4e8ee3066aaf0cedc4a26aaca642376
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/61800
Kokoro: Kokoro <noreply+kokoro@google.com>
Auto-Submit: James Price <jrprice@google.com>
Commit-Queue: Sarah Mashayekhi <sarahmashay@google.com>
Reviewed-by: Sarah Mashayekhi <sarahmashay@google.com>
diff --git a/src/resolver/atomics_validation_test.cc b/src/resolver/atomics_validation_test.cc
index 15aa2d6..c5a1597 100644
--- a/src/resolver/atomics_validation_test.cc
+++ b/src/resolver/atomics_validation_test.cc
@@ -327,14 +327,6 @@
             "12:34 error: function variable must have a constructible type");
 }
 
-TEST_F(ResolverAtomicValidationTest, NoAtomicExpr) {
-  WrapInFunction(Construct(Source{{12, 34}}, ty.atomic<u32>()));
-
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: an expression must not evaluate to an atomic type");
-}
-
 }  // namespace
 }  // namespace resolver
 }  // namespace tint
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index b029c0d..b8fca54 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -2241,13 +2241,6 @@
     return false;
   }
 
-  auto* ty = TypeOf(expr);
-  if (ty->Is<sem::Atomic>()) {
-    AddError("an expression must not evaluate to an atomic type",
-             expr->source());
-    return false;
-  }
-
   return true;
 }
 
@@ -2600,11 +2593,6 @@
     // Now that the argument types have been determined, make sure that they
     // obey the constructor type rules laid out in
     // https://gpuweb.github.io/gpuweb/wgsl.html#type-constructor-expr.
-    if (type->Is<sem::Pointer>()) {
-      AddError("cannot cast to a pointer", expr->source());
-      return false;
-    }
-
     bool ok = true;
     if (auto* vec_type = type->As<sem::Vector>()) {
       ok = ValidateVectorConstructor(type_ctor, vec_type, type_name);
@@ -2616,6 +2604,9 @@
       ok = ValidateArrayConstructor(type_ctor, arr_type);
     } else if (auto* struct_type = type->As<sem::Struct>()) {
       ok = ValidateStructureConstructor(type_ctor, struct_type);
+    } else {
+      AddError("type is not constructible", type_ctor->source());
+      return false;
     }
     if (!ok) {
       return false;
@@ -2641,6 +2632,11 @@
 bool Resolver::ValidateStructureConstructor(
     const ast::TypeConstructorExpression* ctor,
     const sem::Struct* struct_type) {
+  if (!struct_type->IsConstructible()) {
+    AddError("struct constructor has non-constructible type", ctor->source());
+    return false;
+  }
+
   if (ctor->values().size() > 0) {
     if (ctor->values().size() != struct_type->Members().size()) {
       std::string fm = ctor->values().size() < struct_type->Members().size()
@@ -2689,6 +2685,10 @@
   if (array_type->IsRuntimeSized()) {
     AddError("cannot init a runtime-sized array", ctor->source());
     return false;
+  } else if (!elem_type->IsConstructible()) {
+    AddError("array constructor has non-constructible element type",
+             ctor->type()->As<ast::Array>()->type()->source());
+    return false;
   } else if (!values.empty() && (values.size() != array_type->Count())) {
     std::string fm = values.size() < array_type->Count() ? "few" : "many";
     AddError("array constructor has too " + fm + " elements: expected " +
diff --git a/src/resolver/type_constructor_validation_test.cc b/src/resolver/type_constructor_validation_test.cc
index a7556fb..295b61f 100644
--- a/src/resolver/type_constructor_validation_test.cc
+++ b/src/resolver/type_constructor_validation_test.cc
@@ -2148,6 +2148,44 @@
 }
 }  // namespace StructConstructor
 
+TEST_F(ResolverTypeConstructorValidationTest, NonConstructibleType_Atomic) {
+  WrapInFunction(
+      Call("ignore", Construct(Source{{12, 34}}, ty.atomic(ty.i32()))));
+
+  EXPECT_FALSE(r()->Resolve());
+  EXPECT_EQ(r()->error(), "12:34 error: type is not constructible");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest,
+       NonConstructibleType_AtomicArray) {
+  WrapInFunction(Call(
+      "ignore", Construct(ty.array(ty.atomic(Source{{12, 34}}, ty.i32()), 4))));
+
+  EXPECT_FALSE(r()->Resolve());
+  EXPECT_EQ(
+      r()->error(),
+      "12:34 error: array constructor has non-constructible element type");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest,
+       NonConstructibleType_AtomicStructMember) {
+  auto* str = Structure("S", {Member("a", ty.atomic(ty.i32()))});
+  WrapInFunction(Call("ignore", Construct(Source{{12, 34}}, ty.Of(str))));
+
+  EXPECT_FALSE(r()->Resolve());
+  EXPECT_EQ(r()->error(),
+            "12:34 error: struct constructor has non-constructible type");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, NonConstructibleType_Sampler) {
+  WrapInFunction(Call(
+      "ignore",
+      Construct(Source{{12, 34}}, ty.sampler(ast::SamplerKind::kSampler))));
+
+  EXPECT_FALSE(r()->Resolve());
+  EXPECT_EQ(r()->error(), "12:34 error: type is not constructible");
+}
+
 }  // namespace
 }  // namespace resolver
 }  // namespace tint
diff --git a/src/resolver/validation_test.cc b/src/resolver/validation_test.cc
index 1b88cc3..58abd73 100644
--- a/src/resolver/validation_test.cc
+++ b/src/resolver/validation_test.cc
@@ -919,7 +919,7 @@
   WrapInFunction(Decl(vf), Decl(ip));
 
   EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: cannot cast to a pointer");
+  EXPECT_EQ(r()->error(), "12:34 error: type is not constructible");
 }
 
 }  // namespace