Make TypedIntegers work with absl::Format.

This avoids the need for a bunch of static casts in places when trying
to print them in error messages.

Bug: dawn:2222
Change-Id: I9621d670a3223b9b2d15f0c034d8cfc2acf2f314
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/161688
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Brandon Jones <bajones@chromium.org>
diff --git a/generator/templates/dawn/native/ValidationUtils.cpp b/generator/templates/dawn/native/ValidationUtils.cpp
index 6461359..95dcddd 100644
--- a/generator/templates/dawn/native/ValidationUtils.cpp
+++ b/generator/templates/dawn/native/ValidationUtils.cpp
@@ -42,7 +42,7 @@
                         return {};
                 {% endfor %}
                 default:
-                    return DAWN_VALIDATION_ERROR("Value %i is invalid for {{as_cType(type.name)}}.", static_cast<uint32_t>(value));
+                    return DAWN_VALIDATION_ERROR("Value %i is invalid for {{as_cType(type.name)}}.", value);
             }
         }
 
@@ -53,7 +53,7 @@
             if ((value & static_cast<{{namespace}}::{{as_cppType(type.name)}}>(~{{type.full_mask}})) == 0) {
                 return {};
             }
-            return DAWN_VALIDATION_ERROR("Value %i is invalid for {{as_cType(type.name)}}.", static_cast<uint32_t>(value));
+            return DAWN_VALIDATION_ERROR("Value %i is invalid for {{as_cType(type.name)}}.", value);
         }
 
     {% endfor %}
diff --git a/src/dawn/native/CommandBufferStateTracker.cpp b/src/dawn/native/CommandBufferStateTracker.cpp
index 900eac1..4946180 100644
--- a/src/dawn/native/CommandBufferStateTracker.cpp
+++ b/src/dawn/native/CommandBufferStateTracker.cpp
@@ -409,8 +409,7 @@
             DAWN_INVALID_IF(vertexBuffer.usedBytesInStride > bufferSize,
                             "Bound vertex buffer size (%u) at slot %u with an arrayStride of 0 "
                             "is smaller than the required size for all attributes (%u)",
-                            bufferSize, static_cast<uint8_t>(usedSlotVertex),
-                            vertexBuffer.usedBytesInStride);
+                            bufferSize, usedSlotVertex, vertexBuffer.usedBytesInStride);
         } else {
             DAWN_ASSERT(strideCount != 0u);
             uint64_t requiredSize = (strideCount - 1u) * arrayStride + vertexBuffer.lastStride;
@@ -425,8 +424,7 @@
                 "Vertex range (first: %u, count: %u) requires a larger buffer (%u) than "
                 "the "
                 "bound buffer size (%u) of the vertex buffer at slot %u with stride %u.",
-                firstVertex, vertexCount, requiredSize, bufferSize,
-                static_cast<uint8_t>(usedSlotVertex), arrayStride);
+                firstVertex, vertexCount, requiredSize, bufferSize, usedSlotVertex, arrayStride);
         }
     }
 
@@ -457,8 +455,7 @@
             DAWN_INVALID_IF(vertexBuffer.usedBytesInStride > bufferSize,
                             "Bound vertex buffer size (%u) at slot %u with an arrayStride of 0 "
                             "is smaller than the required size for all attributes (%u)",
-                            bufferSize, static_cast<uint8_t>(usedSlotInstance),
-                            vertexBuffer.usedBytesInStride);
+                            bufferSize, usedSlotInstance, vertexBuffer.usedBytesInStride);
         } else {
             DAWN_ASSERT(strideCount != 0u);
             uint64_t requiredSize = (strideCount - 1u) * arrayStride + vertexBuffer.lastStride;
@@ -473,8 +470,8 @@
                 "Instance range (first: %u, count: %u) requires a larger buffer (%u) than "
                 "the "
                 "bound buffer size (%u) of the vertex buffer at slot %u with stride %u.",
-                firstInstance, instanceCount, requiredSize, bufferSize,
-                static_cast<uint8_t>(usedSlotInstance), arrayStride);
+                firstInstance, instanceCount, requiredSize, bufferSize, usedSlotInstance,
+                arrayStride);
         }
     }
 
