[wasm-gc] Test improvements/additions.

Changes:
- Fix error message typo in function-body-decoder.
- Generalize wasm test macros related to reference types.
- Change wasm-gc test API to return bytes.
- Add unittests for ref.test/cast.

Bug: v8:7748
Change-Id: I361987e0b6ac90c4e89a49a8abc125757a5fc8d0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2317319
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69220}
diff --git a/src/wasm/function-body-decoder-impl.h b/src/wasm/function-body-decoder-impl.h
index fa6e735..97f1609 100644
--- a/src/wasm/function-body-decoder-impl.h
+++ b/src/wasm/function-body-decoder-impl.h
@@ -3646,7 +3646,7 @@
                                   ValueType::Ref(obj_type.type, kNonNullable),
                                   this->module_))) {
           this->errorf(this->pc_,
-                       "ret.cast: rtt type must be subtype of object type");
+                       "ref.cast: rtt type must be subtype of object type");
           return 0;
         }
         Value rtt = Pop(1);
diff --git a/test/cctest/wasm/test-gc.cc b/test/cctest/wasm/test-gc.cc
index 7198c1b..57ee477 100644
--- a/test/cctest/wasm/test-gc.cc
+++ b/test/cctest/wasm/test-gc.cc
@@ -43,13 +43,12 @@
     testing::SetupIsolateForWasmModule(isolate_);
   }
 
