naga/valid/
expression.rs

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            // `Validator::validate_module_handles` should have caught this.
146            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                // See the documentation for `Expression::Access`.
200                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                    //TODO: only allow one of these
213                    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 we know both the length and the index, we can do the
229                // bounds check now.
230                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, // can't statically know, but need run-time checks
269                        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                // check the validity of expressions
355                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                        // check the array property
370                        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                // check sampling and comparison properties
388                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                // check texture coordinates type
409                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                // check constant offset
427                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                // check depth reference type
442                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                // check level properties
476                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                    //TODO: restrict Negate for bools?
618                    | (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                            // Straight scalar and mixed scalar/vector.
654                            (&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                            // Scalar/matrix.
660                            (
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                            // Vector/vector.
673                            (
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                            // Matrix * vector.
686                            (
687                                &Ti::Matrix { columns, .. },
688                                &Ti::Vector {
689                                    kind: Sk::Float,
690                                    size,
691                                    ..
692                                },
693                            ) => columns == size,
694                            // Vector * matrix.
695                            (
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                        // When `condition` is a single boolean, `accept` and
819                        // `reject` can be vectors or scalars.
820                        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                        // the last argument can always be a scalar
1197                        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                    // Sized | Constructible is exactly the types currently supported by
1423                    // WorkGroupUniformLoad
1424                    .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}