[tint] Split sem methods to a helper.
This CL moves the various sem methods in the resolver to a helper class. Bug: tint:1313 Change-Id: I1f5e77a7864935d44d327b2b8462f931d46977ca Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/87149 Reviewed-by: Ben Clayton <bclayton@google.com> Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
d58820a330
commit
bb62ef0d2c
|
@ -377,6 +377,8 @@ libtint_source_set("libtint_core_all_src") {
|
||||||
"resolver/resolver.h",
|
"resolver/resolver.h",
|
||||||
"resolver/resolver_constants.cc",
|
"resolver/resolver_constants.cc",
|
||||||
"resolver/resolver_validation.cc",
|
"resolver/resolver_validation.cc",
|
||||||
|
"resolver/sem_helper.cc",
|
||||||
|
"resolver/sem_helper.h",
|
||||||
"scope_stack.h",
|
"scope_stack.h",
|
||||||
"sem/array.h",
|
"sem/array.h",
|
||||||
"sem/atomic_type.h",
|
"sem/atomic_type.h",
|
||||||
|
|
|
@ -258,6 +258,8 @@ set(TINT_LIB_SRCS
|
||||||
resolver/resolver_constants.cc
|
resolver/resolver_constants.cc
|
||||||
resolver/resolver_validation.cc
|
resolver/resolver_validation.cc
|
||||||
resolver/resolver.h
|
resolver/resolver.h
|
||||||
|
resolver/sem_helper.cc
|
||||||
|
resolver/sem_helper.h
|
||||||
scope_stack.h
|
scope_stack.h
|
||||||
sem/array.cc
|
sem/array.cc
|
||||||
sem/array.h
|
sem/array.h
|
||||||
|
|
|
@ -84,7 +84,8 @@ namespace tint::resolver {
|
||||||
Resolver::Resolver(ProgramBuilder* builder)
|
Resolver::Resolver(ProgramBuilder* builder)
|
||||||
: builder_(builder),
|
: builder_(builder),
|
||||||
diagnostics_(builder->Diagnostics()),
|
diagnostics_(builder->Diagnostics()),
|
||||||
builtin_table_(BuiltinTable::Create(*builder)) {}
|
builtin_table_(BuiltinTable::Create(*builder)),
|
||||||
|
sem_(builder) {}
|
||||||
|
|
||||||
Resolver::~Resolver() = default;
|
Resolver::~Resolver() = default;
|
||||||
|
|
||||||
|
@ -505,7 +506,7 @@ void Resolver::AllocateOverridableConstantIds() {
|
||||||
next_constant_id = constant_id + 1;
|
next_constant_id = constant_id + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* sem = Sem<sem::GlobalVariable>(var);
|
auto* sem = sem_.Get<sem::GlobalVariable>(var);
|
||||||
const_cast<sem::GlobalVariable*>(sem)->SetConstantId(constant_id);
|
const_cast<sem::GlobalVariable*>(sem)->SetConstantId(constant_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -513,9 +514,11 @@ void Resolver::AllocateOverridableConstantIds() {
|
||||||
void Resolver::SetShadows() {
|
void Resolver::SetShadows() {
|
||||||
for (auto it : dependencies_.shadows) {
|
for (auto it : dependencies_.shadows) {
|
||||||
Switch(
|
Switch(
|
||||||
Sem(it.first), //
|
sem_.Get(it.first), //
|
||||||
[&](sem::LocalVariable* local) { local->SetShadows(Sem(it.second)); },
|
[&](sem::LocalVariable* local) {
|
||||||
[&](sem::Parameter* param) { param->SetShadows(Sem(it.second)); });
|
local->SetShadows(sem_.Get(it.second));
|
||||||
|
},
|
||||||
|
[&](sem::Parameter* param) { param->SetShadows(sem_.Get(it.second)); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -755,7 +758,7 @@ bool Resolver::WorkgroupSize(const ast::Function* func) {
|
||||||
"workgroup_size arguments must be of the same type, either i32 "
|
"workgroup_size arguments must be of the same type, either i32 "
|
||||||
"or u32";
|
"or u32";
|
||||||
|
|
||||||
auto* ty = TypeOf(expr);
|
auto* ty = sem_.TypeOf(expr);
|
||||||
bool is_i32 = ty->UnwrapRef()->Is<sem::I32>();
|
bool is_i32 = ty->UnwrapRef()->Is<sem::I32>();
|
||||||
bool is_u32 = ty->UnwrapRef()->Is<sem::U32>();
|
bool is_u32 = ty->UnwrapRef()->Is<sem::U32>();
|
||||||
if (!is_i32 && !is_u32) {
|
if (!is_i32 && !is_u32) {
|
||||||
|
@ -772,7 +775,7 @@ bool Resolver::WorkgroupSize(const ast::Function* func) {
|
||||||
|
|
||||||
sem::Constant value;
|
sem::Constant value;
|
||||||
|
|
||||||
if (auto* user = Sem(expr)->As<sem::VariableUser>()) {
|
if (auto* user = sem_.Get(expr)->As<sem::VariableUser>()) {
|
||||||
// We have an variable of a module-scope constant.
|
// We have an variable of a module-scope constant.
|
||||||
auto* decl = user->Variable()->Declaration();
|
auto* decl = user->Variable()->Declaration();
|
||||||
if (!decl->is_const) {
|
if (!decl->is_const) {
|
||||||
|
@ -785,14 +788,14 @@ bool Resolver::WorkgroupSize(const ast::Function* func) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decl->constructor) {
|
if (decl->constructor) {
|
||||||
value = Sem(decl->constructor)->ConstantValue();
|
value = sem_.Get(decl->constructor)->ConstantValue();
|
||||||
} else {
|
} else {
|
||||||
// No constructor means this value must be overriden by the user.
|
// No constructor means this value must be overriden by the user.
|
||||||
ws[i].value = 0;
|
ws[i].value = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (expr->Is<ast::LiteralExpression>()) {
|
} else if (expr->Is<ast::LiteralExpression>()) {
|
||||||
value = Sem(expr)->ConstantValue();
|
value = sem_.Get(expr)->ConstantValue();
|
||||||
} else {
|
} else {
|
||||||
AddError(
|
AddError(
|
||||||
"workgroup_size argument must be either a literal or a "
|
"workgroup_size argument must be either a literal or a "
|
||||||
|
@ -1168,8 +1171,8 @@ sem::Expression* Resolver::Expression(const ast::Expression* root) {
|
||||||
|
|
||||||
sem::Expression* Resolver::IndexAccessor(
|
sem::Expression* Resolver::IndexAccessor(
|
||||||
const ast::IndexAccessorExpression* expr) {
|
const ast::IndexAccessorExpression* expr) {
|
||||||
auto* idx = Sem(expr->index);
|
auto* idx = sem_.Get(expr->index);
|
||||||
auto* obj = Sem(expr->object);
|
auto* obj = sem_.Get(expr->object);
|
||||||
auto* obj_raw_ty = obj->Type();
|
auto* obj_raw_ty = obj->Type();
|
||||||
auto* obj_ty = obj_raw_ty->UnwrapRef();
|
auto* obj_ty = obj_raw_ty->UnwrapRef();
|
||||||
auto* ty = Switch(
|
auto* ty = Switch(
|
||||||
|
@ -1180,7 +1183,7 @@ sem::Expression* Resolver::IndexAccessor(
|
||||||
return builder_->create<sem::Vector>(mat->type(), mat->rows());
|
return builder_->create<sem::Vector>(mat->type(), mat->rows());
|
||||||
},
|
},
|
||||||
[&](Default) {
|
[&](Default) {
|
||||||
AddError("cannot index type '" + TypeNameOf(obj_ty) + "'",
|
AddError("cannot index type '" + sem_.TypeNameOf(obj_ty) + "'",
|
||||||
expr->source);
|
expr->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
});
|
});
|
||||||
|
@ -1191,7 +1194,7 @@ sem::Expression* Resolver::IndexAccessor(
|
||||||
auto* idx_ty = idx->Type()->UnwrapRef();
|
auto* idx_ty = idx->Type()->UnwrapRef();
|
||||||
if (!idx_ty->IsAnyOf<sem::I32, sem::U32>()) {
|
if (!idx_ty->IsAnyOf<sem::I32, sem::U32>()) {
|
||||||
AddError("index must be of type 'i32' or 'u32', found: '" +
|
AddError("index must be of type 'i32' or 'u32', found: '" +
|
||||||
TypeNameOf(idx_ty) + "'",
|
sem_.TypeNameOf(idx_ty) + "'",
|
||||||
idx->Declaration()->source);
|
idx->Declaration()->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -1211,7 +1214,7 @@ sem::Expression* Resolver::IndexAccessor(
|
||||||
}
|
}
|
||||||
|
|
||||||
sem::Expression* Resolver::Bitcast(const ast::BitcastExpression* expr) {
|
sem::Expression* Resolver::Bitcast(const ast::BitcastExpression* expr) {
|
||||||
auto* inner = Sem(expr->expr);
|
auto* inner = sem_.Get(expr->expr);
|
||||||
auto* ty = Type(expr->type);
|
auto* ty = Type(expr->type);
|
||||||
if (!ty) {
|
if (!ty) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -1240,7 +1243,7 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
|
||||||
const sem::Type* arg_el_ty = nullptr;
|
const sem::Type* arg_el_ty = nullptr;
|
||||||
|
|
||||||
for (size_t i = 0; i < expr->args.size(); i++) {
|
for (size_t i = 0; i < expr->args.size(); i++) {
|
||||||
auto* arg = Sem(expr->args[i]);
|
auto* arg = sem_.Get(expr->args[i]);
|
||||||
if (!arg) {
|
if (!arg) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -1637,7 +1640,7 @@ sem::Call* Resolver::TypeConstructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
sem::Expression* Resolver::Literal(const ast::LiteralExpression* literal) {
|
sem::Expression* Resolver::Literal(const ast::LiteralExpression* literal) {
|
||||||
auto* ty = TypeOf(literal);
|
auto* ty = sem_.TypeOf(literal);
|
||||||
if (!ty) {
|
if (!ty) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -1725,14 +1728,14 @@ sem::Expression* Resolver::Identifier(const ast::IdentifierExpression* expr) {
|
||||||
|
|
||||||
sem::Expression* Resolver::MemberAccessor(
|
sem::Expression* Resolver::MemberAccessor(
|
||||||
const ast::MemberAccessorExpression* expr) {
|
const ast::MemberAccessorExpression* expr) {
|
||||||
auto* structure = TypeOf(expr->structure);
|
auto* structure = sem_.TypeOf(expr->structure);
|
||||||
auto* storage_ty = structure->UnwrapRef();
|
auto* storage_ty = structure->UnwrapRef();
|
||||||
|
|
||||||
const sem::Type* ret = nullptr;
|
const sem::Type* ret = nullptr;
|
||||||
std::vector<uint32_t> swizzle;
|
std::vector<uint32_t> swizzle;
|
||||||
|
|
||||||
// Structure may be a side-effecting expression (e.g. function call).
|
// Structure may be a side-effecting expression (e.g. function call).
|
||||||
auto* sem_structure = Sem(expr->structure);
|
auto* sem_structure = sem_.Get(expr->structure);
|
||||||
bool has_side_effects = sem_structure && sem_structure->HasSideEffects();
|
bool has_side_effects = sem_structure && sem_structure->HasSideEffects();
|
||||||
|
|
||||||
if (auto* str = storage_ty->As<sem::Struct>()) {
|
if (auto* str = storage_ty->As<sem::Struct>()) {
|
||||||
|
@ -1840,14 +1843,14 @@ sem::Expression* Resolver::MemberAccessor(
|
||||||
|
|
||||||
AddError(
|
AddError(
|
||||||
"invalid member accessor expression. Expected vector or struct, got '" +
|
"invalid member accessor expression. Expected vector or struct, got '" +
|
||||||
TypeNameOf(storage_ty) + "'",
|
sem_.TypeNameOf(storage_ty) + "'",
|
||||||
expr->structure->source);
|
expr->structure->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
sem::Expression* Resolver::Binary(const ast::BinaryExpression* expr) {
|
sem::Expression* Resolver::Binary(const ast::BinaryExpression* expr) {
|
||||||
auto* lhs = Sem(expr->lhs);
|
auto* lhs = sem_.Get(expr->lhs);
|
||||||
auto* rhs = Sem(expr->rhs);
|
auto* rhs = sem_.Get(expr->rhs);
|
||||||
auto* lhs_ty = lhs->Type()->UnwrapRef();
|
auto* lhs_ty = lhs->Type()->UnwrapRef();
|
||||||
auto* rhs_ty = rhs->Type()->UnwrapRef();
|
auto* rhs_ty = rhs->Type()->UnwrapRef();
|
||||||
|
|
||||||
|
@ -1855,8 +1858,8 @@ sem::Expression* Resolver::Binary(const ast::BinaryExpression* expr) {
|
||||||
if (!ty) {
|
if (!ty) {
|
||||||
AddError(
|
AddError(
|
||||||
"Binary expression operand types are invalid for this operation: " +
|
"Binary expression operand types are invalid for this operation: " +
|
||||||
TypeNameOf(lhs_ty) + " " + FriendlyName(expr->op) + " " +
|
sem_.TypeNameOf(lhs_ty) + " " + FriendlyName(expr->op) + " " +
|
||||||
TypeNameOf(rhs_ty),
|
sem_.TypeNameOf(rhs_ty),
|
||||||
expr->source);
|
expr->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2036,7 +2039,7 @@ const sem::Type* Resolver::BinaryOpType(const sem::Type* lhs_ty,
|
||||||
}
|
}
|
||||||
|
|
||||||
sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
||||||
auto* expr = Sem(unary->expr);
|
auto* expr = sem_.Get(unary->expr);
|
||||||
auto* expr_ty = expr->Type();
|
auto* expr_ty = expr->Type();
|
||||||
if (!expr_ty) {
|
if (!expr_ty) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -2049,8 +2052,8 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
||||||
// Result type matches the deref'd inner type.
|
// Result type matches the deref'd inner type.
|
||||||
ty = expr_ty->UnwrapRef();
|
ty = expr_ty->UnwrapRef();
|
||||||
if (!ty->Is<sem::Bool>() && !ty->is_bool_vector()) {
|
if (!ty->Is<sem::Bool>() && !ty->is_bool_vector()) {
|
||||||
AddError(
|
AddError("cannot logical negate expression of type '" +
|
||||||
"cannot logical negate expression of type '" + TypeNameOf(expr_ty),
|
sem_.TypeNameOf(expr_ty),
|
||||||
unary->expr->source);
|
unary->expr->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2061,7 +2064,7 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
||||||
ty = expr_ty->UnwrapRef();
|
ty = expr_ty->UnwrapRef();
|
||||||
if (!ty->is_integer_scalar_or_vector()) {
|
if (!ty->is_integer_scalar_or_vector()) {
|
||||||
AddError("cannot bitwise complement expression of type '" +
|
AddError("cannot bitwise complement expression of type '" +
|
||||||
TypeNameOf(expr_ty),
|
sem_.TypeNameOf(expr_ty),
|
||||||
unary->expr->source);
|
unary->expr->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2072,7 +2075,8 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
||||||
ty = expr_ty->UnwrapRef();
|
ty = expr_ty->UnwrapRef();
|
||||||
if (!(ty->IsAnyOf<sem::F32, sem::I32>() ||
|
if (!(ty->IsAnyOf<sem::F32, sem::I32>() ||
|
||||||
ty->is_signed_integer_vector() || ty->is_float_vector())) {
|
ty->is_signed_integer_vector() || ty->is_float_vector())) {
|
||||||
AddError("cannot negate expression of type '" + TypeNameOf(expr_ty),
|
AddError(
|
||||||
|
"cannot negate expression of type '" + sem_.TypeNameOf(expr_ty),
|
||||||
unary->expr->source);
|
unary->expr->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2089,9 +2093,10 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
||||||
|
|
||||||
auto* array = unary->expr->As<ast::IndexAccessorExpression>();
|
auto* array = unary->expr->As<ast::IndexAccessorExpression>();
|
||||||
auto* member = unary->expr->As<ast::MemberAccessorExpression>();
|
auto* member = unary->expr->As<ast::MemberAccessorExpression>();
|
||||||
if ((array && TypeOf(array->object)->UnwrapRef()->Is<sem::Vector>()) ||
|
if ((array &&
|
||||||
|
sem_.TypeOf(array->object)->UnwrapRef()->Is<sem::Vector>()) ||
|
||||||
(member &&
|
(member &&
|
||||||
TypeOf(member->structure)->UnwrapRef()->Is<sem::Vector>())) {
|
sem_.TypeOf(member->structure)->UnwrapRef()->Is<sem::Vector>())) {
|
||||||
AddError("cannot take the address of a vector component",
|
AddError("cannot take the address of a vector component",
|
||||||
unary->expr->source);
|
unary->expr->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -2111,7 +2116,7 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
||||||
ptr->StoreType(), ptr->StorageClass(), ptr->Access());
|
ptr->StoreType(), ptr->StorageClass(), ptr->Access());
|
||||||
} else {
|
} else {
|
||||||
AddError("cannot dereference expression of type '" +
|
AddError("cannot dereference expression of type '" +
|
||||||
TypeNameOf(expr_ty) + "'",
|
sem_.TypeNameOf(expr_ty) + "'",
|
||||||
unary->expr->source);
|
unary->expr->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2143,41 +2148,6 @@ sem::Type* Resolver::TypeDecl(const ast::TypeDecl* named_type) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Resolver::TypeNameOf(const sem::Type* ty) const {
|
|
||||||
return RawTypeNameOf(ty->UnwrapRef());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Resolver::RawTypeNameOf(const sem::Type* ty) const {
|
|
||||||
return ty->FriendlyName(builder_->Symbols());
|
|
||||||
}
|
|
||||||
|
|
||||||
sem::Type* Resolver::TypeOf(const ast::Expression* expr) const {
|
|
||||||
auto* sem = Sem(expr);
|
|
||||||
return sem ? const_cast<sem::Type*>(sem->Type()) : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
sem::Type* Resolver::TypeOf(const ast::LiteralExpression* lit) {
|
|
||||||
return Switch(
|
|
||||||
lit,
|
|
||||||
[&](const ast::SintLiteralExpression*) {
|
|
||||||
return builder_->create<sem::I32>();
|
|
||||||
},
|
|
||||||
[&](const ast::UintLiteralExpression*) {
|
|
||||||
return builder_->create<sem::U32>();
|
|
||||||
},
|
|
||||||
[&](const ast::FloatLiteralExpression*) {
|
|
||||||
return builder_->create<sem::F32>();
|
|
||||||
},
|
|
||||||
[&](const ast::BoolLiteralExpression*) {
|
|
||||||
return builder_->create<sem::Bool>();
|
|
||||||
},
|
|
||||||
[&](Default) {
|
|
||||||
TINT_UNREACHABLE(Resolver, diagnostics_)
|
|
||||||
<< "Unhandled literal type: " << lit->TypeInfo().name;
|
|
||||||
return nullptr;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
sem::Array* Resolver::Array(const ast::Array* arr) {
|
sem::Array* Resolver::Array(const ast::Array* arr) {
|
||||||
auto source = arr->source;
|
auto source = arr->source;
|
||||||
|
|
||||||
|
@ -2187,7 +2157,7 @@ sem::Array* Resolver::Array(const ast::Array* arr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsPlain(elem_type)) { // Check must come before GetDefaultAlignAndSize()
|
if (!IsPlain(elem_type)) { // Check must come before GetDefaultAlignAndSize()
|
||||||
AddError(TypeNameOf(elem_type) +
|
AddError(sem_.TypeNameOf(elem_type) +
|
||||||
" cannot be used as an element type of an array",
|
" cannot be used as an element type of an array",
|
||||||
source);
|
source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -2367,7 +2337,7 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
|
||||||
|
|
||||||
// Validate member type
|
// Validate member type
|
||||||
if (!IsPlain(type)) {
|
if (!IsPlain(type)) {
|
||||||
AddError(TypeNameOf(type) +
|
AddError(sem_.TypeNameOf(type) +
|
||||||
" cannot be used as the type of a structure member",
|
" cannot be used as the type of a structure member",
|
||||||
member->source);
|
member->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -2507,7 +2477,7 @@ sem::Statement* Resolver::ReturnStatement(const ast::ReturnStatement* stmt) {
|
||||||
|
|
||||||
// Validate after processing the return value expression so that its type
|
// Validate after processing the return value expression so that its type
|
||||||
// is available for validation.
|
// is available for validation.
|
||||||
auto* ret_type = stmt->value ? TypeOf(stmt->value)->UnwrapRef()
|
auto* ret_type = stmt->value ? sem_.TypeOf(stmt->value)->UnwrapRef()
|
||||||
: builder_->create<sem::Void>();
|
: builder_->create<sem::Void>();
|
||||||
return ValidateReturn(stmt, current_function_->ReturnType(), ret_type);
|
return ValidateReturn(stmt, current_function_->ReturnType(), ret_type);
|
||||||
});
|
});
|
||||||
|
@ -2597,7 +2567,7 @@ sem::Statement* Resolver::AssignmentStatement(
|
||||||
behaviors.Add(lhs->Behaviors());
|
behaviors.Add(lhs->Behaviors());
|
||||||
}
|
}
|
||||||
|
|
||||||
return ValidateAssignment(stmt, TypeOf(stmt->rhs));
|
return ValidateAssignment(stmt, sem_.TypeOf(stmt->rhs));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2645,8 +2615,8 @@ sem::Statement* Resolver::CompoundAssignmentStatement(
|
||||||
auto* ty = BinaryOpType(lhs_ty, rhs_ty, stmt->op);
|
auto* ty = BinaryOpType(lhs_ty, rhs_ty, stmt->op);
|
||||||
if (!ty) {
|
if (!ty) {
|
||||||
AddError("compound assignment operand types are invalid: " +
|
AddError("compound assignment operand types are invalid: " +
|
||||||
TypeNameOf(lhs_ty) + " " + FriendlyName(stmt->op) + " " +
|
sem_.TypeNameOf(lhs_ty) + " " + FriendlyName(stmt->op) +
|
||||||
TypeNameOf(rhs_ty),
|
" " + sem_.TypeNameOf(rhs_ty),
|
||||||
stmt->source);
|
stmt->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2725,7 +2695,8 @@ bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc,
|
||||||
for (auto* member : str->Members()) {
|
for (auto* member : str->Members()) {
|
||||||
if (!ApplyStorageClassUsageToType(sc, member->Type(), usage)) {
|
if (!ApplyStorageClassUsageToType(sc, member->Type(), usage)) {
|
||||||
std::stringstream err;
|
std::stringstream err;
|
||||||
err << "while analysing structure member " << TypeNameOf(str) << "."
|
err << "while analysing structure member " << sem_.TypeNameOf(str)
|
||||||
|
<< "."
|
||||||
<< builder_->Symbols().NameFor(member->Declaration()->symbol);
|
<< builder_->Symbols().NameFor(member->Declaration()->symbol);
|
||||||
AddNote(err.str(), member->Declaration()->source);
|
AddNote(err.str(), member->Declaration()->source);
|
||||||
return false;
|
return false;
|
||||||
|
@ -2749,8 +2720,9 @@ bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc,
|
||||||
|
|
||||||
if (ast::IsHostShareable(sc) && !IsHostShareable(ty)) {
|
if (ast::IsHostShareable(sc) && !IsHostShareable(ty)) {
|
||||||
std::stringstream err;
|
std::stringstream err;
|
||||||
err << "Type '" << TypeNameOf(ty) << "' cannot be used in storage class '"
|
err << "Type '" << sem_.TypeNameOf(ty)
|
||||||
<< sc << "' as it is non-host-shareable";
|
<< "' cannot be used in storage class '" << sc
|
||||||
|
<< "' as it is non-host-shareable";
|
||||||
AddError(err.str(), usage);
|
AddError(err.str(), usage);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "src/tint/builtin_table.h"
|
#include "src/tint/builtin_table.h"
|
||||||
#include "src/tint/program_builder.h"
|
#include "src/tint/program_builder.h"
|
||||||
#include "src/tint/resolver/dependency_graph.h"
|
#include "src/tint/resolver/dependency_graph.h"
|
||||||
|
#include "src/tint/resolver/sem_helper.h"
|
||||||
#include "src/tint/scope_stack.h"
|
#include "src/tint/scope_stack.h"
|
||||||
#include "src/tint/sem/binding_point.h"
|
#include "src/tint/sem/binding_point.h"
|
||||||
#include "src/tint/sem/block_statement.h"
|
#include "src/tint/sem/block_statement.h"
|
||||||
|
@ -405,23 +406,6 @@ class Resolver {
|
||||||
/// Set the shadowing information on variable declarations.
|
/// Set the shadowing information on variable declarations.
|
||||||
/// @note this method must only be called after all semantic nodes are built.
|
/// @note this method must only be called after all semantic nodes are built.
|
||||||
void SetShadows();
|
void SetShadows();
|
||||||
|
|
||||||
/// @returns the resolved type of the ast::Expression `expr`
|
|
||||||
/// @param expr the expression
|
|
||||||
sem::Type* TypeOf(const ast::Expression* expr) const;
|
|
||||||
|
|
||||||
/// @returns the type name of the given semantic type, unwrapping
|
|
||||||
/// references.
|
|
||||||
std::string TypeNameOf(const sem::Type* ty) const;
|
|
||||||
|
|
||||||
/// @returns the type name of the given semantic type, without unwrapping
|
|
||||||
/// references.
|
|
||||||
std::string RawTypeNameOf(const sem::Type* ty) const;
|
|
||||||
|
|
||||||
/// @returns the semantic type of the AST literal `lit`
|
|
||||||
/// @param lit the literal
|
|
||||||
sem::Type* TypeOf(const ast::LiteralExpression* lit);
|
|
||||||
|
|
||||||
/// StatementScope() does the following:
|
/// StatementScope() does the following:
|
||||||
/// * Creates the AST -> SEM mapping.
|
/// * Creates the AST -> SEM mapping.
|
||||||
/// * Assigns `sem` to #current_statement_
|
/// * Assigns `sem` to #current_statement_
|
||||||
|
@ -467,21 +451,6 @@ class Resolver {
|
||||||
sem::Constant EvaluateConstantValue(const ast::CallExpression* call,
|
sem::Constant EvaluateConstantValue(const ast::CallExpression* call,
|
||||||
const sem::Type* type);
|
const sem::Type* type);
|
||||||
|
|
||||||
/// Sem is a helper for obtaining the semantic node for the given AST node.
|
|
||||||
template <typename SEM = sem::Info::InferFromAST,
|
|
||||||
typename AST_OR_TYPE = CastableBase>
|
|
||||||
auto* Sem(const AST_OR_TYPE* ast) const {
|
|
||||||
using T = sem::Info::GetResultType<SEM, AST_OR_TYPE>;
|
|
||||||
auto* sem = builder_->Sem().Get(ast);
|
|
||||||
if (!sem) {
|
|
||||||
TINT_ICE(Resolver, diagnostics_)
|
|
||||||
<< "AST node '" << ast->TypeInfo().name << "' had no semantic info\n"
|
|
||||||
<< "At: " << ast->source << "\n"
|
|
||||||
<< "Pointer: " << ast;
|
|
||||||
}
|
|
||||||
return const_cast<T*>(As<T>(sem));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @returns true if the symbol is the name of a builtin function.
|
/// @returns true if the symbol is the name of a builtin function.
|
||||||
bool IsBuiltin(Symbol) const;
|
bool IsBuiltin(Symbol) const;
|
||||||
|
|
||||||
|
@ -541,6 +510,7 @@ class Resolver {
|
||||||
diag::List& diagnostics_;
|
diag::List& diagnostics_;
|
||||||
std::unique_ptr<BuiltinTable> const builtin_table_;
|
std::unique_ptr<BuiltinTable> const builtin_table_;
|
||||||
DependencyGraph dependencies_;
|
DependencyGraph dependencies_;
|
||||||
|
SemHelper sem_;
|
||||||
std::vector<sem::Function*> entry_points_;
|
std::vector<sem::Function*> entry_points_;
|
||||||
std::unordered_map<const sem::Type*, const Source&> atomic_composite_info_;
|
std::unordered_map<const sem::Type*, const Source&> atomic_composite_info_;
|
||||||
std::unordered_set<const ast::Node*> marked_;
|
std::unordered_set<const ast::Node*> marked_;
|
||||||
|
|
|
@ -201,8 +201,8 @@ bool Resolver::ValidateVariableConstructorOrCast(
|
||||||
if (storage_ty != value_type) {
|
if (storage_ty != value_type) {
|
||||||
std::string decl = var->is_const ? "let" : "var";
|
std::string decl = var->is_const ? "let" : "var";
|
||||||
AddError("cannot initialize " + decl + " of type '" +
|
AddError("cannot initialize " + decl + " of type '" +
|
||||||
TypeNameOf(storage_ty) + "' with value of type '" +
|
sem_.TypeNameOf(storage_ty) + "' with value of type '" +
|
||||||
TypeNameOf(rhs_ty) + "'",
|
sem_.TypeNameOf(rhs_ty) + "'",
|
||||||
var->source);
|
var->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -536,8 +536,8 @@ bool Resolver::ValidateAtomicVariable(const sem::Variable* var) const {
|
||||||
AddError(
|
AddError(
|
||||||
"atomic variables must have <storage> or <workgroup> storage class",
|
"atomic variables must have <storage> or <workgroup> storage class",
|
||||||
source);
|
source);
|
||||||
AddNote(
|
AddNote("atomic sub-type of '" + sem_.TypeNameOf(type) +
|
||||||
"atomic sub-type of '" + TypeNameOf(type) + "' is declared here",
|
"' is declared here",
|
||||||
found->second);
|
found->second);
|
||||||
return false;
|
return false;
|
||||||
} else if (sc == ast::StorageClass::kStorage &&
|
} else if (sc == ast::StorageClass::kStorage &&
|
||||||
|
@ -546,8 +546,8 @@ bool Resolver::ValidateAtomicVariable(const sem::Variable* var) const {
|
||||||
"atomic variables in <storage> storage class must have read_write "
|
"atomic variables in <storage> storage class must have read_write "
|
||||||
"access mode",
|
"access mode",
|
||||||
source);
|
source);
|
||||||
AddNote(
|
AddNote("atomic sub-type of '" + sem_.TypeNameOf(type) +
|
||||||
"atomic sub-type of '" + TypeNameOf(type) + "' is declared here",
|
"' is declared here",
|
||||||
found->second);
|
found->second);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -575,14 +575,16 @@ bool Resolver::ValidateVariable(const sem::Variable* var) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!decl->is_const && !IsStorable(storage_ty)) {
|
if (!decl->is_const && !IsStorable(storage_ty)) {
|
||||||
AddError(TypeNameOf(storage_ty) + " cannot be used as the type of a var",
|
AddError(
|
||||||
|
sem_.TypeNameOf(storage_ty) + " cannot be used as the type of a var",
|
||||||
decl->source);
|
decl->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decl->is_const && !var->Is<sem::Parameter>() &&
|
if (decl->is_const && !var->Is<sem::Parameter>() &&
|
||||||
!(storage_ty->IsConstructible() || storage_ty->Is<sem::Pointer>())) {
|
!(storage_ty->IsConstructible() || storage_ty->Is<sem::Pointer>())) {
|
||||||
AddError(TypeNameOf(storage_ty) + " cannot be used as the type of a let",
|
AddError(
|
||||||
|
sem_.TypeNameOf(storage_ty) + " cannot be used as the type of a let",
|
||||||
decl->source);
|
decl->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -616,7 +618,7 @@ bool Resolver::ValidateVariable(const sem::Variable* var) const {
|
||||||
// If the store type is a texture type or a sampler type, then the
|
// If the store type is a texture type or a sampler type, then the
|
||||||
// variable declaration must not have a storage class attribute. The
|
// variable declaration must not have a storage class attribute. The
|
||||||
// storage class will always be handle.
|
// storage class will always be handle.
|
||||||
AddError("variables of type '" + TypeNameOf(storage_ty) +
|
AddError("variables of type '" + sem_.TypeNameOf(storage_ty) +
|
||||||
"' must not have a storage class",
|
"' must not have a storage class",
|
||||||
decl->source);
|
decl->source);
|
||||||
return false;
|
return false;
|
||||||
|
@ -686,8 +688,8 @@ bool Resolver::ValidateFunctionParameter(const ast::Function* func,
|
||||||
}
|
}
|
||||||
} else if (!var->Type()
|
} else if (!var->Type()
|
||||||
->IsAnyOf<sem::Texture, sem::Sampler, sem::Pointer>()) {
|
->IsAnyOf<sem::Texture, sem::Sampler, sem::Pointer>()) {
|
||||||
AddError(
|
AddError("store type of function parameter cannot be " +
|
||||||
"store type of function parameter cannot be " + TypeNameOf(var->Type()),
|
sem_.TypeNameOf(var->Type()),
|
||||||
decl->source);
|
decl->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -886,7 +888,7 @@ bool Resolver::ValidateFunction(const sem::Function* func,
|
||||||
if (decl->body) {
|
if (decl->body) {
|
||||||
sem::Behaviors behaviors{sem::Behavior::kNext};
|
sem::Behaviors behaviors{sem::Behavior::kNext};
|
||||||
if (auto* last = decl->body->Last()) {
|
if (auto* last = decl->body->Last()) {
|
||||||
behaviors = Sem(last)->Behaviors();
|
behaviors = sem_.Get(last)->Behaviors();
|
||||||
}
|
}
|
||||||
if (behaviors.Contains(sem::Behavior::kNext)) {
|
if (behaviors.Contains(sem::Behavior::kNext)) {
|
||||||
AddError("missing return at end of function", decl->source);
|
AddError("missing return at end of function", decl->source);
|
||||||
|
@ -1222,7 +1224,7 @@ bool Resolver::ValidateEntryPoint(const sem::Function* func,
|
||||||
|
|
||||||
bool Resolver::ValidateStatements(const ast::StatementList& stmts) const {
|
bool Resolver::ValidateStatements(const ast::StatementList& stmts) const {
|
||||||
for (auto* stmt : stmts) {
|
for (auto* stmt : stmts) {
|
||||||
if (!Sem(stmt)->IsReachable()) {
|
if (!sem_.Get(stmt)->IsReachable()) {
|
||||||
/// TODO(https://github.com/gpuweb/gpuweb/issues/2378): This may need to
|
/// TODO(https://github.com/gpuweb/gpuweb/issues/2378): This may need to
|
||||||
/// become an error.
|
/// become an error.
|
||||||
AddWarning("code is unreachable", stmt->source);
|
AddWarning("code is unreachable", stmt->source);
|
||||||
|
@ -1234,14 +1236,15 @@ bool Resolver::ValidateStatements(const ast::StatementList& stmts) const {
|
||||||
|
|
||||||
bool Resolver::ValidateBitcast(const ast::BitcastExpression* cast,
|
bool Resolver::ValidateBitcast(const ast::BitcastExpression* cast,
|
||||||
const sem::Type* to) const {
|
const sem::Type* to) const {
|
||||||
auto* from = TypeOf(cast->expr)->UnwrapRef();
|
auto* from = sem_.TypeOf(cast->expr)->UnwrapRef();
|
||||||
if (!from->is_numeric_scalar_or_vector()) {
|
if (!from->is_numeric_scalar_or_vector()) {
|
||||||
AddError("'" + TypeNameOf(from) + "' cannot be bitcast",
|
AddError("'" + sem_.TypeNameOf(from) + "' cannot be bitcast",
|
||||||
cast->expr->source);
|
cast->expr->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!to->is_numeric_scalar_or_vector()) {
|
if (!to->is_numeric_scalar_or_vector()) {
|
||||||
AddError("cannot bitcast to '" + TypeNameOf(to) + "'", cast->type->source);
|
AddError("cannot bitcast to '" + sem_.TypeNameOf(to) + "'",
|
||||||
|
cast->type->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1253,8 +1256,8 @@ bool Resolver::ValidateBitcast(const ast::BitcastExpression* cast,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (width(from) != width(to)) {
|
if (width(from) != width(to)) {
|
||||||
AddError("cannot bitcast from '" + TypeNameOf(from) + "' to '" +
|
AddError("cannot bitcast from '" + sem_.TypeNameOf(from) + "' to '" +
|
||||||
TypeNameOf(to) + "'",
|
sem_.TypeNameOf(to) + "'",
|
||||||
cast->source);
|
cast->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1389,8 +1392,8 @@ bool Resolver::ValidateElseStatement(const sem::ElseStatement* stmt) const {
|
||||||
if (auto* cond = stmt->Condition()) {
|
if (auto* cond = stmt->Condition()) {
|
||||||
auto* cond_ty = cond->Type()->UnwrapRef();
|
auto* cond_ty = cond->Type()->UnwrapRef();
|
||||||
if (!cond_ty->Is<sem::Bool>()) {
|
if (!cond_ty->Is<sem::Bool>()) {
|
||||||
AddError(
|
AddError("else statement condition must be bool, got " +
|
||||||
"else statement condition must be bool, got " + TypeNameOf(cond_ty),
|
sem_.TypeNameOf(cond_ty),
|
||||||
stmt->Condition()->Declaration()->source);
|
stmt->Condition()->Declaration()->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1415,7 +1418,8 @@ bool Resolver::ValidateForLoopStatement(
|
||||||
if (auto* cond = stmt->Condition()) {
|
if (auto* cond = stmt->Condition()) {
|
||||||
auto* cond_ty = cond->Type()->UnwrapRef();
|
auto* cond_ty = cond->Type()->UnwrapRef();
|
||||||
if (!cond_ty->Is<sem::Bool>()) {
|
if (!cond_ty->Is<sem::Bool>()) {
|
||||||
AddError("for-loop condition must be bool, got " + TypeNameOf(cond_ty),
|
AddError(
|
||||||
|
"for-loop condition must be bool, got " + sem_.TypeNameOf(cond_ty),
|
||||||
stmt->Condition()->Declaration()->source);
|
stmt->Condition()->Declaration()->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1426,7 +1430,8 @@ bool Resolver::ValidateForLoopStatement(
|
||||||
bool Resolver::ValidateIfStatement(const sem::IfStatement* stmt) const {
|
bool Resolver::ValidateIfStatement(const sem::IfStatement* stmt) const {
|
||||||
auto* cond_ty = stmt->Condition()->Type()->UnwrapRef();
|
auto* cond_ty = stmt->Condition()->Type()->UnwrapRef();
|
||||||
if (!cond_ty->Is<sem::Bool>()) {
|
if (!cond_ty->Is<sem::Bool>()) {
|
||||||
AddError("if statement condition must be bool, got " + TypeNameOf(cond_ty),
|
AddError(
|
||||||
|
"if statement condition must be bool, got " + sem_.TypeNameOf(cond_ty),
|
||||||
stmt->Condition()->Declaration()->source);
|
stmt->Condition()->Declaration()->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1556,13 +1561,13 @@ bool Resolver::ValidateFunctionCall(const sem::Call* call) const {
|
||||||
const sem::Variable* param = target->Parameters()[i];
|
const sem::Variable* param = target->Parameters()[i];
|
||||||
const ast::Expression* arg_expr = decl->args[i];
|
const ast::Expression* arg_expr = decl->args[i];
|
||||||
auto* param_type = param->Type();
|
auto* param_type = param->Type();
|
||||||
auto* arg_type = TypeOf(arg_expr)->UnwrapRef();
|
auto* arg_type = sem_.TypeOf(arg_expr)->UnwrapRef();
|
||||||
|
|
||||||
if (param_type != arg_type) {
|
if (param_type != arg_type) {
|
||||||
AddError("type mismatch for argument " + std::to_string(i + 1) +
|
AddError("type mismatch for argument " + std::to_string(i + 1) +
|
||||||
" in call to '" + name + "', expected '" +
|
" in call to '" + name + "', expected '" +
|
||||||
TypeNameOf(param_type) + "', got '" + TypeNameOf(arg_type) +
|
sem_.TypeNameOf(param_type) + "', got '" +
|
||||||
"'",
|
sem_.TypeNameOf(arg_type) + "'",
|
||||||
arg_expr->source);
|
arg_expr->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1664,13 +1669,13 @@ bool Resolver::ValidateStructureConstructorOrCast(
|
||||||
}
|
}
|
||||||
for (auto* member : struct_type->Members()) {
|
for (auto* member : struct_type->Members()) {
|
||||||
auto* value = ctor->args[member->Index()];
|
auto* value = ctor->args[member->Index()];
|
||||||
auto* value_ty = TypeOf(value);
|
auto* value_ty = sem_.TypeOf(value);
|
||||||
if (member->Type() != value_ty->UnwrapRef()) {
|
if (member->Type() != value_ty->UnwrapRef()) {
|
||||||
AddError(
|
AddError(
|
||||||
"type in struct constructor does not match struct member type: "
|
"type in struct constructor does not match struct member type: "
|
||||||
"expected '" +
|
"expected '" +
|
||||||
TypeNameOf(member->Type()) + "', found '" +
|
sem_.TypeNameOf(member->Type()) + "', found '" +
|
||||||
TypeNameOf(value_ty) + "'",
|
sem_.TypeNameOf(value_ty) + "'",
|
||||||
value->source);
|
value->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1685,12 +1690,13 @@ bool Resolver::ValidateArrayConstructorOrCast(
|
||||||
auto& values = ctor->args;
|
auto& values = ctor->args;
|
||||||
auto* elem_ty = array_type->ElemType();
|
auto* elem_ty = array_type->ElemType();
|
||||||
for (auto* value : values) {
|
for (auto* value : values) {
|
||||||
auto* value_ty = TypeOf(value)->UnwrapRef();
|
auto* value_ty = sem_.TypeOf(value)->UnwrapRef();
|
||||||
if (value_ty != elem_ty) {
|
if (value_ty != elem_ty) {
|
||||||
AddError(
|
AddError(
|
||||||
"type in array constructor does not match array type: "
|
"type in array constructor does not match array type: "
|
||||||
"expected '" +
|
"expected '" +
|
||||||
TypeNameOf(elem_ty) + "', found '" + TypeNameOf(value_ty) + "'",
|
sem_.TypeNameOf(elem_ty) + "', found '" +
|
||||||
|
sem_.TypeNameOf(value_ty) + "'",
|
||||||
value->source);
|
value->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1727,13 +1733,14 @@ bool Resolver::ValidateVectorConstructorOrCast(
|
||||||
auto* elem_ty = vec_type->type();
|
auto* elem_ty = vec_type->type();
|
||||||
size_t value_cardinality_sum = 0;
|
size_t value_cardinality_sum = 0;
|
||||||
for (auto* value : values) {
|
for (auto* value : values) {
|
||||||
auto* value_ty = TypeOf(value)->UnwrapRef();
|
auto* value_ty = sem_.TypeOf(value)->UnwrapRef();
|
||||||
if (value_ty->is_scalar()) {
|
if (value_ty->is_scalar()) {
|
||||||
if (elem_ty != value_ty) {
|
if (elem_ty != value_ty) {
|
||||||
AddError(
|
AddError(
|
||||||
"type in vector constructor does not match vector type: "
|
"type in vector constructor does not match vector type: "
|
||||||
"expected '" +
|
"expected '" +
|
||||||
TypeNameOf(elem_ty) + "', found '" + TypeNameOf(value_ty) + "'",
|
sem_.TypeNameOf(elem_ty) + "', found '" +
|
||||||
|
sem_.TypeNameOf(value_ty) + "'",
|
||||||
value->source);
|
value->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1748,8 +1755,8 @@ bool Resolver::ValidateVectorConstructorOrCast(
|
||||||
AddError(
|
AddError(
|
||||||
"type in vector constructor does not match vector type: "
|
"type in vector constructor does not match vector type: "
|
||||||
"expected '" +
|
"expected '" +
|
||||||
TypeNameOf(elem_ty) + "', found '" + TypeNameOf(value_elem_ty) +
|
sem_.TypeNameOf(elem_ty) + "', found '" +
|
||||||
"'",
|
sem_.TypeNameOf(value_elem_ty) + "'",
|
||||||
value->source);
|
value->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1758,7 +1765,7 @@ bool Resolver::ValidateVectorConstructorOrCast(
|
||||||
} else {
|
} else {
|
||||||
// A vector constructor can only accept vectors and scalars.
|
// A vector constructor can only accept vectors and scalars.
|
||||||
AddError("expected vector or scalar type in vector constructor; found: " +
|
AddError("expected vector or scalar type in vector constructor; found: " +
|
||||||
TypeNameOf(value_ty),
|
sem_.TypeNameOf(value_ty),
|
||||||
value->source);
|
value->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1774,8 +1781,9 @@ bool Resolver::ValidateVectorConstructorOrCast(
|
||||||
}
|
}
|
||||||
const Source& values_start = values[0]->source;
|
const Source& values_start = values[0]->source;
|
||||||
const Source& values_end = values[values.size() - 1]->source;
|
const Source& values_end = values[values.size() - 1]->source;
|
||||||
AddError("attempted to construct '" + TypeNameOf(vec_type) + "' with " +
|
AddError("attempted to construct '" + sem_.TypeNameOf(vec_type) +
|
||||||
std::to_string(value_cardinality_sum) + " component(s)",
|
"' with " + std::to_string(value_cardinality_sum) +
|
||||||
|
" component(s)",
|
||||||
Source::Combine(values_start, values_end));
|
Source::Combine(values_start, values_end));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1817,7 +1825,7 @@ bool Resolver::ValidateMatrixConstructorOrCast(
|
||||||
std::vector<const sem::Type*> arg_tys;
|
std::vector<const sem::Type*> arg_tys;
|
||||||
arg_tys.reserve(values.size());
|
arg_tys.reserve(values.size());
|
||||||
for (auto* value : values) {
|
for (auto* value : values) {
|
||||||
arg_tys.emplace_back(TypeOf(value)->UnwrapRef());
|
arg_tys.emplace_back(sem_.TypeOf(value)->UnwrapRef());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* elem_type = matrix_ty->type();
|
auto* elem_type = matrix_ty->type();
|
||||||
|
@ -1828,8 +1836,8 @@ bool Resolver::ValidateMatrixConstructorOrCast(
|
||||||
auto print_error = [&]() {
|
auto print_error = [&]() {
|
||||||
const Source& values_start = values[0]->source;
|
const Source& values_start = values[0]->source;
|
||||||
const Source& values_end = values[values.size() - 1]->source;
|
const Source& values_end = values[values.size() - 1]->source;
|
||||||
auto type_name = TypeNameOf(matrix_ty);
|
auto type_name = sem_.TypeNameOf(matrix_ty);
|
||||||
auto elem_type_name = TypeNameOf(elem_type);
|
auto elem_type_name = sem_.TypeNameOf(elem_type);
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "no matching constructor " + type_name << "(";
|
ss << "no matching constructor " + type_name << "(";
|
||||||
for (size_t i = 0; i < values.size(); i++) {
|
for (size_t i = 0; i < values.size(); i++) {
|
||||||
|
@ -1891,7 +1899,7 @@ bool Resolver::ValidateScalarConstructorOrCast(const ast::CallExpression* ctor,
|
||||||
|
|
||||||
// Validate constructor
|
// Validate constructor
|
||||||
auto* value = ctor->args[0];
|
auto* value = ctor->args[0];
|
||||||
auto* value_ty = TypeOf(value)->UnwrapRef();
|
auto* value_ty = sem_.TypeOf(value)->UnwrapRef();
|
||||||
|
|
||||||
using Bool = sem::Bool;
|
using Bool = sem::Bool;
|
||||||
using I32 = sem::I32;
|
using I32 = sem::I32;
|
||||||
|
@ -1903,8 +1911,8 @@ bool Resolver::ValidateScalarConstructorOrCast(const ast::CallExpression* ctor,
|
||||||
(ty->Is<U32>() && value_ty->is_scalar()) ||
|
(ty->Is<U32>() && value_ty->is_scalar()) ||
|
||||||
(ty->Is<F32>() && value_ty->is_scalar());
|
(ty->Is<F32>() && value_ty->is_scalar());
|
||||||
if (!is_valid) {
|
if (!is_valid) {
|
||||||
AddError("cannot construct '" + TypeNameOf(ty) +
|
AddError("cannot construct '" + sem_.TypeNameOf(ty) +
|
||||||
"' with a value of type '" + TypeNameOf(value_ty) + "'",
|
"' with a value of type '" + sem_.TypeNameOf(value_ty) + "'",
|
||||||
ctor->source);
|
ctor->source);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -2172,7 +2180,7 @@ bool Resolver::ValidateLocationAttribute(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!type->is_numeric_scalar_or_vector()) {
|
if (!type->is_numeric_scalar_or_vector()) {
|
||||||
std::string invalid_type = TypeNameOf(type);
|
std::string invalid_type = sem_.TypeNameOf(type);
|
||||||
AddError("cannot apply 'location' attribute to declaration of type '" +
|
AddError("cannot apply 'location' attribute to declaration of type '" +
|
||||||
invalid_type + "'",
|
invalid_type + "'",
|
||||||
source);
|
source);
|
||||||
|
@ -2200,13 +2208,13 @@ bool Resolver::ValidateReturn(const ast::ReturnStatement* ret,
|
||||||
AddError(
|
AddError(
|
||||||
"return statement type must match its function "
|
"return statement type must match its function "
|
||||||
"return type, returned '" +
|
"return type, returned '" +
|
||||||
TypeNameOf(ret_type) + "', expected '" + TypeNameOf(func_type) +
|
sem_.TypeNameOf(ret_type) + "', expected '" +
|
||||||
"'",
|
sem_.TypeNameOf(func_type) + "'",
|
||||||
ret->source);
|
ret->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* sem = Sem(ret);
|
auto* sem = sem_.Get(ret);
|
||||||
if (auto* continuing = ClosestContinuing(/*stop_at_loop*/ false)) {
|
if (auto* continuing = ClosestContinuing(/*stop_at_loop*/ false)) {
|
||||||
AddError("continuing blocks must not contain a return statement",
|
AddError("continuing blocks must not contain a return statement",
|
||||||
ret->source);
|
ret->source);
|
||||||
|
@ -2221,7 +2229,7 @@ bool Resolver::ValidateReturn(const ast::ReturnStatement* ret,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resolver::ValidateSwitch(const ast::SwitchStatement* s) {
|
bool Resolver::ValidateSwitch(const ast::SwitchStatement* s) {
|
||||||
auto* cond_ty = TypeOf(s->condition)->UnwrapRef();
|
auto* cond_ty = sem_.TypeOf(s->condition)->UnwrapRef();
|
||||||
if (!cond_ty->is_integer_scalar()) {
|
if (!cond_ty->is_integer_scalar()) {
|
||||||
AddError(
|
AddError(
|
||||||
"switch statement selector expression must be of a "
|
"switch statement selector expression must be of a "
|
||||||
|
@ -2245,7 +2253,7 @@ bool Resolver::ValidateSwitch(const ast::SwitchStatement* s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* selector : case_stmt->selectors) {
|
for (auto* selector : case_stmt->selectors) {
|
||||||
if (cond_ty != TypeOf(selector)) {
|
if (cond_ty != sem_.TypeOf(selector)) {
|
||||||
AddError(
|
AddError(
|
||||||
"the case selector values must have the same "
|
"the case selector values must have the same "
|
||||||
"type as the selector expression.",
|
"type as the selector expression.",
|
||||||
|
@ -2297,7 +2305,7 @@ bool Resolver::ValidateAssignment(const ast::Statement* a,
|
||||||
if (!ty->IsConstructible() &&
|
if (!ty->IsConstructible() &&
|
||||||
!ty->IsAnyOf<sem::Pointer, sem::Texture, sem::Sampler>()) {
|
!ty->IsAnyOf<sem::Pointer, sem::Texture, sem::Sampler>()) {
|
||||||
AddError(
|
AddError(
|
||||||
"cannot assign '" + TypeNameOf(rhs_ty) +
|
"cannot assign '" + sem_.TypeNameOf(rhs_ty) +
|
||||||
"' to '_'. '_' can only be assigned a constructible, pointer, "
|
"' to '_'. '_' can only be assigned a constructible, pointer, "
|
||||||
"texture or sampler type",
|
"texture or sampler type",
|
||||||
rhs->source);
|
rhs->source);
|
||||||
|
@ -2307,7 +2315,7 @@ bool Resolver::ValidateAssignment(const ast::Statement* a,
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#assignment-statement
|
// https://gpuweb.github.io/gpuweb/wgsl/#assignment-statement
|
||||||
auto const* lhs_ty = TypeOf(lhs);
|
auto const* lhs_ty = sem_.TypeOf(lhs);
|
||||||
|
|
||||||
if (auto* var = ResolvedSymbol<sem::Variable>(lhs)) {
|
if (auto* var = ResolvedSymbol<sem::Variable>(lhs)) {
|
||||||
auto* decl = var->Declaration();
|
auto* decl = var->Declaration();
|
||||||
|
@ -2330,7 +2338,7 @@ bool Resolver::ValidateAssignment(const ast::Statement* a,
|
||||||
auto* lhs_ref = lhs_ty->As<sem::Reference>();
|
auto* lhs_ref = lhs_ty->As<sem::Reference>();
|
||||||
if (!lhs_ref) {
|
if (!lhs_ref) {
|
||||||
// LHS is not a reference, so it has no storage.
|
// LHS is not a reference, so it has no storage.
|
||||||
AddError("cannot assign to value of type '" + TypeNameOf(lhs_ty) + "'",
|
AddError("cannot assign to value of type '" + sem_.TypeNameOf(lhs_ty) + "'",
|
||||||
lhs->source);
|
lhs->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2340,8 +2348,8 @@ bool Resolver::ValidateAssignment(const ast::Statement* a,
|
||||||
|
|
||||||
// Value type has to match storage type
|
// Value type has to match storage type
|
||||||
if (storage_ty != value_type) {
|
if (storage_ty != value_type) {
|
||||||
AddError("cannot assign '" + TypeNameOf(rhs_ty) + "' to '" +
|
AddError("cannot assign '" + sem_.TypeNameOf(rhs_ty) + "' to '" +
|
||||||
TypeNameOf(lhs_ty) + "'",
|
sem_.TypeNameOf(lhs_ty) + "'",
|
||||||
a->source);
|
a->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2350,8 +2358,8 @@ bool Resolver::ValidateAssignment(const ast::Statement* a,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (lhs_ref->Access() == ast::Access::kRead) {
|
if (lhs_ref->Access() == ast::Access::kRead) {
|
||||||
AddError(
|
AddError("cannot store into a read-only type '" +
|
||||||
"cannot store into a read-only type '" + RawTypeNameOf(lhs_ty) + "'",
|
sem_.RawTypeNameOf(lhs_ty) + "'",
|
||||||
a->source);
|
a->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2382,11 +2390,11 @@ bool Resolver::ValidateIncrementDecrementStatement(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const* lhs_ty = TypeOf(lhs);
|
auto const* lhs_ty = sem_.TypeOf(lhs);
|
||||||
auto* lhs_ref = lhs_ty->As<sem::Reference>();
|
auto* lhs_ref = lhs_ty->As<sem::Reference>();
|
||||||
if (!lhs_ref) {
|
if (!lhs_ref) {
|
||||||
// LHS is not a reference, so it has no storage.
|
// LHS is not a reference, so it has no storage.
|
||||||
AddError("cannot modify value of type '" + TypeNameOf(lhs_ty) + "'",
|
AddError("cannot modify value of type '" + sem_.TypeNameOf(lhs_ty) + "'",
|
||||||
lhs->source);
|
lhs->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2399,7 +2407,8 @@ bool Resolver::ValidateIncrementDecrementStatement(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lhs_ref->Access() == ast::Access::kRead) {
|
if (lhs_ref->Access() == ast::Access::kRead) {
|
||||||
AddError("cannot modify read-only type '" + RawTypeNameOf(lhs_ty) + "'",
|
AddError(
|
||||||
|
"cannot modify read-only type '" + sem_.RawTypeNameOf(lhs_ty) + "'",
|
||||||
inc->source);
|
inc->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
// Copyright 2022 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/tint/resolver/sem_helper.h"
|
||||||
|
|
||||||
|
#include "src/tint/sem/expression.h"
|
||||||
|
|
||||||
|
namespace tint::resolver {
|
||||||
|
|
||||||
|
SemHelper::SemHelper(ProgramBuilder* builder) : builder_(builder) {}
|
||||||
|
|
||||||
|
SemHelper::~SemHelper() = default;
|
||||||
|
|
||||||
|
std::string SemHelper::TypeNameOf(const sem::Type* ty) const {
|
||||||
|
return RawTypeNameOf(ty->UnwrapRef());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SemHelper::RawTypeNameOf(const sem::Type* ty) const {
|
||||||
|
return ty->FriendlyName(builder_->Symbols());
|
||||||
|
}
|
||||||
|
|
||||||
|
sem::Type* SemHelper::TypeOf(const ast::Expression* expr) const {
|
||||||
|
auto* sem = Get(expr);
|
||||||
|
return sem ? const_cast<sem::Type*>(sem->Type()) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
sem::Type* SemHelper::TypeOf(const ast::LiteralExpression* lit) {
|
||||||
|
return Switch(
|
||||||
|
lit,
|
||||||
|
[&](const ast::SintLiteralExpression*) {
|
||||||
|
return builder_->create<sem::I32>();
|
||||||
|
},
|
||||||
|
[&](const ast::UintLiteralExpression*) {
|
||||||
|
return builder_->create<sem::U32>();
|
||||||
|
},
|
||||||
|
[&](const ast::FloatLiteralExpression*) {
|
||||||
|
return builder_->create<sem::F32>();
|
||||||
|
},
|
||||||
|
[&](const ast::BoolLiteralExpression*) {
|
||||||
|
return builder_->create<sem::Bool>();
|
||||||
|
},
|
||||||
|
[&](Default) {
|
||||||
|
TINT_UNREACHABLE(Resolver, builder_->Diagnostics())
|
||||||
|
<< "Unhandled literal type: " << lit->TypeInfo().name;
|
||||||
|
return nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace tint::resolver
|
|
@ -0,0 +1,66 @@
|
||||||
|
// Copyright 2022 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.
|
||||||
|
|
||||||
|
#ifndef SRC_TINT_RESOLVER_SEM_HELPER_H_
|
||||||
|
#define SRC_TINT_RESOLVER_SEM_HELPER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "src/tint/diagnostic/diagnostic.h"
|
||||||
|
#include "src/tint/program_builder.h"
|
||||||
|
|
||||||
|
namespace tint::resolver {
|
||||||
|
class SemHelper {
|
||||||
|
public:
|
||||||
|
explicit SemHelper(ProgramBuilder* builder);
|
||||||
|
~SemHelper();
|
||||||
|
|
||||||
|
/// Get is a helper for obtaining the semantic node for the given AST node.
|
||||||
|
template <typename SEM = sem::Info::InferFromAST,
|
||||||
|
typename AST_OR_TYPE = CastableBase>
|
||||||
|
auto* Get(const AST_OR_TYPE* ast) const {
|
||||||
|
using T = sem::Info::GetResultType<SEM, AST_OR_TYPE>;
|
||||||
|
auto* sem = builder_->Sem().Get(ast);
|
||||||
|
if (!sem) {
|
||||||
|
TINT_ICE(Resolver, builder_->Diagnostics())
|
||||||
|
<< "AST node '" << ast->TypeInfo().name << "' had no semantic info\n"
|
||||||
|
<< "At: " << ast->source << "\n"
|
||||||
|
<< "Pointer: " << ast;
|
||||||
|
}
|
||||||
|
return const_cast<T*>(As<T>(sem));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns the resolved type of the ast::Expression `expr`
|
||||||
|
/// @param expr the expression
|
||||||
|
sem::Type* TypeOf(const ast::Expression* expr) const;
|
||||||
|
|
||||||
|
/// @returns the semantic type of the AST literal `lit`
|
||||||
|
/// @param lit the literal
|
||||||
|
sem::Type* TypeOf(const ast::LiteralExpression* lit);
|
||||||
|
|
||||||
|
/// @returns the type name of the given semantic type, unwrapping
|
||||||
|
/// references.
|
||||||
|
std::string TypeNameOf(const sem::Type* ty) const;
|
||||||
|
|
||||||
|
/// @returns the type name of the given semantic type, without unwrapping
|
||||||
|
/// references.
|
||||||
|
std::string RawTypeNameOf(const sem::Type* ty) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ProgramBuilder* builder_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace tint::resolver
|
||||||
|
|
||||||
|
#endif // SRC_TINT_RESOLVER_SEM_HELPER_H_
|
Loading…
Reference in New Issue