@@ -618,8 +615,7 @@
         for (BindGroupIndex i : IterateBitSet(mLastPipelineLayout->GetBindGroupLayoutsMask())) {
             DAWN_ASSERT(HasPipeline());
 
-            DAWN_INVALID_IF(mBindgroups[i] == nullptr, "No bind group set at group index %u.",
-                            static_cast<uint32_t>(i));
+            DAWN_INVALID_IF(mBindgroups[i] == nullptr, "No bind group set at group index %u.", i);
 
             BindGroupLayoutBase* requiredBGL = mLastPipelineLayout->GetFrontendBindGroupLayout(i);
             BindGroupLayoutBase* currentBGL = mBindgroups[i]->GetFrontendLayout();
@@ -633,8 +629,7 @@
                 "created by the pipeline. Either use the bind group layout returned by calling "
                 "getBindGroupLayout(%u) on the pipeline when creating the bind group, or "
                 "provide an explicit pipeline layout when creating the pipeline.",
-                mLastPipeline, mBindgroups[i], static_cast<uint32_t>(i), currentBGL,
-                static_cast<uint32_t>(i));
+                mLastPipeline, mBindgroups[i], i, currentBGL, i);
 
             DAWN_INVALID_IF(
                 requiredBGL->GetPipelineCompatibilityToken() == PipelineCompatibilityToken(0) &&
@@ -645,15 +640,14 @@
                 "compatible. Use an explicit bind group layout when creating bind groups and "
                 "an explicit pipeline layout when creating pipelines to share bind groups "
                 "between pipelines.",
-                mBindgroups[i], static_cast<uint32_t>(i), currentBGL, mLastPipeline);
+                mBindgroups[i], i, currentBGL, mLastPipeline);
 
             DAWN_INVALID_IF(
                 requiredBGL->GetInternalBindGroupLayout() !=
                     currentBGL->GetInternalBindGroupLayout(),
                 "Bind group layout %s of pipeline layout %s does not match layout %s of bind "
                 "group %s set at group index %u.",
-                requiredBGL, mLastPipelineLayout, currentBGL, mBindgroups[i],
-                static_cast<uint32_t>(i));
+                requiredBGL, mLastPipelineLayout, currentBGL, mBindgroups[i], i);
 
             std::optional<uint32_t> packedIndex = FindFirstUndersizedBuffer(
                 mBindgroups[i]->GetUnverifiedBufferSizes(), (*mMinBufferSizes)[i]);
@@ -683,8 +677,7 @@
                 return DAWN_VALIDATION_ERROR(
                     "%s bound with size %u at group %u, binding %u is too small. The pipeline (%s) "
                     "requires a buffer binding which is at least %u bytes.%s",
-                    buffer, bufferSize, static_cast<uint32_t>(i),
-                    static_cast<uint32_t>(bindingNumber), mLastPipeline, minBufferSize,
+                    buffer, bufferSize, i, bindingNumber, mLastPipeline, minBufferSize,
                     (bindingInfo.buffer.type == wgpu::BufferBindingType::Uniform
                          ? " This binding is a uniform buffer binding. It is padded to a multiple "
                            "of 16 bytes, and as a result may be larger than the associated data in "
@@ -702,11 +695,9 @@
                 "Writable storage buffer binding aliasing found between %s set at bind group index "
                 "%u, binding index %u, and %s set at bind group index %u, binding index %u, with "
                 "overlapping ranges (offset: %u, size: %u) and (offset: %u, size: %u) in %s.",
-                mBindgroups[a.e0.bindGroupIndex], static_cast<uint32_t>(a.e0.bindGroupIndex),
-                static_cast<uint32_t>(a.e0.bindingIndex), mBindgroups[a.e1.bindGroupIndex],
-                static_cast<uint32_t>(a.e1.bindGroupIndex),
-                static_cast<uint32_t>(a.e1.bindingIndex), a.e0.offset, a.e0.size, a.e1.offset,
-                a.e1.size,
+                mBindgroups[a.e0.bindGroupIndex], a.e0.bindGroupIndex, a.e0.bindingIndex,
+                mBindgroups[a.e1.bindGroupIndex], a.e1.bindGroupIndex, a.e1.bindingIndex,
+                a.e0.offset, a.e0.size, a.e1.offset, a.e1.size,
                 mBindgroups[a.e0.bindGroupIndex]
                     ->GetBindingAsBufferBinding(a.e0.bindingIndex)
                     .buffer);
@@ -719,12 +710,10 @@
                 "with subresources (base mipmap level: %u, mip level count: %u, base array layer: "
                 "%u, array layer count: %u) and (base mipmap level: %u, mip level count: %u, base "
                 "array layer: %u, array layer count: %u) in %s.",
-                mBindgroups[a.e0.bindGroupIndex], static_cast<uint32_t>(a.e0.bindGroupIndex),
-                static_cast<uint32_t>(a.e0.bindingIndex), mBindgroups[a.e1.bindGroupIndex],
-                static_cast<uint32_t>(a.e1.bindGroupIndex),
-                static_cast<uint32_t>(a.e1.bindingIndex), a.e0.baseMipLevel, a.e0.mipLevelCount,
-                a.e0.baseArrayLayer, a.e0.arrayLayerCount, a.e1.baseMipLevel, a.e1.mipLevelCount,
-                a.e1.baseArrayLayer, a.e1.arrayLayerCount,
+                mBindgroups[a.e0.bindGroupIndex], a.e0.bindGroupIndex, a.e0.bindingIndex,
+                mBindgroups[a.e1.bindGroupIndex], a.e1.bindGroupIndex, a.e1.bindingIndex,
+                a.e0.baseMipLevel, a.e0.mipLevelCount, a.e0.baseArrayLayer, a.e0.arrayLayerCount,
+                a.e1.baseMipLevel, a.e1.mipLevelCount, a.e1.baseArrayLayer, a.e1.arrayLayerCount,
                 mBindgroups[a.e0.bindGroupIndex]
                     ->GetBindingAsTextureView(a.e0.bindingIndex)
                     ->GetTexture());
diff --git a/src/dawn/native/Pipeline.cpp b/src/dawn/native/Pipeline.cpp
index 49664f3..347c738 100644
--- a/src/dawn/native/Pipeline.cpp
+++ b/src/dawn/native/Pipeline.cpp
@@ -272,11 +272,11 @@
     DAWN_TRY(GetDevice()->ValidateObject(mLayout.Get()));
     DAWN_INVALID_IF(groupIndex >= kMaxBindGroupsTyped,
                     "Bind group layout index (%u) exceeds the maximum number of bind groups (%u).",
-                    static_cast<uint32_t>(groupIndex), kMaxBindGroups);
+                    groupIndex, kMaxBindGroups);
     DAWN_INVALID_IF(
         !mLayout->GetBindGroupLayoutsMask()[groupIndex],
         "Bind group layout index (%u) doesn't correspond to a bind group for this pipeline.",
-        static_cast<uint32_t>(groupIndex));
+        groupIndex);
     return {};
 }
 
diff --git a/src/dawn/native/ProgrammableEncoder.cpp b/src/dawn/native/ProgrammableEncoder.cpp
index 0bbca40..4d577d2 100644
--- a/src/dawn/native/ProgrammableEncoder.cpp
+++ b/src/dawn/native/ProgrammableEncoder.cpp
@@ -124,7 +124,7 @@
                                                      uint32_t dynamicOffsetCountIn,
                                                      const uint32_t* dynamicOffsetsIn) const {
     DAWN_INVALID_IF(index >= kMaxBindGroupsTyped, "Bind group index (%u) exceeds the maximum (%u).",
-                    static_cast<uint32_t>(index), kMaxBindGroups);
+                    index, kMaxBindGroupsTyped);
 
     ityp::span<BindingIndex, const uint32_t> dynamicOffsets(dynamicOffsetsIn,
                                                             BindingIndex(dynamicOffsetCountIn));
@@ -143,8 +143,7 @@
         layout->GetDynamicBufferCount() != dynamicOffsets.size(),
         "The number of dynamic offsets (%u) does not match the number of dynamic buffers (%u) "
         "in %s.",
