tint/resolver: Handle array() constructors
If the array constructor has no explicit type and count, infer from the
arguments.
Implement and test array materialization.
Also:
* Change sem::AbstractNumeric::IsConstructable() to return true. This
has changed in the WGSL spec.
* Fix the test-helper builder for DataType<array<N, T>> - it was
incorrectly calculating the array size.
Bug: tint:1628
Change-Id: I0ec4e55b469ca6423b4d1848f27bb11df4fa683b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/97663
Commit-Queue: Ben Clayton <bclayton@chromium.org>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index da6cfe2..3af15ab 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -1316,7 +1316,9 @@
return nullptr;
}
-const sem::Type* Resolver::ConcreteType(const sem::Type* ty, const sem::Type* target_ty) {
+const sem::Type* Resolver::ConcreteType(const sem::Type* ty,
+ const sem::Type* target_ty,
+ const Source& source) {
auto i32 = [&] { return builder_->create<sem::I32>(); };
auto f32 = [&] { return builder_->create<sem::F32>(); };
auto i32v = [&](uint32_t width) { return builder_->create<sem::Vector>(i32(), width); };
@@ -1342,6 +1344,16 @@
[&](const sem::AbstractFloat*) {
return target_ty ? target_ty : f32m(m->columns(), m->rows());
});
+ },
+ [&](const sem::Array* a) -> const sem::Type* {
+ const sem::Type* target_el_ty = nullptr;
+ if (auto* target_arr_ty = As<sem::Array>(target_ty)) {
+ target_el_ty = target_arr_ty->ElemType();
+ }
+ if (auto* el_ty = ConcreteType(a->ElemType(), target_el_ty, source)) {
+ return Array(source, el_ty, a->Count(), /* explicit_stride */ 0);
+ }
+ return nullptr;
});
}
@@ -1354,7 +1366,7 @@
auto* decl = expr->Declaration();
- auto* concrete_ty = ConcreteType(expr->Type(), target_type);
+ auto* concrete_ty = ConcreteType(expr->Type(), target_type, decl->source);
if (!concrete_ty) {
return expr; // Does not require materialization
}
@@ -1579,16 +1591,14 @@
auto* call_target = utils::GetOrCreate(
array_ctors_, ArrayConstructorSig{{arr, args.Length(), args_stage}},
[&]() -> sem::TypeConstructor* {
- utils::Vector<const sem::Parameter*, 8> params;
- params.Reserve(args.Length());
- for (size_t i = 0; i < args.Length(); i++) {
- params.Push(builder_->create<sem::Parameter>(
- nullptr, // declaration
- static_cast<uint32_t>(i), // index
- arr->ElemType(), // type
- ast::StorageClass::kNone, // storage_class
- ast::Access::kUndefined)); // access
- }
+ auto params = utils::Transform(args, [&](auto, size_t i) {
+ return builder_->create<sem::Parameter>(
+ nullptr, // declaration
+ static_cast<uint32_t>(i), // index
+ arr->ElemType(), // type
+ ast::StorageClass::kNone, // storage_class
+ ast::Access::kUndefined);
+ });
return builder_->create<sem::TypeConstructor>(arr, std::move(params),
args_stage);
});
@@ -1679,6 +1689,59 @@
}
return nullptr;
},
+ [&](const ast::Array* a) -> sem::Call* {
+ Mark(a);
+ // array element type must be inferred if it was not specified.
+ auto el_count = static_cast<uint32_t>(args.Length());
+ const sem::Type* el_ty = nullptr;
+ if (a->type) {
+ el_ty = Type(a->type);
+ if (!el_ty) {
+ return nullptr;
+ }
+ if (!a->count) {
+ AddError("cannot construct a runtime-sized array", expr->source);
+ return nullptr;
+ }
+ if (auto count = ArrayCount(a->count)) {
+ el_count = count.Get();
+ } else {
+ return nullptr;
+ }
+ // Note: validation later will detect any mismatches between explicit array
+ // size and number of constructor expressions.
+ } else {
+ auto arg_tys =
+ utils::Transform(args, [](auto* arg) { return arg->Type()->UnwrapRef(); });
+ el_ty = sem::Type::Common(arg_tys);
+ if (!el_ty) {
+ AddError(
+ "cannot infer common array element type from constructor arguments",
+ expr->source);
+ std::unordered_set<const sem::Type*> types;
+ for (size_t i = 0; i < args.Length(); i++) {
+ if (types.emplace(args[i]->Type()).second) {
+ AddNote("argument " + std::to_string(i) + " is of type '" +
+ sem_.TypeNameOf(args[i]->Type()) + "'",
+ args[i]->Declaration()->source);
+ }
+ }
+ return nullptr;
+ }
+ }
+ uint32_t explicit_stride = 0;
+ if (!ArrayAttributes(a->attributes, el_ty, explicit_stride)) {
+ return nullptr;
+ }
+
+ auto* arr = Array(a->source, el_ty, el_count, explicit_stride);
+ if (!arr) {
+ return nullptr;
+ }
+ builder_->Sem().Add(a, arr);
+
+ return ty_ctor_or_conv(arr);
+ },
[&](const ast::Type* ast) -> sem::Call* {
// Handler for AST types that do not have an optional element type.
if (auto* ty = Type(ast)) {