Start cleaning up tests (4/N)

Remove Source{} with ast::Builder::create<>
Use Builder helpers where possible

Change-Id: I07fdefdbbcc4a9289069e2e494f475c7baea7531
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/35741
Auto-Submit: Ben Clayton <bclayton@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
Ben Clayton 2020-12-15 14:10:28 +00:00 committed by Commit Bot service account
parent 983e8dd938
commit 7e805ba44a
9 changed files with 601 additions and 1137 deletions

View File

@ -75,6 +75,18 @@ Variable* Builder::Const(const std::string& name,
return var; return var;
} }
Variable* Builder::Const(const Source& source,
const std::string& name,
StorageClass storage,
type::Type* type,
Expression* constructor,
VariableDecorationList decorations) {
auto* var = create<Variable>(source, name, storage, type, true, constructor,
decorations);
OnVariableBuilt(var);
return var;
}
BuilderWithModule::BuilderWithModule() : Builder(new Module()) {} BuilderWithModule::BuilderWithModule() : Builder(new Module()) {}
BuilderWithModule::~BuilderWithModule() { BuilderWithModule::~BuilderWithModule() {

View File

@ -499,6 +499,20 @@ class Builder {
Expression* constructor, Expression* constructor,
VariableDecorationList decorations); VariableDecorationList decorations);
/// @param source the variable source
/// @param name the variable name
/// @param storage the variable storage class
/// @param type the variable type
/// @param constructor optional constructor expression
/// @param decorations optional variable decorations
/// @returns a constant `Variable` with the given name, storage and type
Variable* Const(const Source& source,
const std::string& name,
StorageClass storage,
type::Type* type,
Expression* constructor,
VariableDecorationList decorations);
/// @param func the function name /// @param func the function name
/// @param args the function call arguments /// @param args the function call arguments
/// @returns a `CallExpression` to the function `func`, with the /// @returns a `CallExpression` to the function `func`, with the

View File

@ -17,6 +17,7 @@
#include <utility> #include <utility>
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/builder.h"
#include "src/ast/function.h" #include "src/ast/function.h"
#include "src/ast/pipeline_stage.h" #include "src/ast/pipeline_stage.h"
#include "src/ast/stage_decoration.h" #include "src/ast/stage_decoration.h"
@ -34,10 +35,9 @@ namespace tint {
namespace transform { namespace transform {
namespace { namespace {
class VertexPullingHelper { class VertexPullingHelper : public ast::BuilderWithModule {
public: public:
VertexPullingHelper() { VertexPullingHelper() {
mod_ = std::make_unique<ast::Module>();
manager_ = std::make_unique<Manager>(); manager_ = std::make_unique<Manager>();
auto transform = std::make_unique<VertexPulling>(); auto transform = std::make_unique<VertexPulling>();
transform_ = transform.get(); transform_ = transform.get();
@ -47,19 +47,19 @@ class VertexPullingHelper {
// Create basic module with an entry point and vertex function // Create basic module with an entry point and vertex function
void InitBasicModule() { void InitBasicModule() {
auto* func = create<ast::Function>( auto* func = create<ast::Function>(
Source{}, mod()->RegisterSymbol("main"), "main", ast::VariableList{}, mod->RegisterSymbol("main"), "main", ast::VariableList{},
mod_->create<ast::type::Void>(), mod->create<ast::type::Void>(),
create<ast::BlockStatement>(Source{}, ast::StatementList{}), create<ast::BlockStatement>(ast::StatementList{}),
ast::FunctionDecorationList{create<ast::StageDecoration>( ast::FunctionDecorationList{
Source{}, ast::PipelineStage::kVertex)}); create<ast::StageDecoration>(ast::PipelineStage::kVertex)});
mod()->AddFunction(func); mod->AddFunction(func);
} }
// Set up the transformation, after building the module // Set up the transformation, after building the module
void InitTransform(VertexStateDescriptor vertex_state) { void InitTransform(VertexStateDescriptor vertex_state) {
EXPECT_TRUE(mod_->IsValid()); EXPECT_TRUE(mod->IsValid());
TypeDeterminer td(mod_.get()); TypeDeterminer td(mod);
EXPECT_TRUE(td.Determine()); EXPECT_TRUE(td.Determine());
transform_->SetVertexState(vertex_state); transform_->SetVertexState(vertex_state);
@ -70,37 +70,18 @@ class VertexPullingHelper {
void AddVertexInputVariable(uint32_t location, void AddVertexInputVariable(uint32_t location,
std::string name, std::string name,
ast::type::Type* type) { ast::type::Type* type) {
auto* var = create<ast::Variable>( auto* var = Var(name, ast::StorageClass::kInput, type, nullptr,
Source{}, // source ast::VariableDecorationList{
name, // name create<ast::LocationDecoration>(location),
ast::StorageClass::kInput, // storage_class });
type, // type
false, // is_const
nullptr, // constructor
ast::VariableDecorationList{
// decorations
create<ast::LocationDecoration>(Source{}, location),
});
mod_->AddGlobalVariable(var); mod->AddGlobalVariable(var);
} }
ast::Module* mod() { return mod_.get(); }
Manager* manager() { return manager_.get(); } Manager* manager() { return manager_.get(); }
VertexPulling* transform() { return transform_; } VertexPulling* transform() { return transform_; }
/// Creates a new `ast::Node` owned by the Module. When the Module is
/// destructed, the `ast::Node` will also be destructed.
/// @param args the arguments to pass to the type constructor
/// @returns the node pointer
template <typename T, typename... ARGS>
T* create(ARGS&&... args) {
return mod_->create<T>(std::forward<ARGS>(args)...);
}
private: private:
std::unique_ptr<ast::Module> mod_;
std::unique_ptr<Manager> manager_; std::unique_ptr<Manager> manager_;
VertexPulling* transform_; VertexPulling* transform_;
}; };
@ -108,7 +89,7 @@ class VertexPullingHelper {
class VertexPullingTest : public VertexPullingHelper, public testing::Test {}; class VertexPullingTest : public VertexPullingHelper, public testing::Test {};
TEST_F(VertexPullingTest, Error_NoVertexState) { TEST_F(VertexPullingTest, Error_NoVertexState) {
auto result = manager()->Run(mod()); auto result = manager()->Run(mod);
EXPECT_TRUE(result.diagnostics.contains_errors()); EXPECT_TRUE(result.diagnostics.contains_errors());
EXPECT_EQ(diag::Formatter().format(result.diagnostics), EXPECT_EQ(diag::Formatter().format(result.diagnostics),
"error: SetVertexState not called"); "error: SetVertexState not called");
@ -116,7 +97,7 @@ TEST_F(VertexPullingTest, Error_NoVertexState) {
TEST_F(VertexPullingTest, Error_NoEntryPoint) { TEST_F(VertexPullingTest, Error_NoEntryPoint) {
transform()->SetVertexState({}); transform()->SetVertexState({});
auto result = manager()->Run(mod()); auto result = manager()->Run(mod);
EXPECT_TRUE(result.diagnostics.contains_errors()); EXPECT_TRUE(result.diagnostics.contains_errors());
EXPECT_EQ(diag::Formatter().format(result.diagnostics), EXPECT_EQ(diag::Formatter().format(result.diagnostics),
"error: Vertex stage entry point not found"); "error: Vertex stage entry point not found");
@ -127,7 +108,7 @@ TEST_F(VertexPullingTest, Error_InvalidEntryPoint) {
InitTransform({}); InitTransform({});
transform()->SetEntryPoint("_"); transform()->SetEntryPoint("_");
auto result = manager()->Run(mod()); auto result = manager()->Run(mod);
EXPECT_TRUE(result.diagnostics.contains_errors()); EXPECT_TRUE(result.diagnostics.contains_errors());
EXPECT_EQ(diag::Formatter().format(result.diagnostics), EXPECT_EQ(diag::Formatter().format(result.diagnostics),
"error: Vertex stage entry point not found"); "error: Vertex stage entry point not found");
@ -135,16 +116,16 @@ TEST_F(VertexPullingTest, Error_InvalidEntryPoint) {
TEST_F(VertexPullingTest, Error_EntryPointWrongStage) { TEST_F(VertexPullingTest, Error_EntryPointWrongStage) {
auto* func = create<ast::Function>( auto* func = create<ast::Function>(
Source{}, mod()->RegisterSymbol("main"), "main", ast::VariableList{}, mod->RegisterSymbol("main"), "main", ast::VariableList{},
mod()->create<ast::type::Void>(), mod->create<ast::type::Void>(),
create<ast::BlockStatement>(Source{}, ast::StatementList{}), create<ast::BlockStatement>(ast::StatementList{}),
ast::FunctionDecorationList{ ast::FunctionDecorationList{
create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment), create<ast::StageDecoration>(ast::PipelineStage::kFragment),
}); });
mod()->AddFunction(func); mod->AddFunction(func);
InitTransform({}); InitTransform({});
auto result = manager()->Run(mod()); auto result = manager()->Run(mod);
EXPECT_TRUE(result.diagnostics.contains_errors()); EXPECT_TRUE(result.diagnostics.contains_errors());
EXPECT_EQ(diag::Formatter().format(result.diagnostics), EXPECT_EQ(diag::Formatter().format(result.diagnostics),
"error: Vertex stage entry point not found"); "error: Vertex stage entry point not found");
@ -153,7 +134,7 @@ TEST_F(VertexPullingTest, Error_EntryPointWrongStage) {
TEST_F(VertexPullingTest, BasicModule) { TEST_F(VertexPullingTest, BasicModule) {
InitBasicModule(); InitBasicModule();
InitTransform({}); InitTransform({});
auto result = manager()->Run(mod()); auto result = manager()->Run(mod);
ASSERT_FALSE(result.diagnostics.contains_errors()) ASSERT_FALSE(result.diagnostics.contains_errors())
<< diag::Formatter().format(result.diagnostics); << diag::Formatter().format(result.diagnostics);
} }
@ -166,7 +147,7 @@ TEST_F(VertexPullingTest, OneAttribute) {
InitTransform({{{4, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}}}}}); InitTransform({{{4, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}}}}});
auto result = manager()->Run(mod()); auto result = manager()->Run(mod);
ASSERT_FALSE(result.diagnostics.contains_errors()) ASSERT_FALSE(result.diagnostics.contains_errors())
<< diag::Formatter().format(result.diagnostics); << diag::Formatter().format(result.diagnostics);
@ -253,7 +234,7 @@ TEST_F(VertexPullingTest, OneInstancedAttribute) {
InitTransform( InitTransform(
{{{4, InputStepMode::kInstance, {{VertexFormat::kF32, 0, 0}}}}}); {{{4, InputStepMode::kInstance, {{VertexFormat::kF32, 0, 0}}}}});
auto result = manager()->Run(mod()); auto result = manager()->Run(mod);
ASSERT_FALSE(result.diagnostics.contains_errors()) ASSERT_FALSE(result.diagnostics.contains_errors())
<< diag::Formatter().format(result.diagnostics); << diag::Formatter().format(result.diagnostics);
@ -340,7 +321,7 @@ TEST_F(VertexPullingTest, OneAttributeDifferentOutputSet) {
InitTransform({{{4, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}}}}}); InitTransform({{{4, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}}}}});
transform()->SetPullingBufferBindingSet(5); transform()->SetPullingBufferBindingSet(5);
auto result = manager()->Run(mod()); auto result = manager()->Run(mod);
ASSERT_FALSE(result.diagnostics.contains_errors()) ASSERT_FALSE(result.diagnostics.contains_errors())
<< diag::Formatter().format(result.diagnostics); << diag::Formatter().format(result.diagnostics);
@ -428,35 +409,23 @@ TEST_F(VertexPullingTest, ExistingVertexIndexAndInstanceIndex) {
ast::type::I32 i32; ast::type::I32 i32;
mod()->AddGlobalVariable(create<ast::Variable>( mod->AddGlobalVariable(
Source{}, // source Var("custom_vertex_index", ast::StorageClass::kInput, &i32, nullptr,
"custom_vertex_index", // name ast::VariableDecorationList{
ast::StorageClass::kInput, // storage_class create<ast::BuiltinDecoration>(ast::Builtin::kVertexIdx),
&i32, // type }));
false, // is_const
nullptr, // constructor
ast::VariableDecorationList{
// decorations
create<ast::BuiltinDecoration>(Source{}, ast::Builtin::kVertexIdx),
}));
mod()->AddGlobalVariable(create<ast::Variable>( mod->AddGlobalVariable(
Source{}, // source Var("custom_instance_index", ast::StorageClass::kInput, &i32, nullptr,
"custom_instance_index", // name ast::VariableDecorationList{
ast::StorageClass::kInput, // storage_class create<ast::BuiltinDecoration>(ast::Builtin::kInstanceIdx),
&i32, // type }));
false, // is_const
nullptr, // constructor
ast::VariableDecorationList{
// decorations
create<ast::BuiltinDecoration>(Source{}, ast::Builtin::kInstanceIdx),
}));
InitTransform( InitTransform(
{{{4, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}}}, {{{4, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}}},
{4, InputStepMode::kInstance, {{VertexFormat::kF32, 0, 1}}}}}); {4, InputStepMode::kInstance, {{VertexFormat::kF32, 0, 1}}}}});
auto result = manager()->Run(mod()); auto result = manager()->Run(mod);
ASSERT_FALSE(result.diagnostics.contains_errors()) ASSERT_FALSE(result.diagnostics.contains_errors())
<< diag::Formatter().format(result.diagnostics); << diag::Formatter().format(result.diagnostics);
@ -598,7 +567,7 @@ TEST_F(VertexPullingTest, TwoAttributesSameBuffer) {
InputStepMode::kVertex, InputStepMode::kVertex,
{{VertexFormat::kF32, 0, 0}, {VertexFormat::kVec4F32, 0, 1}}}}}); {{VertexFormat::kF32, 0, 0}, {VertexFormat::kVec4F32, 0, 1}}}}});
auto result = manager()->Run(mod()); auto result = manager()->Run(mod);
ASSERT_FALSE(result.diagnostics.contains_errors()) ASSERT_FALSE(result.diagnostics.contains_errors())
<< diag::Formatter().format(result.diagnostics); << diag::Formatter().format(result.diagnostics);
@ -785,7 +754,7 @@ TEST_F(VertexPullingTest, FloatVectorAttributes) {
{12, InputStepMode::kVertex, {{VertexFormat::kVec3F32, 0, 1}}}, {12, InputStepMode::kVertex, {{VertexFormat::kVec3F32, 0, 1}}},
{16, InputStepMode::kVertex, {{VertexFormat::kVec4F32, 0, 2}}}}}); {16, InputStepMode::kVertex, {{VertexFormat::kVec4F32, 0, 2}}}}});
auto result = manager()->Run(mod()); auto result = manager()->Run(mod);
ASSERT_FALSE(result.diagnostics.contains_errors()) ASSERT_FALSE(result.diagnostics.contains_errors())
<< diag::Formatter().format(result.diagnostics); << diag::Formatter().format(result.diagnostics);

View File

@ -42,32 +42,20 @@ TEST_F(ValidateControlBlockTest, SwitchSelectorExpressionNoneIntegerType_Fail) {
// switch (a) { // switch (a) {
// default: {} // default: {}
// } // }
ast::type::F32 f32; auto* var = Var("a", ast::StorageClass::kNone, ty.f32, Expr(3.14f),
auto* var = create<ast::Variable>( ast::VariableDecorationList{});
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &f32, 3.14f)), // constructor
ast::VariableDecorationList{}); // decorations
auto* cond = create<ast::IdentifierExpression>( auto* cond = create<ast::IdentifierExpression>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("a"), "a"); Source{Source::Location{12, 34}}, mod->RegisterSymbol("a"), "a");
ast::CaseSelectorList default_csl; ast::CaseSelectorList default_csl;
auto* block_default = auto* block_default = create<ast::BlockStatement>(ast::StatementList{});
create<ast::BlockStatement>(Source{}, ast::StatementList{});
ast::CaseStatementList body; ast::CaseStatementList body;
body.push_back( body.push_back(create<ast::CaseStatement>(default_csl, block_default));
create<ast::CaseStatement>(Source{}, default_csl, block_default));
auto* block = create<ast::BlockStatement>( auto* block = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var),
create<ast::VariableDeclStatement>(Source{}, var), create<ast::SwitchStatement>(cond, body),
create<ast::SwitchStatement>(Source{}, cond, body), });
});
EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
EXPECT_FALSE(v()->ValidateStatements(block)); EXPECT_FALSE(v()->ValidateStatements(block));
@ -81,33 +69,21 @@ TEST_F(ValidateControlBlockTest, SwitchWithoutDefault_Fail) {
// switch (a) { // switch (a) {
// case 1: {} // case 1: {}
// } // }
ast::type::I32 i32; auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
auto* var = create<ast::Variable>( ast::VariableDecorationList{});
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &i32, 2)), // constructor
ast::VariableDecorationList{}); // decorations
auto* cond = create<ast::IdentifierExpression>( auto* cond = Expr("a");
Source{}, mod()->RegisterSymbol("a"), "a");
ast::CaseSelectorList csl; ast::CaseSelectorList csl;
csl.push_back(create<ast::SintLiteral>(Source{}, &i32, 1)); csl.push_back(Literal(1));
ast::CaseStatementList body; ast::CaseStatementList body;
body.push_back(create<ast::CaseStatement>( body.push_back(create<ast::CaseStatement>(
Source{}, csl, csl, create<ast::BlockStatement>(ast::StatementList{})));
create<ast::BlockStatement>(Source{}, ast::StatementList{})));
auto* block = create<ast::BlockStatement>( auto* block = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var),
create<ast::VariableDeclStatement>(Source{}, var), create<ast::SwitchStatement>(Source{Source::Location{12, 34}}, cond,
create<ast::SwitchStatement>( body),
Source{Source::Location{12, 34}}, cond, body), });
});
EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
EXPECT_FALSE(v()->ValidateStatements(block)); EXPECT_FALSE(v()->ValidateStatements(block));
@ -123,47 +99,32 @@ TEST_F(ValidateControlBlockTest, SwitchWithTwoDefault_Fail) {
// case 1: {} // case 1: {}
// default: {} // default: {}
// } // }
ast::type::I32 i32; auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
auto* var = create<ast::Variable>( ast::VariableDecorationList{});
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &i32, 2)), // constructor
ast::VariableDecorationList{}); // decorations
ast::CaseStatementList switch_body; ast::CaseStatementList switch_body;
auto* cond = create<ast::IdentifierExpression>( auto* cond = Expr("a");
Source{}, mod()->RegisterSymbol("a"), "a");
ast::CaseSelectorList default_csl_1; ast::CaseSelectorList default_csl_1;
auto* block_default_1 = auto* block_default_1 = create<ast::BlockStatement>(ast::StatementList{});
create<ast::BlockStatement>(Source{}, ast::StatementList{});
switch_body.push_back( switch_body.push_back(
create<ast::CaseStatement>(Source{}, default_csl_1, block_default_1)); create<ast::CaseStatement>(default_csl_1, block_default_1));
ast::CaseSelectorList csl_case_1; ast::CaseSelectorList csl_case_1;
csl_case_1.push_back(create<ast::SintLiteral>(Source{}, &i32, 1)); csl_case_1.push_back(Literal(1));
auto* block_case_1 = auto* block_case_1 = create<ast::BlockStatement>(ast::StatementList{});
create<ast::BlockStatement>(Source{}, ast::StatementList{}); switch_body.push_back(create<ast::CaseStatement>(csl_case_1, block_case_1));
switch_body.push_back(
create<ast::CaseStatement>(Source{}, csl_case_1, block_case_1));
ast::CaseSelectorList default_csl_2; ast::CaseSelectorList default_csl_2;
auto* block_default_2 = auto* block_default_2 = create<ast::BlockStatement>(ast::StatementList{});
create<ast::BlockStatement>(Source{}, ast::StatementList{});
switch_body.push_back( switch_body.push_back(
create<ast::CaseStatement>(Source{}, default_csl_2, block_default_2)); create<ast::CaseStatement>(default_csl_2, block_default_2));
auto* block = create<ast::BlockStatement>( auto* block = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var),
create<ast::VariableDeclStatement>(Source{}, var), create<ast::SwitchStatement>(Source{Source::Location{12, 34}}, cond,
create<ast::SwitchStatement>( switch_body),
Source{Source::Location{12, 34}}, cond, switch_body), });
});
EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
EXPECT_FALSE(v()->ValidateStatements(block)); EXPECT_FALSE(v()->ValidateStatements(block));
@ -179,40 +140,26 @@ TEST_F(ValidateControlBlockTest,
// case 1: {} // case 1: {}
// default: {} // default: {}
// } // }
ast::type::U32 u32; auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
ast::type::I32 i32; ast::VariableDecorationList{});
auto* var = create<ast::Variable>(
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &i32, 2)), // constructor
ast::VariableDecorationList{}); // decorations
ast::CaseStatementList switch_body; ast::CaseStatementList switch_body;
auto* cond = create<ast::IdentifierExpression>( auto* cond = Expr("a");
Source{}, mod()->RegisterSymbol("a"), "a");
ast::CaseSelectorList csl; ast::CaseSelectorList csl;
csl.push_back(create<ast::UintLiteral>(Source{}, &u32, 1)); csl.push_back(create<ast::UintLiteral>(ty.u32, 1));
switch_body.push_back(create<ast::CaseStatement>( switch_body.push_back(create<ast::CaseStatement>(
Source{Source::Location{12, 34}}, csl, Source{Source::Location{12, 34}}, csl,
create<ast::BlockStatement>(Source{}, ast::StatementList{}))); create<ast::BlockStatement>(ast::StatementList{})));
ast::CaseSelectorList default_csl; ast::CaseSelectorList default_csl;
auto* block_default = auto* block_default = create<ast::BlockStatement>(ast::StatementList{});
create<ast::BlockStatement>(Source{}, ast::StatementList{}); switch_body.push_back(create<ast::CaseStatement>(default_csl, block_default));
switch_body.push_back(
create<ast::CaseStatement>(Source{}, default_csl, block_default));
auto* block = create<ast::BlockStatement>( auto* block = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var),
create<ast::VariableDeclStatement>(Source{}, var), create<ast::SwitchStatement>(cond, switch_body),
create<ast::SwitchStatement>(Source{}, cond, switch_body), });
});
EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
EXPECT_FALSE(v()->ValidateStatements(block)); EXPECT_FALSE(v()->ValidateStatements(block));
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
@ -227,40 +174,28 @@ TEST_F(ValidateControlBlockTest,
// case -1: {} // case -1: {}
// default: {} // default: {}
// } // }
ast::type::U32 u32; auto* var = Var("a", ast::StorageClass::kNone, ty.u32,
ast::type::I32 i32; create<ast::ScalarConstructorExpression>(
auto* var = create<ast::Variable>( create<ast::UintLiteral>(ty.u32, 2)),
Source{}, // source ast::VariableDecorationList{});
"a", // name
ast::StorageClass::kNone, // storage_class
&u32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::UintLiteral>(Source{}, &u32, 2)), // constructor
ast::VariableDecorationList{}); // decorations
ast::CaseStatementList switch_body; ast::CaseStatementList switch_body;
auto* cond = create<ast::IdentifierExpression>( auto* cond = Expr("a");
Source{}, mod()->RegisterSymbol("a"), "a");
ast::CaseSelectorList csl; ast::CaseSelectorList csl;
csl.push_back(create<ast::SintLiteral>(Source{}, &i32, -1)); csl.push_back(Literal(-1));
switch_body.push_back(create<ast::CaseStatement>( switch_body.push_back(create<ast::CaseStatement>(
Source{Source::Location{12, 34}}, csl, Source{Source::Location{12, 34}}, csl,
create<ast::BlockStatement>(Source{}, ast::StatementList{}))); create<ast::BlockStatement>(ast::StatementList{})));
ast::CaseSelectorList default_csl; ast::CaseSelectorList default_csl;
auto* block_default = auto* block_default = create<ast::BlockStatement>(ast::StatementList{});
create<ast::BlockStatement>(Source{}, ast::StatementList{}); switch_body.push_back(create<ast::CaseStatement>(default_csl, block_default));
switch_body.push_back(
create<ast::CaseStatement>(Source{}, default_csl, block_default));
auto* block = create<ast::BlockStatement>( auto* block = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var),
create<ast::VariableDeclStatement>(Source{}, var), create<ast::SwitchStatement>(cond, switch_body),
create<ast::SwitchStatement>(Source{}, cond, switch_body), });
});
EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
EXPECT_FALSE(v()->ValidateStatements(block)); EXPECT_FALSE(v()->ValidateStatements(block));
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
@ -275,46 +210,34 @@ TEST_F(ValidateControlBlockTest, NonUniqueCaseSelectorValueUint_Fail) {
// case 2, 2: {} // case 2, 2: {}
// default: {} // default: {}
// } // }
ast::type::U32 u32; auto* var = Var("a", ast::StorageClass::kNone, ty.u32,
auto* var = create<ast::Variable>( create<ast::ScalarConstructorExpression>(
Source{}, // source create<ast::UintLiteral>(ty.u32, 3)),
"a", // name ast::VariableDecorationList{});
ast::StorageClass::kNone, // storage_class
&u32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::UintLiteral>(Source{}, &u32, 3)), // constructor
ast::VariableDecorationList{}); // decorations
ast::CaseStatementList switch_body; ast::CaseStatementList switch_body;
auto* cond = create<ast::IdentifierExpression>( auto* cond = Expr("a");
Source{}, mod()->RegisterSymbol("a"), "a");
ast::CaseSelectorList csl_1; ast::CaseSelectorList csl_1;
csl_1.push_back(create<ast::UintLiteral>(Source{}, &u32, 0)); csl_1.push_back(create<ast::UintLiteral>(ty.u32, 0));
switch_body.push_back(create<ast::CaseStatement>( switch_body.push_back(create<ast::CaseStatement>(
Source{}, csl_1, csl_1, create<ast::BlockStatement>(ast::StatementList{})));
create<ast::BlockStatement>(Source{}, ast::StatementList{})));
ast::CaseSelectorList csl_2; ast::CaseSelectorList csl_2;
csl_2.push_back(create<ast::UintLiteral>(Source{}, &u32, 2)); csl_2.push_back(create<ast::UintLiteral>(ty.u32, 2));
csl_2.push_back(create<ast::UintLiteral>(Source{}, &u32, 2)); csl_2.push_back(create<ast::UintLiteral>(ty.u32, 2));
switch_body.push_back(create<ast::CaseStatement>( switch_body.push_back(create<ast::CaseStatement>(
Source{Source::Location{12, 34}}, csl_2, Source{Source::Location{12, 34}}, csl_2,
create<ast::BlockStatement>(Source{}, ast::StatementList{}))); create<ast::BlockStatement>(ast::StatementList{})));
ast::CaseSelectorList default_csl; ast::CaseSelectorList default_csl;
auto* block_default = auto* block_default = create<ast::BlockStatement>(ast::StatementList{});
create<ast::BlockStatement>(Source{}, ast::StatementList{}); switch_body.push_back(create<ast::CaseStatement>(default_csl, block_default));
switch_body.push_back(
create<ast::CaseStatement>(Source{}, default_csl, block_default));
auto* block = create<ast::BlockStatement>( auto* block = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var),
create<ast::VariableDeclStatement>(Source{}, var), create<ast::SwitchStatement>(cond, switch_body),
create<ast::SwitchStatement>(Source{}, cond, switch_body), });
});
EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
EXPECT_FALSE(v()->ValidateStatements(block)); EXPECT_FALSE(v()->ValidateStatements(block));
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
@ -329,48 +252,34 @@ TEST_F(ValidateControlBlockTest, NonUniqueCaseSelectorValueSint_Fail) {
// case 0,1,2,10: {} // case 0,1,2,10: {}
// default: {} // default: {}
// } // }
ast::type::I32 i32; auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
auto* var = create<ast::Variable>( ast::VariableDecorationList{});
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &i32, 2)), // constructor
ast::VariableDecorationList{}); // decorations
ast::CaseStatementList switch_body; ast::CaseStatementList switch_body;
auto* cond = create<ast::IdentifierExpression>( auto* cond = Expr("a");
Source{}, mod()->RegisterSymbol("a"), "a");
ast::CaseSelectorList csl_1; ast::CaseSelectorList csl_1;
csl_1.push_back(create<ast::SintLiteral>(Source{}, &i32, 10)); csl_1.push_back(Literal(10));
switch_body.push_back(create<ast::CaseStatement>( switch_body.push_back(create<ast::CaseStatement>(
Source{}, csl_1, csl_1, create<ast::BlockStatement>(ast::StatementList{})));
create<ast::BlockStatement>(Source{}, ast::StatementList{})));
ast::CaseSelectorList csl_2; ast::CaseSelectorList csl_2;
csl_2.push_back(create<ast::SintLiteral>(Source{}, &i32, 0)); csl_2.push_back(Literal(0));
csl_2.push_back(create<ast::SintLiteral>(Source{}, &i32, 1)); csl_2.push_back(Literal(1));
csl_2.push_back(create<ast::SintLiteral>(Source{}, &i32, 2)); csl_2.push_back(Literal(2));
csl_2.push_back(create<ast::SintLiteral>(Source{}, &i32, 10)); csl_2.push_back(Literal(10));
switch_body.push_back(create<ast::CaseStatement>( switch_body.push_back(create<ast::CaseStatement>(
Source{Source::Location{12, 34}}, csl_2, Source{Source::Location{12, 34}}, csl_2,
create<ast::BlockStatement>(Source{}, ast::StatementList{}))); create<ast::BlockStatement>(ast::StatementList{})));
ast::CaseSelectorList default_csl; ast::CaseSelectorList default_csl;
auto* block_default = auto* block_default = create<ast::BlockStatement>(ast::StatementList{});
create<ast::BlockStatement>(Source{}, ast::StatementList{}); switch_body.push_back(create<ast::CaseStatement>(default_csl, block_default));
switch_body.push_back(
create<ast::CaseStatement>(Source{}, default_csl, block_default));
auto* block = create<ast::BlockStatement>( auto* block = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var),
create<ast::VariableDeclStatement>(Source{}, var), create<ast::SwitchStatement>(cond, switch_body),
create<ast::SwitchStatement>(Source{}, cond, switch_body), });
});
EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
EXPECT_FALSE(v()->ValidateStatements(block)); EXPECT_FALSE(v()->ValidateStatements(block));
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
@ -383,35 +292,23 @@ TEST_F(ValidateControlBlockTest, LastClauseLastStatementIsFallthrough_Fail) {
// switch (a) { // switch (a) {
// default: { fallthrough; } // default: { fallthrough; }
// } // }
ast::type::I32 i32; auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
auto* var = create<ast::Variable>( ast::VariableDecorationList{});
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &i32, 2)), // constructor
ast::VariableDecorationList{}); // decorations
auto* cond = create<ast::IdentifierExpression>( auto* cond = Expr("a");
Source{}, mod()->RegisterSymbol("a"), "a");
ast::CaseSelectorList default_csl; ast::CaseSelectorList default_csl;
auto* block_default = create<ast::BlockStatement>( auto* block_default = create<ast::BlockStatement>(
Source{},
ast::StatementList{ ast::StatementList{
create<ast::FallthroughStatement>(Source{Source::Location{12, 34}}), create<ast::FallthroughStatement>(Source{Source::Location{12, 34}}),
}); });
ast::CaseStatementList body; ast::CaseStatementList body;
body.push_back( body.push_back(create<ast::CaseStatement>(default_csl, block_default));
create<ast::CaseStatement>(Source{}, default_csl, block_default));
auto* block = create<ast::BlockStatement>( auto* block = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var),
create<ast::VariableDeclStatement>(Source{}, var), create<ast::SwitchStatement>(cond, body),
create<ast::SwitchStatement>(Source{}, cond, body), });
});
EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
EXPECT_FALSE(v()->ValidateStatements(block)); EXPECT_FALSE(v()->ValidateStatements(block));
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
@ -425,37 +322,24 @@ TEST_F(ValidateControlBlockTest, SwitchCase_Pass) {
// default: {} // default: {}
// case 5: {} // case 5: {}
// } // }
ast::type::I32 i32; auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
auto* var = create<ast::Variable>( ast::VariableDecorationList{});
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &i32, 2)), // constructor
ast::VariableDecorationList{}); // decorations
auto* cond = create<ast::IdentifierExpression>( auto* cond = Expr("a");
Source{}, mod()->RegisterSymbol("a"), "a");
ast::CaseSelectorList default_csl; ast::CaseSelectorList default_csl;
auto* block_default = auto* block_default = create<ast::BlockStatement>(ast::StatementList{});
create<ast::BlockStatement>(Source{}, ast::StatementList{});
ast::CaseStatementList body; ast::CaseStatementList body;
body.push_back(create<ast::CaseStatement>(Source{Source::Location{12, 34}}, body.push_back(create<ast::CaseStatement>(Source{Source::Location{12, 34}},
default_csl, block_default)); default_csl, block_default));
ast::CaseSelectorList case_csl; ast::CaseSelectorList case_csl;
case_csl.push_back(create<ast::SintLiteral>(Source{}, &i32, 5)); case_csl.push_back(Literal(5));
auto* block_case = auto* block_case = create<ast::BlockStatement>(ast::StatementList{});
create<ast::BlockStatement>(Source{}, ast::StatementList{}); body.push_back(create<ast::CaseStatement>(case_csl, block_case));
body.push_back(create<ast::CaseStatement>(Source{}, case_csl, block_case));
auto* block = create<ast::BlockStatement>( auto* block = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var),
create<ast::VariableDeclStatement>(Source{}, var), create<ast::SwitchStatement>(cond, body),
create<ast::SwitchStatement>(Source{}, cond, body), });
});
EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
EXPECT_TRUE(v()->ValidateStatements(block)) << v()->error(); EXPECT_TRUE(v()->ValidateStatements(block)) << v()->error();
} }
@ -467,35 +351,23 @@ TEST_F(ValidateControlBlockTest, SwitchCaseAlias_Pass) {
// default: {} // default: {}
// } // }
ast::type::U32 u32; ast::type::Alias my_int{mod->RegisterSymbol("MyInt"), "MyInt", ty.u32};
ast::type::Alias my_int{mod()->RegisterSymbol("MyInt"), "MyInt", &u32};
auto* var = create<ast::Variable>( auto* var = Var("a", ast::StorageClass::kNone, &my_int, Expr(2u),
Source{}, // source ast::VariableDecorationList{});
"a", // name
ast::StorageClass::kNone, // storage_class
&my_int, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &u32, 2)), // constructor
ast::VariableDecorationList{}); // decorations
auto* cond = create<ast::IdentifierExpression>( auto* cond = Expr("a");
Source{}, mod()->RegisterSymbol("a"), "a");
ast::CaseSelectorList default_csl; ast::CaseSelectorList default_csl;
auto* block_default = auto* block_default = create<ast::BlockStatement>(ast::StatementList{});
create<ast::BlockStatement>(Source{}, ast::StatementList{});
ast::CaseStatementList body; ast::CaseStatementList body;
body.push_back(create<ast::CaseStatement>(Source{Source::Location{12, 34}}, body.push_back(create<ast::CaseStatement>(Source{Source::Location{12, 34}},
default_csl, block_default)); default_csl, block_default));
auto* block = create<ast::BlockStatement>( auto* block = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var),
create<ast::VariableDeclStatement>(Source{}, var), create<ast::SwitchStatement>(cond, body),
create<ast::SwitchStatement>(Source{}, cond, body), });
}); mod->AddConstructedType(&my_int);
mod()->AddConstructedType(&my_int);
EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
EXPECT_TRUE(v()->ValidateStatements(block)) << v()->error(); EXPECT_TRUE(v()->ValidateStatements(block)) << v()->error();