-        static_cast<uint32_t>(dynamicOffsets.size()),
-        static_cast<uint32_t>(layout->GetDynamicBufferCount()), layout);
+        dynamicOffsets.size(), layout->GetDynamicBufferCount(), layout);
 
     for (BindingIndex i{0}; i < dynamicOffsets.size(); ++i) {
         const BindingInfo& bindingInfo = layout->GetBindingInfo(i);
@@ -169,8 +168,8 @@
         }
 
         DAWN_INVALID_IF(!IsAligned(dynamicOffsets[i], requiredAlignment),
-                        "Dynamic Offset[%u] (%u) is not %u byte aligned.", static_cast<uint32_t>(i),
-                        dynamicOffsets[i], requiredAlignment);
+                        "Dynamic Offset[%u] (%u) is not %u byte aligned.", i, dynamicOffsets[i],
+                        requiredAlignment);
 
         BufferBinding bufferBinding = group->GetBindingAsBufferBinding(i);
 
@@ -187,14 +186,14 @@
                 "range of (offset: %u, size: %u). The binding goes to the end of the buffer "
                 "even with a dynamic offset of 0. Did you forget to specify "
                 "the binding's size?",
-                static_cast<uint32_t>(i), dynamicOffsets[i], bufferBinding.buffer,
-                bufferBinding.buffer->GetSize(), bufferBinding.offset, bufferBinding.size);
+                i, dynamicOffsets[i], bufferBinding.buffer, bufferBinding.buffer->GetSize(),
+                bufferBinding.offset, bufferBinding.size);
 
             return DAWN_VALIDATION_ERROR(
                 "Dynamic Offset[%u] (%u) is out of bounds of "
                 "%s with a size of %u and a bound range of (offset: %u, size: %u).",
-                static_cast<uint32_t>(i), dynamicOffsets[i], bufferBinding.buffer,
-                bufferBinding.buffer->GetSize(), bufferBinding.offset, bufferBinding.size);
+                i, dynamicOffsets[i], bufferBinding.buffer, bufferBinding.buffer->GetSize(),
+                bufferBinding.offset, bufferBinding.size);
         }
     }
 
diff --git a/src/dawn/native/RenderPipeline.cpp b/src/dawn/native/RenderPipeline.cpp
index f5a749c..8286dd6 100644
--- a/src/dawn/native/RenderPipeline.cpp
+++ b/src/dawn/native/RenderPipeline.cpp
@@ -489,9 +489,9 @@
     return {};
 }
 
-MaybeError ValidateColorTargetStatesMatch(const uint8_t firstColorTargetIndex,
+MaybeError ValidateColorTargetStatesMatch(ColorAttachmentIndex firstColorTargetIndex,
                                           const ColorTargetState* const firstColorTargetState,
-                                          const uint8_t targetIndex,
+                                          ColorAttachmentIndex targetIndex,
                                           const ColorTargetState* target) {
     DAWN_INVALID_IF(firstColorTargetState->writeMask != target->writeMask,
                     "targets[%u].writeMask (%s) does not match targets[%u].writeMask (%s).",
@@ -585,8 +585,7 @@
     for (ColorAttachmentIndex i{}; i < targets.size(); ++i) {
         if (targets[i].format == wgpu::TextureFormat::Undefined) {
             DAWN_INVALID_IF(targets[i].blend,
-                            "Color target[%u] blend state is set when the format is undefined.",
-                            static_cast<uint8_t>(i));
+                            "Color target[%u] blend state is set when the format is undefined.", i);
         } else {
             targetMask.set(i);
         }
@@ -600,14 +599,13 @@
         DAWN_TRY_CONTEXT(ValidateColorTargetState(device, targets[i], format,
                                                   fragmentMetadata.fragmentOutputMask[i],
                                                   fragmentMetadata.fragmentOutputVariables[i]),
-                         "validating targets[%u] framebuffer output.", static_cast<uint8_t>(i));
+                         "validating targets[%u] framebuffer output.", i);
         colorAttachmentFormats->push_back(&device->GetValidInternalFormat(targets[i].format));
 
         if (fragmentMetadata.fragmentInputMask[i]) {
             DAWN_TRY_CONTEXT(ValidateFramebufferInput(device, format,
                                                       fragmentMetadata.fragmentInputVariables[i]),
-                             "validating targets[%u]'s framebuffer input.",
-                             static_cast<uint8_t>(i));
+                             "validating targets[%u]'s framebuffer input.", i);
         }
     }
 
@@ -655,9 +653,8 @@
                 continue;
             }
 
