Skip to content

Commit 0387c92

Browse files
committed
[naga wgsl-in] Use common type-formatting code.
Replace the type printing code in `front::wgsl::to_wgsl` with calls to the shared type printing code in `common::wgsl`. Use this new API throughout the front end.
1 parent b459c5d commit 0387c92

File tree

7 files changed

+93
-145
lines changed

7 files changed

+93
-145
lines changed

naga/src/front/wgsl/error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use super::parse::directive::language_extension::{
99
LanguageExtension, UnimplementedLanguageExtension,
1010
};
1111
use super::parse::lexer::Token;
12+
use super::to_wgsl::ToWgslForError;
1213

1314
use codespan_reporting::diagnostic::{Diagnostic, Label};
1415
use codespan_reporting::files::SimpleFile;

naga/src/front/wgsl/lower/construction.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use core::num::NonZeroU32;
99
use crate::front::wgsl::error::Error;
1010
use crate::front::wgsl::lower::{ExpressionContext, Lowerer};
1111
use crate::front::wgsl::parse::ast;
12+
use crate::front::wgsl::to_wgsl::ToWgslForErrorWithContext;
1213
use crate::{Handle, Span};
1314

1415
/// A cooked form of `ast::ConstructorType` that uses Naga types whenever

naga/src/front/wgsl/lower/conversion.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use alloc::{boxed::Box, string::String, vec::Vec};
55
use crate::front::wgsl::error::{
66
AutoConversionError, AutoConversionLeafScalarError, ConcretizationFailedError,
77
};
8+
use crate::front::wgsl::to_wgsl::{ToWgslForError, ToWgslForErrorWithContext};
89
use crate::{Handle, Span};
910

