1
1
//! Producing the WGSL forms of types, for use in error messages.
2
2
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
+ }
9
19
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
+ }
12
34
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 {
15
37
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 ) ,
18
40
}
19
41
}
20
42
}
21
43
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)
32
47
}
33
48
}
34
49
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
+ }
45
55
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
+ }
97
64
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
+ }
105
69
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
+ }
123
76
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:?}}}" ) ,
144
81
}
145
82
}
146
- }
147
83
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
+ }
162
102
}
163
103
}
164
104
165
105
#[ cfg( test) ]
166
106
mod tests {
107
+ use super :: ToWgslForErrorWithContext ;
108
+
109
+ use crate :: proc:: GlobalCtx ;
167
110
use alloc:: { string:: ToString , vec} ;
168
111
169
112
#[ test]
@@ -193,7 +136,7 @@ mod tests {
193
136
Default :: default ( ) ,
194
137
) ;
195
138
196
- let gctx = crate :: proc :: GlobalCtx {
139
+ let gctx = GlobalCtx {
197
140
types : & types,
198
141
constants : & crate :: Arena :: new ( ) ,
199
142
overrides : & crate :: Arena :: new ( ) ,
@@ -219,7 +162,7 @@ mod tests {
219
162
access : crate :: StorageAccess :: default ( ) ,
220
163
} ,
221
164
} ;
222
- assert_eq ! ( ptr. to_wgsl_for_error( & gctx) , "ptr<MyType2>" ) ;
165
+ assert_eq ! ( ptr. to_wgsl_for_error( & gctx) , "ptr<storage, MyType2>" ) ;
223
166
224
167
let img1 = crate :: TypeInner :: Image {
225
168
dim : crate :: ImageDimension :: D2 ,
0 commit comments