-  uint32_t AddGlobal(ValueType type, bool mutability, WasmInitExpr init) {
+  byte AddGlobal(ValueType type, bool mutability, WasmInitExpr init) {
     return builder_.AddGlobal(type, mutability, std::move(init));
   }
 
-  uint32_t DefineFunction(FunctionSig* sig,
-                          std::initializer_list<ValueType> locals,
-                          std::initializer_list<byte> code) {
+  byte DefineFunction(FunctionSig* sig, std::initializer_list<ValueType> locals,
+                      std::initializer_list<byte> code) {
     WasmFunctionBuilder* fun = builder_.AddFunction(sig);
     for (ValueType local : locals) {
       fun->AddLocal(local);
@@ -74,7 +73,7 @@
                            isolate_->factory()->undefined_value(), argc, args);
   }
 
-  uint32_t DefineStruct(std::initializer_list<F> fields) {
+  byte DefineStruct(std::initializer_list<F> fields) {
     StructType::Builder type_builder(&zone,
                                      static_cast<uint32_t>(fields.size()));
     for (F field : fields) {
@@ -83,7 +82,7 @@
     return builder_.AddStructType(type_builder.Build());
   }
 
-  uint32_t DefineArray(ValueType element_type, bool mutability) {
+  byte DefineArray(ValueType element_type, bool mutability) {
     return builder_.AddArrayType(zone.New<ArrayType>(element_type, mutability));
   }
 
@@ -177,14 +176,14 @@
 // TODO(7748): Use WASM_EXEC_TEST once interpreter and liftoff are supported.
 TEST(WasmBasicStruct) {
   WasmGCTester tester;
-  uint32_t type_index =
+  const byte type_index =
       tester.DefineStruct({F(kWasmI32, true), F(kWasmI32, true)});
   ValueType kRefTypes[] = {ref(type_index)};
   ValueType kOptRefType = optref(type_index);
   FunctionSig sig_q_v(1, 0, kRefTypes);
 
   // Test struct.new and struct.get.
-  const uint32_t kGet1 = tester.DefineFunction(
+  const byte kGet1 = tester.DefineFunction(
       tester.sigs.i_v(), {},
       {WASM_STRUCT_GET(
            type_index, 0,
@@ -193,7 +192,7 @@
        kExprEnd});
 
   // Test struct.new and struct.get.
-  const uint32_t kGet2 = tester.DefineFunction(
+  const byte kGet2 = tester.DefineFunction(
       tester.sigs.i_v(), {},
       {WASM_STRUCT_GET(
            type_index, 1,
@@ -202,16 +201,16 @@
        kExprEnd});
 
   // Test struct.new, returning struct reference.
-  const uint32_t kGetStruct = tester.DefineFunction(
+  const byte kGetStruct = tester.DefineFunction(
       &sig_q_v, {},
       {WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42), WASM_I32V(64),
                                 WASM_RTT_CANON(type_index)),
        kExprEnd});
 
   // Test struct.set, struct refs types in locals.
-  uint32_t j_local_index = 0;
-  uint32_t j_field_index = 0;
-  const uint32_t kSet = tester.DefineFunction(
+  const byte j_local_index = 0;
+  const byte j_field_index = 0;
+  const byte kSet = tester.DefineFunction(
       tester.sigs.i_v(), {kOptRefType},
       {WASM_SET_LOCAL(
            j_local_index,
@@ -235,18 +234,18 @@
 // struct refs types in globals and if-results.
 TEST(WasmRefAsNonNull) {
   WasmGCTester tester;
-  uint32_t type_index =
+  const byte type_index =
       tester.DefineStruct({F(kWasmI32, true), F(kWasmI32, true)});
   ValueType kRefTypes[] = {ref(type_index)};
   ValueType kOptRefType = optref(type_index);
   FunctionSig sig_q_v(1, 0, kRefTypes);
 
-  uint32_t global_index =
+  const byte global_index =
       tester.AddGlobal(kOptRefType, true,
                        WasmInitExpr::RefNullConst(
                            static_cast<HeapType::Representation>(type_index)));
-  uint32_t field_index = 0;
-  const uint32_t kFunc = tester.DefineFunction(
+  const byte field_index = 0;
+  const byte kFunc = tester.DefineFunction(
       tester.sigs.i_v(), {},
       {WASM_SET_GLOBAL(
            global_index,
@@ -254,9 +253,9 @@
                                     WASM_RTT_CANON(type_index))),
        WASM_STRUCT_GET(
            type_index, field_index,
-           WASM_REF_AS_NON_NULL(WASM_IF_ELSE_R(
-               kOptRefType, WASM_I32V(1), WASM_GET_GLOBAL(global_index),
-               WASM_REF_NULL(static_cast<byte>(type_index))))),
+           WASM_REF_AS_NON_NULL(WASM_IF_ELSE_R(kOptRefType, WASM_I32V(1),
+                                               WASM_GET_GLOBAL(global_index),
+                                               WASM_REF_NULL(type_index)))),
        kExprEnd});
 
   tester.CompileModule();
@@ -265,13 +264,13 @@
 
 TEST(WasmBrOnNull) {
   WasmGCTester tester;
-  uint32_t type_index =
+  const byte type_index =
       tester.DefineStruct({F(kWasmI32, true), F(kWasmI32, true)});
   ValueType kRefTypes[] = {ref(type_index)};
   ValueType kOptRefType = optref(type_index);
   FunctionSig sig_q_v(1, 0, kRefTypes);
-  uint32_t l_local_index = 0;
-  const uint32_t kTaken = tester.DefineFunction(
+  const byte l_local_index = 0;
+  const byte kTaken = tester.DefineFunction(
       tester.sigs.i_v(), {kOptRefType},
       {WASM_BLOCK_I(WASM_I32V(42),
                     // Branch will be taken.
@@ -280,8 +279,8 @@
                     WASM_I32V(52), WASM_BR(0)),
        kExprEnd});
 
-  uint32_t m_field_index = 0;
-  const uint32_t kNotTaken = tester.DefineFunction(
+  const byte m_field_index = 0;
+  const byte kNotTaken = tester.DefineFunction(
       tester.sigs.i_v(), {},
       {WASM_BLOCK_I(
            WASM_I32V(42),
@@ -302,12 +301,12 @@
 
 TEST(BrOnCast) {
   WasmGCTester tester;
-  uint32_t type_index = tester.DefineStruct({F(kWasmI32, true)});
-  uint32_t rtt_index =
+  const byte type_index = tester.DefineStruct({F(kWasmI32, true)});
+  const byte rtt_index =
       tester.AddGlobal(ValueType::Rtt(type_index, 1), false,
                        WasmInitExpr::RttCanon(
                            static_cast<HeapType::Representation>(type_index)));
-  const uint32_t kTestStruct = tester.DefineFunction(
+  const byte kTestStruct = tester.DefineFunction(
       tester.sigs.i_v(), {kWasmI32, kWasmEqRef},
       {WASM_BLOCK(WASM_SET_LOCAL(0, WASM_I32V(111)),
                   // Pipe a struct through a local so it's statically typed
@@ -325,7 +324,7 @@
                   WASM_DROP, WASM_SET_LOCAL(0, WASM_I32V(333))),
        WASM_GET_LOCAL(0), kExprEnd});
 
-  const uint32_t kTestI31 = tester.DefineFunction(
+  const byte kTestI31 = tester.DefineFunction(
       tester.sigs.i_v(), {kWasmI32, kWasmEqRef},
       {WASM_BLOCK(WASM_SET_LOCAL(0, WASM_I32V(111)),
                   // Pipe an i31ref through a local so it's statically typed
@@ -341,7 +340,7 @@
                   WASM_DROP, WASM_SET_LOCAL(0, WASM_I32V(333))),
        WASM_GET_LOCAL(0), kExprEnd});
 
-  const uint32_t kTestNull = tester.DefineFunction(
+  const byte kTestNull = tester.DefineFunction(
       tester.sigs.i_v(), {kWasmI32, kWasmEqRef},
       {WASM_BLOCK(WASM_SET_LOCAL(0, WASM_I32V(111)),
                   WASM_GET_LOCAL(1),  // Put a nullref onto the value stack.
@@ -352,7 +351,7 @@
                   WASM_SET_LOCAL(0, WASM_I32V(333))),  // Final result.
        WASM_GET_LOCAL(0), kExprEnd});
 
-  const uint32_t kTypedAfterBranch = tester.DefineFunction(
+  const byte kTypedAfterBranch = tester.DefineFunction(
       tester.sigs.i_v(), {kWasmI32, kWasmEqRef},
       {WASM_SET_LOCAL(1, WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42),
                                                   WASM_GET_GLOBAL(rtt_index))),
@@ -380,14 +379,13 @@
 
 TEST(WasmRefEq) {
   WasmGCTester tester;
-  byte type_index = static_cast<byte>(
-      tester.DefineStruct({F(kWasmI32, true), F(kWasmI32, true)}));
+  byte type_index = tester.DefineStruct({F(kWasmI32, true), F(kWasmI32, true)});
   ValueType kRefTypes[] = {ref(type_index)};
   ValueType kOptRefType = optref(type_index);
   FunctionSig sig_q_v(1, 0, kRefTypes);
 
   byte local_index = 0;
-  const uint32_t kFunc = tester.DefineFunction(
+  const byte kFunc = tester.DefineFunction(
       tester.sigs.i_v(), {kOptRefType},
       {WASM_SET_LOCAL(local_index, WASM_STRUCT_NEW_WITH_RTT(
                                        type_index, WASM_I32V(55), WASM_I32V(66),
@@ -421,16 +419,16 @@
 TEST(WasmPackedStructU) {
   WasmGCTester tester;
 
-  uint32_t type_index = tester.DefineStruct(
+  const byte type_index = tester.DefineStruct(
       {F(kWasmI8, true), F(kWasmI16, true), F(kWasmI32, true)});
   ValueType struct_type = optref(type_index);
 
-  uint32_t local_index = 0;
+  const byte local_index = 0;
 
   int32_t expected_output_0 = 0x1234;
   int32_t expected_output_1 = -1;
 
-  const uint32_t kF0 = tester.DefineFunction(
+  const byte kF0 = tester.DefineFunction(
       tester.sigs.i_v(), {struct_type},
       {WASM_SET_LOCAL(local_index,
                       WASM_STRUCT_NEW_WITH_RTT(
@@ -440,7 +438,7 @@
        WASM_STRUCT_GET_U(type_index, 0, WASM_GET_LOCAL(local_index)),
        kExprEnd});
 
-  const uint32_t kF1 = tester.DefineFunction(
+  const byte kF1 = tester.DefineFunction(
       tester.sigs.i_v(), {struct_type},
       {WASM_SET_LOCAL(local_index,
                       WASM_STRUCT_NEW_WITH_RTT(
@@ -458,16 +456,16 @@
 TEST(WasmPackedStructS) {
   WasmGCTester tester;
 
-  uint32_t type_index = tester.DefineStruct(
+  const byte type_index = tester.DefineStruct(
       {F(kWasmI8, true), F(kWasmI16, true), F(kWasmI32, true)});
   ValueType struct_type = optref(type_index);
 
-  uint32_t local_index = 0;
+  const byte local_index = 0;
 
   int32_t expected_output_0 = 0x80;
   int32_t expected_output_1 = 42;
 
-  const uint32_t kF0 = tester.DefineFunction(
+  const byte kF0 = tester.DefineFunction(
       tester.sigs.i_v(), {struct_type},
       {WASM_SET_LOCAL(
            local_index,
@@ -477,7 +475,7 @@
        WASM_STRUCT_GET_S(type_index, 0, WASM_GET_LOCAL(local_index)),
        kExprEnd});
 
-  const uint32_t kF1 = tester.DefineFunction(
+  const byte kF1 = tester.DefineFunction(
       tester.sigs.i_v(), {struct_type},
       {WASM_SET_LOCAL(
            local_index,
@@ -495,27 +493,27 @@
 
 TEST(WasmLetInstruction) {
   WasmGCTester tester;
-  uint32_t type_index =
+  const byte type_index =
       tester.DefineStruct({F(kWasmI32, true), F(kWasmI32, true)});
 
-  uint32_t let_local_index = 0;
-  uint32_t let_field_index = 0;
-  const uint32_t kLetTest1 = tester.DefineFunction(
+  const byte let_local_index = 0;
+  const byte let_field_index = 0;
+  const byte kLetTest1 = tester.DefineFunction(
       tester.sigs.i_v(), {},
       {WASM_LET_1_I(
-           WASM_SEQ(kLocalRef, static_cast<byte>(type_index)),
+           WASM_SEQ(kLocalRef, type_index),
            WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42), WASM_I32V(52),
                                     WASM_RTT_CANON(type_index)),
            WASM_STRUCT_GET(type_index, let_field_index,
                            WASM_GET_LOCAL(let_local_index))),
        kExprEnd});
 
-  uint32_t let_2_field_index = 0;
-  const uint32_t kLetTest2 = tester.DefineFunction(
+  const byte let_2_field_index = 0;
+  const byte kLetTest2 = tester.DefineFunction(
       tester.sigs.i_v(), {},
       {WASM_LET_2_I(
            kLocalI32, WASM_I32_ADD(WASM_I32V(42), WASM_I32V(-32)),
-           WASM_SEQ(kLocalRef, static_cast<byte>(type_index)),
+           WASM_SEQ(kLocalRef, type_index),
            WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42), WASM_I32V(52),
                                     WASM_RTT_CANON(type_index)),
            WASM_I32_MUL(WASM_STRUCT_GET(type_index, let_2_field_index,
@@ -523,7 +521,7 @@
                         WASM_GET_LOCAL(0))),
        kExprEnd});
 
-  const uint32_t kLetTestLocals = tester.DefineFunction(
+  const byte kLetTestLocals = tester.DefineFunction(
       tester.sigs.i_i(), {kWasmI32},
       {WASM_SET_LOCAL(1, WASM_I32V(100)),
        WASM_LET_2_I(
@@ -535,8 +533,8 @@
        kExprEnd});
   // Result: (1 + 1000) - (10 + 100) = 891
 
-  uint32_t let_erase_local_index = 0;
-  const uint32_t kLetTestErase = tester.DefineFunction(
+  const byte let_erase_local_index = 0;
+  const byte kLetTestErase = tester.DefineFunction(
       tester.sigs.i_v(), {kWasmI32},
       {WASM_SET_LOCAL(let_erase_local_index, WASM_I32V(0)),
        WASM_LET_1_V(kLocalI32, WASM_I32V(1), WASM_NOP),
@@ -554,14 +552,14 @@
 
 TEST(WasmBasicArray) {
   WasmGCTester tester;
-  uint32_t type_index = tester.DefineArray(wasm::kWasmI32, true);
+  const byte type_index = tester.DefineArray(wasm::kWasmI32, true);
   ValueType kRefTypes[] = {ref(type_index)};
   FunctionSig sig_q_v(1, 0, kRefTypes);
   ValueType kOptRefType = optref(type_index);
 
   // f: a = [12, 12, 12]; a[1] = 42; return a[arg0]
-  uint32_t local_index = 1;
-  const uint32_t kGetElem = tester.DefineFunction(
+  const byte local_index = 1;
+  const byte kGetElem = tester.DefineFunction(
       tester.sigs.i_i(), {kOptRefType},
       {WASM_SET_LOCAL(local_index, WASM_ARRAY_NEW_WITH_RTT(
                                        type_index, WASM_I32V(12), WASM_I32V(3),
@@ -573,7 +571,7 @@
        kExprEnd});
 
   // Reads and returns an array's length.
-  const uint32_t kGetLength = tester.DefineFunction(
+  const byte kGetLength = tester.DefineFunction(
       tester.sigs.i_v(), {},
       {WASM_ARRAY_LEN(type_index, WASM_ARRAY_NEW_WITH_RTT(
                                       type_index, WASM_I32V(0), WASM_I32V(42),
@@ -581,7 +579,7 @@
        kExprEnd});
 
   // Create an array of length 2, initialized to [42, 42].
-  const uint32_t kAllocate = tester.DefineFunction(
+  const byte kAllocate = tester.DefineFunction(
       &sig_q_v, {},
       {WASM_ARRAY_NEW_WITH_RTT(type_index, WASM_I32V(42), WASM_I32V(2),
                                WASM_RTT_CANON(type_index)),
@@ -605,15 +603,15 @@
 
 TEST(WasmPackedArrayU) {
   WasmGCTester tester;
-  uint32_t array_index = tester.DefineArray(kWasmI8, true);
+  const byte array_index = tester.DefineArray(kWasmI8, true);
   ValueType array_type = optref(array_index);
 
-  uint32_t param_index = 0;
-  uint32_t local_index = 1;
+  const byte param_index = 0;
+  const byte local_index = 1;
 
   int32_t expected_output_3 = 258;
 
-  const uint32_t kF = tester.DefineFunction(
+  const byte kF = tester.DefineFunction(
       tester.sigs.i_i(), {array_type},
       {WASM_SET_LOCAL(local_index, WASM_ARRAY_NEW_WITH_RTT(
                                        array_index, WASM_I32V(0), WASM_I32V(4),
@@ -640,14 +638,14 @@
 
 TEST(WasmPackedArrayS) {
   WasmGCTester tester;
-  uint32_t array_index = tester.DefineArray(kWasmI16, true);
+  const byte array_index = tester.DefineArray(kWasmI16, true);
   ValueType array_type = optref(array_index);
 
   int32_t expected_outputs[] = {0x12345678, 10, 0xFEDC, 0xFF1234};
 
-  uint32_t param_index = 0;
-  uint32_t local_index = 1;
-  const uint32_t kF = tester.DefineFunction(
+  const byte param_index = 0;
+  const byte local_index = 1;
+  const byte kF = tester.DefineFunction(
       tester.sigs.i_i(), {array_type},
       {WASM_SET_LOCAL(
            local_index,
@@ -675,8 +673,8 @@
 
 TEST(BasicRTT) {
   WasmGCTester tester;
-  uint32_t type_index = tester.DefineStruct({F(wasm::kWasmI32, true)});
-  uint32_t subtype_index =
+  const byte type_index = tester.DefineStruct({F(wasm::kWasmI32, true)});
+  const byte subtype_index =
       tester.DefineStruct({F(wasm::kWasmI32, true), F(wasm::kWasmI32, true)});
   ValueType kRttTypes[] = {ValueType::Rtt(type_index, 1)};
   FunctionSig sig_t_v(1, 0, kRttTypes);
@@ -688,15 +686,15 @@
   ValueType kRefTypes[] = {ref(type_index)};
   FunctionSig sig_q_v(1, 0, kRefTypes);
 
-  const uint32_t kRttCanon = tester.DefineFunction(
+  const byte kRttCanon = tester.DefineFunction(
       &sig_t_v, {}, {WASM_RTT_CANON(type_index), kExprEnd});
-  const uint32_t kRttSub = tester.DefineFunction(
+  const byte kRttSub = tester.DefineFunction(
       &sig_t2_v, {},
       {WASM_RTT_SUB(subtype_index, WASM_RTT_CANON(type_index)), kExprEnd});
-  const uint32_t kRttSubGeneric = tester.DefineFunction(
+  const byte kRttSubGeneric = tester.DefineFunction(
       &sig_t3_v, {},
       {WASM_RTT_SUB(type_index, WASM_RTT_CANON(kLocalEqRef)), kExprEnd});
-  const uint32_t kStructWithRtt = tester.DefineFunction(
+  const byte kStructWithRtt = tester.DefineFunction(
       &sig_q_v, {},
       {WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42),
                                 WASM_RTT_CANON(type_index)),
@@ -712,7 +710,7 @@
   //            ((ref.cast local_struct local_rtt)[field0]);
   //   }
   // The expected return value is 1+42 = 43.
-  const uint32_t kRefCast = tester.DefineFunction(
+  const byte kRefCast = tester.DefineFunction(
       tester.sigs.i_v(), {optref(type_index)},
       {WASM_LET_1_I(
           WASM_RTT(2, subtype_index),
@@ -770,11 +768,11 @@
 
 TEST(ArrayNewMap) {
   WasmGCTester tester;
-  uint32_t type_index = tester.DefineArray(kWasmI32, true);
+  const byte type_index = tester.DefineArray(kWasmI32, true);
 
   ValueType array_type = ValueType::Ref(type_index, kNonNullable);
   FunctionSig sig(1, 0, &array_type);
-  const uint32_t array_new_with_rtt = tester.DefineFunction(
+  const byte array_new_with_rtt = tester.DefineFunction(
       &sig, {},
       {WASM_ARRAY_NEW_WITH_RTT(type_index, WASM_I32V(10), WASM_I32V(42),
                                WASM_RTT_CANON(type_index)),
@@ -782,7 +780,7 @@
 
   ValueType rtt_type = ValueType::Rtt(type_index, 1);
   FunctionSig rtt_canon_sig(1, 0, &rtt_type);
-  const uint32_t kRttCanon = tester.DefineFunction(
+  const byte kRttCanon = tester.DefineFunction(
       &rtt_canon_sig, {}, {WASM_RTT_CANON(type_index), kExprEnd});
 
   tester.CompileModule();
@@ -797,16 +795,15 @@
 
 TEST(RefTestCastNull) {
   WasmGCTester tester;
-  uint8_t type_index =
-      static_cast<uint8_t>(tester.DefineStruct({F(wasm::kWasmI32, true)}));
+  byte type_index = tester.DefineStruct({F(wasm::kWasmI32, true)});
 
-  const uint32_t kRefTestNull = tester.DefineFunction(
+  const byte kRefTestNull = tester.DefineFunction(
       tester.sigs.i_v(), {},
       {WASM_REF_TEST(type_index, type_index, WASM_REF_NULL(type_index),
                      WASM_RTT_CANON(type_index)),
        kExprEnd});
 
-  const uint32_t kRefCastNull = tester.DefineFunction(
+  const byte kRefCastNull = tester.DefineFunction(
       tester.sigs.i_i(),  // Argument and return value ignored
       {},
       {WASM_REF_CAST(type_index, type_index, WASM_REF_NULL(type_index),
@@ -819,10 +816,10 @@
 
 TEST(BasicI31) {
   WasmGCTester tester;
-  const uint32_t kSigned = tester.DefineFunction(
+  const byte kSigned = tester.DefineFunction(
       tester.sigs.i_i(), {},
       {WASM_I31_GET_S(WASM_I31_NEW(WASM_GET_LOCAL(0))), kExprEnd});
-  const uint32_t kUnsigned = tester.DefineFunction(
+  const byte kUnsigned = tester.DefineFunction(
       tester.sigs.i_i(), {},
       {WASM_I31_GET_U(WASM_I31_NEW(WASM_GET_LOCAL(0))), kExprEnd});
   // TODO(7748): Support (rtt.canon i31), and add a test like:
@@ -840,16 +837,17 @@
 
 TEST(I31Casts) {
   WasmGCTester tester;
-  uint32_t struct_type = tester.DefineStruct({F(wasm::kWasmI32, true)});
-  uint32_t i31_rtt = tester.AddGlobal(ValueType::Rtt(HeapType::kI31, 1), false,
-                                      WasmInitExpr::RttCanon(HeapType::kI31));
-  uint32_t struct_rtt =
+  const byte struct_type = tester.DefineStruct({F(wasm::kWasmI32, true)});
+  const byte i31_rtt =
+      tester.AddGlobal(ValueType::Rtt(HeapType::kI31, 1), false,
+                       WasmInitExpr::RttCanon(HeapType::kI31));
+  const byte struct_rtt =
       tester.AddGlobal(ValueType::Rtt(struct_type, 1), false,
                        WasmInitExpr::RttCanon(
                            static_cast<HeapType::Representation>(struct_type)));
   // Adds the result of a successful typecheck to the untagged value, i.e.
   // should return 1 + 42 = 43.
-  const uint32_t kTestAndCastSuccess = tester.DefineFunction(
+  const byte kTestAndCastSuccess = tester.DefineFunction(
       tester.sigs.i_v(), {kWasmEqRef},
       {WASM_SET_LOCAL(0, WASM_I31_NEW(WASM_I32V(42))),
        WASM_I32_ADD(WASM_REF_TEST(kLocalEqRef, kLocalI31Ref, WASM_GET_LOCAL(0),
@@ -860,7 +858,7 @@
        kExprEnd});
   // Adds the results of two unsuccessful type checks (an i31ref is not a
   // struct, nor the other way round).
-  const uint32_t kTestFalse = tester.DefineFunction(
+  const byte kTestFalse = tester.DefineFunction(
       tester.sigs.i_v(), {},
       {WASM_I32_ADD(
            WASM_REF_TEST(kLocalEqRef, kLocalI31Ref,
@@ -871,7 +869,7 @@
                          WASM_GET_GLOBAL(struct_rtt))),
        kExprEnd});
   // Tries to cast an i31ref to a struct, which should trap.
-  const uint32_t kCastI31ToStruct = tester.DefineFunction(
+  const byte kCastI31ToStruct = tester.DefineFunction(
       tester.sigs.i_i(),  // Argument and return value ignored
       {},
       {WASM_STRUCT_GET(
@@ -880,7 +878,7 @@
                          WASM_GET_GLOBAL(struct_rtt))),
        kExprEnd});
   // Tries to cast a struct to i31ref, which should trap.
-  const uint32_t kCastStructToI31 = tester.DefineFunction(
+  const byte kCastStructToI31 = tester.DefineFunction(
       tester.sigs.i_i(),  // Argument and return value ignored
       {},
       {WASM_I31_GET_S(
@@ -898,7 +896,7 @@
 
 TEST(JsAccess) {
   WasmGCTester tester;
-  uint32_t type_index = tester.DefineStruct({F(wasm::kWasmI32, true)});
+  const byte type_index = tester.DefineStruct({F(wasm::kWasmI32, true)});
   ValueType kRefTypes[] = {ref(type_index)};
   ValueType kEqRefTypes[] = {kWasmEqRef};
   ValueType kEqToI[] = {kWasmI32, kWasmEqRef};
diff --git a/test/common/wasm/wasm-macro-gen.h b/test/common/wasm/wasm-macro-gen.h
index e31b2d6..e62b347 100644
--- a/test/common/wasm/wasm-macro-gen.h
+++ b/test/common/wasm/wasm-macro-gen.h
@@ -83,12 +83,11 @@
 #define DEPTH_2 2
 #define ARITY_2 2
 
-#define WASM_HEAP_TYPE(heap_type) static_cast<byte>(0x7F & heap_type.code())
+#define WASM_HEAP_TYPE(heap_type) static_cast<byte>((heap_type).code() & 0x7f)
 
-#define WASM_REF_TYPE(type)                                         \
-  static_cast<byte>(type.kind() == ValueType::kRef ? kLocalRef      \
-                                                   : kLocalOptRef), \
-      WASM_HEAP_TYPE(type.heap_type())
+#define WASM_REF_TYPE(type)                                    \
+  (type).kind() == ValueType::kRef ? kLocalRef : kLocalOptRef, \
+      WASM_HEAP_TYPE((type).heap_type())
 
 #define WASM_BLOCK(...) kExprBlock, kLocalVoid, __VA_ARGS__, kExprEnd
 #define WASM_BLOCK_I(...) kExprBlock, kLocalI32, __VA_ARGS__, kExprEnd
@@ -447,12 +446,10 @@
 #define WASM_REF_IS_NULL(val) val, kExprRefIsNull
 #define WASM_REF_AS_NON_NULL(val) val, kExprRefAsNonNull
 #define WASM_REF_EQ(lhs, rhs) lhs, rhs, kExprRefEq
-#define WASM_REF_TEST(obj_type, rtt_type, ref, rtt)                \
-  ref, rtt, WASM_GC_OP(kExprRefTest), static_cast<byte>(obj_type), \
-      static_cast<byte>(rtt_type)
-#define WASM_REF_CAST(obj_type, rtt_type, ref, rtt)                \
-  ref, rtt, WASM_GC_OP(kExprRefCast), static_cast<byte>(obj_type), \
-      static_cast<byte>(rtt_type)
+#define WASM_REF_TEST(obj_type, rtt_type, ref, rtt) \
+  ref, rtt, WASM_GC_OP(kExprRefTest), obj_type, rtt_type
+#define WASM_REF_CAST(obj_type, rtt_type, ref, rtt) \
+  ref, rtt, WASM_GC_OP(kExprRefCast), obj_type, rtt_type
 // Takes a reference value from the value stack to allow sequences of
 // conditional branches.
 #define WASM_BR_ON_CAST(depth, rtt) \
diff --git a/test/unittests/wasm/function-body-decoder-unittest.cc b/test/unittests/wasm/function-body-decoder-unittest.cc
index 2c50573..408b70c 100644
--- a/test/unittests/wasm/function-body-decoder-unittest.cc
+++ b/test/unittests/wasm/function-body-decoder-unittest.cc
@@ -4061,6 +4061,111 @@
   }
 }
 
+TEST_F(FunctionBodyDecoderTest, RefTestCast) {
+  WASM_FEATURE_SCOPE(reftypes);
+  WASM_FEATURE_SCOPE(typed_funcref);
+  WASM_FEATURE_SCOPE(gc);
+  WASM_FEATURE_SCOPE(eh);
+
+  TestModuleBuilder builder;
+  module = builder.module();
+  HeapType::Representation array_heap =
+      static_cast<HeapType::Representation>(builder.AddArray(kWasmI8, true));
+  HeapType::Representation super_struct_heap =
+      static_cast<HeapType::Representation>(
+          builder.AddStruct({F(kWasmI16, true)}));
+
+  HeapType::Representation sub_struct_heap =
+      static_cast<HeapType::Representation>(
+          builder.AddStruct({F(kWasmI16, true), F(kWasmI32, false)}));
+
+  // Passing/failing tests due to static subtyping.
+  std::pair<HeapType::Representation, HeapType::Representation> valid_pairs[] =
+      {{HeapType::kEq, HeapType::kI31},
+       {HeapType::kFunc, HeapType::kFunc},
+       {HeapType::kEq, array_heap},
+       {HeapType::kEq, super_struct_heap},
+       {super_struct_heap, sub_struct_heap}};
+
+  for (auto pair : valid_pairs) {
+    HeapType from_heap = HeapType(pair.first);
+    HeapType to_heap = HeapType(pair.second);
+    ValueType test_reps[] = {kWasmI32, ValueType::Ref(from_heap, kNullable)};
+    FunctionSig test_sig(1, 1, test_reps);
+    ValueType cast_reps[] = {ValueType::Ref(to_heap, kNonNullable),
+                             ValueType::Ref(from_heap, kNullable)};
+    FunctionSig cast_sig(1, 1, cast_reps);
+    ExpectValidates(&test_sig,
+                    {WASM_REF_TEST(WASM_HEAP_TYPE(from_heap),
+                                   WASM_HEAP_TYPE(to_heap), WASM_GET_LOCAL(0),
+                                   WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))});
+    ExpectValidates(&cast_sig,
+                    {WASM_REF_CAST(WASM_HEAP_TYPE(from_heap),
+                                   WASM_HEAP_TYPE(to_heap), WASM_GET_LOCAL(0),
+                                   WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))});
+  }
+
+  std::pair<HeapType::Representation, HeapType::Representation>
+      invalid_pairs[] = {{HeapType::kI31, HeapType::kEq},
+                         {array_heap, super_struct_heap},
+                         {array_heap, HeapType::kEq},
+                         {HeapType::kExtern, HeapType::kExn}};
+
+  for (auto pair : invalid_pairs) {
+    HeapType from_heap = HeapType(pair.first);
+    HeapType to_heap = HeapType(pair.second);
+    ValueType test_reps[] = {kWasmI32, ValueType::Ref(from_heap, kNullable)};
+    FunctionSig test_sig(1, 1, test_reps);
+    ValueType cast_reps[] = {ValueType::Ref(to_heap, kNonNullable),
+                             ValueType::Ref(from_heap, kNullable)};
+    FunctionSig cast_sig(1, 1, cast_reps);
+    ExpectFailure(&test_sig,
+                  {WASM_REF_TEST(WASM_HEAP_TYPE(from_heap),
+                                 WASM_HEAP_TYPE(to_heap), WASM_GET_LOCAL(0),
+                                 WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))},
+                  kAppendEnd,
+                  "ref.test: rtt type must be subtype of object type");
+    ExpectFailure(&cast_sig,
+                  {WASM_REF_CAST(WASM_HEAP_TYPE(from_heap),
+                                 WASM_HEAP_TYPE(to_heap), WASM_GET_LOCAL(0),
+                                 WASM_RTT_CANON(WASM_HEAP_TYPE(to_heap)))},
+                  kAppendEnd,
+                  "ref.cast: rtt type must be subtype of object type");
+  }
+
+  // Trivial type error.
+  ExpectFailure(sigs.v_v(),
+                {WASM_REF_TEST(kLocalEqRef, kLocalI31Ref, WASM_I32V(1),
+                               WASM_RTT_CANON(kLocalI31Ref)),
+                 kExprDrop},
+                kAppendEnd,
+                "ref.test[0] expected type eqref, found i32.const of type i32");
+  ExpectFailure(sigs.v_v(),
+                {WASM_REF_CAST(kLocalEqRef, kLocalI31Ref, WASM_I32V(1),
+                               WASM_RTT_CANON(kLocalI31Ref)),
+                 kExprDrop},
+                kAppendEnd,
+                "ref.cast[0] expected type eqref, found i32.const of type i32");
+
+  // Mismached object heap immediate.
+  {
+    ValueType arg_type = ValueType::Ref(HeapType::kEq, kNonNullable);
+    FunctionSig sig(0, 1, &arg_type);
+    ExpectFailure(
+        &sig,
+        {WASM_REF_TEST(kLocalEqRef, static_cast<byte>(array_heap),
+                       WASM_GET_LOCAL(0), WASM_RTT_CANON(kLocalI31Ref)),
+         kExprDrop},
+        kAppendEnd, "ref.test: expected rtt for type 0 but got (rtt 1 i31)");
+    ExpectFailure(
+        &sig,
+        {WASM_REF_CAST(kLocalEqRef, static_cast<byte>(array_heap),
+                       WASM_GET_LOCAL(0), WASM_RTT_CANON(kLocalI31Ref)),
+         kExprDrop},
+        kAppendEnd, "ref.cast: expected rtt for type 0 but got (rtt 1 i31)");
+  }
+}
+
 class BranchTableIteratorTest : public TestWithZone {
  public:
   BranchTableIteratorTest() : TestWithZone() {}