mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-13 23:26:24 +00:00
ast: Remove TypeConstructorExpression
Add a new 'Target' to the ast::CallExpression, which can be either an Identifier or Type. The Identifier may resolve to a Type, if the Type is a structure or alias. The Resolver now resolves the CallExpression target to one of the following sem::CallTargets: * sem::Function * sem::Intrinsic * sem::TypeConstructor * sem::TypeCast This change will allow us to remove the type tracking logic from the WGSL parser, which is required for out-of-order module scope declarations. Bug: tint:888 Bug: tint:1266 Change-Id: I696f117115a50981fd5c102a0d7764641bb755dd Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/68525 Reviewed-by: David Neto <dneto@google.com> Reviewed-by: James Price <jrprice@google.com> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
@@ -90,11 +90,15 @@ TEST_F(ResolverCallTest, Valid) {
|
||||
args.push_back(p.create_value(*this, 0));
|
||||
}
|
||||
|
||||
Func("foo", std::move(params), ty.f32(), {Return(1.23f)});
|
||||
auto* call = Call("foo", std::move(args));
|
||||
WrapInFunction(call);
|
||||
auto* func = Func("foo", std::move(params), ty.f32(), {Return(1.23f)});
|
||||
auto* call_expr = Call("foo", std::move(args));
|
||||
WrapInFunction(call_expr);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* call = Sem().Get(call_expr);
|
||||
EXPECT_NE(call, nullptr);
|
||||
EXPECT_EQ(call->Target(), Sem().Get(func));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -70,12 +70,15 @@
|
||||
#include "src/sem/storage_texture_type.h"
|
||||
#include "src/sem/struct.h"
|
||||
#include "src/sem/switch_statement.h"
|
||||
#include "src/sem/type_constructor.h"
|
||||
#include "src/sem/type_conversion.h"
|
||||
#include "src/sem/variable.h"
|
||||
#include "src/utils/defer.h"
|
||||
#include "src/utils/get_or_create.h"
|
||||
#include "src/utils/math.h"
|
||||
#include "src/utils/reverse.h"
|
||||
#include "src/utils/scoped_assignment.h"
|
||||
#include "src/utils/transform.h"
|
||||
|
||||
namespace tint {
|
||||
namespace resolver {
|
||||
@@ -510,8 +513,8 @@ sem::Variable* Resolver::Variable(const ast::Variable* var,
|
||||
builder_->create<sem::Reference>(storage_ty, storage_class, access);
|
||||
}
|
||||
|
||||
if (rhs && !ValidateVariableConstructor(var, storage_class, storage_ty,
|
||||
rhs->Type())) {
|
||||
if (rhs && !ValidateVariableConstructorOrCast(var, storage_class, storage_ty,
|
||||
rhs->Type())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -641,10 +644,11 @@ void Resolver::AllocateOverridableConstantIds() {
|
||||
}
|
||||
}
|
||||
|
||||
bool Resolver::ValidateVariableConstructor(const ast::Variable* var,
|
||||
ast::StorageClass storage_class,
|
||||
const sem::Type* storage_ty,
|
||||
const sem::Type* rhs_ty) {
|
||||
bool Resolver::ValidateVariableConstructorOrCast(
|
||||
const ast::Variable* var,
|
||||
ast::StorageClass storage_class,
|
||||
const sem::Type* storage_ty,
|
||||
const sem::Type* rhs_ty) {
|
||||
auto* value_type = rhs_ty->UnwrapRef(); // Implicit load of RHS
|
||||
|
||||
// Value type has to match storage type
|
||||
@@ -2369,8 +2373,6 @@ sem::Expression* Resolver::Expression(const ast::Expression* root) {
|
||||
sem_expr = Bitcast(bitcast);
|
||||
} else if (auto* call = expr->As<ast::CallExpression>()) {
|
||||
sem_expr = Call(call);
|
||||
} else if (auto* ctor = expr->As<ast::TypeConstructorExpression>()) {
|
||||
sem_expr = TypeConstructor(ctor);
|
||||
} else if (auto* ident = expr->As<ast::IdentifierExpression>()) {
|
||||
sem_expr = Identifier(ident);
|
||||
} else if (auto* literal = expr->As<ast::LiteralExpression>()) {
|
||||
@@ -2462,33 +2464,72 @@ sem::Expression* Resolver::Bitcast(const ast::BitcastExpression* expr) {
|
||||
return builder_->create<sem::Expression>(expr, ty, current_statement_, val);
|
||||
}
|
||||
|
||||
sem::Expression* Resolver::Call(const ast::CallExpression* expr) {
|
||||
auto* ident = expr->func;
|
||||
Mark(ident);
|
||||
auto name = builder_->Symbols().NameFor(ident->symbol);
|
||||
|
||||
auto intrinsic_type = sem::ParseIntrinsicType(name);
|
||||
auto* call = (intrinsic_type != IntrinsicType::kNone)
|
||||
? IntrinsicCall(expr, intrinsic_type)
|
||||
: FunctionCall(expr);
|
||||
|
||||
current_function_->AddDirectCall(call);
|
||||
return call;
|
||||
}
|
||||
|
||||
sem::Call* Resolver::IntrinsicCall(const ast::CallExpression* expr,
|
||||
sem::IntrinsicType intrinsic_type) {
|
||||
sem::Call* Resolver::Call(const ast::CallExpression* expr) {
|
||||
std::vector<const sem::Expression*> args(expr->args.size());
|
||||
std::vector<const sem::Type*> arg_tys(expr->args.size());
|
||||
std::vector<const sem::Type*> arg_tys(args.size());
|
||||
for (size_t i = 0; i < expr->args.size(); i++) {
|
||||
auto* arg = Sem(expr->args[i]);
|
||||
if (!arg) {
|
||||
return nullptr;
|
||||
}
|
||||
args[i] = arg;
|
||||
arg_tys[i] = arg->Type();
|
||||
arg_tys[i] = args[i]->Type();
|
||||
}
|
||||
|
||||
auto type_ctor_or_conv = [&](const sem::Type* ty) -> sem::Call* {
|
||||
// The call has resolved to a type constructor or cast.
|
||||
if (args.size() == 1) {
|
||||
auto* target = ty;
|
||||
auto* source = args[0]->Type()->UnwrapRef();
|
||||
if ((source != target) && //
|
||||
((source->is_scalar() && target->is_scalar()) ||
|
||||
(source->Is<sem::Vector>() && target->Is<sem::Vector>()) ||
|
||||
(source->Is<sem::Matrix>() && target->Is<sem::Matrix>()))) {
|
||||
// Note: Matrix types currently cannot be converted (the element type
|
||||
// must only be f32). We implement this for the day we support other
|
||||
// matrix element types.
|
||||
return TypeConversion(expr, ty, args[0], arg_tys[0]);
|
||||
}
|
||||
}
|
||||
return TypeConstructor(expr, ty, std::move(args), std::move(arg_tys));
|
||||
};
|
||||
|
||||
// Resolve the target of the CallExpression to determine whether this is a
|
||||
// function call, cast or type constructor expression.
|
||||
if (expr->target.type) {
|
||||
auto* ty = Type(expr->target.type);
|
||||
if (!ty) {
|
||||
return nullptr;
|
||||
}
|
||||
return type_ctor_or_conv(ty);
|
||||
}
|
||||
|
||||
auto* ident = expr->target.name;
|
||||
Mark(ident);
|
||||
|
||||
auto it = named_type_info_.find(ident->symbol);
|
||||
if (it != named_type_info_.end()) {
|
||||
// We have a type.
|
||||
return type_ctor_or_conv(it->second.sem);
|
||||
}
|
||||
|
||||
// Not a type, treat as a intrinsic / function call.
|
||||
auto name = builder_->Symbols().NameFor(ident->symbol);
|
||||
auto intrinsic_type = sem::ParseIntrinsicType(name);
|
||||
auto* call = (intrinsic_type != IntrinsicType::kNone)
|
||||
? IntrinsicCall(expr, intrinsic_type, std::move(args),
|
||||
std::move(arg_tys))
|
||||
: FunctionCall(expr, std::move(args));
|
||||
|
||||
current_function_->AddDirectCall(call);
|
||||
return call;
|
||||
}
|
||||
|
||||
sem::Call* Resolver::IntrinsicCall(
|
||||
const ast::CallExpression* expr,
|
||||
sem::IntrinsicType intrinsic_type,
|
||||
const std::vector<const sem::Expression*> args,
|
||||
const std::vector<const sem::Type*> arg_tys) {
|
||||
auto* intrinsic = intrinsic_table_->Lookup(intrinsic_type, std::move(arg_tys),
|
||||
expr->source);
|
||||
if (!intrinsic) {
|
||||
@@ -2509,21 +2550,45 @@ sem::Call* Resolver::IntrinsicCall(const ast::CallExpression* expr,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!ValidateCall(call)) {
|
||||
if (!ValidateIntrinsicCall(call)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return call;
|
||||
}
|
||||
|
||||
sem::Call* Resolver::FunctionCall(const ast::CallExpression* expr) {
|
||||
auto* ident = expr->func;
|
||||
auto name = builder_->Symbols().NameFor(ident->symbol);
|
||||
bool Resolver::ValidateIntrinsicCall(const sem::Call* call) {
|
||||
if (call->Type()->Is<sem::Void>()) {
|
||||
bool is_call_statement = false;
|
||||
if (auto* call_stmt = As<ast::CallStatement>(call->Stmt()->Declaration())) {
|
||||
if (call_stmt->expr == call->Declaration()) {
|
||||
is_call_statement = true;
|
||||
}
|
||||
}
|
||||
if (!is_call_statement) {
|
||||
// https://gpuweb.github.io/gpuweb/wgsl/#function-call-expr
|
||||
// If the called function does not return a value, a function call
|
||||
// statement should be used instead.
|
||||
auto* ident = call->Declaration()->target.name;
|
||||
auto name = builder_->Symbols().NameFor(ident->symbol);
|
||||
AddError("intrinsic '" + name + "' does not return a value",
|
||||
call->Declaration()->source);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto target_it = symbol_to_function_.find(ident->symbol);
|
||||
return true;
|
||||
}
|
||||
|
||||
sem::Call* Resolver::FunctionCall(
|
||||
const ast::CallExpression* expr,
|
||||
const std::vector<const sem::Expression*> args) {
|
||||
auto sym = expr->target.name->symbol;
|
||||
auto name = builder_->Symbols().NameFor(sym);
|
||||
|
||||
auto target_it = symbol_to_function_.find(sym);
|
||||
if (target_it == symbol_to_function_.end()) {
|
||||
if (current_function_ &&
|
||||
current_function_->Declaration()->symbol == ident->symbol) {
|
||||
if (current_function_ && current_function_->Declaration()->symbol == sym) {
|
||||
AddError("recursion is not permitted. '" + name +
|
||||
"' attempted to call itself.",
|
||||
expr->source);
|
||||
@@ -2533,16 +2598,6 @@ sem::Call* Resolver::FunctionCall(const ast::CallExpression* expr) {
|
||||
return nullptr;
|
||||
}
|
||||
auto* target = target_it->second;
|
||||
|
||||
std::vector<const sem::Expression*> args(expr->args.size());
|
||||
for (size_t i = 0; i < expr->args.size(); i++) {
|
||||
auto* arg = Sem(expr->args[i]);
|
||||
if (!arg) {
|
||||
return nullptr;
|
||||
}
|
||||
args[i] = arg;
|
||||
}
|
||||
|
||||
auto* call = builder_->create<sem::Call>(expr, target, std::move(args),
|
||||
current_statement_, sem::Constant{});
|
||||
|
||||
@@ -2567,38 +2622,9 @@ sem::Call* Resolver::FunctionCall(const ast::CallExpression* expr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!ValidateCall(call)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return call;
|
||||
}
|
||||
|
||||
bool Resolver::ValidateCall(const sem::Call* call) {
|
||||
if (call->Type()->Is<sem::Void>()) {
|
||||
bool is_call_statement = false;
|
||||
if (auto* call_stmt = As<ast::CallStatement>(call->Stmt()->Declaration())) {
|
||||
if (call_stmt->expr == call->Declaration()) {
|
||||
is_call_statement = true;
|
||||
}
|
||||
}
|
||||
if (!is_call_statement) {
|
||||
// https://gpuweb.github.io/gpuweb/wgsl/#function-call-expr
|
||||
// If the called function does not return a value, a function call
|
||||
// statement should be used instead.
|
||||
auto* ident = call->Declaration()->func;
|
||||
auto name = builder_->Symbols().NameFor(ident->symbol);
|
||||
bool is_function = call->Target()->Is<sem::Function>();
|
||||
AddError((is_function ? "function" : "intrinsic") + std::string(" '") +
|
||||
name + "' does not return a value",
|
||||
call->Declaration()->source);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resolver::ValidateTextureIntrinsicFunction(const sem::Call* call) {
|
||||
auto* intrinsic = call->Target()->As<sem::Intrinsic>();
|
||||
if (!intrinsic) {
|
||||
@@ -2623,8 +2649,7 @@ bool Resolver::ValidateTextureIntrinsicFunction(const sem::Call* call) {
|
||||
bool is_const_expr = true;
|
||||
ast::TraverseExpressions(
|
||||
arg->Declaration(), diagnostics_, [&](const ast::Expression* e) {
|
||||
if (e->IsAnyOf<ast::LiteralExpression,
|
||||
ast::TypeConstructorExpression>()) {
|
||||
if (e->IsAnyOf<ast::LiteralExpression, ast::CallExpression>()) {
|
||||
return ast::TraverseAction::Descend;
|
||||
}
|
||||
is_const_expr = false;
|
||||
@@ -2654,9 +2679,9 @@ bool Resolver::ValidateTextureIntrinsicFunction(const sem::Call* call) {
|
||||
|
||||
bool Resolver::ValidateFunctionCall(const sem::Call* call) {
|
||||
auto* decl = call->Declaration();
|
||||
auto* ident = decl->func;
|
||||
auto* target = call->Target()->As<sem::Function>();
|
||||
auto name = builder_->Symbols().NameFor(ident->symbol);
|
||||
auto sym = decl->target.name->symbol;
|
||||
auto name = builder_->Symbols().NameFor(sym);
|
||||
|
||||
if (target->Declaration()->IsEntryPoint()) {
|
||||
// https://www.w3.org/TR/WGSL/#function-restriction
|
||||
@@ -2735,40 +2760,150 @@ bool Resolver::ValidateFunctionCall(const sem::Call* call) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (call->Type()->Is<sem::Void>()) {
|
||||
bool is_call_statement = false;
|
||||
if (auto* call_stmt = As<ast::CallStatement>(call->Stmt()->Declaration())) {
|
||||
if (call_stmt->expr == call->Declaration()) {
|
||||
is_call_statement = true;
|
||||
}
|
||||
}
|
||||
if (!is_call_statement) {
|
||||
// https://gpuweb.github.io/gpuweb/wgsl/#function-call-expr
|
||||
// If the called function does not return a value, a function call
|
||||
// statement should be used instead.
|
||||
AddError("function '" + name + "' does not return a value", decl->source);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
sem::Expression* Resolver::TypeConstructor(
|
||||
const ast::TypeConstructorExpression* expr) {
|
||||
auto* ty = Type(expr->type);
|
||||
if (!ty) {
|
||||
sem::Call* Resolver::TypeConversion(const ast::CallExpression* expr,
|
||||
const sem::Type* target,
|
||||
const sem::Expression* arg,
|
||||
const sem::Type* source) {
|
||||
// It is not valid to have a type-cast call expression inside a call
|
||||
// statement.
|
||||
if (current_statement_) {
|
||||
if (auto* stmt =
|
||||
current_statement_->Declaration()->As<ast::CallStatement>()) {
|
||||
if (stmt->expr == expr) {
|
||||
AddError("type cast evaluated but not used", expr->source);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto* call_target = utils::GetOrCreate(
|
||||
type_conversions_, TypeConversionSig{target, source},
|
||||
[&]() -> sem::TypeConversion* {
|
||||
// Now that the argument types have been determined, make sure that they
|
||||
// obey the conversion rules laid out in
|
||||
// https://gpuweb.github.io/gpuweb/wgsl/#conversion-expr.
|
||||
bool ok = true;
|
||||
if (auto* vec_type = target->As<sem::Vector>()) {
|
||||
ok = ValidateVectorConstructorOrCast(expr, vec_type);
|
||||
} else if (auto* mat_type = target->As<sem::Matrix>()) {
|
||||
// Note: Matrix types currently cannot be converted (the element type
|
||||
// must only be f32). We implement this for the day we support other
|
||||
// matrix element types.
|
||||
ok = ValidateMatrixConstructorOrCast(expr, mat_type);
|
||||
} else if (target->is_scalar()) {
|
||||
ok = ValidateScalarConstructorOrCast(expr, target);
|
||||
} else if (auto* arr_type = target->As<sem::Array>()) {
|
||||
ok = ValidateArrayConstructorOrCast(expr, arr_type);
|
||||
} else if (auto* struct_type = target->As<sem::Struct>()) {
|
||||
ok = ValidateStructureConstructorOrCast(expr, struct_type);
|
||||
} else {
|
||||
AddError("type is not constructible", expr->source);
|
||||
return nullptr;
|
||||
}
|
||||
if (!ok) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* param = builder_->create<sem::Parameter>(
|
||||
nullptr, // declaration
|
||||
0, // index
|
||||
source->UnwrapRef(), // type
|
||||
ast::StorageClass::kNone, // storage_class
|
||||
ast::Access::kUndefined); // access
|
||||
return builder_->create<sem::TypeConversion>(target, param);
|
||||
});
|
||||
|
||||
if (!call_target) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Now that the argument types have been determined, make sure that they
|
||||
// obey the constructor type rules laid out in
|
||||
// https://gpuweb.github.io/gpuweb/wgsl.html#type-constructor-expr.
|
||||
bool ok = true;
|
||||
if (auto* vec_type = ty->As<sem::Vector>()) {
|
||||
ok = ValidateVectorConstructor(expr, vec_type);
|
||||
} else if (auto* mat_type = ty->As<sem::Matrix>()) {
|
||||
ok = ValidateMatrixConstructor(expr, mat_type);
|
||||
} else if (ty->is_scalar()) {
|
||||
ok = ValidateScalarConstructor(expr, ty);
|
||||
} else if (auto* arr_type = ty->As<sem::Array>()) {
|
||||
ok = ValidateArrayConstructor(expr, arr_type);
|
||||
} else if (auto* struct_type = ty->As<sem::Struct>()) {
|
||||
ok = ValidateStructureConstructor(expr, struct_type);
|
||||
} else {
|
||||
AddError("type is not constructible", expr->source);
|
||||
return nullptr;
|
||||
auto val = EvaluateConstantValue(expr, target);
|
||||
return builder_->create<sem::Call>(expr, call_target,
|
||||
std::vector<const sem::Expression*>{arg},
|
||||
current_statement_, val);
|
||||
}
|
||||
|
||||
sem::Call* Resolver::TypeConstructor(
|
||||
const ast::CallExpression* expr,
|
||||
const sem::Type* ty,
|
||||
const std::vector<const sem::Expression*> args,
|
||||
const std::vector<const sem::Type*> arg_tys) {
|
||||
// It is not valid to have a type-constructor call expression as a call
|
||||
// statement.
|
||||
if (current_statement_) {
|
||||
if (auto* stmt =
|
||||
current_statement_->Declaration()->As<ast::CallStatement>()) {
|
||||
if (stmt->expr == expr) {
|
||||
AddError("type constructor evaluated but not used", expr->source);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
|
||||
auto* call_target = utils::GetOrCreate(
|
||||
type_ctors_, TypeConstructorSig{ty, arg_tys},
|
||||
[&]() -> sem::TypeConstructor* {
|
||||
// Now that the argument types have been determined, make sure that they
|
||||
// obey the constructor type rules laid out in
|
||||
// https://gpuweb.github.io/gpuweb/wgsl/#type-constructor-expr.
|
||||
bool ok = true;
|
||||
if (auto* vec_type = ty->As<sem::Vector>()) {
|
||||
ok = ValidateVectorConstructorOrCast(expr, vec_type);
|
||||
} else if (auto* mat_type = ty->As<sem::Matrix>()) {
|
||||
ok = ValidateMatrixConstructorOrCast(expr, mat_type);
|
||||
} else if (ty->is_scalar()) {
|
||||
ok = ValidateScalarConstructorOrCast(expr, ty);
|
||||
} else if (auto* arr_type = ty->As<sem::Array>()) {
|
||||
ok = ValidateArrayConstructorOrCast(expr, arr_type);
|
||||
} else if (auto* struct_type = ty->As<sem::Struct>()) {
|
||||
ok = ValidateStructureConstructorOrCast(expr, struct_type);
|
||||
} else {
|
||||
AddError("type is not constructible", expr->source);
|
||||
return nullptr;
|
||||
}
|
||||
if (!ok) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return builder_->create<sem::TypeConstructor>(
|
||||
ty, utils::Transform(
|
||||
arg_tys,
|
||||
[&](const sem::Type* t, size_t i) -> const sem::Parameter* {
|
||||
return builder_->create<sem::Parameter>(
|
||||
nullptr, // declaration
|
||||
i, // index
|
||||
t->UnwrapRef(), // type
|
||||
ast::StorageClass::kNone, // storage_class
|
||||
ast::Access::kUndefined); // access
|
||||
}));
|
||||
});
|
||||
|
||||
if (!call_target) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto val = EvaluateConstantValue(expr, ty);
|
||||
return builder_->create<sem::Expression>(expr, ty, current_statement_, val);
|
||||
return builder_->create<sem::Call>(expr, call_target, std::move(args),
|
||||
current_statement_, val);
|
||||
}
|
||||
|
||||
sem::Expression* Resolver::Literal(const ast::LiteralExpression* literal) {
|
||||
@@ -2782,26 +2917,26 @@ sem::Expression* Resolver::Literal(const ast::LiteralExpression* literal) {
|
||||
val);
|
||||
}
|
||||
|
||||
bool Resolver::ValidateStructureConstructor(
|
||||
const ast::TypeConstructorExpression* ctor,
|
||||
bool Resolver::ValidateStructureConstructorOrCast(
|
||||
const ast::CallExpression* ctor,
|
||||
const sem::Struct* struct_type) {
|
||||
if (!struct_type->IsConstructible()) {
|
||||
AddError("struct constructor has non-constructible type", ctor->source);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctor->values.size() > 0) {
|
||||
if (ctor->values.size() != struct_type->Members().size()) {
|
||||
if (ctor->args.size() > 0) {
|
||||
if (ctor->args.size() != struct_type->Members().size()) {
|
||||
std::string fm =
|
||||
ctor->values.size() < struct_type->Members().size() ? "few" : "many";
|
||||
ctor->args.size() < struct_type->Members().size() ? "few" : "many";
|
||||
AddError("struct constructor has too " + fm + " inputs: expected " +
|
||||
std::to_string(struct_type->Members().size()) + ", found " +
|
||||
std::to_string(ctor->values.size()),
|
||||
std::to_string(ctor->args.size()),
|
||||
ctor->source);
|
||||
return false;
|
||||
}
|
||||
for (auto* member : struct_type->Members()) {
|
||||
auto* value = ctor->values[member->Index()];
|
||||
auto* value = ctor->args[member->Index()];
|
||||
auto* value_ty = TypeOf(value);
|
||||
if (member->Type() != value_ty->UnwrapRef()) {
|
||||
AddError(
|
||||
@@ -2817,10 +2952,9 @@ bool Resolver::ValidateStructureConstructor(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resolver::ValidateArrayConstructor(
|
||||
const ast::TypeConstructorExpression* ctor,
|
||||
const sem::Array* array_type) {
|
||||
auto& values = ctor->values;
|
||||
bool Resolver::ValidateArrayConstructorOrCast(const ast::CallExpression* ctor,
|
||||
const sem::Array* array_type) {
|
||||
auto& values = ctor->args;
|
||||
auto* elem_ty = array_type->ElemType();
|
||||
for (auto* value : values) {
|
||||
auto* value_ty = TypeOf(value)->UnwrapRef();
|
||||
@@ -2839,7 +2973,7 @@ bool Resolver::ValidateArrayConstructor(
|
||||
return false;
|
||||
} else if (!elem_ty->IsConstructible()) {
|
||||
AddError("array constructor has non-constructible element type",
|
||||
ctor->type->As<ast::Array>()->type->source);
|
||||
ctor->source);
|
||||
return false;
|
||||
} else if (!values.empty() && (values.size() != array_type->Count())) {
|
||||
std::string fm = values.size() < array_type->Count() ? "few" : "many";
|
||||
@@ -2858,10 +2992,9 @@ bool Resolver::ValidateArrayConstructor(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resolver::ValidateVectorConstructor(
|
||||
const ast::TypeConstructorExpression* ctor,
|
||||
const sem::Vector* vec_type) {
|
||||
auto& values = ctor->values;
|
||||
bool Resolver::ValidateVectorConstructorOrCast(const ast::CallExpression* ctor,
|
||||
const sem::Vector* vec_type) {
|
||||
auto& values = ctor->args;
|
||||
auto* elem_ty = vec_type->type();
|
||||
size_t value_cardinality_sum = 0;
|
||||
for (auto* value : values) {
|
||||
@@ -2937,10 +3070,9 @@ bool Resolver::ValidateMatrix(const sem::Matrix* ty, const Source& source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resolver::ValidateMatrixConstructor(
|
||||
const ast::TypeConstructorExpression* ctor,
|
||||
const sem::Matrix* matrix_ty) {
|
||||
auto& values = ctor->values;
|
||||
bool Resolver::ValidateMatrixConstructorOrCast(const ast::CallExpression* ctor,
|
||||
const sem::Matrix* matrix_ty) {
|
||||
auto& values = ctor->args;
|
||||
// Zero Value expression
|
||||
if (values.empty()) {
|
||||
return true;
|
||||
@@ -3000,21 +3132,20 @@ bool Resolver::ValidateMatrixConstructor(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resolver::ValidateScalarConstructor(
|
||||
const ast::TypeConstructorExpression* ctor,
|
||||
const sem::Type* ty) {
|
||||
if (ctor->values.size() == 0) {
|
||||
bool Resolver::ValidateScalarConstructorOrCast(const ast::CallExpression* ctor,
|
||||
const sem::Type* ty) {
|
||||
if (ctor->args.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
if (ctor->values.size() > 1) {
|
||||
if (ctor->args.size() > 1) {
|
||||
AddError("expected zero or one value in constructor, got " +
|
||||
std::to_string(ctor->values.size()),
|
||||
std::to_string(ctor->args.size()),
|
||||
ctor->source);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate constructor
|
||||
auto* value = ctor->values[0];
|
||||
auto* value = ctor->args[0];
|
||||
auto* value_ty = TypeOf(value)->UnwrapRef();
|
||||
|
||||
using Bool = sem::Bool;
|
||||
@@ -4547,5 +4678,37 @@ const sem::Info::GetResultType<SEM, AST_OR_TYPE>* Resolver::Sem(
|
||||
return sem;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Resolver::TypeConversionSig
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Resolver::TypeConversionSig::operator==(
|
||||
const TypeConversionSig& rhs) const {
|
||||
return target == rhs.target && source == rhs.source;
|
||||
}
|
||||
std::size_t Resolver::TypeConversionSig::Hasher::operator()(
|
||||
const TypeConversionSig& sig) const {
|
||||
return utils::Hash(sig.target, sig.source);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Resolver::TypeConstructorSig
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Resolver::TypeConstructorSig::TypeConstructorSig(
|
||||
const sem::Type* ty,
|
||||
const std::vector<const sem::Type*> params)
|
||||
: type(ty), parameters(params) {}
|
||||
Resolver::TypeConstructorSig::TypeConstructorSig(const TypeConstructorSig&) =
|
||||
default;
|
||||
Resolver::TypeConstructorSig::~TypeConstructorSig() = default;
|
||||
|
||||
bool Resolver::TypeConstructorSig::operator==(
|
||||
const TypeConstructorSig& rhs) const {
|
||||
return type == rhs.type && parameters == rhs.parameters;
|
||||
}
|
||||
std::size_t Resolver::TypeConstructorSig::Hasher::operator()(
|
||||
const TypeConstructorSig& sig) const {
|
||||
return utils::Hash(sig.type, sig.parameters);
|
||||
}
|
||||
|
||||
} // namespace resolver
|
||||
} // namespace tint
|
||||
|
||||
@@ -59,6 +59,7 @@ class Array;
|
||||
class Atomic;
|
||||
class Intrinsic;
|
||||
class Statement;
|
||||
class TypeConstructor;
|
||||
} // namespace sem
|
||||
|
||||
namespace resolver {
|
||||
@@ -170,15 +171,26 @@ class Resolver {
|
||||
sem::Expression* IndexAccessor(const ast::IndexAccessorExpression*);
|
||||
sem::Expression* Binary(const ast::BinaryExpression*);
|
||||
sem::Expression* Bitcast(const ast::BitcastExpression*);
|
||||
sem::Expression* Call(const ast::CallExpression*);
|
||||
sem::Call* Call(const ast::CallExpression*);
|
||||
sem::Expression* Expression(const ast::Expression*);
|
||||
sem::Function* Function(const ast::Function*);
|
||||
sem::Call* FunctionCall(const ast::CallExpression*);
|
||||
sem::Call* FunctionCall(const ast::CallExpression*,
|
||||
const std::vector<const sem::Expression*> args);
|
||||
sem::Expression* Identifier(const ast::IdentifierExpression*);
|
||||
sem::Call* IntrinsicCall(const ast::CallExpression*, sem::IntrinsicType);
|
||||
sem::Call* IntrinsicCall(const ast::CallExpression*,
|
||||
sem::IntrinsicType,
|
||||
const std::vector<const sem::Expression*> args,
|
||||
const std::vector<const sem::Type*> arg_tys);
|
||||
sem::Expression* Literal(const ast::LiteralExpression*);
|
||||
sem::Expression* MemberAccessor(const ast::MemberAccessorExpression*);
|
||||
sem::Expression* TypeConstructor(const ast::TypeConstructorExpression*);
|
||||
sem::Call* TypeConversion(const ast::CallExpression* expr,
|
||||
const sem::Type* ty,
|
||||
const sem::Expression* arg,
|
||||
const sem::Type* arg_ty);
|
||||
sem::Call* TypeConstructor(const ast::CallExpression* expr,
|
||||
const sem::Type* ty,
|
||||
const std::vector<const sem::Expression*> args,
|
||||
const std::vector<const sem::Type*> arg_tys);
|
||||
sem::Expression* UnaryOp(const ast::UnaryOpExpression*);
|
||||
|
||||
// Statement resolving methods
|
||||
@@ -211,13 +223,13 @@ class Resolver {
|
||||
bool ValidateBuiltinDecoration(const ast::BuiltinDecoration* deco,
|
||||
const sem::Type* storage_type,
|
||||
const bool is_input);
|
||||
bool ValidateCall(const sem::Call* call);
|
||||
bool ValidateEntryPoint(const sem::Function* func);
|
||||
bool ValidateFunction(const sem::Function* func);
|
||||
bool ValidateFunctionCall(const sem::Call* call);
|
||||
bool ValidateGlobalVariable(const sem::Variable* var);
|
||||
bool ValidateInterpolateDecoration(const ast::InterpolateDecoration* deco,
|
||||
const sem::Type* storage_type);
|
||||
bool ValidateIntrinsicCall(const sem::Call* call);
|
||||
bool ValidateLocationDecoration(const ast::LocationDecoration* location,
|
||||
const sem::Type* type,
|
||||
std::unordered_set<uint32_t>& locations,
|
||||
@@ -234,23 +246,23 @@ class Resolver {
|
||||
bool ValidateStatements(const ast::StatementList& stmts);
|
||||
bool ValidateStorageTexture(const ast::StorageTexture* t);
|
||||
bool ValidateStructure(const sem::Struct* str);
|
||||
bool ValidateStructureConstructor(const ast::TypeConstructorExpression* ctor,
|
||||
const sem::Struct* struct_type);
|
||||
bool ValidateStructureConstructorOrCast(const ast::CallExpression* ctor,
|
||||
const sem::Struct* struct_type);
|
||||
bool ValidateSwitch(const ast::SwitchStatement* s);
|
||||
bool ValidateVariable(const sem::Variable* var);
|
||||
bool ValidateVariableConstructor(const ast::Variable* var,
|
||||
ast::StorageClass storage_class,
|
||||
const sem::Type* storage_type,
|
||||
const sem::Type* rhs_type);
|
||||
bool ValidateVariableConstructorOrCast(const ast::Variable* var,
|
||||
ast::StorageClass storage_class,
|
||||
const sem::Type* storage_type,
|
||||
const sem::Type* rhs_type);
|
||||
bool ValidateVector(const sem::Vector* ty, const Source& source);
|
||||
bool ValidateVectorConstructor(const ast::TypeConstructorExpression* ctor,
|
||||
const sem::Vector* vec_type);
|
||||
bool ValidateMatrixConstructor(const ast::TypeConstructorExpression* ctor,
|
||||
const sem::Matrix* matrix_type);
|
||||
bool ValidateScalarConstructor(const ast::TypeConstructorExpression* ctor,
|
||||
const sem::Type* type);
|
||||
bool ValidateArrayConstructor(const ast::TypeConstructorExpression* ctor,
|
||||
const sem::Array* arr_type);
|
||||
bool ValidateVectorConstructorOrCast(const ast::CallExpression* ctor,
|
||||
const sem::Vector* vec_type);
|
||||
bool ValidateMatrixConstructorOrCast(const ast::CallExpression* ctor,
|
||||
const sem::Matrix* matrix_type);
|
||||
bool ValidateScalarConstructorOrCast(const ast::CallExpression* ctor,
|
||||
const sem::Type* type);
|
||||
bool ValidateArrayConstructorOrCast(const ast::CallExpression* ctor,
|
||||
const sem::Array* arr_type);
|
||||
bool ValidateTypeDecl(const ast::TypeDecl* named_type) const;
|
||||
bool ValidateTextureIntrinsicFunction(const sem::Call* call);
|
||||
bool ValidateNoDuplicateDecorations(const ast::DecorationList& decorations);
|
||||
@@ -378,15 +390,46 @@ class Resolver {
|
||||
const sem::Type* type);
|
||||
sem::Constant EvaluateConstantValue(const ast::LiteralExpression* literal,
|
||||
const sem::Type* type);
|
||||
sem::Constant EvaluateConstantValue(
|
||||
const ast::TypeConstructorExpression* type_ctor,
|
||||
const sem::Type* type);
|
||||
sem::Constant EvaluateConstantValue(const ast::CallExpression* call,
|
||||
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>
|
||||
const sem::Info::GetResultType<SEM, AST_OR_TYPE>* Sem(const AST_OR_TYPE* ast);
|
||||
|
||||
struct TypeConversionSig {
|
||||
const sem::Type* target;
|
||||
const sem::Type* source;
|
||||
|
||||
bool operator==(const TypeConversionSig&) const;
|
||||
|
||||
/// Hasher provides a hash function for the TypeConversionSig
|
||||
struct Hasher {
|
||||
/// @param sig the TypeConversionSig to create a hash for
|
||||
/// @return the hash value
|
||||
std::size_t operator()(const TypeConversionSig& sig) const;
|
||||
};
|
||||
};
|
||||
|
||||
struct TypeConstructorSig {
|
||||
const sem::Type* type;
|
||||
const std::vector<const sem::Type*> parameters;
|
||||
|
||||
TypeConstructorSig(const sem::Type* ty,
|
||||
const std::vector<const sem::Type*> params);
|
||||
TypeConstructorSig(const TypeConstructorSig&);
|
||||
~TypeConstructorSig();
|
||||
bool operator==(const TypeConstructorSig&) const;
|
||||
|
||||
/// Hasher provides a hash function for the TypeConstructorSig
|
||||
struct Hasher {
|
||||
/// @param sig the TypeConstructorSig to create a hash for
|
||||
/// @return the hash value
|
||||
std::size_t operator()(const TypeConstructorSig& sig) const;
|
||||
};
|
||||
};
|
||||
|
||||
ProgramBuilder* const builder_;
|
||||
diag::List& diagnostics_;
|
||||
std::unique_ptr<IntrinsicTable> const intrinsic_table_;
|
||||
@@ -398,6 +441,14 @@ class Resolver {
|
||||
|
||||
std::unordered_set<const ast::Node*> marked_;
|
||||
std::unordered_map<uint32_t, const sem::Variable*> constant_ids_;
|
||||
std::unordered_map<TypeConversionSig,
|
||||
sem::CallTarget*,
|
||||
TypeConversionSig::Hasher>
|
||||
type_conversions_;
|
||||
std::unordered_map<TypeConstructorSig,
|
||||
sem::CallTarget*,
|
||||
TypeConstructorSig::Hasher>
|
||||
type_ctors_;
|
||||
|
||||
sem::Function* current_function_ = nullptr;
|
||||
sem::Statement* current_statement_ = nullptr;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "src/resolver/resolver.h"
|
||||
|
||||
#include "src/sem/constant.h"
|
||||
#include "src/sem/type_constructor.h"
|
||||
#include "src/utils/get_or_create.h"
|
||||
|
||||
namespace tint {
|
||||
@@ -32,7 +33,7 @@ sem::Constant Resolver::EvaluateConstantValue(const ast::Expression* expr,
|
||||
if (auto* e = expr->As<ast::LiteralExpression>()) {
|
||||
return EvaluateConstantValue(e, type);
|
||||
}
|
||||
if (auto* e = expr->As<ast::TypeConstructorExpression>()) {
|
||||
if (auto* e = expr->As<ast::CallExpression>()) {
|
||||
return EvaluateConstantValue(e, type);
|
||||
}
|
||||
return {};
|
||||
@@ -57,10 +58,8 @@ sem::Constant Resolver::EvaluateConstantValue(
|
||||
return {};
|
||||
}
|
||||
|
||||
sem::Constant Resolver::EvaluateConstantValue(
|
||||
const ast::TypeConstructorExpression* type_ctor,
|
||||
const sem::Type* type) {
|
||||
auto& ctor_values = type_ctor->values;
|
||||
sem::Constant Resolver::EvaluateConstantValue(const ast::CallExpression* call,
|
||||
const sem::Type* type) {
|
||||
auto* vec = type->As<sem::Vector>();
|
||||
|
||||
// For now, only fold scalars and vectors
|
||||
@@ -72,7 +71,7 @@ sem::Constant Resolver::EvaluateConstantValue(
|
||||
int result_size = vec ? static_cast<int>(vec->Width()) : 1;
|
||||
|
||||
// For zero value init, return 0s
|
||||
if (ctor_values.empty()) {
|
||||
if (call->args.empty()) {
|
||||
if (elem_type->Is<sem::I32>()) {
|
||||
return sem::Constant(type, sem::Constant::Scalars(result_size, 0));
|
||||
}
|
||||
@@ -90,12 +89,12 @@ sem::Constant Resolver::EvaluateConstantValue(
|
||||
// Build value for type_ctor from each child value by casting to
|
||||
// type_ctor's type.
|
||||
sem::Constant::Scalars elems;
|
||||
for (auto* cv : ctor_values) {
|
||||
auto* expr = builder_->Sem().Get(cv);
|
||||
if (!expr || !expr->ConstantValue()) {
|
||||
for (auto* expr : call->args) {
|
||||
auto* arg = builder_->Sem().Get(expr);
|
||||
if (!arg || !arg->ConstantValue()) {
|
||||
return {};
|
||||
}
|
||||
auto cast = ConstantCast(expr->ConstantValue(), elem_type);
|
||||
auto cast = ConstantCast(arg->ConstantValue(), elem_type);
|
||||
elems.insert(elems.end(), cast.Elements().begin(), cast.Elements().end());
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "gmock/gmock.h"
|
||||
#include "src/resolver/resolver_test_helper.h"
|
||||
#include "src/sem/reference_type.h"
|
||||
#include "src/sem/type_constructor.h"
|
||||
#include "src/sem/type_conversion.h"
|
||||
|
||||
namespace tint {
|
||||
namespace resolver {
|
||||
@@ -223,68 +225,74 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
|
||||
|
||||
} // namespace InferTypeTest
|
||||
|
||||
namespace ConversionConstructorTest {
|
||||
namespace ConversionConstructTest {
|
||||
enum class Kind {
|
||||
Construct,
|
||||
Conversion,
|
||||
};
|
||||
|
||||
struct Params {
|
||||
Kind kind;
|
||||
builder::ast_type_func_ptr lhs_type;
|
||||
builder::ast_type_func_ptr rhs_type;
|
||||
builder::ast_expr_func_ptr rhs_value_expr;
|
||||
};
|
||||
|
||||
template <typename LhsType, typename RhsType>
|
||||
constexpr Params ParamsFor() {
|
||||
return Params{DataType<LhsType>::AST, DataType<RhsType>::AST,
|
||||
constexpr Params ParamsFor(Kind kind) {
|
||||
return Params{kind, DataType<LhsType>::AST, DataType<RhsType>::AST,
|
||||
DataType<RhsType>::Expr};
|
||||
}
|
||||
|
||||
static constexpr Params valid_cases[] = {
|
||||
// Direct init (non-conversions)
|
||||
ParamsFor<bool, bool>(), //
|
||||
ParamsFor<i32, i32>(), //
|
||||
ParamsFor<u32, u32>(), //
|
||||
ParamsFor<f32, f32>(), //
|
||||
ParamsFor<vec3<bool>, vec3<bool>>(), //
|
||||
ParamsFor<vec3<i32>, vec3<i32>>(), //
|
||||
ParamsFor<vec3<u32>, vec3<u32>>(), //
|
||||
ParamsFor<vec3<f32>, vec3<f32>>(), //
|
||||
ParamsFor<bool, bool>(Kind::Construct), //
|
||||
ParamsFor<i32, i32>(Kind::Construct), //
|
||||
ParamsFor<u32, u32>(Kind::Construct), //
|
||||
ParamsFor<f32, f32>(Kind::Construct), //
|
||||
ParamsFor<vec3<bool>, vec3<bool>>(Kind::Construct), //
|
||||
ParamsFor<vec3<i32>, vec3<i32>>(Kind::Construct), //
|
||||
ParamsFor<vec3<u32>, vec3<u32>>(Kind::Construct), //
|
||||
ParamsFor<vec3<f32>, vec3<f32>>(Kind::Construct), //
|
||||
|
||||
// Splat
|
||||
ParamsFor<vec3<bool>, bool>(), //
|
||||
ParamsFor<vec3<i32>, i32>(), //
|
||||
ParamsFor<vec3<u32>, u32>(), //
|
||||
ParamsFor<vec3<f32>, f32>(), //
|
||||
ParamsFor<vec3<bool>, bool>(Kind::Construct), //
|
||||
ParamsFor<vec3<i32>, i32>(Kind::Construct), //
|
||||
ParamsFor<vec3<u32>, u32>(Kind::Construct), //
|
||||
ParamsFor<vec3<f32>, f32>(Kind::Construct), //
|
||||
|
||||
// Conversion
|
||||
ParamsFor<bool, u32>(), //
|
||||
ParamsFor<bool, i32>(), //
|
||||
ParamsFor<bool, f32>(), //
|
||||
ParamsFor<bool, u32>(Kind::Conversion), //
|
||||
ParamsFor<bool, i32>(Kind::Conversion), //
|
||||
ParamsFor<bool, f32>(Kind::Conversion), //
|
||||
|
||||
ParamsFor<i32, bool>(), //
|
||||
ParamsFor<i32, u32>(), //
|
||||
ParamsFor<i32, f32>(), //
|
||||
ParamsFor<i32, bool>(Kind::Conversion), //
|
||||
ParamsFor<i32, u32>(Kind::Conversion), //
|
||||
ParamsFor<i32, f32>(Kind::Conversion), //
|
||||
|
||||
ParamsFor<u32, bool>(), //
|
||||
ParamsFor<u32, i32>(), //
|
||||
ParamsFor<u32, f32>(), //
|
||||
ParamsFor<u32, bool>(Kind::Conversion), //
|
||||
ParamsFor<u32, i32>(Kind::Conversion), //
|
||||
ParamsFor<u32, f32>(Kind::Conversion), //
|
||||
|
||||
ParamsFor<f32, bool>(), //
|
||||
ParamsFor<f32, u32>(), //
|
||||
ParamsFor<f32, i32>(), //
|
||||
ParamsFor<f32, bool>(Kind::Conversion), //
|
||||
ParamsFor<f32, u32>(Kind::Conversion), //
|
||||
ParamsFor<f32, i32>(Kind::Conversion), //
|
||||
|
||||
ParamsFor<vec3<bool>, vec3<u32>>(), //
|
||||
ParamsFor<vec3<bool>, vec3<i32>>(), //
|
||||
ParamsFor<vec3<bool>, vec3<f32>>(), //
|
||||
ParamsFor<vec3<bool>, vec3<u32>>(Kind::Conversion), //
|
||||
ParamsFor<vec3<bool>, vec3<i32>>(Kind::Conversion), //
|
||||
ParamsFor<vec3<bool>, vec3<f32>>(Kind::Conversion), //
|
||||
|
||||
ParamsFor<vec3<i32>, vec3<bool>>(), //
|
||||
ParamsFor<vec3<i32>, vec3<u32>>(), //
|
||||
ParamsFor<vec3<i32>, vec3<f32>>(), //
|
||||
ParamsFor<vec3<i32>, vec3<bool>>(Kind::Conversion), //
|
||||
ParamsFor<vec3<i32>, vec3<u32>>(Kind::Conversion), //
|
||||
ParamsFor<vec3<i32>, vec3<f32>>(Kind::Conversion), //
|
||||
|
||||
ParamsFor<vec3<u32>, vec3<bool>>(), //
|
||||
ParamsFor<vec3<u32>, vec3<i32>>(), //
|
||||
ParamsFor<vec3<u32>, vec3<f32>>(), //
|
||||
ParamsFor<vec3<u32>, vec3<bool>>(Kind::Conversion), //
|
||||
ParamsFor<vec3<u32>, vec3<i32>>(Kind::Conversion), //
|
||||
ParamsFor<vec3<u32>, vec3<f32>>(Kind::Conversion), //
|
||||
|
||||
ParamsFor<vec3<f32>, vec3<bool>>(), //
|
||||
ParamsFor<vec3<f32>, vec3<u32>>(), //
|
||||
ParamsFor<vec3<f32>, vec3<i32>>(), //
|
||||
ParamsFor<vec3<f32>, vec3<bool>>(Kind::Conversion), //
|
||||
ParamsFor<vec3<f32>, vec3<u32>>(Kind::Conversion), //
|
||||
ParamsFor<vec3<f32>, vec3<i32>>(Kind::Conversion), //
|
||||
};
|
||||
|
||||
using ConversionConstructorValidTest = ResolverTestWithParam<Params>;
|
||||
@@ -302,8 +310,9 @@ TEST_P(ConversionConstructorValidTest, All) {
|
||||
<< FriendlyName(rhs_type) << "(<rhs value expr>))";
|
||||
SCOPED_TRACE(ss.str());
|
||||
|
||||
auto* a = Var("a", lhs_type1, ast::StorageClass::kNone,
|
||||
Construct(lhs_type2, Construct(rhs_type, rhs_value_expr)));
|
||||
auto* arg = Construct(rhs_type, rhs_value_expr);
|
||||
auto* tc = Construct(lhs_type2, arg);
|
||||
auto* a = Var("a", lhs_type1, ast::StorageClass::kNone, tc);
|
||||
|
||||
// Self-assign 'a' to force the expression to be resolved so we can test its
|
||||
// type below
|
||||
@@ -311,6 +320,27 @@ TEST_P(ConversionConstructorValidTest, All) {
|
||||
WrapInFunction(Decl(a), Assign(a_ident, "a"));
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
switch (params.kind) {
|
||||
case Kind::Construct: {
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 1u);
|
||||
EXPECT_EQ(ctor->Parameters()[0]->Type(), TypeOf(arg));
|
||||
break;
|
||||
}
|
||||
case Kind::Conversion: {
|
||||
auto* conv = call->Target()->As<sem::TypeConversion>();
|
||||
ASSERT_NE(conv, nullptr);
|
||||
EXPECT_EQ(call->Type(), conv->ReturnType());
|
||||
ASSERT_EQ(conv->Parameters().size(), 1u);
|
||||
EXPECT_EQ(conv->Parameters()[0]->Type(), TypeOf(arg));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
|
||||
ConversionConstructorValidTest,
|
||||
@@ -408,7 +438,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
"'array<f32, 4>'");
|
||||
}
|
||||
|
||||
} // namespace ConversionConstructorTest
|
||||
} // namespace ConversionConstructTest
|
||||
|
||||
namespace ArrayConstructor {
|
||||
|
||||
@@ -418,7 +448,15 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = array<u32, 10>();
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve());
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
EXPECT_TRUE(call->Type()->Is<sem::Array>());
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -427,7 +465,18 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = array<u32, 3>(Expr(0u), Expr(10u), Expr(20u));
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve());
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
EXPECT_TRUE(call->Type()->Is<sem::Array>());
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 3u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
|
||||
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::U32>());
|
||||
EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::U32>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -587,6 +636,118 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
|
||||
} // namespace ArrayConstructor
|
||||
|
||||
namespace ScalarConstructor {
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest, Expr_Construct_i32_Success) {
|
||||
auto* expr = Construct<i32>(Expr(123));
|
||||
WrapInFunction(expr);
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(expr), nullptr);
|
||||
ASSERT_TRUE(TypeOf(expr)->Is<sem::I32>());
|
||||
|
||||
auto* call = Sem().Get(expr);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 1u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest, Expr_Construct_u32_Success) {
|
||||
auto* expr = Construct<u32>(Expr(123u));
|
||||
WrapInFunction(expr);
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(expr), nullptr);
|
||||
ASSERT_TRUE(TypeOf(expr)->Is<sem::U32>());
|
||||
|
||||
auto* call = Sem().Get(expr);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 1u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest, Expr_Construct_f32_Success) {
|
||||
auto* expr = Construct<f32>(Expr(1.23f));
|
||||
WrapInFunction(expr);
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(expr), nullptr);
|
||||
ASSERT_TRUE(TypeOf(expr)->Is<sem::F32>());
|
||||
|
||||
auto* call = Sem().Get(expr);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 1u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest, Expr_Convert_f32_to_i32_Success) {
|
||||
auto* expr = Construct<i32>(1.23f);
|
||||
WrapInFunction(expr);
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(expr), nullptr);
|
||||
ASSERT_TRUE(TypeOf(expr)->Is<sem::I32>());
|
||||
|
||||
auto* call = Sem().Get(expr);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConversion>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 1u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest, Expr_Convert_i32_to_u32_Success) {
|
||||
auto* expr = Construct<u32>(123);
|
||||
WrapInFunction(expr);
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(expr), nullptr);
|
||||
ASSERT_TRUE(TypeOf(expr)->Is<sem::U32>());
|
||||
|
||||
auto* call = Sem().Get(expr);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConversion>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 1u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest, Expr_Convert_u32_to_f32_Success) {
|
||||
auto* expr = Construct<f32>(123u);
|
||||
WrapInFunction(expr);
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(expr), nullptr);
|
||||
ASSERT_TRUE(TypeOf(expr)->Is<sem::F32>());
|
||||
|
||||
auto* call = Sem().Get(expr);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConversion>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 1u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
|
||||
}
|
||||
|
||||
} // namespace ScalarConstructor
|
||||
|
||||
namespace VectorConstructor {
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -708,12 +869,19 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec2<f32>();
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
|
||||
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -721,12 +889,21 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec2<f32>(1.0f, 1.0f);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
|
||||
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 2u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
|
||||
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::F32>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -734,12 +911,21 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec2<u32>(1u, 1u);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::U32>());
|
||||
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 2u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
|
||||
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::U32>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -747,12 +933,21 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec2<i32>(1, 1);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::I32>());
|
||||
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 2u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
|
||||
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -760,12 +955,21 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec2<bool>(true, false);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::Bool>());
|
||||
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 2u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Bool>());
|
||||
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Bool>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -773,12 +977,20 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec2<f32>(vec2<f32>());
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
|
||||
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 1u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -786,12 +998,20 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec2<f32>(vec2<i32>());
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
|
||||
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConversion>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 1u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -938,12 +1158,19 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec3<f32>();
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
|
||||
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -951,12 +1178,22 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec3<f32>(1.0f, 1.0f, 1.0f);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
|
||||
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 3u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
|
||||
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::F32>());
|
||||
EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::F32>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -964,12 +1201,22 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec3<u32>(1u, 1u, 1u);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::U32>());
|
||||
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 3u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
|
||||
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::U32>());
|
||||
EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::U32>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -977,12 +1224,22 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec3<i32>(1, 1, 1);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::I32>());
|
||||
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 3u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
|
||||
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
|
||||
EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -990,12 +1247,22 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec3<bool>(true, false, true);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::Bool>());
|
||||
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 3u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Bool>());
|
||||
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Bool>());
|
||||
EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::Bool>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -1003,12 +1270,21 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec3<f32>(vec2<f32>(), 1.0f);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
|
||||
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 2u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
|
||||
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::F32>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -1016,12 +1292,21 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec3<f32>(1.0f, vec2<f32>());
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
|
||||
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 2u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
|
||||
EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Vector>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -1029,12 +1314,20 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec3<f32>(vec3<f32>());
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
|
||||
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConstructor>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 1u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -1042,12 +1335,20 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec3<f32>(vec3<i32>());
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
|
||||
EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
|
||||
|
||||
auto* call = Sem().Get(tc);
|
||||
ASSERT_NE(call, nullptr);
|
||||
auto* ctor = call->Target()->As<sem::TypeConversion>();
|
||||
ASSERT_NE(ctor, nullptr);
|
||||
EXPECT_EQ(call->Type(), ctor->ReturnType());
|
||||
ASSERT_EQ(ctor->Parameters().size(), 1u);
|
||||
EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -1248,7 +1549,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec4<f32>();
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
@@ -1261,7 +1562,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
@@ -1274,7 +1575,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec4<u32>(1u, 1u, 1u, 1u);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
@@ -1287,7 +1588,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec4<i32>(1, 1, 1, 1);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
@@ -1300,7 +1601,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec4<bool>(true, false, true, false);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
@@ -1313,7 +1614,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec4<f32>(vec2<f32>(), 1.0f, 1.0f);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
@@ -1326,7 +1627,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec4<f32>(1.0f, vec2<f32>(), 1.0f);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
@@ -1339,7 +1640,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec4<f32>(1.0f, 1.0f, vec2<f32>());
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
@@ -1352,7 +1653,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec4<f32>(vec2<f32>(), vec2<f32>());
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
@@ -1365,7 +1666,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec4<f32>(vec3<f32>(), 1.0f);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
@@ -1378,7 +1679,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec4<f32>(1.0f, vec3<f32>());
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
@@ -1391,7 +1692,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec4<f32>(vec4<f32>());
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
@@ -1404,7 +1705,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec4<f32>(vec4<i32>());
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
@@ -1431,7 +1732,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec4<f32>(vec3<f32>(vec2<f32>(1.0f, 1.0f), 1.0f), 1.0f);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
ASSERT_NE(TypeOf(tc), nullptr);
|
||||
ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
|
||||
@@ -1462,7 +1763,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
|
||||
auto* tc = vec3<f32>("my_vec2", "my_f32");
|
||||
WrapInFunction(tc);
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -1490,7 +1791,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = Construct(Source{{12, 34}}, vec_type, 1.0f, 1.0f);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -1517,7 +1818,7 @@ TEST_F(ResolverTypeConstructorValidationTest,
|
||||
auto* tc = vec3<f32>(Construct(Source{{12, 34}}, vec_type), 1.0f);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
} // namespace VectorConstructor
|
||||
@@ -1728,7 +2029,7 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ZeroValue_Success) {
|
||||
auto* tc = Construct(Source{{12, 40}}, matrix_type);
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
TEST_P(MatrixConstructorTest, Expr_Constructor_WithColumns_Success) {
|
||||
@@ -1746,7 +2047,7 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_WithColumns_Success) {
|
||||
auto* tc = Construct(Source{}, matrix_type, std::move(args));
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
TEST_P(MatrixConstructorTest, Expr_Constructor_WithElements_Success) {
|
||||
@@ -1763,7 +2064,7 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_WithElements_Success) {
|
||||
auto* tc = Construct(Source{}, matrix_type, std::move(args));
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
TEST_P(MatrixConstructorTest, Expr_Constructor_ElementTypeAlias_Error) {
|
||||
@@ -1804,7 +2105,7 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ElementTypeAlias_Success) {
|
||||
auto* tc = Construct(Source{}, matrix_type, std::move(args));
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
@@ -1839,7 +2140,7 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentTypeAlias_Success) {
|
||||
auto* tc = Construct(Source{}, matrix_type, std::move(args));
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentElementTypeAlias_Error) {
|
||||
@@ -1877,7 +2178,7 @@ TEST_P(MatrixConstructorTest,
|
||||
auto* tc = Construct(Source{}, matrix_type, std::move(args));
|
||||
WrapInFunction(tc);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
|
||||
@@ -2044,7 +2345,7 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Struct) {
|
||||
auto* s = Structure("MyInputs", {m});
|
||||
auto* tc = Construct(Source{{12, 34}}, ty.Of(s));
|
||||
WrapInFunction(tc);
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Struct_Empty) {
|
||||
@@ -2055,7 +2356,7 @@ TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Struct_Empty) {
|
||||
});
|
||||
|
||||
WrapInFunction(Construct(ty.Of(str)));
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
} // namespace StructConstructor
|
||||
|
||||
@@ -2070,7 +2371,7 @@ TEST_F(ResolverTypeConstructorValidationTest, NonConstructibleType_Atomic) {
|
||||
TEST_F(ResolverTypeConstructorValidationTest,
|
||||
NonConstructibleType_AtomicArray) {
|
||||
WrapInFunction(Call(
|
||||
"ignore", Construct(ty.array(ty.atomic(Source{{12, 34}}, ty.i32()), 4))));
|
||||
"ignore", Construct(Source{{12, 34}}, ty.array(ty.atomic(ty.i32()), 4))));
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(
|
||||
@@ -2097,6 +2398,22 @@ TEST_F(ResolverTypeConstructorValidationTest, NonConstructibleType_Sampler) {
|
||||
EXPECT_EQ(r()->error(), "12:34 error: type is not constructible");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest, TypeConstructorAsStatement) {
|
||||
WrapInFunction(
|
||||
CallStmt(Construct(Source{{12, 34}}, ty.vec2<f32>(), 1.f, 2.f)));
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(),
|
||||
"12:34 error: type constructor evaluated but not used");
|
||||
}
|
||||
|
||||
TEST_F(ResolverTypeConstructorValidationTest, TypeConversionAsStatement) {
|
||||
WrapInFunction(CallStmt(Construct(Source{{12, 34}}, ty.f32(), 1)));
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(), "12:34 error: type cast evaluated but not used");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace resolver
|
||||
} // namespace tint
|
||||
|
||||
Reference in New Issue
Block a user