Skip to main content

wgsl_types/builtin/
ops_ty.rs

1//! Type-checking of operators.
2
3use crate::{
4    Error,
5    conv::{Convert, convert_ty},
6    syntax::{AddressSpace, BinaryOperator, UnaryOperator},
7    ty::{Ty, Type},
8};
9
10type E = Error;
11
12/// Compute the return type of a unary operator expression.
13pub fn type_unary_op(operator: UnaryOperator, operand: &Type) -> Result<Type, E> {
14    match operator {
15        UnaryOperator::LogicalNegation => operand.op_not(),
16        UnaryOperator::Negation => operand.op_neg(),
17        UnaryOperator::BitwiseComplement => operand.op_bitnot(),
18        UnaryOperator::AddressOf => operand.op_ref(),
19        UnaryOperator::Indirection => operand.op_deref(),
20    }
21}
22
23/// Compute the return type of a binary operator expression.
24pub fn type_binary_op(op: BinaryOperator, lhs: &Type, rhs: &Type) -> Result<Type, E> {
25    match op {
26        BinaryOperator::ShortCircuitOr => lhs.op_or(rhs),
27        BinaryOperator::ShortCircuitAnd => lhs.op_and(rhs),
28        BinaryOperator::Addition => lhs.op_add(rhs),
29        BinaryOperator::Subtraction => lhs.op_sub(rhs),
30        BinaryOperator::Multiplication => lhs.op_mul(rhs),
31        BinaryOperator::Division => lhs.op_div(rhs),
32        BinaryOperator::Remainder => lhs.op_rem(rhs),
33        BinaryOperator::Equality => lhs.op_eq(rhs),
34        BinaryOperator::Inequality => lhs.op_ne(rhs),
35        BinaryOperator::LessThan => lhs.op_lt(rhs),
36        BinaryOperator::LessThanEqual => lhs.op_le(rhs),
37        BinaryOperator::GreaterThan => lhs.op_gt(rhs),
38        BinaryOperator::GreaterThanEqual => lhs.op_ge(rhs),
39        BinaryOperator::BitwiseOr => lhs.op_bitor(rhs),
40        BinaryOperator::BitwiseAnd => lhs.op_bitand(rhs),
41        BinaryOperator::BitwiseXor => lhs.op_bitxor(rhs),
42        BinaryOperator::ShiftLeft => lhs.op_shl(rhs),
43        BinaryOperator::ShiftRight => lhs.op_shr(rhs),
44    }
45}
46
47// -------------------
48// LOGICAL EXPRESSIONS
49// -------------------
50// reference: https://www.w3.org/TR/WGSL/#logical-expr
51
52impl Type {
53    pub fn op_not(&self) -> Result<Self, E> {
54        match self {
55            Self::Bool | Self::Vec(_, _) => Ok(self.clone()),
56            _ => Err(E::Unary(UnaryOperator::LogicalNegation, self.clone())),
57        }
58    }
59    pub fn op_or(&self, rhs: &Type) -> Result<Self, E> {
60        match (self, rhs) {
61            (Type::Bool, Type::Bool) => Ok(Type::Bool),
62            _ => Err(E::Binary(
63                BinaryOperator::ShortCircuitOr,
64                self.ty(),
65                rhs.ty(),
66            )),
67        }
68    }
69    pub fn op_and(&self, rhs: &Type) -> Result<Self, E> {
70        match (self, rhs) {
71            (Type::Bool, Type::Bool) => Ok(Type::Bool),
72            _ => Err(E::Binary(
73                BinaryOperator::ShortCircuitAnd,
74                self.ty(),
75                rhs.ty(),
76            )),
77        }
78    }
79}
80
81// ----------------------
82// ARITHMETIC EXPRESSIONS
83// ----------------------
84// reference: https://www.w3.org/TR/WGSL/#arithmetic-expr
85
86impl Type {
87    /// Valid operands:
88    /// * `-S`, S: scalar
89    pub fn op_neg(&self) -> Result<Self, E> {
90        if self.is_scalar() || matches!(self, Type::Vec(_, inner_ty) if inner_ty.is_scalar()) {
91            Ok(self.clone())
92        } else {
93            Err(E::Unary(UnaryOperator::Negation, self.ty()))
94        }
95    }
96
97    /// Valid operands:
98    /// * `T + T`, T: scalar or vec
99    /// * `S + V` or `V + S`, S: scalar, V: `vec<S>`
100    /// * `M + M`, M: mat
101    pub fn op_add(&self, rhs: &Type) -> Result<Self, E> {
102        let err = || E::Binary(BinaryOperator::Addition, self.ty(), rhs.ty());
103        match (self, rhs) {
104            (lhs, rhs) if lhs.is_scalar() && rhs.is_scalar() || lhs.is_vec() && rhs.is_vec() => {
105                let ty = convert_ty(self, rhs).ok_or_else(err)?;
106                Ok(ty.clone())
107            }
108            (scalar_ty, Type::Vec(n, vec_ty)) | (Type::Vec(n, vec_ty), scalar_ty)
109                if scalar_ty.is_scalar() =>
110            {
111                let inner_ty = convert_ty(scalar_ty, vec_ty).ok_or_else(err)?;
112                Ok(Type::Vec(*n, Box::new(inner_ty.clone())))
113            }
114            (Type::Mat(c1, r1, lhs), Type::Mat(c2, r2, rhs)) if c1 == c2 && r1 == r2 => {
115                let inner_ty = convert_ty(lhs, rhs).ok_or_else(err)?;
116                Ok(Type::Mat(*c1, *c2, Box::new(inner_ty.clone())))
117            }
118            _ => Err(err()),
119        }
120    }
121
122    /// Valid operands:
123    /// * `T - T`, T: scalar or vec
124    /// * `S - V` or `V - S`, S: scalar, V: `vec<S>`
125    /// * `M - M`, M: mat
126    pub fn op_sub(&self, rhs: &Type) -> Result<Self, E> {
127        let err = || E::Binary(BinaryOperator::Subtraction, self.ty(), rhs.ty());
128        match (self, rhs) {
129            (lhs, rhs) if lhs.is_scalar() && rhs.is_scalar() || lhs.is_vec() && rhs.is_vec() => {
130                let ty = convert_ty(self, rhs).ok_or_else(err)?;
131                Ok(ty.clone())
132            }
133            (scalar_ty, Type::Vec(n, vec_ty)) | (Type::Vec(n, vec_ty), scalar_ty)
134                if scalar_ty.is_scalar() =>
135            {
136                let inner_ty = convert_ty(scalar_ty, vec_ty).ok_or_else(err)?;
137                Ok(Type::Vec(*n, Box::new(inner_ty.clone())))
138            }
139            (Type::Mat(c1, r1, lhs), Type::Mat(c2, r2, rhs)) if c1 == c2 && r1 == r2 => {
140                let inner_ty = convert_ty(lhs, rhs).ok_or_else(err)?;
141                Ok(Type::Mat(*c1, *c2, Box::new(inner_ty.clone())))
142            }
143            _ => Err(err()),
144        }
145    }
146
147    /// Valid operands:
148    /// * `T * T`, T: scalar or vec
149    /// * `S * V` or `V * S`, S: scalar, V: `vec<S>`
150    /// * `S * M` or `M * S`, S: float, M: `mat<S>`
151    /// * `V * M` or `M * V`, S: float, V: `vec<S>`, M: `mat<S>`
152    /// * `M1 * M1`, M1: `matKxR`, M2: `matCxK`
153    pub fn op_mul(&self, rhs: &Type) -> Result<Self, E> {
154        let err = || E::Binary(BinaryOperator::Multiplication, self.ty(), rhs.ty());
155        match (self, rhs) {
156            (lhs, rhs) if lhs.is_scalar() && rhs.is_scalar() || lhs.is_vec() && rhs.is_vec() => {
157                let ty = convert_ty(self, rhs).ok_or_else(err)?;
158                Ok(ty.clone())
159            }
160            // component-wise scaling
161            (scalar_ty, Type::Vec(n, vec_ty)) | (Type::Vec(n, vec_ty), scalar_ty)
162                if scalar_ty.is_scalar() =>
163            {
164                let inner_ty = convert_ty(scalar_ty, vec_ty).ok_or_else(err)?;
165                Ok(Type::Vec(*n, Box::new(inner_ty.clone())))
166            }
167            // component-wise scaling
168            (scalar_ty, Type::Mat(c, r, mat_ty)) | (Type::Mat(c, r, mat_ty), scalar_ty)
169                if scalar_ty.is_scalar() =>
170            {
171                let inner_ty = convert_ty(scalar_ty, mat_ty).ok_or_else(err)?;
172                Ok(Type::Mat(*c, *r, Box::new(inner_ty.clone())))
173            }
174            // linear algebra row-vector-matrix product
175            (Type::Vec(n1, vec_ty), Type::Mat(n, n2, mat_ty))
176            // linear algebra matrix-column-vector product
177            | (Type::Mat(n1, n, mat_ty), Type::Vec(n2, vec_ty))
178             if n1 == n2 => {
179                let inner_ty = convert_ty(vec_ty, mat_ty).ok_or_else(err)?;
180                Ok(Type::Vec(*n, Box::new(inner_ty.clone())))
181            }
182            // linear algebra matrix product
183            (Type::Mat(k1, r, lhs), Type::Mat(c, k2, rhs)) if k1 == k2 => {
184                let inner_ty = convert_ty(lhs, rhs).ok_or_else(err)?;
185                Ok(Type::Mat(*c, *r, Box::new(inner_ty.clone())))
186            }
187            _ => Err(err()),
188        }
189    }
190
191    /// Valid operands:
192    /// * `T / T`, T: scalar or vec
193    /// * `S / V` or `V / S`, S: scalar, V: `vec<S>`
194    pub fn op_div(&self, rhs: &Type) -> Result<Self, E> {
195        let err = || E::Binary(BinaryOperator::Division, self.ty(), rhs.ty());
196        match (self, rhs) {
197            (lhs, rhs) if lhs.is_scalar() && rhs.is_scalar() || lhs.is_vec() && rhs.is_vec() => {
198                let ty = convert_ty(self, rhs).ok_or_else(err)?;
199                Ok(ty.clone())
200            }
201            (scalar_ty, Type::Vec(n, vec_ty)) | (Type::Vec(n, vec_ty), scalar_ty)
202                if scalar_ty.is_scalar() =>
203            {
204                let inner_ty = convert_ty(scalar_ty, vec_ty).ok_or_else(err)?;
205                Ok(Type::Vec(*n, Box::new(inner_ty.clone())))
206            }
207            _ => Err(err()),
208        }
209    }
210
211    /// Valid operands:
212    /// * `T % T`, T: scalar or vec
213    /// * `S % V` or `V % S`, S: scalar, V: `vec<S>`
214    pub fn op_rem(&self, rhs: &Type) -> Result<Self, E> {
215        let err = || E::Binary(BinaryOperator::Remainder, self.ty(), rhs.ty());
216        match (self, rhs) {
217            (lhs, rhs) if lhs.is_scalar() && rhs.is_scalar() || lhs.is_vec() && rhs.is_vec() => {
218                let ty = convert_ty(self, rhs).ok_or_else(err)?;
219                Ok(ty.clone())
220            }
221            (scalar_ty, Type::Vec(n, vec_ty)) | (Type::Vec(n, vec_ty), scalar_ty)
222                if scalar_ty.is_scalar() =>
223            {
224                let inner_ty = convert_ty(scalar_ty, vec_ty).ok_or_else(err)?;
225                Ok(Type::Vec(*n, Box::new(inner_ty.clone())))
226            }
227            _ => Err(err()),
228        }
229    }
230}
231
232// ----------------------
233// COMPARISON EXPRESSIONS
234// ----------------------
235// reference: https://www.w3.org/TR/WGSL/#comparison-expr
236
237impl Type {
238    /// Valid operands:
239    /// * `T == T`, T: scalar or vec
240    pub fn op_eq(&self, rhs: &Type) -> Result<Type, E> {
241        let err = || E::Binary(BinaryOperator::Equality, self.ty(), rhs.ty());
242        match convert_ty(self, rhs).ok_or_else(err)? {
243            ty if ty.is_scalar() => Ok(Type::Bool),
244            Type::Vec(n, _) => Ok(Type::Vec(*n, Box::new(Type::Bool))),
245            _ => Err(err()),
246        }
247    }
248    /// Valid operands:
249    /// * `T != T`, T: scalar or vec
250    pub fn op_ne(&self, rhs: &Type) -> Result<Type, E> {
251        let err = || E::Binary(BinaryOperator::Inequality, self.ty(), rhs.ty());
252        match convert_ty(self, rhs).ok_or_else(err)? {
253            ty if ty.is_scalar() => Ok(Type::Bool),
254            Type::Vec(n, _) => Ok(Type::Vec(*n, Box::new(Type::Bool))),
255            _ => Err(err()),
256        }
257    }
258    /// Valid operands:
259    /// * `T < T`, T: scalar or vec
260    pub fn op_lt(&self, rhs: &Type) -> Result<Type, E> {
261        let err = || E::Binary(BinaryOperator::LessThan, self.ty(), rhs.ty());
262        match convert_ty(self, rhs).ok_or_else(err)? {
263            ty if ty.is_scalar() => Ok(Type::Bool),
264            Type::Vec(n, _) => Ok(Type::Vec(*n, Box::new(Type::Bool))),
265            _ => Err(err()),
266        }
267    }
268    /// Valid operands:
269    /// * `T <= T`, T: scalar or vec
270    pub fn op_le(&self, rhs: &Type) -> Result<Type, E> {
271        let err = || E::Binary(BinaryOperator::LessThanEqual, self.ty(), rhs.ty());
272        match convert_ty(self, rhs).ok_or_else(err)? {
273            ty if ty.is_scalar() => Ok(Type::Bool),
274            Type::Vec(n, _) => Ok(Type::Vec(*n, Box::new(Type::Bool))),
275            _ => Err(err()),
276        }
277    }
278    /// Valid operands:
279    /// * `T > T`, T: scalar or vec
280    pub fn op_gt(&self, rhs: &Type) -> Result<Type, E> {
281        let err = || E::Binary(BinaryOperator::GreaterThan, self.ty(), rhs.ty());
282        match convert_ty(self, rhs).ok_or_else(err)? {
283            ty if ty.is_scalar() => Ok(Type::Bool),
284            Type::Vec(n, _) => Ok(Type::Vec(*n, Box::new(Type::Bool))),
285            _ => Err(err()),
286        }
287    }
288    /// Valid operands:
289    /// * `T >= T`, T: scalar or vec
290    pub fn op_ge(&self, rhs: &Type) -> Result<Type, E> {
291        let err = || E::Binary(BinaryOperator::GreaterThanEqual, self.ty(), rhs.ty());
292        match convert_ty(self, rhs).ok_or_else(err)? {
293            ty if ty.is_scalar() => Ok(Type::Bool),
294            Type::Vec(n, _) => Ok(Type::Vec(*n, Box::new(Type::Bool))),
295            _ => Err(err()),
296        }
297    }
298}
299
300// ---------------
301// BIT EXPRESSIONS
302// ---------------
303// reference: https://www.w3.org/TR/WGSL/#bit-expr
304
305impl Type {
306    /// Valid operands:
307    /// * `~T`, I: integer, T: I or `vec<I>`
308    pub fn op_bitnot(&self) -> Result<Type, E> {
309        match self {
310            ty if ty.is_integer() => Ok(self.clone()),
311            Type::Vec(_, ty) if ty.is_integer() => Ok(self.clone()),
312            _ => Err(E::Unary(UnaryOperator::BitwiseComplement, self.ty())),
313        }
314    }
315
316    /// Note: this is both the "bitwise OR" and "logical OR" operator.
317    ///
318    /// Valid operands:
319    /// * `T | T`, T: integer, or `vec<integer>` (bitwise OR)
320    /// * `V | V`, V: `vec<bool>` (logical OR)
321    pub fn op_bitor(&self, rhs: &Type) -> Result<Type, E> {
322        let err = || E::Binary(BinaryOperator::BitwiseOr, self.ty(), rhs.ty());
323        match convert_ty(self, rhs).ok_or_else(err)? {
324            ty if ty.is_integer() => Ok(self.clone()),
325            Type::Vec(_, ty) if ty.is_integer() => Ok(self.clone()),
326            Type::Vec(_, ty) if ty.is_bool() => Ok(self.clone()),
327            _ => Err(err()),
328        }
329    }
330
331    /// Note: this is both the "bitwise AND" and "logical AND" operator.
332    ///
333    /// Valid operands:
334    /// * `T & T`, T: integer or `vec<integer>` (bitwise AND)
335    /// * `V & V`, V: `vec<bool>` (logical AND)
336    pub fn op_bitand(&self, rhs: &Type) -> Result<Type, E> {
337        let err = || E::Binary(BinaryOperator::BitwiseAnd, self.ty(), rhs.ty());
338        match convert_ty(self, rhs).ok_or_else(err)? {
339            ty if ty.is_integer() => Ok(self.clone()),
340            Type::Vec(_, ty) if ty.is_integer() => Ok(self.clone()),
341            Type::Vec(_, ty) if ty.is_bool() => Ok(self.clone()),
342            _ => Err(err()),
343        }
344    }
345
346    /// Valid operands:
347    /// * `T ^ T`, T: integer or `vec<integer>`
348    pub fn op_bitxor(&self, rhs: &Type) -> Result<Type, E> {
349        let err = || E::Binary(BinaryOperator::BitwiseXor, self.ty(), rhs.ty());
350        match convert_ty(self, rhs).ok_or_else(err)? {
351            ty if ty.is_integer() => Ok(self.clone()),
352            Type::Vec(_, ty) if ty.is_integer() => Ok(self.clone()),
353            _ => Err(err()),
354        }
355    }
356
357    /// Valid operands:
358    /// * `integer << u32`
359    /// * `vec<integer> << vec<u32>`
360    pub fn op_shl(&self, rhs: &Type) -> Result<Type, E> {
361        let err = || E::Binary(BinaryOperator::ShiftLeft, self.ty(), rhs.ty());
362        let rhs = rhs.convert_inner_to(&Type::U32).ok_or_else(err)?;
363        match (self, rhs) {
364            (lhs, Type::U32) if lhs.is_integer() => Ok(lhs.clone()),
365            (lhs, Type::Vec(_, _)) => Ok(lhs.clone()),
366            _ => Err(err()),
367        }
368    }
369
370    /// Valid operands:
371    /// * `integer >> u32`
372    /// * `vec<integer> >> vec<u32>`
373    pub fn op_shr(&self, rhs: &Type) -> Result<Type, E> {
374        let err = || E::Binary(BinaryOperator::ShiftRight, self.ty(), rhs.ty());
375        let rhs = rhs.convert_inner_to(&Type::U32).ok_or_else(err)?;
376        match (self, rhs) {
377            (lhs, Type::U32) if lhs.is_integer() => Ok(lhs.clone()),
378            (lhs, Type::Vec(_, _)) => Ok(lhs.clone()),
379            _ => Err(err()),
380        }
381    }
382}
383
384// -------------------
385// POINTER EXPRESSIONS
386// -------------------
387// reference: https://www.w3.org/TR/WGSL/#address-of-expr
388// reference: https://www.w3.org/TR/WGSL/#indirection-expr
389
390impl Type {
391    pub fn op_ref(&self) -> Result<Type, E> {
392        match self {
393            Type::Ref(a_s, ty, a_m) => {
394                if *a_s == AddressSpace::Handle {
395                    // "It is a shader-creation error if AS is the handle address space."
396                    Err(E::PtrHandle)
397                } else if false {
398                    // TODO: We do not yet have enough information to check this:
399                    // "It is a shader-creation error if r is a reference to a vector component."
400                    Err(E::PtrVecComp)
401                } else {
402                    Ok(Type::Ptr(*a_s, ty.clone(), *a_m))
403                }
404            }
405            _ => Err(E::Unary(UnaryOperator::AddressOf, self.ty())),
406        }
407    }
408
409    pub fn op_deref(&self) -> Result<Type, E> {
410        match self {
411            Type::Ptr(a_s, ty, a_m) => Ok(Type::Ref(*a_s, ty.clone(), *a_m)),
412            _ => Err(E::Unary(UnaryOperator::Indirection, self.ty())),
413        }
414    }
415}