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::ValuePointer { .. }
398 | crate::TypeInner::Atomic { .. }
399 | crate::TypeInner::Image { .. }
400 | crate::TypeInner::Sampler { .. }
401 | crate::TypeInner::AccelerationStructure { .. }
402 | crate::TypeInner::RayQuery { .. } => None,
403 crate::TypeInner::Pointer { base, space: _ } => {
404 handle.check_dep(base)?;
405 None
406 }
407 crate::TypeInner::Array { base, size, .. }
408 | crate::TypeInner::BindingArray { base, size, .. } => {
409 handle.check_dep(base)?;
410 match size {
411 crate::ArraySize::Pending(h) => {
412 Self::validate_override_handle(h, overrides)?;
413 let r#override = &overrides[h];
414 handle.check_dep(r#override.ty)?;
415 r#override.init
416 }
417 crate::ArraySize::Constant(_) | crate::ArraySize::Dynamic => None,
418 }
419 }
420 crate::TypeInner::Struct {
421 ref members,
422 span: _,
423 } => {
424 handle.check_dep_iter(members.iter().map(|m| m.ty))?;
425 None
426 }
427 };
428
429 Ok(max_expr)
430 }
431
432 fn validate_entry_point_index(
433 entry_point_index: usize,
434 entry_points: &[EntryPoint],
435 ) -> Result<(), InvalidHandleError> {
436 (0..entry_points.len())
437 .contains(&entry_point_index)
438 .then_some(())
439 .ok_or_else(|| {
440 BadHandle {
441 kind: "EntryPoint",
442 index: entry_point_index,
443 }
444 .into()
445 })
446 }
447
448 fn validate_const_expression_handles(
454 (handle, expression): (Handle<crate::Expression>, &crate::Expression),
455 constants: &Arena<crate::Constant>,
456 overrides: &Arena<crate::Override>,
457 ) -> Result<Option<Handle<crate::Type>>, InvalidHandleError> {
458 let validate_constant = |handle| Self::validate_constant_handle(handle, constants);
459 let validate_override = |handle| Self::validate_override_handle(handle, overrides);
460
461 let max_type = match *expression {
462 crate::Expression::Literal(_) => None,
463 crate::Expression::Constant(constant) => {
464 validate_constant(constant)?;
465 handle.check_dep(constants[constant].init)?;
466 None
467 }
468 crate::Expression::Override(r#override) => {
469 validate_override(r#override)?;
470 if let Some(init) = overrides[r#override].init {
471 handle.check_dep(init)?;
472 }
473 None
474 }
475 crate::Expression::ZeroValue(ty) => Some(ty),
476 crate::Expression::Compose { ty, ref components } => {
477 handle.check_dep_iter(components.iter().copied())?;
478 Some(ty)
479 }
480 _ => None,
481 };
482 Ok(max_type)
483 }
484
485 #[allow(clippy::too_many_arguments)]
486 fn validate_expression_handles(
487 (handle, expression): (Handle<crate::Expression>, &crate::Expression),
488 constants: &Arena<crate::Constant>,
489 overrides: &Arena<crate::Override>,
490 types: &UniqueArena<crate::Type>,
491 local_variables: &Arena<crate::LocalVariable>,
492 global_variables: &Arena<crate::GlobalVariable>,
493 functions: &Arena<crate::Function>,
494 current_function: Option<Handle<crate::Function>>,
496 ) -> Result<(), InvalidHandleError> {
497 let validate_constant = |handle| Self::validate_constant_handle(handle, constants);
498 let validate_override = |handle| Self::validate_override_handle(handle, overrides);
499 let validate_type = |handle| Self::validate_type_handle(handle, types);
500
501 match *expression {
502 crate::Expression::Access { base, index } => {
503 handle.check_dep(base)?.check_dep(index)?;
504 }
505 crate::Expression::AccessIndex { base, .. } => {
506 handle.check_dep(base)?;
507 }
508 crate::Expression::Splat { value, .. } => {
509 handle.check_dep(value)?;
510 }
511 crate::Expression::Swizzle { vector, .. } => {
512 handle.check_dep(vector)?;
513 }
514 crate::Expression::Literal(_) => {}
515 crate::Expression::Constant(constant) => {
516 validate_constant(constant)?;
517 }
518 crate::Expression::Override(r#override) => {
519 validate_override(r#override)?;
520 }
521 crate::Expression::ZeroValue(ty) => {
522 validate_type(ty)?;
523 }
524 crate::Expression::Compose { ty, ref components } => {
525 validate_type(ty)?;
526 handle.check_dep_iter(components.iter().copied())?;
527 }
528 crate::Expression::FunctionArgument(_arg_idx) => (),
529 crate::Expression::GlobalVariable(global_variable) => {
530 global_variable.check_valid_for(global_variables)?;
531 }
532 crate::Expression::LocalVariable(local_variable) => {
533 local_variable.check_valid_for(local_variables)?;
534 }
535 crate::Expression::Load { pointer } => {
536 handle.check_dep(pointer)?;
537 }
538 crate::Expression::ImageSample {
539 image,
540 sampler,
541 gather: _,
542 coordinate,
543 array_index,
544 offset,
545 level,
546 depth_ref,
547 clamp_to_edge: _,
548 } => {
549 handle
550 .check_dep(image)?
551 .check_dep(sampler)?
552 .check_dep(coordinate)?
553 .check_dep_opt(array_index)?
554 .check_dep_opt(offset)?;
555
556 match level {
557 crate::SampleLevel::Auto | crate::SampleLevel::Zero => (),
558 crate::SampleLevel::Exact(expr) => {
559 handle.check_dep(expr)?;
560 }
561 crate::SampleLevel::Bias(expr) => {
562 handle.check_dep(expr)?;
563 }
564 crate::SampleLevel::Gradient { x, y } => {
565 handle.check_dep(x)?.check_dep(y)?;
566 }
567 };
568
569 handle.check_dep_opt(depth_ref)?;
570 }
571 crate::Expression::ImageLoad {
572 image,
573 coordinate,
574 array_index,
575 sample,
576 level,
577 } => {
578 handle
579 .check_dep(image)?
580 .check_dep(coordinate)?
581 .check_dep_opt(array_index)?
582 .check_dep_opt(sample)?
583 .check_dep_opt(level)?;
584 }
585 crate::Expression::ImageQuery { image, query } => {
586 handle.check_dep(image)?;
587 match query {
588 crate::ImageQuery::Size { level } => {
589 handle.check_dep_opt(level)?;
590 }
591 crate::ImageQuery::NumLevels
592 | crate::ImageQuery::NumLayers
593 | crate::ImageQuery::NumSamples => (),
594 };
595 }
596 crate::Expression::Unary {
597 op: _,
598 expr: operand,
599 } => {
600 handle.check_dep(operand)?;
601 }
602 crate::Expression::Binary { op: _, left, right } => {
603 handle.check_dep(left)?.check_dep(right)?;
604 }
605 crate::Expression::Select {
606 condition,
607 accept,
608 reject,
609 } => {
610 handle
611 .check_dep(condition)?
612 .check_dep(accept)?
613 .check_dep(reject)?;
614 }
615 crate::Expression::Derivative { expr: argument, .. } => {
616 handle.check_dep(argument)?;
617 }
618 crate::Expression::Relational { fun: _, argument } => {
619 handle.check_dep(argument)?;
620 }
621 crate::Expression::Math {
622 fun: _,
623 arg,
624 arg1,
625 arg2,
626 arg3,
627 } => {
628 handle
629 .check_dep(arg)?
630 .check_dep_opt(arg1)?
631 .check_dep_opt(arg2)?
632 .check_dep_opt(arg3)?;
633 }
634 crate::Expression::As {
635 expr: input,
636 kind: _,
637 convert: _,
638 } => {
639 handle.check_dep(input)?;
640 }
641 crate::Expression::CallResult(function) => {
642 Self::validate_function_handle(function, functions)?;
643 if let Some(handle) = current_function {
644 handle.check_dep(function)?;
645 }
646 }
647 crate::Expression::AtomicResult { .. }
648 | crate::Expression::RayQueryProceedResult
649 | crate::Expression::SubgroupBallotResult
650 | crate::Expression::SubgroupOperationResult { .. }
651 | crate::Expression::WorkGroupUniformLoadResult { .. } => (),
652 crate::Expression::ArrayLength(array) => {
653 handle.check_dep(array)?;
654 }
655 crate::Expression::RayQueryGetIntersection {
656 query,
657 committed: _,
658 }
659 | crate::Expression::RayQueryVertexPositions {
660 query,
661 committed: _,
662 } => {
663 handle.check_dep(query)?;
664 }
665 }
666 Ok(())
667 }
668
669 fn validate_block_handles(
670 block: &crate::Block,
671 expressions: &Arena<crate::Expression>,
672 functions: &Arena<crate::Function>,
673 ) -> Result<(), InvalidHandleError> {
674 let validate_block = |block| Self::validate_block_handles(block, expressions, functions);
675 let validate_expr = |handle| Self::validate_expression_handle(handle, expressions);
676 let validate_expr_opt = |handle_opt| {
677 if let Some(handle) = handle_opt {
678 validate_expr(handle)?;
679 }
680 Ok(())
681 };
682
683 block.iter().try_for_each(|stmt| match *stmt {
684 crate::Statement::Emit(ref expr_range) => {
685 expr_range.check_valid_for(expressions)?;
686 Ok(())
687 }
688 crate::Statement::Block(ref block) => {
689 validate_block(block)?;
690 Ok(())
691 }
692 crate::Statement::If {
693 condition,
694 ref accept,
695 ref reject,
696 } => {
697 validate_expr(condition)?;
698 validate_block(accept)?;
699 validate_block(reject)?;
700 Ok(())
701 }
702 crate::Statement::Switch {
703 selector,
704 ref cases,
705 } => {
706 validate_expr(selector)?;
707 for &crate::SwitchCase {
708 value: _,
709 ref body,
710 fall_through: _,
711 } in cases
712 {
713 validate_block(body)?;
714 }
715 Ok(())
716 }
717 crate::Statement::Loop {
718 ref body,
719 ref continuing,
720 break_if,
721 } => {
722 validate_block(body)?;
723 validate_block(continuing)?;
724 validate_expr_opt(break_if)?;
725 Ok(())
726 }
727 crate::Statement::Return { value } => validate_expr_opt(value),
728 crate::Statement::Store { pointer, value } => {
729 validate_expr(pointer)?;
730 validate_expr(value)?;
731 Ok(())
732 }
733 crate::Statement::ImageStore {
734 image,
735 coordinate,
736 array_index,
737 value,
738 } => {
739 validate_expr(image)?;
740 validate_expr(coordinate)?;
741 validate_expr_opt(array_index)?;
742 validate_expr(value)?;
743 Ok(())
744 }
745 crate::Statement::Atomic {
746 pointer,
747 fun,
748 value,
749 result,
750 } => {
751 validate_expr(pointer)?;
752 match fun {
753 crate::AtomicFunction::Add
754 | crate::AtomicFunction::Subtract
755 | crate::AtomicFunction::And
756 | crate::AtomicFunction::ExclusiveOr
757 | crate::AtomicFunction::InclusiveOr
758 | crate::AtomicFunction::Min
759 | crate::AtomicFunction::Max => (),
760 crate::AtomicFunction::Exchange { compare } => validate_expr_opt(compare)?,
761 };
762 validate_expr(value)?;
763 if let Some(result) = result {
764 validate_expr(result)?;
765 }
766 Ok(())
767 }
768 crate::Statement::ImageAtomic {
769 image,
770 coordinate,
771 array_index,
772 fun: _,
773 value,
774 } => {
775 validate_expr(image)?;
776 validate_expr(coordinate)?;
777 validate_expr_opt(array_index)?;
778 validate_expr(value)?;
779 Ok(())
780 }
781 crate::Statement::WorkGroupUniformLoad { pointer, result } => {
782 validate_expr(pointer)?;
783 validate_expr(result)?;
784 Ok(())
785 }
786 crate::Statement::Call {
787 function,
788 ref arguments,
789 result,
790 } => {
791 Self::validate_function_handle(function, functions)?;
792 for arg in arguments.iter().copied() {
793 validate_expr(arg)?;
794 }
795 validate_expr_opt(result)?;
796 Ok(())
797 }
798 crate::Statement::RayQuery { query, ref fun } => {
799 validate_expr(query)?;
800 match *fun {
801 crate::RayQueryFunction::Initialize {
802 acceleration_structure,
803 descriptor,
804 } => {
805 validate_expr(acceleration_structure)?;
806 validate_expr(descriptor)?;
807 }
808 crate::RayQueryFunction::Proceed { result } => {
809 validate_expr(result)?;
810 }
811 crate::RayQueryFunction::GenerateIntersection { hit_t } => {
812 validate_expr(hit_t)?;
813 }
814 crate::RayQueryFunction::ConfirmIntersection => {}
815 crate::RayQueryFunction::Terminate => {}
816 }
817 Ok(())
818 }
819 crate::Statement::SubgroupBallot { result, predicate } => {
820 validate_expr_opt(predicate)?;
821 validate_expr(result)?;
822 Ok(())
823 }
824 crate::Statement::SubgroupCollectiveOperation {
825 op: _,
826 collective_op: _,
827 argument,
828 result,
829 } => {
830 validate_expr(argument)?;
831 validate_expr(result)?;
832 Ok(())
833 }
834 crate::Statement::SubgroupGather {
835 mode,
836 argument,
837 result,
838 } => {
839 validate_expr(argument)?;
840 match mode {
841 crate::GatherMode::BroadcastFirst => {}
842 crate::GatherMode::Broadcast(index)
843 | crate::GatherMode::Shuffle(index)
844 | crate::GatherMode::ShuffleDown(index)
845 | crate::GatherMode::ShuffleUp(index)
846 | crate::GatherMode::ShuffleXor(index)
847 | crate::GatherMode::QuadBroadcast(index) => validate_expr(index)?,
848 crate::GatherMode::QuadSwap(_) => {}
849 }
850 validate_expr(result)?;
851 Ok(())
852 }
853 crate::Statement::Break
854 | crate::Statement::Continue
855 | crate::Statement::Kill
856 | crate::Statement::ControlBarrier(_)
857 | crate::Statement::MemoryBarrier(_) => Ok(()),
858 })
859 }
860}
861
862impl From<BadHandle> for ValidationError {
863 fn from(source: BadHandle) -> Self {
864 Self::InvalidHandle(source.into())
865 }
866}
867
868impl From<FwdDepError> for ValidationError {
869 fn from(source: FwdDepError) -> Self {
870 Self::InvalidHandle(source.into())
871 }
872}
873
874impl From<BadRangeError> for ValidationError {
875 fn from(source: BadRangeError) -> Self {
876 Self::InvalidHandle(source.into())
877 }
878}
879
880#[derive(Clone, Debug, thiserror::Error)]
881#[cfg_attr(test, derive(PartialEq))]
882pub enum InvalidHandleError {
883 #[error(transparent)]
884 BadHandle(#[from] BadHandle),
885 #[error(transparent)]
886 ForwardDependency(#[from] FwdDepError),
887 #[error(transparent)]
888 BadRange(#[from] BadRangeError),
889}
890
891#[derive(Clone, Debug, thiserror::Error)]
892#[cfg_attr(test, derive(PartialEq))]
893#[error(
894 "{subject:?} of kind {subject_kind:?} depends on {depends_on:?} of kind {depends_on_kind}, \
895 which has not been processed yet"
896)]
897pub struct FwdDepError {
898 subject: Handle<()>,
901 subject_kind: &'static str,
902 depends_on: Handle<()>,
903 depends_on_kind: &'static str,
904}
905
906impl<T> Handle<T> {
907 pub(self) fn check_valid_for(self, arena: &Arena<T>) -> Result<(), InvalidHandleError> {
909 arena.check_contains_handle(self)?;
910 Ok(())
911 }
912
913 pub(self) fn check_valid_for_uniq(
915 self,
916 arena: &UniqueArena<T>,
917 ) -> Result<(), InvalidHandleError>
918 where
919 T: Eq + Hash,
920 {
921 arena.check_contains_handle(self)?;
922 Ok(())
923 }
924
925 pub(self) fn check_dep(self, depends_on: Self) -> Result<Self, FwdDepError> {
937 if depends_on < self {
938 Ok(self)
939 } else {
940 let erase_handle_type = |handle: Handle<_>| {
941 Handle::new(NonMaxU32::new((handle.index()).try_into().unwrap()).unwrap())
942 };
943 Err(FwdDepError {
944 subject: erase_handle_type(self),
945 subject_kind: core::any::type_name::<T>(),
946 depends_on: erase_handle_type(depends_on),
947 depends_on_kind: core::any::type_name::<T>(),
948 })
949 }
950 }
951
952 pub(self) fn check_dep_opt(self, depends_on: Option<Self>) -> Result<Self, FwdDepError> {
954 self.check_dep_iter(depends_on.into_iter())
955 }
956
957 pub(self) fn check_dep_iter(
959 self,
960 depends_on: impl Iterator<Item = Self>,
961 ) -> Result<Self, FwdDepError> {
962 for handle in depends_on {
963 self.check_dep(handle)?;
964 }
965 Ok(self)
966 }
967}
968
969impl<T> crate::arena::Range<T> {
970 pub(self) fn check_valid_for(&self, arena: &Arena<T>) -> Result<(), BadRangeError> {
971 arena.check_contains_range(self)
972 }
973}
974
975#[test]
976fn constant_deps() {
977 use crate::{Constant, Expression, Literal, Span, Type, TypeInner};
978
979 let nowhere = Span::default();
980
981 let mut types = UniqueArena::new();
982 let mut const_exprs = Arena::new();
983 let mut fun_exprs = Arena::new();
984 let mut constants = Arena::new();
985 let overrides = Arena::new();
986
987 let i32_handle = types.insert(
988 Type {
989 name: None,
990 inner: TypeInner::Scalar(crate::Scalar::I32),
991 },
992 nowhere,
993 );
994
995 let fun_expr = fun_exprs.append(Expression::Literal(Literal::I32(42)), nowhere);
998 let self_referential_const = constants.append(
999 Constant {
1000 name: None,
1001 ty: i32_handle,
1002 init: fun_expr,
1003 },
1004 nowhere,
1005 );
1006 let _self_referential_expr =
1007 const_exprs.append(Expression::Constant(self_referential_const), nowhere);
1008
1009 for handle_and_expr in const_exprs.iter() {
1010 assert!(super::Validator::validate_const_expression_handles(
1011 handle_and_expr,
1012 &constants,
1013 &overrides,
1014 )
1015 .is_err());
1016 }
1017}
1018
1019#[test]
1020fn array_size_deps() {
1021 use super::Validator;
1022 use crate::{ArraySize, Expression, Override, Scalar, Span, Type, TypeInner};
1023
1024 let nowhere = Span::default();
1025
1026 let mut m = crate::Module::default();
1027
1028 let ty_u32 = m.types.insert(
1029 Type {
1030 name: Some("u32".to_string()),
1031 inner: TypeInner::Scalar(Scalar::U32),
1032 },
1033 nowhere,
1034 );
1035 let ex_zero = m
1036 .global_expressions
1037 .append(Expression::ZeroValue(ty_u32), nowhere);
1038 let ty_handle = m.overrides.append(
1039 Override {
1040 name: None,
1041 id: None,
1042 ty: ty_u32,
1043 init: Some(ex_zero),
1044 },
1045 nowhere,
1046 );
1047 let ty_arr = m.types.insert(
1048 Type {
1049 name: Some("bad_array".to_string()),
1050 inner: TypeInner::Array {
1051 base: ty_u32,
1052 size: ArraySize::Pending(ty_handle),
1053 stride: 4,
1054 },
1055 },
1056 nowhere,
1057 );
1058
1059 assert!(Validator::validate_module_handles(&m).is_ok());
1061
1062 m.global_expressions[ex_zero] = Expression::ZeroValue(ty_arr);
1065 assert!(Validator::validate_module_handles(&m).is_err());
1066}
1067
1068#[test]
1069fn array_size_override() {
1070 use super::Validator;
1071 use crate::{ArraySize, Override, Scalar, Span, Type, TypeInner};
1072
1073 let nowhere = Span::default();
1074
1075 let mut m = crate::Module::default();
1076
1077 let ty_u32 = m.types.insert(
1078 Type {
1079 name: Some("u32".to_string()),
1080 inner: TypeInner::Scalar(Scalar::U32),
1081 },
1082 nowhere,
1083 );
1084
1085 let bad_override: Handle<Override> = Handle::new(NonMaxU32::new(1000).unwrap());
1086 let _ty_arr = m.types.insert(
1087 Type {
1088 name: Some("bad_array".to_string()),
1089 inner: TypeInner::Array {
1090 base: ty_u32,
1091 size: ArraySize::Pending(bad_override),
1092 stride: 4,
1093 },
1094 },
1095 nowhere,
1096 );
1097
1098 assert!(Validator::validate_module_handles(&m).is_err());
1099}
1100
1101#[test]
1102fn override_init_deps() {
1103 use super::Validator;
1104 use crate::{ArraySize, Expression, Override, Scalar, Span, Type, TypeInner};
1105
1106 let nowhere = Span::default();
1107
1108 let mut m = crate::Module::default();
1109
1110 let ty_u32 = m.types.insert(
1111 Type {
1112 name: Some("u32".to_string()),
1113 inner: TypeInner::Scalar(Scalar::U32),
1114 },
1115 nowhere,
1116 );
1117 let ex_zero = m
1118 .global_expressions
1119 .append(Expression::ZeroValue(ty_u32), nowhere);
1120 let r#override = m.overrides.append(
1121 Override {
1122 name: Some("bad_override".into()),
1123 id: None,
1124 ty: ty_u32,
1125 init: Some(ex_zero),
1126 },
1127 nowhere,
1128 );
1129 let ty_arr = m.types.insert(
1130 Type {
1131 name: Some("bad_array".to_string()),
1132 inner: TypeInner::Array {
1133 base: ty_u32,
1134 size: ArraySize::Pending(r#override),
1135 stride: 4,
1136 },
1137 },
1138 nowhere,
1139 );
1140 let ex_arr = m
1141 .global_expressions
1142 .append(Expression::ZeroValue(ty_arr), nowhere);
1143
1144 assert!(Validator::validate_module_handles(&m).is_ok());
1145
1146 m.overrides[r#override].init = Some(ex_arr);
1149 assert!(Validator::validate_module_handles(&m).is_err());
1150}