mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
[naga] Add DiagnosticDisplay and DiagnosticDebug wrappers.
Define two new types in `naga::common`, `DiagnosticDisplay` and `DiagnosticDebug`, that allow Naga IR types to be formatted using `core::fmt::Display` and `core::fmt::Debug`. In `naga::common::wgsl`, add supporting implementations of `TypeContext` for `GlobalCtx` and `UniqueArena<Type>`
This commit is contained in:
parent
e284e8055f
commit
8f7dc8c070
86
naga/src/common/diagnostic_debug.rs
Normal file
86
naga/src/common/diagnostic_debug.rs
Normal file
@ -0,0 +1,86 @@
|
||||
//! Displaying Naga IR terms in debugging output.
|
||||
|
||||
#[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
|
||||
use crate::common::wgsl::TypeContext;
|
||||
|
||||
use crate::proc::TypeResolution;
|
||||
use crate::{Handle, Scalar, Type, TypeInner, UniqueArena};
|
||||
|
||||
use core::fmt;
|
||||
|
||||
/// A wrapper for displaying Naga IR terms in debugging output.
|
||||
///
|
||||
/// This is like [`DiagnosticDisplay`], but requires weaker context
|
||||
/// and produces correspondingly lower-fidelity output. For example,
|
||||
/// this cannot show the override names for override-sized array
|
||||
/// lengths.
|
||||
///
|
||||
/// [`DiagnosticDisplay`]: super::DiagnosticDisplay
|
||||
pub struct DiagnosticDebug<T>(pub T);
|
||||
|
||||
impl fmt::Debug for DiagnosticDebug<(Handle<Type>, &UniqueArena<Type>)> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let (handle, ctx) = self.0;
|
||||
|
||||
#[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
|
||||
ctx.write_type(handle, f)?;
|
||||
|
||||
#[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
|
||||
{
|
||||
let _ = ctx;
|
||||
write!(f, "{handle:?}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for DiagnosticDebug<(&TypeInner, &UniqueArena<Type>)> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let (inner, ctx) = self.0;
|
||||
|
||||
#[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
|
||||
ctx.write_type_inner(inner, f)?;
|
||||
|
||||
#[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
|
||||
{
|
||||
let _ = ctx;
|
||||
write!(f, "{inner:?}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for DiagnosticDebug<(&TypeResolution, &UniqueArena<Type>)> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let (resolution, ctx) = self.0;
|
||||
|
||||
#[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
|
||||
ctx.write_type_resolution(resolution, f)?;
|
||||
|
||||
#[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
|
||||
{
|
||||
let _ = ctx;
|
||||
write!(f, "{resolution:?}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for DiagnosticDebug<Scalar> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let scalar = self.0;
|
||||
|
||||
#[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
|
||||
f.write_str(&crate::common::wgsl::TryToWgsl::to_wgsl_for_diagnostics(
|
||||
scalar,
|
||||
))?;
|
||||
|
||||
#[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
|
||||
write!(f, "{scalar:?}")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
100
naga/src/common/diagnostic_display.rs
Normal file
100
naga/src/common/diagnostic_display.rs
Normal file
@ -0,0 +1,100 @@
|
||||
//! Displaying Naga IR terms in diagnostic output.
|
||||
|
||||
use crate::proc::GlobalCtx;
|
||||
use crate::{Handle, Scalar, Type, TypeInner};
|
||||
|
||||
#[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
|
||||
use crate::common::wgsl::TypeContext;
|
||||
|
||||
use core::fmt;
|
||||
|
||||
/// A wrapper for displaying Naga IR terms in diagnostic output.
|
||||
///
|
||||
/// For some Naga IR type `T`, `DiagnosticDisplay<T>` implements
|
||||
/// [`core::fmt::Display`] in a way that displays values of type `T`
|
||||
/// appropriately for diagnostic messages presented to human readers.
|
||||
///
|
||||
/// For example, the implementation of [`Display`] for
|
||||
/// `DiagnosticDisplay<Scalar>` formats the type represented by the
|
||||
/// given [`Scalar`] appropriately for users.
|
||||
///
|
||||
/// Some types like `Handle<Type>` require contextual information like
|
||||
/// a type arena to be displayed. In such cases, we implement [`Display`]
|
||||
/// for a type like `DiagnosticDisplay<(Handle<Type>, GlobalCtx)>`, where
|
||||
/// the [`GlobalCtx`] type provides the necessary context.
|
||||
///
|
||||
/// If you only need debugging output, [`DiagnosticDebug`] uses
|
||||
/// easier-to-obtain context types but still does a good enough job
|
||||
/// for logging or debugging.
|
||||
///
|
||||
/// [`Display`]: core::fmt::Display
|
||||
/// [`Scalar`]: crate::Scalar
|
||||
/// [`GlobalCtx`]: crate::proc::GlobalCtx
|
||||
/// [`DiagnosticDebug`]: super::DiagnosticDebug
|
||||
///
|
||||
/// ## Language-sensitive diagnostics
|
||||
///
|
||||
/// Diagnostic output ought to depend on the source language from
|
||||
/// which the IR was produced: diagnostics resulting from processing
|
||||
/// GLSL code should use GLSL type syntax, for example. That means
|
||||
/// that `DiagnosticDisplay` ought to include some indication of which
|
||||
/// notation to use.
|
||||
///
|
||||
/// For the moment, only WGSL output is implemented, so
|
||||
/// `DiagnosticDisplay` lacks any support for this (#7268). However,
|
||||
/// the plan is that all language-independent code in Naga should use
|
||||
/// `DiagnosticDisplay` wherever appropriate, such that when its
|
||||
/// definition is expanded to include some indication of the right
|
||||
/// source language to use, any use site that does not supply this
|
||||
/// indication will provoke a compile-time error.
|
||||
pub struct DiagnosticDisplay<T>(pub T);
|
||||
|
||||
impl fmt::Display for DiagnosticDisplay<(Handle<Type>, GlobalCtx<'_>)> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let (handle, ref ctx) = self.0;
|
||||
|
||||
#[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
|
||||
ctx.write_type(handle, f)?;
|
||||
|
||||
#[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
|
||||
{
|
||||
let _ = ctx;
|
||||
write!(f, "{handle:?}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DiagnosticDisplay<(&TypeInner, GlobalCtx<'_>)> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let (inner, ref ctx) = self.0;
|
||||
|
||||
#[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
|
||||
ctx.write_type_inner(inner, f)?;
|
||||
|
||||
#[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
|
||||
{
|
||||
let _ = ctx;
|
||||
write!(f, "{inner:?}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DiagnosticDisplay<Scalar> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let scalar = self.0;
|
||||
|
||||
#[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
|
||||
f.write_str(&crate::common::wgsl::TryToWgsl::to_wgsl_for_diagnostics(
|
||||
scalar,
|
||||
))?;
|
||||
|
||||
#[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
|
||||
write!(f, "{scalar:?}")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,13 @@
|
||||
//! Code common to the front and backends for specific languages.
|
||||
|
||||
mod diagnostic_debug;
|
||||
mod diagnostic_display;
|
||||
pub mod predeclared;
|
||||
pub mod wgsl;
|
||||
|
||||
pub use diagnostic_debug::DiagnosticDebug;
|
||||
pub use diagnostic_display::DiagnosticDisplay;
|
||||
|
||||
/// Helper function that returns the string corresponding to the [`VectorSize`](crate::VectorSize)
|
||||
pub const fn vector_size_str(size: crate::VectorSize) -> &'static str {
|
||||
match size {
|
||||
|
||||
@ -356,3 +356,70 @@ impl From<core::fmt::Error> for WriteTypeError {
|
||||
Self::Format(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Format types as WGSL based on a [`GlobalCtx`].
|
||||
///
|
||||
/// This is probably good enough for diagnostic output, but it has some
|
||||
/// limitations:
|
||||
///
|
||||
/// - It does not apply [`Namer`] renamings, to avoid collisions.
|
||||
///
|
||||
/// - It generates invalid WGSL for anonymous struct types.
|
||||
///
|
||||
/// - It doesn't write the lengths of override-expression-sized arrays
|
||||
/// correctly, unless the expression is just the override identifier.
|
||||
///
|
||||
/// [`GlobalCtx`]: crate::proc::GlobalCtx
|
||||
/// [`Namer`]: crate::proc::Namer
|
||||
impl TypeContext for crate::proc::GlobalCtx<'_> {
|
||||
fn lookup_type(&self, handle: Handle<crate::Type>) -> &crate::Type {
|
||||
&self.types[handle]
|
||||
}
|
||||
|
||||
fn type_name(&self, handle: Handle<crate::Type>) -> &str {
|
||||
self.types[handle]
|
||||
.name
|
||||
.as_deref()
|
||||
.unwrap_or("{anonymous type}")
|
||||
}
|
||||
|
||||
fn write_override<W: Write>(
|
||||
&self,
|
||||
handle: Handle<crate::Override>,
|
||||
out: &mut W,
|
||||
) -> core::fmt::Result {
|
||||
match self.overrides[handle].name {
|
||||
Some(ref name) => out.write_str(name),
|
||||
None => write!(out, "{{anonymous override {handle:?}}}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Format types as WGSL based on a `UniqueArena<Type>`.
|
||||
///
|
||||
/// This is probably only good enough for logging:
|
||||
///
|
||||
/// - It does not apply any kind of [`Namer`] renamings.
|
||||
///
|
||||
/// - It generates invalid WGSL for anonymous struct types.
|
||||
///
|
||||
/// - It doesn't write override-sized arrays properly.
|
||||
///
|
||||
/// [`Namer`]: crate::proc::Namer
|
||||
impl TypeContext for crate::UniqueArena<crate::Type> {
|
||||
fn lookup_type(&self, handle: Handle<crate::Type>) -> &crate::Type {
|
||||
&self[handle]
|
||||
}
|
||||
|
||||
fn type_name(&self, handle: Handle<crate::Type>) -> &str {
|
||||
self[handle].name.as_deref().unwrap_or("{anonymous type}")
|
||||
}
|
||||
|
||||
fn write_override<W: Write>(
|
||||
&self,
|
||||
handle: Handle<crate::Override>,
|
||||
out: &mut W,
|
||||
) -> core::fmt::Result {
|
||||
write!(out, "{{override {handle:?}}}")
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user