1mod analyzer;
6mod compose;
7mod expression;
8mod function;
9mod handles;
10pub(crate) mod immediates;
11mod interface;
12mod r#type;
13
14use alloc::{boxed::Box, string::String, vec, vec::Vec};
15use core::ops;
16
17use bit_set::BitSet;
18
19use crate::{
20 arena::{Handle, HandleSet},
21 proc::{ExpressionKindTracker, LayoutError, Layouter, TypeResolution},
22 FastHashSet,
23};
24
25use crate::span::{AddSpan as _, WithSpan};
29pub use analyzer::{ExpressionInfo, FunctionInfo, GlobalUse, Uniformity, UniformityRequirements};
30pub use compose::ComposeError;
31pub use expression::{check_literal_value, LiteralError};
32pub use expression::{ConstExpressionError, ExpressionError};
33pub use function::{CallError, FunctionError, LocalVariableError, SubgroupError};
34pub use immediates::ImmediateSlots;
35pub use interface::{EntryPointError, GlobalVariableError, VaryingError};
36pub use r#type::{Disalignment, ImmediateError, TypeError, TypeFlags, WidthError};
37
38use self::handles::InvalidHandleError;
39
40pub const MAX_TYPE_SIZE: u32 = i32::MAX as u32;
42
43bitflags::bitflags! {
44 #[cfg_attr(feature = "serialize", derive(serde::Serialize))]
58 #[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
59 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
60 pub struct ValidationFlags: u8 {
61 const EXPRESSIONS = 0x1;
63 const BLOCKS = 0x2;
65 const CONTROL_FLOW_UNIFORMITY = 0x4;
67 const STRUCT_LAYOUTS = 0x8;
69 const CONSTANTS = 0x10;
71 const BINDINGS = 0x20;
73 }
74}
75
76impl Default for ValidationFlags {
77 fn default() -> Self {
78 Self::all()
79 }
80}
81
82bitflags::bitflags! {
83 #[must_use]
85 #[cfg_attr(feature = "serialize", derive(serde::Serialize))]
86 #[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
87 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
88 pub struct Capabilities: u64 {
89 const IMMEDIATES = 1 << 0;
93 const FLOAT64 = 1 << 1;
95 const PRIMITIVE_INDEX = 1 << 2;
99 const TEXTURE_AND_SAMPLER_BINDING_ARRAY = 1 << 3;
101 const BUFFER_BINDING_ARRAY = 1 << 4;
103 const STORAGE_TEXTURE_BINDING_ARRAY = 1 << 5;
105 const STORAGE_BUFFER_BINDING_ARRAY = 1 << 6;
107 const CLIP_DISTANCES = 1 << 7;
111 const CULL_DISTANCE = 1 << 8;
115 const STORAGE_TEXTURE_16BIT_NORM_FORMATS = 1 << 9;
117 const MULTIVIEW = 1 << 10;
121 const EARLY_DEPTH_TEST = 1 << 11;
123 const MULTISAMPLED_SHADING = 1 << 12;
128 const RAY_QUERY = 1 << 13;
130 const DUAL_SOURCE_BLENDING = 1 << 14;
132 const CUBE_ARRAY_TEXTURES = 1 << 15;
134 const SHADER_INT64 = 1 << 16;
136 const SUBGROUP = 1 << 17;
147 const SUBGROUP_BARRIER = 1 << 18;
151 const SUBGROUP_VERTEX_STAGE = 1 << 19;
157 const SHADER_INT64_ATOMIC_MIN_MAX = 1 << 20;
167 const SHADER_INT64_ATOMIC_ALL_OPS = 1 << 21;
169 const SHADER_FLOAT32_ATOMIC = 1 << 22;
178 const TEXTURE_ATOMIC = 1 << 23;
180 const TEXTURE_INT64_ATOMIC = 1 << 24;
182 const RAY_HIT_VERTEX_POSITION = 1 << 25;
184 const SHADER_FLOAT16 = 1 << 26;
186 const TEXTURE_EXTERNAL = 1 << 27;
188 const SHADER_FLOAT16_IN_FLOAT32 = 1 << 28;
191 const SHADER_BARYCENTRICS = 1 << 29;
193 const MESH_SHADER = 1 << 30;
195 const MESH_SHADER_POINT_TOPOLOGY = 1 << 31;
197 const TEXTURE_AND_SAMPLER_BINDING_ARRAY_NON_UNIFORM_INDEXING = 1 << 32;
199 const BUFFER_BINDING_ARRAY_NON_UNIFORM_INDEXING = 1 << 33;
201 const STORAGE_TEXTURE_BINDING_ARRAY_NON_UNIFORM_INDEXING = 1 << 34;
203 const STORAGE_BUFFER_BINDING_ARRAY_NON_UNIFORM_INDEXING = 1 << 35;
205 const COOPERATIVE_MATRIX = 1 << 36;
207 const PER_VERTEX = 1 << 37;
209 const RAY_TRACING_PIPELINE = 1 << 38;
211 const DRAW_INDEX = 1 << 39;
213 const ACCELERATION_STRUCTURE_BINDING_ARRAY = 1 << 40;
215 const MEMORY_DECORATION_COHERENT = 1 << 41;
217 const MEMORY_DECORATION_VOLATILE = 1 << 42;
219 }
220}
221
222impl Capabilities {
223 #[cfg(feature = "wgsl-in")]
227 #[doc(hidden)]
228 pub const fn extension(&self) -> Option<crate::front::wgsl::ImplementedEnableExtension> {
229 use crate::front::wgsl::ImplementedEnableExtension as Ext;
230 match *self {
231 Self::DUAL_SOURCE_BLENDING => Some(Ext::DualSourceBlending),
232 Self::SHADER_FLOAT16 => Some(Ext::F16),
234 Self::CLIP_DISTANCES => Some(Ext::ClipDistances),
235 Self::MESH_SHADER => Some(Ext::WgpuMeshShader),
236 Self::RAY_QUERY => Some(Ext::WgpuRayQuery),
237 Self::RAY_HIT_VERTEX_POSITION => Some(Ext::WgpuRayQueryVertexReturn),
238 Self::COOPERATIVE_MATRIX => Some(Ext::WgpuCooperativeMatrix),
239 Self::RAY_TRACING_PIPELINE => Some(Ext::WgpuRayTracingPipeline),
240 Self::PER_VERTEX => Some(Ext::WgpuPerVertex),
241 Self::BUFFER_BINDING_ARRAY
242 | Self::BUFFER_BINDING_ARRAY_NON_UNIFORM_INDEXING
243 | Self::STORAGE_BUFFER_BINDING_ARRAY
244 | Self::STORAGE_BUFFER_BINDING_ARRAY_NON_UNIFORM_INDEXING
245 | Self::STORAGE_TEXTURE_BINDING_ARRAY
246 | Self::STORAGE_TEXTURE_BINDING_ARRAY_NON_UNIFORM_INDEXING
247 | Self::TEXTURE_AND_SAMPLER_BINDING_ARRAY
248 | Self::TEXTURE_AND_SAMPLER_BINDING_ARRAY_NON_UNIFORM_INDEXING => {
249 Some(Ext::WgpuBindingArray)
250 }
251 _ => None,
252 }
253 }
254}
255
256impl Default for Capabilities {
257 fn default() -> Self {
258 Self::MULTISAMPLED_SHADING | Self::CUBE_ARRAY_TEXTURES
259 }
260}
261
262bitflags::bitflags! {
263 #[cfg_attr(feature = "serialize", derive(serde::Serialize))]
265 #[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
266 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
267 pub struct SubgroupOperationSet: u8 {
268 const BASIC = 1 << 0;
274 const VOTE = 1 << 1;
276 const ARITHMETIC = 1 << 2;
278 const BALLOT = 1 << 3;
280 const SHUFFLE = 1 << 4;
282 const SHUFFLE_RELATIVE = 1 << 5;
284 const QUAD_FRAGMENT_COMPUTE = 1 << 7;
289 }
292}
293
294impl super::SubgroupOperation {
295 const fn required_operations(&self) -> SubgroupOperationSet {
296 use SubgroupOperationSet as S;
297 match *self {
298 Self::All | Self::Any => S::VOTE,
299 Self::Add | Self::Mul | Self::Min | Self::Max | Self::And | Self::Or | Self::Xor => {
300 S::ARITHMETIC
301 }
302 }
303 }
304}
305
306impl super::GatherMode {
307 const fn required_operations(&self) -> SubgroupOperationSet {
308 use SubgroupOperationSet as S;
309 match *self {
310 Self::BroadcastFirst | Self::Broadcast(_) => S::BALLOT,
311 Self::Shuffle(_) | Self::ShuffleXor(_) => S::SHUFFLE,
312 Self::ShuffleUp(_) | Self::ShuffleDown(_) => S::SHUFFLE_RELATIVE,
313 Self::QuadBroadcast(_) | Self::QuadSwap(_) => S::QUAD_FRAGMENT_COMPUTE,
314 }
315 }
316}
317
318bitflags::bitflags! {
319 #[cfg_attr(feature = "serialize", derive(serde::Serialize))]
321 #[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
322 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
323 pub struct ShaderStages: u16 {
324 const VERTEX = 0x1;
325 const FRAGMENT = 0x2;
326 const COMPUTE = 0x4;
327 const MESH = 0x8;
328 const TASK = 0x10;
329 const RAY_GENERATION = 0x20;
330 const ANY_HIT = 0x40;
331 const CLOSEST_HIT = 0x80;
332 const MISS = 0x100;
333 const COMPUTE_LIKE = Self::COMPUTE.bits() | Self::TASK.bits() | Self::MESH.bits();
334 }
335}
336
337#[derive(Debug, Clone, Default)]
338#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
339#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
340pub struct ModuleInfo {
341 type_flags: Vec<TypeFlags>,
342 functions: Vec<FunctionInfo>,
343 entry_points: Vec<FunctionInfo>,
344 const_expression_types: Box<[TypeResolution]>,
345}
346
347impl ops::Index<Handle<crate::Type>> for ModuleInfo {
348 type Output = TypeFlags;
349 fn index(&self, handle: Handle<crate::Type>) -> &Self::Output {
350 &self.type_flags[handle.index()]
351 }
352}
353
354impl ops::Index<Handle<crate::Function>> for ModuleInfo {
355 type Output = FunctionInfo;
356 fn index(&self, handle: Handle<crate::Function>) -> &Self::Output {
357 &self.functions[handle.index()]
358 }
359}
360
361impl ops::Index<Handle<crate::Expression>> for ModuleInfo {
362 type Output = TypeResolution;
363 fn index(&self, handle: Handle<crate::Expression>) -> &Self::Output {
364 &self.const_expression_types[handle.index()]
365 }
366}
367
368#[derive(Debug)]
369pub struct Validator {
370 flags: ValidationFlags,
371 capabilities: Capabilities,
372 subgroup_stages: ShaderStages,
373 subgroup_operations: SubgroupOperationSet,
374 types: Vec<r#type::TypeInfo>,
375 layouter: Layouter,
376 location_mask: BitSet,
377 ep_resource_bindings: FastHashSet<crate::ResourceBinding>,
378 switch_values: FastHashSet<crate::SwitchValue>,
379 valid_expression_list: Vec<Handle<crate::Expression>>,
380 valid_expression_set: HandleSet<crate::Expression>,
381 override_ids: FastHashSet<u16>,
382
383 overrides_resolved: bool,
386
387 needs_visit: HandleSet<crate::Expression>,
406
407 trace_rays_vertex_return: TraceRayVertexReturnState,
411
412 trace_rays_payload_type: Option<Handle<crate::Type>>,
415}
416
417#[derive(Debug)]
418enum TraceRayVertexReturnState {
419 NoTraceRays,
421 #[expect(
425 unused,
426 reason = "Don't yet have vertex return builtins to return this error for."
427 )]
428 NoVertexReturn(crate::Span),
429 VertexReturn,
433}
434
435#[derive(Clone, Debug, thiserror::Error)]
436#[cfg_attr(test, derive(PartialEq))]
437pub enum ConstantError {
438 #[error("Initializer must be a const-expression")]
439 InitializerExprType,
440 #[error("The type doesn't match the constant")]
441 InvalidType,
442 #[error("The type is not constructible")]
443 NonConstructibleType,
444}
445
446#[derive(Clone, Debug, thiserror::Error)]
447#[cfg_attr(test, derive(PartialEq))]
448pub enum OverrideError {
449 #[error("Override name and ID are missing")]
450 MissingNameAndID,
451 #[error("Override ID must be unique")]
452 DuplicateID,
453 #[error("Initializer must be a const-expression or override-expression")]
454 InitializerExprType,
455 #[error("The type doesn't match the override")]
456 InvalidType,
457 #[error("The type is not constructible")]
458 NonConstructibleType,
459 #[error("The type is not a scalar")]
460 TypeNotScalar,
461 #[error("Override declarations are not allowed")]
462 NotAllowed,
463 #[error("Override is uninitialized")]
464 UninitializedOverride,
465 #[error("Constant expression {handle:?} is invalid")]
466 ConstExpression {
467 handle: Handle<crate::Expression>,
468 source: ConstExpressionError,
469 },
470}
471
472#[derive(Clone, Debug, thiserror::Error)]
473#[cfg_attr(test, derive(PartialEq))]
474pub enum ValidationError {
475 #[error(transparent)]
476 InvalidHandle(#[from] InvalidHandleError),
477 #[error(transparent)]
478 Layouter(#[from] LayoutError),
479 #[error("Type {handle:?} '{name}' is invalid")]
480 Type {
481 handle: Handle<crate::Type>,
482 name: String,
483 source: TypeError,
484 },
485 #[error("Constant expression {handle:?} is invalid")]
486 ConstExpression {
487 handle: Handle<crate::Expression>,
488 source: ConstExpressionError,
489 },
490 #[error("Array size expression {handle:?} is not strictly positive")]
491 ArraySizeError { handle: Handle<crate::Expression> },
492 #[error("Constant {handle:?} '{name}' is invalid")]
493 Constant {
494 handle: Handle<crate::Constant>,
495 name: String,
496 source: ConstantError,
497 },
498 #[error("Override {handle:?} '{name}' is invalid")]
499 Override {
500 handle: Handle<crate::Override>,
501 name: String,
502 source: OverrideError,
503 },
504 #[error("Global variable {handle:?} '{name}' is invalid")]
505 GlobalVariable {
506 handle: Handle<crate::GlobalVariable>,
507 name: String,
508 source: GlobalVariableError,
509 },
510 #[error("Function {handle:?} '{name}' is invalid")]
511 Function {
512 handle: Handle<crate::Function>,
513 name: String,
514 source: FunctionError,
515 },
516 #[error("Entry point {name} at {stage:?} is invalid")]
517 EntryPoint {
518 stage: crate::ShaderStage,
519 name: String,
520 source: EntryPointError,
521 },
522 #[error("Module is corrupted")]
523 Corrupted,
524}
525
526impl crate::TypeInner {
527 const fn is_sized(&self) -> bool {
528 match *self {
529 Self::Scalar { .. }
530 | Self::Vector { .. }
531 | Self::Matrix { .. }
532 | Self::CooperativeMatrix { .. }
533 | Self::Array {
534 size: crate::ArraySize::Constant(_),
535 ..
536 }
537 | Self::Atomic { .. }
538 | Self::Pointer { .. }
539 | Self::ValuePointer { .. }
540 | Self::Struct { .. } => true,
541 Self::Array { .. }
542 | Self::Image { .. }
543 | Self::Sampler { .. }
544 | Self::AccelerationStructure { .. }
545 | Self::RayQuery { .. }
546 | Self::BindingArray { .. } => false,
547 }
548 }
549
550 const fn image_storage_coordinates(&self) -> Option<crate::ImageDimension> {
552 match *self {
553 Self::Scalar(crate::Scalar {
554 kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint,
555 ..
556 }) => Some(crate::ImageDimension::D1),
557 Self::Vector {
558 size: crate::VectorSize::Bi,
559 scalar:
560 crate::Scalar {
561 kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint,
562 ..
563 },
564 } => Some(crate::ImageDimension::D2),
565 Self::Vector {
566 size: crate::VectorSize::Tri,
567 scalar:
568 crate::Scalar {
569 kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint,
570 ..
571 },
572 } => Some(crate::ImageDimension::D3),
573 _ => None,
574 }
575 }
576}
577
578impl Validator {
579 pub fn new(flags: ValidationFlags, capabilities: Capabilities) -> Self {
593 let subgroup_operations = if capabilities.contains(Capabilities::SUBGROUP) {
594 use SubgroupOperationSet as S;
595 S::BASIC
596 | S::VOTE
597 | S::ARITHMETIC
598 | S::BALLOT
599 | S::SHUFFLE
600 | S::SHUFFLE_RELATIVE
601 | S::QUAD_FRAGMENT_COMPUTE
602 } else {
603 SubgroupOperationSet::empty()
604 };
605 let subgroup_stages = {
606 let mut stages = ShaderStages::empty();
607 if capabilities.contains(Capabilities::SUBGROUP_VERTEX_STAGE) {
608 stages |= ShaderStages::VERTEX;
609 }
610 if capabilities.contains(Capabilities::SUBGROUP) {
611 stages |= ShaderStages::FRAGMENT | ShaderStages::COMPUTE_LIKE;
612 }
613 stages
614 };
615
616 Validator {
617 flags,
618 capabilities,
619 subgroup_stages,
620 subgroup_operations,
621 types: Vec::new(),
622 layouter: Layouter::default(),
623 location_mask: BitSet::new(),
624 ep_resource_bindings: FastHashSet::default(),
625 switch_values: FastHashSet::default(),
626 valid_expression_list: Vec::new(),
627 valid_expression_set: HandleSet::new(),
628 override_ids: FastHashSet::default(),
629 overrides_resolved: false,
630 needs_visit: HandleSet::new(),
631 trace_rays_vertex_return: TraceRayVertexReturnState::NoTraceRays,
632 trace_rays_payload_type: None,
633 }
634 }
635
636 pub const fn subgroup_stages(&mut self, stages: ShaderStages) -> &mut Self {
638 self.subgroup_stages = stages;
639 self
640 }
641
642 pub const fn subgroup_operations(&mut self, operations: SubgroupOperationSet) -> &mut Self {
644 self.subgroup_operations = operations;
645 self
646 }
647
648 pub fn reset(&mut self) {
650 self.types.clear();
651 self.layouter.clear();
652 self.location_mask.make_empty();
653 self.ep_resource_bindings.clear();
654 self.switch_values.clear();
655 self.valid_expression_list.clear();
656 self.valid_expression_set.clear();
657 self.override_ids.clear();
658 }
659
660 fn validate_constant(
661 &self,
662 handle: Handle<crate::Constant>,
663 gctx: crate::proc::GlobalCtx,
664 mod_info: &ModuleInfo,
665 global_expr_kind: &ExpressionKindTracker,
666 ) -> Result<(), ConstantError> {
667 let con = &gctx.constants[handle];
668
669 let type_info = &self.types[con.ty.index()];
670 if !type_info.flags.contains(TypeFlags::CONSTRUCTIBLE) {
671 return Err(ConstantError::NonConstructibleType);
672 }
673
674 if !global_expr_kind.is_const(con.init) {
675 return Err(ConstantError::InitializerExprType);
676 }
677
678 if !gctx.compare_types(&TypeResolution::Handle(con.ty), &mod_info[con.init]) {
679 return Err(ConstantError::InvalidType);
680 }
681
682 Ok(())
683 }
684
685 fn validate_override(
686 &mut self,
687 handle: Handle<crate::Override>,
688 gctx: crate::proc::GlobalCtx,
689 mod_info: &ModuleInfo,
690 ) -> Result<(), OverrideError> {
691 let o = &gctx.overrides[handle];
692
693 if let Some(id) = o.id {
694 if !self.override_ids.insert(id) {
695 return Err(OverrideError::DuplicateID);
696 }
697 }
698
699 let type_info = &self.types[o.ty.index()];
700 if !type_info.flags.contains(TypeFlags::CONSTRUCTIBLE) {
701 return Err(OverrideError::NonConstructibleType);
702 }
703
704 match gctx.types[o.ty].inner {
705 crate::TypeInner::Scalar(
706 crate::Scalar::BOOL
707 | crate::Scalar::I32
708 | crate::Scalar::U32
709 | crate::Scalar::F16
710 | crate::Scalar::F32
711 | crate::Scalar::F64,
712 ) => {}
713 _ => return Err(OverrideError::TypeNotScalar),
714 }
715
716 if let Some(init) = o.init {
717 if !gctx.compare_types(&TypeResolution::Handle(o.ty), &mod_info[init]) {
718 return Err(OverrideError::InvalidType);
719 }
720 } else if self.overrides_resolved {
721 return Err(OverrideError::UninitializedOverride);
722 }
723
724 Ok(())
725 }
726
727 pub fn validate(
729 &mut self,
730 module: &crate::Module,
731 ) -> Result<ModuleInfo, WithSpan<ValidationError>> {
732 self.overrides_resolved = false;
733 self.validate_impl(module)
734 }
735
736 pub fn validate_resolved_overrides(
744 &mut self,
745 module: &crate::Module,
746 ) -> Result<ModuleInfo, WithSpan<ValidationError>> {
747 self.overrides_resolved = true;
748 self.validate_impl(module)
749 }
750
751 fn validate_impl(
752 &mut self,
753 module: &crate::Module,
754 ) -> Result<ModuleInfo, WithSpan<ValidationError>> {
755 self.reset();
756 self.reset_types(module.types.len());
757
758 Self::validate_module_handles(module).map_err(|e| e.with_span())?;
759
760 self.layouter.update(module.to_ctx()).map_err(|e| {
761 let handle = e.ty;
762 ValidationError::from(e).with_span_handle(handle, &module.types)
763 })?;
764
765 let placeholder = TypeResolution::Value(crate::TypeInner::Scalar(crate::Scalar {
767 kind: crate::ScalarKind::Bool,
768 width: 0,
769 }));
770
771 let mut mod_info = ModuleInfo {
772 type_flags: Vec::with_capacity(module.types.len()),
773 functions: Vec::with_capacity(module.functions.len()),
774 entry_points: Vec::with_capacity(module.entry_points.len()),
775 const_expression_types: vec![placeholder; module.global_expressions.len()]
776 .into_boxed_slice(),
777 };
778
779 for (handle, ty) in module.types.iter() {
780 let ty_info = self
781 .validate_type(handle, module.to_ctx())
782 .map_err(|source| {
783 ValidationError::Type {
784 handle,
785 name: ty.name.clone().unwrap_or_default(),
786 source,
787 }
788 .with_span_handle(handle, &module.types)
789 })?;
790 debug_assert!(
791 ty_info.flags.contains(TypeFlags::CONSTRUCTIBLE)
792 == module.types[handle].inner.is_constructible(&module.types)
793 );
794 mod_info.type_flags.push(ty_info.flags);
795 self.types[handle.index()] = ty_info;
796 }
797
798 {
799 let t = crate::Arena::new();
800 let resolve_context = crate::proc::ResolveContext::with_locals(module, &t, &[]);
801 for (handle, _) in module.global_expressions.iter() {
802 mod_info
803 .process_const_expression(handle, &resolve_context, module.to_ctx())
804 .map_err(|source| {
805 ValidationError::ConstExpression { handle, source }
806 .with_span_handle(handle, &module.global_expressions)
807 })?
808 }
809 }
810
811 let global_expr_kind = ExpressionKindTracker::from_arena(&module.global_expressions);
812
813 if self.flags.contains(ValidationFlags::CONSTANTS) {
814 for (handle, _) in module.global_expressions.iter() {
815 self.validate_const_expression(
816 handle,
817 module.to_ctx(),
818 &mod_info,
819 &global_expr_kind,
820 )
821 .map_err(|source| {
822 ValidationError::ConstExpression { handle, source }
823 .with_span_handle(handle, &module.global_expressions)
824 })?
825 }
826
827 for (handle, constant) in module.constants.iter() {
828 self.validate_constant(handle, module.to_ctx(), &mod_info, &global_expr_kind)
829 .map_err(|source| {
830 ValidationError::Constant {
831 handle,
832 name: constant.name.clone().unwrap_or_default(),
833 source,
834 }
835 .with_span_handle(handle, &module.constants)
836 })?
837 }
838
839 for (handle, r#override) in module.overrides.iter() {
840 self.validate_override(handle, module.to_ctx(), &mod_info)
841 .map_err(|source| {
842 ValidationError::Override {
843 handle,
844 name: r#override.name.clone().unwrap_or_default(),
845 source,
846 }
847 .with_span_handle(handle, &module.overrides)
848 })?;
849 }
850 }
851
852 for (var_handle, var) in module.global_variables.iter() {
853 self.validate_global_var(var, module.to_ctx(), &mod_info, &global_expr_kind)
854 .map_err(|source| {
855 ValidationError::GlobalVariable {
856 handle: var_handle,
857 name: var.name.clone().unwrap_or_default(),
858 source,
859 }
860 .with_span_handle(var_handle, &module.global_variables)
861 })?;
862 }
863
864 for (handle, fun) in module.functions.iter() {
865 match self.validate_function(fun, module, &mod_info, false) {
866 Ok(info) => mod_info.functions.push(info),
867 Err(error) => {
868 return Err(error.and_then(|source| {
869 ValidationError::Function {
870 handle,
871 name: fun.name.clone().unwrap_or_default(),
872 source,
873 }
874 .with_span_handle(handle, &module.functions)
875 }))
876 }
877 }
878 }
879
880 let mut ep_map = FastHashSet::default();
881 for ep in module.entry_points.iter() {
882 if !ep_map.insert((ep.stage, &ep.name)) {
883 return Err(ValidationError::EntryPoint {
884 stage: ep.stage,
885 name: ep.name.clone(),
886 source: EntryPointError::Conflict,
887 }
888 .with_span()); }
890
891 match self.validate_entry_point(ep, module, &mod_info) {
892 Ok(info) => mod_info.entry_points.push(info),
893 Err(error) => {
894 return Err(error.and_then(|source| {
895 ValidationError::EntryPoint {
896 stage: ep.stage,
897 name: ep.name.clone(),
898 source,
899 }
900 .with_span()
901 }));
902 }
903 }
904 }
905
906 Ok(mod_info)
907 }
908}
909
910fn validate_atomic_compare_exchange_struct(
911 types: &crate::UniqueArena<crate::Type>,
912 members: &[crate::StructMember],
913 scalar_predicate: impl FnOnce(&crate::TypeInner) -> bool,
914) -> bool {
915 members.len() == 2
916 && members[0].name.as_deref() == Some("old_value")
917 && scalar_predicate(&types[members[0].ty].inner)
918 && members[1].name.as_deref() == Some("exchanged")
919 && types[members[1].ty].inner == crate::TypeInner::Scalar(crate::Scalar::BOOL)
920}