/src/wgpu/naga/src/common/diagnostic_display.rs
Line | Count | Source |
1 | | //! Displaying Naga IR terms in diagnostic output. |
2 | | |
3 | | use crate::proc::{GlobalCtx, Rule, TypeResolution}; |
4 | | use crate::{Handle, Scalar, Type}; |
5 | | |
6 | | #[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))] |
7 | | use crate::common::wgsl::TypeContext; |
8 | | |
9 | | use 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 | | )] |
57 | | pub struct DiagnosticDisplay<T>(pub T); |
58 | | |
59 | | impl fmt::Display for DiagnosticDisplay<(&TypeResolution, GlobalCtx<'_>)> { |
60 | 2 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
61 | 2 | let (resolution, ctx) = self.0; |
62 | | |
63 | | #[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))] |
64 | 2 | 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 | 2 | Ok(()) |
73 | 2 | } |
74 | | } |
75 | | |
76 | | impl fmt::Display for DiagnosticDisplay<(Handle<Type>, GlobalCtx<'_>)> { |
77 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
78 | 0 | let (handle, ref ctx) = self.0; |
79 | | |
80 | | #[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))] |
81 | 0 | 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 | 0 | Ok(()) |
90 | 0 | } |
91 | | } |
92 | | |
93 | | impl fmt::Display for DiagnosticDisplay<(&str, &Rule, GlobalCtx<'_>)> { |
94 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
95 | 0 | let (name, rule, ref ctx) = self.0; |
96 | | |
97 | | #[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))] |
98 | 0 | 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 | 0 | Ok(()) |
107 | 0 | } |
108 | | } |
109 | | |
110 | | impl fmt::Display for DiagnosticDisplay<Scalar> { |
111 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
112 | 0 | let scalar = self.0; |
113 | | |
114 | | #[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))] |
115 | 0 | f.write_str(&crate::common::wgsl::TryToWgsl::to_wgsl_for_diagnostics( |
116 | 0 | scalar, |
117 | 0 | ))?; |
118 | | |
119 | | #[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))] |
120 | | write!(f, "{scalar:?}")?; |
121 | | |
122 | 0 | Ok(()) |
123 | 0 | } |
124 | | } |