1#[cfg(feature = "validate")]
2use super::{
3 compose::validate_compose, validate_atomic_compare_exchange_struct, FunctionInfo, ModuleInfo,
4 ShaderStages, TypeFlags,
5};
6#[cfg(feature = "validate")]
7use crate::arena::UniqueArena;
8
9use crate::{
10 arena::Handle,
11 proc::{IndexableLengthError, ResolveError},
12};
13
14#[derive(Clone, Debug, thiserror::Error)]
15#[cfg_attr(test, derive(PartialEq))]
16pub enum ExpressionError {
17 #[error("Doesn't exist")]
18 DoesntExist,
19 #[error("Used by a statement before it was introduced into the scope by any of the dominating blocks")]
20 NotInScope,
21 #[error("Base type {0:?} is not compatible with this expression")]
22 InvalidBaseType(Handle<crate::Expression>),
23 #[error("Accessing with index {0:?} can't be done")]
24 InvalidIndexType(Handle<crate::Expression>),
25 #[error("Accessing {0:?} via a negative index is invalid")]
26 NegativeIndex(Handle<crate::Expression>),
27 #[error("Accessing index {1} is out of {0:?} bounds")]
28 IndexOutOfBounds(Handle<crate::Expression>, u32),
29 #[error("The expression {0:?} may only be indexed by a constant")]
30 IndexMustBeConstant(Handle<crate::Expression>),
31 #[error("Function argument {0:?} doesn't exist")]
32 FunctionArgumentDoesntExist(u32),
33 #[error("Loading of {0:?} can't be done")]
34 InvalidPointerType(Handle<crate::Expression>),
35 #[error("Array length of {0:?} can't be done")]
36 InvalidArrayType(Handle<crate::Expression>),
37 #[error("Get intersection of {0:?} can't be done")]
38 InvalidRayQueryType(Handle<crate::Expression>),
39 #[error("Splatting {0:?} can't be done")]
40 InvalidSplatType(Handle<crate::Expression>),
41 #[error("Swizzling {0:?} can't be done")]
42 InvalidVectorType(Handle<crate::Expression>),
43 #[error("Swizzle component {0:?} is outside of vector size {1:?}")]
44 InvalidSwizzleComponent(crate::SwizzleComponent, crate::VectorSize),
45 #[error(transparent)]
46 Compose(#[from] super::ComposeError),
47 #[error(transparent)]
48 IndexableLength(#[from] IndexableLengthError),
49 #[error("Operation {0:?} can't work with {1:?}")]
50 InvalidUnaryOperandType(crate::UnaryOperator, Handle<crate::Expression>),
51 #[error("Operation {0:?} can't work with {1:?} and {2:?}")]
52 InvalidBinaryOperandTypes(
53 crate::BinaryOperator,
54 Handle<crate::Expression>,
55 Handle<crate::Expression>,
56 ),
57 #[error("Selecting is not possible")]
58 InvalidSelectTypes,
59 #[error("Relational argument {0:?} is not a boolean vector")]
60 InvalidBooleanVector(Handle<crate::Expression>),
61 #[error("Relational argument {0:?} is not a float")]
62 InvalidFloatArgument(Handle<crate::Expression>),
63 #[error("Type resolution failed")]
64 Type(#[from] ResolveError),
65 #[error("Not a global variable")]
66 ExpectedGlobalVariable,
67 #[error("Not a global variable or a function argument")]
68 ExpectedGlobalOrArgument,
69 #[error("Needs to be an binding array instead of {0:?}")]
70 ExpectedBindingArrayType(Handle<crate::Type>),
71 #[error("Needs to be an image instead of {0:?}")]
72 ExpectedImageType(Handle<crate::Type>),
73 #[error("Needs to be an image instead of {0:?}")]
74 ExpectedSamplerType(Handle<crate::Type>),
75 #[error("Unable to operate on image class {0:?}")]
76 InvalidImageClass(crate::ImageClass),
77 #[error("Derivatives can only be taken from scalar and vector floats")]
78 InvalidDerivative,
79 #[error("Image array index parameter is misplaced")]
80 InvalidImageArrayIndex,
81 #[error("Inappropriate sample or level-of-detail index for texel access")]
82 InvalidImageOtherIndex,
83 #[error("Image array index type of {0:?} is not an integer scalar")]
84 InvalidImageArrayIndexType(Handle<crate::Expression>),
85 #[error("Image sample or level-of-detail index's type of {0:?} is not an integer scalar")]
86 InvalidImageOtherIndexType(Handle<crate::Expression>),
87 #[error("Image coordinate type of {1:?} does not match dimension {0:?}")]
88 InvalidImageCoordinateType(crate::ImageDimension, Handle<crate::Expression>),
89 #[error("Comparison sampling mismatch: image has class {image:?}, but the sampler is comparison={sampler}, and the reference was provided={has_ref}")]
90 ComparisonSamplingMismatch {
91 image: crate::ImageClass,
92 sampler: bool,
93 has_ref: bool,
94 },
95 #[error("Sample offset constant {1:?} doesn't match the image dimension {0:?}")]
96 InvalidSampleOffset(crate::ImageDimension, Handle<crate::Expression>),
97 #[error("Depth reference {0:?} is not a scalar float")]
98 InvalidDepthReference(Handle<crate::Expression>),
99 #[error("Depth sample level can only be Auto or Zero")]
100 InvalidDepthSampleLevel,
101 #[error("Gather level can only be Zero")]
102 InvalidGatherLevel,
103 #[error("Gather component {0:?} doesn't exist in the image")]
104 InvalidGatherComponent(crate::SwizzleComponent),
105 #[error("Gather can't be done for image dimension {0:?}")]
106 InvalidGatherDimension(crate::ImageDimension),
107 #[error("Sample level (exact) type {0:?} is not a scalar float")]
108 InvalidSampleLevelExactType(Handle<crate::Expression>),
109 #[error("Sample level (bias) type {0:?} is not a scalar float")]
110 InvalidSampleLevelBiasType(Handle<crate::Expression>),
111 #[error("Sample level (gradient) of {1:?} doesn't match the image dimension {0:?}")]
112 InvalidSampleLevelGradientType(crate::ImageDimension, Handle<crate::Expression>),
113 #[error("Unable to cast")]
114 InvalidCastArgument,
115 #[error("Invalid argument count for {0:?}")]
116 WrongArgumentCount(crate::MathFunction),
117 #[error("Argument [{1}] to {0:?} as expression {2:?} has an invalid type.")]
118 InvalidArgumentType(crate::MathFunction, u32, Handle<crate::Expression>),
119 #[error("Atomic result type can't be {0:?}")]
120 InvalidAtomicResultType(Handle<crate::Type>),
121 #[error(
122 "workgroupUniformLoad result type can't be {0:?}. It can only be a constructible type."
123 )]
124 InvalidWorkGroupUniformLoadResultType(Handle<crate::Type>),
125 #[error("Shader requires capability {0:?}")]
126 MissingCapabilities(super::Capabilities),
127}
128
129#[cfg(feature = "validate")]
130struct ExpressionTypeResolver<'a> {
131 root: Handle<crate::Expression>,
132 types: &'a UniqueArena<crate::Type>,
133 info: &'a FunctionInfo,
134}
135
136#[cfg(feature = "validate")]
137impl<'a> std::ops::Index<Handle<crate::Expression>> for ExpressionTypeResolver<'a> {
138 type Output = crate::TypeInner;
139
140 #[allow(clippy::panic)]
141 fn index(&self, handle: Handle<crate::Expression>) -> &Self::Output {
142 if handle < self.root {
143 self.info[handle].ty.inner_with(self.types)
144 } else {
145 panic!(
147 "Depends on {:?}, which has not been processed yet",
148 self.root
149 )
150 }
151 }
152}
153
154#[cfg(feature = "validate")]
155impl super::Validator {
156 pub(super) fn validate_const_expression(
157 &self,
158 handle: Handle<crate::Expression>,
159 gctx: crate::proc::GlobalCtx,
160 mod_info: &mut ModuleInfo,
161 ) -> Result<(), super::ConstExpressionError> {
162 use crate::Expression as E;
163
164 match gctx.const_expressions[handle] {
165 E::Literal(_) | E::Constant(_) | E::ZeroValue(_) => {}
166 E::Compose { ref components, ty } => {
167 validate_compose(
168 ty,
169 gctx,
170 components.iter().map(|&handle| mod_info[handle].clone()),
171 )?;
172 }
173 _ => return Err(super::ConstExpressionError::NonConst),
174 }
175
176 Ok(())
177 }
178
179 pub(super) fn validate_expression(
180 &self,
181 root: Handle<crate::Expression>,
182 expression: &crate::Expression,
183 function: &crate::Function,
184 module: &crate::Module,
185 info: &FunctionInfo,
186 mod_info: &ModuleInfo,
187 ) -> Result<ShaderStages, ExpressionError> {
188 use crate::{Expression as E, ScalarKind as Sk, TypeInner as Ti};
189
190 let resolver = ExpressionTypeResolver {
191 root,
192 types: &module.types,
193 info,
194 };
195
196 let stages = match *expression {
197 E::Access { base, index } => {
198 let base_type = &resolver[base];
199 let dynamic_indexing_restricted = match *base_type {
201 Ti::Vector { .. } => false,
202 Ti::Matrix { .. } | Ti::Array { .. } => true,
203 Ti::Pointer { .. }
204 | Ti::ValuePointer { size: Some(_), .. }
205 | Ti::BindingArray { .. } => false,
206 ref other => {
207 log::error!("Indexing of {:?}", other);
208 return Err(ExpressionError::InvalidBaseType(base));
209 }
210 };
211 match resolver[index] {
212 Ti::Scalar {
214 kind: Sk::Sint | Sk::Uint,
215 width: _,
216 } => {}
217 ref other => {
218 log::error!("Indexing by {:?}", other);
219 return Err(ExpressionError::InvalidIndexType(index));
220 }
221 }
222 if dynamic_indexing_restricted
223 && function.expressions[index].is_dynamic_index(module)
224 {
225 return Err(ExpressionError::IndexMustBeConstant(base));
226 }
227
228 if let crate::proc::IndexableLength::Known(known_length) =
231 base_type.indexable_length(module)?
232 {
233 match module
234 .to_ctx()
235 .eval_expr_to_u32_from(index, &function.expressions)
236 {
237 Ok(value) => {
238 if value >= known_length {
239 return Err(ExpressionError::IndexOutOfBounds(base, value));
240 }
241 }
242 Err(crate::proc::U32EvalError::Negative) => {
243 return Err(ExpressionError::NegativeIndex(base))
244 }
245 Err(crate::proc::U32EvalError::NonConst) => {}
246 }
247 }
248
249 ShaderStages::all()
250 }
251 E::AccessIndex { base, index } => {
252 fn resolve_index_limit(
253 module: &crate::Module,
254 top: Handle<crate::Expression>,
255 ty: &crate::TypeInner,
256 top_level: bool,
257 ) -> Result<u32, ExpressionError> {
258 let limit = match *ty {
259 Ti::Vector { size, .. }
260 | Ti::ValuePointer {
261 size: Some(size), ..
262 } => size as u32,
263 Ti::Matrix { columns, .. } => columns as u32,
264 Ti::Array {
265 size: crate::ArraySize::Constant(len),
266 ..
267 } => len.get(),
268 Ti::Array { .. } | Ti::BindingArray { .. } => u32::MAX, Ti::Pointer { base, .. } if top_level => {
270 resolve_index_limit(module, top, &module.types[base].inner, false)?
271 }
272 Ti::Struct { ref members, .. } => members.len() as u32,
273 ref other => {
274 log::error!("Indexing of {:?}", other);
275 return Err(ExpressionError::InvalidBaseType(top));
276 }
277 };
278 Ok(limit)
279 }
280
281 let limit = resolve_index_limit(module, base, &resolver[base], true)?;
282 if index >= limit {
283 return Err(ExpressionError::IndexOutOfBounds(base, limit));
284 }
285 ShaderStages::all()
286 }
287 E::Splat { size: _, value } => match resolver[value] {
288 Ti::Scalar { .. } => ShaderStages::all(),
289 ref other => {
290 log::error!("Splat scalar type {:?}", other);
291 return Err(ExpressionError::InvalidSplatType(value));
292 }
293 },
294 E::Swizzle {
295 size,
296 vector,
297 pattern,
298 } => {
299 let vec_size = match resolver[vector] {
300 Ti::Vector { size: vec_size, .. } => vec_size,
301 ref other => {
302 log::error!("Swizzle vector type {:?}", other);
303 return Err(ExpressionError::InvalidVectorType(vector));
304 }
305 };
306 for &sc in pattern[..size as usize].iter() {
307 if sc as u8 >= vec_size as u8 {
308 return Err(ExpressionError::InvalidSwizzleComponent(sc, vec_size));
309 }
310 }
311 ShaderStages::all()
312 }
313 E::Literal(_) | E::Constant(_) | E::ZeroValue(_) => ShaderStages::all(),
314 E::Compose { ref components, ty } => {
315 validate_compose(
316 ty,
317 module.to_ctx(),
318 components.iter().map(|&handle| info[handle].ty.clone()),
319 )?;
320 ShaderStages::all()
321 }
322 E::FunctionArgument(index) => {
323 if index >= function.arguments.len() as u32 {
324 return Err(ExpressionError::FunctionArgumentDoesntExist(index));
325 }
326 ShaderStages::all()
327 }
328 E::GlobalVariable(_handle) => ShaderStages::all(),
329 E::LocalVariable(_handle) => ShaderStages::all(),
330 E::Load { pointer } => {
331 match resolver[pointer] {
332 Ti::Pointer { base, .. }
333 if self.types[base.index()]
334 .flags
335 .contains(TypeFlags::SIZED | TypeFlags::DATA) => {}
336 Ti::ValuePointer { .. } => {}
337 ref other => {
338 log::error!("Loading {:?}", other);
339 return Err(ExpressionError::InvalidPointerType(pointer));
340 }
341 }
342 ShaderStages::all()
343 }
344 E::ImageSample {
345 image,
346 sampler,
347 gather,
348 coordinate,
349 array_index,
350 offset,
351 level,
352 depth_ref,
353 } => {
354 let image_ty = Self::global_var_ty(module, function, image)?;
356 let sampler_ty = Self::global_var_ty(module, function, sampler)?;
357
358 let comparison = match module.types[sampler_ty].inner {
359 Ti::Sampler { comparison } => comparison,
360 _ => return Err(ExpressionError::ExpectedSamplerType(sampler_ty)),
361 };
362
363 let (class, dim) = match module.types[image_ty].inner {
364 Ti::Image {
365 class,
366 arrayed,
367 dim,
368 } => {
369 if arrayed != array_index.is_some() {
371 return Err(ExpressionError::InvalidImageArrayIndex);
372 }
373 if let Some(expr) = array_index {
374 match resolver[expr] {
375 Ti::Scalar {
376 kind: Sk::Sint | Sk::Uint,
377 width: _,
378 } => {}
379 _ => return Err(ExpressionError::InvalidImageArrayIndexType(expr)),
380 }
381 }
382 (class, dim)
383 }
384 _ => return Err(ExpressionError::ExpectedImageType(image_ty)),
385 };
386
387 let image_depth = match class {
389 crate::ImageClass::Sampled {
390 kind: crate::ScalarKind::Float,
391 multi: false,
392 } => false,
393 crate::ImageClass::Sampled {
394 kind: crate::ScalarKind::Uint | crate::ScalarKind::Sint,
395 multi: false,
396 } if gather.is_some() => false,
397 crate::ImageClass::Depth { multi: false } => true,
398 _ => return Err(ExpressionError::InvalidImageClass(class)),
399 };
400 if comparison != depth_ref.is_some() || (comparison && !image_depth) {
401 return Err(ExpressionError::ComparisonSamplingMismatch {
402 image: class,
403 sampler: comparison,
404 has_ref: depth_ref.is_some(),
405 });
406 }
407
408 let num_components = match dim {
410 crate::ImageDimension::D1 => 1,
411 crate::ImageDimension::D2 => 2,
412 crate::ImageDimension::D3 | crate::ImageDimension::Cube => 3,
413 };
414 match resolver[coordinate] {
415 Ti::Scalar {
416 kind: Sk::Float, ..
417 } if num_components == 1 => {}
418 Ti::Vector {
419 size,
420 kind: Sk::Float,
421 ..
422 } if size as u32 == num_components => {}
423 _ => return Err(ExpressionError::InvalidImageCoordinateType(dim, coordinate)),
424 }
425
426 if let Some(const_expr) = offset {
428 match *mod_info[const_expr].inner_with(&module.types) {
429 Ti::Scalar { kind: Sk::Sint, .. } if num_components == 1 => {}
430 Ti::Vector {
431 size,
432 kind: Sk::Sint,
433 ..
434 } if size as u32 == num_components => {}
435 _ => {
436 return Err(ExpressionError::InvalidSampleOffset(dim, const_expr));
437 }
438 }
439 }
440
441 if let Some(expr) = depth_ref {
443 match resolver[expr] {
444 Ti::Scalar {
445 kind: Sk::Float, ..
446 } => {}
447 _ => return Err(ExpressionError::InvalidDepthReference(expr)),
448 }
449 match level {
450 crate::SampleLevel::Auto | crate::SampleLevel::Zero => {}
451 _ => return Err(ExpressionError::InvalidDepthSampleLevel),
452 }
453 }
454
455 if let Some(component) = gather {
456 match dim {
457 crate::ImageDimension::D2 | crate::ImageDimension::Cube => {}
458 crate::ImageDimension::D1 | crate::ImageDimension::D3 => {
459 return Err(ExpressionError::InvalidGatherDimension(dim))
460 }
461 };
462 let max_component = match class {
463 crate::ImageClass::Depth { .. } => crate::SwizzleComponent::X,
464 _ => crate::SwizzleComponent::W,
465 };
466 if component > max_component {
467 return Err(ExpressionError::InvalidGatherComponent(component));
468 }
469 match level {
470 crate::SampleLevel::Zero => {}
471 _ => return Err(ExpressionError::InvalidGatherLevel),
472 }
473 }
474
475 match level {
477 crate::SampleLevel::Auto => ShaderStages::FRAGMENT,
478 crate::SampleLevel::Zero => ShaderStages::all(),
479 crate::SampleLevel::Exact(expr) => {
480 match resolver[expr] {
481 Ti::Scalar {
482 kind: Sk::Float, ..
483 } => {}
484 _ => return Err(ExpressionError::InvalidSampleLevelExactType(expr)),
485 }
486 ShaderStages::all()
487 }
488 crate::SampleLevel::Bias(expr) => {
489 match resolver[expr] {
490 Ti::Scalar {
491 kind: Sk::Float, ..
492 } => {}
493 _ => return Err(ExpressionError::InvalidSampleLevelBiasType(expr)),
494 }
495 ShaderStages::all()
496 }
497 crate::SampleLevel::Gradient { x, y } => {
498 match resolver[x] {
499 Ti::Scalar {
500 kind: Sk::Float, ..
501 } if num_components == 1 => {}
502 Ti::Vector {
503 size,
504 kind: Sk::Float,
505 ..
506 } if size as u32 == num_components => {}
507 _ => {
508 return Err(ExpressionError::InvalidSampleLevelGradientType(dim, x))
509 }
510 }
511 match resolver[y] {
512 Ti::Scalar {
513 kind: Sk::Float, ..
514 } if num_components == 1 => {}
515 Ti::Vector {
516 size,
517 kind: Sk::Float,
518 ..
519 } if size as u32 == num_components => {}
520 _ => {
521 return Err(ExpressionError::InvalidSampleLevelGradientType(dim, y))
522 }
523 }
524 ShaderStages::all()
525 }
526 }
527 }
528 E::ImageLoad {
529 image,
530 coordinate,
531 array_index,
532 sample,
533 level,
534 } => {
535 let ty = Self::global_var_ty(module, function, image)?;
536 match module.types[ty].inner {
537 Ti::Image {
538 class,
539 arrayed,
540 dim,
541 } => {
542 match resolver[coordinate].image_storage_coordinates() {
543 Some(coord_dim) if coord_dim == dim => {}
544 _ => {
545 return Err(ExpressionError::InvalidImageCoordinateType(
546 dim, coordinate,
547 ))
548 }
549 };
550 if arrayed != array_index.is_some() {
551 return Err(ExpressionError::InvalidImageArrayIndex);
552 }
553 if let Some(expr) = array_index {
554 match resolver[expr] {
555 Ti::Scalar {
556 kind: Sk::Sint | Sk::Uint,
557 width: _,
558 } => {}
559 _ => return Err(ExpressionError::InvalidImageArrayIndexType(expr)),
560 }
561 }
562
563 match (sample, class.is_multisampled()) {
564 (None, false) => {}
565 (Some(sample), true) => {
566 if resolver[sample].scalar_kind() != Some(Sk::Sint) {
567 return Err(ExpressionError::InvalidImageOtherIndexType(
568 sample,
569 ));
570 }
571 }
572 _ => {
573 return Err(ExpressionError::InvalidImageOtherIndex);
574 }
575 }
576
577 match (level, class.is_mipmapped()) {
578 (None, false) => {}
579 (Some(level), true) => {
580 if resolver[level].scalar_kind() != Some(Sk::Sint) {
581 return Err(ExpressionError::InvalidImageOtherIndexType(level));
582 }
583 }
584 _ => {
585 return Err(ExpressionError::InvalidImageOtherIndex);
586 }
587 }
588 }
589 _ => return Err(ExpressionError::ExpectedImageType(ty)),
590 }
591 ShaderStages::all()
592 }
593 E::ImageQuery { image, query } => {
594 let ty = Self::global_var_ty(module, function, image)?;
595 match module.types[ty].inner {
596 Ti::Image { class, arrayed, .. } => {
597 let good = match query {
598 crate::ImageQuery::NumLayers => arrayed,
599 crate::ImageQuery::Size { level: None } => true,
600 crate::ImageQuery::Size { level: Some(_) }
601 | crate::ImageQuery::NumLevels => class.is_mipmapped(),
602 crate::ImageQuery::NumSamples => class.is_multisampled(),
603 };
604 if !good {
605 return Err(ExpressionError::InvalidImageClass(class));
606 }
607 }
608 _ => return Err(ExpressionError::ExpectedImageType(ty)),
609 }
610 ShaderStages::all()
611 }
612 E::Unary { op, expr } => {
613 use crate::UnaryOperator as Uo;
614 let inner = &resolver[expr];
615 match (op, inner.scalar_kind()) {
616 (_, Some(Sk::Sint | Sk::Bool))
617 | (Uo::Negate, Some(Sk::Float))
619 | (Uo::Not, Some(Sk::Uint)) => {}
620 other => {
621 log::error!("Op {:?} kind {:?}", op, other);
622 return Err(ExpressionError::InvalidUnaryOperandType(op, expr));
623 }
624 }
625 ShaderStages::all()
626 }
627 E::Binary { op, left, right } => {
628 use crate::BinaryOperator as Bo;
629 let left_inner = &resolver[left];
630 let right_inner = &resolver[right];
631 let good = match op {
632 Bo::Add | Bo::Subtract => match *left_inner {
633 Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => match kind {
634 Sk::Uint | Sk::Sint | Sk::Float => left_inner == right_inner,
635 Sk::Bool => false,
636 },
637 Ti::Matrix { .. } => left_inner == right_inner,
638 _ => false,
639 },
640 Bo::Divide | Bo::Modulo => match *left_inner {
641 Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => match kind {
642 Sk::Uint | Sk::Sint | Sk::Float => left_inner == right_inner,
643 Sk::Bool => false,
644 },
645 _ => false,
646 },
647 Bo::Multiply => {
648 let kind_allowed = match left_inner.scalar_kind() {
649 Some(Sk::Uint | Sk::Sint | Sk::Float) => true,
650 Some(Sk::Bool) | None => false,
651 };
652 let types_match = match (left_inner, right_inner) {
653 (&Ti::Scalar { kind: kind1, .. }, &Ti::Scalar { kind: kind2, .. })
655 | (&Ti::Vector { kind: kind1, .. }, &Ti::Scalar { kind: kind2, .. })
656 | (&Ti::Scalar { kind: kind1, .. }, &Ti::Vector { kind: kind2, .. }) => {
657 kind1 == kind2
658 }
659 (
661 &Ti::Scalar {
662 kind: Sk::Float, ..
663 },
664 &Ti::Matrix { .. },
665 )
666 | (
667 &Ti::Matrix { .. },
668 &Ti::Scalar {
669 kind: Sk::Float, ..
670 },
671 ) => true,
672 (
674 &Ti::Vector {
675 kind: kind1,
676 size: size1,
677 ..
678 },
679 &Ti::Vector {
680 kind: kind2,
681 size: size2,
682 ..
683 },
684 ) => kind1 == kind2 && size1 == size2,
685 (
687 &Ti::Matrix { columns, .. },
688 &Ti::Vector {
689 kind: Sk::Float,
690 size,
691 ..
692 },
693 ) => columns == size,
694 (
696 &Ti::Vector {
697 kind: Sk::Float,
698 size,
699 ..
700 },
701 &Ti::Matrix { rows, .. },
702 ) => size == rows,
703 (&Ti::Matrix { columns, .. }, &Ti::Matrix { rows, .. }) => {
704 columns == rows
705 }
706 _ => false,
707 };
708 let left_width = match *left_inner {
709 Ti::Scalar { width, .. }
710 | Ti::Vector { width, .. }
711 | Ti::Matrix { width, .. } => width,
712 _ => 0,
713 };
714 let right_width = match *right_inner {
715 Ti::Scalar { width, .. }
716 | Ti::Vector { width, .. }
717 | Ti::Matrix { width, .. } => width,
718 _ => 0,
719 };
720 kind_allowed && types_match && left_width == right_width
721 }
722 Bo::Equal | Bo::NotEqual => left_inner.is_sized() && left_inner == right_inner,
723 Bo::Less | Bo::LessEqual | Bo::Greater | Bo::GreaterEqual => {
724 match *left_inner {
725 Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => match kind {
726 Sk::Uint | Sk::Sint | Sk::Float => left_inner == right_inner,
727 Sk::Bool => false,
728 },
729 ref other => {
730 log::error!("Op {:?} left type {:?}", op, other);
731 false
732 }
733 }
734 }
735 Bo::LogicalAnd | Bo::LogicalOr => match *left_inner {
736 Ti::Scalar { kind: Sk::Bool, .. } | Ti::Vector { kind: Sk::Bool, .. } => {
737 left_inner == right_inner
738 }
739 ref other => {
740 log::error!("Op {:?} left type {:?}", op, other);
741 false
742 }
743 },
744 Bo::And | Bo::InclusiveOr => match *left_inner {
745 Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => match kind {
746 Sk::Bool | Sk::Sint | Sk::Uint => left_inner == right_inner,
747 Sk::Float => false,
748 },
749 ref other => {
750 log::error!("Op {:?} left type {:?}", op, other);
751 false
752 }
753 },
754 Bo::ExclusiveOr => match *left_inner {
755 Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => match kind {
756 Sk::Sint | Sk::Uint => left_inner == right_inner,
757 Sk::Bool | Sk::Float => false,
758 },
759 ref other => {
760 log::error!("Op {:?} left type {:?}", op, other);
761 false
762 }
763 },
764 Bo::ShiftLeft | Bo::ShiftRight => {
765 let (base_size, base_kind) = match *left_inner {
766 Ti::Scalar { kind, .. } => (Ok(None), kind),
767 Ti::Vector { size, kind, .. } => (Ok(Some(size)), kind),
768 ref other => {
769 log::error!("Op {:?} base type {:?}", op, other);
770 (Err(()), Sk::Bool)
771 }
772 };
773 let shift_size = match *right_inner {
774 Ti::Scalar { kind: Sk::Uint, .. } => Ok(None),
775 Ti::Vector {
776 size,
777 kind: Sk::Uint,
778 ..
779 } => Ok(Some(size)),
780 ref other => {
781 log::error!("Op {:?} shift type {:?}", op, other);
782 Err(())
783 }
784 };
785 match base_kind {
786 Sk::Sint | Sk::Uint => base_size.is_ok() && base_size == shift_size,
787 Sk::Float | Sk::Bool => false,
788 }
789 }
790 };
791 if !good {
792 log::error!(
793 "Left: {:?} of type {:?}",
794 function.expressions[left],
795 left_inner
796 );
797 log::error!(
798 "Right: {:?} of type {:?}",
799 function.expressions[right],
800 right_inner
801 );
802 return Err(ExpressionError::InvalidBinaryOperandTypes(op, left, right));
803 }
804 ShaderStages::all()
805 }
806 E::Select {
807 condition,
808 accept,
809 reject,
810 } => {
811 let accept_inner = &resolver[accept];
812 let reject_inner = &resolver[reject];
813 let condition_good = match resolver[condition] {
814 Ti::Scalar {
815 kind: Sk::Bool,
816 width: _,
817 } => {
818 match *accept_inner {
821 Ti::Scalar { .. } | Ti::Vector { .. } => true,
822 _ => false,
823 }
824 }
825 Ti::Vector {
826 size,
827 kind: Sk::Bool,
828 width: _,
829 } => match *accept_inner {
830 Ti::Vector {
831 size: other_size, ..
832 } => size == other_size,
833 _ => false,
834 },
835 _ => false,
836 };
837 if !condition_good || accept_inner != reject_inner {
838 return Err(ExpressionError::InvalidSelectTypes);
839 }
840 ShaderStages::all()
841 }
842 E::Derivative { expr, .. } => {
843 match resolver[expr] {
844 Ti::Scalar {
845 kind: Sk::Float, ..
846 }
847 | Ti::Vector {
848 kind: Sk::Float, ..
849 } => {}
850 _ => return Err(ExpressionError::InvalidDerivative),
851 }
852 ShaderStages::FRAGMENT
853 }
854 E::Relational { fun, argument } => {
855 use crate::RelationalFunction as Rf;
856 let argument_inner = &resolver[argument];
857 match fun {
858 Rf::All | Rf::Any => match *argument_inner {
859 Ti::Vector { kind: Sk::Bool, .. } => {}
860 ref other => {
861 log::error!("All/Any of type {:?}", other);
862 return Err(ExpressionError::InvalidBooleanVector(argument));
863 }
864 },
865 Rf::IsNan | Rf::IsInf | Rf::IsFinite | Rf::IsNormal => match *argument_inner {
866 Ti::Scalar {
867 kind: Sk::Float, ..
868 }
869 | Ti::Vector {
870 kind: Sk::Float, ..
871 } => {}
872 ref other => {
873 log::error!("Float test of type {:?}", other);
874 return Err(ExpressionError::InvalidFloatArgument(argument));
875 }
876 },
877 }
878 ShaderStages::all()
879 }
880 E::Math {
881 fun,
882 arg,
883 arg1,
884 arg2,
885 arg3,
886 } => {
887 use crate::MathFunction as Mf;
888
889 let resolve = |arg| &resolver[arg];
890 let arg_ty = resolve(arg);
891 let arg1_ty = arg1.map(resolve);
892 let arg2_ty = arg2.map(resolve);
893 let arg3_ty = arg3.map(resolve);
894 match fun {
895 Mf::Abs => {
896 if arg1_ty.is_some() | arg2_ty.is_some() | arg3_ty.is_some() {
897 return Err(ExpressionError::WrongArgumentCount(fun));
898 }
899 let good = match *arg_ty {
900 Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => kind != Sk::Bool,
901 _ => false,
902 };
903 if !good {
904 return Err(ExpressionError::InvalidArgumentType(fun, 0, arg));
905 }
906 }
907 Mf::Min | Mf::Max => {
908 let arg1_ty = match (arg1_ty, arg2_ty, arg3_ty) {
909 (Some(ty1), None, None) => ty1,
910 _ => return Err(ExpressionError::WrongArgumentCount(fun)),
911 };
912 let good = match *arg_ty {
913 Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => kind != Sk::Bool,
914 _ => false,
915 };
916 if !good {
917 return Err(ExpressionError::InvalidArgumentType(fun, 0, arg));
918 }
919 if arg1_ty != arg_ty {
920 return Err(ExpressionError::InvalidArgumentType(
921 fun,
922 1,
923 arg1.unwrap(),
924 ));
925 }
926 }
927 Mf::Clamp => {
928 let (arg1_ty, arg2_ty) = match (arg1_ty, arg2_ty, arg3_ty) {
929 (Some(ty1), Some(ty2), None) => (ty1, ty2),
930 _ => return Err(ExpressionError::WrongArgumentCount(fun)),
931 };
932 let good = match *arg_ty {
933 Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => kind != Sk::Bool,
934 _ => false,
935 };
936 if !good {
937 return Err(ExpressionError::InvalidArgumentType(fun, 0, arg));
938 }
939 if arg1_ty != arg_ty {
940 return Err(ExpressionError::InvalidArgumentType(
941 fun,
942 1,
943 arg1.unwrap(),
944 ));
945 }
946 if arg2_ty != arg_ty {
947 return Err(ExpressionError::InvalidArgumentType(
948 fun,
949 2,
950 arg2.unwrap(),
951 ));
952 }
953 }
954 Mf::Saturate
955 | Mf::Cos
956 | Mf::Cosh
957 | Mf::Sin
958 | Mf::Sinh
959 | Mf::Tan
960 | Mf::Tanh
961 | Mf::Acos
962 | Mf::Asin
963 | Mf::Atan
964 | Mf::Asinh
965 | Mf::Acosh
966 | Mf::Atanh
967 | Mf::Radians
968 | Mf::Degrees
969 | Mf::Ceil
970 | Mf::Floor
971 | Mf::Round
972 | Mf::Fract
973 | Mf::Trunc
974 | Mf::Exp
975 | Mf::Exp2
976 | Mf::Log
977 | Mf::Log2
978 | Mf::Length
979 | Mf::Sign
980 | Mf::Sqrt
981 | Mf::InverseSqrt => {
982 if arg1_ty.is_some() | arg2_ty.is_some() | arg3_ty.is_some() {
983 return Err(ExpressionError::WrongArgumentCount(fun));
984 }
985 match *arg_ty {
986 Ti::Scalar {
987 kind: Sk::Float, ..
988 }
989 | Ti::Vector {
990 kind: Sk::Float, ..
991 } => {}
992 _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
993 }
994 }
995 Mf::Atan2 | Mf::Pow | Mf::Distance | Mf::Step => {
996 let arg1_ty = match (arg1_ty, arg2_ty, arg3_ty) {
997 (Some(ty1), None, None) => ty1,
998 _ => return Err(ExpressionError::WrongArgumentCount(fun)),
999 };
1000 match *arg_ty {
1001 Ti::Scalar {
1002 kind: Sk::Float, ..
1003 }
1004 | Ti::Vector {
1005 kind: Sk::Float, ..
1006 } => {}
1007 _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
1008 }
1009 if arg1_ty != arg_ty {
1010 return Err(ExpressionError::InvalidArgumentType(
1011 fun,
1012 1,
1013 arg1.unwrap(),
1014 ));
1015 }
1016 }
1017 Mf::Modf | Mf::Frexp | Mf::Ldexp => {
1018 let arg1_ty = match (arg1_ty, arg2_ty, arg3_ty) {
1019 (Some(ty1), None, None) => ty1,
1020 _ => return Err(ExpressionError::WrongArgumentCount(fun)),
1021 };
1022 let (size0, width0) = match *arg_ty {
1023 Ti::Scalar {
1024 kind: Sk::Float,
1025 width,
1026 } => (None, width),
1027 Ti::Vector {
1028 kind: Sk::Float,
1029 size,
1030 width,
1031 } => (Some(size), width),
1032 _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
1033 };
1034 let good = match *arg1_ty {
1035 Ti::Pointer { base, space: _ } => module.types[base].inner == *arg_ty,
1036 Ti::ValuePointer {
1037 size,
1038 kind: Sk::Float,
1039 width,
1040 space: _,
1041 } => size == size0 && width == width0,
1042 _ => false,
1043 };
1044 if !good {
1045 return Err(ExpressionError::InvalidArgumentType(
1046 fun,
1047 1,
1048 arg1.unwrap(),
1049 ));
1050 }
1051 }
1052 Mf::Dot => {
1053 let arg1_ty = match (arg1_ty, arg2_ty, arg3_ty) {
1054 (Some(ty1), None, None) => ty1,
1055 _ => return Err(ExpressionError::WrongArgumentCount(fun)),
1056 };
1057 match *arg_ty {
1058 Ti::Vector {
1059 kind: Sk::Float | Sk::Sint | Sk::Uint,
1060 ..
1061 } => {}
1062 _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
1063 }
1064 if arg1_ty != arg_ty {
1065 return Err(ExpressionError::InvalidArgumentType(
1066 fun,
1067 1,
1068 arg1.unwrap(),
1069 ));
1070 }
1071 }
1072 Mf::Outer | Mf::Cross | Mf::Reflect => {
1073 let arg1_ty = match (arg1_ty, arg2_ty, arg3_ty) {
1074 (Some(ty1), None, None) => ty1,
1075 _ => return Err(ExpressionError::WrongArgumentCount(fun)),
1076 };
1077 match *arg_ty {
1078 Ti::Vector {
1079 kind: Sk::Float, ..
1080 } => {}
1081 _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
1082 }
1083 if arg1_ty != arg_ty {
1084 return Err(ExpressionError::InvalidArgumentType(
1085 fun,
1086 1,
1087 arg1.unwrap(),
1088 ));
1089 }
1090 }
1091 Mf::Refract => {
1092 let (arg1_ty, arg2_ty) = match (arg1_ty, arg2_ty, arg3_ty) {
1093 (Some(ty1), Some(ty2), None) => (ty1, ty2),
1094 _ => return Err(ExpressionError::WrongArgumentCount(fun)),
1095 };
1096
1097 match *arg_ty {
1098 Ti::Vector {
1099 kind: Sk::Float, ..
1100 } => {}
1101 _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
1102 }
1103
1104 if arg1_ty != arg_ty {
1105 return Err(ExpressionError::InvalidArgumentType(
1106 fun,
1107 1,
1108 arg1.unwrap(),
1109 ));
1110 }
1111
1112 match (arg_ty, arg2_ty) {
1113 (
1114 &Ti::Vector {
1115 width: vector_width,
1116 ..
1117 },
1118 &Ti::Scalar {
1119 width: scalar_width,
1120 kind: Sk::Float,
1121 },
1122 ) if vector_width == scalar_width => {}
1123 _ => {
1124 return Err(ExpressionError::InvalidArgumentType(
1125 fun,
1126 2,
1127 arg2.unwrap(),
1128 ))
1129 }
1130 }
1131 }
1132 Mf::Normalize => {
1133 if arg1_ty.is_some() | arg2_ty.is_some() | arg3_ty.is_some() {
1134 return Err(ExpressionError::WrongArgumentCount(fun));
1135 }
1136 match *arg_ty {
1137 Ti::Vector {
1138 kind: Sk::Float, ..
1139 } => {}
1140 _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
1141 }
1142 }
1143 Mf::FaceForward | Mf::Fma | Mf::SmoothStep => {
1144 let (arg1_ty, arg2_ty) = match (arg1_ty, arg2_ty, arg3_ty) {
1145 (Some(ty1), Some(ty2), None) => (ty1, ty2),
1146 _ => return Err(ExpressionError::WrongArgumentCount(fun)),
1147 };
1148 match *arg_ty {
1149 Ti::Scalar {
1150 kind: Sk::Float, ..
1151 }
1152 | Ti::Vector {
1153 kind: Sk::Float, ..
1154 } => {}
1155 _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
1156 }
1157 if arg1_ty != arg_ty {
1158 return Err(ExpressionError::InvalidArgumentType(
1159 fun,
1160 1,
1161 arg1.unwrap(),
1162 ));
1163 }
1164 if arg2_ty != arg_ty {
1165 return Err(ExpressionError::InvalidArgumentType(
1166 fun,
1167 2,
1168 arg2.unwrap(),
1169 ));
1170 }
1171 }
1172 Mf::Mix => {
1173 let (arg1_ty, arg2_ty) = match (arg1_ty, arg2_ty, arg3_ty) {
1174 (Some(ty1), Some(ty2), None) => (ty1, ty2),
1175 _ => return Err(ExpressionError::WrongArgumentCount(fun)),
1176 };
1177 let arg_width = match *arg_ty {
1178 Ti::Scalar {
1179 kind: Sk::Float,
1180 width,
1181 }
1182 | Ti::Vector {
1183 kind: Sk::Float,
1184 width,
1185 ..
1186 } => width,
1187 _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
1188 };
1189 if arg1_ty != arg_ty {
1190 return Err(ExpressionError::InvalidArgumentType(
1191 fun,
1192 1,
1193 arg1.unwrap(),
1194 ));
1195 }
1196 match *arg2_ty {
1198 Ti::Scalar {
1199 kind: Sk::Float,
1200 width,
1201 } if width == arg_width => {}
1202 _ if arg2_ty == arg_ty => {}
1203 _ => {
1204 return Err(ExpressionError::InvalidArgumentType(
1205 fun,
1206 2,
1207 arg2.unwrap(),
1208 ));
1209 }
1210 }
1211 }
1212 Mf::Inverse | Mf::Determinant => {
1213 if arg1_ty.is_some() | arg2_ty.is_some() | arg3_ty.is_some() {
1214 return Err(ExpressionError::WrongArgumentCount(fun));
1215 }
1216 let good = match *arg_ty {
1217 Ti::Matrix { columns, rows, .. } => columns == rows,
1218 _ => false,
1219 };
1220 if !good {
1221 return Err(ExpressionError::InvalidArgumentType(fun, 0, arg));
1222 }
1223 }
1224 Mf::Transpose => {
1225 if arg1_ty.is_some() | arg2_ty.is_some() | arg3_ty.is_some() {
1226 return Err(ExpressionError::WrongArgumentCount(fun));
1227 }
1228 match *arg_ty {
1229 Ti::Matrix { .. } => {}
1230 _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
1231 }
1232 }
1233 Mf::CountTrailingZeros
1234 | Mf::CountLeadingZeros
1235 | Mf::CountOneBits
1236 | Mf::ReverseBits
1237 | Mf::FindLsb
1238 | Mf::FindMsb => {
1239 if arg1_ty.is_some() | arg2_ty.is_some() | arg3_ty.is_some() {
1240 return Err(ExpressionError::WrongArgumentCount(fun));
1241 }
1242 match *arg_ty {
1243 Ti::Scalar {
1244 kind: Sk::Sint | Sk::Uint,
1245 ..
1246 }
1247 | Ti::Vector {
1248 kind: Sk::Sint | Sk::Uint,
1249 ..
1250 } => {}
1251 _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
1252 }
1253 }
1254 Mf::InsertBits => {
1255 let (arg1_ty, arg2_ty, arg3_ty) = match (arg1_ty, arg2_ty, arg3_ty) {
1256 (Some(ty1), Some(ty2), Some(ty3)) => (ty1, ty2, ty3),
1257 _ => return Err(ExpressionError::WrongArgumentCount(fun)),
1258 };
1259 match *arg_ty {
1260 Ti::Scalar {
1261 kind: Sk::Sint | Sk::Uint,
1262 ..
1263 }
1264 | Ti::Vector {
1265 kind: Sk::Sint | Sk::Uint,
1266 ..
1267 } => {}
1268 _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
1269 }
1270 if arg1_ty != arg_ty {
1271 return Err(ExpressionError::InvalidArgumentType(
1272 fun,
1273 1,
1274 arg1.unwrap(),
1275 ));
1276 }
1277 match *arg2_ty {
1278 Ti::Scalar { kind: Sk::Uint, .. } => {}
1279 _ => {
1280 return Err(ExpressionError::InvalidArgumentType(
1281 fun,
1282 2,
1283 arg2.unwrap(),
1284 ))
1285 }
1286 }
1287 match *arg3_ty {
1288 Ti::Scalar { kind: Sk::Uint, .. } => {}
1289 _ => {
1290 return Err(ExpressionError::InvalidArgumentType(
1291 fun,
1292 2,
1293 arg3.unwrap(),
1294 ))
1295 }
1296 }
1297 }
1298 Mf::ExtractBits => {
1299 let (arg1_ty, arg2_ty) = match (arg1_ty, arg2_ty, arg3_ty) {
1300 (Some(ty1), Some(ty2), None) => (ty1, ty2),
1301 _ => return Err(ExpressionError::WrongArgumentCount(fun)),
1302 };
1303 match *arg_ty {
1304 Ti::Scalar {
1305 kind: Sk::Sint | Sk::Uint,
1306 ..
1307 }
1308 | Ti::Vector {
1309 kind: Sk::Sint | Sk::Uint,
1310 ..
1311 } => {}
1312 _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
1313 }
1314 match *arg1_ty {
1315 Ti::Scalar { kind: Sk::Uint, .. } => {}
1316 _ => {
1317 return Err(ExpressionError::InvalidArgumentType(
1318 fun,
1319 2,
1320 arg1.unwrap(),
1321 ))
1322 }
1323 }
1324 match *arg2_ty {
1325 Ti::Scalar { kind: Sk::Uint, .. } => {}
1326 _ => {
1327 return Err(ExpressionError::InvalidArgumentType(
1328 fun,
1329 2,
1330 arg2.unwrap(),
1331 ))
1332 }
1333 }
1334 }
1335 Mf::Pack2x16unorm | Mf::Pack2x16snorm | Mf::Pack2x16float => {
1336 if arg1_ty.is_some() | arg2_ty.is_some() | arg3_ty.is_some() {
1337 return Err(ExpressionError::WrongArgumentCount(fun));
1338 }
1339 match *arg_ty {
1340 Ti::Vector {
1341 size: crate::VectorSize::Bi,
1342 kind: Sk::Float,
1343 ..
1344 } => {}
1345 _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
1346 }
1347 }
1348 Mf::Pack4x8snorm | Mf::Pack4x8unorm => {
1349 if arg1_ty.is_some() | arg2_ty.is_some() | arg3_ty.is_some() {
1350 return Err(ExpressionError::WrongArgumentCount(fun));
1351 }
1352 match *arg_ty {
1353 Ti::Vector {
1354 size: crate::VectorSize::Quad,
1355 kind: Sk::Float,
1356 ..
1357 } => {}
1358 _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
1359 }
1360 }
1361 Mf::Unpack2x16float
1362 | Mf::Unpack2x16snorm
1363 | Mf::Unpack2x16unorm
1364 | Mf::Unpack4x8snorm
1365 | Mf::Unpack4x8unorm => {
1366 if arg1_ty.is_some() | arg2_ty.is_some() | arg3_ty.is_some() {
1367 return Err(ExpressionError::WrongArgumentCount(fun));
1368 }
1369 match *arg_ty {
1370 Ti::Scalar { kind: Sk::Uint, .. } => {}
1371 _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
1372 }
1373 }
1374 }
1375 ShaderStages::all()
1376 }
1377 E::As {
1378 expr,
1379 kind,
1380 convert,
1381 } => {
1382 let base_width = match resolver[expr] {
1383 crate::TypeInner::Scalar { width, .. }
1384 | crate::TypeInner::Vector { width, .. }
1385 | crate::TypeInner::Matrix { width, .. } => width,
1386 _ => return Err(ExpressionError::InvalidCastArgument),
1387 };
1388 let width = convert.unwrap_or(base_width);
1389 if self.check_width(kind, width).is_err() {
1390 return Err(ExpressionError::InvalidCastArgument);
1391 }
1392 ShaderStages::all()
1393 }
1394 E::CallResult(function) => mod_info.functions[function.index()].available_stages,
1395 E::AtomicResult { ty, comparison } => {
1396 let scalar_predicate = |ty: &crate::TypeInner| match ty {
1397 &crate::TypeInner::Scalar {
1398 kind: kind @ (crate::ScalarKind::Uint | crate::ScalarKind::Sint),
1399 width,
1400 } => self.check_width(kind, width).is_ok(),
1401 _ => false,
1402 };
1403 let good = match &module.types[ty].inner {
1404 ty if !comparison => scalar_predicate(ty),
1405 &crate::TypeInner::Struct { ref members, .. } if comparison => {
1406 validate_atomic_compare_exchange_struct(
1407 &module.types,
1408 members,
1409 scalar_predicate,
1410 )
1411 }
1412 _ => false,
1413 };
1414 if !good {
1415 return Err(ExpressionError::InvalidAtomicResultType(ty));
1416 }
1417 ShaderStages::all()
1418 }
1419 E::WorkGroupUniformLoadResult { ty } => {
1420 if self.types[ty.index()]
1421 .flags
1422 .contains(TypeFlags::SIZED | TypeFlags::CONSTRUCTIBLE)
1425 {
1426 ShaderStages::COMPUTE
1427 } else {
1428 return Err(ExpressionError::InvalidWorkGroupUniformLoadResultType(ty));
1429 }
1430 }
1431 E::ArrayLength(expr) => match resolver[expr] {
1432 Ti::Pointer { base, .. } => {
1433 let base_ty = &resolver.types[base];
1434 if let Ti::Array {
1435 size: crate::ArraySize::Dynamic,
1436 ..
1437 } = base_ty.inner
1438 {
1439 ShaderStages::all()
1440 } else {
1441 return Err(ExpressionError::InvalidArrayType(expr));
1442 }
1443 }
1444 ref other => {
1445 log::error!("Array length of {:?}", other);
1446 return Err(ExpressionError::InvalidArrayType(expr));
1447 }
1448 },
1449 E::RayQueryProceedResult => ShaderStages::all(),
1450 E::RayQueryGetIntersection {
1451 query,
1452 committed: _,
1453 } => match resolver[query] {
1454 Ti::Pointer {
1455 base,
1456 space: crate::AddressSpace::Function,
1457 } => match resolver.types[base].inner {
1458 Ti::RayQuery => ShaderStages::all(),
1459 ref other => {
1460 log::error!("Intersection result of a pointer to {:?}", other);
1461 return Err(ExpressionError::InvalidRayQueryType(query));
1462 }
1463 },
1464 ref other => {
1465 log::error!("Intersection result of {:?}", other);
1466 return Err(ExpressionError::InvalidRayQueryType(query));
1467 }
1468 },
1469 };
1470 Ok(stages)
1471 }
1472
1473 fn global_var_ty(
1474 module: &crate::Module,
1475 function: &crate::Function,
1476 expr: Handle<crate::Expression>,
1477 ) -> Result<Handle<crate::Type>, ExpressionError> {
1478 use crate::Expression as Ex;
1479
1480 match function.expressions[expr] {
1481 Ex::GlobalVariable(var_handle) => Ok(module.global_variables[var_handle].ty),
1482 Ex::FunctionArgument(i) => Ok(function.arguments[i as usize].ty),
1483 Ex::Access { base, .. } | Ex::AccessIndex { base, .. } => {
1484 match function.expressions[base] {
1485 Ex::GlobalVariable(var_handle) => {
1486 let array_ty = module.global_variables[var_handle].ty;
1487
1488 match module.types[array_ty].inner {
1489 crate::TypeInner::BindingArray { base, .. } => Ok(base),
1490 _ => Err(ExpressionError::ExpectedBindingArrayType(array_ty)),
1491 }
1492 }
1493 _ => Err(ExpressionError::ExpectedGlobalVariable),
1494 }
1495 }
1496 _ => Err(ExpressionError::ExpectedGlobalVariable),
1497 }
1498 }
1499}