1011
impl<'source> super::ExpressionContext<'source, '_, '_> {

naga/src/front/wgsl/lower/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::front::wgsl::error::{Error, ExpectedToken, InvalidAssignmentType};
99
use crate::front::wgsl::index::Index;
1010
use crate::front::wgsl::parse::number::Number;
1111
use crate::front::wgsl::parse::{ast, conv};
12+
use crate::front::wgsl::to_wgsl::ToWgslForErrorWithContext;
1213
use crate::front::Typifier;
1314
use crate::proc::{
1415
ensure_block_returns, Alignment, ConstantEvaluator, Emitter, Layouter, ResolveContext,

naga/src/front/wgsl/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use crate::front::wgsl::error::Error;
2323
use crate::front::wgsl::lower::Lowerer;
2424
use crate::front::wgsl::parse::Parser;
2525
use crate::Scalar;
26+
pub use to_wgsl::ToWgslForError;
2627

2728
#[cfg(test)]
2829
use std::println;

naga/src/front/wgsl/to_wgsl.rs

Lines changed: 87 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,169 +1,112 @@
11
//! Producing the WGSL forms of types, for use in error messages.
22
3-
use crate::common::wgsl::ToWgsl;
4-
5-
use alloc::{
6-
format,
7-
string::{String, ToString},
8-
};
3+
use crate::common::wgsl::{TryToWgsl, TypeContext};
4+
use crate::proc::{GlobalCtx, TypeResolution};
5+
use crate::{Handle, Scalar, Type, TypeInner};
6+
use alloc::format;
7+
use alloc::string::{String, ToString};
8+
use core::fmt;
9+
10+
/// A trait for rendering simple Naga IR types into strings for error messages.
11+
///
12+
/// Some Naga IR types also require a [`GlobalCtx`] to generate WGSL;
13+
/// for example, `Handle<Type>` depends on a type arena, and might
14+
/// refer to overrides as well. Such types should implement
15+
/// [`ToWgslForErrorWithContext`] instead.
16+
pub trait ToWgslForError {
17+
fn to_wgsl_for_error(&self) -> String;
18+
}
919

10-
use crate::proc::GlobalCtx;
11-
use crate::Handle;
20+
/// A trait for rendering complex Naga IR types into strings for error messages.
21+
///
22+
/// Some Naga IR types do not require a [`GlobalCtx`] to generate
23+
/// WGSL; for example, [`Scalar`] is self-contained. Such types should
24+
/// implement [`ToWgslForError`] instead.
25+
pub trait ToWgslForErrorWithContext {
26+
fn write_wgsl_for_error(&self, ctx: &GlobalCtx<'_>, out: &mut String) -> fmt::Result;
27+
28+
fn to_wgsl_for_error(&self, ctx: &GlobalCtx<'_>) -> String {
29+
let mut buf = String::new();
30+
self.write_wgsl_for_error(ctx, &mut buf).unwrap();
31+
buf
32+
}
33+
}
1234

13-
impl crate::proc::TypeResolution {
14-
pub fn to_wgsl_for_error(&self, gctx: &GlobalCtx) -> String {
35+
impl ToWgslForErrorWithContext for TypeResolution {
36+
fn write_wgsl_for_error(&self, ctx: &GlobalCtx<'_>, out: &mut String) -> fmt::Result {
1537
match *self {
16-
crate::proc::TypeResolution::Handle(handle) => handle.to_wgsl_for_error(gctx),
17-
crate::proc::TypeResolution::Value(ref inner) => inner.to_wgsl_for_error(gctx),
38+
TypeResolution::Handle(handle) => ctx.write_type(handle, out),
39+
TypeResolution::Value(ref inner) => ctx.write_type_inner(inner, out),
1840
}
1941
}
2042
}
2143

22-
impl Handle<crate::Type> {
23-
/// Formats the type as it is written in wgsl.
24-
///
25-
/// For example `vec3<f32>`.
26-
pub fn to_wgsl_for_error(self, gctx: &GlobalCtx) -> String {
27-
let ty = &gctx.types[self];
28-
match ty.name {
29-
Some(ref name) => name.clone(),
30-
None => ty.inner.to_wgsl_for_error(gctx),
31-
}
44+
impl ToWgslForErrorWithContext for Handle<Type> {
45+
fn write_wgsl_for_error(&self, ctx: &GlobalCtx<'_>, out: &mut String) -> fmt::Result {
46+
ctx.write_type(*self, out)
3247
}
3348
}
3449

35-
impl crate::TypeInner {
36-
/// Formats the type as it is written in wgsl.
37-
///
38-
/// For example `vec3<f32>`.
39-
///
40-
/// Note: `TypeInner::Struct` doesn't include the name of the
41-
/// struct type. Therefore this method will simply return "struct"
42-
/// for them.
43-
pub fn to_wgsl_for_error(&self, gctx: &GlobalCtx) -> String {
44-
use crate::TypeInner as Ti;
50+
impl ToWgslForErrorWithContext for TypeInner {
51+
fn write_wgsl_for_error(&self, ctx: &GlobalCtx<'_>, out: &mut String) -> fmt::Result {
52+
ctx.write_type_inner(self, out)
53+
}
54+
}
4555

46-
match *self {
47-
Ti::Scalar(scalar) => scalar.to_wgsl_for_error(),
48-
Ti::Vector { size, scalar } => {
49-
format!("vec{}<{}>", size as u32, scalar.to_wgsl_for_error())
50-
}
51-
Ti::Matrix {
52-
columns,
53-
rows,
54-
scalar,
55-
} => {
56-
format!(
57-
"mat{}x{}<{}>",
58-
columns as u32,
59-
rows as u32,
60-
scalar.to_wgsl_for_error(),
61-
)
62-
}
63-
Ti::Atomic(scalar) => {
64-
format!("atomic<{}>", scalar.to_wgsl_for_error())
65-
}
66-
Ti::Pointer { base, .. } => {
67-
let name = base.to_wgsl_for_error(gctx);
68-
format!("ptr<{name}>")
69-
}
70-
Ti::ValuePointer { scalar, .. } => {
71-
format!("ptr<{}>", scalar.to_wgsl_for_error())
72-
}
73-
Ti::Array { base, size, .. } => {
74-
let base = base.to_wgsl_for_error(gctx);
75-
match size {
76-
crate::ArraySize::Constant(size) => format!("array<{base}, {size}>"),
77-
crate::ArraySize::Pending(_) => unreachable!(),
78-
crate::ArraySize::Dynamic => format!("array<{base}>"),
79-
}
80-
}
81-
Ti::Struct { .. } => {
82-
// TODO: Actually output the struct?
83-
"struct".to_string()
84-
}
85-
Ti::Image {
86-
dim,
87-
arrayed,
88-
class,
89-
} => {
90-
let dim_suffix = match dim {
91-
crate::ImageDimension::D1 => "_1d",
92-
crate::ImageDimension::D2 => "_2d",
93-
crate::ImageDimension::D3 => "_3d",
94-
crate::ImageDimension::Cube => "_cube",
95-
};
96-
let array_suffix = if arrayed { "_array" } else { "" };
56+
impl ToWgslForError for Scalar {
57+
fn to_wgsl_for_error(&self) -> String {
58+
match self.try_to_wgsl() {
59+
Some(static_string) => static_string.to_string(),
60+
None => format!("{{non-WGSL Naga scalar {self:?}}}"),
61+
}
62+
}
63+
}
9764

98-
let class_suffix = match class {
99-
crate::ImageClass::Sampled { multi: true, .. } => "_multisampled",
100-
crate::ImageClass::Depth { multi: false } => "_depth",
101-
crate::ImageClass::Depth { multi: true } => "_depth_multisampled",
102-
crate::ImageClass::Sampled { multi: false, .. }
103-
| crate::ImageClass::Storage { .. } => "",
104-
};
65+
impl<W: fmt::Write> TypeContext<W> for GlobalCtx<'_> {
66+
fn lookup_type(&self, handle: Handle<Type>) -> &Type {
67+
&self.types[handle]
68+
}
10569

106-
let type_in_brackets = match class {
107-
crate::ImageClass::Sampled { kind, .. } => {
108-
// Note: The only valid widths are 4 bytes wide.
109-
// The lexer has already verified this, so we can safely assume it here.
110-
// https://gpuweb.github.io/gpuweb/wgsl/#sampled-texture-type
111-
let element_type = crate::Scalar { kind, width: 4 }.to_wgsl_for_error();
112-
format!("<{element_type}>")
113-
}
114-
crate::ImageClass::Depth { multi: _ } => String::new(),
115-
crate::ImageClass::Storage { format, access } => {
116-
if access.contains(crate::StorageAccess::STORE) {
117-
format!("<{},write>", format.to_wgsl())
118-
} else {
119-
format!("<{}>", format.to_wgsl())
120-
}
121-
}
122-
};
70+
fn type_name(&self, handle: Handle<Type>) -> &str {
71+
self.types[handle]
72+
.name
73+
.as_deref()
74+
.unwrap_or("{anonymous type}")
75+
}
12376

124-
format!("texture{class_suffix}{dim_suffix}{array_suffix}{type_in_brackets}")
125-
}
126-
Ti::Sampler { .. } => "sampler".to_string(),
127-
Ti::AccelerationStructure { vertex_return } => {
128-
let caps = if vertex_return { "<vertex_return>" } else { "" };
129-
format!("acceleration_structure{}", caps)
130-
}
131-
Ti::RayQuery { vertex_return } => {
132-
let caps = if vertex_return { "<vertex_return>" } else { "" };
133-
format!("ray_query{}", caps)
134-
}
135-
Ti::BindingArray { base, size, .. } => {
136-
let member_type = &gctx.types[base];
137-
let base = member_type.name.as_deref().unwrap_or("unknown");
138-
match size {
139-
crate::ArraySize::Constant(size) => format!("binding_array<{base}, {size}>"),
140-
crate::ArraySize::Pending(_) => unreachable!(),
141-
crate::ArraySize::Dynamic => format!("binding_array<{base}>"),
142-
}
143-
}
77+
fn write_override(&self, handle: Handle<crate::Override>, out: &mut W) -> fmt::Result {
78+
match self.overrides[handle].name {
79+
Some(ref name) => out.write_str(name),
80+
None => write!(out, "{{anonymous override {handle:?}}}"),
14481
}
14582
}
146-
}
14783

148-
impl crate::Scalar {
149-
/// Format a scalar kind+width as a type is written in wgsl.
150-
///
151-
/// Examples: `f32`, `u64`, `bool`.
152-
pub fn to_wgsl_for_error(self) -> String {
153-
let prefix = match self.kind {
154-
crate::ScalarKind::Sint => "i",
155-
crate::ScalarKind::Uint => "u",
156-
crate::ScalarKind::Float => "f",
157-
crate::ScalarKind::Bool => return "bool".to_string(),
158-
crate::ScalarKind::AbstractInt => return "{AbstractInt}".to_string(),
159-
crate::ScalarKind::AbstractFloat => return "{AbstractFloat}".to_string(),
160-
};
161-
format!("{}{}", prefix, self.width * 8)
84+
fn write_non_wgsl_inner(&self, inner: &TypeInner, out: &mut W) -> fmt::Result {
85+
write!(out, "{{non-WGSL Naga type {inner:?}}}")
86+
}
87+
88+
fn write_non_wgsl_scalar(&self, scalar: Scalar, out: &mut W) -> fmt::Result {
89+
match scalar.kind {
90+
crate::ScalarKind::Sint
91+
| crate::ScalarKind::Uint
92+
| crate::ScalarKind::Float
93+
| crate::ScalarKind::Bool => write!(out, "{{non-WGSL Naga scalar {scalar:?}}}"),
94+
95+
// The abstract types are kind of an odd pseudo-WGSL category:
96+
// they are definitely part of the spec, but they are not expressible
97+
// in WGSL itself. So we want to call them out by name in error messages,
98+
// but the WGSL backend should never generate these.
99+
crate::ScalarKind::AbstractInt => out.write_str("{AbstractInt}"),
100+
crate::ScalarKind::AbstractFloat => out.write_str("{AbstractFloat}"),
101+
}
162102
}
163103
}
164104

165105
#[cfg(test)]
166106
mod tests {
107+
use super::ToWgslForErrorWithContext;
108+
109+
use crate::proc::GlobalCtx;
167110
use alloc::{string::ToString, vec};
168111

169112
#[test]
@@ -193,7 +136,7 @@ mod tests {
193136
Default::default(),
194137
);
195138

196-
let gctx = crate::proc::GlobalCtx {
139+
let gctx = GlobalCtx {
197140
types: &types,
198141
constants: &crate::Arena::new(),
199142
overrides: &crate::Arena::new(),
@@ -219,7 +162,7 @@ mod tests {
219162
access: crate::StorageAccess::default(),
220163
},
221164
};
222-
assert_eq!(ptr.to_wgsl_for_error(&gctx), "ptr<MyType2>");
165+
assert_eq!(ptr.to_wgsl_for_error(&gctx), "ptr<storage, MyType2>");
223166

224167
let img1 = crate::TypeInner::Image {
225168
dim: crate::ImageDimension::D2,

naga/src/proc/constant_evaluator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1554,7 +1554,7 @@ impl<'a> ConstantEvaluator<'a> {
15541554
let from = format!("{:?} {:?}", expr, self.expressions[expr]);
15551555

15561556
#[cfg(feature = "wgsl-in")]
1557-
let to = target.to_wgsl_for_error();
1557+
let to = crate::front::wgsl::ToWgslForError::to_wgsl_for_error(&target);
15581558

15591559
#[cfg(not(feature = "wgsl-in"))]
15601560
let to = format!("{target:?}");

0 commit comments

Comments
 (0)