1 use crate::arena::{Arena, Handle, UniqueArena};
2
3 use thiserror::Error;
4
5 /// The result of computing an expression's type.
6 ///
7 /// This is the (Rust) type returned by [`ResolveContext::resolve`] to represent
8 /// the (Naga) type it ascribes to some expression.
9 ///
10 /// You might expect such a function to simply return a `Handle<Type>`. However,
11 /// we want type resolution to be a read-only process, and that would limit the
12 /// possible results to types already present in the expression's associated
13 /// `UniqueArena<Type>`. Naga IR does have certain expressions whose types are
14 /// not certain to be present.
15 ///
16 /// So instead, type resolution returns a `TypeResolution` enum: either a
17 /// [`Handle`], referencing some type in the arena, or a [`Value`], holding a
18 /// free-floating [`TypeInner`]. This extends the range to cover anything that
19 /// can be represented with a `TypeInner` referring to the existing arena.
20 ///
21 /// What sorts of expressions can have types not available in the arena?
22 ///
23 /// - An [`Access`] or [`AccessIndex`] expression applied to a [`Vector`] or
24 /// [`Matrix`] must have a [`Scalar`] or [`Vector`] type. But since `Vector`
25 /// and `Matrix` represent their element and column types implicitly, not
26 /// via a handle, there may not be a suitable type in the expression's
27 /// associated arena. Instead, resolving such an expression returns a
28 /// `TypeResolution::Value(TypeInner::X { ... })`, where `X` is `Scalar` or
29 /// `Vector`.
30 ///
31 /// - Similarly, the type of an [`Access`] or [`AccessIndex`] expression
32 /// applied to a *pointer to* a vector or matrix must produce a *pointer to*
33 /// a scalar or vector type. These cannot be represented with a
34 /// [`TypeInner::Pointer`], since the `Pointer`'s `base` must point into the
35 /// arena, and as before, we cannot assume that a suitable scalar or vector
36 /// type is there. So we take things one step further and provide
37 /// [`TypeInner::ValuePointer`], specifically for the case of pointers to
38 /// scalars or vectors. This type fits in a `TypeInner` and is exactly
39 /// equivalent to a `Pointer` to a `Vector` or `Scalar`.
40 ///
41 /// So, for example, the type of an `Access` expression applied to a value of type:
42 ///
43 /// ```ignore
44 /// TypeInner::Matrix { columns, rows, width }
45 /// ```
46 ///
47 /// might be:
48 ///
49 /// ```ignore
50 /// TypeResolution::Value(TypeInner::Vector {
51 /// size: rows,
52 /// kind: ScalarKind::Float,
53 /// width,
54 /// })
55 /// ```
56 ///
57 /// and the type of an access to a pointer of storage class `class` to such a
58 /// matrix might be:
59 ///
60 /// ```ignore
61 /// TypeResolution::Value(TypeInner::ValuePointer {
62 /// size: Some(rows),
63 /// kind: ScalarKind::Float,
64 /// width,
65 /// class
66 /// })
67 /// ```
68 ///
69 /// [`Handle`]: TypeResolution::Handle
70 /// [`Value`]: TypeResolution::Value
71 ///
72 /// [`Access`]: crate::Expression::Access
73 /// [`AccessIndex`]: crate::Expression::AccessIndex
74 ///
75 /// [`TypeInner`]: crate::TypeInner
76 /// [`Matrix`]: crate::TypeInner::Matrix
77 /// [`Pointer`]: crate::TypeInner::Pointer
78 /// [`Scalar`]: crate::TypeInner::Scalar
79 /// [`ValuePointer`]: crate::TypeInner::ValuePointer
80 /// [`Vector`]: crate::TypeInner::Vector
81 ///
82 /// [`TypeInner::Pointer`]: crate::TypeInner::Pointer
83 /// [`TypeInner::ValuePointer`]: crate::TypeInner::ValuePointer
84 #[derive(Debug, PartialEq)]
85 #[cfg_attr(feature = "serialize", derive(serde::Serialize))]
86 #[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
87 pub enum TypeResolution {
88 /// A type stored in the associated arena.
89 Handle(Handle<crate::Type>),
90
91 /// A free-floating [`TypeInner`], representing a type that may not be
92 /// available in the associated arena. However, the `TypeInner` itself may
93 /// contain `Handle<Type>` values referring to types from the arena.
94 ///
95 /// [`TypeInner`]: crate::TypeInner
96 Value(crate::TypeInner),
97 }
98
99 impl TypeResolution {
handle(&self) -> Option<Handle<crate::Type>>100 pub fn handle(&self) -> Option<Handle<crate::Type>> {
101 match *self {
102 Self::Handle(handle) => Some(handle),
103 Self::Value(_) => None,
104 }
105 }
106
inner_with<'a>(&'a self, arena: &'a UniqueArena<crate::Type>) -> &'a crate::TypeInner107 pub fn inner_with<'a>(&'a self, arena: &'a UniqueArena<crate::Type>) -> &'a crate::TypeInner {
108 match *self {
109 Self::Handle(handle) => &arena[handle].inner,
110 Self::Value(ref inner) => inner,
111 }
112 }
113 }
114
115 // Clone is only implemented for numeric variants of `TypeInner`.
116 impl Clone for TypeResolution {
clone(&self) -> Self117 fn clone(&self) -> Self {
118 use crate::TypeInner as Ti;
119 match *self {
120 Self::Handle(handle) => Self::Handle(handle),
121 Self::Value(ref v) => Self::Value(match *v {
122 Ti::Scalar { kind, width } => Ti::Scalar { kind, width },
123 Ti::Vector { size, kind, width } => Ti::Vector { size, kind, width },
124 Ti::Matrix {
125 rows,
126 columns,
127 width,
128 } => Ti::Matrix {
129 rows,
130 columns,
131 width,
132 },
133 Ti::Pointer { base, class } => Ti::Pointer { base, class },
134 Ti::ValuePointer {
135 size,
136 kind,
137 width,
138 class,
139 } => Ti::ValuePointer {
140 size,
141 kind,
142 width,
143 class,
144 },
145 _ => unreachable!("Unexpected clone type: {:?}", v),
146 }),
147 }
148 }
149 }
150
151 impl crate::ConstantInner {
resolve_type(&self) -> TypeResolution152 pub fn resolve_type(&self) -> TypeResolution {
153 match *self {
154 Self::Scalar { width, ref value } => TypeResolution::Value(crate::TypeInner::Scalar {
155 kind: value.scalar_kind(),
156 width,
157 }),
158 Self::Composite { ty, components: _ } => TypeResolution::Handle(ty),
159 }
160 }
161 }
162
163 #[derive(Clone, Debug, Error, PartialEq)]
164 pub enum ResolveError {
165 #[error("Index {index} is out of bounds for expression {expr:?}")]
166 OutOfBoundsIndex {
167 expr: Handle<crate::Expression>,
168 index: u32,
169 },
170 #[error("Invalid access into expression {expr:?}, indexed: {indexed}")]
171 InvalidAccess {
172 expr: Handle<crate::Expression>,
173 indexed: bool,
174 },
175 #[error("Invalid sub-access into type {ty:?}, indexed: {indexed}")]
176 InvalidSubAccess {
177 ty: Handle<crate::Type>,
178 indexed: bool,
179 },
180 #[error("Invalid scalar {0:?}")]
181 InvalidScalar(Handle<crate::Expression>),
182 #[error("Invalid vector {0:?}")]
183 InvalidVector(Handle<crate::Expression>),
184 #[error("Invalid pointer {0:?}")]
185 InvalidPointer(Handle<crate::Expression>),
186 #[error("Invalid image {0:?}")]
187 InvalidImage(Handle<crate::Expression>),
188 #[error("Function {name} not defined")]
189 FunctionNotDefined { name: String },
190 #[error("Function without return type")]
191 FunctionReturnsVoid,
192 #[error("Type is not found in the given immutable arena")]
193 TypeNotFound,
194 #[error("Incompatible operands: {0}")]
195 IncompatibleOperands(String),
196 }
197
198 pub struct ResolveContext<'a> {
199 pub constants: &'a Arena<crate::Constant>,
200 pub types: &'a UniqueArena<crate::Type>,
201 pub global_vars: &'a Arena<crate::GlobalVariable>,
202 pub local_vars: &'a Arena<crate::LocalVariable>,
203 pub functions: &'a Arena<crate::Function>,
204 pub arguments: &'a [crate::FunctionArgument],
205 }
206
207 impl<'a> ResolveContext<'a> {
208 /// Determine the type of `expr`.
209 ///
210 /// The `past` argument must be a closure that can resolve the types of any
211 /// expressions that `expr` refers to. These can be gathered by caching the
212 /// results of prior calls to `resolve`, perhaps as done by the
213 /// [`front::Typifier`] utility type.
214 ///
215 /// Type resolution is a read-only process: this method takes `self` by
216 /// shared reference. However, this means that we cannot add anything to
217 /// `self.types` that we might need to describe `expr`. To work around this,
218 /// this method returns a [`TypeResolution`], rather than simply returning a
219 /// `Handle<Type>`; see the documentation for [`TypeResolution`] for
220 /// details.
221 ///
222 /// [`front::Typifier`]: crate::front::Typifier
resolve( &self, expr: &crate::Expression, past: impl Fn(Handle<crate::Expression>) -> &'a TypeResolution, ) -> Result<TypeResolution, ResolveError>223 pub fn resolve(
224 &self,
225 expr: &crate::Expression,
226 past: impl Fn(Handle<crate::Expression>) -> &'a TypeResolution,
227 ) -> Result<TypeResolution, ResolveError> {
228 use crate::TypeInner as Ti;
229 let types = self.types;
230 Ok(match *expr {
231 crate::Expression::Access { base, .. } => match *past(base).inner_with(types) {
232 // Arrays and matrices can only be indexed dynamically behind a
233 // pointer, but that's a validation error, not a type error, so
234 // go ahead provide a type here.
235 Ti::Array { base, .. } => TypeResolution::Handle(base),
236 Ti::Matrix { rows, width, .. } => TypeResolution::Value(Ti::Vector {
237 size: rows,
238 kind: crate::ScalarKind::Float,
239 width,
240 }),
241 Ti::Vector {
242 size: _,
243 kind,
244 width,
245 } => TypeResolution::Value(Ti::Scalar { kind, width }),
246 Ti::ValuePointer {
247 size: Some(_),
248 kind,
249 width,
250 class,
251 } => TypeResolution::Value(Ti::ValuePointer {
252 size: None,
253 kind,
254 width,
255 class,
256 }),
257 Ti::Pointer { base, class } => {
258 TypeResolution::Value(match types[base].inner {
259 Ti::Array { base, .. } => Ti::Pointer { base, class },
260 Ti::Vector {
261 size: _,
262 kind,
263 width,
264 } => Ti::ValuePointer {
265 size: None,
266 kind,
267 width,
268 class,
269 },
270 // Matrices are only dynamically indexed behind a pointer
271 Ti::Matrix {
272 columns: _,
273 rows,
274 width,
275 } => Ti::ValuePointer {
276 kind: crate::ScalarKind::Float,
277 size: Some(rows),
278 width,
279 class,
280 },
281 ref other => {
282 log::error!("Access sub-type {:?}", other);
283 return Err(ResolveError::InvalidSubAccess {
284 ty: base,
285 indexed: false,
286 });
287 }
288 })
289 }
290 ref other => {
291 log::error!("Access type {:?}", other);
292 return Err(ResolveError::InvalidAccess {
293 expr: base,
294 indexed: false,
295 });
296 }
297 },
298 crate::Expression::AccessIndex { base, index } => match *past(base).inner_with(types) {
299 Ti::Vector { size, kind, width } => {
300 if index >= size as u32 {
301 return Err(ResolveError::OutOfBoundsIndex { expr: base, index });
302 }
303 TypeResolution::Value(Ti::Scalar { kind, width })
304 }
305 Ti::Matrix {
306 columns,
307 rows,
308 width,
309 } => {
310 if index >= columns as u32 {
311 return Err(ResolveError::OutOfBoundsIndex { expr: base, index });
312 }
313 TypeResolution::Value(crate::TypeInner::Vector {
314 size: rows,
315 kind: crate::ScalarKind::Float,
316 width,
317 })
318 }
319 Ti::Array { base, .. } => TypeResolution::Handle(base),
320 Ti::Struct { ref members, .. } => {
321 let member = members
322 .get(index as usize)
323 .ok_or(ResolveError::OutOfBoundsIndex { expr: base, index })?;
324 TypeResolution::Handle(member.ty)
325 }
326 Ti::ValuePointer {
327 size: Some(size),
328 kind,
329 width,
330 class,
331 } => {
332 if index >= size as u32 {
333 return Err(ResolveError::OutOfBoundsIndex { expr: base, index });
334 }
335 TypeResolution::Value(Ti::ValuePointer {
336 size: None,
337 kind,
338 width,
339 class,
340 })
341 }
342 Ti::Pointer {
343 base: ty_base,
344 class,
345 } => TypeResolution::Value(match types[ty_base].inner {
346 Ti::Array { base, .. } => Ti::Pointer { base, class },
347 Ti::Vector { size, kind, width } => {
348 if index >= size as u32 {
349 return Err(ResolveError::OutOfBoundsIndex { expr: base, index });
350 }
351 Ti::ValuePointer {
352 size: None,
353 kind,
354 width,
355 class,
356 }
357 }
358 Ti::Matrix {
359 rows,
360 columns,
361 width,
362 } => {
363 if index >= columns as u32 {
364 return Err(ResolveError::OutOfBoundsIndex { expr: base, index });
365 }
366 Ti::ValuePointer {
367 size: Some(rows),
368 kind: crate::ScalarKind::Float,
369 width,
370 class,
371 }
372 }
373 Ti::Struct { ref members, .. } => {
374 let member = members
375 .get(index as usize)
376 .ok_or(ResolveError::OutOfBoundsIndex { expr: base, index })?;
377 Ti::Pointer {
378 base: member.ty,
379 class,
380 }
381 }
382 ref other => {
383 log::error!("Access index sub-type {:?}", other);
384 return Err(ResolveError::InvalidSubAccess {
385 ty: ty_base,
386 indexed: true,
387 });
388 }
389 }),
390 ref other => {
391 log::error!("Access index type {:?}", other);
392 return Err(ResolveError::InvalidAccess {
393 expr: base,
394 indexed: true,
395 });
396 }
397 },
398 crate::Expression::Constant(h) => match self.constants[h].inner {
399 crate::ConstantInner::Scalar { width, ref value } => {
400 TypeResolution::Value(Ti::Scalar {
401 kind: value.scalar_kind(),
402 width,
403 })
404 }
405 crate::ConstantInner::Composite { ty, components: _ } => TypeResolution::Handle(ty),
406 },
407 crate::Expression::Splat { size, value } => match *past(value).inner_with(types) {
408 Ti::Scalar { kind, width } => {
409 TypeResolution::Value(Ti::Vector { size, kind, width })
410 }
411 ref other => {
412 log::error!("Scalar type {:?}", other);
413 return Err(ResolveError::InvalidScalar(value));
414 }
415 },
416 crate::Expression::Swizzle {
417 size,
418 vector,
419 pattern: _,
420 } => match *past(vector).inner_with(types) {
421 Ti::Vector {
422 size: _,
423 kind,
424 width,
425 } => TypeResolution::Value(Ti::Vector { size, kind, width }),
426 ref other => {
427 log::error!("Vector type {:?}", other);
428 return Err(ResolveError::InvalidVector(vector));
429 }
430 },
431 crate::Expression::Compose { ty, .. } => TypeResolution::Handle(ty),
432 crate::Expression::FunctionArgument(index) => {
433 TypeResolution::Handle(self.arguments[index as usize].ty)
434 }
435 crate::Expression::GlobalVariable(h) => {
436 let var = &self.global_vars[h];
437 if var.class == crate::StorageClass::Handle {
438 TypeResolution::Handle(var.ty)
439 } else {
440 TypeResolution::Value(Ti::Pointer {
441 base: var.ty,
442 class: var.class,
443 })
444 }
445 }
446 crate::Expression::LocalVariable(h) => {
447 let var = &self.local_vars[h];
448 TypeResolution::Value(Ti::Pointer {
449 base: var.ty,
450 class: crate::StorageClass::Function,
451 })
452 }
453 crate::Expression::Load { pointer } => match *past(pointer).inner_with(types) {
454 Ti::Pointer { base, class: _ } => {
455 if let Ti::Atomic { kind, width } = types[base].inner {
456 TypeResolution::Value(Ti::Scalar { kind, width })
457 } else {
458 TypeResolution::Handle(base)
459 }
460 }
461 Ti::ValuePointer {
462 size,
463 kind,
464 width,
465 class: _,
466 } => TypeResolution::Value(match size {
467 Some(size) => Ti::Vector { size, kind, width },
468 None => Ti::Scalar { kind, width },
469 }),
470 ref other => {
471 log::error!("Pointer type {:?}", other);
472 return Err(ResolveError::InvalidPointer(pointer));
473 }
474 },
475 crate::Expression::ImageSample {
476 image,
477 gather: Some(_),
478 ..
479 } => match *past(image).inner_with(types) {
480 Ti::Image { class, .. } => TypeResolution::Value(Ti::Vector {
481 kind: match class {
482 crate::ImageClass::Sampled { kind, multi: _ } => kind,
483 _ => crate::ScalarKind::Float,
484 },
485 width: 4,
486 size: crate::VectorSize::Quad,
487 }),
488 ref other => {
489 log::error!("Image type {:?}", other);
490 return Err(ResolveError::InvalidImage(image));
491 }
492 },
493 crate::Expression::ImageSample { image, .. }
494 | crate::Expression::ImageLoad { image, .. } => match *past(image).inner_with(types) {
495 Ti::Image { class, .. } => TypeResolution::Value(match class {
496 crate::ImageClass::Depth { multi: _ } => Ti::Scalar {
497 kind: crate::ScalarKind::Float,
498 width: 4,
499 },
500 crate::ImageClass::Sampled { kind, multi: _ } => Ti::Vector {
501 kind,
502 width: 4,
503 size: crate::VectorSize::Quad,
504 },
505 crate::ImageClass::Storage { format, .. } => Ti::Vector {
506 kind: format.into(),
507 width: 4,
508 size: crate::VectorSize::Quad,
509 },
510 }),
511 ref other => {
512 log::error!("Image type {:?}", other);
513 return Err(ResolveError::InvalidImage(image));
514 }
515 },
516 crate::Expression::ImageQuery { image, query } => TypeResolution::Value(match query {
517 crate::ImageQuery::Size { level: _ } => match *past(image).inner_with(types) {
518 Ti::Image { dim, .. } => match dim {
519 crate::ImageDimension::D1 => Ti::Scalar {
520 kind: crate::ScalarKind::Sint,
521 width: 4,
522 },
523 crate::ImageDimension::D2 | crate::ImageDimension::Cube => Ti::Vector {
524 size: crate::VectorSize::Bi,
525 kind: crate::ScalarKind::Sint,
526 width: 4,
527 },
528 crate::ImageDimension::D3 => Ti::Vector {
529 size: crate::VectorSize::Tri,
530 kind: crate::ScalarKind::Sint,
531 width: 4,
532 },
533 },
534 ref other => {
535 log::error!("Image type {:?}", other);
536 return Err(ResolveError::InvalidImage(image));
537 }
538 },
539 crate::ImageQuery::NumLevels
540 | crate::ImageQuery::NumLayers
541 | crate::ImageQuery::NumSamples => Ti::Scalar {
542 kind: crate::ScalarKind::Sint,
543 width: 4,
544 },
545 }),
546 crate::Expression::Unary { expr, .. } => past(expr).clone(),
547 crate::Expression::Binary { op, left, right } => match op {
548 crate::BinaryOperator::Add
549 | crate::BinaryOperator::Subtract
550 | crate::BinaryOperator::Divide
551 | crate::BinaryOperator::Modulo => past(left).clone(),
552 crate::BinaryOperator::Multiply => {
553 let (res_left, res_right) = (past(left), past(right));
554 match (res_left.inner_with(types), res_right.inner_with(types)) {
555 (
556 &Ti::Matrix {
557 columns: _,
558 rows,
559 width,
560 },
561 &Ti::Matrix { columns, .. },
562 ) => TypeResolution::Value(Ti::Matrix {
563 columns,
564 rows,
565 width,
566 }),
567 (
568 &Ti::Matrix {
569 columns: _,
570 rows,
571 width,
572 },
573 &Ti::Vector { .. },
574 ) => TypeResolution::Value(Ti::Vector {
575 size: rows,
576 kind: crate::ScalarKind::Float,
577 width,
578 }),
579 (
580 &Ti::Vector { .. },
581 &Ti::Matrix {
582 columns,
583 rows: _,
584 width,
585 },
586 ) => TypeResolution::Value(Ti::Vector {
587 size: columns,
588 kind: crate::ScalarKind::Float,
589 width,
590 }),
591 (&Ti::Scalar { .. }, _) => res_right.clone(),
592 (_, &Ti::Scalar { .. }) => res_left.clone(),
593 (&Ti::Vector { .. }, &Ti::Vector { .. }) => res_left.clone(),
594 (tl, tr) => {
595 return Err(ResolveError::IncompatibleOperands(format!(
596 "{:?} * {:?}",
597 tl, tr
598 )))
599 }
600 }
601 }
602 crate::BinaryOperator::Equal
603 | crate::BinaryOperator::NotEqual
604 | crate::BinaryOperator::Less
605 | crate::BinaryOperator::LessEqual
606 | crate::BinaryOperator::Greater
607 | crate::BinaryOperator::GreaterEqual
608 | crate::BinaryOperator::LogicalAnd
609 | crate::BinaryOperator::LogicalOr => {
610 let kind = crate::ScalarKind::Bool;
611 let width = crate::BOOL_WIDTH;
612 let inner = match *past(left).inner_with(types) {
613 Ti::Scalar { .. } => Ti::Scalar { kind, width },
614 Ti::Vector { size, .. } => Ti::Vector { size, kind, width },
615 ref other => {
616 return Err(ResolveError::IncompatibleOperands(format!(
617 "{:?}({:?}, _)",
618 op, other
619 )))
620 }
621 };
622 TypeResolution::Value(inner)
623 }
624 crate::BinaryOperator::And
625 | crate::BinaryOperator::ExclusiveOr
626 | crate::BinaryOperator::InclusiveOr
627 | crate::BinaryOperator::ShiftLeft
628 | crate::BinaryOperator::ShiftRight => past(left).clone(),
629 },
630 crate::Expression::AtomicResult {
631 kind,
632 width,
633 comparison,
634 } => {
635 if comparison {
636 TypeResolution::Value(Ti::Vector {
637 size: crate::VectorSize::Bi,
638 kind,
639 width,
640 })
641 } else {
642 TypeResolution::Value(Ti::Scalar { kind, width })
643 }
644 }
645 crate::Expression::Select { accept, .. } => past(accept).clone(),
646 crate::Expression::Derivative { axis: _, expr } => past(expr).clone(),
647 crate::Expression::Relational { fun, argument } => match fun {
648 crate::RelationalFunction::All | crate::RelationalFunction::Any => {
649 TypeResolution::Value(Ti::Scalar {
650 kind: crate::ScalarKind::Bool,
651 width: crate::BOOL_WIDTH,
652 })
653 }
654 crate::RelationalFunction::IsNan
655 | crate::RelationalFunction::IsInf
656 | crate::RelationalFunction::IsFinite
657 | crate::RelationalFunction::IsNormal => match *past(argument).inner_with(types) {
658 Ti::Scalar { .. } => TypeResolution::Value(Ti::Scalar {
659 kind: crate::ScalarKind::Bool,
660 width: crate::BOOL_WIDTH,
661 }),
662 Ti::Vector { size, .. } => TypeResolution::Value(Ti::Vector {
663 kind: crate::ScalarKind::Bool,
664 width: crate::BOOL_WIDTH,
665 size,
666 }),
667 ref other => {
668 return Err(ResolveError::IncompatibleOperands(format!(
669 "{:?}({:?})",
670 fun, other
671 )))
672 }
673 },
674 },
675 crate::Expression::Math {
676 fun,
677 arg,
678 arg1,
679 arg2: _,
680 arg3: _,
681 } => {
682 use crate::MathFunction as Mf;
683 let res_arg = past(arg);
684 match fun {
685 // comparison
686 Mf::Abs |
687 Mf::Min |
688 Mf::Max |
689 Mf::Clamp |
690 // trigonometry
691 Mf::Cos |
692 Mf::Cosh |
693 Mf::Sin |
694 Mf::Sinh |
695 Mf::Tan |
696 Mf::Tanh |
697 Mf::Acos |
698 Mf::Asin |
699 Mf::Atan |
700 Mf::Atan2 |
701 Mf::Asinh |
702 Mf::Acosh |
703 Mf::Atanh |
704 Mf::Radians |
705 Mf::Degrees |
706 // decomposition
707 Mf::Ceil |
708 Mf::Floor |
709 Mf::Round |
710 Mf::Fract |
711 Mf::Trunc |
712 Mf::Modf |
713 Mf::Frexp |
714 Mf::Ldexp |
715 // exponent
716 Mf::Exp |
717 Mf::Exp2 |
718 Mf::Log |
719 Mf::Log2 |
720 Mf::Pow => res_arg.clone(),
721 // geometry
722 Mf::Dot => match *res_arg.inner_with(types) {
723 Ti::Vector {
724 kind,
725 size: _,
726 width,
727 } => TypeResolution::Value(Ti::Scalar { kind, width }),
728 ref other =>
729 return Err(ResolveError::IncompatibleOperands(
730 format!("{:?}({:?}, _)", fun, other)
731 )),
732 },
733 Mf::Outer => {
734 let arg1 = arg1.ok_or_else(|| ResolveError::IncompatibleOperands(
735 format!("{:?}(_, None)", fun)
736 ))?;
737 match (res_arg.inner_with(types), past(arg1).inner_with(types)) {
738 (&Ti::Vector {kind: _, size: columns,width}, &Ti::Vector{ size: rows, .. }) => TypeResolution::Value(Ti::Matrix { columns, rows, width }),
739 (left, right) =>
740 return Err(ResolveError::IncompatibleOperands(
741 format!("{:?}({:?}, {:?})", fun, left, right)
742 )),
743 }
744 },
745 Mf::Cross => res_arg.clone(),
746 Mf::Distance |
747 Mf::Length => match *res_arg.inner_with(types) {
748 Ti::Scalar {width,kind} |
749 Ti::Vector {width,kind,size:_} => TypeResolution::Value(Ti::Scalar { kind, width }),
750 ref other => return Err(ResolveError::IncompatibleOperands(
751 format!("{:?}({:?})", fun, other)
752 )),
753 },
754 Mf::Normalize |
755 Mf::FaceForward |
756 Mf::Reflect |
757 Mf::Refract => res_arg.clone(),
758 // computational
759 Mf::Sign |
760 Mf::Fma |
761 Mf::Mix |
762 Mf::Step |
763 Mf::SmoothStep |
764 Mf::Sqrt |
765 Mf::InverseSqrt => res_arg.clone(),
766 Mf::Transpose => match *res_arg.inner_with(types) {
767 Ti::Matrix {
768 columns,
769 rows,
770 width,
771 } => TypeResolution::Value(Ti::Matrix {
772 columns: rows,
773 rows: columns,
774 width,
775 }),
776 ref other => return Err(ResolveError::IncompatibleOperands(
777 format!("{:?}({:?})", fun, other)
778 )),
779 },
780 Mf::Inverse => match *res_arg.inner_with(types) {
781 Ti::Matrix {
782 columns,
783 rows,
784 width,
785 } if columns == rows => TypeResolution::Value(Ti::Matrix {
786 columns,
787 rows,
788 width,
789 }),
790 ref other => return Err(ResolveError::IncompatibleOperands(
791 format!("{:?}({:?})", fun, other)
792 )),
793 },
794 Mf::Determinant => match *res_arg.inner_with(types) {
795 Ti::Matrix {
796 width,
797 ..
798 } => TypeResolution::Value(Ti::Scalar { kind: crate::ScalarKind::Float, width }),
799 ref other => return Err(ResolveError::IncompatibleOperands(
800 format!("{:?}({:?})", fun, other)
801 )),
802 },
803 // bits
804 Mf::CountOneBits |
805 Mf::ReverseBits |
806 Mf::ExtractBits |
807 Mf::InsertBits => res_arg.clone(),
808 Mf::FindLsb |
809 Mf::FindMsb => match *res_arg.inner_with(types) {
810 Ti::Scalar { kind: _, width } =>
811 TypeResolution::Value(Ti::Scalar { kind: crate::ScalarKind::Sint, width }),
812 Ti::Vector { size, kind: _, width } =>
813 TypeResolution::Value(Ti::Vector { size, kind: crate::ScalarKind::Sint, width }),
814 ref other => return Err(ResolveError::IncompatibleOperands(
815 format!("{:?}({:?})", fun, other)
816 )),
817 },
818 // data packing
819 Mf::Pack4x8snorm |
820 Mf::Pack4x8unorm |
821 Mf::Pack2x16snorm |
822 Mf::Pack2x16unorm |
823 Mf::Pack2x16float => TypeResolution::Value(Ti::Scalar { kind: crate::ScalarKind::Uint, width: 4 }),
824 // data unpacking
825 Mf::Unpack4x8snorm |
826 Mf::Unpack4x8unorm => TypeResolution::Value(Ti::Vector { size: crate::VectorSize::Quad, kind: crate::ScalarKind::Float, width: 4 }),
827 Mf::Unpack2x16snorm |
828 Mf::Unpack2x16unorm |
829 Mf::Unpack2x16float => TypeResolution::Value(Ti::Vector { size: crate::VectorSize::Bi, kind: crate::ScalarKind::Float, width: 4 }),
830 }
831 }
832 crate::Expression::As {
833 expr,
834 kind,
835 convert,
836 } => match *past(expr).inner_with(types) {
837 Ti::Scalar { kind: _, width } => TypeResolution::Value(Ti::Scalar {
838 kind,
839 width: convert.unwrap_or(width),
840 }),
841 Ti::Vector {
842 kind: _,
843 size,
844 width,
845 } => TypeResolution::Value(Ti::Vector {
846 kind,
847 size,
848 width: convert.unwrap_or(width),
849 }),
850 ref other => {
851 return Err(ResolveError::IncompatibleOperands(format!(
852 "{:?} as {:?}",
853 other, kind
854 )))
855 }
856 },
857 crate::Expression::CallResult(function) => {
858 let result = self.functions[function]
859 .result
860 .as_ref()
861 .ok_or(ResolveError::FunctionReturnsVoid)?;
862 TypeResolution::Handle(result.ty)
863 }
864 crate::Expression::ArrayLength(_) => TypeResolution::Value(Ti::Scalar {
865 kind: crate::ScalarKind::Uint,
866 width: 4,
867 }),
868 })
869 }
870 }
871
872 #[test]
test_error_size()873 fn test_error_size() {
874 use std::mem::size_of;
875 assert_eq!(size_of::<ResolveError>(), 32);
876 }
877