dawn-cmake/src/program_builder.cc

105 lines
3.1 KiB
C++
Raw Normal View History

// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/program_builder.h"
Simplify usage of the TypeDeterminer in tests Make private all TypeDeterminer::DetermineXXX() methods, forcing all tests to use the root-level TypeDeterminer::Determine() method. Remove TypeDeterminer::RegisterVariableForTesting(). The main use for calling the TypeDeterminer::DetermineXXX() methods was to perform type determination on a partial AST. This was messy and often resulting in multiple calls into TypeDeterminer. Most tests already perform a full TypeDeterminer::Determine() call when the program is built, so many of these were redundant. The exposure of these internal methods for testing also makes refactoring the TypeDeterminer extremely difficult. Add a number of ProgramBuilder helper methods for attaching the partial AST in these tests to the root of the AST, greatly simplifying the use of the TypeDeterminer: * ProgramBuilder::Global() and ProgramBuilder::GlobalConst() are helpers that register the variable returned by ProgramBuilder::Var() and ProgramBuilder::Const(), respectively. * ProgramBuilder::WrapInFunction() is a variadic function that accepts variables, expressions and statements, attaching these to the root of the AST via a dummy function. Most test classes now no longer use their own TypeDeterminer, and instead properly depend on the automatic type determination performed at Program build time. Bug: tint:390 Change-Id: Ie901890420c5de170cdf2a7aaef9b96fc3bebd60 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/40062 Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: David Neto <dneto@google.com>
2021-02-03 17:19:59 +00:00
#include "src/ast/assignment_statement.h"
#include "src/ast/variable_decl_statement.h"
#include "src/demangler.h"
#include "src/semantic/expression.h"
namespace tint {
ProgramBuilder::ProgramBuilder()
: ast_(ast_nodes_.Create<ast::Module>(Source{})) {}
ProgramBuilder::ProgramBuilder(ProgramBuilder&& rhs)
: types_(std::move(rhs.types_)),
ast_nodes_(std::move(rhs.ast_nodes_)),
sem_nodes_(std::move(rhs.sem_nodes_)),
ast_(rhs.ast_),
sem_(std::move(rhs.sem_)),
symbols_(std::move(rhs.symbols_)) {
rhs.MarkAsMoved();
}
ProgramBuilder::~ProgramBuilder() = default;
ProgramBuilder& ProgramBuilder::operator=(ProgramBuilder&& rhs) {
rhs.MarkAsMoved();
AssertNotMoved();
types_ = std::move(rhs.types_);
ast_nodes_ = std::move(rhs.ast_nodes_);
sem_nodes_ = std::move(rhs.sem_nodes_);
ast_ = rhs.ast_;
sem_ = std::move(rhs.sem_);
symbols_ = std::move(rhs.symbols_);
return *this;
}
ProgramBuilder ProgramBuilder::Wrap(const Program* program) {
ProgramBuilder builder;
builder.types_ = type::Manager::Wrap(program->Types());
builder.ast_ = builder.create<ast::Module>(
program->AST().source(), program->AST().GlobalDeclarations());
builder.sem_ = semantic::Info::Wrap(program->Sem());
builder.symbols_ = program->Symbols();
builder.diagnostics_ = program->Diagnostics();
return builder;
}
bool ProgramBuilder::IsValid() const {
ast: Replace IsValid() with TINT_ASSERT() The readers must not produce invalid ASTs. If readers cannot produce a valid AST, then they should error instead. If a reader does produce an invalid AST, this change catches this bad behavior early, significantly helping identify the root of the broken logic. IsValid() made a bit more sense in the days where the AST was mutable, and was constructed by calling setters on the nodes to build up the tree. In order to detect bad ASTs, IsValid() would have to perform an entire AST traversal and give a yes / no answer for the entire tree. Not only was this slow, an answer of 'no' didn't tell you *where* the AST was invalid, resulting in a lot of manual debugging. Now that the AST is fully immutable, all child nodes need to be built before their parents. The AST node constructors now become a perfect place to perform pointer sanity checking. The argument for attempting to catch and handle invalid ASTs is not a compelling one. Invalid ASTs are invalid compiler behavior, not something that should ever happen with a correctly functioning compiler. If this were to happen in production, the user would be utterly clueless to _why_ the program is invalid, or _how_ to fix it. Attempting to handle invalid ASTs is just masking a much larger problem. Let's just let the fuzzers do their job to catch any of these cases early. Fixed: chromium:1185569 Change-Id: I6496426a3a9da9d42627d2c1ca23917bfd04cc5c Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/44048 Commit-Queue: Ben Clayton <bclayton@chromium.org> Reviewed-by: David Neto <dneto@google.com>
2021-03-10 11:41:49 +00:00
return !diagnostics_.contains_errors();
}
std::string ProgramBuilder::str(const ast::Node* node) const {
return Demangler().Demangle(Symbols(), node->str(Sem()));
}
void ProgramBuilder::MarkAsMoved() {
AssertNotMoved();
moved_ = true;
}
void ProgramBuilder::AssertNotMoved() const {
assert(!moved_);
}
type::Type* ProgramBuilder::TypeOf(ast::Expression* expr) const {
auto* sem = Sem().Get(expr);
return sem ? sem->Type() : nullptr;
}
ProgramBuilder::TypesBuilder::TypesBuilder(ProgramBuilder* pb) : builder(pb) {}
Simplify usage of the TypeDeterminer in tests Make private all TypeDeterminer::DetermineXXX() methods, forcing all tests to use the root-level TypeDeterminer::Determine() method. Remove TypeDeterminer::RegisterVariableForTesting(). The main use for calling the TypeDeterminer::DetermineXXX() methods was to perform type determination on a partial AST. This was messy and often resulting in multiple calls into TypeDeterminer. Most tests already perform a full TypeDeterminer::Determine() call when the program is built, so many of these were redundant. The exposure of these internal methods for testing also makes refactoring the TypeDeterminer extremely difficult. Add a number of ProgramBuilder helper methods for attaching the partial AST in these tests to the root of the AST, greatly simplifying the use of the TypeDeterminer: * ProgramBuilder::Global() and ProgramBuilder::GlobalConst() are helpers that register the variable returned by ProgramBuilder::Var() and ProgramBuilder::Const(), respectively. * ProgramBuilder::WrapInFunction() is a variadic function that accepts variables, expressions and statements, attaching these to the root of the AST via a dummy function. Most test classes now no longer use their own TypeDeterminer, and instead properly depend on the automatic type determination performed at Program build time. Bug: tint:390 Change-Id: Ie901890420c5de170cdf2a7aaef9b96fc3bebd60 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/40062 Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: David Neto <dneto@google.com>
2021-02-03 17:19:59 +00:00
ast::VariableDeclStatement* ProgramBuilder::WrapInStatement(ast::Variable* v) {
return create<ast::VariableDeclStatement>(v);
}
ast::Statement* ProgramBuilder::WrapInStatement(ast::Expression* expr) {
// TODO(ben-clayton): This is valid enough for the Resolver, but the LHS
Simplify usage of the TypeDeterminer in tests Make private all TypeDeterminer::DetermineXXX() methods, forcing all tests to use the root-level TypeDeterminer::Determine() method. Remove TypeDeterminer::RegisterVariableForTesting(). The main use for calling the TypeDeterminer::DetermineXXX() methods was to perform type determination on a partial AST. This was messy and often resulting in multiple calls into TypeDeterminer. Most tests already perform a full TypeDeterminer::Determine() call when the program is built, so many of these were redundant. The exposure of these internal methods for testing also makes refactoring the TypeDeterminer extremely difficult. Add a number of ProgramBuilder helper methods for attaching the partial AST in these tests to the root of the AST, greatly simplifying the use of the TypeDeterminer: * ProgramBuilder::Global() and ProgramBuilder::GlobalConst() are helpers that register the variable returned by ProgramBuilder::Var() and ProgramBuilder::Const(), respectively. * ProgramBuilder::WrapInFunction() is a variadic function that accepts variables, expressions and statements, attaching these to the root of the AST via a dummy function. Most test classes now no longer use their own TypeDeterminer, and instead properly depend on the automatic type determination performed at Program build time. Bug: tint:390 Change-Id: Ie901890420c5de170cdf2a7aaef9b96fc3bebd60 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/40062 Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: David Neto <dneto@google.com>
2021-02-03 17:19:59 +00:00
// may not be assignable, and so may not validate.
return create<ast::AssignmentStatement>(expr, expr);
}
ast::Statement* ProgramBuilder::WrapInStatement(ast::Statement* stmt) {
return stmt;
}
ast::Function* ProgramBuilder::WrapInFunction(ast::StatementList stmts) {
return Func("test_function", {}, ty.void_(), std::move(stmts), {});
}
} // namespace tint