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.
53pub struct DiagnosticDisplay<T>(pub T);
54
55impl fmt::Display for DiagnosticDisplay<(&TypeResolution, GlobalCtx<'_>)> {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        let (resolution, ctx) = self.0;
58
59        #[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
60        ctx.write_type_resolution(resolution, f)?;
61
62        #[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
63        {
64            let _ = ctx;
65            write!(f, "{resolution:?}")?;
66        }
67
68        Ok(())
69    }
70}
71
72impl fmt::Display for DiagnosticDisplay<(Handle<Type>, GlobalCtx<'_>)> {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        let (handle, ref ctx) = self.0;
75
76        #[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
77        ctx.write_type(handle, f)?;
78
79        #[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
80        {
81            let _ = ctx;
82            write!(f, "{handle:?}")?;
83        }
84
85        Ok(())
86    }
87}
88
89impl fmt::Display for DiagnosticDisplay<(&str, &Rule, GlobalCtx<'_>)> {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        let (name, rule, ref ctx) = self.0;
92
93        #[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
94        ctx.write_type_rule(name, rule, f)?;
95
96        #[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
97        {
98            let _ = ctx;
99            write!(f, "{name}({:?}) -> {:?}", rule.arguments, rule.conclusion)?;
100        }
101
102        Ok(())
103    }
104}
105
106impl fmt::Display for DiagnosticDisplay<Scalar> {
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        let scalar = self.0;
109
110        #[cfg(any(feature = "wgsl-in", feature = "wgsl-out"))]
111        f.write_str(&crate::common::wgsl::TryToWgsl::to_wgsl_for_diagnostics(
112            scalar,
113        ))?;
114
115        #[cfg(not(any(feature = "wgsl-in", feature = "wgsl-out")))]
116        write!(f, "{scalar:?}")?;
117
118        Ok(())
119    }
120}