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