Add type alias unwrapping methods
Change-Id: I8dbd3bba48ae95d76f75a5eba3e97ed4e091ed01
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/23580
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/src/ast/expression.cc b/src/ast/expression.cc
index bbbc7ad..c1c9765 100644
--- a/src/ast/expression.cc
+++ b/src/ast/expression.cc
@@ -38,10 +38,7 @@
void Expression::set_result_type(type::Type* type) {
// The expression result should never be an alias type
- while (type->IsAlias()) {
- type = type->AsAlias()->type();
- }
- result_type_ = type;
+ result_type_ = type->UnwrapAliasesIfNeeded();
}
bool Expression::IsArrayAccessor() const {
diff --git a/src/ast/type/alias_type_test.cc b/src/ast/type/alias_type_test.cc
index 38d05b6..35b85f8 100644
--- a/src/ast/type/alias_type_test.cc
+++ b/src/ast/type/alias_type_test.cc
@@ -15,7 +15,9 @@
#include "src/ast/type/alias_type.h"
#include "gtest/gtest.h"
+#include "src/ast/storage_class.h"
#include "src/ast/type/i32_type.h"
+#include "src/ast/type/pointer_type.h"
#include "src/ast/type/u32_type.h"
namespace tint {
@@ -54,6 +56,61 @@
EXPECT_EQ(at.type_name(), "__alias_Particle__i32");
}
+TEST_F(AliasTypeTest, UnwrapAliasesIfNeeded) {
+ U32Type u32;
+ AliasType a{"a_type", &u32};
+ EXPECT_EQ(a.name(), "a_type");
+ EXPECT_EQ(a.type(), &u32);
+ EXPECT_EQ(a.UnwrapAliasesIfNeeded(), &u32);
+ EXPECT_EQ(u32.UnwrapAliasesIfNeeded(), &u32);
+}
+
+TEST_F(AliasTypeTest, UnwrapAliasesIfNeeded_MultiLevel) {
+ U32Type u32;
+ AliasType a{"a_type", &u32};
+ AliasType aa{"aa_type", &a};
+ EXPECT_EQ(aa.name(), "aa_type");
+ EXPECT_EQ(aa.type(), &a);
+ EXPECT_EQ(aa.UnwrapAliasesIfNeeded(), &u32);
+}
+
+TEST_F(AliasTypeTest, UnwrapAliasPtrAlias_TwiceAliasPointerTwiceAlias) {
+ U32Type u32;
+ AliasType a{"a_type", &u32};
+ AliasType aa{"aa_type", &a};
+ PointerType paa{&aa, StorageClass::kUniform};
+ AliasType apaa{"paa_type", &paa};
+ AliasType aapaa{"aapaa_type", &apaa};
+ EXPECT_EQ(aapaa.name(), "aapaa_type");
+ EXPECT_EQ(aapaa.type(), &apaa);
+ EXPECT_EQ(aapaa.UnwrapAliasPtrAlias(), &u32);
+ EXPECT_EQ(u32.UnwrapAliasPtrAlias(), &u32);
+}
+
+TEST_F(AliasTypeTest,
+ UnwrapAliasPtrAlias_SecondConsecutivePointerBlocksWUnrapping) {
+ U32Type u32;
+ AliasType a{"a_type", &u32};
+ AliasType aa{"aa_type", &a};
+ PointerType paa{&aa, StorageClass::kUniform};
+ PointerType ppaa{&paa, StorageClass::kUniform};
+ AliasType appaa{"appaa_type", &ppaa};
+ EXPECT_EQ(appaa.UnwrapAliasPtrAlias(), &paa);
+}
+
+TEST_F(AliasTypeTest,
+ UnwrapAliasPtrAlias_SecondNonConsecutivePointerBlocksWUnrapping) {
+ U32Type u32;
+ AliasType a{"a_type", &u32};
+ AliasType aa{"aa_type", &a};
+ PointerType paa{&aa, StorageClass::kUniform};
+ AliasType apaa{"apaa_type", &paa};
+ AliasType aapaa{"aapaa_type", &apaa};
+ PointerType paapaa{&aapaa, StorageClass::kUniform};
+ AliasType apaapaa{"apaapaa_type", &paapaa};
+ EXPECT_EQ(apaapaa.UnwrapAliasPtrAlias(), &paa);
+}
+
} // namespace
} // namespace type
} // namespace ast
diff --git a/src/ast/type/type.cc b/src/ast/type/type.cc
index a5b3ece..8475e9a 100644
--- a/src/ast/type/type.cc
+++ b/src/ast/type/type.cc
@@ -43,6 +43,18 @@
return this;
}
+Type* Type::UnwrapAliasesIfNeeded() {
+ auto* where = this;
+ while (where->IsAlias()) {
+ where = where->AsAlias()->type();
+ }
+ return where;
+}
+
+Type* Type::UnwrapAliasPtrAlias() {
+ return UnwrapAliasesIfNeeded()->UnwrapPtrIfNeeded()->UnwrapAliasesIfNeeded();
+}
+
bool Type::IsAlias() const {
return false;
}
diff --git a/src/ast/type/type.h b/src/ast/type/type.h
index e368bad..b7086aa 100644
--- a/src/ast/type/type.h
+++ b/src/ast/type/type.h
@@ -69,6 +69,21 @@
/// @returns the pointee type if this is a pointer, |this| otherwise
Type* UnwrapPtrIfNeeded();
+ /// Removes all levels of aliasing, if this is an alias type. Otherwise
+ /// returns |this|. This is just enough to assist with WGSL translation
+ /// in that you want see through one level of pointer to get from an
+ /// identifier-like expression as an l-value to its corresponding r-value,
+ /// plus see through the aliases on either side.
+ /// @returns the completely unaliased type.
+ Type* UnwrapAliasesIfNeeded();
+
+ /// Returns the type found after:
+ /// - removing all layers of aliasing if they exist, then
+ /// - removing the pointer, if it exists, then
+ /// - removing all further layers of aliasing, if they exist
+ /// @returns the unwrapped type
+ Type* UnwrapAliasPtrAlias();
+
/// @returns true if this type is a float scalar
bool is_float_scalar();
/// @returns true if this type is a float matrix
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index 1a7dd00..d118b19 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -586,11 +586,7 @@
}
auto* res = expr->structure()->result_type();
- auto* data_type = res->UnwrapPtrIfNeeded();
-
- while (data_type->IsAlias()) {
- data_type = data_type->AsAlias()->type();
- }
+ auto* data_type = res->UnwrapPtrIfNeeded()->UnwrapAliasesIfNeeded();
ast::type::Type* ret = nullptr;
if (data_type->IsStruct()) {
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index 586b045..0157837 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -642,10 +642,10 @@
bool Builder::GenerateMemberAccessor(ast::MemberAccessorExpression* expr,
AccessorInfo* info) {
- auto* data_type = expr->structure()->result_type()->UnwrapPtrIfNeeded();
- while (data_type->IsAlias()) {
- data_type = data_type->AsAlias()->type();
- }
+ auto* data_type = expr->structure()
+ ->result_type()
+ ->UnwrapPtrIfNeeded()
+ ->UnwrapAliasesIfNeeded();
// If the data_type is a structure we're accessing a member, if it's a
// vector we're accessing a swizzle.