Add semantic::Variable::Type() and use it instead of ast::Variable::type()
In anticipation of adding support for type inference, no longer use ast::Variable::type() everywhere, as it will eventually return nullptr for type-inferred variables. Instead, the Resolver now stores the final resolved type into the semantic::Variable, and nearly all code now makes use of that. ast::Variable::type() has been renamed to ast::Variable::declared_type() to help make its usage clear, and to distinguish it from semantic::Variable::Type(). Fixed tests that failed after this change because variables were missing VariableDeclStatements, so there was no path to the variables during resolving, and thus no semantic info generated for them. Bug: tint:672 Change-Id: I0125e2f555839a4892248dc6739a72e9c7f51b1e Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/46100 Reviewed-by: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
parent
d7f23f5c75
commit
9ef17472e8
|
@ -125,7 +125,9 @@ std::string Function::type_name() const {
|
||||||
|
|
||||||
out << "__func" + return_type_->type_name();
|
out << "__func" + return_type_->type_name();
|
||||||
for (auto* param : params_) {
|
for (auto* param : params_) {
|
||||||
out << param->type()->type_name();
|
// No need for the semantic::Variable here, functions params must have a
|
||||||
|
// type
|
||||||
|
out << param->declared_type()->type_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
return out.str();
|
return out.str();
|
||||||
|
|
|
@ -25,20 +25,20 @@ namespace ast {
|
||||||
|
|
||||||
Variable::Variable(const Source& source,
|
Variable::Variable(const Source& source,
|
||||||
const Symbol& sym,
|
const Symbol& sym,
|
||||||
StorageClass sc,
|
StorageClass declared_storage_class,
|
||||||
type::Type* type,
|
type::Type* declared_type,
|
||||||
bool is_const,
|
bool is_const,
|
||||||
Expression* constructor,
|
Expression* constructor,
|
||||||
DecorationList decorations)
|
DecorationList decorations)
|
||||||
: Base(source),
|
: Base(source),
|
||||||
symbol_(sym),
|
symbol_(sym),
|
||||||
type_(type),
|
declared_type_(declared_type),
|
||||||
is_const_(is_const),
|
is_const_(is_const),
|
||||||
constructor_(constructor),
|
constructor_(constructor),
|
||||||
decorations_(std::move(decorations)),
|
decorations_(std::move(decorations)),
|
||||||
declared_storage_class_(sc) {
|
declared_storage_class_(declared_storage_class) {
|
||||||
TINT_ASSERT(symbol_.IsValid());
|
TINT_ASSERT(symbol_.IsValid());
|
||||||
TINT_ASSERT(type_);
|
TINT_ASSERT(declared_type_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Variable::Variable(Variable&&) = default;
|
Variable::Variable(Variable&&) = default;
|
||||||
|
@ -94,7 +94,7 @@ uint32_t Variable::constant_id() const {
|
||||||
Variable* Variable::Clone(CloneContext* ctx) const {
|
Variable* Variable::Clone(CloneContext* ctx) const {
|
||||||
auto src = ctx->Clone(source());
|
auto src = ctx->Clone(source());
|
||||||
auto sym = ctx->Clone(symbol());
|
auto sym = ctx->Clone(symbol());
|
||||||
auto* ty = ctx->Clone(type());
|
auto* ty = ctx->Clone(declared_type());
|
||||||
auto* ctor = ctx->Clone(constructor());
|
auto* ctor = ctx->Clone(constructor());
|
||||||
auto decos = ctx->Clone(decorations());
|
auto decos = ctx->Clone(decorations());
|
||||||
return ctx->dst->create<Variable>(src, sym, declared_storage_class(), ty,
|
return ctx->dst->create<Variable>(src, sym, declared_storage_class(), ty,
|
||||||
|
@ -111,7 +111,7 @@ void Variable::info_to_str(const semantic::Info& sem,
|
||||||
out << (var_sem ? var_sem->StorageClass() : declared_storage_class())
|
out << (var_sem ? var_sem->StorageClass() : declared_storage_class())
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
make_indent(out, indent);
|
make_indent(out, indent);
|
||||||
out << type_->type_name() << std::endl;
|
out << declared_type_->type_name() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Variable::constructor_to_str(const semantic::Info& sem,
|
void Variable::constructor_to_str(const semantic::Info& sem,
|
||||||
|
|
|
@ -79,15 +79,15 @@ class Variable : public Castable<Variable, Node> {
|
||||||
/// Create a variable
|
/// Create a variable
|
||||||
/// @param source the variable source
|
/// @param source the variable source
|
||||||
/// @param sym the variable symbol
|
/// @param sym the variable symbol
|
||||||
/// @param sc the declared storage class
|
/// @param declared_storage_class the declared storage class
|
||||||
/// @param type the value type
|
/// @param declared_type the declared variable type
|
||||||
/// @param is_const true if the variable is const
|
/// @param is_const true if the variable is const
|
||||||
/// @param constructor the constructor expression
|
/// @param constructor the constructor expression
|
||||||
/// @param decorations the variable decorations
|
/// @param decorations the variable decorations
|
||||||
Variable(const Source& source,
|
Variable(const Source& source,
|
||||||
const Symbol& sym,
|
const Symbol& sym,
|
||||||
StorageClass sc,
|
StorageClass declared_storage_class,
|
||||||
type::Type* type,
|
type::Type* declared_type,
|
||||||
bool is_const,
|
bool is_const,
|
||||||
Expression* constructor,
|
Expression* constructor,
|
||||||
DecorationList decorations);
|
DecorationList decorations);
|
||||||
|
@ -99,8 +99,8 @@ class Variable : public Castable<Variable, Node> {
|
||||||
/// @returns the variable symbol
|
/// @returns the variable symbol
|
||||||
const Symbol& symbol() const { return symbol_; }
|
const Symbol& symbol() const { return symbol_; }
|
||||||
|
|
||||||
/// @returns the variable's type.
|
/// @returns the declared type
|
||||||
type::Type* type() const { return type_; }
|
type::Type* declared_type() const { return declared_type_; }
|
||||||
|
|
||||||
/// @returns the declared storage class
|
/// @returns the declared storage class
|
||||||
StorageClass declared_storage_class() const {
|
StorageClass declared_storage_class() const {
|
||||||
|
@ -166,7 +166,7 @@ class Variable : public Castable<Variable, Node> {
|
||||||
|
|
||||||
Symbol const symbol_;
|
Symbol const symbol_;
|
||||||
// The value type if a const or formal paramter, and the store type if a var
|
// The value type if a const or formal paramter, and the store type if a var
|
||||||
type::Type* const type_;
|
type::Type* const declared_type_;
|
||||||
bool const is_const_;
|
bool const is_const_;
|
||||||
Expression* const constructor_;
|
Expression* const constructor_;
|
||||||
DecorationList const decorations_;
|
DecorationList const decorations_;
|
||||||
|
|
|
@ -27,7 +27,7 @@ TEST_F(VariableTest, Creation) {
|
||||||
|
|
||||||
EXPECT_EQ(v->symbol(), Symbol(1));
|
EXPECT_EQ(v->symbol(), Symbol(1));
|
||||||
EXPECT_EQ(v->declared_storage_class(), StorageClass::kFunction);
|
EXPECT_EQ(v->declared_storage_class(), StorageClass::kFunction);
|
||||||
EXPECT_EQ(v->type(), ty.i32());
|
EXPECT_EQ(v->declared_type(), ty.i32());
|
||||||
EXPECT_EQ(v->source().range.begin.line, 0u);
|
EXPECT_EQ(v->source().range.begin.line, 0u);
|
||||||
EXPECT_EQ(v->source().range.begin.column, 0u);
|
EXPECT_EQ(v->source().range.begin.column, 0u);
|
||||||
EXPECT_EQ(v->source().range.end.line, 0u);
|
EXPECT_EQ(v->source().range.end.line, 0u);
|
||||||
|
@ -41,7 +41,7 @@ TEST_F(VariableTest, CreationWithSource) {
|
||||||
|
|
||||||
EXPECT_EQ(v->symbol(), Symbol(1));
|
EXPECT_EQ(v->symbol(), Symbol(1));
|
||||||
EXPECT_EQ(v->declared_storage_class(), StorageClass::kPrivate);
|
EXPECT_EQ(v->declared_storage_class(), StorageClass::kPrivate);
|
||||||
EXPECT_EQ(v->type(), ty.f32());
|
EXPECT_EQ(v->declared_type(), ty.f32());
|
||||||
EXPECT_EQ(v->source().range.begin.line, 27u);
|
EXPECT_EQ(v->source().range.begin.line, 27u);
|
||||||
EXPECT_EQ(v->source().range.begin.column, 4u);
|
EXPECT_EQ(v->source().range.begin.column, 4u);
|
||||||
EXPECT_EQ(v->source().range.end.line, 27u);
|
EXPECT_EQ(v->source().range.end.line, 27u);
|
||||||
|
@ -55,7 +55,7 @@ TEST_F(VariableTest, CreationEmpty) {
|
||||||
|
|
||||||
EXPECT_EQ(v->symbol(), Symbol(1));
|
EXPECT_EQ(v->symbol(), Symbol(1));
|
||||||
EXPECT_EQ(v->declared_storage_class(), StorageClass::kWorkgroup);
|
EXPECT_EQ(v->declared_storage_class(), StorageClass::kWorkgroup);
|
||||||
EXPECT_EQ(v->type(), ty.i32());
|
EXPECT_EQ(v->declared_type(), ty.i32());
|
||||||
EXPECT_EQ(v->source().range.begin.line, 27u);
|
EXPECT_EQ(v->source().range.begin.line, 27u);
|
||||||
EXPECT_EQ(v->source().range.begin.column, 4u);
|
EXPECT_EQ(v->source().range.begin.column, 4u);
|
||||||
EXPECT_EQ(v->source().range.end.line, 27u);
|
EXPECT_EQ(v->source().range.end.line, 27u);
|
||||||
|
|
|
@ -211,7 +211,7 @@ std::vector<EntryPoint> Inspector::GetEntryPoints() {
|
||||||
stage_variable.name = name;
|
stage_variable.name = name;
|
||||||
|
|
||||||
stage_variable.component_type = ComponentType::kUnknown;
|
stage_variable.component_type = ComponentType::kUnknown;
|
||||||
auto* type = var->Declaration()->type()->UnwrapAll();
|
auto* type = var->Type()->UnwrapAll();
|
||||||
if (type->is_float_scalar_or_vector() || type->is_float_matrix()) {
|
if (type->is_float_scalar_or_vector() || type->is_float_matrix()) {
|
||||||
stage_variable.component_type = ComponentType::kFloat;
|
stage_variable.component_type = ComponentType::kFloat;
|
||||||
} else if (type->is_unsigned_scalar_or_vector()) {
|
} else if (type->is_unsigned_scalar_or_vector()) {
|
||||||
|
@ -367,10 +367,9 @@ std::vector<ResourceBinding> Inspector::GetUniformBufferResourceBindings(
|
||||||
auto* func_sem = program_->Sem().Get(func);
|
auto* func_sem = program_->Sem().Get(func);
|
||||||
for (auto& ruv : func_sem->ReferencedUniformVariables()) {
|
for (auto& ruv : func_sem->ReferencedUniformVariables()) {
|
||||||
auto* var = ruv.first;
|
auto* var = ruv.first;
|
||||||
auto* decl = var->Declaration();
|
|
||||||
auto binding_info = ruv.second;
|
auto binding_info = ruv.second;
|
||||||
|
|
||||||
auto* unwrapped_type = decl->type()->UnwrapIfNeeded();
|
auto* unwrapped_type = var->Type()->UnwrapIfNeeded();
|
||||||
auto* str = unwrapped_type->As<type::Struct>();
|
auto* str = unwrapped_type->As<type::Struct>();
|
||||||
if (str == nullptr) {
|
if (str == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -492,7 +491,6 @@ std::vector<ResourceBinding> Inspector::GetDepthTextureResourceBindings(
|
||||||
auto* func_sem = program_->Sem().Get(func);
|
auto* func_sem = program_->Sem().Get(func);
|
||||||
for (auto& ref : func_sem->ReferencedDepthTextureVariables()) {
|
for (auto& ref : func_sem->ReferencedDepthTextureVariables()) {
|
||||||
auto* var = ref.first;
|
auto* var = ref.first;
|
||||||
auto* decl = var->Declaration();
|
|
||||||
auto binding_info = ref.second;
|
auto binding_info = ref.second;
|
||||||
|
|
||||||
ResourceBinding entry;
|
ResourceBinding entry;
|
||||||
|
@ -500,7 +498,7 @@ std::vector<ResourceBinding> Inspector::GetDepthTextureResourceBindings(
|
||||||
entry.bind_group = binding_info.group->value();
|
entry.bind_group = binding_info.group->value();
|
||||||
entry.binding = binding_info.binding->value();
|
entry.binding = binding_info.binding->value();
|
||||||
|
|
||||||
auto* texture_type = decl->type()->UnwrapIfNeeded()->As<type::Texture>();
|
auto* texture_type = var->Type()->UnwrapIfNeeded()->As<type::Texture>();
|
||||||
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
|
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
|
||||||
texture_type->dim());
|
texture_type->dim());
|
||||||
|
|
||||||
|
@ -537,10 +535,9 @@ std::vector<ResourceBinding> Inspector::GetStorageBufferResourceBindingsImpl(
|
||||||
std::vector<ResourceBinding> result;
|
std::vector<ResourceBinding> result;
|
||||||
for (auto& rsv : func_sem->ReferencedStorageBufferVariables()) {
|
for (auto& rsv : func_sem->ReferencedStorageBufferVariables()) {
|
||||||
auto* var = rsv.first;
|
auto* var = rsv.first;
|
||||||
auto* decl = var->Declaration();
|
|
||||||
auto binding_info = rsv.second;
|
auto binding_info = rsv.second;
|
||||||
|
|
||||||
auto* ac_type = decl->type()->As<type::AccessControl>();
|
auto* ac_type = var->Type()->As<type::AccessControl>();
|
||||||
if (ac_type == nullptr) {
|
if (ac_type == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -549,7 +546,7 @@ std::vector<ResourceBinding> Inspector::GetStorageBufferResourceBindingsImpl(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* str = decl->type()->UnwrapIfNeeded()->As<type::Struct>();
|
auto* str = var->Type()->UnwrapIfNeeded()->As<type::Struct>();
|
||||||
if (!str) {
|
if (!str) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -591,7 +588,6 @@ std::vector<ResourceBinding> Inspector::GetSampledTextureResourceBindingsImpl(
|
||||||
: func_sem->ReferencedSampledTextureVariables();
|
: func_sem->ReferencedSampledTextureVariables();
|
||||||
for (auto& ref : referenced_variables) {
|
for (auto& ref : referenced_variables) {
|
||||||
auto* var = ref.first;
|
auto* var = ref.first;
|
||||||
auto* decl = var->Declaration();
|
|
||||||
auto binding_info = ref.second;
|
auto binding_info = ref.second;
|
||||||
|
|
||||||
ResourceBinding entry;
|
ResourceBinding entry;
|
||||||
|
@ -601,7 +597,7 @@ std::vector<ResourceBinding> Inspector::GetSampledTextureResourceBindingsImpl(
|
||||||
entry.bind_group = binding_info.group->value();
|
entry.bind_group = binding_info.group->value();
|
||||||
entry.binding = binding_info.binding->value();
|
entry.binding = binding_info.binding->value();
|
||||||
|
|
||||||
auto* texture_type = decl->type()->UnwrapIfNeeded()->As<type::Texture>();
|
auto* texture_type = var->Type()->UnwrapIfNeeded()->As<type::Texture>();
|
||||||
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
|
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
|
||||||
texture_type->dim());
|
texture_type->dim());
|
||||||
|
|
||||||
|
@ -634,10 +630,9 @@ std::vector<ResourceBinding> Inspector::GetStorageTextureResourceBindingsImpl(
|
||||||
std::vector<ResourceBinding> result;
|
std::vector<ResourceBinding> result;
|
||||||
for (auto& ref : func_sem->ReferencedStorageTextureVariables()) {
|
for (auto& ref : func_sem->ReferencedStorageTextureVariables()) {
|
||||||
auto* var = ref.first;
|
auto* var = ref.first;
|
||||||
auto* decl = var->Declaration();
|
|
||||||
auto binding_info = ref.second;
|
auto binding_info = ref.second;
|
||||||
|
|
||||||
auto* ac_type = decl->type()->As<type::AccessControl>();
|
auto* ac_type = var->Type()->As<type::AccessControl>();
|
||||||
if (ac_type == nullptr) {
|
if (ac_type == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -654,7 +649,7 @@ std::vector<ResourceBinding> Inspector::GetStorageTextureResourceBindingsImpl(
|
||||||
entry.binding = binding_info.binding->value();
|
entry.binding = binding_info.binding->value();
|
||||||
|
|
||||||
auto* texture_type =
|
auto* texture_type =
|
||||||
decl->type()->UnwrapIfNeeded()->As<type::StorageTexture>();
|
var->Type()->UnwrapIfNeeded()->As<type::StorageTexture>();
|
||||||
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
|
entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
|
||||||
texture_type->dim());
|
texture_type->dim());
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,8 @@ TEST_F(ParserImplTest, GlobalConstantDecl) {
|
||||||
|
|
||||||
EXPECT_TRUE(e->is_const());
|
EXPECT_TRUE(e->is_const());
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
||||||
ASSERT_NE(e->type(), nullptr);
|
ASSERT_NE(e->declared_type(), nullptr);
|
||||||
EXPECT_TRUE(e->type()->Is<type::F32>());
|
EXPECT_TRUE(e->declared_type()->Is<type::F32>());
|
||||||
|
|
||||||
EXPECT_EQ(e->source().range.begin.line, 1u);
|
EXPECT_EQ(e->source().range.begin.line, 1u);
|
||||||
EXPECT_EQ(e->source().range.begin.column, 7u);
|
EXPECT_EQ(e->source().range.begin.column, 7u);
|
||||||
|
@ -112,8 +112,8 @@ TEST_F(ParserImplTest, GlobalConstantDec_ConstantId) {
|
||||||
|
|
||||||
EXPECT_TRUE(e->is_const());
|
EXPECT_TRUE(e->is_const());
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
||||||
ASSERT_NE(e->type(), nullptr);
|
ASSERT_NE(e->declared_type(), nullptr);
|
||||||
EXPECT_TRUE(e->type()->Is<type::F32>());
|
EXPECT_TRUE(e->declared_type()->Is<type::F32>());
|
||||||
|
|
||||||
EXPECT_EQ(e->source().range.begin.line, 1u);
|
EXPECT_EQ(e->source().range.begin.line, 1u);
|
||||||
EXPECT_EQ(e->source().range.begin.column, 26u);
|
EXPECT_EQ(e->source().range.begin.column, 26u);
|
||||||
|
|
|
@ -31,7 +31,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithoutConstructor) {
|
||||||
ASSERT_NE(e.value, nullptr);
|
ASSERT_NE(e.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
||||||
EXPECT_TRUE(e->type()->Is<type::F32>());
|
EXPECT_TRUE(e->declared_type()->Is<type::F32>());
|
||||||
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kOutput);
|
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kOutput);
|
||||||
|
|
||||||
EXPECT_EQ(e->source().range.begin.line, 1u);
|
EXPECT_EQ(e->source().range.begin.line, 1u);
|
||||||
|
@ -54,7 +54,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithConstructor) {
|
||||||
ASSERT_NE(e.value, nullptr);
|
ASSERT_NE(e.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
||||||
EXPECT_TRUE(e->type()->Is<type::F32>());
|
EXPECT_TRUE(e->declared_type()->Is<type::F32>());
|
||||||
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kOutput);
|
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kOutput);
|
||||||
|
|
||||||
EXPECT_EQ(e->source().range.begin.line, 1u);
|
EXPECT_EQ(e->source().range.begin.line, 1u);
|
||||||
|
@ -79,8 +79,8 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) {
|
||||||
ASSERT_NE(e.value, nullptr);
|
ASSERT_NE(e.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
||||||
ASSERT_NE(e->type(), nullptr);
|
ASSERT_NE(e->declared_type(), nullptr);
|
||||||
EXPECT_TRUE(e->type()->Is<type::F32>());
|
EXPECT_TRUE(e->declared_type()->Is<type::F32>());
|
||||||
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kOutput);
|
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kOutput);
|
||||||
|
|
||||||
EXPECT_EQ(e->source().range.begin.line, 1u);
|
EXPECT_EQ(e->source().range.begin.line, 1u);
|
||||||
|
@ -109,8 +109,8 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration_MulitpleGroups) {
|
||||||
ASSERT_NE(e.value, nullptr);
|
ASSERT_NE(e.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
||||||
ASSERT_NE(e->type(), nullptr);
|
ASSERT_NE(e->declared_type(), nullptr);
|
||||||
EXPECT_TRUE(e->type()->Is<type::F32>());
|
EXPECT_TRUE(e->declared_type()->Is<type::F32>());
|
||||||
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kOutput);
|
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kOutput);
|
||||||
|
|
||||||
EXPECT_EQ(e->source().range.begin.line, 1u);
|
EXPECT_EQ(e->source().range.begin.line, 1u);
|
||||||
|
@ -180,7 +180,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_SamplerImplicitStorageClass) {
|
||||||
ASSERT_NE(e.value, nullptr);
|
ASSERT_NE(e.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("s"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("s"));
|
||||||
EXPECT_TRUE(e->type()->Is<type::Sampler>());
|
EXPECT_TRUE(e->declared_type()->Is<type::Sampler>());
|
||||||
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kUniformConstant);
|
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kUniformConstant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_TextureImplicitStorageClass) {
|
||||||
ASSERT_NE(e.value, nullptr);
|
ASSERT_NE(e.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("s"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("s"));
|
||||||
EXPECT_TRUE(e->type()->UnwrapAll()->Is<type::Texture>());
|
EXPECT_TRUE(e->declared_type()->UnwrapAll()->Is<type::Texture>());
|
||||||
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kUniformConstant);
|
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kUniformConstant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ TEST_F(ParserImplTest, ParamList_Single) {
|
||||||
EXPECT_EQ(e.value.size(), 1u);
|
EXPECT_EQ(e.value.size(), 1u);
|
||||||
|
|
||||||
EXPECT_EQ(e.value[0]->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e.value[0]->symbol(), p->builder().Symbols().Get("a"));
|
||||||
EXPECT_EQ(e.value[0]->type(), i32);
|
EXPECT_EQ(e.value[0]->declared_type(), i32);
|
||||||
EXPECT_TRUE(e.value[0]->is_const());
|
EXPECT_TRUE(e.value[0]->is_const());
|
||||||
|
|
||||||
ASSERT_EQ(e.value[0]->source().range.begin.line, 1u);
|
ASSERT_EQ(e.value[0]->source().range.begin.line, 1u);
|
||||||
|
@ -52,7 +52,7 @@ TEST_F(ParserImplTest, ParamList_Multiple) {
|
||||||
EXPECT_EQ(e.value.size(), 3u);
|
EXPECT_EQ(e.value.size(), 3u);
|
||||||
|
|
||||||
EXPECT_EQ(e.value[0]->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e.value[0]->symbol(), p->builder().Symbols().Get("a"));
|
||||||
EXPECT_EQ(e.value[0]->type(), i32);
|
EXPECT_EQ(e.value[0]->declared_type(), i32);
|
||||||
EXPECT_TRUE(e.value[0]->is_const());
|
EXPECT_TRUE(e.value[0]->is_const());
|
||||||
|
|
||||||
ASSERT_EQ(e.value[0]->source().range.begin.line, 1u);
|
ASSERT_EQ(e.value[0]->source().range.begin.line, 1u);
|
||||||
|
@ -61,7 +61,7 @@ TEST_F(ParserImplTest, ParamList_Multiple) {
|
||||||
ASSERT_EQ(e.value[0]->source().range.end.column, 2u);
|
ASSERT_EQ(e.value[0]->source().range.end.column, 2u);
|
||||||
|
|
||||||
EXPECT_EQ(e.value[1]->symbol(), p->builder().Symbols().Get("b"));
|
EXPECT_EQ(e.value[1]->symbol(), p->builder().Symbols().Get("b"));
|
||||||
EXPECT_EQ(e.value[1]->type(), f32);
|
EXPECT_EQ(e.value[1]->declared_type(), f32);
|
||||||
EXPECT_TRUE(e.value[1]->is_const());
|
EXPECT_TRUE(e.value[1]->is_const());
|
||||||
|
|
||||||
ASSERT_EQ(e.value[1]->source().range.begin.line, 1u);
|
ASSERT_EQ(e.value[1]->source().range.begin.line, 1u);
|
||||||
|
@ -70,7 +70,7 @@ TEST_F(ParserImplTest, ParamList_Multiple) {
|
||||||
ASSERT_EQ(e.value[1]->source().range.end.column, 11u);
|
ASSERT_EQ(e.value[1]->source().range.end.column, 11u);
|
||||||
|
|
||||||
EXPECT_EQ(e.value[2]->symbol(), p->builder().Symbols().Get("c"));
|
EXPECT_EQ(e.value[2]->symbol(), p->builder().Symbols().Get("c"));
|
||||||
EXPECT_EQ(e.value[2]->type(), vec2);
|
EXPECT_EQ(e.value[2]->declared_type(), vec2);
|
||||||
EXPECT_TRUE(e.value[2]->is_const());
|
EXPECT_TRUE(e.value[2]->is_const());
|
||||||
|
|
||||||
ASSERT_EQ(e.value[2]->source().range.begin.line, 1u);
|
ASSERT_EQ(e.value[2]->source().range.begin.line, 1u);
|
||||||
|
@ -109,7 +109,7 @@ TEST_F(ParserImplTest, ParamList_Decorations) {
|
||||||
ASSERT_EQ(e.value.size(), 2u);
|
ASSERT_EQ(e.value.size(), 2u);
|
||||||
|
|
||||||
EXPECT_EQ(e.value[0]->symbol(), p->builder().Symbols().Get("coord"));
|
EXPECT_EQ(e.value[0]->symbol(), p->builder().Symbols().Get("coord"));
|
||||||
EXPECT_EQ(e.value[0]->type(), vec4);
|
EXPECT_EQ(e.value[0]->declared_type(), vec4);
|
||||||
EXPECT_TRUE(e.value[0]->is_const());
|
EXPECT_TRUE(e.value[0]->is_const());
|
||||||
auto decos0 = e.value[0]->decorations();
|
auto decos0 = e.value[0]->decorations();
|
||||||
ASSERT_EQ(decos0.size(), 1u);
|
ASSERT_EQ(decos0.size(), 1u);
|
||||||
|
@ -123,7 +123,7 @@ TEST_F(ParserImplTest, ParamList_Decorations) {
|
||||||
ASSERT_EQ(e.value[0]->source().range.end.column, 30u);
|
ASSERT_EQ(e.value[0]->source().range.end.column, 30u);
|
||||||
|
|
||||||
EXPECT_EQ(e.value[1]->symbol(), p->builder().Symbols().Get("loc1"));
|
EXPECT_EQ(e.value[1]->symbol(), p->builder().Symbols().Get("loc1"));
|
||||||
EXPECT_EQ(e.value[1]->type(), f32);
|
EXPECT_EQ(e.value[1]->declared_type(), f32);
|
||||||
EXPECT_TRUE(e.value[1]->is_const());
|
EXPECT_TRUE(e.value[1]->is_const());
|
||||||
auto decos1 = e.value[1]->decorations();
|
auto decos1 = e.value[1]->decorations();
|
||||||
ASSERT_EQ(decos1.size(), 1u);
|
ASSERT_EQ(decos1.size(), 1u);
|
||||||
|
|
|
@ -201,7 +201,8 @@ bool Resolver::ResolveInternal() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (auto* var = decl->As<ast::Variable>()) {
|
} else if (auto* var = decl->As<ast::Variable>()) {
|
||||||
variable_stack_.set_global(var->symbol(), CreateVariableInfo(var));
|
auto* info = CreateVariableInfo(var);
|
||||||
|
variable_stack_.set_global(var->symbol(), info);
|
||||||
|
|
||||||
if (var->has_constructor()) {
|
if (var->has_constructor()) {
|
||||||
if (!Expression(var->constructor())) {
|
if (!Expression(var->constructor())) {
|
||||||
|
@ -210,7 +211,7 @@ bool Resolver::ResolveInternal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ApplyStorageClassUsageToType(var->declared_storage_class(),
|
if (!ApplyStorageClassUsageToType(var->declared_storage_class(),
|
||||||
var->type(), var->source())) {
|
info->type, var->source())) {
|
||||||
diagnostics_.add_note("while instantiating variable " +
|
diagnostics_.add_note("while instantiating variable " +
|
||||||
builder_->Symbols().NameFor(var->symbol()),
|
builder_->Symbols().NameFor(var->symbol()),
|
||||||
var->source());
|
var->source());
|
||||||
|
@ -223,7 +224,8 @@ bool Resolver::ResolveInternal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resolver::ValidateParameter(const ast::Variable* param) {
|
bool Resolver::ValidateParameter(const ast::Variable* param) {
|
||||||
if (auto* r = param->type()->UnwrapAll()->As<type::Array>()) {
|
auto* type = variable_to_info_[param]->type;
|
||||||
|
if (auto* r = type->UnwrapAll()->As<type::Array>()) {
|
||||||
if (r->IsRuntimeArray()) {
|
if (r->IsRuntimeArray()) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"v-0015",
|
"v-0015",
|
||||||
|
@ -277,10 +279,6 @@ bool Resolver::ValidateFunction(const ast::Function* func) {
|
||||||
bool Resolver::Function(ast::Function* func) {
|
bool Resolver::Function(ast::Function* func) {
|
||||||
auto* func_info = function_infos_.Create<FunctionInfo>(func);
|
auto* func_info = function_infos_.Create<FunctionInfo>(func);
|
||||||
|
|
||||||
if (!ValidateFunction(func)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScopedAssignment<FunctionInfo*> sa(current_function_, func_info);
|
ScopedAssignment<FunctionInfo*> sa(current_function_, func_info);
|
||||||
|
|
||||||
variable_stack_.push_scope();
|
variable_stack_.push_scope();
|
||||||
|
@ -293,6 +291,10 @@ bool Resolver::Function(ast::Function* func) {
|
||||||
}
|
}
|
||||||
variable_stack_.pop_scope();
|
variable_stack_.pop_scope();
|
||||||
|
|
||||||
|
if (!ValidateFunction(func)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Register the function information _after_ processing the statements. This
|
// Register the function information _after_ processing the statements. This
|
||||||
// allows us to catch a function calling itself when determining the call
|
// allows us to catch a function calling itself when determining the call
|
||||||
// information as this function doesn't exist until it's finished.
|
// information as this function doesn't exist until it's finished.
|
||||||
|
@ -780,12 +782,12 @@ bool Resolver::Identifier(ast::IdentifierExpression* expr) {
|
||||||
// A constant is the type, but a variable is always a pointer so synthesize
|
// A constant is the type, but a variable is always a pointer so synthesize
|
||||||
// the pointer around the variable type.
|
// the pointer around the variable type.
|
||||||
if (var->declaration->is_const()) {
|
if (var->declaration->is_const()) {
|
||||||
SetType(expr, var->declaration->type());
|
SetType(expr, var->type);
|
||||||
} else if (var->declaration->type()->Is<type::Pointer>()) {
|
} else if (var->type->Is<type::Pointer>()) {
|
||||||
SetType(expr, var->declaration->type());
|
SetType(expr, var->type);
|
||||||
} else {
|
} else {
|
||||||
SetType(expr, builder_->create<type::Pointer>(var->declaration->type(),
|
SetType(expr,
|
||||||
var->storage_class));
|
builder_->create<type::Pointer>(var->type, var->storage_class));
|
||||||
}
|
}
|
||||||
|
|
||||||
var->users.push_back(expr);
|
var->users.push_back(expr);
|
||||||
|
@ -1200,15 +1202,18 @@ bool Resolver::UnaryOp(ast::UnaryOpExpression* expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
|
bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
|
||||||
|
ast::Variable* var = stmt->variable();
|
||||||
|
type::Type* type = var->declared_type();
|
||||||
|
|
||||||
if (auto* ctor = stmt->variable()->constructor()) {
|
if (auto* ctor = stmt->variable()->constructor()) {
|
||||||
if (!Expression(ctor)) {
|
if (!Expression(ctor)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto* lhs_type = stmt->variable()->type();
|
|
||||||
auto* rhs_type = TypeOf(ctor);
|
auto* rhs_type = TypeOf(ctor);
|
||||||
if (!IsValidAssignment(lhs_type, rhs_type)) {
|
|
||||||
|
if (!IsValidAssignment(type, rhs_type)) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"variable of type '" + lhs_type->FriendlyName(builder_->Symbols()) +
|
"variable of type '" + type->FriendlyName(builder_->Symbols()) +
|
||||||
"' cannot be initialized with a value of type '" +
|
"' cannot be initialized with a value of type '" +
|
||||||
rhs_type->FriendlyName(builder_->Symbols()) + "'",
|
rhs_type->FriendlyName(builder_->Symbols()) + "'",
|
||||||
stmt->source());
|
stmt->source());
|
||||||
|
@ -1216,10 +1221,8 @@ bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* var = stmt->variable();
|
|
||||||
|
|
||||||
auto* info = CreateVariableInfo(var);
|
auto* info = CreateVariableInfo(var);
|
||||||
variable_to_info_.emplace(var, info);
|
info->type = type;
|
||||||
variable_stack_.set(var->symbol(), info);
|
variable_stack_.set(var->symbol(), info);
|
||||||
current_block_->decls.push_back(var);
|
current_block_->decls.push_back(var);
|
||||||
|
|
||||||
|
@ -1235,7 +1238,7 @@ bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ApplyStorageClassUsageToType(info->storage_class, var->type(),
|
if (!ApplyStorageClassUsageToType(info->storage_class, info->type,
|
||||||
var->source())) {
|
var->source())) {
|
||||||
diagnostics_.add_note("while instantiating variable " +
|
diagnostics_.add_note("while instantiating variable " +
|
||||||
builder_->Symbols().NameFor(var->symbol()),
|
builder_->Symbols().NameFor(var->symbol()),
|
||||||
|
@ -1303,8 +1306,8 @@ void Resolver::CreateSemanticNodes() const {
|
||||||
}
|
}
|
||||||
users.push_back(sem_expr);
|
users.push_back(sem_expr);
|
||||||
}
|
}
|
||||||
sem.Add(var, builder_->create<semantic::Variable>(var, info->storage_class,
|
sem.Add(var, builder_->create<semantic::Variable>(
|
||||||
std::move(users)));
|
var, info->type, info->storage_class, std::move(users)));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remap_vars = [&sem](const std::vector<VariableInfo*>& in) {
|
auto remap_vars = [&sem](const std::vector<VariableInfo*>& in) {
|
||||||
|
@ -1812,7 +1815,9 @@ std::string Resolver::VectorPretty(uint32_t size, type::Type* element_type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Resolver::VariableInfo::VariableInfo(ast::Variable* decl)
|
Resolver::VariableInfo::VariableInfo(ast::Variable* decl)
|
||||||
: declaration(decl), storage_class(decl->declared_storage_class()) {}
|
: declaration(decl),
|
||||||
|
type(decl->declared_type()),
|
||||||
|
storage_class(decl->declared_storage_class()) {}
|
||||||
|
|
||||||
Resolver::VariableInfo::~VariableInfo() = default;
|
Resolver::VariableInfo::~VariableInfo() = default;
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,7 @@ class Resolver {
|
||||||
~VariableInfo();
|
~VariableInfo();
|
||||||
|
|
||||||
ast::Variable* const declaration;
|
ast::Variable* const declaration;
|
||||||
|
type::Type* type;
|
||||||
ast::StorageClass storage_class;
|
ast::StorageClass storage_class;
|
||||||
std::vector<ast::IdentifierExpression*> users;
|
std::vector<ast::IdentifierExpression*> users;
|
||||||
};
|
};
|
||||||
|
@ -290,7 +291,7 @@ class Resolver {
|
||||||
ScopeStack<VariableInfo*> variable_stack_;
|
ScopeStack<VariableInfo*> variable_stack_;
|
||||||
std::unordered_map<Symbol, FunctionInfo*> symbol_to_function_;
|
std::unordered_map<Symbol, FunctionInfo*> symbol_to_function_;
|
||||||
std::unordered_map<const ast::Function*, FunctionInfo*> function_to_info_;
|
std::unordered_map<const ast::Function*, FunctionInfo*> function_to_info_;
|
||||||
std::unordered_map<ast::Variable*, VariableInfo*> variable_to_info_;
|
std::unordered_map<const ast::Variable*, VariableInfo*> variable_to_info_;
|
||||||
std::unordered_map<ast::CallExpression*, FunctionCallInfo> function_calls_;
|
std::unordered_map<ast::CallExpression*, FunctionCallInfo> function_calls_;
|
||||||
std::unordered_map<ast::Expression*, ExpressionInfo> expr_info_;
|
std::unordered_map<ast::Expression*, ExpressionInfo> expr_info_;
|
||||||
std::unordered_map<type::Struct*, StructInfo*> struct_info_;
|
std::unordered_map<type::Struct*, StructInfo*> struct_info_;
|
||||||
|
|
|
@ -32,7 +32,8 @@ ParameterList GetParameters(ast::Function* ast) {
|
||||||
ParameterList parameters;
|
ParameterList parameters;
|
||||||
parameters.reserve(ast->params().size());
|
parameters.reserve(ast->params().size());
|
||||||
for (auto* param : ast->params()) {
|
for (auto* param : ast->params()) {
|
||||||
parameters.emplace_back(Parameter{param->type(), Parameter::Usage::kNone});
|
parameters.emplace_back(
|
||||||
|
Parameter{param->declared_type(), Parameter::Usage::kNone});
|
||||||
}
|
}
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
@ -160,7 +161,8 @@ Function::VariableBindings Function::ReferencedStorageTextureVariables() const {
|
||||||
VariableBindings ret;
|
VariableBindings ret;
|
||||||
|
|
||||||
for (auto* var : ReferencedModuleVariables()) {
|
for (auto* var : ReferencedModuleVariables()) {
|
||||||
auto* unwrapped_type = var->Declaration()->type()->UnwrapIfNeeded();
|
auto* unwrapped_type =
|
||||||
|
var->Declaration()->declared_type()->UnwrapIfNeeded();
|
||||||
auto* storage_texture = unwrapped_type->As<type::StorageTexture>();
|
auto* storage_texture = unwrapped_type->As<type::StorageTexture>();
|
||||||
if (storage_texture == nullptr) {
|
if (storage_texture == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -182,7 +184,8 @@ Function::VariableBindings Function::ReferencedDepthTextureVariables() const {
|
||||||
VariableBindings ret;
|
VariableBindings ret;
|
||||||
|
|
||||||
for (auto* var : ReferencedModuleVariables()) {
|
for (auto* var : ReferencedModuleVariables()) {
|
||||||
auto* unwrapped_type = var->Declaration()->type()->UnwrapIfNeeded();
|
auto* unwrapped_type =
|
||||||
|
var->Declaration()->declared_type()->UnwrapIfNeeded();
|
||||||
auto* storage_texture = unwrapped_type->As<type::DepthTexture>();
|
auto* storage_texture = unwrapped_type->As<type::DepthTexture>();
|
||||||
if (storage_texture == nullptr) {
|
if (storage_texture == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -229,7 +232,8 @@ Function::VariableBindings Function::ReferencedSamplerVariablesImpl(
|
||||||
VariableBindings ret;
|
VariableBindings ret;
|
||||||
|
|
||||||
for (auto* var : ReferencedModuleVariables()) {
|
for (auto* var : ReferencedModuleVariables()) {
|
||||||
auto* unwrapped_type = var->Declaration()->type()->UnwrapIfNeeded();
|
auto* unwrapped_type =
|
||||||
|
var->Declaration()->declared_type()->UnwrapIfNeeded();
|
||||||
auto* sampler = unwrapped_type->As<type::Sampler>();
|
auto* sampler = unwrapped_type->As<type::Sampler>();
|
||||||
if (sampler == nullptr || sampler->kind() != kind) {
|
if (sampler == nullptr || sampler->kind() != kind) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -252,7 +256,8 @@ Function::VariableBindings Function::ReferencedSampledTextureVariablesImpl(
|
||||||
VariableBindings ret;
|
VariableBindings ret;
|
||||||
|
|
||||||
for (auto* var : ReferencedModuleVariables()) {
|
for (auto* var : ReferencedModuleVariables()) {
|
||||||
auto* unwrapped_type = var->Declaration()->type()->UnwrapIfNeeded();
|
auto* unwrapped_type =
|
||||||
|
var->Declaration()->declared_type()->UnwrapIfNeeded();
|
||||||
auto* texture = unwrapped_type->As<type::Texture>();
|
auto* texture = unwrapped_type->As<type::Texture>();
|
||||||
if (texture == nullptr) {
|
if (texture == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -19,10 +19,12 @@ TINT_INSTANTIATE_TYPEINFO(tint::semantic::Variable);
|
||||||
namespace tint {
|
namespace tint {
|
||||||
namespace semantic {
|
namespace semantic {
|
||||||
|
|
||||||
Variable::Variable(ast::Variable* declaration,
|
Variable::Variable(const ast::Variable* declaration,
|
||||||
|
type::Type* type,
|
||||||
ast::StorageClass storage_class,
|
ast::StorageClass storage_class,
|
||||||
std::vector<const Expression*> users)
|
std::vector<const Expression*> users)
|
||||||
: declaration_(declaration),
|
: declaration_(declaration),
|
||||||
|
type_(type),
|
||||||
storage_class_(storage_class),
|
storage_class_(storage_class),
|
||||||
users_(std::move(users)) {}
|
users_(std::move(users)) {}
|
||||||
|
|
||||||
|
|
|
@ -37,9 +37,11 @@ class Variable : public Castable<Variable, Node> {
|
||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param declaration the AST declaration node
|
/// @param declaration the AST declaration node
|
||||||
|
/// @param type the variable type
|
||||||
/// @param storage_class the variable storage class
|
/// @param storage_class the variable storage class
|
||||||
/// @param users the expressions that use the variable
|
/// @param users the expressions that use the variable
|
||||||
explicit Variable(ast::Variable* declaration,
|
explicit Variable(const ast::Variable* declaration,
|
||||||
|
type::Type* type,
|
||||||
ast::StorageClass storage_class,
|
ast::StorageClass storage_class,
|
||||||
std::vector<const Expression*> users);
|
std::vector<const Expression*> users);
|
||||||
|
|
||||||
|
@ -47,7 +49,10 @@ class Variable : public Castable<Variable, Node> {
|
||||||
~Variable() override;
|
~Variable() override;
|
||||||
|
|
||||||
/// @returns the AST declaration node
|
/// @returns the AST declaration node
|
||||||
ast::Variable* Declaration() const { return declaration_; }
|
const ast::Variable* Declaration() const { return declaration_; }
|
||||||
|
|
||||||
|
/// @returns the type for the variable
|
||||||
|
type::Type* Type() const { return type_; }
|
||||||
|
|
||||||
/// @returns the storage class for the variable
|
/// @returns the storage class for the variable
|
||||||
ast::StorageClass StorageClass() const { return storage_class_; }
|
ast::StorageClass StorageClass() const { return storage_class_; }
|
||||||
|
@ -56,7 +61,8 @@ class Variable : public Castable<Variable, Node> {
|
||||||
const std::vector<const Expression*>& Users() const { return users_; }
|
const std::vector<const Expression*>& Users() const { return users_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ast::Variable* const declaration_;
|
const ast::Variable* const declaration_;
|
||||||
|
type::Type* const type_;
|
||||||
ast::StorageClass const storage_class_;
|
ast::StorageClass const storage_class_;
|
||||||
std::vector<const Expression*> const users_;
|
std::vector<const Expression*> const users_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -39,7 +39,7 @@ ast::Variable* clone_variable_with_new_name(CloneContext* ctx,
|
||||||
// Clone arguments outside of create() call to have deterministic ordering
|
// Clone arguments outside of create() call to have deterministic ordering
|
||||||
auto source = ctx->Clone(in->source());
|
auto source = ctx->Clone(in->source());
|
||||||
auto symbol = ctx->dst->Symbols().Register(new_name);
|
auto symbol = ctx->dst->Symbols().Register(new_name);
|
||||||
auto* type = ctx->Clone(in->type());
|
auto* type = ctx->Clone(in->declared_type());
|
||||||
auto* constructor = ctx->Clone(in->constructor());
|
auto* constructor = ctx->Clone(in->constructor());
|
||||||
auto decorations = ctx->Clone(in->decorations());
|
auto decorations = ctx->Clone(in->decorations());
|
||||||
return ctx->dst->create<ast::Variable>(
|
return ctx->dst->create<ast::Variable>(
|
||||||
|
|
|
@ -145,7 +145,8 @@ void Hlsl::HandleEntryPointIOTypes(CloneContext& ctx) const {
|
||||||
// Build a new structure to hold the non-struct input parameters.
|
// Build a new structure to hold the non-struct input parameters.
|
||||||
ast::StructMemberList struct_members;
|
ast::StructMemberList struct_members;
|
||||||
for (auto* param : func->params()) {
|
for (auto* param : func->params()) {
|
||||||
if (param->type()->Is<type::Struct>()) {
|
auto* type = ctx.src->Sem().Get(param)->Type();
|
||||||
|
if (type->Is<type::Struct>()) {
|
||||||
// Already a struct, nothing to do.
|
// Already a struct, nothing to do.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -159,14 +160,12 @@ void Hlsl::HandleEntryPointIOTypes(CloneContext& ctx) const {
|
||||||
auto* deco = param->decorations()[0];
|
auto* deco = param->decorations()[0];
|
||||||
if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
|
if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
|
||||||
// Create a struct member with the builtin decoration.
|
// Create a struct member with the builtin decoration.
|
||||||
struct_members.push_back(
|
struct_members.push_back(ctx.dst->Member(
|
||||||
ctx.dst->Member(name, ctx.Clone(param->type()),
|
name, ctx.Clone(type), ast::DecorationList{ctx.Clone(builtin)}));
|
||||||
ast::DecorationList{ctx.Clone(builtin)}));
|
|
||||||
} else if (auto* loc = deco->As<ast::LocationDecoration>()) {
|
} else if (auto* loc = deco->As<ast::LocationDecoration>()) {
|
||||||
// Create a struct member with the location decoration.
|
// Create a struct member with the location decoration.
|
||||||
struct_members.push_back(
|
struct_members.push_back(ctx.dst->Member(
|
||||||
ctx.dst->Member(name, ctx.Clone(param->type()),
|
name, ctx.Clone(type), ast::DecorationList{ctx.Clone(loc)}));
|
||||||
ast::DecorationList{ctx.Clone(loc)}));
|
|
||||||
} else {
|
} else {
|
||||||
TINT_ICE(ctx.dst->Diagnostics())
|
TINT_ICE(ctx.dst->Diagnostics())
|
||||||
<< "Unsupported entry point parameter decoration";
|
<< "Unsupported entry point parameter decoration";
|
||||||
|
@ -195,7 +194,8 @@ void Hlsl::HandleEntryPointIOTypes(CloneContext& ctx) const {
|
||||||
|
|
||||||
// Replace the original parameters with function-scope constants.
|
// Replace the original parameters with function-scope constants.
|
||||||
for (auto* param : func->params()) {
|
for (auto* param : func->params()) {
|
||||||
if (param->type()->Is<type::Struct>()) {
|
auto* type = ctx.src->Sem().Get(param)->Type();
|
||||||
|
if (type->Is<type::Struct>()) {
|
||||||
// Keep struct parameters unchanged.
|
// Keep struct parameters unchanged.
|
||||||
new_parameters.push_back(ctx.Clone(param));
|
new_parameters.push_back(ctx.Clone(param));
|
||||||
continue;
|
continue;
|
||||||
|
@ -207,7 +207,7 @@ void Hlsl::HandleEntryPointIOTypes(CloneContext& ctx) const {
|
||||||
// Initialize it with the value extracted from the struct parameter.
|
// Initialize it with the value extracted from the struct parameter.
|
||||||
auto func_const_symbol = ctx.dst->Symbols().Register(name);
|
auto func_const_symbol = ctx.dst->Symbols().Register(name);
|
||||||
auto* func_const =
|
auto* func_const =
|
||||||
ctx.dst->Const(func_const_symbol, ctx.Clone(param->type()),
|
ctx.dst->Const(func_const_symbol, ctx.Clone(type),
|
||||||
ctx.dst->MemberAccessor(struct_param_symbol, name));
|
ctx.dst->MemberAccessor(struct_param_symbol, name));
|
||||||
|
|
||||||
new_body.push_back(ctx.dst->WrapInStatement(func_const));
|
new_body.push_back(ctx.dst->WrapInStatement(func_const));
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "src/transform/msl.h"
|
#include "src/transform/msl.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -326,9 +327,10 @@ void Msl::HandleEntryPointIOTypes(CloneContext& ctx) const {
|
||||||
continue;
|
continue;
|
||||||
} else if (auto* loc = deco->As<ast::LocationDecoration>()) {
|
} else if (auto* loc = deco->As<ast::LocationDecoration>()) {
|
||||||
// Create a struct member with the location decoration.
|
// Create a struct member with the location decoration.
|
||||||
struct_members.push_back(ctx.dst->Member(
|
std::string name = ctx.src->Symbols().NameFor(param->symbol());
|
||||||
ctx.src->Symbols().NameFor(param->symbol()),
|
auto* type = ctx.Clone(ctx.src->Sem().Get(param)->Type());
|
||||||
ctx.Clone(param->type()), ast::DecorationList{ctx.Clone(loc)}));
|
struct_members.push_back(
|
||||||
|
ctx.dst->Member(name, type, ast::DecorationList{ctx.Clone(loc)}));
|
||||||
} else {
|
} else {
|
||||||
TINT_ICE(ctx.dst->Diagnostics())
|
TINT_ICE(ctx.dst->Diagnostics())
|
||||||
<< "Unsupported entry point parameter decoration";
|
<< "Unsupported entry point parameter decoration";
|
||||||
|
@ -368,9 +370,9 @@ void Msl::HandleEntryPointIOTypes(CloneContext& ctx) const {
|
||||||
// Create a function-scope const to replace the parameter.
|
// Create a function-scope const to replace the parameter.
|
||||||
// Initialize it with the value extracted from the struct parameter.
|
// Initialize it with the value extracted from the struct parameter.
|
||||||
auto func_const_symbol = ctx.dst->Symbols().Register(name);
|
auto func_const_symbol = ctx.dst->Symbols().Register(name);
|
||||||
auto* func_const =
|
auto* type = ctx.Clone(ctx.src->Sem().Get(param)->Type());
|
||||||
ctx.dst->Const(func_const_symbol, ctx.Clone(param->type()),
|
auto* constructor = ctx.dst->MemberAccessor(struct_param_symbol, name);
|
||||||
ctx.dst->MemberAccessor(struct_param_symbol, name));
|
auto* func_const = ctx.dst->Const(func_const_symbol, type, constructor);
|
||||||
|
|
||||||
new_body.push_back(ctx.dst->WrapInStatement(func_const));
|
new_body.push_back(ctx.dst->WrapInStatement(func_const));
|
||||||
|
|
||||||
|
|
|
@ -137,8 +137,8 @@ void Spirv::HandleEntryPointIOTypes(CloneContext& ctx) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* param : func->params()) {
|
for (auto* param : func->params()) {
|
||||||
Symbol new_var =
|
Symbol new_var = HoistToInputVariables(
|
||||||
HoistToInputVariables(ctx, func, param->type(), param->decorations());
|
ctx, func, ctx.src->Sem().Get(param)->Type(), param->decorations());
|
||||||
|
|
||||||
// Replace all uses of the function parameter with the new variable.
|
// Replace all uses of the function parameter with the new variable.
|
||||||
for (auto* user : ctx.src->Sem().Get(param)->Users()) {
|
for (auto* user : ctx.src->Sem().Get(param)->Users()) {
|
||||||
|
|
|
@ -207,7 +207,7 @@ void VertexPulling::State::ConvertVertexInputVariablesToPrivate() {
|
||||||
Source{}, // source
|
Source{}, // source
|
||||||
ctx.dst->Symbols().Register(name), // symbol
|
ctx.dst->Symbols().Register(name), // symbol
|
||||||
ast::StorageClass::kPrivate, // storage_class
|
ast::StorageClass::kPrivate, // storage_class
|
||||||
ctx.Clone(v->type()), // type
|
ctx.Clone(v->declared_type()), // type
|
||||||
false, // is_const
|
false, // is_const
|
||||||
nullptr, // constructor
|
nullptr, // constructor
|
||||||
ast::DecorationList{}); // decorations
|
ast::DecorationList{}); // decorations
|
||||||
|
|
|
@ -219,7 +219,8 @@ bool ValidatorImpl::ValidateDeclStatement(
|
||||||
// storable.
|
// storable.
|
||||||
// - types match or the RHS can be dereferenced to equal the LHS type.
|
// - types match or the RHS can be dereferenced to equal the LHS type.
|
||||||
variable_stack_.set(symbol, decl->variable());
|
variable_stack_.set(symbol, decl->variable());
|
||||||
if (auto* arr = decl->variable()->type()->UnwrapAll()->As<type::Array>()) {
|
if (auto* arr =
|
||||||
|
decl->variable()->declared_type()->UnwrapAll()->As<type::Array>()) {
|
||||||
if (arr->IsRuntimeArray()) {
|
if (arr->IsRuntimeArray()) {
|
||||||
add_error(
|
add_error(
|
||||||
decl->source(), "v-0015",
|
decl->source(), "v-0015",
|
||||||
|
|
|
@ -1515,11 +1515,13 @@ bool GeneratorImpl::EmitFunctionInternal(std::ostream& out,
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
if (!EmitType(out, v->type(), builder_.Symbols().NameFor(v->symbol()))) {
|
auto* type = builder_.Sem().Get(v)->Type();
|
||||||
|
|
||||||
|
if (!EmitType(out, type, builder_.Symbols().NameFor(v->symbol()))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Array name is output as part of the type
|
// Array name is output as part of the type
|
||||||
if (!v->type()->Is<type::Array>()) {
|
if (!type->Is<type::Array>()) {
|
||||||
out << " " << builder_.Symbols().NameFor(v->symbol());
|
out << " " << builder_.Symbols().NameFor(v->symbol());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1541,8 +1543,8 @@ bool GeneratorImpl::EmitEntryPointData(
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
ast::Function* func,
|
ast::Function* func,
|
||||||
std::unordered_set<Symbol>& emitted_globals) {
|
std::unordered_set<Symbol>& emitted_globals) {
|
||||||
std::vector<std::pair<ast::Variable*, ast::Decoration*>> in_variables;
|
std::vector<std::pair<const ast::Variable*, ast::Decoration*>> in_variables;
|
||||||
std::vector<std::pair<ast::Variable*, ast::Decoration*>> outvariables;
|
std::vector<std::pair<const ast::Variable*, ast::Decoration*>> outvariables;
|
||||||
auto* func_sem = builder_.Sem().Get(func);
|
auto* func_sem = builder_.Sem().Get(func);
|
||||||
auto func_sym = func->symbol();
|
auto func_sym = func->symbol();
|
||||||
|
|
||||||
|
@ -1595,7 +1597,7 @@ bool GeneratorImpl::EmitEntryPointData(
|
||||||
}
|
}
|
||||||
// auto* set = data.second.set;
|
// auto* set = data.second.set;
|
||||||
|
|
||||||
auto* type = decl->type()->UnwrapIfNeeded();
|
auto* type = var->Type()->UnwrapIfNeeded();
|
||||||
if (auto* strct = type->As<type::Struct>()) {
|
if (auto* strct = type->As<type::Struct>()) {
|
||||||
out << "ConstantBuffer<" << builder_.Symbols().NameFor(strct->symbol())
|
out << "ConstantBuffer<" << builder_.Symbols().NameFor(strct->symbol())
|
||||||
<< "> " << builder_.Symbols().NameFor(decl->symbol())
|
<< "> " << builder_.Symbols().NameFor(decl->symbol())
|
||||||
|
@ -1638,7 +1640,7 @@ bool GeneratorImpl::EmitEntryPointData(
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* binding = data.second.binding;
|
auto* binding = data.second.binding;
|
||||||
auto* ac = decl->type()->As<type::AccessControl>();
|
auto* ac = var->Type()->As<type::AccessControl>();
|
||||||
if (ac == nullptr) {
|
if (ac == nullptr) {
|
||||||
diagnostics_.add_error("access control type required for storage buffer");
|
diagnostics_.add_error("access control type required for storage buffer");
|
||||||
return false;
|
return false;
|
||||||
|
@ -1672,10 +1674,10 @@ bool GeneratorImpl::EmitEntryPointData(
|
||||||
for (auto& data : in_variables) {
|
for (auto& data : in_variables) {
|
||||||
auto* var = data.first;
|
auto* var = data.first;
|
||||||
auto* deco = data.second;
|
auto* deco = data.second;
|
||||||
|
auto* type = builder_.Sem().Get(var)->Type();
|
||||||
|
|
||||||
make_indent(out);
|
make_indent(out);
|
||||||
if (!EmitType(out, var->type(),
|
if (!EmitType(out, type, builder_.Symbols().NameFor(var->symbol()))) {
|
||||||
builder_.Symbols().NameFor(var->symbol()))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1722,10 +1724,10 @@ bool GeneratorImpl::EmitEntryPointData(
|
||||||
for (auto& data : outvariables) {
|
for (auto& data : outvariables) {
|
||||||
auto* var = data.first;
|
auto* var = data.first;
|
||||||
auto* deco = data.second;
|
auto* deco = data.second;
|
||||||
|
auto* type = builder_.Sem().Get(var)->Type();
|
||||||
|
|
||||||
make_indent(out);
|
make_indent(out);
|
||||||
if (!EmitType(out, var->type(),
|
if (!EmitType(out, type, builder_.Symbols().NameFor(var->symbol()))) {
|
||||||
builder_.Symbols().NameFor(var->symbol()))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1766,7 +1768,7 @@ bool GeneratorImpl::EmitEntryPointData(
|
||||||
for (auto* var : func_sem->ReferencedModuleVariables()) {
|
for (auto* var : func_sem->ReferencedModuleVariables()) {
|
||||||
auto* decl = var->Declaration();
|
auto* decl = var->Declaration();
|
||||||
|
|
||||||
auto* unwrapped_type = decl->type()->UnwrapAll();
|
auto* unwrapped_type = var->Type()->UnwrapAll();
|
||||||
if (!unwrapped_type->Is<type::Texture>() &&
|
if (!unwrapped_type->Is<type::Texture>() &&
|
||||||
!unwrapped_type->Is<type::Sampler>()) {
|
!unwrapped_type->Is<type::Sampler>()) {
|
||||||
continue; // Not interested in this type
|
continue; // Not interested in this type
|
||||||
|
@ -1776,7 +1778,7 @@ bool GeneratorImpl::EmitEntryPointData(
|
||||||
continue; // Global already emitted
|
continue; // Global already emitted
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!EmitType(out, decl->type(), "")) {
|
if (!EmitType(out, var->Type(), "")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
out << " " << namer_.NameFor(builder_.Symbols().NameFor(decl->symbol()))
|
out << " " << namer_.NameFor(builder_.Symbols().NameFor(decl->symbol()))
|
||||||
|
@ -1861,7 +1863,8 @@ bool GeneratorImpl::EmitEntryPointFunction(std::ostream& out,
|
||||||
|
|
||||||
// Emit entry point parameters.
|
// Emit entry point parameters.
|
||||||
for (auto* var : func->params()) {
|
for (auto* var : func->params()) {
|
||||||
if (!var->type()->Is<type::Struct>()) {
|
auto* type = builder_.Sem().Get(var)->Type();
|
||||||
|
if (!type->Is<type::Struct>()) {
|
||||||
TINT_ICE(diagnostics_) << "Unsupported non-struct entry point parameter";
|
TINT_ICE(diagnostics_) << "Unsupported non-struct entry point parameter";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1870,7 +1873,7 @@ bool GeneratorImpl::EmitEntryPointFunction(std::ostream& out,
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
if (!EmitType(out, var->type(), "")) {
|
if (!EmitType(out, type, "")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2024,7 +2027,7 @@ bool GeneratorImpl::EmitLoop(std::ostream& out, ast::LoopStatement* stmt) {
|
||||||
if (var->constructor() != nullptr) {
|
if (var->constructor() != nullptr) {
|
||||||
out << constructor_out.str();
|
out << constructor_out.str();
|
||||||
} else {
|
} else {
|
||||||
if (!EmitZeroValue(out, var->type())) {
|
if (!EmitZeroValue(out, builder_.Sem().Get(var)->Type())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2678,10 +2681,11 @@ bool GeneratorImpl::EmitVariable(std::ostream& out,
|
||||||
if (var->is_const()) {
|
if (var->is_const()) {
|
||||||
out << "const ";
|
out << "const ";
|
||||||
}
|
}
|
||||||
if (!EmitType(out, var->type(), builder_.Symbols().NameFor(var->symbol()))) {
|
auto* type = builder_.Sem().Get(var)->Type();
|
||||||
|
if (!EmitType(out, type, builder_.Symbols().NameFor(var->symbol()))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!var->type()->Is<type::Array>()) {
|
if (!type->Is<type::Array>()) {
|
||||||
out << " " << builder_.Symbols().NameFor(var->symbol());
|
out << " " << builder_.Symbols().NameFor(var->symbol());
|
||||||
}
|
}
|
||||||
out << constructor_out.str() << ";" << std::endl;
|
out << constructor_out.str() << ";" << std::endl;
|
||||||
|
@ -2713,6 +2717,8 @@ bool GeneratorImpl::EmitProgramConstVariable(std::ostream& out,
|
||||||
out << pre.str();
|
out << pre.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* type = builder_.Sem().Get(var)->Type();
|
||||||
|
|
||||||
if (var->HasConstantIdDecoration()) {
|
if (var->HasConstantIdDecoration()) {
|
||||||
auto const_id = var->constant_id();
|
auto const_id = var->constant_id();
|
||||||
|
|
||||||
|
@ -2727,8 +2733,7 @@ bool GeneratorImpl::EmitProgramConstVariable(std::ostream& out,
|
||||||
}
|
}
|
||||||
out << "#endif" << std::endl;
|
out << "#endif" << std::endl;
|
||||||
out << "static const ";
|
out << "static const ";
|
||||||
if (!EmitType(out, var->type(),
|
if (!EmitType(out, type, builder_.Symbols().NameFor(var->symbol()))) {
|
||||||
builder_.Symbols().NameFor(var->symbol()))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
out << " " << builder_.Symbols().NameFor(var->symbol())
|
out << " " << builder_.Symbols().NameFor(var->symbol())
|
||||||
|
@ -2736,11 +2741,10 @@ bool GeneratorImpl::EmitProgramConstVariable(std::ostream& out,
|
||||||
out << "#undef WGSL_SPEC_CONSTANT_" << const_id << std::endl;
|
out << "#undef WGSL_SPEC_CONSTANT_" << const_id << std::endl;
|
||||||
} else {
|
} else {
|
||||||
out << "static const ";
|
out << "static const ";
|
||||||
if (!EmitType(out, var->type(),
|
if (!EmitType(out, type, builder_.Symbols().NameFor(var->symbol()))) {
|
||||||
builder_.Symbols().NameFor(var->symbol()))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!var->type()->Is<type::Array>()) {
|
if (!type->Is<type::Array>()) {
|
||||||
out << " " << builder_.Symbols().NameFor(var->symbol());
|
out << " " << builder_.Symbols().NameFor(var->symbol());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -412,6 +412,10 @@ a = (_tint_tmp_0);
|
||||||
TEST_F(HlslGeneratorImplTest_Binary, Decl_WithLogical) {
|
TEST_F(HlslGeneratorImplTest_Binary, Decl_WithLogical) {
|
||||||
// var a : bool = (b && c) || d;
|
// var a : bool = (b && c) || d;
|
||||||
|
|
||||||
|
auto* b_decl = Decl(Var("b", ty.bool_(), ast::StorageClass::kFunction));
|
||||||
|
auto* c_decl = Decl(Var("c", ty.bool_(), ast::StorageClass::kFunction));
|
||||||
|
auto* d_decl = Decl(Var("d", ty.bool_(), ast::StorageClass::kFunction));
|
||||||
|
|
||||||
auto* b = Expr("b");
|
auto* b = Expr("b");
|
||||||
auto* c = Expr("c");
|
auto* c = Expr("c");
|
||||||
auto* d = Expr("d");
|
auto* d = Expr("d");
|
||||||
|
@ -422,11 +426,12 @@ TEST_F(HlslGeneratorImplTest_Binary, Decl_WithLogical) {
|
||||||
ast::BinaryOp::kLogicalOr,
|
ast::BinaryOp::kLogicalOr,
|
||||||
create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, b, c), d));
|
create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, b, c), d));
|
||||||
|
|
||||||
auto* expr = create<ast::VariableDeclStatement>(var);
|
auto* decl = Decl(var);
|
||||||
|
WrapInFunction(b_decl, c_decl, d_decl, Decl(var));
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitStatement(out, expr)) << gen.error();
|
ASSERT_TRUE(gen.EmitStatement(out, decl)) << gen.error();
|
||||||
EXPECT_EQ(result(), R"(bool _tint_tmp = b;
|
EXPECT_EQ(result(), R"(bool _tint_tmp = b;
|
||||||
if (_tint_tmp) {
|
if (_tint_tmp) {
|
||||||
_tint_tmp = c;
|
_tint_tmp = c;
|
||||||
|
|
|
@ -24,6 +24,7 @@ using HlslGeneratorImplTest_ModuleConstant = TestHelper;
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_ModuleConstant) {
|
TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_ModuleConstant) {
|
||||||
auto* var = Const("pos", ty.array<f32, 3>(), array<f32, 3>(1.f, 2.f, 3.f));
|
auto* var = Const("pos", ty.array<f32, 3>(), array<f32, 3>(1.f, 2.f, 3.f));
|
||||||
|
WrapInFunction(Decl(var));
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
|
@ -36,6 +37,7 @@ TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant) {
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::ConstantIdDecoration>(23),
|
create<ast::ConstantIdDecoration>(23),
|
||||||
});
|
});
|
||||||
|
WrapInFunction(Decl(var));
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
|
@ -53,6 +55,7 @@ TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoConstructor) {
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::ConstantIdDecoration>(23),
|
create<ast::ConstantIdDecoration>(23),
|
||||||
});
|
});
|
||||||
|
WrapInFunction(Decl(var));
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
|
||||||
auto* var = Const("a", ty.f32());
|
auto* var = Const("a", ty.f32());
|
||||||
|
|
||||||
auto* stmt = create<ast::VariableDeclStatement>(var);
|
auto* stmt = create<ast::VariableDeclStatement>(var);
|
||||||
|
WrapInFunction(stmt);
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
|
|
|
@ -964,8 +964,8 @@ bool GeneratorImpl::EmitLiteral(ast::Literal* lit) {
|
||||||
bool GeneratorImpl::EmitEntryPointData(ast::Function* func) {
|
bool GeneratorImpl::EmitEntryPointData(ast::Function* func) {
|
||||||
auto* func_sem = program_->Sem().Get(func);
|
auto* func_sem = program_->Sem().Get(func);
|
||||||
|
|
||||||
std::vector<std::pair<ast::Variable*, uint32_t>> in_locations;
|
std::vector<std::pair<const ast::Variable*, uint32_t>> in_locations;
|
||||||
std::vector<std::pair<ast::Variable*, ast::Decoration*>> out_variables;
|
std::vector<std::pair<const ast::Variable*, ast::Decoration*>> out_variables;
|
||||||
|
|
||||||
for (auto data : func_sem->ReferencedLocationVariables()) {
|
for (auto data : func_sem->ReferencedLocationVariables()) {
|
||||||
auto* var = data.first;
|
auto* var = data.first;
|
||||||
|
@ -1003,7 +1003,8 @@ bool GeneratorImpl::EmitEntryPointData(ast::Function* func) {
|
||||||
uint32_t loc = data.second;
|
uint32_t loc = data.second;
|
||||||
|
|
||||||
make_indent();
|
make_indent();
|
||||||
if (!EmitType(var->type(), program_->Symbols().NameFor(var->symbol()))) {
|
if (!EmitType(program_->Sem().Get(var)->Type(),
|
||||||
|
program_->Symbols().NameFor(var->symbol()))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1039,7 +1040,8 @@ bool GeneratorImpl::EmitEntryPointData(ast::Function* func) {
|
||||||
auto* deco = data.second;
|
auto* deco = data.second;
|
||||||
|
|
||||||
make_indent();
|
make_indent();
|
||||||
if (!EmitType(var->type(), program_->Symbols().NameFor(var->symbol()))) {
|
if (!EmitType(program_->Sem().Get(var)->Type(),
|
||||||
|
program_->Symbols().NameFor(var->symbol()))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1252,7 +1254,7 @@ bool GeneratorImpl::EmitFunctionInternal(ast::Function* func,
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
out_ << "thread ";
|
out_ << "thread ";
|
||||||
if (!EmitType(var->Declaration()->type(), "")) {
|
if (!EmitType(var->Type(), "")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
out_ << "& " << program_->Symbols().NameFor(var->Declaration()->symbol());
|
out_ << "& " << program_->Symbols().NameFor(var->Declaration()->symbol());
|
||||||
|
@ -1267,7 +1269,7 @@ bool GeneratorImpl::EmitFunctionInternal(ast::Function* func,
|
||||||
|
|
||||||
out_ << "constant ";
|
out_ << "constant ";
|
||||||
// TODO(dsinclair): Can arrays be uniform? If so, fix this ...
|
// TODO(dsinclair): Can arrays be uniform? If so, fix this ...
|
||||||
if (!EmitType(var->Declaration()->type(), "")) {
|
if (!EmitType(var->Type(), "")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
out_ << "& " << program_->Symbols().NameFor(var->Declaration()->symbol());
|
out_ << "& " << program_->Symbols().NameFor(var->Declaration()->symbol());
|
||||||
|
@ -1280,7 +1282,7 @@ bool GeneratorImpl::EmitFunctionInternal(ast::Function* func,
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
auto* ac = var->Declaration()->type()->As<type::AccessControl>();
|
auto* ac = var->Type()->As<type::AccessControl>();
|
||||||
if (ac == nullptr) {
|
if (ac == nullptr) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"invalid type for storage buffer, expected access control");
|
"invalid type for storage buffer, expected access control");
|
||||||
|
@ -1303,11 +1305,13 @@ bool GeneratorImpl::EmitFunctionInternal(ast::Function* func,
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
if (!EmitType(v->type(), program_->Symbols().NameFor(v->symbol()))) {
|
auto* type = program_->Sem().Get(v)->Type();
|
||||||
|
|
||||||
|
if (!EmitType(type, program_->Symbols().NameFor(v->symbol()))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Array name is output as part of the type
|
// Array name is output as part of the type
|
||||||
if (!v->type()->Is<type::Array>()) {
|
if (!type->Is<type::Array>()) {
|
||||||
out_ << " " << program_->Symbols().NameFor(v->symbol());
|
out_ << " " << program_->Symbols().NameFor(v->symbol());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1394,13 +1398,15 @@ bool GeneratorImpl::EmitEntryPointFunction(ast::Function* func) {
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
if (!EmitType(var->type(), "")) {
|
auto* type = program_->Sem().Get(var)->Type();
|
||||||
|
|
||||||
|
if (!EmitType(type, "")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_ << " " << program_->Symbols().NameFor(var->symbol());
|
out_ << " " << program_->Symbols().NameFor(var->symbol());
|
||||||
|
|
||||||
if (var->type()->Is<type::Struct>()) {
|
if (type->Is<type::Struct>()) {
|
||||||
out_ << " [[stage_in]]";
|
out_ << " [[stage_in]]";
|
||||||
} else {
|
} else {
|
||||||
auto& decos = var->decorations();
|
auto& decos = var->decorations();
|
||||||
|
@ -1440,7 +1446,7 @@ bool GeneratorImpl::EmitEntryPointFunction(ast::Function* func) {
|
||||||
|
|
||||||
auto* builtin = data.second;
|
auto* builtin = data.second;
|
||||||
|
|
||||||
if (!EmitType(var->Declaration()->type(), "")) {
|
if (!EmitType(var->Type(), "")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1475,7 +1481,7 @@ bool GeneratorImpl::EmitEntryPointFunction(ast::Function* func) {
|
||||||
out_ << "constant ";
|
out_ << "constant ";
|
||||||
// TODO(dsinclair): Can you have a uniform array? If so, this needs to be
|
// TODO(dsinclair): Can you have a uniform array? If so, this needs to be
|
||||||
// updated to handle arrays property.
|
// updated to handle arrays property.
|
||||||
if (!EmitType(var->Declaration()->type(), "")) {
|
if (!EmitType(var->Type(), "")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
out_ << "& " << program_->Symbols().NameFor(var->Declaration()->symbol())
|
out_ << "& " << program_->Symbols().NameFor(var->Declaration()->symbol())
|
||||||
|
@ -1495,7 +1501,7 @@ bool GeneratorImpl::EmitEntryPointFunction(ast::Function* func) {
|
||||||
auto* binding = data.second.binding;
|
auto* binding = data.second.binding;
|
||||||
// auto* set = data.second.set;
|
// auto* set = data.second.set;
|
||||||
|
|
||||||
auto* ac = var->Declaration()->type()->As<type::AccessControl>();
|
auto* ac = var->Type()->As<type::AccessControl>();
|
||||||
if (ac == nullptr) {
|
if (ac == nullptr) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"invalid type for storage buffer, expected access control");
|
"invalid type for storage buffer, expected access control");
|
||||||
|
@ -1640,7 +1646,7 @@ bool GeneratorImpl::EmitLoop(ast::LoopStatement* stmt) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!EmitZeroValue(var->type())) {
|
if (!EmitZeroValue(program_->Sem().Get(var)->Type())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2156,10 +2162,10 @@ bool GeneratorImpl::EmitVariable(const semantic::Variable* var,
|
||||||
if (decl->is_const()) {
|
if (decl->is_const()) {
|
||||||
out_ << "const ";
|
out_ << "const ";
|
||||||
}
|
}
|
||||||
if (!EmitType(decl->type(), program_->Symbols().NameFor(decl->symbol()))) {
|
if (!EmitType(var->Type(), program_->Symbols().NameFor(decl->symbol()))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!decl->type()->Is<type::Array>()) {
|
if (!var->Type()->Is<type::Array>()) {
|
||||||
out_ << " " << program_->Symbols().NameFor(decl->symbol());
|
out_ << " " << program_->Symbols().NameFor(decl->symbol());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2173,7 +2179,7 @@ bool GeneratorImpl::EmitVariable(const semantic::Variable* var,
|
||||||
var->StorageClass() == ast::StorageClass::kFunction ||
|
var->StorageClass() == ast::StorageClass::kFunction ||
|
||||||
var->StorageClass() == ast::StorageClass::kNone ||
|
var->StorageClass() == ast::StorageClass::kNone ||
|
||||||
var->StorageClass() == ast::StorageClass::kOutput) {
|
var->StorageClass() == ast::StorageClass::kOutput) {
|
||||||
if (!EmitZeroValue(decl->type())) {
|
if (!EmitZeroValue(var->Type())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2198,10 +2204,11 @@ bool GeneratorImpl::EmitProgramConstVariable(const ast::Variable* var) {
|
||||||
}
|
}
|
||||||
|
|
||||||
out_ << "constant ";
|
out_ << "constant ";
|
||||||
if (!EmitType(var->type(), program_->Symbols().NameFor(var->symbol()))) {
|
auto* type = program_->Sem().Get(var)->Type();
|
||||||
|
if (!EmitType(type, program_->Symbols().NameFor(var->symbol()))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!var->type()->Is<type::Array>()) {
|
if (!type->Is<type::Array>()) {
|
||||||
out_ << " " << program_->Symbols().NameFor(var->symbol());
|
out_ << " " << program_->Symbols().NameFor(var->symbol());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ using MslGeneratorImplTest = TestHelper;
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, Emit_ModuleConstant) {
|
TEST_F(MslGeneratorImplTest, Emit_ModuleConstant) {
|
||||||
auto* var = Const("pos", ty.array<f32, 3>(), array<f32, 3>(1.f, 2.f, 3.f));
|
auto* var = Const("pos", ty.array<f32, 3>(), array<f32, 3>(1.f, 2.f, 3.f));
|
||||||
|
WrapInFunction(Decl(var));
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
|
@ -36,6 +37,7 @@ TEST_F(MslGeneratorImplTest, Emit_SpecConstant) {
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::ConstantIdDecoration>(23),
|
create<ast::ConstantIdDecoration>(23),
|
||||||
});
|
});
|
||||||
|
WrapInFunction(Decl(var));
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
|
|
|
@ -538,7 +538,8 @@ bool Builder::GenerateFunction(ast::Function* func) {
|
||||||
auto param_op = result_op();
|
auto param_op = result_op();
|
||||||
auto param_id = param_op.to_i();
|
auto param_id = param_op.to_i();
|
||||||
|
|
||||||
auto param_type_id = GenerateTypeIfNeeded(param->type());
|
auto param_type_id =
|
||||||
|
GenerateTypeIfNeeded(builder_.Sem().Get(param)->Type());
|
||||||
if (param_type_id == 0) {
|
if (param_type_id == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -592,7 +593,8 @@ uint32_t Builder::GenerateFunctionTypeIfNeeded(ast::Function* func) {
|
||||||
|
|
||||||
OperandList ops = {func_op, Operand::Int(ret_id)};
|
OperandList ops = {func_op, Operand::Int(ret_id)};
|
||||||
for (auto* param : func->params()) {
|
for (auto* param : func->params()) {
|
||||||
auto param_type_id = GenerateTypeIfNeeded(param->type());
|
auto param_type_id =
|
||||||
|
GenerateTypeIfNeeded(builder_.Sem().Get(param)->Type());
|
||||||
if (param_type_id == 0) {
|
if (param_type_id == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -629,7 +631,8 @@ bool Builder::GenerateFunctionVariable(ast::Variable* var) {
|
||||||
auto result = result_op();
|
auto result = result_op();
|
||||||
auto var_id = result.to_i();
|
auto var_id = result.to_i();
|
||||||
auto sc = ast::StorageClass::kFunction;
|
auto sc = ast::StorageClass::kFunction;
|
||||||
type::Pointer pt(var->type(), sc);
|
auto* type = builder_.Sem().Get(var)->Type();
|
||||||
|
type::Pointer pt(type, sc);
|
||||||
auto type_id = GenerateTypeIfNeeded(&pt);
|
auto type_id = GenerateTypeIfNeeded(&pt);
|
||||||
if (type_id == 0) {
|
if (type_id == 0) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -641,7 +644,7 @@ bool Builder::GenerateFunctionVariable(ast::Variable* var) {
|
||||||
|
|
||||||
// TODO(dsinclair) We could detect if the constructor is fully const and emit
|
// TODO(dsinclair) We could detect if the constructor is fully const and emit
|
||||||
// an initializer value for the variable instead of doing the OpLoad.
|
// an initializer value for the variable instead of doing the OpLoad.
|
||||||
auto null_id = GenerateConstantNullIfNeeded(var->type()->UnwrapPtrIfNeeded());
|
auto null_id = GenerateConstantNullIfNeeded(type->UnwrapPtrIfNeeded());
|
||||||
if (null_id == 0) {
|
if (null_id == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -704,7 +707,7 @@ bool Builder::GenerateGlobalVariable(ast::Variable* var) {
|
||||||
? ast::StorageClass::kPrivate
|
? ast::StorageClass::kPrivate
|
||||||
: sem->StorageClass();
|
: sem->StorageClass();
|
||||||
|
|
||||||
type::Pointer pt(var->type(), sc);
|
type::Pointer pt(sem->Type(), sc);
|
||||||
auto type_id = GenerateTypeIfNeeded(&pt);
|
auto type_id = GenerateTypeIfNeeded(&pt);
|
||||||
if (type_id == 0) {
|
if (type_id == 0) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -719,11 +722,11 @@ bool Builder::GenerateGlobalVariable(ast::Variable* var) {
|
||||||
|
|
||||||
// Unwrap after emitting the access control as unwrap all removes access
|
// Unwrap after emitting the access control as unwrap all removes access
|
||||||
// control types.
|
// control types.
|
||||||
auto* type = var->type()->UnwrapAll();
|
auto* type_no_ac = sem->Type()->UnwrapAll();
|
||||||
if (var->has_constructor()) {
|
if (var->has_constructor()) {
|
||||||
ops.push_back(Operand::Int(init_id));
|
ops.push_back(Operand::Int(init_id));
|
||||||
} else if (type->Is<type::Texture>()) {
|
} else if (type_no_ac->Is<type::Texture>()) {
|
||||||
if (auto* ac = var->type()->As<type::AccessControl>()) {
|
if (auto* ac = sem->Type()->As<type::AccessControl>()) {
|
||||||
switch (ac->access_control()) {
|
switch (ac->access_control()) {
|
||||||
case ast::AccessControl::kWriteOnly:
|
case ast::AccessControl::kWriteOnly:
|
||||||
push_annot(
|
push_annot(
|
||||||
|
@ -739,7 +742,7 @@ bool Builder::GenerateGlobalVariable(ast::Variable* var) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!type->Is<type::Sampler>()) {
|
} else if (!type_no_ac->Is<type::Sampler>()) {
|
||||||
// Certain cases require us to generate a constructor value.
|
// Certain cases require us to generate a constructor value.
|
||||||
//
|
//
|
||||||
// 1- ConstantId's must be attached to the OpConstant, if we have a
|
// 1- ConstantId's must be attached to the OpConstant, if we have a
|
||||||
|
@ -748,17 +751,17 @@ bool Builder::GenerateGlobalVariable(ast::Variable* var) {
|
||||||
// 2- If we don't have a constructor and we're an Output or Private variable
|
// 2- If we don't have a constructor and we're an Output or Private variable
|
||||||
// then WGSL requires an initializer.
|
// then WGSL requires an initializer.
|
||||||
if (var->HasConstantIdDecoration()) {
|
if (var->HasConstantIdDecoration()) {
|
||||||
if (type->Is<type::F32>()) {
|
if (type_no_ac->Is<type::F32>()) {
|
||||||
ast::FloatLiteral l(Source{}, type, 0.0f);
|
ast::FloatLiteral l(Source{}, type_no_ac, 0.0f);
|
||||||
init_id = GenerateLiteralIfNeeded(var, &l);
|
init_id = GenerateLiteralIfNeeded(var, &l);
|
||||||
} else if (type->Is<type::U32>()) {
|
} else if (type_no_ac->Is<type::U32>()) {
|
||||||
ast::UintLiteral l(Source{}, type, 0);
|
ast::UintLiteral l(Source{}, type_no_ac, 0);
|
||||||
init_id = GenerateLiteralIfNeeded(var, &l);
|
init_id = GenerateLiteralIfNeeded(var, &l);
|
||||||
} else if (type->Is<type::I32>()) {
|
} else if (type_no_ac->Is<type::I32>()) {
|
||||||
ast::SintLiteral l(Source{}, type, 0);
|
ast::SintLiteral l(Source{}, type_no_ac, 0);
|
||||||
init_id = GenerateLiteralIfNeeded(var, &l);
|
init_id = GenerateLiteralIfNeeded(var, &l);
|
||||||
} else if (type->Is<type::Bool>()) {
|
} else if (type_no_ac->Is<type::Bool>()) {
|
||||||
ast::BoolLiteral l(Source{}, type, false);
|
ast::BoolLiteral l(Source{}, type_no_ac, false);
|
||||||
init_id = GenerateLiteralIfNeeded(var, &l);
|
init_id = GenerateLiteralIfNeeded(var, &l);
|
||||||
} else {
|
} else {
|
||||||
error_ = "invalid type for constant_id, must be scalar";
|
error_ = "invalid type for constant_id, must be scalar";
|
||||||
|
@ -771,7 +774,7 @@ bool Builder::GenerateGlobalVariable(ast::Variable* var) {
|
||||||
} else if (sem->StorageClass() == ast::StorageClass::kPrivate ||
|
} else if (sem->StorageClass() == ast::StorageClass::kPrivate ||
|
||||||
sem->StorageClass() == ast::StorageClass::kNone ||
|
sem->StorageClass() == ast::StorageClass::kNone ||
|
||||||
sem->StorageClass() == ast::StorageClass::kOutput) {
|
sem->StorageClass() == ast::StorageClass::kOutput) {
|
||||||
init_id = GenerateConstantNullIfNeeded(type);
|
init_id = GenerateConstantNullIfNeeded(type_no_ac);
|
||||||
if (init_id == 0) {
|
if (init_id == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -321,7 +321,7 @@ bool GeneratorImpl::EmitFunction(ast::Function* func) {
|
||||||
|
|
||||||
out_ << program_->Symbols().NameFor(v->symbol()) << " : ";
|
out_ << program_->Symbols().NameFor(v->symbol()) << " : ";
|
||||||
|
|
||||||
if (!EmitType(v->type())) {
|
if (!EmitType(program_->Sem().Get(v)->Type())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -578,13 +578,13 @@ bool GeneratorImpl::EmitVariable(ast::Variable* var) {
|
||||||
out_ << "var";
|
out_ << "var";
|
||||||
if (sem->StorageClass() != ast::StorageClass::kNone &&
|
if (sem->StorageClass() != ast::StorageClass::kNone &&
|
||||||
sem->StorageClass() != ast::StorageClass::kFunction &&
|
sem->StorageClass() != ast::StorageClass::kFunction &&
|
||||||
!var->type()->UnwrapAll()->is_handle()) {
|
!sem->Type()->UnwrapAll()->is_handle()) {
|
||||||
out_ << "<" << sem->StorageClass() << ">";
|
out_ << "<" << sem->StorageClass() << ">";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out_ << " " << program_->Symbols().NameFor(var->symbol()) << " : ";
|
out_ << " " << program_->Symbols().NameFor(var->symbol()) << " : ";
|
||||||
if (!EmitType(var->type())) {
|
if (!EmitType(sem->Type())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,23 +75,24 @@ TEST_F(WgslGeneratorImplTest, EmitVariable_Decorated_Multiple) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitVariable_Constructor) {
|
TEST_F(WgslGeneratorImplTest, EmitVariable_Constructor) {
|
||||||
auto* v =
|
auto* v = Global("a", ty.f32(), ast::StorageClass::kNone, Expr(1.0f));
|
||||||
Global("a", ty.f32(), ast::StorageClass::kNone, Expr("initializer"));
|
WrapInFunction(Decl(v));
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
|
ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
|
||||||
EXPECT_EQ(gen.result(), R"(var a : f32 = initializer;
|
EXPECT_EQ(gen.result(), R"(var a : f32 = 1.0;
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitVariable_Const) {
|
TEST_F(WgslGeneratorImplTest, EmitVariable_Const) {
|
||||||
auto* v = Const("a", ty.f32(), Expr("initializer"));
|
auto* v = Const("a", ty.f32(), Expr(1.0f));
|
||||||
|
WrapInFunction(Decl(v));
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
|
ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
|
||||||
EXPECT_EQ(gen.result(), R"(const a : f32 = initializer;
|
EXPECT_EQ(gen.result(), R"(const a : f32 = 1.0;
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue