From e17c0bdc171419da91c05297f92bc28abe5f3a27 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Sun, 16 Mar 2025 12:35:03 -0700 Subject: [PATCH] [naga wgsl] Fix generics on `naga::common::wgsl::TypeContext`. In `naga::common::wgsl::types`, move the type parameter `` from the `TypeContext` trait itself to the individual methods of the trait. It is very unlikely for Naga to need to be able to implement `TypeContext`, but only for one particular kind of output stream. The motivation for this change is that the old parameterization makes it awkward to provide utility methods for generating `String`s on the trait, which we do in subsequent commits. In order to write to a `String`, such utility methods need `Self` to implement `TypeContext`, so you can add bounds to the methods like this: fn type_to_string(..., out: &mut W) -> ... where Self: TypeContext { ... self.write(..., &mut string_buf)?; } That will compile, but if you try to actually call it, Rust gets confused. Remember, the above is not a method on `TypeContext`, it's a method on `TypeContext` that uses `TypeContext` internally. So when you write `ctx.type_to_string(...)`, Rust needs to decide whether `ctx` implements `TypeContext` for some completely unspecified `W`, and asks for type annotations. You could supply type annotations, but this would be basically supplying some never-used type that implements `core::fmt::Write`. Instead of ctx.type_to_string(handle) you'd have to write TypeContext::::type_to_string(ctx, handle) which is dumb. (I don't *think* this explanation belongs in the code, since it's an explanation of a design *not* used, replaced by a design that's pretty natural --- so I'll leave it here.) --- naga/src/back/wgsl/writer.rs | 8 ++++---- naga/src/common/wgsl/types.rs | 27 +++++++++++++++++---------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/naga/src/back/wgsl/writer.rs b/naga/src/back/wgsl/writer.rs index 77b331b7b7..cab4d1e5a8 100644 --- a/naga/src/back/wgsl/writer.rs +++ b/naga/src/back/wgsl/writer.rs @@ -1726,7 +1726,7 @@ struct WriterTypeContext<'m> { names: &'m crate::FastHashMap, } -impl TypeContext for WriterTypeContext<'_> { +impl TypeContext for WriterTypeContext<'_> { fn lookup_type(&self, handle: Handle) -> &crate::Type { &self.module.types[handle] } @@ -1735,15 +1735,15 @@ impl TypeContext for WriterTypeContext<'_> { self.names[&NameKey::Type(handle)].as_str() } - fn write_override(&self, _: Handle, _: &mut W) -> core::fmt::Result { + fn write_override(&self, _: Handle, _: &mut W) -> core::fmt::Result { unreachable!("overrides should be validated out"); } - fn write_non_wgsl_inner(&self, _: &TypeInner, _: &mut W) -> core::fmt::Result { + fn write_non_wgsl_inner(&self, _: &TypeInner, _: &mut W) -> core::fmt::Result { unreachable!("backends should only be passed validated modules"); } - fn write_non_wgsl_scalar(&self, _: crate::Scalar, _: &mut W) -> core::fmt::Result { + fn write_non_wgsl_scalar(&self, _: crate::Scalar, _: &mut W) -> core::fmt::Result { unreachable!("backends should only be passed validated modules"); } } diff --git a/naga/src/common/wgsl/types.rs b/naga/src/common/wgsl/types.rs index 319fabc37d..89037242a5 100644 --- a/naga/src/common/wgsl/types.rs +++ b/naga/src/common/wgsl/types.rs @@ -21,7 +21,7 @@ use core::fmt::Write; /// [`write_type`]: TypeContext::write_type /// [`write_type_inner`]: TypeContext::write_type_inner /// [`type_name`]: TypeContext::type_name -pub trait TypeContext { +pub trait TypeContext { /// Return the [`Type`] referred to by `handle`. /// /// [`Type`]: crate::Type @@ -32,8 +32,11 @@ pub trait TypeContext { fn type_name(&self, handle: Handle) -> &str; /// Write the WGSL form of `override` to `out`. - fn write_override(&self, r#override: Handle, out: &mut W) - -> core::fmt::Result; + fn write_override( + &self, + r#override: Handle, + out: &mut W, + ) -> core::fmt::Result; /// Write a [`TypeInner`] that has no representation as WGSL source, /// even including Naga extensions. @@ -43,7 +46,7 @@ pub trait TypeContext { /// validation, whereas something generating type names to appear in error messages /// might punt to `TypeInner`'s [`core::fmt::Debug`] implementation, since it's /// probably better to show the user something they can act on. - fn write_non_wgsl_inner(&self, inner: &TypeInner, out: &mut W) -> core::fmt::Result; + fn write_non_wgsl_inner(&self, inner: &TypeInner, out: &mut W) -> core::fmt::Result; /// Write a [`Scalar`] that has no representation as WGSL source, /// even including Naga extensions. @@ -53,13 +56,13 @@ pub trait TypeContext { /// validation, whereas something generating type names to appear in error messages /// might punt to `Scalar`'s [`core::fmt::Debug`] implementation, since it's /// probably better to show the user something they can act on. - fn write_non_wgsl_scalar(&self, scalar: Scalar, out: &mut W) -> core::fmt::Result; + fn write_non_wgsl_scalar(&self, scalar: Scalar, out: &mut W) -> core::fmt::Result; /// Write the type `ty` as it would appear in a value's declaration. /// /// Write the type referred to by `ty` in `module` as it would appear in /// a `var`, `let`, etc. declaration, or in a function's argument list. - fn write_type(&self, handle: Handle, out: &mut W) -> core::fmt::Result { + fn write_type(&self, handle: Handle, out: &mut W) -> core::fmt::Result { let ty = self.lookup_type(handle); match ty.inner { TypeInner::Struct { .. } => out.write_str(self.type_name(handle))?, @@ -79,7 +82,7 @@ pub trait TypeContext { /// [`TypeInner`]. /// /// [`Struct`]: TypeInner::Struct - fn write_type_inner(&self, inner: &TypeInner, out: &mut W) -> core::fmt::Result { + fn write_type_inner(&self, inner: &TypeInner, out: &mut W) -> core::fmt::Result { match try_write_type_inner(self, inner, out) { Ok(()) => Ok(()), Err(WriteTypeError::Format(err)) => Err(err), @@ -88,7 +91,7 @@ pub trait TypeContext { } /// Write the [`Scalar`] `scalar` as a WGSL type. - fn write_scalar(&self, scalar: Scalar, out: &mut W) -> core::fmt::Result { + fn write_scalar(&self, scalar: Scalar, out: &mut W) -> core::fmt::Result { match scalar.try_to_wgsl() { Some(string) => out.write_str(string), None => self.write_non_wgsl_scalar(scalar, out), @@ -96,7 +99,11 @@ pub trait TypeContext { } /// Write the [`TypeResolution`] `resolution` as a WGSL type. - fn write_type_resolution(&self, resolution: &TypeResolution, out: &mut W) -> core::fmt::Result { + fn write_type_resolution( + &self, + resolution: &TypeResolution, + out: &mut W, + ) -> core::fmt::Result { match *resolution { TypeResolution::Handle(handle) => self.write_type(handle, out), TypeResolution::Value(ref inner) => self.write_type_inner(inner, out), @@ -106,7 +113,7 @@ pub trait TypeContext { fn try_write_type_inner(ctx: &C, inner: &TypeInner, out: &mut W) -> Result<(), WriteTypeError> where - C: TypeContext + ?Sized, + C: TypeContext + ?Sized, W: Write, { match *inner {