Remove sem::Alias

With the parsers now using ast::Types, nothing should be producing these any more.

This change also removes Resolver::Canonical(), which is now unneeded as there are no sem::Aliases to remove.

Bug: tint:724
Change-Id: I0c1a49f49372c1fcc37864502f07c5c76328d471
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/50304
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
Ben Clayton 2021-05-10 17:38:01 +00:00 committed by Commit Bot service account
parent cbbe576415
commit a34fa0ecb7
63 changed files with 143 additions and 661 deletions

View File

@ -447,8 +447,6 @@ libtint_source_set("libtint_core_all_src") {
"scope_stack.h",
"sem/access_control_type.cc",
"sem/access_control_type.h",
"sem/alias_type.cc",
"sem/alias_type.h",
"sem/array.h",
"sem/bool_type.cc",
"sem/bool_type.h",

View File

@ -287,8 +287,6 @@ set(TINT_LIB_SRCS
transform/vertex_pulling.h
sem/access_control_type.cc
sem/access_control_type.h
sem/alias_type.cc
sem/alias_type.h
sem/bool_type.cc
sem/bool_type.h
sem/depth_texture_type.cc
@ -567,7 +565,6 @@ if(${TINT_BUILD_TESTS})
transform/transform_test.cc
test_main.cc
sem/access_control_type_test.cc
sem/alias_type_test.cc
sem/bool_type_test.cc
sem/depth_texture_type_test.cc
sem/external_texture_type_test.cc

View File

@ -89,13 +89,10 @@ class Matcher {
virtual ~Matcher() = default;
/// Checks whether the given argument type matches.
/// Aliases are automatically unwrapped before matching.
/// Match may add to, or compare against the open types and numbers in state.
/// @returns true if the argument type is as expected.
bool Match(MatchState& state, const sem::Type* argument_type) const {
auto* unwrapped = argument_type->UnwrapAliasIfNeeded();
return MatchUnwrapped(state, unwrapped);
}
virtual bool Match(MatchState& state,
const sem::Type* argument_type) const = 0;
/// @return true if the matcher is expecting a pointer. If this method returns
/// false and the argument is a pointer type, then the argument should be
@ -107,12 +104,6 @@ class Matcher {
virtual std::string str() const = 0;
protected:
/// Checks whether the given alias-unwrapped argument type matches.
/// Match may add to, or compare against the open types and numbers in state.
/// @returns true if the argument type is as expected.
virtual bool MatchUnwrapped(MatchState& state,
const sem::Type* argument_type) const = 0;
/// Checks `state.open_type` to see if the OpenType `t` is equal to the type
/// `ty`. If `state.open_type` does not contain an entry for `t`, then `ty`
/// is added and returns true.
@ -167,7 +158,7 @@ class OpenTypeBuilder : public Builder {
public:
explicit OpenTypeBuilder(OpenType open_type) : open_type_(open_type) {}
bool MatchUnwrapped(MatchState& state, const sem::Type* ty) const override {
bool Match(MatchState& state, const sem::Type* ty) const override {
return MatchOpenType(state, open_type_, ty);
}
@ -184,7 +175,7 @@ class OpenTypeBuilder : public Builder {
/// VoidBuilder is a Matcher / Builder for void types.
class VoidBuilder : public Builder {
public:
bool MatchUnwrapped(MatchState&, const sem::Type* ty) const override {
bool Match(MatchState&, const sem::Type* ty) const override {
return ty->Is<sem::Void>();
}
sem::Type* Build(BuildState& state) const override {
@ -196,7 +187,7 @@ class VoidBuilder : public Builder {
/// BoolBuilder is a Matcher / Builder for boolean types.
class BoolBuilder : public Builder {
public:
bool MatchUnwrapped(MatchState&, const sem::Type* ty) const override {
bool Match(MatchState&, const sem::Type* ty) const override {
return ty->Is<sem::Bool>();
}
sem::Type* Build(BuildState& state) const override {
@ -208,7 +199,7 @@ class BoolBuilder : public Builder {
/// F32Builder is a Matcher / Builder for f32 types.
class F32Builder : public Builder {
public:
bool MatchUnwrapped(MatchState&, const sem::Type* ty) const override {
bool Match(MatchState&, const sem::Type* ty) const override {
return ty->Is<sem::F32>();
}
sem::Type* Build(BuildState& state) const override {
@ -220,7 +211,7 @@ class F32Builder : public Builder {
/// U32Builder is a Matcher / Builder for u32 types.
class U32Builder : public Builder {
public:
bool MatchUnwrapped(MatchState&, const sem::Type* ty) const override {
bool Match(MatchState&, const sem::Type* ty) const override {
return ty->Is<sem::U32>();
}
sem::Type* Build(BuildState& state) const override {
@ -232,7 +223,7 @@ class U32Builder : public Builder {
/// I32Builder is a Matcher / Builder for i32 types.
class I32Builder : public Builder {
public:
bool MatchUnwrapped(MatchState&, const sem::Type* ty) const override {
bool Match(MatchState&, const sem::Type* ty) const override {
return ty->Is<sem::I32>();
}
sem::Type* Build(BuildState& state) const override {
@ -244,7 +235,7 @@ class I32Builder : public Builder {
/// IU32Matcher is a Matcher for i32 or u32 types.
class IU32Matcher : public Matcher {
public:
bool MatchUnwrapped(MatchState&, const sem::Type* ty) const override {
bool Match(MatchState&, const sem::Type* ty) const override {
return ty->Is<sem::I32>() || ty->Is<sem::U32>();
}
std::string str() const override { return "i32 or u32"; }
@ -253,7 +244,7 @@ class IU32Matcher : public Matcher {
/// FIU32Matcher is a Matcher for f32, i32 or u32 types.
class FIU32Matcher : public Matcher {
public:
bool MatchUnwrapped(MatchState&, const sem::Type* ty) const override {
bool Match(MatchState&, const sem::Type* ty) const override {
return ty->Is<sem::F32>() || ty->Is<sem::I32>() || ty->Is<sem::U32>();
}
std::string str() const override { return "f32, i32 or u32"; }
@ -262,7 +253,7 @@ class FIU32Matcher : public Matcher {
/// ScalarMatcher is a Matcher for f32, i32, u32 or boolean types.
class ScalarMatcher : public Matcher {
public:
bool MatchUnwrapped(MatchState&, const sem::Type* ty) const override {
bool Match(MatchState&, const sem::Type* ty) const override {
return ty->is_scalar();
}
std::string str() const override { return "scalar"; }
@ -275,7 +266,7 @@ class OpenSizeVecBuilder : public Builder {
OpenSizeVecBuilder(OpenNumber size, Builder* element_builder)
: size_(size), element_builder_(element_builder) {}
bool MatchUnwrapped(MatchState& state, const sem::Type* ty) const override {
bool Match(MatchState& state, const sem::Type* ty) const override {
if (auto* vec = ty->As<sem::Vector>()) {
if (!MatchOpenNumber(state, size_, vec->size())) {
return false;
@ -307,7 +298,7 @@ class VecBuilder : public Builder {
VecBuilder(uint32_t size, Builder* element_builder)
: size_(size), element_builder_(element_builder) {}
bool MatchUnwrapped(MatchState& state, const sem::Type* ty) const override {
bool Match(MatchState& state, const sem::Type* ty) const override {
if (auto* vec = ty->As<sem::Vector>()) {
if (vec->size() == size_) {
return element_builder_->Match(state, vec->type());
@ -339,7 +330,7 @@ class OpenSizeMatBuilder : public Builder {
Builder* element_builder)
: columns_(columns), rows_(rows), element_builder_(element_builder) {}
bool MatchUnwrapped(MatchState& state, const sem::Type* ty) const override {
bool Match(MatchState& state, const sem::Type* ty) const override {
if (auto* mat = ty->As<sem::Matrix>()) {
if (!MatchOpenNumber(state, columns_, mat->columns())) {
return false;
@ -378,7 +369,7 @@ class PtrBuilder : public Builder {
explicit PtrBuilder(Builder* element_builder)
: element_builder_(element_builder) {}
bool MatchUnwrapped(MatchState& state, const sem::Type* ty) const override {
bool Match(MatchState& state, const sem::Type* ty) const override {
if (auto* ptr = ty->As<sem::Pointer>()) {
return element_builder_->Match(state, ptr->type());
}
@ -407,7 +398,7 @@ class ArrayBuilder : public Builder {
explicit ArrayBuilder(Builder* element_builder)
: element_builder_(element_builder) {}
bool MatchUnwrapped(MatchState& state, const sem::Type* ty) const override {
bool Match(MatchState& state, const sem::Type* ty) const override {
if (auto* arr = ty->As<sem::Array>()) {
if (arr->IsRuntimeSized()) {
return element_builder_->Match(state, arr->ElemType());
@ -436,7 +427,7 @@ class SampledTextureBuilder : public Builder {
Builder* type_builder)
: dimensions_(dimensions), type_builder_(type_builder) {}
bool MatchUnwrapped(MatchState& state, const sem::Type* ty) const override {
bool Match(MatchState& state, const sem::Type* ty) const override {
if (auto* tex = ty->As<sem::SampledTexture>()) {
if (tex->dim() == dimensions_) {
return type_builder_->Match(state, tex->type());
@ -469,7 +460,7 @@ class MultisampledTextureBuilder : public Builder {
Builder* type_builder)
: dimensions_(dimensions), type_builder_(type_builder) {}
bool MatchUnwrapped(MatchState& state, const sem::Type* ty) const override {
bool Match(MatchState& state, const sem::Type* ty) const override {
if (auto* tex = ty->As<sem::MultisampledTexture>()) {
if (tex->dim() == dimensions_) {
return type_builder_->Match(state, tex->type());
@ -501,7 +492,7 @@ class DepthTextureBuilder : public Builder {
explicit DepthTextureBuilder(ast::TextureDimension dimensions)
: dimensions_(dimensions) {}
bool MatchUnwrapped(MatchState&, const sem::Type* ty) const override {
bool Match(MatchState&, const sem::Type* ty) const override {
if (auto* tex = ty->As<sem::DepthTexture>()) {
return tex->dim() == dimensions_;
}
@ -534,7 +525,7 @@ class StorageTextureBuilder : public Builder {
texel_format_(texel_format),
channel_format_(channel_format) {}
bool MatchUnwrapped(MatchState& state, const sem::Type* ty) const override {
bool Match(MatchState& state, const sem::Type* ty) const override {
if (auto* ac = ty->As<sem::AccessControl>()) {
// If we have an storage texture argument that's got an access control
// type wrapped around it, accept it. Signatures that don't include an
@ -579,7 +570,7 @@ class ExternalTextureBuilder : public Builder {
public:
ExternalTextureBuilder() {}
bool MatchUnwrapped(MatchState&, const sem::Type* ty) const override {
bool Match(MatchState&, const sem::Type* ty) const override {
return ty->Is<sem::ExternalTexture>();
}
@ -595,7 +586,7 @@ class SamplerBuilder : public Builder {
public:
explicit SamplerBuilder(ast::SamplerKind kind) : kind_(kind) {}
bool MatchUnwrapped(MatchState&, const sem::Type* ty) const override {
bool Match(MatchState&, const sem::Type* ty) const override {
if (auto* sampler = ty->As<sem::Sampler>()) {
return sampler->kind() == kind_;
}
@ -627,7 +618,7 @@ class AccessControlBuilder : public Builder {
Builder* type)
: access_control_(access_control), type_(type) {}
bool MatchUnwrapped(MatchState& state, const sem::Type* ty) const override {
bool Match(MatchState& state, const sem::Type* ty) const override {
if (auto* ac = ty->As<sem::AccessControl>()) {
if (ac->access_control() == access_control_) {
return type_->Match(state, ty);

View File

@ -352,35 +352,6 @@ TEST_F(IntrinsicTableTest, MatchAutoPointerDereference) {
EXPECT_THAT(result.intrinsic->Parameters(), ElementsAre(Parameter{ty.f32()}));
}
TEST_F(IntrinsicTableTest, MatchWithAliasUnwrapping) {
auto alias_a = ty.alias("alias_a", ty.f32());
auto alias_b = ty.alias("alias_b", alias_a);
auto alias_c = ty.alias("alias_c", alias_b);
auto result = table->Lookup(*this, IntrinsicType::kCos, {alias_c}, Source{});
ASSERT_NE(result.intrinsic, nullptr);
ASSERT_EQ(result.diagnostics.str(), "");
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kCos);
EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
EXPECT_THAT(result.intrinsic->Parameters(), ElementsAre(Parameter{ty.f32()}));
}
TEST_F(IntrinsicTableTest, MatchWithNestedAliasUnwrapping) {
auto alias_a = ty.alias("alias_a", ty.bool_());
auto alias_b = ty.alias("alias_b", alias_a);
auto alias_c = ty.alias("alias_c", alias_b);
auto vec4_of_c = ty.vec4(alias_c);
auto alias_d = ty.alias("alias_d", vec4_of_c);
auto alias_e = ty.alias("alias_e", alias_d);
auto result = table->Lookup(*this, IntrinsicType::kAll, {alias_e}, Source{});
ASSERT_NE(result.intrinsic, nullptr);
ASSERT_EQ(result.diagnostics.str(), "");
EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kAll);
EXPECT_THAT(result.intrinsic->ReturnType(), ty.bool_());
EXPECT_THAT(result.intrinsic->Parameters(),
ElementsAre(Parameter{ty.vec4<bool>()}));
}
TEST_F(IntrinsicTableTest, MatchOpenType) {
auto result = table->Lookup(*this, IntrinsicType::kClamp,
{ty.f32(), ty.f32(), ty.f32()}, Source{});

View File

@ -60,7 +60,6 @@
#include "src/program.h"
#include "src/program_id.h"
#include "src/sem/access_control_type.h"
#include "src/sem/alias_type.h"
#include "src/sem/array.h"
#include "src/sem/bool_type.h"
#include "src/sem/depth_texture_type.h"
@ -682,13 +681,10 @@ class ProgramBuilder {
/// @param type the alias type
/// @returns the alias pointer
template <typename NAME>
typ::Alias alias(NAME&& name, typ::Type type) const {
ast::Alias* alias(NAME&& name, typ::Type type) const {
type = MaybeCreateTypename(type);
auto sym = builder->Sym(std::forward<NAME>(name));
return {
type.ast ? builder->create<ast::Alias>(sym, type) : nullptr,
type.sem ? builder->create<sem::Alias>(sym, type) : nullptr,
};
return builder->create<ast::Alias>(sym, type);
}
/// Creates an alias type
@ -697,13 +693,10 @@ class ProgramBuilder {
/// @param type the alias type
/// @returns the alias pointer
template <typename NAME>
typ::Alias alias(const Source& source, NAME&& name, typ::Type type) const {
ast::Alias* alias(const Source& source, NAME&& name, typ::Type type) const {
type = MaybeCreateTypename(type);
auto sym = builder->Sym(std::forward<NAME>(name));
return {
type.ast ? builder->create<ast::Alias>(source, sym, type) : nullptr,
type.sem ? builder->create<sem::Alias>(sym, type) : nullptr,
};
return builder->create<ast::Alias>(source, sym, type);
}
/// Creates an access control qualifier type

View File

@ -1206,7 +1206,7 @@ const Type* ParserImpl::MaybeGenerateAlias(
}
const auto name = namer_.GetName(type_id);
const auto sym = builder_.Symbols().Register(name);
auto ast_alias_type =
auto* ast_alias_type =
builder_.ty.alias(sym, ast_underlying_type->Build(builder_));
// Record this new alias as the AST type for this SPIR-V ID.

View File

@ -985,8 +985,8 @@ Maybe<ast::Alias*> ParserImpl::type_alias() {
if (!type.matched)
return add_error(peek(), "invalid type alias");
auto alias = builder_.ty.alias(make_source_range_from(t.source()), name.value,
type.value);
auto* alias = builder_.ty.alias(make_source_range_from(t.source()),
name.value, type.value);
register_constructed(name.value, alias);
return alias;
}

View File

@ -37,7 +37,7 @@ TEST_F(ParserImplTest, TypeDecl_Identifier) {
auto p = parser("A");
auto& builder = p->builder();
auto alias_type = builder.ty.alias("A", builder.ty.i32());
auto* alias_type = builder.ty.alias("A", builder.ty.i32());
p->register_constructed("A", alias_type);
auto t = p->type_decl();

View File

@ -166,7 +166,7 @@ TEST_F(ResolverAssignmentValidationTest,
// alias myint = i32;
// var a :myint = 2;
// a = 2
auto myint = ty.alias("myint", ty.i32());
auto* myint = ty.alias("myint", ty.i32());
AST().AddConstructedType(myint);
auto* var = Var("a", myint, ast::StorageClass::kNone, Expr(2));

View File

@ -294,7 +294,7 @@ TEST_F(ResolverControlBlockValidationTest, SwitchCaseAlias_Pass) {
// default: {}
// }
auto my_int = ty.alias("MyInt", ty.u32());
auto* my_int = ty.alias("MyInt", ty.u32());
auto* var = Var("a", my_int, ast::StorageClass::kNone, Expr(2u));
ast::CaseSelectorList default_csl;

View File

@ -157,7 +157,7 @@ TEST_F(ResolverFunctionValidationTest,
FunctionTypeMustMatchReturnStatementTypeF32Alias_pass) {
// type myf32 = f32;
// fn func -> myf32 { return 2.0; }
auto myf32 = ty.alias("myf32", ty.f32());
auto* myf32 = ty.alias("myf32", ty.f32());
AST().AddConstructedType(myf32);
Func("func", ast::VariableList{}, myf32,
ast::StatementList{
@ -172,7 +172,7 @@ TEST_F(ResolverFunctionValidationTest,
FunctionTypeMustMatchReturnStatementTypeF32Alias_fail) {
// type myf32 = f32;
// fn func -> myf32 { return 2; }
auto myf32 = ty.alias("myf32", ty.f32());
auto* myf32 = ty.alias("myf32", ty.f32());
AST().AddConstructedType(myf32);
Func("func", ast::VariableList{}, myf32,
ast::StatementList{

View File

@ -57,12 +57,12 @@ TEST_F(ResolverHostShareableValidationTest, BoolVectorMember) {
}
TEST_F(ResolverHostShareableValidationTest, Aliases) {
auto a1 = ty.alias("a1", ty.bool_());
auto* a1 = ty.alias("a1", ty.bool_());
AST().AddConstructedType(a1);
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", a1)},
{create<ast::StructBlockDecoration>()});
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
auto a2 = ty.alias("a2", ac);
auto* a2 = ty.alias("a2", ac);
AST().AddConstructedType(a2);
Global(Source{{56, 78}}, "g", a2, ast::StorageClass::kStorage);
@ -104,14 +104,14 @@ TEST_F(ResolverHostShareableValidationTest, NoError) {
Member(Source{{2, 1}}, "y1", ty.vec3<f32>()),
Member(Source{{3, 1}}, "z1", ty.array<i32, 4>()),
});
auto a1 = ty.alias("a1", i1);
auto* a1 = ty.alias("a1", i1);
AST().AddConstructedType(a1);
auto* i2 = Structure("I2", {
Member(Source{{4, 1}}, "x2", ty.mat2x2<f32>()),
Member(Source{{5, 1}}, "y2", i1),
Member(Source{{6, 1}}, "z2", ty.mat3x2<i32>()),
});
auto a2 = ty.alias("a2", i2);
auto* a2 = ty.alias("a2", i2);
AST().AddConstructedType(a2);
auto* i3 = Structure("I3", {
Member(Source{{4, 1}}, "x3", a1),

View File

@ -79,14 +79,6 @@ TEST_F(ResolverIsHostShareable, Pointer) {
r()->IsHostShareable(ty.pointer<i32>(ast::StorageClass::kPrivate)));
}
TEST_F(ResolverIsHostShareable, AliasVoid) {
EXPECT_FALSE(r()->IsHostShareable(ty.alias("a", ty.void_())));
}
TEST_F(ResolverIsHostShareable, AliasI32) {
EXPECT_TRUE(r()->IsHostShareable(ty.alias("a", ty.i32())));
}
TEST_F(ResolverIsHostShareable, AccessControlVoid) {
EXPECT_FALSE(r()->IsHostShareable(
ty.access(ast::AccessControl::kReadOnly, ty.void_())));

View File

@ -63,14 +63,6 @@ TEST_F(ResolverIsStorableTest, Pointer) {
EXPECT_FALSE(r()->IsStorable(ty.pointer<i32>(ast::StorageClass::kPrivate)));
}
TEST_F(ResolverIsStorableTest, AliasVoid) {
EXPECT_FALSE(r()->IsStorable(ty.alias("a", ty.void_())));
}
TEST_F(ResolverIsStorableTest, AliasI32) {
EXPECT_TRUE(r()->IsStorable(ty.alias("a", ty.i32())));
}
TEST_F(ResolverIsStorableTest, AccessControlVoid) {
EXPECT_FALSE(r()->IsStorable(
create<sem::AccessControl>(ast::AccessControl::kReadOnly, ty.void_())));

View File

@ -430,8 +430,8 @@ Resolver::VariableInfo* Resolver::Variable(
return nullptr;
}
auto* ctype = Canonical(const_cast<sem::Type*>(type));
auto* info = variable_infos_.Create(var, ctype, type_name);
auto* info =
variable_infos_.Create(var, const_cast<sem::Type*>(type), type_name);
variable_to_info_.emplace(var, info);
return info;
@ -797,7 +797,7 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
}
// Check that we saw a pipeline IO attribute iff we need one.
if (Canonical(ty)->Is<sem::Struct>()) {
if (ty->Is<sem::Struct>()) {
if (pipeline_io_attribute) {
diagnostics_.add_error(
"entry point IO attributes must not be used on structure " +
@ -823,7 +823,7 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
// of numeric scalars.
// Testing for being a struct is handled by the if portion above.
if (!pipeline_io_attribute->Is<ast::BuiltinDecoration>()) {
if (!Canonical(ty)->is_numeric_scalar_or_vector()) {
if (!ty->is_numeric_scalar_or_vector()) {
diagnostics_.add_error(
"User defined entry point IO types must be a numeric scalar, "
"a numeric vector, or a structure",
@ -846,12 +846,11 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
return false;
}
if (auto* str = Canonical(ty)->As<sem::Struct>()) {
if (auto* str = ty->As<sem::Struct>()) {
// Validate the decorations for each struct members, and also check for
// invalid member types.
for (auto* member : str->Members()) {
auto* member_ty = Canonical(member->Type());
if (member_ty->Is<sem::Struct>()) {
if (member->Type()->Is<sem::Struct>()) {
diagnostics_.add_error(
"entry point IO types cannot contain nested structures",
member->Declaration()->source());
@ -859,7 +858,9 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
builder_->Symbols().NameFor(func->symbol()),
func->source());
return false;
} else if (auto* arr = member_ty->As<sem::Array>()) {
}
if (auto* arr = member->Type()->As<sem::Array>()) {
if (arr->IsRuntimeSized()) {
diagnostics_.add_error(
"entry point IO types cannot contain runtime sized arrays",
@ -873,7 +874,7 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
}
if (!validate_entry_point_decorations_inner(
member->Declaration()->decorations(), member_ty,
member->Declaration()->decorations(), member->Type(),
member->Declaration()->source(), param_or_ret, true)) {
diagnostics_.add_note("while analysing entry point " +
builder_->Symbols().NameFor(func->symbol()),
@ -992,8 +993,6 @@ bool Resolver::Function(ast::Function* func) {
info->return_type->FriendlyName(builder_->Symbols());
}
info->return_type = Canonical(info->return_type);
if (auto* str = info->return_type->As<sem::Struct>()) {
if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, str,
func->source())) {
@ -1746,11 +1745,8 @@ bool Resolver::ValidateBinary(ast::BinaryExpression* expr) {
using Matrix = sem::Matrix;
using Vector = sem::Vector;
auto* lhs_declared_type = TypeOf(expr->lhs())->UnwrapAll();
auto* rhs_declared_type = TypeOf(expr->rhs())->UnwrapAll();
auto* lhs_type = Canonical(const_cast<sem::Type*>(lhs_declared_type));
auto* rhs_type = Canonical(const_cast<sem::Type*>(rhs_declared_type));
auto* lhs_type = const_cast<sem::Type*>(TypeOf(expr->lhs())->UnwrapAll());
auto* rhs_type = const_cast<sem::Type*>(TypeOf(expr->rhs())->UnwrapAll());
auto* lhs_vec = lhs_type->As<Vector>();
auto* lhs_vec_elem_type = lhs_vec ? lhs_vec->type() : nullptr;
@ -1895,9 +1891,9 @@ bool Resolver::ValidateBinary(ast::BinaryExpression* expr) {
diagnostics_.add_error(
"Binary expression operand types are invalid for this operation: " +
lhs_declared_type->FriendlyName(builder_->Symbols()) + " " +
lhs_type->FriendlyName(builder_->Symbols()) + " " +
FriendlyName(expr->op()) + " " +
rhs_declared_type->FriendlyName(builder_->Symbols()),
rhs_type->FriendlyName(builder_->Symbols()),
expr->source());
return false;
}
@ -2142,7 +2138,6 @@ void Resolver::SetType(ast::Expression* expr,
TINT_ICE(builder_->Diagnostics())
<< "SetType() called twice for the same expression";
}
type = Canonical(type);
expr_info_.emplace(expr, ExpressionInfo{type, type_name, current_statement_});
}
@ -2262,13 +2257,12 @@ bool Resolver::DefaultAlignAndSize(const sem::Type* ty,
/*vec4*/ 16,
};
auto* cty = Canonical(const_cast<sem::Type*>(ty));
if (cty->is_scalar()) {
if (ty->is_scalar()) {
// Note: Also captures booleans, but these are not host-shareable.
align = 4;
size = 4;
return true;
} else if (auto* vec = cty->As<sem::Vector>()) {
} else if (auto* vec = ty->As<sem::Vector>()) {
if (vec->size() < 2 || vec->size() > 4) {
TINT_UNREACHABLE(diagnostics_)
<< "Invalid vector size: vec" << vec->size();
@ -2277,7 +2271,7 @@ bool Resolver::DefaultAlignAndSize(const sem::Type* ty,
align = vector_align[vec->size()];
size = vector_size[vec->size()];
return true;
} else if (auto* mat = cty->As<sem::Matrix>()) {
} else if (auto* mat = ty->As<sem::Matrix>()) {
if (mat->columns() < 2 || mat->columns() > 4 || mat->rows() < 2 ||
mat->rows() > 4) {
TINT_UNREACHABLE(diagnostics_)
@ -2287,11 +2281,11 @@ bool Resolver::DefaultAlignAndSize(const sem::Type* ty,
align = vector_align[mat->rows()];
size = vector_align[mat->rows()] * mat->columns();
return true;
} else if (auto* s = cty->As<sem::Struct>()) {
} else if (auto* s = ty->As<sem::Struct>()) {
align = s->Align();
size = s->Size();
return true;
} else if (auto* a = cty->As<sem::Array>()) {
} else if (auto* a = ty->As<sem::Array>()) {
align = a->Align();
size = a->SizeInBytes();
return true;
@ -2818,45 +2812,6 @@ std::string Resolver::VectorPretty(uint32_t size,
return vec_type.FriendlyName(builder_->Symbols());
}
sem::Type* Resolver::Canonical(sem::Type* type) {
using AccessControl = sem::AccessControl;
using Alias = sem::Alias;
using Matrix = sem::Matrix;
using Type = sem::Type;
using Vector = sem::Vector;
if (!type) {
TINT_ICE(diagnostics_) << "Canonical() called with nullptr";
return nullptr;
}
std::function<Type*(Type*)> make_canonical;
make_canonical = [&](Type* t) -> sem::Type* {
// Unwrap alias sequence
Type* ct = t;
while (auto* p = ct->As<Alias>()) {
ct = p->type();
}
if (auto* v = ct->As<Vector>()) {
return builder_->create<Vector>(make_canonical(v->type()), v->size());
}
if (auto* m = ct->As<Matrix>()) {
auto* column_type =
builder_->create<sem::Vector>(make_canonical(m->type()), m->rows());
return builder_->create<Matrix>(column_type, m->columns());
}
if (auto* ac = ct->As<AccessControl>()) {
return builder_->create<AccessControl>(ac->access_control(),
make_canonical(ac->type()));
}
return ct;
};
return utils::GetOrCreate(type_to_canonical_, type,
[&] { return make_canonical(type); });
}
void Resolver::Mark(const ast::Node* node) {
if (node == nullptr) {
TINT_ICE(diagnostics_) << "Resolver::Mark() called with nullptr";

View File

@ -83,12 +83,6 @@ class Resolver {
/// structure member or array element of type `lhs`
static bool IsValidAssignment(const sem::Type* lhs, const sem::Type* rhs);
/// @param type the input type
/// @returns the canonical type for `type`; that is, a type with all aliases
/// removed. For example, `Canonical(alias<alias<vec3<alias<f32>>>>)` is
/// `vec3<f32>`.
sem::Type* Canonical(sem::Type* type);
private:
/// Structure holding semantic information about a variable.
/// Used to build the sem::Variable nodes at the end of resolving.
@ -351,7 +345,6 @@ class Resolver {
std::unordered_map<const ast::Variable*, VariableInfo*> variable_to_info_;
std::unordered_map<ast::CallExpression*, FunctionCallInfo> function_calls_;
std::unordered_map<const ast::Expression*, ExpressionInfo> expr_info_;
std::unordered_map<sem::Type*, sem::Type*> type_to_canonical_;
std::unordered_map<Symbol, sem::Type*> named_types_;
std::unordered_set<const ast::Node*> marked_;
FunctionInfo* current_function_ = nullptr;

View File

@ -260,7 +260,7 @@ TEST_F(ResolverTest, Stmt_VariableDecl) {
}
TEST_F(ResolverTest, Stmt_VariableDecl_Alias) {
auto my_int = ty.alias("MyInt", ty.i32());
auto* my_int = ty.alias("MyInt", ty.i32());
AST().AddConstructedType(my_int);
auto* var = Var("my_var", my_int, ast::StorageClass::kNone, Expr(2));
auto* init = var->constructor();
@ -408,7 +408,7 @@ TEST_F(ResolverTest, Expr_ArrayAccessor_Array) {
}
TEST_F(ResolverTest, Expr_ArrayAccessor_Alias_Array) {
auto aary = ty.alias("myarrty", ty.array<f32, 3>());
auto* aary = ty.alias("myarrty", ty.array<f32, 3>());
AST().AddConstructedType(aary);
Global("my_var", aary, ast::StorageClass::kFunction);
@ -909,7 +909,7 @@ TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
TEST_F(ResolverTest, Expr_MemberAccessor_Struct_Alias) {
auto* st = Structure("S", {Member("first_member", ty.i32()),
Member("second_member", ty.f32())});
auto alias = ty.alias("alias", st);
auto* alias = ty.alias("alias", st);
AST().AddConstructedType(alias);
Global("my_struct", alias, ast::StorageClass::kInput);
@ -1234,18 +1234,18 @@ TEST_P(Expr_Binary_Test_WithAlias_Valid, All) {
// For vectors and matrices, wrap the sub type in an alias
auto make_alias = [this](ast::Type* type) -> ast::Type* {
if (auto* v = type->As<ast::Vector>()) {
auto alias = ty.alias(Symbols().New(), v->type());
auto* alias = ty.alias(Symbols().New(), v->type());
AST().AddConstructedType(alias);
return ty.vec(alias, v->size());
}
if (auto* m = type->As<ast::Matrix>()) {
auto alias = ty.alias(Symbols().New(), m->type());
auto* alias = ty.alias(Symbols().New(), m->type());
AST().AddConstructedType(alias);
return ty.mat(alias, m->columns(), m->rows());
}
auto alias = ty.alias(Symbols().New(), type);
auto* alias = ty.alias(Symbols().New(), type);
AST().AddConstructedType(alias);
return ty.type_name(alias.ast->name());
return ty.type_name(alias->name());
};
// Wrap in alias

View File

@ -75,7 +75,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferArray) {
TEST_F(ResolverStorageClassValidationTest, StorageBufferBoolAlias) {
// type a = bool;
// var<storage> g : [[access(read)]] a;
auto a = ty.alias("a", ty.bool_());
auto* a = ty.alias("a", ty.bool_());
AST().AddConstructedType(a);
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
@ -131,10 +131,10 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Aliases) {
// var<storage> g : a2;
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
{create<ast::StructBlockDecoration>()});
auto a1 = ty.alias("a1", s);
auto* a1 = ty.alias("a1", s);
AST().AddConstructedType(a1);
auto ac = ty.access(ast::AccessControl::kReadOnly, a1);
auto a2 = ty.alias("a2", ac);
auto* a2 = ty.alias("a2", ac);
AST().AddConstructedType(a2);
Global(Source{{56, 78}}, "g", a2, ast::StorageClass::kStorage);
@ -183,7 +183,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferArray) {
TEST_F(ResolverStorageClassValidationTest, UniformBufferBoolAlias) {
// type a = bool;
// var<uniform> g : [[access(read)]] a;
auto a = ty.alias("a", ty.bool_());
auto* a = ty.alias("a", ty.bool_());
AST().AddConstructedType(a);
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kUniform);
@ -224,7 +224,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Aliases) {
// var<uniform> g : a1;
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
{create<ast::StructBlockDecoration>()});
auto a1 = ty.alias("a1", s);
auto* a1 = ty.alias("a1", s);
AST().AddConstructedType(a1);
Global(Source{{56, 78}}, "g", a1, ast::StorageClass::kUniform);

View File

@ -52,9 +52,9 @@ TEST_F(ResolverStructLayoutTest, Scalars) {
}
TEST_F(ResolverStructLayoutTest, Alias) {
auto alias_a = ty.alias("a", ty.f32());
auto* alias_a = ty.alias("a", ty.f32());
AST().AddConstructedType(alias_a);
auto alias_b = ty.alias("b", ty.f32());
auto* alias_b = ty.alias("b", ty.f32());
AST().AddConstructedType(alias_b);
auto* s = Structure("S", {

View File

@ -158,7 +158,7 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedMultipleStages) {
TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderParamViaAlias) {
auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
auto s_alias = ty.alias("S_alias", s);
auto* s_alias = ty.alias("S_alias", s);
AST().AddConstructedType(s_alias);
Func("main", {Param("param", s_alias)}, ty.void_(), {},
@ -174,7 +174,7 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderParamViaAlias) {
TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderReturnTypeViaAlias) {
auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
auto s_alias = ty.alias("S_alias", s);
auto* s_alias = ty.alias("S_alias", s);
AST().AddConstructedType(s_alias);
Func("main", {}, s_alias, {Return(Construct(s_alias, Expr(0.f)))},

View File

@ -78,7 +78,7 @@ TEST_F(ResolverStorageClassUseTest, StructReachableFromGlobal) {
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalAlias) {
auto* s = Structure("S", {Member("a", ty.f32())});
auto a = ty.alias("A", s);
auto* a = ty.alias("A", s);
AST().AddConstructedType(a);
Global("g", a, ast::StorageClass::kPrivate);
@ -131,7 +131,7 @@ TEST_F(ResolverStorageClassUseTest, StructReachableFromLocal) {
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalAlias) {
auto* s = Structure("S", {Member("a", ty.f32())});
auto a = ty.alias("A", s);
auto* a = ty.alias("A", s);
AST().AddConstructedType(a);
WrapInFunction(Var("g", a, ast::StorageClass::kFunction));

View File

@ -431,7 +431,7 @@ TEST_F(ResolverTypeValidationTest, AliasRuntimeArrayIsNotLast_Fail) {
// a: u32;
//}
auto alias = ty.alias("RTArr", ty.array<u32>());
auto* alias = ty.alias("RTArr", ty.array<u32>());
AST().AddConstructedType(alias);
Structure("s",
@ -458,7 +458,7 @@ TEST_F(ResolverTypeValidationTest, AliasRuntimeArrayIsLast_Pass) {
// b: RTArr;
//}
auto alias = ty.alias("RTArr", ty.array<u32>());
auto* alias = ty.alias("RTArr", ty.array<u32>());
AST().AddConstructedType(alias);
Structure("s",

View File

@ -178,7 +178,7 @@ TEST_F(ResolverValidationTest,
TEST_F(ResolverValidationTest,
Stmt_VariableDecl_MismatchedTypeScalarConstructor_Alias) {
auto my_int = ty.alias("MyInt", ty.i32());
auto* my_int = ty.alias("MyInt", ty.i32());
AST().AddConstructedType(my_int);
u32 unsigned_value = 2u; // Type does not match variable type
auto* var =
@ -1699,7 +1699,7 @@ TEST_F(ResolverValidationTest,
}
TEST_F(ResolverValidationTest, Expr_Constructor_Vector_Alias_Argument_Error) {
auto alias = ty.alias("UnsignedInt", ty.u32());
auto* alias = ty.alias("UnsignedInt", ty.u32());
AST().AddConstructedType(alias);
Global("uint_var", alias, ast::StorageClass::kInput);
@ -1713,8 +1713,8 @@ TEST_F(ResolverValidationTest, Expr_Constructor_Vector_Alias_Argument_Error) {
}
TEST_F(ResolverValidationTest, Expr_Constructor_Vector_Alias_Argument_Success) {
auto f32_alias = ty.alias("Float32", ty.f32());
auto vec2_alias = ty.alias("VectorFloat2", ty.vec2<f32>());
auto* f32_alias = ty.alias("Float32", ty.f32());
auto* vec2_alias = ty.alias("VectorFloat2", ty.vec2<f32>());
AST().AddConstructedType(f32_alias);
AST().AddConstructedType(vec2_alias);
Global("my_f32", f32_alias, ast::StorageClass::kInput);
@ -1726,7 +1726,7 @@ TEST_F(ResolverValidationTest, Expr_Constructor_Vector_Alias_Argument_Success) {
}
TEST_F(ResolverValidationTest, Expr_Constructor_Vector_ElementTypeAlias_Error) {
auto f32_alias = ty.alias("Float32", ty.f32());
auto* f32_alias = ty.alias("Float32", ty.f32());
AST().AddConstructedType(f32_alias);
// vec2<Float32>(1.0f, 1u)
@ -1745,7 +1745,7 @@ TEST_F(ResolverValidationTest, Expr_Constructor_Vector_ElementTypeAlias_Error) {
TEST_F(ResolverValidationTest,
Expr_Constructor_Vector_ElementTypeAlias_Success) {
auto f32_alias = ty.alias("Float32", ty.f32());
auto* f32_alias = ty.alias("Float32", ty.f32());
AST().AddConstructedType(f32_alias);
// vec2<Float32>(1.0f, 1.0f)
@ -1759,7 +1759,7 @@ TEST_F(ResolverValidationTest,
TEST_F(ResolverValidationTest,
Expr_Constructor_Vector_ArgumentElementTypeAlias_Error) {
auto f32_alias = ty.alias("Float32", ty.f32());
auto* f32_alias = ty.alias("Float32", ty.f32());
AST().AddConstructedType(f32_alias);
// vec3<u32>(vec<Float32>(), 1.0f)
@ -1777,7 +1777,7 @@ TEST_F(ResolverValidationTest,
TEST_F(ResolverValidationTest,
Expr_Constructor_Vector_ArgumentElementTypeAlias_Success) {
auto f32_alias = ty.alias("Float32", ty.f32());
auto* f32_alias = ty.alias("Float32", ty.f32());
AST().AddConstructedType(f32_alias);
// vec3<f32>(vec<Float32>(), 1.0f)
@ -2008,7 +2008,7 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ElementTypeAlias_Error) {
// matNxM<Float32>(vecM<u32>(), ...); with N arguments
const auto param = GetParam();
auto f32_alias = ty.alias("Float32", ty.f32());
auto* f32_alias = ty.alias("Float32", ty.f32());
AST().AddConstructedType(f32_alias);
ast::ExpressionList args;
@ -2034,7 +2034,7 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ElementTypeAlias_Success) {
// matNxM<Float32>(vecM<f32>(), ...); with N arguments
const auto param = GetParam();
auto f32_alias = ty.alias("Float32", ty.f32());
auto* f32_alias = ty.alias("Float32", ty.f32());
AST().AddConstructedType(f32_alias);
ast::ExpressionList args;
@ -2053,7 +2053,7 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ElementTypeAlias_Success) {
}
TEST_F(ResolverValidationTest, Expr_MatrixConstructor_ArgumentTypeAlias_Error) {
auto alias = ty.alias("VectorUnsigned2", ty.vec2<u32>());
auto* alias = ty.alias("VectorUnsigned2", ty.vec2<u32>());
AST().AddConstructedType(alias);
auto* tc = mat2x2<f32>(
create<ast::TypeConstructorExpression>(
@ -2071,7 +2071,7 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentTypeAlias_Success) {
const auto param = GetParam();
auto matrix_type = ty.mat<f32>(param.columns, param.rows);
auto vec_type = ty.vec<f32>(param.rows);
auto vec_alias = ty.alias("VectorFloat2", vec_type);
auto* vec_alias = ty.alias("VectorFloat2", vec_type);
AST().AddConstructedType(vec_alias);
ast::ExpressionList args;
@ -2090,7 +2090,7 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentTypeAlias_Success) {
TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentElementTypeAlias_Error) {
const auto param = GetParam();
auto matrix_type = ty.mat<f32>(param.columns, param.rows);
auto f32_alias = ty.alias("UnsignedInt", ty.u32());
auto* f32_alias = ty.alias("UnsignedInt", ty.u32());
AST().AddConstructedType(f32_alias);
ast::ExpressionList args;
@ -2114,7 +2114,7 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentElementTypeAlias_Error) {
TEST_P(MatrixConstructorTest,
Expr_Constructor_ArgumentElementTypeAlias_Success) {
const auto param = GetParam();
auto f32_alias = ty.alias("Float32", ty.f32());
auto* f32_alias = ty.alias("Float32", ty.f32());
AST().AddConstructedType(f32_alias);
ast::ExpressionList args;

View File

@ -36,7 +36,6 @@ TEST_F(AccessControlTest, Is) {
AccessControl at{ast::AccessControl::kReadOnly, &i32};
Type* ty = &at;
EXPECT_TRUE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>());
EXPECT_FALSE(ty->Is<Array>());
EXPECT_FALSE(ty->Is<Bool>());
EXPECT_FALSE(ty->Is<F32>());

View File

@ -1,44 +0,0 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/sem/alias_type.h"
#include "src/program_builder.h"
TINT_INSTANTIATE_TYPEINFO(tint::sem::Alias);
namespace tint {
namespace sem {
Alias::Alias(const Symbol& sym, const Type* subtype)
: symbol_(sym),
subtype_(subtype),
type_name_("__alias_" + sym.to_str() + subtype->type_name()) {
TINT_ASSERT(subtype_);
}
Alias::Alias(Alias&&) = default;
Alias::~Alias() = default;
std::string Alias::type_name() const {
return type_name_;
}
std::string Alias::FriendlyName(const SymbolTable& symbols) const {
return symbols.NameFor(symbol_);
}
} // namespace sem
} // namespace tint

View File

@ -1,60 +0,0 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_SEM_ALIAS_TYPE_H_
#define SRC_SEM_ALIAS_TYPE_H_
#include <string>
#include "src/sem/type.h"
#include "src/symbol.h"
namespace tint {
namespace sem {
/// A type alias type. Holds a name and pointer to another type.
class Alias : public Castable<Alias, Type> {
public:
/// Constructor
/// @param sym the symbol for the alias
/// @param subtype the alias'd type
Alias(const Symbol& sym, const Type* subtype);
/// Move constructor
Alias(Alias&&);
/// Destructor
~Alias() override;
/// @returns the alias symbol
Symbol symbol() const { return symbol_; }
/// @returns the alias type
Type* type() const { return const_cast<Type*>(subtype_); }
/// @returns the type_name for this type
std::string type_name() const override;
/// @param symbols the program's symbol table
/// @returns the name for this type that closely resembles how it would be
/// declared in WGSL.
std::string FriendlyName(const SymbolTable& symbols) const override;
private:
Symbol const symbol_;
Type const* const subtype_;
std::string const type_name_;
};
} // namespace sem
} // namespace tint
#endif // SRC_SEM_ALIAS_TYPE_H_

View File

@ -1,162 +0,0 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/sem/access_control_type.h"
#include "src/sem/test_helper.h"
#include "src/sem/texture_type.h"
namespace tint {
namespace sem {
namespace {
using AliasTest = TestHelper;
TEST_F(AliasTest, Create) {
auto* a = create<Alias>(Sym("a_type"), ty.u32());
EXPECT_EQ(a->symbol(), Symbol(1, ID()));
EXPECT_EQ(a->type(), ty.u32());
}
TEST_F(AliasTest, Is) {
auto* at = create<Alias>(Sym("a"), ty.i32());
sem::Type* ty = at;
EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_TRUE(ty->Is<Alias>());
EXPECT_FALSE(ty->Is<Array>());
EXPECT_FALSE(ty->Is<Bool>());
EXPECT_FALSE(ty->Is<F32>());
EXPECT_FALSE(ty->Is<I32>());
EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<Struct>());
EXPECT_FALSE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>());
}
// Check for linear-time evaluation of Alias::type_name().
// If type_name() is non-linear, this test should noticeably stall.
// See: crbug.com/1200936
TEST_F(AliasTest, TypeName_LinearTime) {
Type* type = ty.i32();
for (int i = 0; i < 1024; i++) {
type = create<Alias>(Symbols().New(), type);
}
for (int i = 0; i < 16384; i++) {
type->type_name();
}
}
TEST_F(AliasTest, TypeName) {
auto* at = create<Alias>(Sym("Particle"), ty.i32());
EXPECT_EQ(at->type_name(), "__alias_$1__i32");
}
TEST_F(AliasTest, FriendlyName) {
auto* at = create<Alias>(Sym("Particle"), ty.i32());
EXPECT_EQ(at->FriendlyName(Symbols()), "Particle");
}
TEST_F(AliasTest, UnwrapIfNeeded_Alias) {
auto* a = create<Alias>(Sym("a_type"), ty.u32());
EXPECT_EQ(a->symbol(), Symbol(1, ID()));
EXPECT_EQ(a->type(), ty.u32());
EXPECT_EQ(a->UnwrapIfNeeded(), ty.u32());
EXPECT_EQ(ty.u32()->UnwrapIfNeeded(), ty.u32());
}
TEST_F(AliasTest, UnwrapIfNeeded_AccessControl) {
auto* a = create<AccessControl>(ast::AccessControl::kReadOnly, ty.u32());
EXPECT_EQ(a->type(), ty.u32());
EXPECT_EQ(a->UnwrapIfNeeded(), ty.u32());
}
TEST_F(AliasTest, UnwrapIfNeeded_MultiLevel) {
auto* a = create<Alias>(Sym("a_type"), ty.u32());
auto* aa = create<Alias>(Sym("aa_type"), a);
EXPECT_EQ(aa->symbol(), Symbol(2, ID()));
EXPECT_EQ(aa->type(), a);
EXPECT_EQ(aa->UnwrapIfNeeded(), ty.u32());
}
TEST_F(AliasTest, UnwrapIfNeeded_MultiLevel_AliasAccessControl) {
auto* a = create<Alias>(Sym("a_type"), ty.u32());
auto* aa = create<AccessControl>(ast::AccessControl::kReadWrite, a);
EXPECT_EQ(aa->type(), a);
EXPECT_EQ(aa->UnwrapIfNeeded(), ty.u32());
}
TEST_F(AliasTest, UnwrapAll_TwiceAliasPointerTwiceAlias) {
auto* u32 = create<U32>();
auto* a = create<Alias>(Sym(Sym("a_type")), u32);
auto* aa = create<Alias>(Sym("aa_type"), a);
auto* paa = create<Pointer>(aa, ast::StorageClass::kUniform);
auto* apaa = create<Alias>(Sym("paa_type"), paa);
auto* aapaa = create<Alias>(Sym("aapaa_type"), apaa);
EXPECT_EQ(aapaa->symbol(), Symbol(4, ID()));
EXPECT_EQ(aapaa->type(), apaa);
EXPECT_EQ(aapaa->UnwrapAll(), ty.u32());
}
TEST_F(AliasTest, UnwrapAll_SecondConsecutivePointerBlocksUnrapping) {
auto* a = create<Alias>(Sym("a_type"), ty.u32());
auto* aa = create<Alias>(Sym("aa_type"), a);
auto* paa = create<Pointer>(aa, ast::StorageClass::kUniform);
auto* ppaa = create<Pointer>(paa, ast::StorageClass::kUniform);
auto* appaa = create<Alias>(Sym("appaa_type"), ppaa);
EXPECT_EQ(appaa->UnwrapAll(), paa);
}
TEST_F(AliasTest, UnwrapAll_SecondNonConsecutivePointerBlocksUnrapping) {
auto* a = create<Alias>(Sym("a_type"), ty.u32());
auto* aa = create<Alias>(Sym("aa_type"), a);
auto* paa = create<Pointer>(aa, ast::StorageClass::kUniform);
auto* apaa = create<Alias>(Sym("apaa_type"), paa);
auto* aapaa = create<Alias>(Sym("aapaa_type"), apaa);
auto* paapaa = create<Pointer>(aapaa, ast::StorageClass::kUniform);
auto* apaapaa = create<Alias>(Sym("apaapaa_type"), paapaa);
EXPECT_EQ(apaapaa->UnwrapAll(), paa);
}
TEST_F(AliasTest, UnwrapAll_AccessControlPointer) {
auto* a = create<AccessControl>(ast::AccessControl::kReadOnly, ty.u32());
auto* pa = create<Pointer>(a, ast::StorageClass::kUniform);
EXPECT_EQ(pa->type(), a);
EXPECT_EQ(pa->UnwrapAll(), ty.u32());
}
TEST_F(AliasTest, UnwrapAll_PointerAccessControl) {
auto* p = create<Pointer>(ty.u32(), ast::StorageClass::kUniform);
auto* a = create<AccessControl>(ast::AccessControl::kReadOnly, p);
EXPECT_EQ(a->type(), p);
EXPECT_EQ(a->UnwrapAll(), ty.u32());
}
TEST_F(AliasTest, UnwrapAliasIfNeeded) {
auto* alias1 = create<Alias>(Sym("alias1"), ty.f32());
auto* alias2 = create<Alias>(Sym("alias2"), alias1);
auto* alias3 = create<Alias>(Sym("alias3"), alias2);
EXPECT_EQ(alias3->UnwrapAliasIfNeeded(), ty.f32());
}
} // namespace
} // namespace sem
} // namespace tint

View File

@ -26,7 +26,6 @@ TEST_F(BoolTest, Is) {
Bool b;
Type* ty = &b;
EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>());
EXPECT_FALSE(ty->Is<Array>());
EXPECT_TRUE(ty->Is<Bool>());
EXPECT_FALSE(ty->Is<F32>());

View File

@ -31,7 +31,6 @@ TEST_F(DepthTextureTest, Is) {
DepthTexture d(ast::TextureDimension::kCube);
Type* ty = &d;
EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>());
EXPECT_FALSE(ty->Is<Array>());
EXPECT_FALSE(ty->Is<Bool>());
EXPECT_FALSE(ty->Is<F32>());

View File

@ -32,7 +32,6 @@ TEST_F(ExternalTextureTest, Is) {
ExternalTexture s;
Type* ty = &s;
EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>());
EXPECT_FALSE(ty->Is<Array>());
EXPECT_FALSE(ty->Is<Bool>());
EXPECT_FALSE(ty->Is<F32>());

View File

@ -26,7 +26,6 @@ TEST_F(F32Test, Is) {
F32 f;
Type* ty = &f;
EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>());
EXPECT_FALSE(ty->Is<Array>());
EXPECT_FALSE(ty->Is<Bool>());
EXPECT_TRUE(ty->Is<F32>());

View File

@ -26,7 +26,6 @@ TEST_F(I32Test, Is) {
I32 i;
Type* ty = &i;
EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>());
EXPECT_FALSE(ty->Is<Array>());
EXPECT_FALSE(ty->Is<Bool>());
EXPECT_FALSE(ty->Is<F32>());

View File

@ -37,7 +37,6 @@ TEST_F(MatrixTest, Is) {
Matrix m{&c, 4};
Type* ty = &m;
EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>());
EXPECT_FALSE(ty->Is<Array>());
EXPECT_FALSE(ty->Is<Bool>());
EXPECT_FALSE(ty->Is<F32>());

View File

@ -32,7 +32,6 @@ TEST_F(MultisampledTextureTest, Is) {
MultisampledTexture s(ast::TextureDimension::kCube, &f32);
Type* ty = &s;
EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>());
EXPECT_FALSE(ty->Is<Array>());
EXPECT_FALSE(ty->Is<Bool>());
EXPECT_FALSE(ty->Is<F32>());

View File

@ -34,7 +34,6 @@ TEST_F(PointerTest, Is) {
Pointer p{&i32, ast::StorageClass::kFunction};
Type* ty = &p;
EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>());
EXPECT_FALSE(ty->Is<Array>());
EXPECT_FALSE(ty->Is<Bool>());
EXPECT_FALSE(ty->Is<F32>());

View File

@ -31,7 +31,6 @@ TEST_F(SampledTextureTest, Is) {
SampledTexture s(ast::TextureDimension::kCube, &f32);
Type* ty = &s;
EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>());
EXPECT_FALSE(ty->Is<Array>());
EXPECT_FALSE(ty->Is<Bool>());
EXPECT_FALSE(ty->Is<F32>());

View File

@ -37,7 +37,6 @@ TEST_F(SamplerTest, Is) {
Sampler s{ast::SamplerKind::kSampler};
Type* ty = &s;
EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>());
EXPECT_FALSE(ty->Is<Array>());
EXPECT_FALSE(ty->Is<Bool>());
EXPECT_FALSE(ty->Is<F32>());

View File

@ -51,7 +51,6 @@ TEST_F(ArrayTest, Is) {
Type* ty = create<Array>(&i32, 2, 4, 8, 4, true);
EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>());
EXPECT_TRUE(ty->Is<Array>());
EXPECT_FALSE(ty->Is<Bool>());
EXPECT_FALSE(ty->Is<F32>());

View File

@ -44,7 +44,6 @@ TEST_F(StructTest, Is) {
4 /* size */, 4 /* size_no_padding */);
sem::Type* ty = s;
EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>());
EXPECT_FALSE(ty->Is<Array>());
EXPECT_FALSE(ty->Is<Bool>());
EXPECT_FALSE(ty->Is<F32>());

View File

@ -33,7 +33,6 @@ TEST_F(StorageTextureTest, Is) {
ast::ImageFormat::kRgba32Float, subtype);
Type* ty = s;
EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>());
EXPECT_FALSE(ty->Is<Array>());
EXPECT_FALSE(ty->Is<Bool>());
EXPECT_FALSE(ty->Is<F32>());

View File

@ -15,7 +15,6 @@
#include "src/sem/type.h"
#include "src/sem/access_control_type.h"
#include "src/sem/alias_type.h"
#include "src/sem/bool_type.h"
#include "src/sem/f32_type.h"
#include "src/sem/i32_type.h"
@ -38,36 +37,34 @@ Type::Type(Type&&) = default;
Type::~Type() = default;
const Type* Type::UnwrapPtrIfNeeded() const {
if (auto* ptr = As<sem::Pointer>()) {
return ptr->type();
auto* type = this;
while (auto* ptr = type->As<sem::Pointer>()) {
type = ptr->type();
}
return this;
}
const Type* Type::UnwrapAliasIfNeeded() const {
const Type* unwrapped = this;
while (auto* ptr = unwrapped->As<sem::Alias>()) {
unwrapped = ptr->type();
}
return unwrapped;
return type;
}
const Type* Type::UnwrapIfNeeded() const {
auto* where = this;
while (true) {
if (auto* alias = where->As<sem::Alias>()) {
where = alias->type();
} else if (auto* access = where->As<sem::AccessControl>()) {
where = access->type();
} else {
break;
}
auto* type = this;
while (auto* access = type->As<sem::AccessControl>()) {
type = access->type();
}
return where;
return type;
}
const Type* Type::UnwrapAll() const {
return UnwrapIfNeeded()->UnwrapPtrIfNeeded()->UnwrapIfNeeded();
auto* type = this;
while (true) {
if (auto* ptr = type->As<sem::Pointer>()) {
type = ptr->type();
continue;
}
if (auto* access = type->As<sem::AccessControl>()) {
type = access->type();
continue;
}
return type;
}
}
bool Type::is_scalar() const {

View File

@ -48,11 +48,7 @@ class Type : public Castable<Type, Node> {
/// @returns the pointee type if this is a pointer, `this` otherwise
const Type* UnwrapPtrIfNeeded() const;
/// @returns the most deeply nested aliased type if this is an alias, `this`
/// otherwise
const Type* UnwrapAliasIfNeeded() const;
/// Removes all levels of aliasing and access control.
/// Removes all levels of access control.
/// 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,
@ -60,10 +56,8 @@ class Type : public Castable<Type, Node> {
/// @returns the completely unaliased type.
const Type* UnwrapIfNeeded() const;
/// Returns the type found after:
/// - removing all layers of aliasing and access control if they exist, then
/// - removing the pointer, if it exists, then
/// - removing all further layers of aliasing or access control, if they exist
/// Returns the type found after removing all layers of access control and
/// pointer.
/// @returns the unwrapped type
const Type* UnwrapAll() const;

View File

@ -26,7 +26,6 @@ TEST_F(U32Test, Is) {
U32 u;
Type* ty = &u;
EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>());
EXPECT_FALSE(ty->Is<Array>());
EXPECT_FALSE(ty->Is<Bool>());
EXPECT_FALSE(ty->Is<F32>());

View File

@ -34,7 +34,6 @@ TEST_F(VectorTest, Is) {
Vector v{&i32, 4};
Type* ty = &v;
EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>());
EXPECT_FALSE(ty->Is<Array>());
EXPECT_FALSE(ty->Is<Bool>());
EXPECT_FALSE(ty->Is<F32>());

View File

@ -194,7 +194,7 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
}
// Handle return type.
auto* ret_type = func->ReturnType()->UnwrapAliasIfNeeded();
auto* ret_type = func->ReturnType();
std::function<ast::Type*()> new_ret_type;
if (ret_type->Is<sem::Void>()) {
new_ret_type = [&ctx] { return ctx.dst->ty.void_(); };

View File

@ -349,11 +349,6 @@ const ast::NamedType* ConstructedTypeOf(const sem::Type* ty) {
}
}
/// @returns the given type with all pointers and aliases removed.
const sem::Type* UnwrapPtrAndAlias(const sem::Type* ty) {
return ty->UnwrapPtrIfNeeded()->UnwrapAliasIfNeeded()->UnwrapPtrIfNeeded();
}
/// StorageBufferAccess describes a single storage buffer access
struct StorageBufferAccess {
sem::Expression const* var = nullptr; // Storage buffer variable
@ -751,7 +746,7 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
auto* buf = access.var->Declaration();
auto* offset = access.offset->Build(ctx);
auto* buf_ty = UnwrapPtrAndAlias(access.var->Type());
auto* buf_ty = access.var->Type()->UnwrapPtrIfNeeded();
auto* el_ty = access.type->UnwrapAll();
auto* insert_after = ConstructedTypeOf(access.var->Type());
Symbol func = state.LoadFunc(ctx, insert_after, buf_ty, el_ty);
@ -765,7 +760,7 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
for (auto& store : state.stores) {
auto* buf = store.target.var->Declaration();
auto* offset = store.target.offset->Build(ctx);
auto* buf_ty = UnwrapPtrAndAlias(store.target.var->Type());
auto* buf_ty = store.target.var->Type()->UnwrapPtrIfNeeded();
auto* el_ty = store.target.type->UnwrapAll();
auto* value = store.assignment->rhs();
auto* insert_after = ConstructedTypeOf(store.target.var->Type());

View File

@ -107,9 +107,6 @@ ast::Type* Transform::CreateASTTypeFor(CloneContext* ctx, const sem::Type* ty) {
auto* el = CreateASTTypeFor(ctx, ac->type());
return ctx->dst->create<ast::AccessControl>(ac->access_control(), el);
}
if (auto* a = ty->As<sem::Alias>()) {
return ctx->dst->create<ast::TypeName>(ctx->Clone(a->symbol()));
}
if (auto* s = ty->As<sem::Struct>()) {
return ctx->dst->create<ast::TypeName>(
ctx->Clone(s->Declaration()->name()));

View File

@ -33,7 +33,6 @@ namespace tint {
namespace ast {
class AccessControl;
class Alias;
class Array;
class Bool;
class DepthTexture;
@ -56,7 +55,6 @@ class Void;
namespace sem {
class AccessControl;
class Alias;
class Array;
class Bool;
class DepthTexture;
@ -240,7 +238,6 @@ bool operator!=(std::nullptr_t, const TypePair<AST, SEM>& rhs) {
using Type = TypePair<ast::Type, sem::Type>;
using AccessControl = TypePair<ast::AccessControl, sem::AccessControl>;
using Alias = TypePair<ast::Alias, sem::Alias>;
using Array = TypePair<ast::Array, sem::Array>;
using Bool = TypePair<ast::Bool, sem::Bool>;
using DepthTexture = TypePair<ast::DepthTexture, sem::DepthTexture>;

View File

@ -207,23 +207,7 @@ bool GeneratorImpl::EmitConstructedType(std::ostream& out,
const sem::Type* ty) {
make_indent(out);
if (auto* alias = ty->As<sem::Alias>()) {
// HLSL typedef is for intrinsic types only. For an alias'd struct,
// generate a secondary struct with the new name.
if (auto* str = alias->type()->As<sem::Struct>()) {
if (!EmitStructType(out, str,
builder_.Symbols().NameFor(alias->symbol()))) {
return false;
}
return true;
}
out << "typedef ";
if (!EmitType(out, alias->type(), ast::StorageClass::kNone, "")) {
return false;
}
out << " " << builder_.Symbols().NameFor(alias->symbol()) << ";"
<< std::endl;
} else if (auto* str = ty->As<sem::Struct>()) {
if (auto* str = ty->As<sem::Struct>()) {
if (!EmitStructType(
out, str, builder_.Symbols().NameFor(str->Declaration()->name()))) {
return false;
@ -1324,8 +1308,7 @@ bool GeneratorImpl::EmitTypeConstructor(std::ostream& pre,
return EmitZeroValue(out, type);
}
bool brackets =
type->UnwrapAliasIfNeeded()->IsAnyOf<sem::Array, sem::Struct>();
bool brackets = type->IsAnyOf<sem::Array, sem::Struct>();
if (brackets) {
out << "{";
@ -1918,7 +1901,7 @@ bool GeneratorImpl::EmitEntryPointData(
if (!EmitType(out, var->Type(), var->StorageClass(), name)) {
return false;
}
if (!var->Type()->UnwrapAliasIfNeeded()->Is<sem::Array>()) {
if (!var->Type()->Is<sem::Array>()) {
out << " " << name;
}
@ -2404,9 +2387,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
return true;
}
if (auto* alias = type->As<sem::Alias>()) {
out << builder_.Symbols().NameFor(alias->symbol());
} else if (auto* ary = type->As<sem::Array>()) {
if (auto* ary = type->As<sem::Array>()) {
const sem::Type* base_type = ary;
std::vector<uint32_t> sizes;
while (auto* arr = base_type->As<sem::Array>()) {

View File

@ -32,16 +32,6 @@ using ::testing::HasSubstr;
using HlslGeneratorImplTest_Type = TestHelper;
TEST_F(HlslGeneratorImplTest_Type, EmitType_Alias) {
auto alias = ty.alias("alias", ty.f32());
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitType(out, alias, ast::StorageClass::kNone, ""))
<< gen.error();
EXPECT_EQ(result(), "alias");
}
TEST_F(HlslGeneratorImplTest_Type, EmitType_Array) {
auto* arr = ty.array<bool, 4>();
Global("G", arr, ast::StorageClass::kPrivate);

View File

@ -39,7 +39,7 @@ TEST_F(HlslGeneratorImplTest_WorkgroupVar, Basic) {
}
TEST_F(HlslGeneratorImplTest_WorkgroupVar, Aliased) {
auto alias = ty.alias("F32", ty.f32());
auto* alias = ty.alias("F32", ty.f32());
AST().AddConstructedType(alias);
Global("wg", alias, ast::StorageClass::kWorkgroup);

View File

@ -31,7 +31,6 @@
#include "src/ast/variable_decl_statement.h"
#include "src/ast/void.h"
#include "src/sem/access_control_type.h"
#include "src/sem/alias_type.h"
#include "src/sem/array.h"
#include "src/sem/bool_type.h"
#include "src/sem/call.h"
@ -151,14 +150,7 @@ bool GeneratorImpl::Generate() {
bool GeneratorImpl::EmitConstructedType(const sem::Type* ty) {
make_indent();
if (auto* alias = ty->As<sem::Alias>()) {
out_ << "typedef ";
if (!EmitType(alias->type(), "")) {
return false;
}
out_ << " " << program_->Symbols().NameFor(alias->symbol()) << ";"
<< std::endl;
} else if (auto* str = ty->As<sem::Struct>()) {
if (auto* str = ty->As<sem::Struct>()) {
if (!EmitStructType(str)) {
return false;
}
@ -186,7 +178,7 @@ bool GeneratorImpl::EmitArrayAccessor(ast::ArrayAccessorExpression* expr) {
bool GeneratorImpl::EmitBitcast(ast::BitcastExpression* expr) {
out_ << "as_type<";
if (!EmitType(expr->type(), "")) {
if (!EmitType(TypeOf(expr), "")) {
return false;
}
@ -1224,7 +1216,7 @@ bool GeneratorImpl::EmitFunctionInternal(ast::Function* func,
auto* func_sem = program_->Sem().Get(func);
auto name = func->symbol().to_str();
if (!EmitType(func->return_type(), "")) {
if (!EmitType(func_sem->ReturnType(), "")) {
return false;
}
@ -1899,11 +1891,7 @@ bool GeneratorImpl::EmitSwitch(ast::SwitchStatement* stmt) {
return true;
}
bool GeneratorImpl::EmitType(typ::Type type, const std::string& name) {
if (!type.sem) {
type.sem = program_->Sem().Get(type.ast);
}
bool GeneratorImpl::EmitType(const sem::Type* type, const std::string& name) {
std::string access_str = "";
if (auto* ac = type->As<sem::AccessControl>()) {
if (ac->access_control() == ast::AccessControl::kReadOnly) {
@ -1918,9 +1906,7 @@ bool GeneratorImpl::EmitType(typ::Type type, const std::string& name) {
type = ac->type();
}
if (auto* alias = type->As<sem::Alias>()) {
out_ << program_->Symbols().NameFor(alias->symbol());
} else if (auto* ary = type->As<sem::Array>()) {
if (auto* ary = type->As<sem::Array>()) {
const sem::Type* base_type = ary;
std::vector<uint32_t> sizes;
while (auto* arr = base_type->As<sem::Array>()) {
@ -2037,15 +2023,8 @@ bool GeneratorImpl::EmitType(typ::Type type, const std::string& name) {
return true;
}
bool GeneratorImpl::EmitPackedType(typ::Type type, const std::string& name) {
if (!type.sem) {
type.sem = program_->Sem().Get(type.ast);
}
if (auto* alias = type->As<sem::Alias>()) {
return EmitPackedType(alias->type(), name);
}
bool GeneratorImpl::EmitPackedType(const sem::Type* type,
const std::string& name) {
if (auto* vec = type->As<sem::Vector>()) {
out_ << "packed_";
if (!EmitType(vec->type(), "")) {
@ -2121,7 +2100,7 @@ bool GeneratorImpl::EmitStructType(const sem::Struct* str) {
}
}
auto* ty = mem->Type()->UnwrapAliasIfNeeded();
auto* ty = mem->Type();
// Array member name will be output with the type
if (!ty->Is<sem::Array>()) {
@ -2287,8 +2266,6 @@ bool GeneratorImpl::EmitProgramConstVariable(const ast::Variable* var) {
GeneratorImpl::SizeAndAlign GeneratorImpl::MslPackedTypeSizeAndAlign(
const sem::Type* ty) {
ty = ty->UnwrapAliasIfNeeded();
if (ty->IsAnyOf<sem::U32, sem::I32, sem::F32>()) {
// https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
// 2.1 Scalar Data Types

View File

@ -195,14 +195,14 @@ class GeneratorImpl : public TextGenerator {
/// @param type the type to generate
/// @param name the name of the variable, only used for array emission
/// @returns true if the type is emitted
bool EmitType(typ::Type type, const std::string& name);
bool EmitType(const sem::Type* type, const std::string& name);
/// Handles generating an MSL-packed storage type.
/// If the type does not have a packed form, the standard non-packed form is
/// emitted.
/// @param type the type to generate
/// @param name the name of the variable, only used for array emission
/// @returns true if the type is emitted
bool EmitPackedType(typ::Type type, const std::string& name);
bool EmitPackedType(const sem::Type* type, const std::string& name);
/// Handles generating a struct declaration
/// @param str the struct to generate
/// @returns true if the struct is emitted

View File

@ -57,15 +57,6 @@ using uint = unsigned int;
using MslGeneratorImplTest = TestHelper;
TEST_F(MslGeneratorImplTest, EmitType_Alias) {
auto alias = ty.alias("alias", ty.f32());
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitType(alias, "")) << gen.error();
EXPECT_EQ(gen.result(), "alias");
}
TEST_F(MslGeneratorImplTest, EmitType_Array) {
auto* arr = ty.array<bool, 4>();
Global("G", arr, ast::StorageClass::kPrivate);
@ -186,7 +177,7 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct) {
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitType(s, "")) << gen.error();
ASSERT_TRUE(gen.EmitType(program->TypeOf(s), "")) << gen.error();
EXPECT_EQ(gen.result(), "S");
}
@ -607,7 +598,7 @@ TEST_F(MslGeneratorImplTest, DISABLED_EmitType_Struct_WithDecoration) {
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitType(s, "")) << gen.error();
ASSERT_TRUE(gen.EmitType(program->TypeOf(s), "")) << gen.error();
EXPECT_EQ(gen.result(), R"(struct {
/* 0x0000 */ int a;
/* 0x0004 */ float b;

View File

@ -2930,10 +2930,6 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
return 0;
}
// The alias is a wrapper around the subtype, so emit the subtype
if (auto* alias = type->As<sem::Alias>()) {
return GenerateTypeIfNeeded(alias->type());
}
if (auto* ac = type->As<sem::AccessControl>()) {
if (!ac->type()->UnwrapIfNeeded()->Is<sem::Struct>()) {
return GenerateTypeIfNeeded(ac->type());

View File

@ -393,7 +393,7 @@ TEST_F(BuilderTest, MemberAccessor_Nested_WithAlias) {
Member("b", ty.f32()),
});
auto alias = ty.alias("Inner", inner_struct);
auto* alias = ty.alias("Inner", inner_struct);
auto* s_type = Structure("Outer", {Member("inner", alias)});
auto* var = Global("ident", s_type, ast::StorageClass::kFunction);

View File

@ -93,7 +93,7 @@ TEST_F(SpvBuilderConstructorTest, Type_WithAlias) {
// type Int = i32
// cast<Int>(2.3f)
auto alias = ty.alias("Int", ty.i32());
auto* alias = ty.alias("Int", ty.i32());
AST().AddConstructedType(alias);
auto* cast = Construct(alias, 2.3f);
WrapInFunction(cast);

View File

@ -417,7 +417,7 @@ TEST_F(BuilderTest, GlobalVar_TypeAliasDeclReadOnly) {
auto* A = Structure("A", {Member("a", ty.i32())},
{create<ast::StructBlockDecoration>()});
auto B = ty.alias("B", A);
auto* B = ty.alias("B", A);
AST().AddConstructedType(B);
auto ac = ty.access(ast::AccessControl::kReadOnly, B);
auto* var = Global("b", ac, ast::StorageClass::kStorage);
@ -451,7 +451,7 @@ TEST_F(BuilderTest, GlobalVar_TypeAliasAssignReadOnly) {
auto* A = Structure("A", {Member("a", ty.i32())},
{create<ast::StructBlockDecoration>()});
auto ac = ty.access(ast::AccessControl::kReadOnly, A);
auto B = ty.alias("B", ac);
auto* B = ty.alias("B", ac);
AST().AddConstructedType(B);
auto* var = Global("b", B, ast::StorageClass::kStorage);

View File

@ -26,37 +26,6 @@ namespace {
using BuilderTest_Type = TestHelper;
TEST_F(BuilderTest_Type, GenerateAlias) {
auto alias_type = ty.alias("my_type", ty.f32());
spirv::Builder& b = Build();
auto id = b.GenerateTypeIfNeeded(alias_type);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(id, 1u);
EXPECT_EQ(b.types().size(), 1u);
EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
)");
}
TEST_F(BuilderTest_Type, ReturnsGeneratedAlias) {
auto i32 = ty.i32();
auto f32 = ty.f32();
auto alias_type = ty.alias("my_type", f32);
spirv::Builder& b = Build();
EXPECT_EQ(b.GenerateTypeIfNeeded(alias_type), 1u);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 2u);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(b.GenerateTypeIfNeeded(alias_type), 1u);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(b.GenerateTypeIfNeeded(f32), 1u);
ASSERT_FALSE(b.has_error()) << b.error();
}
TEST_F(BuilderTest_Type, GenerateRuntimeArray) {
auto* ary = ty.array(ty.i32(), 0);
auto* str = Structure("S", {Member("x", ary)},

View File

@ -48,7 +48,6 @@
#include "src/ast/void.h"
#include "src/ast/workgroup_decoration.h"
#include "src/sem/access_control_type.h"
#include "src/sem/alias_type.h"
#include "src/sem/array.h"
#include "src/sem/bool_type.h"
#include "src/sem/depth_texture_type.h"

View File

@ -22,7 +22,7 @@ namespace {
using WgslGeneratorImplTest = TestHelper;
TEST_F(WgslGeneratorImplTest, EmitAlias_F32) {
auto alias = ty.alias("a", ty.f32());
auto* alias = ty.alias("a", ty.f32());
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitConstructedType(alias)) << gen.error();
@ -36,7 +36,7 @@ TEST_F(WgslGeneratorImplTest, EmitConstructedType_Struct) {
Member("b", ty.i32()),
});
auto alias = ty.alias("B", s);
auto* alias = ty.alias("B", s);
GeneratorImpl& gen = Build();
@ -56,7 +56,7 @@ TEST_F(WgslGeneratorImplTest, EmitAlias_ToStruct) {
Member("b", ty.i32()),
});
auto alias = ty.alias("B", s);
auto* alias = ty.alias("B", s);
GeneratorImpl& gen = Build();

View File

@ -27,7 +27,7 @@ namespace {
using WgslGeneratorImplTest = TestHelper;
TEST_F(WgslGeneratorImplTest, EmitType_Alias) {
auto alias = ty.alias("alias", ty.f32());
auto* alias = ty.alias("alias", ty.f32());
AST().AddConstructedType(alias);
GeneratorImpl& gen = Build();

View File

@ -269,7 +269,6 @@ tint_unittests_source_set("tint_unittests_core_src") {
"../src/resolver/validation_test.cc",
"../src/scope_stack_test.cc",
"../src/sem/access_control_type_test.cc",
"../src/sem/alias_type_test.cc",
"../src/sem/bool_type_test.cc",
"../src/sem/depth_texture_type_test.cc",
"../src/sem/external_texture_type_test.cc",