validation: type of a let must be constructible

This forbids let declarations from having handle types.

Change-Id: I6f7467b0fa3963711ec705e1a81bfdd2c550feee
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/59801
Auto-Submit: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index a180646..aeed87e 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -1070,6 +1070,14 @@
     return false;
   }
 
+  if (var->is_const() && info->kind != VariableKind::kParameter &&
+      !(storage_type->IsConstructible() || storage_type->Is<sem::Pointer>())) {
+    AddError(storage_type->FriendlyName(builder_->Symbols()) +
+                 " cannot be used as the type of a let",
+             var->source());
+    return false;
+  }
+
   if (auto* r = storage_type->As<sem::Array>()) {
     if (r->IsRuntimeSized()) {
       AddError("runtime arrays may only appear as the last member of a struct",
diff --git a/src/resolver/var_let_validation_test.cc b/src/resolver/var_let_validation_test.cc
index 973b7b8..7ac9324 100644
--- a/src/resolver/var_let_validation_test.cc
+++ b/src/resolver/var_let_validation_test.cc
@@ -78,6 +78,20 @@
             "type of a var");
 }
 
+TEST_F(ResolverVarLetValidationTest, LetTypeNotConstructible) {
+  // [[group(0), binding(0)]] var t1 : texture_2d<f32>;
+  // let t2 : t1;
+  auto* t1 =
+      Global("t1", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+             GroupAndBinding(0, 0));
+  auto* t2 = Const(Source{{56, 78}}, "t2", nullptr, Expr(t1));
+  WrapInFunction(t2);
+
+  EXPECT_FALSE(r()->Resolve());
+  EXPECT_EQ(r()->error(),
+            "56:78 error: texture_2d<f32> cannot be used as the type of a let");
+}
+
 TEST_F(ResolverVarLetValidationTest, LetConstructorWrongType) {
   // var v : i32 = 2u
   WrapInFunction(Const(Source{{3, 3}}, "v", ty.i32(), Expr(2u)));
diff --git a/test/let/handles/texture_sampler.wgsl b/test/let/handles/texture_sampler.wgsl
deleted file mode 100644
index 56428b9..0000000
--- a/test/let/handles/texture_sampler.wgsl
+++ /dev/null
@@ -1,15 +0,0 @@
-[[group(0), binding(0)]] var t : texture_2d<f32>;
-[[group(0), binding(1)]] var s : sampler;
-
-[[stage(fragment)]]
-fn main() {
-  let x = t;
-  let a = s;
-  ignore(1);
-  let y = x;
-  let b = a;
-  ignore(2);
-  let z = y;
-  let c = b;
-  ignore(textureSample(z, c, vec2<f32>(1., 2.)));
-}
diff --git a/test/let/handles/texture_sampler.wgsl.expected.hlsl b/test/let/handles/texture_sampler.wgsl.expected.hlsl
deleted file mode 100644
index 9926644..0000000
--- a/test/let/handles/texture_sampler.wgsl.expected.hlsl
+++ /dev/null
@@ -1,13 +0,0 @@
-Texture2D<float4> t : register(t0, space0);
-SamplerState s : register(s1, space0);
-
-void main() {
-  const Texture2D<float4> x = t;
-  const SamplerState a = s;
-  1;
-  const Texture2D<float4> y = x;
-  const SamplerState b = a;
-  2;
-  y.Sample(b, float2(1.0f, 2.0f));
-  return;
-}
diff --git a/test/let/handles/texture_sampler.wgsl.expected.msl b/test/let/handles/texture_sampler.wgsl.expected.msl
deleted file mode 100644
index 4c001ef..0000000
--- a/test/let/handles/texture_sampler.wgsl.expected.msl
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <metal_stdlib>
-
-using namespace metal;
-fragment void tint_symbol(texture2d<float, access::sample> tint_symbol_1 [[texture(0)]], sampler tint_symbol_2 [[sampler(1)]]) {
-  texture2d<float, access::sample> const x = tint_symbol_1;
-  sampler const a = tint_symbol_2;
-  (void) 1;
-  texture2d<float, access::sample> const y = x;
-  sampler const b = a;
-  (void) 2;
-  texture2d<float, access::sample> const z = y;
-  sampler const c = b;
-  (void) z.sample(c, float2(1.0f, 2.0f));
-  return;
-}
-
diff --git a/test/let/handles/texture_sampler.wgsl.expected.spvasm b/test/let/handles/texture_sampler.wgsl.expected.spvasm
deleted file mode 100644
index 3907162..0000000
--- a/test/let/handles/texture_sampler.wgsl.expected.spvasm
+++ /dev/null
@@ -1,42 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 28
-; Schema: 0
-               OpCapability Shader
-               OpMemoryModel Logical GLSL450
-               OpEntryPoint Fragment %main "main"
-               OpExecutionMode %main OriginUpperLeft
-               OpName %t "t"
-               OpName %s "s"
-               OpName %main "main"
-               OpDecorate %t DescriptorSet 0
-               OpDecorate %t Binding 0
-               OpDecorate %s DescriptorSet 0
-               OpDecorate %s Binding 1
-      %float = OpTypeFloat 32
-          %3 = OpTypeImage %float 2D 0 0 0 1 Unknown
-%_ptr_UniformConstant_3 = OpTypePointer UniformConstant %3
-          %t = OpVariable %_ptr_UniformConstant_3 UniformConstant
-          %7 = OpTypeSampler
-%_ptr_UniformConstant_7 = OpTypePointer UniformConstant %7
-          %s = OpVariable %_ptr_UniformConstant_7 UniformConstant
-       %void = OpTypeVoid
-          %8 = OpTypeFunction %void
-        %int = OpTypeInt 32 1
-      %int_1 = OpConstant %int 1
-      %int_2 = OpConstant %int 2
-    %v4float = OpTypeVector %float 4
-         %22 = OpTypeSampledImage %3
-    %v2float = OpTypeVector %float 2
-    %float_1 = OpConstant %float 1
-    %float_2 = OpConstant %float 2
-         %27 = OpConstantComposite %v2float %float_1 %float_2
-       %main = OpFunction %void None %8
-         %11 = OpLabel
-         %12 = OpLoad %3 %t
-         %13 = OpLoad %7 %s
-         %23 = OpSampledImage %22 %12 %13
-         %20 = OpImageSampleImplicitLod %v4float %23 %27
-               OpReturn
-               OpFunctionEnd
diff --git a/test/let/handles/texture_sampler.wgsl.expected.wgsl b/test/let/handles/texture_sampler.wgsl.expected.wgsl
deleted file mode 100644
index 29a81ae..0000000
--- a/test/let/handles/texture_sampler.wgsl.expected.wgsl
+++ /dev/null
@@ -1,16 +0,0 @@
-[[group(0), binding(0)]] var t : texture_2d<f32>;
-
-[[group(0), binding(1)]] var s : sampler;
-
-[[stage(fragment)]]
-fn main() {
-  let x = t;
-  let a = s;
-  ignore(1);
-  let y = x;
-  let b = a;
-  ignore(2);
-  let z = y;
-  let c = b;
-  ignore(textureSample(z, c, vec2<f32>(1.0, 2.0)));
-}