naga/common/
diagnostic_display.rs

1//! Displaying Naga IR terms in diagnostic output.
2
3use crate::proc::{GlobalCtx, Rule, TypeResolution};
4use crate::{Handle, Scalar, Type};
5
6#[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
7use crate::common::wgsl::TypeContext;
8
9use core::fmt;
10
11/// A wrapper for displaying Naga IR terms in diagnostic output.
12///
13/// For some Naga IR type `T`, `DiagnosticDisplay<T>` implements
14/// [`core::fmt::Display`] in a way that displays values of type `T`
15/// appropriately for diagnostic messages presented to human readers.
16///
17/// For example, the implementation of [`Display`] for
18/// `DiagnosticDisplay<Scalar>` formats the type represented by the
19/// given [`Scalar`] appropriately for users.
20///
21/// Some types like `Handle<Type>` require contextual information like
22/// a type arena to be displayed. In such cases, we implement [`Display`]
23/// for a type like `DiagnosticDisplay<(Handle<Type>, GlobalCtx)>`, where
24/// the [`GlobalCtx`] type provides the necessary context.
25///
26/// Do not implement this type for [`TypeInner`], as that does not
27/// have enough information to display struct types correctly.
28///
29/// If you only need debugging output, [`DiagnosticDebug`] uses
30/// easier-to-obtain context types but still does a good enough job
31/// for logging or debugging.
32///
33/// [`Display`]: core::fmt::Display
34/// [`GlobalCtx`]: crate::proc::GlobalCtx
35/// [`TypeInner`]: crate::ir::TypeInner
36/// [`DiagnosticDebug`]: super::DiagnosticDebug
37///
38/// ## Language-sensitive diagnostics
39///
40/// Diagnostic output ought to depend on the source language from
41/// which the IR was produced: diagnostics resulting from processing
42/// GLSL code should use GLSL type syntax, for example. That means
43/// that `DiagnosticDisplay` ought to include some indication of which
44/// notation to use.
45///
46/// For the moment, only WGSL output is implemented, so
47/// `DiagnosticDisplay` lacks any support for this (#7268). However,
48/// the plan is that all language-independent code in Naga should use
49/// `DiagnosticDisplay` wherever appropriate, such that when its
50/// definition is expanded to include some indication of the right
51/// source language to use, any use site that does not supply this
52/// indication will provoke a compile-time error.
53#[expect(
54    missing_debug_implementations,
55    reason = "use this type with `Display`, not `Debug`"
56)]
57pub struct DiagnosticDisplay<T>(pub T);
58
59impl fmt::Display for DiagnosticDisplay<(&TypeResolution, GlobalCtx<'_>)> {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        let (resolution, ctx) = self.0;
62
63        #[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
64        ctx.write_type_resolution(resolution, f)?;
65
66        #[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
67        {
68            let _ = ctx;
69            write!(f, "{resolution:?}")?;
70        }
71
72        Ok(())
73    }
74}
75
76impl fmt::Display for DiagnosticDisplay<(Handle<Type>, GlobalCtx<'_>)> {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        let (handle, ref ctx) = self.0;
79
80        #[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
81        ctx.write_type(handle, f)?;
82
83        #[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
84        {
85            let _ = ctx;
86            write!(f, "{handle:?}")?;
87        }
88
89        Ok(())
90    }
91}
92
93impl fmt::Display for DiagnosticDisplay<(&str, &Rule, GlobalCtx<'_>)> {
94    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95        let (name, rule, ref ctx) = self.0;
96
97        #[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
98        ctx.write_type_rule(name, rule, f)?;
99
100        #[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
101        {
102            let _ = ctx;
103            write!(f, "{name}({:?}) -> {:?}", rule.arguments, rule.conclusion)?;
104        }
105
106        Ok(())
107    }
108}
109
110impl fmt::Display for DiagnosticDisplay<Scalar> {
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        let scalar = self.0;
113
114        #[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
115        f.write_str(&crate::common::wgsl::TryToWgsl::to_wgsl_for_diagnostics(
116            scalar,
117        ))?;
118
119        #[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
120        write!(f, "{scalar:?}")?;
121
122        Ok(())
123    }
124}