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}