View File

@ -38,100 +38,74 @@ class ValidateFunctionTest : public ValidatorTestHelper,
TEST_F(ValidateFunctionTest, VoidFunctionEndWithoutReturnStatement_Pass) { TEST_F(ValidateFunctionTest, VoidFunctionEndWithoutReturnStatement_Pass) {
// [[stage(vertex)]] // [[stage(vertex)]]
// fn func -> void { var a:i32 = 2; } // fn func -> void { var a:i32 = 2; }
ast::type::I32 i32; auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
auto* var = create<ast::Variable>( ast::VariableDecorationList{});
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &i32, 2)), // constructor
ast::VariableDecorationList{}); // decorations
ast::VariableList params; ast::VariableList params;
ast::type::Void void_type; auto* body = create<ast::BlockStatement>(ast::StatementList{
auto* body = create<ast::BlockStatement>( create<ast::VariableDeclStatement>(var),
Source{}, ast::StatementList{ });
create<ast::VariableDeclStatement>(Source{}, var),
});
auto* func = create<ast::Function>( auto* func = create<ast::Function>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func", Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
params, &void_type, body, params, ty.void_, body,
ast::FunctionDecorationList{ ast::FunctionDecorationList{
create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex), create<ast::StageDecoration>(ast::PipelineStage::kVertex),
}); });
mod()->AddFunction(func); mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_TRUE(v()->Validate(mod())); EXPECT_TRUE(v()->Validate(mod));
} }
TEST_F(ValidateFunctionTest, TEST_F(ValidateFunctionTest,
VoidFunctionEndWithoutReturnStatementEmptyBody_Pass) { VoidFunctionEndWithoutReturnStatementEmptyBody_Pass) {
// [[stage(vertex)]] // [[stage(vertex)]]
// fn func -> void {} // fn func -> void {}
ast::type::Void void_type;
ast::VariableList params; ast::VariableList params;
auto* func = create<ast::Function>( auto* func = create<ast::Function>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func", Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
params, &void_type, params, ty.void_, create<ast::BlockStatement>(ast::StatementList{}),
create<ast::BlockStatement>(Source{}, ast::StatementList{}),
ast::FunctionDecorationList{ ast::FunctionDecorationList{
create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex), create<ast::StageDecoration>(ast::PipelineStage::kVertex),
}); });
mod()->AddFunction(func); mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_TRUE(v()->Validate(mod())); EXPECT_TRUE(v()->Validate(mod));
} }
TEST_F(ValidateFunctionTest, FunctionEndWithoutReturnStatement_Fail) { TEST_F(ValidateFunctionTest, FunctionEndWithoutReturnStatement_Fail) {
// fn func -> int { var a:i32 = 2; } // fn func -> int { var a:i32 = 2; }
ast::type::I32 i32; auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
auto* var = create<ast::Variable>( ast::VariableDecorationList{});
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &i32, 2)), // constructor
ast::VariableDecorationList{}); // decorations
ast::VariableList params; ast::VariableList params;
ast::type::Void void_type; auto* body = create<ast::BlockStatement>(ast::StatementList{
auto* body = create<ast::BlockStatement>( create<ast::VariableDeclStatement>(var),
Source{}, ast::StatementList{ });
create<ast::VariableDeclStatement>(Source{}, var),
});
auto* func = create<ast::Function>( auto* func = create<ast::Function>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func", Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
params, &i32, body, ast::FunctionDecorationList{}); params, ty.i32, body, ast::FunctionDecorationList{});
mod()->AddFunction(func); mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod())); EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
"12:34 v-0002: non-void function must end with a return statement"); "12:34 v-0002: non-void function must end with a return statement");
} }
TEST_F(ValidateFunctionTest, FunctionEndWithoutReturnStatementEmptyBody_Fail) { TEST_F(ValidateFunctionTest, FunctionEndWithoutReturnStatementEmptyBody_Fail) {
// fn func -> int {} // fn func -> int {}
ast::type::Void void_type;
ast::type::I32 i32;
ast::VariableList params; ast::VariableList params;
auto* func = create<ast::Function>( auto* func = create<ast::Function>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func", Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
params, &i32, create<ast::BlockStatement>(Source{}, ast::StatementList{}), params, ty.i32, create<ast::BlockStatement>(ast::StatementList{}),
ast::FunctionDecorationList{}); ast::FunctionDecorationList{});
mod()->AddFunction(func); mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod())); EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
"12:34 v-0002: non-void function must end with a return statement"); "12:34 v-0002: non-void function must end with a return statement");
} }
@ -139,45 +113,39 @@ TEST_F(ValidateFunctionTest, FunctionEndWithoutReturnStatementEmptyBody_Fail) {
TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementType_Pass) { TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementType_Pass) {
// [[stage(vertex)]] // [[stage(vertex)]]
// fn func -> void { return; } // fn func -> void { return; }
ast::type::Void void_type;
ast::VariableList params; ast::VariableList params;
auto* body = create<ast::BlockStatement>( auto* body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::ReturnStatement>(),
create<ast::ReturnStatement>(Source{}), });
});
auto* func = create<ast::Function>( auto* func = create<ast::Function>(
Source{}, mod()->RegisterSymbol("func"), "func", params, &void_type, body, mod->RegisterSymbol("func"), "func", params, ty.void_, body,
ast::FunctionDecorationList{ ast::FunctionDecorationList{
create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex), create<ast::StageDecoration>(ast::PipelineStage::kVertex),
}); });
mod()->AddFunction(func); mod->AddFunction(func);
EXPECT_TRUE(td()->DetermineFunctions(mod()->functions())) << td()->error(); EXPECT_TRUE(td()->DetermineFunctions(mod->functions())) << td()->error();
EXPECT_TRUE(v()->ValidateFunctions(mod()->functions())) << v()->error(); EXPECT_TRUE(v()->ValidateFunctions(mod->functions())) << v()->error();
} }
TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementType_fail) { TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementType_fail) {
// fn func -> void { return 2; } // fn func -> void { return 2; }
ast::type::Void void_type;
ast::type::I32 i32;
ast::VariableList params; ast::VariableList params;
auto* return_expr = create<ast::ScalarConstructorExpression>( auto* return_expr = Expr(2);
Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
auto* body = create<ast::BlockStatement>( auto* body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::ReturnStatement>(Source{Source::Location{12, 34}},
create<ast::ReturnStatement>( return_expr),
Source{Source::Location{12, 34}}, return_expr), });
});
auto* func = create<ast::Function>(Source{}, mod()->RegisterSymbol("func"), auto* func =
"func", params, &void_type, body, create<ast::Function>(mod->RegisterSymbol("func"), "func", params,
ast::FunctionDecorationList{}); ty.void_, body, ast::FunctionDecorationList{});
mod()->AddFunction(func); mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod())); EXPECT_FALSE(v()->Validate(mod));
// TODO(sarahM0): replace 000y with a rule number // TODO(sarahM0): replace 000y with a rule number
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
"12:34 v-000y: return statement type must match its function " "12:34 v-000y: return statement type must match its function "
@ -186,25 +154,21 @@ TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementType_fail) {
TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementTypeF32_fail) { TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementTypeF32_fail) {
// fn func -> f32 { return 2; } // fn func -> f32 { return 2; }
ast::type::I32 i32;
ast::type::F32 f32;
ast::VariableList params; ast::VariableList params;
auto* return_expr = create<ast::ScalarConstructorExpression>( auto* return_expr = Expr(2);
Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
auto* body = create<ast::BlockStatement>( auto* body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::ReturnStatement>(Source{Source::Location{12, 34}},
create<ast::ReturnStatement>( return_expr),
Source{Source::Location{12, 34}}, return_expr), });
});
auto* func = auto* func =
create<ast::Function>(Source{}, mod()->RegisterSymbol("func"), "func", create<ast::Function>(mod->RegisterSymbol("func"), "func", params, ty.f32,
params, &f32, body, ast::FunctionDecorationList{}); body, ast::FunctionDecorationList{});
mod()->AddFunction(func); mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod())); EXPECT_FALSE(v()->Validate(mod));
// TODO(sarahM0): replace 000y with a rule number // TODO(sarahM0): replace 000y with a rule number
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
"12:34 v-000y: return statement type must match its function " "12:34 v-000y: return statement type must match its function "
@ -214,127 +178,100 @@ TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementTypeF32_fail) {
TEST_F(ValidateFunctionTest, FunctionNamesMustBeUnique_fail) { TEST_F(ValidateFunctionTest, FunctionNamesMustBeUnique_fail) {
// fn func -> i32 { return 2; } // fn func -> i32 { return 2; }
// fn func -> i32 { return 2; } // fn func -> i32 { return 2; }
ast::type::Void void_type;
ast::type::I32 i32;
ast::VariableList params; ast::VariableList params;
auto* return_expr = create<ast::ScalarConstructorExpression>( auto* return_expr = Expr(2);
Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
auto* body = create<ast::BlockStatement>( auto* body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::ReturnStatement>(return_expr),
create<ast::ReturnStatement>(Source{}, return_expr), });
});
auto* func = auto* func =
create<ast::Function>(Source{}, mod()->RegisterSymbol("func"), "func", create<ast::Function>(mod->RegisterSymbol("func"), "func", params, ty.i32,
params, &i32, body, ast::FunctionDecorationList{}); body, ast::FunctionDecorationList{});
ast::VariableList params_copy; ast::VariableList params_copy;
auto* return_expr_copy = create<ast::ScalarConstructorExpression>( auto* return_expr_copy = Expr(2);
Source{}, create<ast::SintLiteral>(Source{}, &i32, 2)); auto* body_copy = create<ast::BlockStatement>(ast::StatementList{
auto* body_copy = create<ast::BlockStatement>( create<ast::ReturnStatement>(return_expr_copy),
Source{}, ast::StatementList{ });
create<ast::ReturnStatement>(Source{}, return_expr_copy),
});
auto* func_copy = create<ast::Function>( auto* func_copy = create<ast::Function>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func", Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
params_copy, &i32, body_copy, ast::FunctionDecorationList{}); params_copy, ty.i32, body_copy, ast::FunctionDecorationList{});
mod()->AddFunction(func); mod->AddFunction(func);
mod()->AddFunction(func_copy); mod->AddFunction(func_copy);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod())); EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ(v()->error(), "12:34 v-0016: function names must be unique 'func'"); EXPECT_EQ(v()->error(), "12:34 v-0016: function names must be unique 'func'");
} }
TEST_F(ValidateFunctionTest, RecursionIsNotAllowed_Fail) { TEST_F(ValidateFunctionTest, RecursionIsNotAllowed_Fail) {
// fn func() -> void {func(); return; } // fn func() -> void {func(); return; }
ast::type::F32 f32;
ast::type::Void void_type;
ast::ExpressionList call_params; ast::ExpressionList call_params;
auto* call_expr = create<ast::CallExpression>( auto* call_expr = create<ast::CallExpression>(
Source{Source::Location{12, 34}}, Source{Source::Location{12, 34}}, Expr("func"), call_params);
create<ast::IdentifierExpression>(Source{}, mod()->RegisterSymbol("func"),
"func"),
call_params);
ast::VariableList params0; ast::VariableList params0;
auto* body0 = create<ast::BlockStatement>( auto* body0 = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::CallStatement>(call_expr),
create<ast::CallStatement>(Source{}, call_expr), create<ast::ReturnStatement>(),
create<ast::ReturnStatement>(Source{}), });
}); auto* func0 =
auto* func0 = create<ast::Function>(Source{}, mod()->RegisterSymbol("func"), create<ast::Function>(mod->RegisterSymbol("func"), "func", params0,
"func", params0, &f32, body0, ty.f32, body0, ast::FunctionDecorationList{});
ast::FunctionDecorationList{}); mod->AddFunction(func0);
mod()->AddFunction(func0);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod())) << v()->error(); EXPECT_FALSE(v()->Validate(mod)) << v()->error();
EXPECT_EQ(v()->error(), "12:34 v-0004: recursion is not allowed: 'func'"); EXPECT_EQ(v()->error(), "12:34 v-0004: recursion is not allowed: 'func'");
} }
TEST_F(ValidateFunctionTest, RecursionIsNotAllowedExpr_Fail) { TEST_F(ValidateFunctionTest, RecursionIsNotAllowedExpr_Fail) {
// fn func() -> i32 {var a: i32 = func(); return 2; } // fn func() -> i32 {var a: i32 = func(); return 2; }
ast::type::I32 i32;
ast::ExpressionList call_params; ast::ExpressionList call_params;
auto* call_expr = create<ast::CallExpression>( auto* call_expr = create<ast::CallExpression>(
Source{Source::Location{12, 34}}, Source{Source::Location{12, 34}}, Expr("func"), call_params);
create<ast::IdentifierExpression>(Source{}, mod()->RegisterSymbol("func"), auto* var = Var("a", ast::StorageClass::kNone, ty.i32, call_expr,
"func"), ast::VariableDecorationList{});
call_params);
auto* var =
create<ast::Variable>(Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
false, // is_const
call_expr, // constructor
ast::VariableDecorationList{}); // decorations
ast::VariableList params0; ast::VariableList params0;
auto* return_expr = create<ast::ScalarConstructorExpression>( auto* return_expr = Expr(2);
Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
auto* body0 = create<ast::BlockStatement>( auto* body0 = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var),
create<ast::VariableDeclStatement>(Source{}, var), create<ast::ReturnStatement>(return_expr),
create<ast::ReturnStatement>(Source{}, return_expr), });
});
auto* func0 = create<ast::Function>(Source{}, mod()->RegisterSymbol("func"), auto* func0 =
"func", params0, &i32, body0, create<ast::Function>(mod->RegisterSymbol("func"), "func", params0,
ast::FunctionDecorationList{}); ty.i32, body0, ast::FunctionDecorationList{});
mod()->AddFunction(func0); mod->AddFunction(func0);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod())) << v()->error(); EXPECT_FALSE(v()->Validate(mod)) << v()->error();
EXPECT_EQ(v()->error(), "12:34 v-0004: recursion is not allowed: 'func'"); EXPECT_EQ(v()->error(), "12:34 v-0004: recursion is not allowed: 'func'");
} }
TEST_F(ValidateFunctionTest, Function_WithPipelineStage_NotVoid_Fail) { TEST_F(ValidateFunctionTest, Function_WithPipelineStage_NotVoid_Fail) {
// [[stage(vertex)]] // [[stage(vertex)]]
// fn vtx_main() -> i32 { return 0; } // fn vtx_main() -> i32 { return 0; }
ast::type::I32 i32;
ast::VariableList params; ast::VariableList params;
auto* return_expr = create<ast::ScalarConstructorExpression>( auto* return_expr = Expr(0);
Source{}, create<ast::SintLiteral>(Source{}, &i32, 0));
auto* body = create<ast::BlockStatement>( auto* body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::ReturnStatement>(return_expr),
create<ast::ReturnStatement>(Source{}, return_expr), });
});
auto* func = create<ast::Function>( auto* func = create<ast::Function>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("vtx_main"), Source{Source::Location{12, 34}}, mod->RegisterSymbol("vtx_main"),
"vtx_main", params, &i32, body, "vtx_main", params, ty.i32, body,
ast::FunctionDecorationList{ ast::FunctionDecorationList{
create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex), create<ast::StageDecoration>(ast::PipelineStage::kVertex),
}); });
mod()->AddFunction(func); mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod())); EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
"12:34 v-0024: Entry point function must return void: 'vtx_main'"); "12:34 v-0024: Entry point function must return void: 'vtx_main'");
} }
@ -342,31 +279,22 @@ TEST_F(ValidateFunctionTest, Function_WithPipelineStage_NotVoid_Fail) {
TEST_F(ValidateFunctionTest, Function_WithPipelineStage_WithParams_Fail) { TEST_F(ValidateFunctionTest, Function_WithPipelineStage_WithParams_Fail) {
// [[stage(vertex)]] // [[stage(vertex)]]
// fn vtx_func(a : i32) -> void { return; } // fn vtx_func(a : i32) -> void { return; }
ast::type::I32 i32;
ast::type::Void void_type;
ast::VariableList params; ast::VariableList params;
params.push_back( params.push_back(Var("a", ast::StorageClass::kNone, ty.i32, nullptr,
create<ast::Variable>(Source{}, // source ast::VariableDecorationList{}));
"a", // name auto* body = create<ast::BlockStatement>(ast::StatementList{
ast::StorageClass::kNone, // storage_class create<ast::ReturnStatement>(),
&i32, // type });
false, // is_const
nullptr, // constructor
ast::VariableDecorationList{})); // decorations
auto* body = create<ast::BlockStatement>(
Source{}, ast::StatementList{
create<ast::ReturnStatement>(Source{}),
});
auto* func = create<ast::Function>( auto* func = create<ast::Function>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("vtx_func"), Source{Source::Location{12, 34}}, mod->RegisterSymbol("vtx_func"),
"vtx_func", params, &void_type, body, "vtx_func", params, ty.void_, body,
ast::FunctionDecorationList{ ast::FunctionDecorationList{
create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex), create<ast::StageDecoration>(ast::PipelineStage::kVertex),
}); });
mod()->AddFunction(func); mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod())); EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
"12:34 v-0023: Entry point function must accept no parameters: " "12:34 v-0023: Entry point function must accept no parameters: "
"'vtx_func'"); "'vtx_func'");
@ -376,23 +304,21 @@ TEST_F(ValidateFunctionTest, PipelineStage_MustBeUnique_Fail) {
// [[stage(fragment)]] // [[stage(fragment)]]
// [[stage(vertex)]] // [[stage(vertex)]]
// fn main() -> void { return; } // fn main() -> void { return; }
ast::type::Void void_type;
ast::VariableList params; ast::VariableList params;
auto* body = create<ast::BlockStatement>( auto* body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::ReturnStatement>(),
create<ast::ReturnStatement>(Source{}), });
});
auto* func = create<ast::Function>( auto* func = create<ast::Function>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("main"), "main", Source{Source::Location{12, 34}}, mod->RegisterSymbol("main"), "main",
params, &void_type, body, params, ty.void_, body,
ast::FunctionDecorationList{ ast::FunctionDecorationList{
create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex), create<ast::StageDecoration>(ast::PipelineStage::kVertex),
create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment), create<ast::StageDecoration>(ast::PipelineStage::kFragment),
}); });
mod()->AddFunction(func); mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod())); EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ( EXPECT_EQ(
v()->error(), v()->error(),
"12:34 v-0020: only one stage decoration permitted per entry point"); "12:34 v-0020: only one stage decoration permitted per entry point");
@ -401,39 +327,34 @@ TEST_F(ValidateFunctionTest, PipelineStage_MustBeUnique_Fail) {
TEST_F(ValidateFunctionTest, OnePipelineStageFunctionMustBePresent_Pass) { TEST_F(ValidateFunctionTest, OnePipelineStageFunctionMustBePresent_Pass) {
// [[stage(vertex)]] // [[stage(vertex)]]
// fn vtx_func() -> void { return; } // fn vtx_func() -> void { return; }
ast::type::Void void_type;
ast::VariableList params; ast::VariableList params;
auto* body = create<ast::BlockStatement>( auto* body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::ReturnStatement>(),
create<ast::ReturnStatement>(Source{}), });
});
auto* func = create<ast::Function>( auto* func = create<ast::Function>(
Source{}, mod()->RegisterSymbol("vtx_func"), "vtx_func", params, mod->RegisterSymbol("vtx_func"), "vtx_func", params, ty.void_, body,
&void_type, body,
ast::FunctionDecorationList{ ast::FunctionDecorationList{
create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex), create<ast::StageDecoration>(ast::PipelineStage::kVertex),
}); });
mod()->AddFunction(func); mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_TRUE(v()->Validate(mod())) << v()->error(); EXPECT_TRUE(v()->Validate(mod)) << v()->error();
} }
TEST_F(ValidateFunctionTest, OnePipelineStageFunctionMustBePresent_Fail) { TEST_F(ValidateFunctionTest, OnePipelineStageFunctionMustBePresent_Fail) {
// fn vtx_func() -> void { return; } // fn vtx_func() -> void { return; }
ast::type::Void void_type;
ast::VariableList params; ast::VariableList params;
auto* body = create<ast::BlockStatement>( auto* body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::ReturnStatement>(),
create<ast::ReturnStatement>(Source{}), });
}); auto* func =
auto* func = create<ast::Function>( create<ast::Function>(mod->RegisterSymbol("vtx_func"), "vtx_func", params,
Source{}, mod()->RegisterSymbol("vtx_func"), "vtx_func", params, ty.void_, body, ast::FunctionDecorationList{});
&void_type, body, ast::FunctionDecorationList{}); mod->AddFunction(func);
mod()->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod())); EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
"v-0003: At least one of vertex, fragment or compute shader must " "v-0003: At least one of vertex, fragment or compute shader must "
"be present"); "be present");

