1use core::{convert::TryInto, hash::Hash};
4
5use super::ValidationError;
6use crate::non_max_u32::NonMaxU32;
7use crate::{
8 arena::{BadHandle, BadRangeError},
9 diagnostic_filter::DiagnosticFilterNode,
10 Handle,
11};
12use crate::{Arena, UniqueArena};
13
14#[cfg(test)]
15use alloc::string::ToString;
16
17impl super::Validator {
18 pub(super) fn validate_module_handles(module: &crate::Module) -> Result<(), ValidationError> {
35 let &crate::Module {
36 ref constants,
37 ref overrides,
38 ref entry_points,
39 ref functions,
40 ref global_variables,
41 ref types,
42 ref special_types,
43 ref global_expressions,
44 ref diagnostic_filters,
45 ref diagnostic_filter_leaf,
46 } = module;
47
48 let mut global_exprs_iter = global_expressions.iter().peekable();
60 for (th, t) in types.iter() {
61 if let Some(max_expr) = Self::validate_type_handles((th, t), overrides)? {
97 max_expr.check_valid_for(global_expressions)?;
98 while let Some((eh, e)) = global_exprs_iter.next_if(|&(eh, _)| eh <= max_expr) {
102 if let Some(max_type) =
103 Self::validate_const_expression_handles((eh, e), constants, overrides)?
104 {
105 th.check_dep(max_type)?;
107 }
108 }
114 }
115
116 }
122
123 for handle_and_expr in global_exprs_iter {
130 Self::validate_const_expression_handles(handle_and_expr, constants, overrides)?;
131 }
132
133 let validate_type = |handle| Self::validate_type_handle(handle, types);
134 let validate_const_expr =
135 |handle| Self::validate_expression_handle(handle, global_expressions);
136
137 for (_handle, constant) in constants.iter() {
138 let &crate::Constant { name: _, ty, init } = constant;
139 validate_type(ty)?;
140 validate_const_expr(init)?;
141 }
142
143 for (_handle, r#override) in overrides.iter() {
144 let &crate::Override {
145 name: _,
146 id: _,
147 ty,
148 init,
149 } = r#override;
150 validate_type(ty)?;
151 if let Some(init_expr) = init {
152 validate_const_expr(init_expr)?;
153 }
154 }
155
156 for (_handle, global_variable) in global_variables.iter() {
157 let &crate::GlobalVariable {
158 name: _,
159 space: _,
160 binding: _,
161 ty,
162 init,
163 } = global_variable;
164 validate_type(ty)?;
165 if let Some(init_expr) = init {
166 validate_const_expr(init_expr)?;
167 }
168 }
169
170 let validate_function = |function_handle, function: &_| -> Result<_, InvalidHandleError> {
171 let &crate::Function {
172 name: _,
173 ref arguments,
174 ref result,
175 ref local_variables,
176 ref expressions,
177 ref named_expressions,
178 ref body,
179 ref diagnostic_filter_leaf,
180 } = function;
181
182 for arg in arguments.iter() {
183 let &crate::FunctionArgument {
184 name: _,
185 ty,
186 binding: _,
187 } = arg;
188 validate_type(ty)?;
189 }
190
191 if let &Some(crate::FunctionResult { ty, binding: _ }) = result {
192 validate_type(ty)?;
193 }
194
195 for (_handle, local_variable) in local_variables.iter() {
196 let &crate::LocalVariable { name: _, ty, init } = local_variable;
197 validate_type(ty)?;
198 if let Some(init) = init {
199 Self::validate_expression_handle(init, expressions)?;
200 }
201 }
202
203 for handle in named_expressions.keys().copied() {
204 Self::validate_expression_handle(handle, expressions)?;
205 }
206
207 for handle_and_expr in expressions.iter() {
208 Self::validate_expression_handles(
209 handle_and_expr,
210 constants,
211 overrides,
212 types,
213 local_variables,
214 global_variables,
215 functions,
216 function_handle,
217 )?;
218 }
219
220 Self::validate_block_handles(body, expressions, functions)?;
221
222 if let Some(handle) = *diagnostic_filter_leaf {
223 handle.check_valid_for(diagnostic_filters)?;
224 }
225
226 Ok(())
227 };
228
229 for entry_point in entry_points.iter() {
230 validate_function(None, &entry_point.function)?;
231 if let Some(sizes) = entry_point.workgroup_size_overrides {
232 for size in sizes.iter().filter_map(|x| *x) {
233 validate_const_expr(size)?;
234 }
235 }
236 }
237
238 for (function_handle, function) in functions.iter() {
239 validate_function(Some(function_handle), function)?;
240 }
241
242 if let Some(ty) = special_types.ray_desc {
243 validate_type(ty)?;
244 }
245 if let Some(ty) = special_types.ray_intersection {
246 validate_type(ty)?;
247 }
248 if let Some(ty) = special_types.ray_vertex_return {
249 validate_type(ty)?;
250 }
251
252 for (handle, _node) in diagnostic_filters.iter() {
253 let DiagnosticFilterNode { inner: _, parent } = diagnostic_filters[handle];
254 handle.check_dep_opt(parent)?;
255 }
256 if let Some(handle) = *diagnostic_filter_leaf {
257 handle.check_valid_for(diagnostic_filters)?;
258 }
259
260 Ok(())
261 }
262
263 fn validate_type_handle(
264 handle: Handle<crate::Type>,
265 types: &UniqueArena<crate::Type>,
266 ) -> Result<(), InvalidHandleError> {
267 handle.check_valid_for_uniq(types).map(|_| ())
268 }
269
270 fn validate_constant_handle(
271 handle: Handle<crate::Constant>,
272 constants: &Arena<crate::Constant>,
273 ) -> Result<(), InvalidHandleError> {
274 handle.check_valid_for(constants).map(|_| ())
275 }
276
277 fn validate_override_handle(
278 handle: Handle<crate::Override>,
279 overrides: &Arena<crate::Override>,
280 ) -> Result<(), InvalidHandleError> {
281 handle.check_valid_for(overrides).map(|_| ())
282 }
283
284 fn validate_expression_handle(
285 handle: Handle<crate::Expression>,
286 expressions: &Arena<crate::Expression>,
287 ) -> Result<(), InvalidHandleError> {
288 handle.check_valid_for(expressions).map(|_| ())
289 }
290
291 fn validate_function_handle(
292 handle: Handle<crate::Function>,
293 functions: &Arena<crate::Function>,
294 ) -> Result<(), InvalidHandleError> {
295 handle.check_valid_for(functions).map(|_| ())
296 }
297
298 fn validate_type_handles(
304 (handle, ty): (Handle<crate::Type>, &crate::Type),
305 overrides: &Arena<crate::Override>,
306 ) -> Result<Option<Handle<crate::Expression>>, InvalidHandleError> {
307 let max_expr = match ty.inner {
308 crate::TypeInner::Scalar { .. }
309 | crate::TypeInner::Vector { .. }
310 | crate::TypeInner::Matrix { .. }
311 | crate::TypeInner::ValuePointer { .. }
312 | crate::TypeInner::Atomic { .. }
313 | crate::TypeInner::Image { .. }
314 | crate::TypeInner::Sampler { .. }
315 | crate::TypeInner::AccelerationStructure { .. }
316 | crate::TypeInner::RayQuery { .. } => None,
317 crate::TypeInner::Pointer { base, space: _ } => {
318 handle.check_dep(base)?;
319 None
320 }
321 crate::TypeInner::Array { base, size, .. }
322 | crate::TypeInner::BindingArray { base, size, .. } => {
323 handle.check_dep(base)?;
324 match size {
325 crate::ArraySize::Pending(h) => {
326 Self::validate_override_handle(h, overrides)?;
327 let r#override = &overrides[h];
328 handle.check_dep(r#override.ty)?;
329 r#override.init
330 }
331 crate::ArraySize::Constant(_) | crate::ArraySize::Dynamic => None,
332 }
333 }
334 crate::TypeInner::Struct {
335 ref members,
336 span: _,
337 } => {
338 handle.check_dep_iter(members.iter().map(|m| m.ty))?;
339 None
340 }
341 };
342
343 Ok(max_expr)
344 }
345
346 fn validate_const_expression_handles(
352 (handle, expression): (Handle<crate::Expression>, &crate::Expression),
353 constants: &Arena<crate::Constant>,
354 overrides: &Arena<crate::Override>,
355 ) -> Result<Option<Handle<crate::Type>>, InvalidHandleError> {
356 let validate_constant = |handle| Self::validate_constant_handle(handle, constants);
357 let validate_override = |handle| Self::validate_override_handle(handle, overrides);
358
359 let max_type = match *expression {
360 crate::Expression::Literal(_) => None,
361 crate::Expression::Constant(constant) => {
362 validate_constant(constant)?;
363 handle.check_dep(constants[constant].init)?;
364 None
365 }
366 crate::Expression::Override(r#override) => {
367 validate_override(r#override)?;
368 if let Some(init) = overrides[r#override].init {
369 handle.check_dep(init)?;
370 }
371 None
372 }
373 crate::Expression::ZeroValue(ty) => Some(ty),
374 crate::Expression::Compose { ty, ref components } => {
375 handle.check_dep_iter(components.iter().copied())?;
376 Some(ty)
377 }
378 _ => None,
379 };
380 Ok(max_type)
381 }
382
383 #[allow(clippy::too_many_arguments)]
384 fn validate_expression_handles(
385 (handle, expression): (Handle<crate::Expression>, &crate::Expression),
386 constants: &Arena<crate::Constant>,
387 overrides: &Arena<crate::Override>,
388 types: &UniqueArena<crate::Type>,
389 local_variables: &Arena<crate::LocalVariable>,
390 global_variables: &Arena<crate::GlobalVariable>,
391 functions: &Arena<crate::Function>,
392 current_function: Option<Handle<crate::Function>>,
394 ) -> Result<(), InvalidHandleError> {
395 let validate_constant = |handle| Self::validate_constant_handle(handle, constants);
396 let validate_override = |handle| Self::validate_override_handle(handle, overrides);
397 let validate_type = |handle| Self::validate_type_handle(handle, types);
398
399 match *expression {
400 crate::Expression::Access { base, index } => {
401 handle.check_dep(base)?.check_dep(index)?;
402 }
403 crate::Expression::AccessIndex { base, .. } => {
404 handle.check_dep(base)?;
405 }
406 crate::Expression::Splat { value, .. } => {
407 handle.check_dep(value)?;
408 }
409 crate::Expression::Swizzle { vector, .. } => {
410 handle.check_dep(vector)?;
411 }
412 crate::Expression::Literal(_) => {}
413 crate::Expression::Constant(constant) => {
414 validate_constant(constant)?;
415 }
416 crate::Expression::Override(r#override) => {
417 validate_override(r#override)?;
418 }
419 crate::Expression::ZeroValue(ty) => {
420 validate_type(ty)?;
421 }
422 crate::Expression::Compose { ty, ref components } => {
423 validate_type(ty)?;
424 handle.check_dep_iter(components.iter().copied())?;
425 }
426 crate::Expression::FunctionArgument(_arg_idx) => (),
427 crate::Expression::GlobalVariable(global_variable) => {
428 global_variable.check_valid_for(global_variables)?;
429 }
430 crate::Expression::LocalVariable(local_variable) => {
431 local_variable.check_valid_for(local_variables)?;
432 }
433 crate::Expression::Load { pointer } => {
434 handle.check_dep(pointer)?;
435 }
436 crate::Expression::ImageSample {
437 image,
438 sampler,
439 gather: _,
440 coordinate,
441 array_index,
442 offset,
443 level,
444 depth_ref,
445 } => {
446 handle
447 .check_dep(image)?
448 .check_dep(sampler)?
449 .check_dep(coordinate)?
450 .check_dep_opt(array_index)?
451 .check_dep_opt(offset)?;
452
453 match level {
454 crate::SampleLevel::Auto | crate::SampleLevel::Zero => (),
455 crate::SampleLevel::Exact(expr) => {
456 handle.check_dep(expr)?;
457 }
458 crate::SampleLevel::Bias(expr) => {
459 handle.check_dep(expr)?;
460 }
461 crate::SampleLevel::Gradient { x, y } => {
462 handle.check_dep(x)?.check_dep(y)?;
463 }
464 };
465
466 handle.check_dep_opt(depth_ref)?;
467 }
468 crate::Expression::ImageLoad {
469 image,
470 coordinate,
471 array_index,
472 sample,
473 level,
474 } => {
475 handle
476 .check_dep(image)?
477 .check_dep(coordinate)?
478 .check_dep_opt(array_index)?
479 .check_dep_opt(sample)?
480 .check_dep_opt(level)?;
481 }
482 crate::Expression::ImageQuery { image, query } => {
483 handle.check_dep(image)?;
484 match query {
485 crate::ImageQuery::Size { level } => {
486 handle.check_dep_opt(level)?;
487 }
488 crate::ImageQuery::NumLevels
489 | crate::ImageQuery::NumLayers
490 | crate::ImageQuery::NumSamples => (),
491 };
492 }
493 crate::Expression::Unary {
494 op: _,
495 expr: operand,
496 } => {
497 handle.check_dep(operand)?;
498 }
499 crate::Expression::Binary { op: _, left, right } => {
500 handle.check_dep(left)?.check_dep(right)?;
501 }
502 crate::Expression::Select {
503 condition,
504 accept,
505 reject,
506 } => {
507 handle
508 .check_dep(condition)?
509 .check_dep(accept)?
510 .check_dep(reject)?;
511 }
512 crate::Expression::Derivative { expr: argument, .. } => {
513 handle.check_dep(argument)?;
514 }
515 crate::Expression::Relational { fun: _, argument } => {
516 handle.check_dep(argument)?;
517 }
518 crate::Expression::Math {
519 fun: _,
520 arg,
521 arg1,
522 arg2,
523 arg3,
524 } => {
525 handle
526 .check_dep(arg)?
527 .check_dep_opt(arg1)?
528 .check_dep_opt(arg2)?
529 .check_dep_opt(arg3)?;
530 }
531 crate::Expression::As {
532 expr: input,
533 kind: _,
534 convert: _,
535 } => {
536 handle.check_dep(input)?;
537 }
538 crate::Expression::CallResult(function) => {
539 Self::validate_function_handle(function, functions)?;
540 if let Some(handle) = current_function {
541 handle.check_dep(function)?;
542 }
543 }
544 crate::Expression::AtomicResult { .. }
545 | crate::Expression::RayQueryProceedResult
546 | crate::Expression::SubgroupBallotResult
547 | crate::Expression::SubgroupOperationResult { .. }
548 | crate::Expression::WorkGroupUniformLoadResult { .. } => (),
549 crate::Expression::ArrayLength(array) => {
550 handle.check_dep(array)?;
551 }
552 crate::Expression::RayQueryGetIntersection {
553 query,
554 committed: _,
555 }
556 | crate::Expression::RayQueryVertexPositions {
557 query,
558 committed: _,
559 } => {
560 handle.check_dep(query)?;
561 }
562 }
563 Ok(())
564 }
565
566 fn validate_block_handles(
567 block: &crate::Block,
568 expressions: &Arena<crate::Expression>,
569 functions: &Arena<crate::Function>,
570 ) -> Result<(), InvalidHandleError> {
571 let validate_block = |block| Self::validate_block_handles(block, expressions, functions);
572 let validate_expr = |handle| Self::validate_expression_handle(handle, expressions);
573 let validate_expr_opt = |handle_opt| {
574 if let Some(handle) = handle_opt {
575 validate_expr(handle)?;
576 }
577 Ok(())
578 };
579
580 block.iter().try_for_each(|stmt| match *stmt {
581 crate::Statement::Emit(ref expr_range) => {
582 expr_range.check_valid_for(expressions)?;
583 Ok(())
584 }
585 crate::Statement::Block(ref block) => {
586 validate_block(block)?;
587 Ok(())
588 }
589 crate::Statement::If {
590 condition,
591 ref accept,
592 ref reject,
593 } => {
594 validate_expr(condition)?;
595 validate_block(accept)?;
596 validate_block(reject)?;
597 Ok(())
598 }
599 crate::Statement::Switch {
600 selector,
601 ref cases,
602 } => {
603 validate_expr(selector)?;
604 for &crate::SwitchCase {
605 value: _,
606 ref body,
607 fall_through: _,
608 } in cases
609 {
610 validate_block(body)?;
611 }
612 Ok(())
613 }
614 crate::Statement::Loop {
615 ref body,
616 ref continuing,
617 break_if,
618 } => {
619 validate_block(body)?;
620 validate_block(continuing)?;
621 validate_expr_opt(break_if)?;
622 Ok(())
623 }
624 crate::Statement::Return { value } => validate_expr_opt(value),
625 crate::Statement::Store { pointer, value } => {
626 validate_expr(pointer)?;
627 validate_expr(value)?;
628 Ok(())
629 }
630 crate::Statement::ImageStore {
631 image,
632 coordinate,
633 array_index,
634 value,
635 } => {
636 validate_expr(image)?;
637 validate_expr(coordinate)?;
638 validate_expr_opt(array_index)?;
639 validate_expr(value)?;
640 Ok(())
641 }
642 crate::Statement::Atomic {
643 pointer,
644 fun,
645 value,
646 result,
647 } => {
648 validate_expr(pointer)?;
649 match fun {
650 crate::AtomicFunction::Add
651 | crate::AtomicFunction::Subtract
652 | crate::AtomicFunction::And
653 | crate::AtomicFunction::ExclusiveOr
654 | crate::AtomicFunction::InclusiveOr
655 | crate::AtomicFunction::Min
656 | crate::AtomicFunction::Max => (),
657 crate::AtomicFunction::Exchange { compare } => validate_expr_opt(compare)?,
658 };
659 validate_expr(value)?;
660 if let Some(result) = result {
661 validate_expr(result)?;
662 }
663 Ok(())
664 }
665 crate::Statement::ImageAtomic {
666 image,
667 coordinate,
668 array_index,
669 fun: _,
670 value,
671 } => {
672 validate_expr(image)?;
673 validate_expr(coordinate)?;
674 validate_expr_opt(array_index)?;
675 validate_expr(value)?;
676 Ok(())
677 }
678 crate::Statement::WorkGroupUniformLoad { pointer, result } => {
679 validate_expr(pointer)?;
680 validate_expr(result)?;
681 Ok(())
682 }
683 crate::Statement::Call {
684 function,
685 ref arguments,
686 result,
687 } => {
688 Self::validate_function_handle(function, functions)?;
689 for arg in arguments.iter().copied() {
690 validate_expr(arg)?;
691 }
692 validate_expr_opt(result)?;
693 Ok(())
694 }
695 crate::Statement::RayQuery { query, ref fun } => {
696 validate_expr(query)?;
697 match *fun {
698 crate::RayQueryFunction::Initialize {
699 acceleration_structure,
700 descriptor,
701 } => {
702 validate_expr(acceleration_structure)?;
703 validate_expr(descriptor)?;
704 }
705 crate::RayQueryFunction::Proceed { result } => {
706 validate_expr(result)?;
707 }
708 crate::RayQueryFunction::GenerateIntersection { hit_t } => {
709 validate_expr(hit_t)?;
710 }
711 crate::RayQueryFunction::ConfirmIntersection => {}
712 crate::RayQueryFunction::Terminate => {}
713 }
714 Ok(())
715 }
716 crate::Statement::SubgroupBallot { result, predicate } => {
717 validate_expr_opt(predicate)?;
718 validate_expr(result)?;
719 Ok(())
720 }
721 crate::Statement::SubgroupCollectiveOperation {
722 op: _,
723 collective_op: _,
724 argument,
725 result,
726 } => {
727 validate_expr(argument)?;
728 validate_expr(result)?;
729 Ok(())
730 }
731 crate::Statement::SubgroupGather {
732 mode,
733 argument,
734 result,
735 } => {
736 validate_expr(argument)?;
737 match mode {
738 crate::GatherMode::BroadcastFirst => {}
739 crate::GatherMode::Broadcast(index)
740 | crate::GatherMode::Shuffle(index)
741 | crate::GatherMode::ShuffleDown(index)
742 | crate::GatherMode::ShuffleUp(index)
743 | crate::GatherMode::ShuffleXor(index) => validate_expr(index)?,
744 }
745 validate_expr(result)?;
746 Ok(())
747 }
748 crate::Statement::Break
749 | crate::Statement::Continue
750 | crate::Statement::Kill
751 | crate::Statement::Barrier(_) => Ok(()),
752 })
753 }
754}
755
756impl From<BadHandle> for ValidationError {
757 fn from(source: BadHandle) -> Self {
758 Self::InvalidHandle(source.into())
759 }
760}
761
762impl From<FwdDepError> for ValidationError {
763 fn from(source: FwdDepError) -> Self {
764 Self::InvalidHandle(source.into())
765 }
766}
767
768impl From<BadRangeError> for ValidationError {
769 fn from(source: BadRangeError) -> Self {
770 Self::InvalidHandle(source.into())
771 }
772}
773
774#[derive(Clone, Debug, thiserror::Error)]
775#[cfg_attr(test, derive(PartialEq))]
776pub enum InvalidHandleError {
777 #[error(transparent)]
778 BadHandle(#[from] BadHandle),
779 #[error(transparent)]
780 ForwardDependency(#[from] FwdDepError),
781 #[error(transparent)]
782 BadRange(#[from] BadRangeError),
783}
784
785#[derive(Clone, Debug, thiserror::Error)]
786#[cfg_attr(test, derive(PartialEq))]
787#[error(
788 "{subject:?} of kind {subject_kind:?} depends on {depends_on:?} of kind {depends_on_kind}, \
789 which has not been processed yet"
790)]
791pub struct FwdDepError {
792 subject: Handle<()>,
795 subject_kind: &'static str,
796 depends_on: Handle<()>,
797 depends_on_kind: &'static str,
798}
799
800impl<T> Handle<T> {
801 pub(self) fn check_valid_for(self, arena: &Arena<T>) -> Result<(), InvalidHandleError> {
803 arena.check_contains_handle(self)?;
804 Ok(())
805 }
806
807 pub(self) fn check_valid_for_uniq(
809 self,
810 arena: &UniqueArena<T>,
811 ) -> Result<(), InvalidHandleError>
812 where
813 T: Eq + Hash,
814 {
815 arena.check_contains_handle(self)?;
816 Ok(())
817 }
818
819 pub(self) fn check_dep(self, depends_on: Self) -> Result<Self, FwdDepError> {
831 if depends_on < self {
832 Ok(self)
833 } else {
834 let erase_handle_type = |handle: Handle<_>| {
835 Handle::new(NonMaxU32::new((handle.index()).try_into().unwrap()).unwrap())
836 };
837 Err(FwdDepError {
838 subject: erase_handle_type(self),
839 subject_kind: core::any::type_name::<T>(),
840 depends_on: erase_handle_type(depends_on),
841 depends_on_kind: core::any::type_name::<T>(),
842 })
843 }
844 }
845
846 pub(self) fn check_dep_opt(self, depends_on: Option<Self>) -> Result<Self, FwdDepError> {
848 self.check_dep_iter(depends_on.into_iter())
849 }
850
851 pub(self) fn check_dep_iter(
853 self,
854 depends_on: impl Iterator<Item = Self>,
855 ) -> Result<Self, FwdDepError> {
856 for handle in depends_on {
857 self.check_dep(handle)?;
858 }
859 Ok(self)
860 }
861}
862
863impl<T> crate::arena::Range<T> {
864 pub(self) fn check_valid_for(&self, arena: &Arena<T>) -> Result<(), BadRangeError> {
865 arena.check_contains_range(self)
866 }
867}
868
869#[test]
870fn constant_deps() {
871 use crate::{Constant, Expression, Literal, Span, Type, TypeInner};
872
873 let nowhere = Span::default();
874
875 let mut types = UniqueArena::new();
876 let mut const_exprs = Arena::new();
877 let mut fun_exprs = Arena::new();
878 let mut constants = Arena::new();
879 let overrides = Arena::new();
880
881 let i32_handle = types.insert(
882 Type {
883 name: None,
884 inner: TypeInner::Scalar(crate::Scalar::I32),
885 },
886 nowhere,
887 );
888
889 let fun_expr = fun_exprs.append(Expression::Literal(Literal::I32(42)), nowhere);
892 let self_referential_const = constants.append(
893 Constant {
894 name: None,
895 ty: i32_handle,
896 init: fun_expr,
897 },
898 nowhere,
899 );
900 let _self_referential_expr =
901 const_exprs.append(Expression::Constant(self_referential_const), nowhere);
902
903 for handle_and_expr in const_exprs.iter() {
904 assert!(super::Validator::validate_const_expression_handles(
905 handle_and_expr,
906 &constants,
907 &overrides,
908 )
909 .is_err());
910 }
911}
912
913#[test]
914fn array_size_deps() {
915 use super::Validator;
916 use crate::{ArraySize, Expression, Override, Scalar, Span, Type, TypeInner};
917
918 let nowhere = Span::default();
919
920 let mut m = crate::Module::default();
921
922 let ty_u32 = m.types.insert(
923 Type {
924 name: Some("u32".to_string()),
925 inner: TypeInner::Scalar(Scalar::U32),
926 },
927 nowhere,
928 );
929 let ex_zero = m
930 .global_expressions
931 .append(Expression::ZeroValue(ty_u32), nowhere);
932 let ty_handle = m.overrides.append(
933 Override {
934 name: None,
935 id: None,
936 ty: ty_u32,
937 init: Some(ex_zero),
938 },
939 nowhere,
940 );
941 let ty_arr = m.types.insert(
942 Type {
943 name: Some("bad_array".to_string()),
944 inner: TypeInner::Array {
945 base: ty_u32,
946 size: ArraySize::Pending(ty_handle),
947 stride: 4,
948 },
949 },
950 nowhere,
951 );
952
953 assert!(Validator::validate_module_handles(&m).is_ok());
955
956 m.global_expressions[ex_zero] = Expression::ZeroValue(ty_arr);
959 assert!(Validator::validate_module_handles(&m).is_err());
960}
961
962#[test]
963fn array_size_override() {
964 use super::Validator;
965 use crate::{ArraySize, Override, Scalar, Span, Type, TypeInner};
966
967 let nowhere = Span::default();
968
969 let mut m = crate::Module::default();
970
971 let ty_u32 = m.types.insert(
972 Type {
973 name: Some("u32".to_string()),
974 inner: TypeInner::Scalar(Scalar::U32),
975 },
976 nowhere,
977 );
978
979 let bad_override: Handle<Override> = Handle::new(NonMaxU32::new(1000).unwrap());
980 let _ty_arr = m.types.insert(
981 Type {
982 name: Some("bad_array".to_string()),
983 inner: TypeInner::Array {
984 base: ty_u32,
985 size: ArraySize::Pending(bad_override),
986 stride: 4,
987 },
988 },
989 nowhere,
990 );
991
992 assert!(Validator::validate_module_handles(&m).is_err());
993}
994
995#[test]
996fn override_init_deps() {
997 use super::Validator;
998 use crate::{ArraySize, Expression, Override, Scalar, Span, Type, TypeInner};
999
1000 let nowhere = Span::default();
1001
1002 let mut m = crate::Module::default();
1003
1004 let ty_u32 = m.types.insert(
1005 Type {
1006 name: Some("u32".to_string()),
1007 inner: TypeInner::Scalar(Scalar::U32),
1008 },
1009 nowhere,
1010 );
1011 let ex_zero = m
1012 .global_expressions
1013 .append(Expression::ZeroValue(ty_u32), nowhere);
1014 let r#override = m.overrides.append(
1015 Override {
1016 name: Some("bad_override".into()),
1017 id: None,
1018 ty: ty_u32,
1019 init: Some(ex_zero),
1020 },
1021 nowhere,
1022 );
1023 let ty_arr = m.types.insert(
1024 Type {
1025 name: Some("bad_array".to_string()),
1026 inner: TypeInner::Array {
1027 base: ty_u32,
1028 size: ArraySize::Pending(r#override),
1029 stride: 4,
1030 },
1031 },
1032 nowhere,
1033 );
1034 let ex_arr = m
1035 .global_expressions
1036 .append(Expression::ZeroValue(ty_arr), nowhere);
1037
1038 assert!(Validator::validate_module_handles(&m).is_ok());
1039
1040 m.overrides[r#override].init = Some(ex_arr);
1043 assert!(Validator::validate_module_handles(&m).is_err());
1044}