-            DAWN_TRY_CONTEXT(ValidateColorTargetStatesMatch(
-                                 static_cast<uint8_t>(firstColorTargetIndex), firstColorTargetState,
-                                 static_cast<uint8_t>(i), &targets[i]),
+            DAWN_TRY_CONTEXT(ValidateColorTargetStatesMatch(firstColorTargetIndex,
+                                                            firstColorTargetState, i, &targets[i]),
                              "validating targets in compatibility mode.");
         }
     }
diff --git a/src/dawn/native/ShaderModule.cpp b/src/dawn/native/ShaderModule.cpp
index 0a99e7b..b119d8e 100644
--- a/src/dawn/native/ShaderModule.cpp
+++ b/src/dawn/native/ShaderModule.cpp
@@ -564,7 +564,7 @@
                              device, layout, entryPoint.stage, bindingId, bindingInfo),
                          "validating that the entry-point's declaration for @group(%u) "
                          "@binding(%u) matches %s",
-                         static_cast<uint32_t>(group), static_cast<uint32_t>(bindingId), layout);
+                         group, bindingId, layout);
     }
 
     return {};
@@ -1108,15 +1108,15 @@
     for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
         DAWN_TRY_CONTEXT(ValidateCompatibilityWithBindGroupLayout(
                              device, group, entryPoint, layout->GetBindGroupLayout(group)),
-                         "validating the entry-point's compatibility for group %u with %s",
-                         static_cast<uint32_t>(group), layout->GetBindGroupLayout(group));
+                         "validating the entry-point's compatibility for group %u with %s", group,
+                         layout->GetBindGroupLayout(group));
     }
 
     for (BindGroupIndex group : IterateBitSet(~layout->GetBindGroupLayoutsMask())) {
         DAWN_INVALID_IF(entryPoint.bindings[group].size() > 0,
                         "The entry-point uses bindings in group %u but %s doesn't have a "
                         "BindGroupLayout for this index",
-                        static_cast<uint32_t>(group), layout);
+                        group, layout);
     }
 
     // Validate that filtering samplers are not used with unfilterable textures.
@@ -1155,9 +1155,8 @@
             textureInfo.texture.sampleType == wgpu::TextureSampleType::UnfilterableFloat,
             "Texture binding (group:%u, binding:%u) is %s but used statically with a sampler "
             "(group:%u, binding:%u) that's %s",
-            static_cast<uint32_t>(pair.texture.group), static_cast<uint32_t>(pair.texture.binding),
-            wgpu::TextureSampleType::UnfilterableFloat, static_cast<uint32_t>(pair.sampler.group),
-            static_cast<uint32_t>(pair.sampler.binding), wgpu::SamplerBindingType::Filtering);
+            pair.texture.group, pair.texture.binding, wgpu::TextureSampleType::UnfilterableFloat,
+            pair.sampler.group, pair.sampler.binding, wgpu::SamplerBindingType::Filtering);
     }
 
     // Validate compatibility of the pixel local storage.
diff --git a/src/dawn/native/webgpu_absl_format.h b/src/dawn/native/webgpu_absl_format.h
index 703d628..d1dcef6 100644
--- a/src/dawn/native/webgpu_absl_format.h
+++ b/src/dawn/native/webgpu_absl_format.h
@@ -32,10 +32,15 @@
 #include "dawn/native/dawn_platform.h"
 #include "dawn/native/webgpu_absl_format_autogen.h"
 
+namespace dawn::detail {
+template <typename Tag, typename T>
+class TypedIntegerImpl;
+}  // namespace dawn::detail
+
 namespace dawn::ityp {
 template <typename Index, typename Value>
 class span;
-}
+}  // namespace dawn::ityp
 
 namespace dawn::native {
 
@@ -190,6 +195,15 @@
     return {true};
 }
 
+template <typename Tag, typename T>
+absl::FormatConvertResult<absl::FormatConversionCharSet::kNumeric> AbslFormatConvert(
+    const dawn::detail::TypedIntegerImpl<Tag, T>& value,
+    const absl::FormatConversionSpec& spec,
+    absl::FormatSink* s) {
+    s->Append(absl::StrFormat("%u", static_cast<T>(value)));
+    return {true};
+}
+
 }  // namespace dawn::native
 
 #endif  // SRC_DAWN_NATIVE_WEBGPU_ABSL_FORMAT_H_