View File

@ -62,13 +62,11 @@ class ValidatorTest : public ValidatorTestHelper, public testing::Test {};
TEST_F(ValidatorTest, DISABLED_AssignToScalar_Fail) { TEST_F(ValidatorTest, DISABLED_AssignToScalar_Fail) {
// 1 = my_var; // 1 = my_var;
ast::type::I32 i32;
auto* lhs = create<ast::ScalarConstructorExpression>( auto* lhs = Expr(1);
Source{}, create<ast::SintLiteral>(Source{}, &i32, 1)); auto* rhs = Expr("my_var");
auto* rhs = create<ast::IdentifierExpression>( SetSource(Source{Source::Location{12, 34}});
Source{}, mod()->RegisterSymbol("my_var"), "my_var"); create<ast::AssignmentStatement>(lhs, rhs);
ast::AssignmentStatement assign(Source{Source::Location{12, 34}}, lhs, rhs);
// TODO(sarahM0): Invalidate assignment to scalar. // TODO(sarahM0): Invalidate assignment to scalar.
ASSERT_TRUE(v()->has_error()); ASSERT_TRUE(v()->has_error());
@ -78,14 +76,11 @@ TEST_F(ValidatorTest, DISABLED_AssignToScalar_Fail) {
TEST_F(ValidatorTest, UsingUndefinedVariable_Fail) { TEST_F(ValidatorTest, UsingUndefinedVariable_Fail) {
// b = 2; // b = 2;
ast::type::I32 i32;
auto* lhs = create<ast::IdentifierExpression>( SetSource(Source{Source::Location{12, 34}});
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("b"), "b"); auto* lhs = Expr("b");
auto* rhs = create<ast::ScalarConstructorExpression>( auto* rhs = Expr(2);
Source{}, create<ast::SintLiteral>(Source{}, &i32, 2)); auto* assign = create<ast::AssignmentStatement>(lhs, rhs);
auto* assign = create<ast::AssignmentStatement>(
Source{Source::Location{12, 34}}, lhs, rhs);
EXPECT_FALSE(td()->DetermineResultType(assign)); EXPECT_FALSE(td()->DetermineResultType(assign));
EXPECT_EQ(td()->error(), EXPECT_EQ(td()->error(),
@ -96,18 +91,14 @@ TEST_F(ValidatorTest, UsingUndefinedVariableInBlockStatement_Fail) {
// { // {
// b = 2; // b = 2;
// } // }
ast::type::I32 i32;
auto* lhs = create<ast::IdentifierExpression>( SetSource(Source{Source::Location{12, 34}});
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("b"), "b"); auto* lhs = Expr("b");
auto* rhs = create<ast::ScalarConstructorExpression>( auto* rhs = Expr(2);
Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
auto* body = create<ast::BlockStatement>( auto* body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::AssignmentStatement>(lhs, rhs),
create<ast::AssignmentStatement>( });
Source{Source::Location{12, 34}}, lhs, rhs),
});
EXPECT_FALSE(td()->DetermineStatements(body)); EXPECT_FALSE(td()->DetermineStatements(body));
EXPECT_EQ(td()->error(), EXPECT_EQ(td()->error(),
@ -117,29 +108,19 @@ TEST_F(ValidatorTest, UsingUndefinedVariableInBlockStatement_Fail) {
TEST_F(ValidatorTest, AssignCompatibleTypes_Pass) { TEST_F(ValidatorTest, AssignCompatibleTypes_Pass) {
// var a :i32 = 2; // var a :i32 = 2;
// a = 2 // a = 2
ast::type::I32 i32; auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
auto* var = create<ast::Variable>( ast::VariableDecorationList{});
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &i32, 2)), // constructor
ast::VariableDecorationList{}); // decorations
auto* lhs = create<ast::IdentifierExpression>( auto* lhs = Expr("a");
Source{}, mod()->RegisterSymbol("a"), "a"); auto* rhs = Expr(2);
auto* rhs = create<ast::ScalarConstructorExpression>(
Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
ast::AssignmentStatement assign(Source{Source::Location{12, 34}}, lhs, rhs); auto* assign = create<ast::AssignmentStatement>(
Source{Source::Location{12, 34}}, lhs, rhs);
td()->RegisterVariableForTesting(var); td()->RegisterVariableForTesting(var);
EXPECT_TRUE(td()->DetermineResultType(&assign)) << td()->error(); EXPECT_TRUE(td()->DetermineResultType(assign)) << td()->error();
ASSERT_NE(lhs->result_type(), nullptr); ASSERT_NE(lhs->result_type(), nullptr);
ASSERT_NE(rhs->result_type(), nullptr); ASSERT_NE(rhs->result_type(), nullptr);
EXPECT_TRUE(v()->ValidateResultTypes(&assign)); EXPECT_TRUE(v()->ValidateResultTypes(assign));
} }
TEST_F(ValidatorTest, AssignIncompatibleTypes_Fail) { TEST_F(ValidatorTest, AssignIncompatibleTypes_Fail) {
@ -147,32 +128,21 @@ TEST_F(ValidatorTest, AssignIncompatibleTypes_Fail) {
// var a :i32 = 2; // var a :i32 = 2;
// a = 2.3; // a = 2.3;
// } // }
ast::type::F32 f32;
ast::type::I32 i32;
auto* var = create<ast::Variable>( auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
Source{}, // source ast::VariableDecorationList{});
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &i32, 2)), // constructor
ast::VariableDecorationList{}); // decorations
auto* lhs = create<ast::IdentifierExpression>( auto* lhs = Expr("a");
Source{}, mod()->RegisterSymbol("a"), "a"); auto* rhs = Expr(2.3f);
auto* rhs = create<ast::ScalarConstructorExpression>(
Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.3f));
ast::AssignmentStatement assign(Source{Source::Location{12, 34}}, lhs, rhs); auto* assign = create<ast::AssignmentStatement>(
Source{Source::Location{12, 34}}, lhs, rhs);
td()->RegisterVariableForTesting(var); td()->RegisterVariableForTesting(var);
EXPECT_TRUE(td()->DetermineResultType(&assign)) << td()->error(); EXPECT_TRUE(td()->DetermineResultType(assign)) << td()->error();
ASSERT_NE(lhs->result_type(), nullptr); ASSERT_NE(lhs->result_type(), nullptr);
ASSERT_NE(rhs->result_type(), nullptr); ASSERT_NE(rhs->result_type(), nullptr);
EXPECT_FALSE(v()->ValidateResultTypes(&assign)); EXPECT_FALSE(v()->ValidateResultTypes(assign));
ASSERT_TRUE(v()->has_error()); ASSERT_TRUE(v()->has_error());
// TODO(sarahM0): figure out what should be the error number. // TODO(sarahM0): figure out what should be the error number.
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
@ -184,29 +154,17 @@ TEST_F(ValidatorTest, AssignCompatibleTypesInBlockStatement_Pass) {
// var a :i32 = 2; // var a :i32 = 2;
// a = 2 // a = 2
// } // }
ast::type::I32 i32; auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
auto* var = create<ast::Variable>( ast::VariableDecorationList{});
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &i32, 2)), // constructor
ast::VariableDecorationList{}); // decorations
auto* lhs = create<ast::IdentifierExpression>( auto* lhs = Expr("a");
Source{}, mod()->RegisterSymbol("a"), "a"); auto* rhs = Expr(2);
auto* rhs = create<ast::ScalarConstructorExpression>(
Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
auto* body = create<ast::BlockStatement>( auto* body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var),
create<ast::VariableDeclStatement>(Source{}, var), create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
create<ast::AssignmentStatement>( rhs),
Source{Source::Location{12, 34}}, lhs, rhs), });
});
EXPECT_TRUE(td()->DetermineStatements(body)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(body)) << td()->error();
ASSERT_NE(lhs->result_type(), nullptr); ASSERT_NE(lhs->result_type(), nullptr);
@ -220,36 +178,24 @@ TEST_F(ValidatorTest, AssignIncompatibleTypesInBlockStatement_Fail) {
// var a :i32 = 2; // var a :i32 = 2;
// a = 2.3; // a = 2.3;
// } // }
ast::type::F32 f32;
ast::type::I32 i32;
auto* var = create<ast::Variable>( auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
Source{}, // source ast::VariableDecorationList{});
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &i32, 2)), // constructor
ast::VariableDecorationList{}); // decorations
auto* lhs = create<ast::IdentifierExpression>(
Source{}, mod()->RegisterSymbol("a"), "a");
auto* rhs = create<ast::ScalarConstructorExpression>(
Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.3f));
ast::BlockStatement block( auto* lhs = Expr("a");
Source{}, ast::StatementList{ auto* rhs = Expr(2.3f);
create<ast::VariableDeclStatement>(Source{}, var),
create<ast::AssignmentStatement>(
Source{Source::Location{12, 34}}, lhs, rhs),
});
EXPECT_TRUE(td()->DetermineStatements(&block)) << td()->error(); auto* block = create<ast::BlockStatement>(ast::StatementList{
create<ast::VariableDeclStatement>(var),
create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
rhs),
});
EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
ASSERT_NE(lhs->result_type(), nullptr); ASSERT_NE(lhs->result_type(), nullptr);
ASSERT_NE(rhs->result_type(), nullptr); ASSERT_NE(rhs->result_type(), nullptr);
EXPECT_FALSE(v()->ValidateStatements(&block)); EXPECT_FALSE(v()->ValidateStatements(block));
ASSERT_TRUE(v()->has_error()); ASSERT_TRUE(v()->has_error());
// TODO(sarahM0): figure out what should be the error number. // TODO(sarahM0): figure out what should be the error number.
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
@ -258,49 +204,31 @@ TEST_F(ValidatorTest, AssignIncompatibleTypesInBlockStatement_Fail) {
TEST_F(ValidatorTest, GlobalVariableWithStorageClass_Pass) { TEST_F(ValidatorTest, GlobalVariableWithStorageClass_Pass) {
// var<in> gloabl_var: f32; // var<in> gloabl_var: f32;
ast::type::F32 f32; mod->AddGlobalVariable(Var(Source{Source::Location{12, 34}}, "global_var",
mod()->AddGlobalVariable( ast::StorageClass::kInput, ty.f32, nullptr,
create<ast::Variable>(Source{Source::Location{12, 34}}, // source ast::VariableDecorationList{}));
"global_var", // name EXPECT_TRUE(v()->ValidateGlobalVariables(mod->global_variables()))
ast::StorageClass::kInput, // storage_class
&f32, // type
false, // is_const
nullptr, // constructor
ast::VariableDecorationList{})); // decorations
EXPECT_TRUE(v()->ValidateGlobalVariables(mod()->global_variables()))
<< v()->error(); << v()->error();
} }
TEST_F(ValidatorTest, GlobalVariableNoStorageClass_Fail) { TEST_F(ValidatorTest, GlobalVariableNoStorageClass_Fail) {
// var gloabl_var: f32; // var gloabl_var: f32;
ast::type::F32 f32; mod->AddGlobalVariable(Var(Source{Source::Location{12, 34}}, "global_var",
mod()->AddGlobalVariable( ast::StorageClass::kNone, ty.f32, nullptr,
create<ast::Variable>(Source{Source::Location{12, 34}}, // source ast::VariableDecorationList{}));
"global_var", // name
ast::StorageClass::kNone, // storage_class
&f32, // type
false, // is_const
nullptr, // constructor
ast::VariableDecorationList{})); // decorations
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod())); EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
"12:34 v-0022: global variables must have a storage class"); "12:34 v-0022: global variables must have a storage class");
} }
TEST_F(ValidatorTest, GlobalConstantWithStorageClass_Fail) { TEST_F(ValidatorTest, GlobalConstantWithStorageClass_Fail) {
// const<in> gloabl_var: f32; // const<in> gloabl_var: f32;
ast::type::F32 f32; mod->AddGlobalVariable(Const(Source{Source::Location{12, 34}}, "global_var",
mod()->AddGlobalVariable( ast::StorageClass::kInput, ty.f32, nullptr,
create<ast::Variable>(Source{Source::Location{12, 34}}, // source ast::VariableDecorationList{}));
"global_var", // name
ast::StorageClass::kInput, // storage_class
&f32, // type
true, // is_const
nullptr, // constructor
ast::VariableDecorationList{})); // decorations
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod())); EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ( EXPECT_EQ(
v()->error(), v()->error(),
"12:34 v-global01: global constants shouldn't have a storage class"); "12:34 v-global01: global constants shouldn't have a storage class");
@ -308,17 +236,11 @@ TEST_F(ValidatorTest, GlobalConstantWithStorageClass_Fail) {
TEST_F(ValidatorTest, GlobalConstNoStorageClass_Pass) { TEST_F(ValidatorTest, GlobalConstNoStorageClass_Pass) {
// const gloabl_var: f32; // const gloabl_var: f32;
ast::type::F32 f32; mod->AddGlobalVariable(Const(Source{Source::Location{12, 34}}, "global_var",
mod()->AddGlobalVariable( ast::StorageClass::kNone, ty.f32, nullptr,
create<ast::Variable>(Source{Source::Location{12, 34}}, // source ast::VariableDecorationList{}));
"global_var", // name
ast::StorageClass::kNone, // storage_class
&f32, // type
true, // is_const
nullptr, // constructor
ast::VariableDecorationList{})); // decorations
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod())) << v()->error(); EXPECT_FALSE(v()->Validate(mod)) << v()->error();
} }
TEST_F(ValidatorTest, UsingUndefinedVariableGlobalVariable_Fail) { TEST_F(ValidatorTest, UsingUndefinedVariableGlobalVariable_Fail) {
@ -326,37 +248,25 @@ TEST_F(ValidatorTest, UsingUndefinedVariableGlobalVariable_Fail) {
// fn my_func() -> f32 { // fn my_func() -> f32 {
// not_global_var = 3.14f; // not_global_var = 3.14f;
// } // }
ast::type::F32 f32; mod->AddGlobalVariable(Var("global_var", ast::StorageClass::kPrivate, ty.f32,
mod()->AddGlobalVariable(create<ast::Variable>( Expr(2.1f), ast::VariableDecorationList{}));
Source{}, // source
"global_var", // name
ast::StorageClass::kPrivate, // storage_class
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::FloatLiteral>(Source{}, &f32, 2.1)), // constructor
ast::VariableDecorationList{})); // decorations
auto* lhs = create<ast::IdentifierExpression>( SetSource(Source{Source::Location{12, 34}});
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("not_global_var"), auto* lhs = Expr("not_global_var");
"not_global_var"); auto* rhs = Expr(3.14f);
auto* rhs = create<ast::ScalarConstructorExpression>(
Source{}, create<ast::FloatLiteral>(Source{}, &f32, 3.14f));
ast::VariableList params; ast::VariableList params;
auto* body = create<ast::BlockStatement>( auto* body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
create<ast::AssignmentStatement>( rhs),
Source{Source::Location{12, 34}}, lhs, rhs), });
});
auto* func = create<ast::Function>(Source{}, mod()->RegisterSymbol("my_func"), auto* func =
"my_func", params, &f32, body, create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func", params,
ast::FunctionDecorationList{}); ty.f32, body, ast::FunctionDecorationList{});
mod()->AddFunction(func); mod->AddFunction(func);
EXPECT_FALSE(v()->Validate(mod())); EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ(v()->error(), "12:34 v-0006: 'not_global_var' is not declared"); EXPECT_EQ(v()->error(), "12:34 v-0006: 'not_global_var' is not declared");
} }
@ -366,44 +276,31 @@ TEST_F(ValidatorTest, UsingUndefinedVariableGlobalVariable_Pass) {
// global_var = 3.14; // global_var = 3.14;
// return; // return;
// } // }
ast::type::F32 f32;
ast::type::Void void_type;
mod()->AddGlobalVariable(create<ast::Variable>( mod->AddGlobalVariable(Var("global_var", ast::StorageClass::kPrivate, ty.f32,
Source{}, // source Expr(2.1f), ast::VariableDecorationList{}));
"global_var", // name
ast::StorageClass::kPrivate, // storage_class
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::FloatLiteral>(Source{}, &f32, 2.1)), // constructor
ast::VariableDecorationList{})); // decorations
auto* lhs = create<ast::IdentifierExpression>( auto* lhs = create<ast::IdentifierExpression>(
Source{}, mod()->RegisterSymbol("global_var"), "global_var"); mod->RegisterSymbol("global_var"), "global_var");
auto* rhs = create<ast::ScalarConstructorExpression>( auto* rhs = Expr(3.14f);
Source{}, create<ast::FloatLiteral>(Source{}, &f32, 3.14f));
ast::VariableList params; ast::VariableList params;
auto* body = create<ast::BlockStatement>( auto* body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
create<ast::AssignmentStatement>( rhs),
Source{Source::Location{12, 34}}, lhs, rhs), create<ast::ReturnStatement>(),
create<ast::ReturnStatement>(Source{}), });
});
auto* func = create<ast::Function>( auto* func = create<ast::Function>(
Source{}, mod()->RegisterSymbol("my_func"), "my_func", params, &void_type, mod->RegisterSymbol("my_func"), "my_func", params, ty.void_, body,
body,
ast::FunctionDecorationList{ ast::FunctionDecorationList{
create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex), create<ast::StageDecoration>(ast::PipelineStage::kVertex),
}); });
mod()->AddFunction(func); mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_TRUE(v()->Validate(mod())) << v()->error(); EXPECT_TRUE(v()->Validate(mod)) << v()->error();
} }
TEST_F(ValidatorTest, UsingUndefinedVariableInnerScope_Fail) { TEST_F(ValidatorTest, UsingUndefinedVariableInnerScope_Fail) {
@ -411,38 +308,24 @@ TEST_F(ValidatorTest, UsingUndefinedVariableInnerScope_Fail) {
// if (true) { var a : f32 = 2.0; } // if (true) { var a : f32 = 2.0; }
// a = 3.14; // a = 3.14;
// } // }
ast::type::F32 f32; auto* var = Var("a", ast::StorageClass::kNone, ty.f32, Expr(2.0f),
auto* var = create<ast::Variable>( ast::VariableDecorationList{});
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::FloatLiteral>(Source{}, &f32, 2.0)), // constructor
ast::VariableDecorationList{}); // decorations
ast::type::Bool bool_type; ast::type::Bool bool_type;
auto* cond = create<ast::ScalarConstructorExpression>( auto* cond = Expr(true);
Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true)); auto* body = create<ast::BlockStatement>(ast::StatementList{
auto* body = create<ast::BlockStatement>( create<ast::VariableDeclStatement>(var),
Source{}, ast::StatementList{ });
create<ast::VariableDeclStatement>(Source{}, var),
});
auto* lhs = create<ast::IdentifierExpression>( SetSource(Source{Source::Location{12, 34}});
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("a"), "a"); auto* lhs = Expr("a");
auto* rhs = create<ast::ScalarConstructorExpression>( auto* rhs = Expr(3.14f);
Source{}, create<ast::FloatLiteral>(Source{}, &f32, 3.14f));
auto* outer_body = create<ast::BlockStatement>( auto* outer_body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::IfStatement>(cond, body, ast::ElseStatementList{}),
create<ast::IfStatement>(Source{}, cond, body, create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
ast::ElseStatementList{}), rhs),
create<ast::AssignmentStatement>( });
Source{Source::Location{12, 34}}, lhs, rhs),
});
EXPECT_TRUE(td()->DetermineStatements(outer_body)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(outer_body)) << td()->error();
ASSERT_NE(lhs->result_type(), nullptr); ASSERT_NE(lhs->result_type(), nullptr);
@ -456,38 +339,24 @@ TEST_F(ValidatorTest, UsingUndefinedVariableOuterScope_Pass) {
// var a : f32 = 2.0; // var a : f32 = 2.0;
// if (true) { a = 3.14; } // if (true) { a = 3.14; }
// } // }
ast::type::F32 f32; auto* var = Var("a", ast::StorageClass::kNone, ty.f32, Expr(2.0f),
auto* var = create<ast::Variable>( ast::VariableDecorationList{});
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::FloatLiteral>(Source{}, &f32, 2.0)), // constructor
ast::VariableDecorationList{}); // decorations
auto* lhs = create<ast::IdentifierExpression>( SetSource(Source{Source::Location{12, 34}});
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("a"), "a"); auto* lhs = Expr("a");
auto* rhs = create<ast::ScalarConstructorExpression>( auto* rhs = Expr(3.14f);
Source{}, create<ast::FloatLiteral>(Source{}, &f32, 3.14f));
ast::type::Bool bool_type; ast::type::Bool bool_type;
auto* cond = create<ast::ScalarConstructorExpression>( auto* cond = Expr(true);
Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true)); auto* body = create<ast::BlockStatement>(ast::StatementList{
auto* body = create<ast::BlockStatement>( create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
Source{}, ast::StatementList{ rhs),
create<ast::AssignmentStatement>( });
Source{Source::Location{12, 34}}, lhs, rhs),
});
auto* outer_body = create<ast::BlockStatement>( auto* outer_body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var),
create<ast::VariableDeclStatement>(Source{}, var), create<ast::IfStatement>(cond, body, ast::ElseStatementList{}),
create<ast::IfStatement>(Source{}, cond, body, });
ast::ElseStatementList{}),
});
EXPECT_TRUE(td()->DetermineStatements(outer_body)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(outer_body)) << td()->error();
ASSERT_NE(lhs->result_type(), nullptr); ASSERT_NE(lhs->result_type(), nullptr);
@ -498,66 +367,32 @@ TEST_F(ValidatorTest, UsingUndefinedVariableOuterScope_Pass) {
TEST_F(ValidatorTest, GlobalVariableUnique_Pass) { TEST_F(ValidatorTest, GlobalVariableUnique_Pass) {
// var global_var0 : f32 = 0.1; // var global_var0 : f32 = 0.1;
// var global_var1 : i32 = 0; // var global_var1 : i32 = 0;
ast::type::F32 f32; auto* var0 = Var("global_var0", ast::StorageClass::kPrivate, ty.f32,
ast::type::I32 i32; Expr(0.1f), ast::VariableDecorationList{});
auto* var0 = create<ast::Variable>( mod->AddGlobalVariable(var0);
Source{}, // source
"global_var0", // name
ast::StorageClass::kPrivate, // storage_class
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::FloatLiteral>(Source{}, &f32, 0.1)), // constructor
ast::VariableDecorationList{}); // decorations
mod()->AddGlobalVariable(var0);
auto* var1 = create<ast::Variable>( auto* var1 = Var(Source{Source::Location{12, 34}}, "global_var1",
Source{Source::Location{12, 34}}, // source ast::StorageClass::kPrivate, ty.f32, Expr(0),
"global_var1", // name ast::VariableDecorationList{});
ast::StorageClass::kPrivate, // storage_class mod->AddGlobalVariable(var1);
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &i32, 0)), // constructor
ast::VariableDecorationList{}); // decorations
mod()->AddGlobalVariable(var1);
EXPECT_TRUE(v()->ValidateGlobalVariables(mod()->global_variables())) EXPECT_TRUE(v()->ValidateGlobalVariables(mod->global_variables()))
<< v()->error(); << v()->error();
} }
TEST_F(ValidatorTest, GlobalVariableNotUnique_Fail) { TEST_F(ValidatorTest, GlobalVariableNotUnique_Fail) {
// var global_var : f32 = 0.1; // var global_var : f32 = 0.1;
// var global_var : i32 = 0; // var global_var : i32 = 0;
ast::type::F32 f32; auto* var0 = Var("global_var", ast::StorageClass::kPrivate, ty.f32,
ast::type::I32 i32; Expr(0.1f), ast::VariableDecorationList{});
auto* var0 = create<ast::Variable>( mod->AddGlobalVariable(var0);
Source{}, // source
"global_var", // name
ast::StorageClass::kPrivate, // storage_class
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::FloatLiteral>(Source{}, &f32, 0.1)), // constructor
ast::VariableDecorationList{}); // decorations
mod()->AddGlobalVariable(var0);
auto* var1 = create<ast::Variable>( auto* var1 = Var(Source{Source::Location{12, 34}}, "global_var",
Source{Source::Location{12, 34}}, // source ast::StorageClass::kPrivate, ty.i32, Expr(0),
"global_var", // name ast::VariableDecorationList{});
ast::StorageClass::kPrivate, // storage_class mod->AddGlobalVariable(var1);
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &i32, 0)), // constructor
ast::VariableDecorationList{}); // decorations
mod()->AddGlobalVariable(var1);
EXPECT_FALSE(v()->ValidateGlobalVariables(mod()->global_variables())); EXPECT_FALSE(v()->ValidateGlobalVariables(mod->global_variables()));
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
"12:34 v-0011: redeclared global identifier 'global_var'"); "12:34 v-0011: redeclared global identifier 'global_var'");
} }
@ -567,29 +402,17 @@ TEST_F(ValidatorTest, AssignToConstant_Fail) {
// const a :i32 = 2; // const a :i32 = 2;
// a = 2 // a = 2
// } // }
ast::type::I32 i32; auto* var = Const("a", ast::StorageClass::kNone, ty.i32, Expr(2),
auto* var = create<ast::Variable>( ast::VariableDecorationList{});
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
true, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &i32, 2)), // constructor
ast::VariableDecorationList{}); // decorations
auto* lhs = create<ast::IdentifierExpression>( auto* lhs = Expr("a");
Source{}, mod()->RegisterSymbol("a"), "a"); auto* rhs = Expr(2);
auto* rhs = create<ast::ScalarConstructorExpression>(
Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
auto* body = create<ast::BlockStatement>( auto* body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var),
create<ast::VariableDeclStatement>(Source{}, var), create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
create<ast::AssignmentStatement>( rhs),
Source{Source::Location{12, 34}}, lhs, rhs), });
});
EXPECT_TRUE(td()->DetermineStatements(body)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(body)) << td()->error();
ASSERT_NE(lhs->result_type(), nullptr); ASSERT_NE(lhs->result_type(), nullptr);
@ -606,46 +429,26 @@ TEST_F(ValidatorTest, GlobalVariableFunctionVariableNotUnique_Fail) {
// return 0; // return 0;
// } // }
ast::type::Void void_type; auto* global_var = Var("a", ast::StorageClass::kPrivate, ty.f32, Expr(2.1f),
ast::type::F32 f32; ast::VariableDecorationList{});
auto* global_var = create<ast::Variable>( mod->AddGlobalVariable(global_var);
Source{}, // source
"a", // name
ast::StorageClass::kPrivate, // storage_class
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::FloatLiteral>(Source{}, &f32, 2.1)), // constructor
ast::VariableDecorationList{}); // decorations
mod()->AddGlobalVariable(global_var);
auto* var = create<ast::Variable>( auto* var = Var("a", ast::StorageClass::kNone, ty.f32, Expr(2.0f),
Source{}, // source ast::VariableDecorationList{});
"a", // name
ast::StorageClass::kNone, // storage_class
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::FloatLiteral>(Source{}, &f32, 2.0)), // constructor
ast::VariableDecorationList{}); // decorations
ast::VariableList params; ast::VariableList params;
auto* body = create<ast::BlockStatement>( auto* body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(Source{Source::Location{12, 34}}, var),
create<ast::VariableDeclStatement>( });
Source{Source::Location{12, 34}}, var),
});
auto* func = create<ast::Function>(Source{}, mod()->RegisterSymbol("my_func"), auto* func =
"my_func", params, &void_type, body, create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func", params,
ast::FunctionDecorationList{}); ty.void_, body, ast::FunctionDecorationList{});
mod()->AddFunction(func); mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_TRUE(td()->DetermineFunction(func)) << td()->error(); EXPECT_TRUE(td()->DetermineFunction(func)) << td()->error();
EXPECT_FALSE(v()->Validate(mod())) << v()->error(); EXPECT_FALSE(v()->Validate(mod)) << v()->error();
EXPECT_EQ(v()->error(), "12:34 v-0013: redeclared identifier 'a'"); EXPECT_EQ(v()->error(), "12:34 v-0013: redeclared identifier 'a'");
} }
@ -654,48 +457,28 @@ TEST_F(ValidatorTest, RedeclaredIndentifier_Fail) {
// var a :i32 = 2; // var a :i32 = 2;
// var a :f21 = 2.0; // var a :f21 = 2.0;
// } // }
ast::type::Void void_type; auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
ast::type::I32 i32; ast::VariableDecorationList{});
ast::type::F32 f32;
auto* var = create<ast::Variable>(
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::SintLiteral>(Source{}, &i32, 2)), // constructor
ast::VariableDecorationList{}); // decorations
auto* var_a_float = create<ast::Variable>( auto* var_a_float = Var("a", ast::StorageClass::kNone, ty.f32, Expr(0.1f),
Source{}, // source ast::VariableDecorationList{});
"a", // name
ast::StorageClass::kNone, // storage_class
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::FloatLiteral>(Source{}, &f32, 0.1)), // constructor
ast::VariableDecorationList{}); // decorations
ast::VariableList params; ast::VariableList params;
auto* body = create<ast::BlockStatement>( auto* body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var),
create<ast::VariableDeclStatement>(Source{}, var), create<ast::VariableDeclStatement>(Source{Source::Location{12, 34}},
create<ast::VariableDeclStatement>( var_a_float),
Source{Source::Location{12, 34}}, var_a_float), });
});
auto* func = create<ast::Function>(Source{}, mod()->RegisterSymbol("my_func"), auto* func =
"my_func", params, &void_type, body, create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func", params,
ast::FunctionDecorationList{}); ty.void_, body, ast::FunctionDecorationList{});
mod()->AddFunction(func); mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_TRUE(td()->DetermineFunction(func)) << td()->error(); EXPECT_TRUE(td()->DetermineFunction(func)) << td()->error();
EXPECT_FALSE(v()->Validate(mod())); EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ(v()->error(), "12:34 v-0014: redeclared identifier 'a'"); EXPECT_EQ(v()->error(), "12:34 v-0014: redeclared identifier 'a'");
} }
@ -704,44 +487,23 @@ TEST_F(ValidatorTest, RedeclaredIdentifierInnerScope_Pass) {
// if (true) { var a : f32 = 2.0; } // if (true) { var a : f32 = 2.0; }
// var a : f32 = 3.14; // var a : f32 = 3.14;
// } // }
ast::type::F32 f32; auto* var = Var("a", ast::StorageClass::kNone, ty.f32, Expr(2.0f),
auto* var = create<ast::Variable>( ast::VariableDecorationList{});
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::FloatLiteral>(Source{}, &f32, 2.0)), // constructor
ast::VariableDecorationList{}); // decorations
ast::type::Bool bool_type; ast::type::Bool bool_type;
auto* cond = create<ast::ScalarConstructorExpression>( auto* cond = Expr(true);
Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true)); auto* body = create<ast::BlockStatement>(ast::StatementList{
auto* body = create<ast::BlockStatement>( create<ast::VariableDeclStatement>(var),
Source{}, ast::StatementList{ });
create<ast::VariableDeclStatement>(Source{}, var),
});
auto* var_a_float = create<ast::Variable>( auto* var_a_float = Var("a", ast::StorageClass::kNone, ty.f32, Expr(3.1f),
Source{}, // source ast::VariableDecorationList{});
"a", // name
ast::StorageClass::kNone, // storage_class
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::FloatLiteral>(Source{}, &f32, 3.14)), // constructor
ast::VariableDecorationList{}); // decorations
auto* outer_body = create<ast::BlockStatement>( auto* outer_body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::IfStatement>(cond, body, ast::ElseStatementList{}),
create<ast::IfStatement>(Source{}, cond, body, create<ast::VariableDeclStatement>(Source{Source::Location{12, 34}},
ast::ElseStatementList{}), var_a_float),
create<ast::VariableDeclStatement>( });
Source{Source::Location{12, 34}}, var_a_float),
});
EXPECT_TRUE(td()->DetermineStatements(outer_body)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(outer_body)) << td()->error();
EXPECT_TRUE(v()->ValidateStatements(outer_body)) << v()->error(); EXPECT_TRUE(v()->ValidateStatements(outer_body)) << v()->error();
@ -754,44 +516,22 @@ TEST_F(ValidatorTest, DISABLED_RedeclaredIdentifierInnerScope_False) {
// var a : f32 = 3.14; // var a : f32 = 3.14;
// if (true) { var a : f32 = 2.0; } // if (true) { var a : f32 = 2.0; }
// } // }
ast::type::F32 f32; auto* var_a_float = Var("a", ast::StorageClass::kNone, ty.f32, Expr(3.1f),
auto* var_a_float = create<ast::Variable>( ast::VariableDecorationList{});
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::FloatLiteral>(Source{}, &f32, 3.14)), // constructor
ast::VariableDecorationList{}); // decorations
auto* var = create<ast::Variable>( auto* var = Var("a", ast::StorageClass::kNone, ty.f32, Expr(2.0f),
Source{}, // source ast::VariableDecorationList{});
"a", // name
ast::StorageClass::kNone, // storage_class
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::FloatLiteral>(Source{}, &f32, 2.0)), // constructor
ast::VariableDecorationList{}); // decorations
ast::type::Bool bool_type; ast::type::Bool bool_type;
auto* cond = create<ast::ScalarConstructorExpression>( auto* cond = Expr(true);
Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true)); auto* body = create<ast::BlockStatement>(ast::StatementList{
auto* body = create<ast::BlockStatement>( create<ast::VariableDeclStatement>(Source{Source::Location{12, 34}}, var),
Source{}, ast::StatementList{ });
create<ast::VariableDeclStatement>(
Source{Source::Location{12, 34}}, var),
});
auto* outer_body = create<ast::BlockStatement>( auto* outer_body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var_a_float),
create<ast::VariableDeclStatement>(Source{}, var_a_float), create<ast::IfStatement>(cond, body, ast::ElseStatementList{}),
create<ast::IfStatement>(Source{}, cond, body, });
ast::ElseStatementList{}),
});
EXPECT_TRUE(td()->DetermineStatements(outer_body)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(outer_body)) << td()->error();
EXPECT_FALSE(v()->ValidateStatements(outer_body)); EXPECT_FALSE(v()->ValidateStatements(outer_body));
@ -801,61 +541,40 @@ TEST_F(ValidatorTest, DISABLED_RedeclaredIdentifierInnerScope_False) {
TEST_F(ValidatorTest, RedeclaredIdentifierDifferentFunctions_Pass) { TEST_F(ValidatorTest, RedeclaredIdentifierDifferentFunctions_Pass) {
// func0 { var a : f32 = 2.0; return; } // func0 { var a : f32 = 2.0; return; }
// func1 { var a : f32 = 3.0; return; } // func1 { var a : f32 = 3.0; return; }
ast::type::F32 f32; auto* var0 = Var("a", ast::StorageClass::kNone, ty.f32, Expr(2.0f),
ast::type::Void void_type; ast::VariableDecorationList{});
auto* var0 = create<ast::Variable>(
Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&f32, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::FloatLiteral>(Source{}, &f32, 2.0)), // constructor
ast::VariableDecorationList{}); // decorations
auto* var1 = create<ast::Variable>( auto* var1 = Var("a", ast::StorageClass::kNone, ty.void_, Expr(1.0f),
Source{}, // source ast::VariableDecorationList{});
"a", // name
ast::StorageClass::kNone, // storage_class
&void_type, // type
false, // is_const
create<ast::ScalarConstructorExpression>(
Source{},
create<ast::FloatLiteral>(Source{}, &f32, 1.0)), // constructor
ast::VariableDecorationList{}); // decorations
ast::VariableList params0; ast::VariableList params0;
auto* body0 = create<ast::BlockStatement>( auto* body0 = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(Source{Source::Location{12, 34}},
create<ast::VariableDeclStatement>( var0),
Source{Source::Location{12, 34}}, var0), create<ast::ReturnStatement>(),
create<ast::ReturnStatement>(Source{}), });
});
auto* func0 = create<ast::Function>(Source{}, mod()->RegisterSymbol("func0"), auto* func0 =
"func0", params0, &void_type, body0, create<ast::Function>(mod->RegisterSymbol("func0"), "func0", params0,
ast::FunctionDecorationList{}); ty.void_, body0, ast::FunctionDecorationList{});
ast::VariableList params1; ast::VariableList params1;
auto* body1 = create<ast::BlockStatement>( auto* body1 = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(Source{Source::Location{13, 34}},
create<ast::VariableDeclStatement>( var1),
Source{Source::Location{13, 34}}, var1), create<ast::ReturnStatement>(),
create<ast::ReturnStatement>(Source{}), });
});
auto* func1 = create<ast::Function>( auto* func1 = create<ast::Function>(
Source{}, mod()->RegisterSymbol("func1"), "func1", params1, &void_type, mod->RegisterSymbol("func1"), "func1", params1, ty.void_, body1,
body1,
ast::FunctionDecorationList{ ast::FunctionDecorationList{
create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex), create<ast::StageDecoration>(ast::PipelineStage::kVertex),
}); });
mod()->AddFunction(func0); mod->AddFunction(func0);
mod()->AddFunction(func1); mod->AddFunction(func1);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_TRUE(v()->Validate(mod())) << v()->error(); EXPECT_TRUE(v()->Validate(mod)) << v()->error();
} }
TEST_F(ValidatorTest, VariableDeclNoConstructor_Pass) { TEST_F(ValidatorTest, VariableDeclNoConstructor_Pass) {
@ -863,28 +582,18 @@ TEST_F(ValidatorTest, VariableDeclNoConstructor_Pass) {
// var a :i32; // var a :i32;
// a = 2; // a = 2;
// } // }
ast::type::I32 i32; auto* var = Var("a", ast::StorageClass::kNone, ty.i32, nullptr,
auto* var = ast::VariableDecorationList{});
create<ast::Variable>(Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
false, // is_const
nullptr, // constructor
ast::VariableDecorationList{}); // decorations
td()->RegisterVariableForTesting(var); td()->RegisterVariableForTesting(var);
auto* lhs = create<ast::IdentifierExpression>( auto* lhs = Expr("a");
Source{}, mod()->RegisterSymbol("a"), "a"); auto* rhs = Expr(2);
auto* rhs = create<ast::ScalarConstructorExpression>(
Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
auto* body = create<ast::BlockStatement>( auto* body = create<ast::BlockStatement>(ast::StatementList{
Source{}, ast::StatementList{ create<ast::VariableDeclStatement>(var),
create<ast::VariableDeclStatement>(Source{}, var), create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
create<ast::AssignmentStatement>( rhs),
Source{Source::Location{12, 34}}, lhs, rhs), });
});
EXPECT_TRUE(td()->DetermineStatements(body)) << td()->error(); EXPECT_TRUE(td()->DetermineStatements(body)) << td()->error();
ASSERT_NE(lhs->result_type(), nullptr); ASSERT_NE(lhs->result_type(), nullptr);

View File

@ -19,7 +19,7 @@
namespace tint { namespace tint {
ValidatorTestHelper::ValidatorTestHelper() { ValidatorTestHelper::ValidatorTestHelper() {
td_ = std::make_unique<TypeDeterminer>(&mod_); td_ = std::make_unique<TypeDeterminer>(mod);
v_ = std::make_unique<ValidatorImpl>(); v_ = std::make_unique<ValidatorImpl>();
} }

View File

@ -18,6 +18,7 @@
#include <memory> #include <memory>
#include <utility> #include <utility>
#include "src/ast/builder.h"
#include "src/ast/type/void_type.h" #include "src/ast/type/void_type.h"
#include "src/type_determiner.h" #include "src/type_determiner.h"
#include "src/validator/validator_impl.h" #include "src/validator/validator_impl.h"
@ -25,11 +26,11 @@
namespace tint { namespace tint {
/// A helper for testing validation /// A helper for testing validation
class ValidatorTestHelper { class ValidatorTestHelper : public ast::BuilderWithModule {
public: public:
/// Constructor /// Constructor
ValidatorTestHelper(); ValidatorTestHelper();
~ValidatorTestHelper(); ~ValidatorTestHelper() override;
/// A handle to validator /// A handle to validator
/// @returns a pointer to the validator /// @returns a pointer to the validator
@ -37,24 +38,10 @@ class ValidatorTestHelper {
/// A handle to type_determiner /// A handle to type_determiner
/// @returns a pointer to the type_determiner object /// @returns a pointer to the type_determiner object
TypeDeterminer* td() const { return td_.get(); } TypeDeterminer* td() const { return td_.get(); }
/// A handle to the created module
/// @return a pointer to the test module
ast::Module* mod() { return &mod_; }
/// Creates a new `ast::Node` owned by the Module. When the Module is
/// destructed, the `ast::Node` will also be destructed.
/// @param args the arguments to pass to the type constructor
/// @returns the node pointer
template <typename T, typename... ARGS>
T* create(ARGS&&... args) {
return mod_.create<T>(std::forward<ARGS>(args)...);
}
private: private:
std::unique_ptr<ValidatorImpl> v_; std::unique_ptr<ValidatorImpl> v_;
ast::Module mod_;
std::unique_ptr<TypeDeterminer> td_; std::unique_ptr<TypeDeterminer> td_;
ast::type::Void void_type_;
}; };
} // namespace tint } // namespace tint

View File

@ -42,25 +42,23 @@ TEST_F(ValidatorTypeTest, RuntimeArrayIsLast_Pass) {
// rt: array<f32>; // rt: array<f32>;
// }; // };
ast::type::F32 f32;
ast::type::Array arr(&f32, 0, ast::ArrayDecorationList{});
ast::StructMemberList members; ast::StructMemberList members;
{ {
ast::StructMemberDecorationList deco; ast::StructMemberDecorationList deco;
members.push_back(create<ast::StructMember>(Source{}, "vf", &f32, deco)); members.push_back(create<ast::StructMember>("vf", ty.f32, deco));
} }
{ {
ast::StructMemberDecorationList deco; ast::StructMemberDecorationList deco;
members.push_back(create<ast::StructMember>( members.push_back(create<ast::StructMember>(
Source{Source::Location{12, 34}}, "rt", &arr, deco)); Source{Source::Location{12, 34}}, "rt", ty.array<f32>(), deco));
} }
ast::StructDecorationList decos; ast::StructDecorationList decos;
decos.push_back(create<ast::StructBlockDecoration>(Source{})); decos.push_back(create<ast::StructBlockDecoration>());
auto* st = create<ast::Struct>(Source{}, members, decos); auto* st = create<ast::Struct>(members, decos);
ast::type::Struct struct_type(mod()->RegisterSymbol("Foo"), "Foo", st); ast::type::Struct struct_type(mod->RegisterSymbol("Foo"), "Foo", st);
mod()->AddConstructedType(&struct_type); mod->AddConstructedType(&struct_type);
EXPECT_TRUE(v()->ValidateConstructedTypes(mod()->constructed_types())); EXPECT_TRUE(v()->ValidateConstructedTypes(mod->constructed_types()));
} }
TEST_F(ValidatorTypeTest, RuntimeArrayIsLastNoBlock_Fail) { TEST_F(ValidatorTypeTest, RuntimeArrayIsLastNoBlock_Fail) {
@ -69,24 +67,22 @@ TEST_F(ValidatorTypeTest, RuntimeArrayIsLastNoBlock_Fail) {
// rt: array<f32>; // rt: array<f32>;
// }; // };
ast::type::F32 f32;
ast::type::Array arr(&f32, 0, ast::ArrayDecorationList{});
ast::StructMemberList members; ast::StructMemberList members;
{ {
ast::StructMemberDecorationList deco; ast::StructMemberDecorationList deco;
members.push_back(create<ast::StructMember>(Source{}, "vf", &f32, deco)); members.push_back(create<ast::StructMember>("vf", ty.f32, deco));
} }
{ {
ast::StructMemberDecorationList deco; ast::StructMemberDecorationList deco;
members.push_back(create<ast::StructMember>( members.push_back(create<ast::StructMember>(
Source{Source::Location{12, 34}}, "rt", &arr, deco)); Source{Source::Location{12, 34}}, "rt", ty.array<f32>(), deco));
} }
ast::StructDecorationList decos; ast::StructDecorationList decos;
auto* st = create<ast::Struct>(Source{}, members, decos); auto* st = create<ast::Struct>(members, decos);
ast::type::Struct struct_type(mod()->RegisterSymbol("Foo"), "Foo", st); ast::type::Struct struct_type(mod->RegisterSymbol("Foo"), "Foo", st);
mod()->AddConstructedType(&struct_type); mod->AddConstructedType(&struct_type);
EXPECT_FALSE(v()->ValidateConstructedTypes(mod()->constructed_types())); EXPECT_FALSE(v()->ValidateConstructedTypes(mod->constructed_types()));
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
"12:34 v-0031: a struct containing a runtime-sized array must be " "12:34 v-0031: a struct containing a runtime-sized array must be "
"in the 'storage' storage class: 'Foo'"); "in the 'storage' storage class: 'Foo'");
@ -99,25 +95,23 @@ TEST_F(ValidatorTypeTest, RuntimeArrayIsNotLast_Fail) {
// vf: f32; // vf: f32;
// }; // };
ast::type::F32 f32;
ast::type::Array arr(&f32, 0, ast::ArrayDecorationList{});
ast::StructMemberList members; ast::StructMemberList members;
{ {
ast::StructMemberDecorationList deco; ast::StructMemberDecorationList deco;
members.push_back(create<ast::StructMember>( members.push_back(create<ast::StructMember>(
Source{Source::Location{12, 34}}, "rt", &arr, deco)); Source{Source::Location{12, 34}}, "rt", ty.array<f32>(), deco));
} }
{ {
ast::StructMemberDecorationList deco; ast::StructMemberDecorationList deco;
members.push_back(create<ast::StructMember>(Source{}, "vf", &f32, deco)); members.push_back(create<ast::StructMember>("vf", ty.f32, deco));
} }
ast::StructDecorationList decos; ast::StructDecorationList decos;
decos.push_back(create<ast::StructBlockDecoration>(Source{})); decos.push_back(create<ast::StructBlockDecoration>());
auto* st = create<ast::Struct>(Source{}, members, decos); auto* st = create<ast::Struct>(members, decos);
ast::type::Struct struct_type(mod()->RegisterSymbol("Foo"), "Foo", st); ast::type::Struct struct_type(mod->RegisterSymbol("Foo"), "Foo", st);
mod()->AddConstructedType(&struct_type); mod->AddConstructedType(&struct_type);
EXPECT_FALSE(v()->ValidateConstructedTypes(mod()->constructed_types())); EXPECT_FALSE(v()->ValidateConstructedTypes(mod->constructed_types()));
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
"12:34 v-0015: runtime arrays may only appear as the last member " "12:34 v-0015: runtime arrays may only appear as the last member "
"of a struct: 'rt'"); "of a struct: 'rt'");
@ -131,9 +125,8 @@ TEST_F(ValidatorTypeTest, AliasRuntimeArrayIsNotLast_Fail) {
// a: u32; // a: u32;
//} //}
ast::type::F32 u32; ast::type::Alias alias{mod->RegisterSymbol("RTArr"), "RTArr",
ast::type::Array array(&u32, 0, ast::ArrayDecorationList{}); ty.array<u32>()};
ast::type::Alias alias{mod()->RegisterSymbol("RTArr"), "RTArr", &array};
ast::StructMemberList members; ast::StructMemberList members;
{ {
@ -143,15 +136,15 @@ TEST_F(ValidatorTypeTest, AliasRuntimeArrayIsNotLast_Fail) {
} }
{ {
ast::StructMemberDecorationList deco; ast::StructMemberDecorationList deco;
members.push_back(create<ast::StructMember>(Source{}, "a", &u32, deco)); members.push_back(create<ast::StructMember>("a", ty.u32, deco));
} }
ast::StructDecorationList decos; ast::StructDecorationList decos;
decos.push_back(create<ast::StructBlockDecoration>(Source{})); decos.push_back(create<ast::StructBlockDecoration>());
auto* st = create<ast::Struct>(Source{}, members, decos); auto* st = create<ast::Struct>(members, decos);
ast::type::Struct struct_type(mod()->RegisterSymbol("s"), "s", st); ast::type::Struct struct_type(mod->RegisterSymbol("s"), "s", st);
mod()->AddConstructedType(&struct_type); mod->AddConstructedType(&struct_type);
EXPECT_FALSE(v()->ValidateConstructedTypes(mod()->constructed_types())); EXPECT_FALSE(v()->ValidateConstructedTypes(mod->constructed_types()));
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
"12:34 v-0015: runtime arrays may only appear as the last member " "12:34 v-0015: runtime arrays may only appear as the last member "
"of a struct: 'b'"); "of a struct: 'b'");
@ -165,14 +158,13 @@ TEST_F(ValidatorTypeTest, AliasRuntimeArrayIsLast_Pass) {
// b: RTArr; // b: RTArr;
//} //}
ast::type::F32 u32; ast::type::Alias alias{mod->RegisterSymbol("RTArr"), "RTArr",
ast::type::Array array(&u32, 0, ast::ArrayDecorationList{}); ty.array<u32>()};
ast::type::Alias alias{mod()->RegisterSymbol("RTArr"), "RTArr", &array};
ast::StructMemberList members; ast::StructMemberList members;
{ {
ast::StructMemberDecorationList deco; ast::StructMemberDecorationList deco;
members.push_back(create<ast::StructMember>(Source{}, "a", &u32, deco)); members.push_back(create<ast::StructMember>("a", ty.u32, deco));
} }
{ {
ast::StructMemberDecorationList deco; ast::StructMemberDecorationList deco;
@ -180,43 +172,31 @@ TEST_F(ValidatorTypeTest, AliasRuntimeArrayIsLast_Pass) {
Source{Source::Location{12, 34}}, "b", &alias, deco)); Source{Source::Location{12, 34}}, "b", &alias, deco));
} }
ast::StructDecorationList decos; ast::StructDecorationList decos;
decos.push_back(create<ast::StructBlockDecoration>(Source{})); decos.push_back(create<ast::StructBlockDecoration>());
auto* st = create<ast::Struct>(Source{}, members, decos); auto* st = create<ast::Struct>(members, decos);
ast::type::Struct struct_type(mod()->RegisterSymbol("s"), "s", st); ast::type::Struct struct_type(mod->RegisterSymbol("s"), "s", st);
mod()->AddConstructedType(&struct_type); mod->AddConstructedType(&struct_type);
EXPECT_TRUE(v()->ValidateConstructedTypes(mod()->constructed_types())); EXPECT_TRUE(v()->ValidateConstructedTypes(mod->constructed_types()));
} }
TEST_F(ValidatorTypeTest, RuntimeArrayInFunction_Fail) { TEST_F(ValidatorTypeTest, RuntimeArrayInFunction_Fail) {
/// [[stage(vertex)]] /// [[stage(vertex)]]
// fn func -> void { var a : array<i32>; } // fn func -> void { var a : array<i32>; }
ast::type::I32 i32;
ast::type::Array array(&i32, 0, ast::ArrayDecorationList{});
auto* var = auto* var = Var("a", ast::StorageClass::kNone, ty.array<i32>());
create<ast::Variable>(Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&array, // type
false, // is_const
nullptr, // constructor
ast::VariableDecorationList{}); // decorations
ast::VariableList params; ast::VariableList params;
ast::type::Void void_type; auto* body = create<ast::BlockStatement>(ast::StatementList{
auto* body = create<ast::BlockStatement>( create<ast::VariableDeclStatement>(Source{Source::Location{12, 34}}, var),
Source{}, ast::StatementList{ });
create<ast::VariableDeclStatement>(
Source{Source::Location{12, 34}}, var),
});
auto* func = create<ast::Function>( auto* func = create<ast::Function>(
Source{}, mod()->RegisterSymbol("func"), "func", params, &void_type, body, mod->RegisterSymbol("func"), "func", params, ty.void_, body,
ast::FunctionDecorationList{ ast::FunctionDecorationList{
create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex), create<ast::StageDecoration>(ast::PipelineStage::kVertex),
}); });
mod()->AddFunction(func); mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error(); EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod())); EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ(v()->error(), EXPECT_EQ(v()->error(),
"12:34 v-0015: runtime arrays may only appear as the last member " "12:34 v-0015: runtime arrays may only appear as the last member "
"of a struct: 'a'"); "of a struct: 'a'");