diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc index 3fb12c4f25..a3a7e894b4 100644 --- a/src/writer/spirv/builder.cc +++ b/src/writer/spirv/builder.cc @@ -445,6 +445,11 @@ uint32_t Builder::GenerateAccessorExpression(ast::Expression* expr) { auto* data_type = mem_accessor->structure()->result_type()->UnwrapPtrIfNeeded(); + + while (data_type->IsAlias()) { + data_type = data_type->AsAlias()->type(); + } + if (data_type->IsStruct()) { auto* strct = data_type->AsStruct()->impl(); auto name = mem_accessor->member()->name(); @@ -468,7 +473,7 @@ uint32_t Builder::GenerateAccessorExpression(ast::Expression* expr) { } else if (data_type->IsVector()) { // TODO(dsinclair): Handle swizzle } else { - error_ = "invalid type for member accessor"; + error_ = "invalid type for member accessor: " + data_type->type_name(); return 0; } } else { diff --git a/src/writer/spirv/builder_accessor_expression_test.cc b/src/writer/spirv/builder_accessor_expression_test.cc index df72fb745b..99f1f5c4f4 100644 --- a/src/writer/spirv/builder_accessor_expression_test.cc +++ b/src/writer/spirv/builder_accessor_expression_test.cc @@ -252,6 +252,75 @@ TEST_F(BuilderTest, MemberAccessor_Nested) { )"); } +TEST_F(BuilderTest, MemberAccessor_Nested_WithAlias) { + ast::type::F32Type f32; + + // type Inner = struct { + // a : f32 + // b : f32 + // } + // my_struct { + // inner : Inner + // } + // + // var ident : my_struct + // ident.inner.a + ast::StructMemberDecorationList decos; + ast::StructMemberList inner_members; + inner_members.push_back( + std::make_unique("a", &f32, std::move(decos))); + inner_members.push_back( + std::make_unique("b", &f32, std::move(decos))); + + ast::type::StructType inner_struct(std::make_unique( + ast::StructDecoration::kNone, std::move(inner_members))); + + ast::type::AliasType alias("Inner", &inner_struct); + + ast::StructMemberList outer_members; + outer_members.push_back(std::make_unique( + "inner", &alias, std::move(decos))); + + ast::type::StructType s_type(std::make_unique( + ast::StructDecoration::kNone, std::move(outer_members))); + s_type.set_name("my_struct"); + + ast::Variable var("ident", ast::StorageClass::kFunction, &s_type); + + ast::MemberAccessorExpression expr( + std::make_unique( + std::make_unique("ident"), + std::make_unique("inner")), + std::make_unique("a")); + + Context ctx; + ast::Module mod; + TypeDeterminer td(&ctx, &mod); + td.RegisterVariableForTesting(&var); + ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error(); + + Builder b(&mod); + b.push_function(Function{}); + ASSERT_TRUE(b.GenerateFunctionVariable(&var)) << b.error(); + + EXPECT_EQ(b.GenerateAccessorExpression(&expr), 6u); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32 +%4 = OpTypeStruct %5 %5 +%3 = OpTypeStruct %4 +%2 = OpTypePointer Function %3 +%7 = OpTypeInt 32 0 +%8 = OpConstant %7 0 +%9 = OpTypePointer Function %5 +)"); + EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), + R"(%1 = OpVariable %2 Function +)"); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), + R"(%6 = OpAccessChain %9 %1 %8 %8 +)"); +} + TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_LHS) { ast::type::F32Type f32;