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;
}
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() {

View File

@ -499,6 +499,20 @@ class Builder {
Expression* constructor,
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 args the function call arguments
/// @returns a `CallExpression` to the function `func`, with the

View File

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

View File

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

View File

@ -38,100 +38,74 @@ class ValidateFunctionTest : public ValidatorTestHelper,
TEST_F(ValidateFunctionTest, VoidFunctionEndWithoutReturnStatement_Pass) {
// [[stage(vertex)]]
// fn func -> void { var a:i32 = 2; }
ast::type::I32 i32;
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 = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
ast::VariableDecorationList{});
ast::VariableList params;
ast::type::Void void_type;
auto* body = create<ast::BlockStatement>(
Source{}, ast::StatementList{
create<ast::VariableDeclStatement>(Source{}, var),
auto* body = create<ast::BlockStatement>(ast::StatementList{
create<ast::VariableDeclStatement>(var),
});
auto* func = create<ast::Function>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func",
params, &void_type, body,
Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
params, ty.void_, body,
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(v()->Validate(mod()));
EXPECT_TRUE(v()->Validate(mod));
}
TEST_F(ValidateFunctionTest,
VoidFunctionEndWithoutReturnStatementEmptyBody_Pass) {
// [[stage(vertex)]]
// fn func -> void {}
ast::type::Void void_type;
ast::VariableList params;
auto* func = create<ast::Function>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func",
params, &void_type,
create<ast::BlockStatement>(Source{}, ast::StatementList{}),
Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
params, ty.void_, create<ast::BlockStatement>(ast::StatementList{}),
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(v()->Validate(mod()));
EXPECT_TRUE(v()->Validate(mod));
}
TEST_F(ValidateFunctionTest, FunctionEndWithoutReturnStatement_Fail) {
// fn func -> int { var a:i32 = 2; }
ast::type::I32 i32;
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 = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
ast::VariableDecorationList{});
ast::VariableList params;
ast::type::Void void_type;
auto* body = create<ast::BlockStatement>(
Source{}, ast::StatementList{
create<ast::VariableDeclStatement>(Source{}, var),
auto* body = create<ast::BlockStatement>(ast::StatementList{
create<ast::VariableDeclStatement>(var),
});
auto* func = create<ast::Function>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func",
params, &i32, body, ast::FunctionDecorationList{});
mod()->AddFunction(func);
Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
params, ty.i32, body, ast::FunctionDecorationList{});
mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod()));
EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ(v()->error(),
"12:34 v-0002: non-void function must end with a return statement");
}
TEST_F(ValidateFunctionTest, FunctionEndWithoutReturnStatementEmptyBody_Fail) {
// fn func -> int {}
ast::type::Void void_type;
ast::type::I32 i32;
ast::VariableList params;
auto* func = create<ast::Function>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func",
params, &i32, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
params, ty.i32, create<ast::BlockStatement>(ast::StatementList{}),
ast::FunctionDecorationList{});
mod()->AddFunction(func);
mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod()));
EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ(v()->error(),
"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) {
// [[stage(vertex)]]
// fn func -> void { return; }
ast::type::Void void_type;
ast::VariableList params;
auto* body = create<ast::BlockStatement>(
Source{}, ast::StatementList{
create<ast::ReturnStatement>(Source{}),
auto* body = create<ast::BlockStatement>(ast::StatementList{
create<ast::ReturnStatement>(),
});
auto* func = create<ast::Function>(
Source{}, mod()->RegisterSymbol("func"), "func", params, &void_type, body,
mod->RegisterSymbol("func"), "func", params, ty.void_, body,
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(v()->ValidateFunctions(mod()->functions())) << v()->error();
EXPECT_TRUE(td()->DetermineFunctions(mod->functions())) << td()->error();
EXPECT_TRUE(v()->ValidateFunctions(mod->functions())) << v()->error();
}
TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementType_fail) {
// fn func -> void { return 2; }
ast::type::Void void_type;
ast::type::I32 i32;
ast::VariableList params;
auto* return_expr = create<ast::ScalarConstructorExpression>(
Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
auto* return_expr = Expr(2);
auto* body = create<ast::BlockStatement>(
Source{}, ast::StatementList{
create<ast::ReturnStatement>(
Source{Source::Location{12, 34}}, return_expr),
auto* body = create<ast::BlockStatement>(ast::StatementList{
create<ast::ReturnStatement>(Source{Source::Location{12, 34}},
return_expr),
});
auto* func = create<ast::Function>(Source{}, mod()->RegisterSymbol("func"),
"func", params, &void_type, body,
ast::FunctionDecorationList{});
mod()->AddFunction(func);
auto* func =
create<ast::Function>(mod->RegisterSymbol("func"), "func", params,
ty.void_, body, ast::FunctionDecorationList{});
mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod()));
EXPECT_FALSE(v()->Validate(mod));
// TODO(sarahM0): replace 000y with a rule number
EXPECT_EQ(v()->error(),
"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) {
// fn func -> f32 { return 2; }
ast::type::I32 i32;
ast::type::F32 f32;
ast::VariableList params;
auto* return_expr = create<ast::ScalarConstructorExpression>(
Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
auto* return_expr = Expr(2);
auto* body = create<ast::BlockStatement>(
Source{}, ast::StatementList{
create<ast::ReturnStatement>(
Source{Source::Location{12, 34}}, return_expr),
auto* body = create<ast::BlockStatement>(ast::StatementList{
create<ast::ReturnStatement>(Source{Source::Location{12, 34}},
return_expr),
});
auto* func =
create<ast::Function>(Source{}, mod()->RegisterSymbol("func"), "func",
params, &f32, body, ast::FunctionDecorationList{});
mod()->AddFunction(func);
create<ast::Function>(mod->RegisterSymbol("func"), "func", params, ty.f32,
body, ast::FunctionDecorationList{});
mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod()));
EXPECT_FALSE(v()->Validate(mod));
// TODO(sarahM0): replace 000y with a rule number
EXPECT_EQ(v()->error(),
"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) {
// fn func -> i32 { return 2; }
// fn func -> i32 { return 2; }
ast::type::Void void_type;
ast::type::I32 i32;
ast::VariableList params;
auto* return_expr = create<ast::ScalarConstructorExpression>(
Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
auto* return_expr = Expr(2);
auto* body = create<ast::BlockStatement>(
Source{}, ast::StatementList{
create<ast::ReturnStatement>(Source{}, return_expr),
auto* body = create<ast::BlockStatement>(ast::StatementList{
create<ast::ReturnStatement>(return_expr),
});
auto* func =
create<ast::Function>(Source{}, mod()->RegisterSymbol("func"), "func",
params, &i32, body, ast::FunctionDecorationList{});
create<ast::Function>(mod->RegisterSymbol("func"), "func", params, ty.i32,
body, ast::FunctionDecorationList{});
ast::VariableList params_copy;
auto* return_expr_copy = create<ast::ScalarConstructorExpression>(
Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
auto* body_copy = create<ast::BlockStatement>(
Source{}, ast::StatementList{
create<ast::ReturnStatement>(Source{}, return_expr_copy),
auto* return_expr_copy = Expr(2);
auto* body_copy = create<ast::BlockStatement>(ast::StatementList{
create<ast::ReturnStatement>(return_expr_copy),
});
auto* func_copy = create<ast::Function>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func",
params_copy, &i32, body_copy, ast::FunctionDecorationList{});
Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
params_copy, ty.i32, body_copy, ast::FunctionDecorationList{});
mod()->AddFunction(func);
mod()->AddFunction(func_copy);
mod->AddFunction(func);
mod->AddFunction(func_copy);
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'");
}
TEST_F(ValidateFunctionTest, RecursionIsNotAllowed_Fail) {
// fn func() -> void {func(); return; }
ast::type::F32 f32;
ast::type::Void void_type;
ast::ExpressionList call_params;
auto* call_expr = create<ast::CallExpression>(
Source{Source::Location{12, 34}},
create<ast::IdentifierExpression>(Source{}, mod()->RegisterSymbol("func"),
"func"),
call_params);
Source{Source::Location{12, 34}}, Expr("func"), call_params);
ast::VariableList params0;
auto* body0 = create<ast::BlockStatement>(
Source{}, ast::StatementList{
create<ast::CallStatement>(Source{}, call_expr),
create<ast::ReturnStatement>(Source{}),
auto* body0 = create<ast::BlockStatement>(ast::StatementList{
create<ast::CallStatement>(call_expr),
create<ast::ReturnStatement>(),
});
auto* func0 = create<ast::Function>(Source{}, mod()->RegisterSymbol("func"),
"func", params0, &f32, body0,
ast::FunctionDecorationList{});
mod()->AddFunction(func0);
auto* func0 =
create<ast::Function>(mod->RegisterSymbol("func"), "func", params0,
ty.f32, body0, ast::FunctionDecorationList{});
mod->AddFunction(func0);
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'");
}
TEST_F(ValidateFunctionTest, RecursionIsNotAllowedExpr_Fail) {
// fn func() -> i32 {var a: i32 = func(); return 2; }
ast::type::I32 i32;
ast::ExpressionList call_params;
auto* call_expr = create<ast::CallExpression>(
Source{Source::Location{12, 34}},
create<ast::IdentifierExpression>(Source{}, mod()->RegisterSymbol("func"),
"func"),
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
Source{Source::Location{12, 34}}, Expr("func"), call_params);
auto* var = Var("a", ast::StorageClass::kNone, ty.i32, call_expr,
ast::VariableDecorationList{});
ast::VariableList params0;
auto* return_expr = create<ast::ScalarConstructorExpression>(
Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
auto* return_expr = Expr(2);
auto* body0 = create<ast::BlockStatement>(
Source{}, ast::StatementList{
create<ast::VariableDeclStatement>(Source{}, var),
create<ast::ReturnStatement>(Source{}, return_expr),
auto* body0 = create<ast::BlockStatement>(ast::StatementList{
create<ast::VariableDeclStatement>(var),
create<ast::ReturnStatement>(return_expr),
});
auto* func0 = create<ast::Function>(Source{}, mod()->RegisterSymbol("func"),
"func", params0, &i32, body0,
ast::FunctionDecorationList{});
mod()->AddFunction(func0);
auto* func0 =
create<ast::Function>(mod->RegisterSymbol("func"), "func", params0,
ty.i32, body0, ast::FunctionDecorationList{});
mod->AddFunction(func0);
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'");
}
TEST_F(ValidateFunctionTest, Function_WithPipelineStage_NotVoid_Fail) {
// [[stage(vertex)]]
// fn vtx_main() -> i32 { return 0; }
ast::type::I32 i32;
ast::VariableList params;
auto* return_expr = create<ast::ScalarConstructorExpression>(
Source{}, create<ast::SintLiteral>(Source{}, &i32, 0));
auto* return_expr = Expr(0);
auto* body = create<ast::BlockStatement>(
Source{}, ast::StatementList{
create<ast::ReturnStatement>(Source{}, return_expr),
auto* body = create<ast::BlockStatement>(ast::StatementList{
create<ast::ReturnStatement>(return_expr),
});
auto* func = create<ast::Function>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("vtx_main"),
"vtx_main", params, &i32, body,
Source{Source::Location{12, 34}}, mod->RegisterSymbol("vtx_main"),
"vtx_main", params, ty.i32, body,
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_FALSE(v()->Validate(mod()));
EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ(v()->error(),
"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) {
// [[stage(vertex)]]
// fn vtx_func(a : i32) -> void { return; }
ast::type::I32 i32;
ast::type::Void void_type;
ast::VariableList params;
params.push_back(
create<ast::Variable>(Source{}, // source
"a", // name
ast::StorageClass::kNone, // storage_class
&i32, // type
false, // is_const
nullptr, // constructor
ast::VariableDecorationList{})); // decorations
auto* body = create<ast::BlockStatement>(
Source{}, ast::StatementList{
create<ast::ReturnStatement>(Source{}),
params.push_back(Var("a", ast::StorageClass::kNone, ty.i32, nullptr,
ast::VariableDecorationList{}));
auto* body = create<ast::BlockStatement>(ast::StatementList{
create<ast::ReturnStatement>(),
});
auto* func = create<ast::Function>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("vtx_func"),
"vtx_func", params, &void_type, body,
Source{Source::Location{12, 34}}, mod->RegisterSymbol("vtx_func"),
"vtx_func", params, ty.void_, body,
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_FALSE(v()->Validate(mod()));
EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ(v()->error(),
"12:34 v-0023: Entry point function must accept no parameters: "
"'vtx_func'");
@ -376,23 +304,21 @@ TEST_F(ValidateFunctionTest, PipelineStage_MustBeUnique_Fail) {
// [[stage(fragment)]]
// [[stage(vertex)]]
// fn main() -> void { return; }
ast::type::Void void_type;
ast::VariableList params;
auto* body = create<ast::BlockStatement>(
Source{}, ast::StatementList{
create<ast::ReturnStatement>(Source{}),
auto* body = create<ast::BlockStatement>(ast::StatementList{
create<ast::ReturnStatement>(),
});
auto* func = create<ast::Function>(
Source{Source::Location{12, 34}}, mod()->RegisterSymbol("main"), "main",
params, &void_type, body,
Source{Source::Location{12, 34}}, mod->RegisterSymbol("main"), "main",
params, ty.void_, body,
ast::FunctionDecorationList{
create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex),
create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
create<ast::StageDecoration>(ast::PipelineStage::kVertex),
create<ast::StageDecoration>(ast::PipelineStage::kFragment),
});
mod()->AddFunction(func);
mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod()));
EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ(
v()->error(),
"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) {
// [[stage(vertex)]]
// fn vtx_func() -> void { return; }
ast::type::Void void_type;
ast::VariableList params;
auto* body = create<ast::BlockStatement>(
Source{}, ast::StatementList{
create<ast::ReturnStatement>(Source{}),
auto* body = create<ast::BlockStatement>(ast::StatementList{
create<ast::ReturnStatement>(),
});
auto* func = create<ast::Function>(
Source{}, mod()->RegisterSymbol("vtx_func"), "vtx_func", params,
&void_type, body,
mod->RegisterSymbol("vtx_func"), "vtx_func", params, ty.void_, body,
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(v()->Validate(mod())) << v()->error();
EXPECT_TRUE(v()->Validate(mod)) << v()->error();
}
TEST_F(ValidateFunctionTest, OnePipelineStageFunctionMustBePresent_Fail) {
// fn vtx_func() -> void { return; }
ast::type::Void void_type;
ast::VariableList params;
auto* body = create<ast::BlockStatement>(
Source{}, ast::StatementList{
create<ast::ReturnStatement>(Source{}),
auto* body = create<ast::BlockStatement>(ast::StatementList{
create<ast::ReturnStatement>(),
});
auto* func = create<ast::Function>(
Source{}, mod()->RegisterSymbol("vtx_func"), "vtx_func", params,
&void_type, body, ast::FunctionDecorationList{});
mod()->AddFunction(func);
auto* func =
create<ast::Function>(mod->RegisterSymbol("vtx_func"), "vtx_func", params,
ty.void_, body, ast::FunctionDecorationList{});
mod->AddFunction(func);
EXPECT_TRUE(td()->Determine()) << td()->error();
EXPECT_FALSE(v()->Validate(mod()));
EXPECT_FALSE(v()->Validate(mod));
EXPECT_EQ(v()->error(),
"v-0003: At least one of vertex, fragment or compute shader must "
"be present");

View File

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

View File

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

View File

@ -18,6 +18,7 @@
#include <memory>
#include <utility>
#include "src/ast/builder.h"
#include "src/ast/type/void_type.h"
#include "src/type_determiner.h"
#include "src/validator/validator_impl.h"
@ -25,11 +26,11 @@
namespace tint {
/// A helper for testing validation
class ValidatorTestHelper {
class ValidatorTestHelper : public ast::BuilderWithModule {
public:
/// Constructor
ValidatorTestHelper();
~ValidatorTestHelper();
~ValidatorTestHelper() override;
/// A handle to validator
/// @returns a pointer to the validator
@ -37,24 +38,10 @@ class ValidatorTestHelper {
/// A handle to type_determiner
/// @returns a pointer to the type_determiner object
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:
std::unique_ptr<ValidatorImpl> v_;
ast::Module mod_;
std::unique_ptr<TypeDeterminer> td_;
ast::type::Void void_type_;
};
} // namespace tint

View File

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