Split Program into Program and ProgramBuilder

Program is now immutable*, and remains part of the public Tint
interface.

ProgramBuilder is the mutable builder for Programs, and is not part of
the public Tint interface. ast::Builder has been folded into
ProgramBuilder.

Immutable Programs can be cloned into a mutable ProgramBuilder with
Program::CloneAsBuilder().

Mutable ProgramBuilders can be moved into immutable Programs.

* - mostly immutable. It still has a move constructor and move
  assignment operator - required for practical usage - and the
  semantic information on AST nodes is still mutable.

Bug: tint:390
Change-Id: Ia856c50b1880c2f95c91467a9eef5024cbc380c6
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/38240
Reviewed-by: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
Ben Clayton
2021-01-26 16:57:10 +00:00
parent 1f7e18bbc0
commit a6b9a8eb2f
186 changed files with 3324 additions and 2645 deletions

View File

@@ -132,8 +132,9 @@ TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementType_Pass) {
EXPECT_TRUE(td()->DetermineFunctions(AST().Functions())) << td()->error();
ValidatorImpl& v = Build();
const Program* program = v.program();
EXPECT_TRUE(v.ValidateFunctions(AST().Functions())) << v.error();
EXPECT_TRUE(v.ValidateFunctions(program->AST().Functions())) << v.error();
}
TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementType_fail) {

View File

@@ -23,12 +23,14 @@
#include "src/ast/function.h"
#include "src/ast/int_literal.h"
#include "src/ast/intrinsic.h"
#include "src/ast/module.h"
#include "src/ast/sint_literal.h"
#include "src/ast/stage_decoration.h"
#include "src/ast/struct.h"
#include "src/ast/switch_statement.h"
#include "src/ast/uint_literal.h"
#include "src/ast/variable_decl_statement.h"
#include "src/type/alias_type.h"
#include "src/type/array_type.h"
#include "src/type/i32_type.h"
#include "src/type/matrix_type.h"

View File

@@ -24,6 +24,7 @@
#include "src/ast/call_expression.h"
#include "src/ast/expression.h"
#include "src/ast/identifier_expression.h"
#include "src/ast/module.h"
#include "src/ast/return_statement.h"
#include "src/ast/statement.h"
#include "src/ast/switch_statement.h"
@@ -48,6 +49,9 @@ class ValidatorImpl {
/// @returns true if the validation was successful
bool Validate();
/// @returns the program being validated
const Program* program() { return program_; }
/// @returns the diagnostic messages
const diag::List& diagnostics() const { return diags_; }
/// @returns the diagnostic messages

View File

@@ -73,9 +73,10 @@ TEST_F(ValidatorTest, AssignToScalar_Fail) {
auto* assign = create<ast::AssignmentStatement>(lhs, rhs);
RegisterVariable(var);
EXPECT_TRUE(td()->DetermineResultType(assign));
ValidatorImpl& v = Build();
EXPECT_TRUE(td()->DetermineResultType(assign));
// TODO(sarahM0): Invalidate assignment to scalar.
EXPECT_FALSE(v.ValidateAssign(assign));
ASSERT_TRUE(v.has_error());
@@ -131,6 +132,7 @@ TEST_F(ValidatorTest, AssignCompatibleTypes_Pass) {
EXPECT_TRUE(td()->DetermineResultType(assign)) << td()->error();
ASSERT_NE(lhs->result_type(), nullptr);
ASSERT_NE(rhs->result_type(), nullptr);
ValidatorImpl& v = Build();
EXPECT_TRUE(v.ValidateAssign(assign)) << v.error();
@@ -153,6 +155,7 @@ TEST_F(ValidatorTest, AssignCompatibleTypesThroughAlias_Pass) {
EXPECT_TRUE(td()->DetermineResultType(assign)) << td()->error();
ASSERT_NE(lhs->result_type(), nullptr);
ASSERT_NE(rhs->result_type(), nullptr);
ValidatorImpl& v = Build();
EXPECT_TRUE(v.ValidateAssign(assign)) << v.error();
@@ -177,6 +180,7 @@ TEST_F(ValidatorTest, AssignCompatibleTypesInferRHSLoad_Pass) {
EXPECT_TRUE(td()->DetermineResultType(assign)) << td()->error();
ASSERT_NE(lhs->result_type(), nullptr);
ASSERT_NE(rhs->result_type(), nullptr);
ValidatorImpl& v = Build();
EXPECT_TRUE(v.ValidateAssign(assign)) << v.error();
@@ -329,8 +333,10 @@ TEST_F(ValidatorTest, GlobalVariableWithStorageClass_Pass) {
ast::VariableDecorationList{}));
ValidatorImpl& v = Build();
const Program* program = v.program();
EXPECT_TRUE(v.ValidateGlobalVariables(AST().GlobalVariables())) << v.error();
EXPECT_TRUE(v.ValidateGlobalVariables(program->AST().GlobalVariables()))
<< v.error();
}
TEST_F(ValidatorTest, GlobalVariableNoStorageClass_Fail) {
@@ -509,8 +515,10 @@ TEST_F(ValidatorTest, GlobalVariableUnique_Pass) {
AST().AddGlobalVariable(var1);
ValidatorImpl& v = Build();
const Program* program = v.program();
EXPECT_TRUE(v.ValidateGlobalVariables(AST().GlobalVariables())) << v.error();
EXPECT_TRUE(v.ValidateGlobalVariables(program->AST().GlobalVariables()))
<< v.error();
}
TEST_F(ValidatorTest, GlobalVariableNotUnique_Fail) {
@@ -526,8 +534,9 @@ TEST_F(ValidatorTest, GlobalVariableNotUnique_Fail) {
AST().AddGlobalVariable(var1);
ValidatorImpl& v = Build();
const Program* program = v.program();
EXPECT_FALSE(v.ValidateGlobalVariables(AST().GlobalVariables()));
EXPECT_FALSE(v.ValidateGlobalVariables(program->AST().GlobalVariables()));
EXPECT_EQ(v.error(),
"12:34 v-0011: redeclared global identifier 'global_var'");
}
@@ -747,50 +756,78 @@ TEST_F(ValidatorTest, VariableDeclNoConstructor_Pass) {
}
TEST_F(ValidatorTest, IsStorable_Void) {
auto* void_ty = ty.void_();
ValidatorImpl& v = Build();
EXPECT_FALSE(v.IsStorable(ty.void_()));
EXPECT_FALSE(v.IsStorable(void_ty));
}
TEST_F(ValidatorTest, IsStorable_Scalar) {
auto* bool_ = ty.bool_();
auto* i32 = ty.i32();
auto* u32 = ty.u32();
auto* f32 = ty.f32();
ValidatorImpl& v = Build();
EXPECT_TRUE(v.IsStorable(ty.bool_()));
EXPECT_TRUE(v.IsStorable(ty.i32()));
EXPECT_TRUE(v.IsStorable(ty.u32()));
EXPECT_TRUE(v.IsStorable(ty.f32()));
EXPECT_TRUE(v.IsStorable(bool_));
EXPECT_TRUE(v.IsStorable(i32));
EXPECT_TRUE(v.IsStorable(u32));
EXPECT_TRUE(v.IsStorable(f32));
}
TEST_F(ValidatorTest, IsStorable_Vector) {
auto* vec2_i32 = ty.vec2<int>();
auto* vec3_i32 = ty.vec3<int>();
auto* vec4_i32 = ty.vec4<int>();
auto* vec2_u32 = ty.vec2<unsigned>();
auto* vec3_u32 = ty.vec3<unsigned>();
auto* vec4_u32 = ty.vec4<unsigned>();
auto* vec2_f32 = ty.vec2<float>();
auto* vec3_f32 = ty.vec3<float>();
auto* vec4_f32 = ty.vec4<float>();
ValidatorImpl& v = Build();
EXPECT_TRUE(v.IsStorable(ty.vec2<int>()));
EXPECT_TRUE(v.IsStorable(ty.vec3<int>()));
EXPECT_TRUE(v.IsStorable(ty.vec4<int>()));
EXPECT_TRUE(v.IsStorable(ty.vec2<unsigned>()));
EXPECT_TRUE(v.IsStorable(ty.vec3<unsigned>()));
EXPECT_TRUE(v.IsStorable(ty.vec4<unsigned>()));
EXPECT_TRUE(v.IsStorable(ty.vec2<float>()));
EXPECT_TRUE(v.IsStorable(ty.vec3<float>()));
EXPECT_TRUE(v.IsStorable(ty.vec4<float>()));
EXPECT_TRUE(v.IsStorable(vec2_i32));
EXPECT_TRUE(v.IsStorable(vec3_i32));
EXPECT_TRUE(v.IsStorable(vec4_i32));
EXPECT_TRUE(v.IsStorable(vec2_u32));
EXPECT_TRUE(v.IsStorable(vec3_u32));
EXPECT_TRUE(v.IsStorable(vec4_u32));
EXPECT_TRUE(v.IsStorable(vec2_f32));
EXPECT_TRUE(v.IsStorable(vec3_f32));
EXPECT_TRUE(v.IsStorable(vec4_f32));
}
TEST_F(ValidatorTest, IsStorable_Matrix) {
auto* mat2x2 = ty.mat2x2<float>();
auto* mat2x3 = ty.mat2x3<float>();
auto* mat2x4 = ty.mat2x4<float>();
auto* mat3x2 = ty.mat3x2<float>();
auto* mat3x3 = ty.mat3x3<float>();
auto* mat3x4 = ty.mat3x4<float>();
auto* mat4x2 = ty.mat4x2<float>();
auto* mat4x3 = ty.mat4x3<float>();
auto* mat4x4 = ty.mat4x4<float>();
ValidatorImpl& v = Build();
EXPECT_TRUE(v.IsStorable(ty.mat2x2<float>()));
EXPECT_TRUE(v.IsStorable(ty.mat2x3<float>()));
EXPECT_TRUE(v.IsStorable(ty.mat2x4<float>()));
EXPECT_TRUE(v.IsStorable(ty.mat3x2<float>()));
EXPECT_TRUE(v.IsStorable(ty.mat3x3<float>()));
EXPECT_TRUE(v.IsStorable(ty.mat3x4<float>()));
EXPECT_TRUE(v.IsStorable(ty.mat4x2<float>()));
EXPECT_TRUE(v.IsStorable(ty.mat4x3<float>()));
EXPECT_TRUE(v.IsStorable(ty.mat4x4<float>()));
EXPECT_TRUE(v.IsStorable(mat2x2));
EXPECT_TRUE(v.IsStorable(mat2x3));
EXPECT_TRUE(v.IsStorable(mat2x4));
EXPECT_TRUE(v.IsStorable(mat3x2));
EXPECT_TRUE(v.IsStorable(mat3x3));
EXPECT_TRUE(v.IsStorable(mat3x4));
EXPECT_TRUE(v.IsStorable(mat4x2));
EXPECT_TRUE(v.IsStorable(mat4x3));
EXPECT_TRUE(v.IsStorable(mat4x4));
}
TEST_F(ValidatorTest, IsStorable_Pointer) {
auto* ptr_ty = ty.pointer<int>(ast::StorageClass::kPrivate);
ValidatorImpl& v = Build();
EXPECT_FALSE(v.IsStorable(ptr_ty));
@@ -798,6 +835,7 @@ TEST_F(ValidatorTest, IsStorable_Pointer) {
TEST_F(ValidatorTest, IsStorable_AliasVoid) {
auto* alias = ty.alias("myalias", ty.void_());
ValidatorImpl& v = Build();
EXPECT_FALSE(v.IsStorable(alias));
@@ -805,39 +843,49 @@ TEST_F(ValidatorTest, IsStorable_AliasVoid) {
TEST_F(ValidatorTest, IsStorable_AliasI32) {
auto* alias = ty.alias("myalias", ty.i32());
ValidatorImpl& v = Build();
EXPECT_TRUE(v.IsStorable(alias));
}
TEST_F(ValidatorTest, IsStorable_ArraySizedOfStorable) {
auto* arr = ty.array(ty.i32(), 5);
ValidatorImpl& v = Build();
EXPECT_TRUE(v.IsStorable(ty.array(ty.i32(), 5)));
EXPECT_TRUE(v.IsStorable(arr));
}
TEST_F(ValidatorTest, IsStorable_ArraySizedOfNonStorable) {
auto* arr = ty.array(ty.void_(), 5);
ValidatorImpl& v = Build();
EXPECT_FALSE(v.IsStorable(ty.array(ty.void_(), 5)));
EXPECT_FALSE(v.IsStorable(arr));
}
TEST_F(ValidatorTest, IsStorable_ArrayUnsizedOfStorable) {
auto* arr = ty.array<int>();
ValidatorImpl& v = Build();
EXPECT_TRUE(v.IsStorable(ty.array<int>()));
EXPECT_TRUE(v.IsStorable(arr));
}
TEST_F(ValidatorTest, IsStorable_ArrayUnsizedOfNonStorable) {
auto* arr = ty.array<void>();
ValidatorImpl& v = Build();
EXPECT_FALSE(v.IsStorable(ty.array<void>()));
EXPECT_FALSE(v.IsStorable(arr));
}
TEST_F(ValidatorTest, IsStorable_Struct_AllMembersStorable) {
ast::StructMemberList members{Member("a", ty.i32()), Member("b", ty.f32())};
auto* s = create<ast::Struct>(Source{}, members, ast::StructDecorationList{});
auto* s_ty = ty.struct_("mystruct", s);
ValidatorImpl& v = Build();
EXPECT_TRUE(v.IsStorable(s_ty));
@@ -848,6 +896,7 @@ TEST_F(ValidatorTest, IsStorable_Struct_SomeMembersNonStorable) {
ast::StructMemberList members{Member("a", ty.i32()), Member("b", ptr_ty)};
auto* s = create<ast::Struct>(Source{}, members, ast::StructDecorationList{});
auto* s_ty = ty.struct_("mystruct", s);
ValidatorImpl& v = Build();
EXPECT_FALSE(v.IsStorable(s_ty));

View File

@@ -19,7 +19,7 @@
namespace tint {
ValidatorTestHelper::ValidatorTestHelper() {
td_ = std::make_unique<TypeDeterminer>(mod);
td_ = std::make_unique<TypeDeterminer>(this);
}
ValidatorTestHelper::~ValidatorTestHelper() = default;

View File

@@ -20,7 +20,7 @@
#include <utility>
#include <vector>
#include "src/ast/builder.h"
#include "src/program_builder.h"
#include "src/type/void_type.h"
#include "src/type_determiner.h"
#include "src/validator/validator_impl.h"
@@ -28,7 +28,7 @@
namespace tint {
/// A helper for testing validation
class ValidatorTestHelper : public ast::BuilderWithProgram {
class ValidatorTestHelper : public ProgramBuilder {
public:
/// Constructor
ValidatorTestHelper();
@@ -42,7 +42,8 @@ class ValidatorTestHelper : public ast::BuilderWithProgram {
if (val_) {
return *val_;
}
val_ = std::make_unique<ValidatorImpl>(program);
program_ = std::make_unique<Program>(std::move(*this));
val_ = std::make_unique<ValidatorImpl>(program_.get());
for (auto* var : vars_for_testing_) {
val_->RegisterVariableForTesting(var);
}
@@ -62,6 +63,7 @@ class ValidatorTestHelper : public ast::BuilderWithProgram {
private:
std::unique_ptr<TypeDeterminer> td_;
std::unique_ptr<Program> program_;
std::unique_ptr<ValidatorImpl> val_;
std::vector<ast::Variable*> vars_for_testing_;
};

View File

@@ -54,8 +54,9 @@ TEST_F(ValidatorTypeTest, RuntimeArrayIsLast_Pass) {
AST().AddConstructedType(struct_type);
ValidatorImpl& v = Build();
const Program* program = v.program();
EXPECT_TRUE(v.ValidateConstructedTypes(AST().ConstructedTypes()));
EXPECT_TRUE(v.ValidateConstructedTypes(program->AST().ConstructedTypes()));
}
TEST_F(ValidatorTypeTest, RuntimeArrayIsLastNoBlock_Fail) {
@@ -74,8 +75,9 @@ TEST_F(ValidatorTypeTest, RuntimeArrayIsLastNoBlock_Fail) {
AST().AddConstructedType(struct_type);
ValidatorImpl& v = Build();
const Program* program = v.program();
EXPECT_FALSE(v.ValidateConstructedTypes(AST().ConstructedTypes()));
EXPECT_FALSE(v.ValidateConstructedTypes(program->AST().ConstructedTypes()));
EXPECT_EQ(v.error(),
"v-0031: a struct containing a runtime-sized array must be "
"in the 'storage' storage class: 'Foo'");
@@ -102,8 +104,9 @@ TEST_F(ValidatorTypeTest, RuntimeArrayIsNotLast_Fail) {
AST().AddConstructedType(struct_type);
ValidatorImpl& v = Build();
const Program* program = v.program();
EXPECT_FALSE(v.ValidateConstructedTypes(AST().ConstructedTypes()));
EXPECT_FALSE(v.ValidateConstructedTypes(program->AST().ConstructedTypes()));
EXPECT_EQ(v.error(),
"12:34 v-0015: runtime arrays may only appear as the last member "
"of a struct");
@@ -128,8 +131,9 @@ TEST_F(ValidatorTypeTest, AliasRuntimeArrayIsNotLast_Fail) {
AST().AddConstructedType(struct_type);
ValidatorImpl& v = Build();
const Program* program = v.program();
EXPECT_FALSE(v.ValidateConstructedTypes(AST().ConstructedTypes()));
EXPECT_FALSE(v.ValidateConstructedTypes(program->AST().ConstructedTypes()));
EXPECT_EQ(v.error(),
"v-0015: runtime arrays may only appear as the last member "
"of a struct");
@@ -154,8 +158,9 @@ TEST_F(ValidatorTypeTest, AliasRuntimeArrayIsLast_Pass) {
AST().AddConstructedType(struct_type);
ValidatorImpl& v = Build();
const Program* program = v.program();
EXPECT_TRUE(v.ValidateConstructedTypes(AST().ConstructedTypes()));
EXPECT_TRUE(v.ValidateConstructedTypes(program->AST().ConstructedTypes()));
}
TEST_F(ValidatorTypeTest, RuntimeArrayInFunction_Fail) {