1use core::{convert::TryInto, hash::Hash};
4
5use super::{TypeError, ValidationError};
6use crate::non_max_u32::NonMaxU32;
7use crate::{
8 arena::{BadHandle, BadRangeError},
9 diagnostic_filter::DiagnosticFilterNode,
10 EntryPoint, Handle,
11};
12use crate::{Arena, UniqueArena};
13
14use alloc::string::ToString;
15
16impl super::Validator {
17 pub(super) fn validate_module_handles(module: &crate::Module) -> Result<(), ValidationError> {
34 let &crate::Module {
35 ref constants,
36 ref overrides,
37 ref entry_points,
38 ref functions,
39 ref global_variables,
40 ref types,
41 ref special_types,
42 ref global_expressions,
43 ref diagnostic_filters,
44 ref diagnostic_filter_leaf,
45 ref doc_comments,
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 if let Some(task_payload) = entry_point.task_payload {
237 Self::validate_global_variable_handle(task_payload, global_variables)?;
238 }
239 if let Some(ref mesh_info) = entry_point.mesh_info {
240 Self::validate_global_variable_handle(mesh_info.output_variable, global_variables)?;
241 validate_type(mesh_info.vertex_output_type)?;
242 validate_type(mesh_info.primitive_output_type)?;
243 for ov in mesh_info
244 .max_vertices_override
245 .iter()
246 .chain(mesh_info.max_primitives_override.iter())
247 {
248 validate_const_expr(*ov)?;
249 }
250 }
251 }
252
253 for (function_handle, function) in functions.iter() {
254 validate_function(Some(function_handle), function)?;
255 }
256
257 if let Some(ty) = special_types.ray_desc {
258 validate_type(ty)?;
259 }
260 if let Some(ty) = special_types.ray_intersection {
261 validate_type(ty)?;
262 }
263 if let Some(ty) = special_types.ray_vertex_return {
264 validate_type(ty)?;
265 }
266
267 for (handle, _node) in diagnostic_filters.iter() {
268 let DiagnosticFilterNode { inner: _, parent } = diagnostic_filters[handle];
269 handle.check_dep_opt(parent)?;
270 }
271 if let Some(handle) = *diagnostic_filter_leaf {
272 handle.check_valid_for(diagnostic_filters)?;
273 }
274
275 if let Some(doc_comments) = doc_comments.as_ref() {
276 let crate::DocComments {
277 module: _,
278 types: ref doc_comments_for_types,
279 struct_members: ref doc_comments_for_struct_members,
280 entry_points: ref doc_comments_for_entry_points,
281 functions: ref doc_comments_for_functions,
282 constants: ref doc_comments_for_constants,
283 global_variables: ref doc_comments_for_global_variables,
284 } = **doc_comments;
285
286 for (&ty, _) in doc_comments_for_types.iter() {
287 validate_type(ty)?;
288 }
289
290 for (&(ty, struct_member_index), _) in doc_comments_for_struct_members.iter() {
291 validate_type(ty)?;
292 let struct_type = types.get_handle(ty).unwrap();
293 match struct_type.inner {
294 crate::TypeInner::Struct {
295 ref members,
296 span: ref _span,
297 } => {
298 (0..members.len())
299 .contains(&struct_member_index)
300 .then_some(())
301 .ok_or_else(|| ValidationError::Type {
303 handle: ty,
304 name: struct_type.name.as_ref().map_or_else(
305 || "members length incorrect".to_string(),
306 |name| name.to_string(),
307 ),
308 source: TypeError::InvalidData(ty),
309 })?;
310 }
311 _ => {
312 return Err(ValidationError::Type {
315 handle: ty,
316 name: struct_type
317 .name
318 .as_ref()
319 .map_or_else(|| "Unknown".to_string(), |name| name.to_string()),
320 source: TypeError::InvalidData(ty),
321 });
322 }
323 }
324 for (&function, _) in doc_comments_for_functions.iter() {
325 Self::validate_function_handle(function, functions)?;
326 }
327 for (&entry_point_index, _) in doc_comments_for_entry_points.iter() {
328 Self::validate_entry_point_index(entry_point_index, entry_points)?;
329 }
330 for (&constant, _) in doc_comments_for_constants.iter() {
331 Self::validate_constant_handle(constant, constants)?;
332 }
333 for (&global_variable, _) in doc_comments_for_global_variables.iter() {
334 Self::validate_global_variable_handle(global_variable, global_variables)?;
335 }
336 }
337 }
338
339 Ok(())
340 }
341
342 fn validate_type_handle(
343 handle: Handle<crate::Type>,
344 types: &UniqueArena<crate::Type>,
345 ) -> Result<(), InvalidHandleError> {
346 handle.check_valid_for_uniq(types).map(|_| ())
347 }
348
349 fn validate_constant_handle(
350 handle: Handle<crate::Constant>,
351 constants: &Arena<crate::Constant>,
352 ) -> Result<(), InvalidHandleError> {
353 handle.check_valid_for(constants).map(|_| ())
354 }
355
356 fn validate_global_variable_handle(
357 handle: Handle<crate::GlobalVariable>,
358 global_variables: &Arena<crate::GlobalVariable>,
359 ) -> Result<(), InvalidHandleError> {
360 handle.check_valid_for(global_variables).map(|_| ())
361 }
362
363 fn validate_override_handle(
364 handle: Handle<crate::Override>,
365 overrides: &Arena<crate::Override>,
366 ) -> Result<(), InvalidHandleError> {
367 handle.check_valid_for(overrides).map(|_| ())
368 }
369
370 fn validate_expression_handle(
371 handle: Handle<crate::Expression>,
372 expressions: &Arena<crate::Expression>,
373 ) -> Result<(), InvalidHandleError> {
374 handle.check_valid_for(expressions).map(|_| ())
375 }
376
377 fn validate_function_handle(
378 handle: Handle<crate::Function>,
379 functions: &Arena<crate::Function>,
380 ) -> Result<(), InvalidHandleError> {
381 handle.check_valid_for(functions).map(|_| ())
382 }
383
384 fn validate_type_handles(
390 (handle, ty): (Handle<crate::Type>, &crate::Type),
391 overrides: &Arena<crate::Override>,
392 ) -> Result<Option<Handle<crate::Expression>>, InvalidHandleError> {
393 let max_expr = match ty.inner {
394 crate::TypeInner::Scalar { .. }
395 | crate::TypeInner::Vector { .. }
396 | crate::TypeInner::Matrix { .. }
397 | crate::TypeInner::CooperativeMatrix { .. }
398 | crate::TypeInner::ValuePointer { .. }
399 | crate::TypeInner::Atomic { .. }
400 | crate::TypeInner::Image { .. }
401 | crate::TypeInner::Sampler { .. }
402 | crate::TypeInner::AccelerationStructure { .. }
403 | crate::TypeInner::RayQuery { .. } => None,
404 crate::TypeInner::Pointer { base, space: _ } => {
405 handle.check_dep(base)?;
406 None
407 }
408 crate::TypeInner::Array { base, size, .. }
409 | crate::TypeInner::BindingArray { base, size, .. } => {
410 handle.check_dep(base)?;
411 match size {
412 crate::ArraySize::Pending(h) => {
413 Self::validate_override_handle(h, overrides)?;
414 let r#override = &overrides[h];
415 handle.check_dep(r#override.ty)?;
416 r#override.init
417 }
418 crate::ArraySize::Constant(_) | crate::ArraySize::Dynamic => None,
419 }
420 }
421 crate::TypeInner::Struct {
422 ref members,
423 span: _,
424 } => {
425 handle.check_dep_iter(members.iter().map(|m| m.ty))?;
426 None
427 }
428 };
429
430 Ok(max_expr)
431 }
432
433 fn validate_entry_point_index(
434 entry_point_index: usize,
435 entry_points: &[EntryPoint],
436 ) -> Result<(), InvalidHandleError> {
437 (0..entry_points.len())
438 .contains(&entry_point_index)
439 .then_some(())
440 .ok_or_else(|| {
441 BadHandle {
442 kind: "EntryPoint",
443 index: entry_point_index,
444 }
445 .into()
446 })
447 }
448
449 fn validate_const_expression_handles(
455 (handle, expression): (Handle<crate::Expression>, &crate::Expression),
456 constants: &Arena<crate::Constant>,
457 overrides: &Arena<crate::Override>,
458 ) -> Result<Option<Handle<crate::Type>>, InvalidHandleError> {
459 let validate_constant = |handle| Self::validate_constant_handle(handle, constants);
460 let validate_override = |handle| Self::validate_override_handle(handle, overrides);
461
462 let max_type = match *expression {
463 crate::Expression::Literal(_) => None,
464 crate::Expression::Constant(constant) => {
465 validate_constant(constant)?;
466 handle.check_dep(constants[constant].init)?;
467 None
468 }
469 crate::Expression::Override(r#override) => {
470 validate_override(r#override)?;
471 if let Some(init) = overrides[r#override].init {
472 handle.check_dep(init)?;
473 }
474 None
475 }
476 crate::Expression::ZeroValue(ty) => Some(ty),
477 crate::Expression::Compose { ty, ref components } => {
478 handle.check_dep_iter(components.iter().copied())?;
479 Some(ty)
480 }
481 _ => None,
482 };
483 Ok(max_type)
484 }
485
486 #[allow(clippy::too_many_arguments)]
487 fn validate_expression_handles(
488 (handle, expression): (Handle<crate::Expression>, &crate::Expression),
489 constants: &Arena<crate::Constant>,
490 overrides: &Arena<crate::Override>,
491 types: &UniqueArena<crate::Type>,
492 local_variables: &Arena<crate::LocalVariable>,
493 global_variables: &Arena<crate::GlobalVariable>,
494 functions: &Arena<crate::Function>,
495 current_function: Option<Handle<crate::Function>>,
497 ) -> Result<(), InvalidHandleError> {
498 let validate_constant = |handle| Self::validate_constant_handle(handle, constants);
499 let validate_override = |handle| Self::validate_override_handle(handle, overrides);
500 let validate_type = |handle| Self::validate_type_handle(handle, types);
501
502 match *expression {
503 crate::Expression::Access { base, index } => {
504 handle.check_dep(base)?.check_dep(index)?;
505 }
506 crate::Expression::AccessIndex { base, .. } => {
507 handle.check_dep(base)?;
508 }
509 crate::Expression::Splat { value, .. } => {
510 handle.check_dep(value)?;
511 }
512 crate::Expression::Swizzle { vector, .. } => {
513 handle.check_dep(vector)?;
514 }
515 crate::Expression::Literal(_) => {}
516 crate::Expression::Constant(constant) => {
517 validate_constant(constant)?;
518 }
519 crate::Expression::Override(r#override) => {
520 validate_override(r#override)?;
521 }
522 crate::Expression::ZeroValue(ty) => {
523 validate_type(ty)?;
524 }
525 crate::Expression::Compose { ty, ref components } => {
526 validate_type(ty)?;
527 handle.check_dep_iter(components.iter().copied())?;
528 }
529 crate::Expression::FunctionArgument(_arg_idx) => (),
530 crate::Expression::GlobalVariable(global_variable) => {
531 global_variable.check_valid_for(global_variables)?;
532 }
533 crate::Expression::LocalVariable(local_variable) => {
534 local_variable.check_valid_for(local_variables)?;
535 }
536 crate::Expression::Load { pointer } => {
537 handle.check_dep(pointer)?;
538 }
539 crate::Expression::ImageSample {
540 image,
541 sampler,
542 gather: _,
543 coordinate,
544 array_index,
545 offset,
546 level,
547 depth_ref,
548 clamp_to_edge: _,
549 } => {
550 handle
551 .check_dep(image)?
552 .check_dep(sampler)?
553 .check_dep(coordinate)?
554 .check_dep_opt(array_index)?
555 .check_dep_opt(offset)?;
556
557 match level {
558 crate::SampleLevel::Auto | crate::SampleLevel::Zero => (),
559 crate::SampleLevel::Exact(expr) => {
560 handle.check_dep(expr)?;
561 }
562 crate::SampleLevel::Bias(expr) => {
563 handle.check_dep(expr)?;
564 }
565 crate::SampleLevel::Gradient { x, y } => {
566 handle.check_dep(x)?.check_dep(y)?;
567 }
568 };
569
570 handle.check_dep_opt(depth_ref)?;
571 }
572 crate::Expression::ImageLoad {
573 image,
574 coordinate,
575 array_index,
576 sample,
577 level,
578 } => {
579 handle
580 .check_dep(image)?
581 .check_dep(coordinate)?
582 .check_dep_opt(array_index)?
583 .check_dep_opt(sample)?
584 .check_dep_opt(level)?;
585 }
586 crate::Expression::ImageQuery { image, query } => {
587 handle.check_dep(image)?;
588 match query {
589 crate::ImageQuery::Size { level } => {
590 handle.check_dep_opt(level)?;
591 }
592 crate::ImageQuery::NumLevels
593 | crate::ImageQuery::NumLayers
594 | crate::ImageQuery::NumSamples => (),
595 };
596 }
597 crate::Expression::Unary {
598 op: _,
599 expr: operand,
600 } => {
601 handle.check_dep(operand)?;
602 }
603 crate::Expression::Binary { op: _, left, right } => {
604 handle.check_dep(left)?.check_dep(right)?;
605 }
606 crate::Expression::Select {
607 condition,
608 accept,
609 reject,
610 } => {
611 handle
612 .check_dep(condition)?
613 .check_dep(accept)?
614 .check_dep(reject)?;
615 }
616 crate::Expression::Derivative { expr: argument, .. } => {
617 handle.check_dep(argument)?;
618 }
619 crate::Expression::Relational { fun: _, argument } => {
620 handle.check_dep(argument)?;
621 }
622 crate::Expression::Math {
623 fun: _,
624 arg,
625 arg1,
626 arg2,
627 arg3,
628 } => {
629 handle
630 .check_dep(arg)?
631 .check_dep_opt(arg1)?
632 .check_dep_opt(arg2)?
633 .check_dep_opt(arg3)?;
634 }
635 crate::Expression::As {
636 expr: input,
637 kind: _,
638 convert: _,
639 } => {
640 handle.check_dep(input)?;
641 }
642 crate::Expression::CallResult(function) => {
643 Self::validate_function_handle(function, functions)?;
644 if let Some(handle) = current_function {
645 handle.check_dep(function)?;
646 }
647 }
648 crate::Expression::AtomicResult { .. }
649 | crate::Expression::RayQueryProceedResult
650 | crate::Expression::SubgroupBallotResult
651 | crate::Expression::SubgroupOperationResult { .. }
652 | crate::Expression::WorkGroupUniformLoadResult { .. } => (),
653 crate::Expression::ArrayLength(array) => {
654 handle.check_dep(array)?;
655 }
656 crate::Expression::RayQueryGetIntersection {
657 query,
658 committed: _,
659 }
660 | crate::Expression::RayQueryVertexPositions {
661 query,
662 committed: _,
663 } => {
664 handle.check_dep(query)?;
665 }
666 crate::Expression::CooperativeLoad { ref data, .. } => {
667 handle.check_dep(data.pointer)?.check_dep(data.stride)?;
668 }
669 crate::Expression::CooperativeMultiplyAdd { a, b, c } => {
670 handle.check_dep(a)?.check_dep(b)?.check_dep(c)?;
671 }
672 }
673 Ok(())
674 }
675
676 fn validate_block_handles(
677 block: &crate::Block,
678 expressions: &Arena<crate::Expression>,
679 functions: &Arena<crate::Function>,
680 ) -> Result<(), InvalidHandleError> {
681 let validate_block = |block| Self::validate_block_handles(block, expressions, functions);
682 let validate_expr = |handle| Self::validate_expression_handle(handle, expressions);
683 let validate_expr_opt = |handle_opt| {
684 if let Some(handle) = handle_opt {
685 validate_expr(handle)?;
686 }
687 Ok(())
688 };
689
690 block.iter().try_for_each(|stmt| match *stmt {
691 crate::Statement::Emit(ref expr_range) => {
692 expr_range.check_valid_for(expressions)?;
693 Ok(())
694 }
695 crate::Statement::Block(ref block) => {
696 validate_block(block)?;
697 Ok(())
698 }
699 crate::Statement::If {
700 condition,
701 ref accept,
702 ref reject,
703 } => {
704 validate_expr(condition)?;
705 validate_block(accept)?;
706 validate_block(reject)?;
707 Ok(())
708 }
709 crate::Statement::Switch {
710 selector,
711 ref cases,
712 } => {
713 validate_expr(selector)?;
714 for &crate::SwitchCase {
715 value: _,
716 ref body,
717 fall_through: _,
718 } in cases
719 {
720 validate_block(body)?;
721 }
722 Ok(())
723 }
724 crate::Statement::Loop {
725 ref body,
726 ref continuing,
727 break_if,
728 } => {
729 validate_block(body)?;
730 validate_block(continuing)?;
731 validate_expr_opt(break_if)?;
732 Ok(())
733 }
734 crate::Statement::Return { value } => validate_expr_opt(value),
735 crate::Statement::Store { pointer, value } => {
736 validate_expr(pointer)?;
737 validate_expr(value)?;
738 Ok(())
739 }
740 crate::Statement::ImageStore {
741 image,
742 coordinate,
743 array_index,
744 value,
745 } => {
746 validate_expr(image)?;
747 validate_expr(coordinate)?;
748 validate_expr_opt(array_index)?;
749 validate_expr(value)?;
750 Ok(())
751 }
752 crate::Statement::Atomic {
753 pointer,
754 fun,
755 value,
756 result,
757 } => {
758 validate_expr(pointer)?;
759 match fun {
760 crate::AtomicFunction::Add
761 | crate::AtomicFunction::Subtract
762 | crate::AtomicFunction::And
763 | crate::AtomicFunction::ExclusiveOr
764 | crate::AtomicFunction::InclusiveOr
765 | crate::AtomicFunction::Min
766 | crate::AtomicFunction::Max => (),
767 crate::AtomicFunction::Exchange { compare } => validate_expr_opt(compare)?,
768 };
769 validate_expr(value)?;
770 if let Some(result) = result {
771 validate_expr(result)?;
772 }
773 Ok(())
774 }
775 crate::Statement::ImageAtomic {
776 image,
777 coordinate,
778 array_index,
779 fun: _,
780 value,
781 } => {
782 validate_expr(image)?;
783 validate_expr(coordinate)?;
784 validate_expr_opt(array_index)?;
785 validate_expr(value)?;
786 Ok(())
787 }
788 crate::Statement::WorkGroupUniformLoad { pointer, result } => {
789 validate_expr(pointer)?;
790 validate_expr(result)?;
791 Ok(())
792 }
793 crate::Statement::Call {
794 function,
795 ref arguments,
796 result,
797 } => {
798 Self::validate_function_handle(function, functions)?;
799 for arg in arguments.iter().copied() {
800 validate_expr(arg)?;
801 }
802 validate_expr_opt(result)?;
803 Ok(())
804 }
805 crate::Statement::RayQuery { query, ref fun } => {
806 validate_expr(query)?;
807 match *fun {
808 crate::RayQueryFunction::Initialize {
809 acceleration_structure,
810 descriptor,
811 } => {
812 validate_expr(acceleration_structure)?;
813 validate_expr(descriptor)?;
814 }
815 crate::RayQueryFunction::Proceed { result } => {
816 validate_expr(result)?;
817 }
818 crate::RayQueryFunction::GenerateIntersection { hit_t } => {
819 validate_expr(hit_t)?;
820 }
821 crate::RayQueryFunction::ConfirmIntersection => {}
822 crate::RayQueryFunction::Terminate => {}
823 }
824 Ok(())
825 }
826 crate::Statement::SubgroupBallot { result, predicate } => {
827 validate_expr_opt(predicate)?;
828 validate_expr(result)?;
829 Ok(())
830 }
831 crate::Statement::SubgroupCollectiveOperation {
832 op: _,
833 collective_op: _,
834 argument,
835 result,
836 } => {
837 validate_expr(argument)?;
838 validate_expr(result)?;
839 Ok(())
840 }
841 crate::Statement::SubgroupGather {
842 mode,
843 argument,
844 result,
845 } => {
846 validate_expr(argument)?;
847 match mode {
848 crate::GatherMode::BroadcastFirst => {}
849 crate::GatherMode::Broadcast(index)
850 | crate::GatherMode::Shuffle(index)
851 | crate::GatherMode::ShuffleDown(index)
852 | crate::GatherMode::ShuffleUp(index)
853 | crate::GatherMode::ShuffleXor(index)
854 | crate::GatherMode::QuadBroadcast(index) => validate_expr(index)?,
855 crate::GatherMode::QuadSwap(_) => {}
856 }
857 validate_expr(result)?;
858 Ok(())
859 }
860 crate::Statement::CooperativeStore { target, ref data } => {
861 validate_expr(target)?;
862 validate_expr(data.pointer)?;
863 validate_expr(data.stride)?;
864 Ok(())
865 }
866 crate::Statement::RayPipelineFunction(fun) => match fun {
867 crate::RayPipelineFunction::TraceRay {
868 acceleration_structure,
869 descriptor,
870 payload,
871 } => {
872 validate_expr(acceleration_structure)?;
873 validate_expr(descriptor)?;
874 validate_expr(payload)?;
875 Ok(())
876 }
877 },
878 crate::Statement::Break
879 | crate::Statement::Continue
880 | crate::Statement::Kill
881 | crate::Statement::ControlBarrier(_)
882 | crate::Statement::MemoryBarrier(_) => Ok(()),
883 })
884 }
885}
886
887impl From<BadHandle> for ValidationError {
888 fn from(source: BadHandle) -> Self {
889 Self::InvalidHandle(source.into())
890 }
891}
892
893impl From<FwdDepError> for ValidationError {
894 fn from(source: FwdDepError) -> Self {
895 Self::InvalidHandle(source.into())
896 }
897}
898
899impl From<BadRangeError> for ValidationError {
900 fn from(source: BadRangeError) -> Self {
901 Self::InvalidHandle(source.into())
902 }
903}
904
905#[derive(Clone, Debug, thiserror::Error)]
906#[cfg_attr(test, derive(PartialEq))]
907pub enum InvalidHandleError {
908 #[error(transparent)]
909 BadHandle(#[from] BadHandle),
910 #[error(transparent)]
911 ForwardDependency(#[from] FwdDepError),
912 #[error(transparent)]
913 BadRange(#[from] BadRangeError),
914}
915
916#[derive(Clone, Debug, thiserror::Error)]
917#[cfg_attr(test, derive(PartialEq))]
918#[error(
919 "{subject:?} of kind {subject_kind:?} depends on {depends_on:?} of kind {depends_on_kind}, \
920 which has not been processed yet"
921)]
922pub struct FwdDepError {
923 subject: Handle<()>,
926 subject_kind: &'static str,
927 depends_on: Handle<()>,
928 depends_on_kind: &'static str,
929}
930
931impl<T> Handle<T> {
932 pub(self) fn check_valid_for(self, arena: &Arena<T>) -> Result<(), InvalidHandleError> {
934 arena.check_contains_handle(self)?;
935 Ok(())
936 }
937
938 pub(self) fn check_valid_for_uniq(
940 self,
941 arena: &UniqueArena<T>,
942 ) -> Result<(), InvalidHandleError>
943 where
944 T: Eq + Hash,
945 {
946 arena.check_contains_handle(self)?;
947 Ok(())
948 }
949
950 pub(self) fn check_dep(self, depends_on: Self) -> Result<Self, FwdDepError> {
962 if depends_on < self {
963 Ok(self)
964 } else {
965 let erase_handle_type = |handle: Handle<_>| {
966 Handle::new(NonMaxU32::new((handle.index()).try_into().unwrap()).unwrap())
967 };
968 Err(FwdDepError {
969 subject: erase_handle_type(self),
970 subject_kind: core::any::type_name::<T>(),
971 depends_on: erase_handle_type(depends_on),
972 depends_on_kind: core::any::type_name::<T>(),
973 })
974 }
975 }
976
977 pub(self) fn check_dep_opt(self, depends_on: Option<Self>) -> Result<Self, FwdDepError> {
979 self.check_dep_iter(depends_on.into_iter())
980 }
981
982 pub(self) fn check_dep_iter(
984 self,
985 depends_on: impl Iterator<Item = Self>,
986 ) -> Result<Self, FwdDepError> {
987 for handle in depends_on {
988 self.check_dep(handle)?;
989 }
990 Ok(self)
991 }
992}
993
994impl<T> crate::arena::Range<T> {
995 pub(self) fn check_valid_for(&self, arena: &Arena<T>) -> Result<(), BadRangeError> {
996 arena.check_contains_range(self)
997 }
998}
999
1000#[test]
1001fn constant_deps() {
1002 use crate::{Constant, Expression, Literal, Span, Type, TypeInner};
1003
1004 let nowhere = Span::default();
1005
1006 let mut types = UniqueArena::new();
1007 let mut const_exprs = Arena::new();
1008 let mut fun_exprs = Arena::new();
1009 let mut constants = Arena::new();
1010 let overrides = Arena::new();
1011
1012 let i32_handle = types.insert(
1013 Type {
1014 name: None,
1015 inner: TypeInner::Scalar(crate::Scalar::I32),
1016 },
1017 nowhere,
1018 );
1019
1020 let fun_expr = fun_exprs.append(Expression::Literal(Literal::I32(42)), nowhere);
1023 let self_referential_const = constants.append(
1024 Constant {
1025 name: None,
1026 ty: i32_handle,
1027 init: fun_expr,
1028 },
1029 nowhere,
1030 );
1031 let _self_referential_expr =
1032 const_exprs.append(Expression::Constant(self_referential_const), nowhere);
1033
1034 for handle_and_expr in const_exprs.iter() {
1035 assert!(super::Validator::validate_const_expression_handles(
1036 handle_and_expr,
1037 &constants,
1038 &overrides,
1039 )
1040 .is_err());
1041 }
1042}
1043
1044#[test]
1045fn array_size_deps() {
1046 use super::Validator;
1047 use crate::{ArraySize, Expression, Override, Scalar, Span, Type, TypeInner};
1048
1049 let nowhere = Span::default();
1050
1051 let mut m = crate::Module::default();
1052
1053 let ty_u32 = m.types.insert(
1054 Type {
1055 name: Some("u32".to_string()),
1056 inner: TypeInner::Scalar(Scalar::U32),
1057 },
1058 nowhere,
1059 );
1060 let ex_zero = m
1061 .global_expressions
1062 .append(Expression::ZeroValue(ty_u32), nowhere);
1063 let ty_handle = m.overrides.append(
1064 Override {
1065 name: None,
1066 id: None,
1067 ty: ty_u32,
1068 init: Some(ex_zero),
1069 },
1070 nowhere,
1071 );
1072 let ty_arr = m.types.insert(
1073 Type {
1074 name: Some("bad_array".to_string()),
1075 inner: TypeInner::Array {
1076 base: ty_u32,
1077 size: ArraySize::Pending(ty_handle),
1078 stride: 4,
1079 },
1080 },
1081 nowhere,
1082 );
1083
1084 assert!(Validator::validate_module_handles(&m).is_ok());
1086
1087 m.global_expressions[ex_zero] = Expression::ZeroValue(ty_arr);
1090 assert!(Validator::validate_module_handles(&m).is_err());
1091}
1092
1093#[test]
1094fn array_size_override() {
1095 use super::Validator;
1096 use crate::{ArraySize, Override, Scalar, Span, Type, TypeInner};
1097
1098 let nowhere = Span::default();
1099
1100 let mut m = crate::Module::default();
1101
1102 let ty_u32 = m.types.insert(
1103 Type {
1104 name: Some("u32".to_string()),
1105 inner: TypeInner::Scalar(Scalar::U32),
1106 },
1107 nowhere,
1108 );
1109
1110 let bad_override: Handle<Override> = Handle::new(NonMaxU32::new(1000).unwrap());
1111 let _ty_arr = m.types.insert(
1112 Type {
1113 name: Some("bad_array".to_string()),
1114 inner: TypeInner::Array {
1115 base: ty_u32,
1116 size: ArraySize::Pending(bad_override),
1117 stride: 4,
1118 },
1119 },
1120 nowhere,
1121 );
1122
1123 assert!(Validator::validate_module_handles(&m).is_err());
1124}
1125
1126#[test]
1127fn override_init_deps() {
1128 use super::Validator;
1129 use crate::{ArraySize, Expression, Override, Scalar, Span, Type, TypeInner};
1130
1131 let nowhere = Span::default();
1132
1133 let mut m = crate::Module::default();
1134
1135 let ty_u32 = m.types.insert(
1136 Type {
1137 name: Some("u32".to_string()),
1138 inner: TypeInner::Scalar(Scalar::U32),
1139 },
1140 nowhere,
1141 );
1142 let ex_zero = m
1143 .global_expressions
1144 .append(Expression::ZeroValue(ty_u32), nowhere);
1145 let r#override = m.overrides.append(
1146 Override {
1147 name: Some("bad_override".into()),
1148 id: None,
1149 ty: ty_u32,
1150 init: Some(ex_zero),
1151 },
1152 nowhere,
1153 );
1154 let ty_arr = m.types.insert(
1155 Type {
1156 name: Some("bad_array".to_string()),
1157 inner: TypeInner::Array {
1158 base: ty_u32,
1159 size: ArraySize::Pending(r#override),
1160 stride: 4,
1161 },
1162 },
1163 nowhere,
1164 );
1165 let ex_arr = m
1166 .global_expressions
1167 .append(Expression::ZeroValue(ty_arr), nowhere);
1168
1169 assert!(Validator::validate_module_handles(&m).is_ok());
1170
1171 m.overrides[r#override].init = Some(ex_arr);
1174 assert!(Validator::validate_module_handles(&m).is_err());
1175}