Import Tint changes from Dawn

Changes:
  - 33fe68ee0f1f2f38caba1f74f44aaeab5892183b tint/resolver: Prevent ICE with invalid input by Ben Clayton <bclayton@google.com>
GitOrigin-RevId: 33fe68ee0f1f2f38caba1f74f44aaeab5892183b
Change-Id: I839a29fe3c9817a42f9d9b510b3e1dfa1f86b538
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/92880
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/resolver/function_validation_test.cc b/src/tint/resolver/function_validation_test.cc
index 317cadc..3be06a9 100644
--- a/src/tint/resolver/function_validation_test.cc
+++ b/src/tint/resolver/function_validation_test.cc
@@ -73,8 +73,8 @@
     // fn func { var a:i32 = 2i; }
     auto* var = Var("a", ty.i32(), Expr(2_i));
 
-    Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.void_(),
-         ast::StatementList{
+    Func(Source{{12, 34}}, "func", {}, ty.void_(),
+         {
              Decl(var),
          });
 
@@ -88,12 +88,11 @@
     // }
 
     auto* var = Var("func", ty.i32(), Expr(0_i));
-    Func("func", ast::VariableList{}, ty.i32(),
-         ast::StatementList{
+    Func("func", {}, ty.i32(),
+         {
              Decl(var),
              Return(Source{{12, 34}}, Expr("func")),
-         },
-         ast::AttributeList{});
+         });
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -103,17 +102,15 @@
     // fn b() -> i32 { return 2; }
 
     auto* var = Var("b", ty.i32(), Expr(0_i));
-    Func("a", ast::VariableList{}, ty.void_(),
-         ast::StatementList{
+    Func("a", {}, ty.void_(),
+         {
              Decl(var),
-         },
-         ast::AttributeList{});
+         });
 
-    Func(Source{{12, 34}}, "b", ast::VariableList{}, ty.i32(),
-         ast::StatementList{
+    Func(Source{{12, 34}}, "b", {}, ty.i32(),
+         {
              Return(2_i),
-         },
-         ast::AttributeList{});
+         });
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -129,7 +126,7 @@
     auto* ret = Return();
     auto* assign_a = Assign(Source{{12, 34}}, "a", 2_i);
 
-    Func("func", ast::VariableList{}, ty.void_(), {decl_a, ret, assign_a});
+    Func("func", {}, ty.void_(), {decl_a, ret, assign_a});
 
     ASSERT_TRUE(r()->Resolve());
 
@@ -150,7 +147,7 @@
     auto* ret = Return();
     auto* assign_a = Assign(Source{{12, 34}}, "a", 2_i);
 
-    Func("func", ast::VariableList{}, ty.void_(), {decl_a, Block(Block(Block(ret))), assign_a});
+    Func("func", {}, ty.void_(), {decl_a, Block(Block(Block(ret))), assign_a});
 
     ASSERT_TRUE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
@@ -170,7 +167,7 @@
     auto* discard = Discard();
     auto* assign_a = Assign(Source{{12, 34}}, "a", 2_i);
 
-    Func("func", ast::VariableList{}, ty.void_(), {decl_a, discard, assign_a});
+    Func("func", {}, ty.void_(), {decl_a, discard, assign_a});
 
     ASSERT_TRUE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
@@ -190,7 +187,7 @@
     auto* discard = Discard();
     auto* assign_a = Assign(Source{{12, 34}}, "a", 2_i);
 
-    Func("func", ast::VariableList{}, ty.void_(), {decl_a, Block(Block(Block(discard))), assign_a});
+    Func("func", {}, ty.void_(), {decl_a, Block(Block(Block(discard))), assign_a});
 
     ASSERT_TRUE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
@@ -204,11 +201,10 @@
 
     auto* var = Var("a", ty.i32(), Expr(2_i));
 
-    Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.i32(),
-         ast::StatementList{
+    Func(Source{{12, 34}}, "func", {}, ty.i32(),
+         {
              Decl(var),
-         },
-         ast::AttributeList{});
+         });
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: missing return at end of function");
@@ -217,7 +213,7 @@
 TEST_F(ResolverFunctionValidationTest, VoidFunctionEndWithoutReturnStatementEmptyBody_Pass) {
     // fn func {}
 
-    Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.void_(), ast::StatementList{});
+    Func(Source{{12, 34}}, "func", {}, ty.void_(), {});
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -225,8 +221,7 @@
 TEST_F(ResolverFunctionValidationTest, FunctionEndWithoutReturnStatementEmptyBody_Fail) {
     // fn func() -> int {}
 
-    Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.i32(), ast::StatementList{},
-         ast::AttributeList{});
+    Func(Source{{12, 34}}, "func", {}, ty.i32(), {});
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: missing return at end of function");
@@ -235,21 +230,34 @@
 TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementType_Pass) {
     // fn func { return; }
 
-    Func("func", ast::VariableList{}, ty.void_(),
-         ast::StatementList{
-             Return(),
-         });
+    Func("func", {}, ty.void_(), {Return()});
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementType_fail) {
+TEST_F(ResolverFunctionValidationTest, VoidFunctionReturnsAInt) {
+    // fn func { return 2; }
+    Func("func", {}, ty.void_(), {Return(Source{{12, 34}}, Expr(2_a))});
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: return statement type must match its function return "
+              "type, returned 'abstract-int', expected 'void'");
+}
+
+TEST_F(ResolverFunctionValidationTest, VoidFunctionReturnsAFloat) {
+    // fn func { return 2.0; }
+    Func("func", {}, ty.void_(), {Return(Source{{12, 34}}, Expr(2.0_a))});
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: return statement type must match its function return "
+              "type, returned 'abstract-float', expected 'void'");
+}
+
+TEST_F(ResolverFunctionValidationTest, VoidFunctionReturnsI32) {
     // fn func { return 2i; }
-    Func("func", ast::VariableList{}, ty.void_(),
-         ast::StatementList{
-             Return(Source{{12, 34}}, Expr(2_i)),
-         },
-         ast::AttributeList{});
+    Func("func", {}, ty.void_(), {Return(Source{{12, 34}}, Expr(2_i))});
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -272,11 +280,10 @@
 
 TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementTypeMissing_fail) {
     // fn func() -> f32 { return; }
-    Func("func", ast::VariableList{}, ty.f32(),
-         ast::StatementList{
+    Func("func", {}, ty.f32(),
+         {
              Return(Source{{12, 34}}, nullptr),
-         },
-         ast::AttributeList{});
+         });
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -286,22 +293,20 @@
 
 TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementTypeF32_pass) {
     // fn func() -> f32 { return 2.0; }
-    Func("func", ast::VariableList{}, ty.f32(),
-         ast::StatementList{
+    Func("func", {}, ty.f32(),
+         {
              Return(Source{{12, 34}}, Expr(2_f)),
-         },
-         ast::AttributeList{});
+         });
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementTypeF32_fail) {
     // fn func() -> f32 { return 2i; }
-    Func("func", ast::VariableList{}, ty.f32(),
-         ast::StatementList{
+    Func("func", {}, ty.f32(),
+         {
              Return(Source{{12, 34}}, Expr(2_i)),
-         },
-         ast::AttributeList{});
+         });
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -313,11 +318,10 @@
     // type myf32 = f32;
     // fn func() -> myf32 { return 2.0; }
     auto* myf32 = Alias("myf32", ty.f32());
-    Func("func", ast::VariableList{}, ty.Of(myf32),
-         ast::StatementList{
+    Func("func", {}, ty.Of(myf32),
+         {
              Return(Source{{12, 34}}, Expr(2_f)),
-         },
-         ast::AttributeList{});
+         });
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -326,11 +330,10 @@
     // type myf32 = f32;
     // fn func() -> myf32 { return 2u; }
     auto* myf32 = Alias("myf32", ty.f32());
-    Func("func", ast::VariableList{}, ty.Of(myf32),
-         ast::StatementList{
+    Func("func", {}, ty.Of(myf32),
+         {
              Return(Source{{12, 34}}, Expr(2_u)),
-         },
-         ast::AttributeList{});
+         });
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -341,10 +344,10 @@
 TEST_F(ResolverFunctionValidationTest, CannotCallEntryPoint) {
     // @stage(compute) @workgroup_size(1) fn entrypoint() {}
     // fn func() { return entrypoint(); }
-    Func("entrypoint", ast::VariableList{}, ty.void_(), {},
+    Func("entrypoint", {}, ty.void_(), {},
          {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-    Func("func", ast::VariableList{}, ty.void_(),
+    Func("func", {}, ty.void_(),
          {
              CallStmt(Call(Source{{12, 34}}, "entrypoint")),
          });
@@ -359,8 +362,8 @@
     // @stage(fragment)
     // @stage(vertex)
     // fn main() { return; }
-    Func(Source{{12, 34}}, "main", ast::VariableList{}, ty.void_(),
-         ast::StatementList{
+    Func(Source{{12, 34}}, "main", {}, ty.void_(),
+         {
              Return(),
          },
          ast::AttributeList{
@@ -375,11 +378,10 @@
 }
 
 TEST_F(ResolverFunctionValidationTest, NoPipelineEntryPoints) {
-    Func("vtx_func", ast::VariableList{}, ty.void_(),
-         ast::StatementList{
+    Func("vtx_func", {}, ty.void_(),
+         {
              Return(),
-         },
-         ast::AttributeList{});
+         });
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -392,8 +394,7 @@
     auto* bar = Param("bar", ty.f32());
     auto* baz = Var("baz", ty.f32(), Expr("bar"));
 
-    Func("foo", ast::VariableList{bar}, ty.void_(), ast::StatementList{Decl(baz)},
-         ast::AttributeList{});
+    Func("foo", ast::VariableList{bar}, ty.void_(), {Decl(baz)});
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -406,8 +407,7 @@
     auto* bar = Param("bar", ty.f32());
     auto* baz = Let("baz", ty.f32(), Expr("bar"));
 
-    Func("foo", ast::VariableList{bar}, ty.void_(), ast::StatementList{Decl(baz)},
-         ast::AttributeList{});
+    Func("foo", ast::VariableList{bar}, ty.void_(), {Decl(baz)});
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index 294b3fb..90ae4b0 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -2302,10 +2302,16 @@
 
         const sem::Type* value_ty = nullptr;
         if (auto* value = stmt->value) {
-            const auto* expr = Materialize(Expression(value), current_function_->ReturnType());
+            const auto* expr = Expression(value);
             if (!expr) {
                 return false;
             }
+            if (auto* ret_ty = current_function_->ReturnType(); !ret_ty->Is<sem::Void>()) {
+                expr = Materialize(expr, ret_ty);
+                if (!expr) {
+                    return false;
+                }
+            }
             behaviors.Add(expr->Behaviors() - sem::Behavior::kNext);
             value_ty = expr->Type()->UnwrapRef();
         } else {