naga/valid/
handles.rs

1//! Implementation of `Validator::validate_module_handles`.
2
3use 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    /// Validates that all handles within `module` are:
19    ///
20    /// * Valid, in the sense that they contain indices within each arena structure inside the
21    ///   [`crate::Module`] type.
22    /// * No arena contents contain any items that have forward dependencies; that is, the value
23    ///   associated with a handle only may contain references to handles in the same arena that
24    ///   were constructed before it.
25    ///
26    /// By validating the above conditions, we free up subsequent logic to assume that handle
27    /// accesses are infallible.
28    ///
29    /// # Errors
30    ///
31    /// Errors returned by this method are intentionally sparse, for simplicity of implementation.
32    /// It is expected that only buggy frontends or fuzzers should ever emit IR that fails this
33    /// validation pass.
34    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        // Because types can refer to global expressions and vice versa, to
49        // ensure the overall structure is free of cycles, we must traverse them
50        // both in tandem.
51        //
52        // Try to visit all types and global expressions in an order such that
53        // each item refers only to previously visited items. If we succeed,
54        // that shows that there cannot be any cycles, since walking any edge
55        // advances you towards the beginning of the visiting order.
56        //
57        // Validate all the handles in types and expressions as we traverse the
58        // arenas.
59        let mut global_exprs_iter = global_expressions.iter().peekable();
60        for (th, t) in types.iter() {
61            // Imagine the `for` loop and `global_exprs_iter` as two fingers
62            // walking the type and global expression arenas. They don't visit
63            // elements at the same rate: sometimes one processes a bunch of
64            // elements while the other one stays still. But at each point, they
65            // check that the two ranges of elements they've visited only refer
66            // to other elements in those ranges.
67            //
68            // For brevity, we'll say 'handles behind `global_exprs_iter`' to
69            // mean handles that have already been produced by
70            // `global_exprs_iter`. Once `global_exprs_iter` returns `None`, all
71            // global expression handles are 'behind' it.
72            //
73            // At this point:
74            //
75            // - All types visited by prior iterations (that is, before
76            //   `th`/`t`) refer only to expressions behind `global_exprs_iter`.
77            //
78            //   On the first iteration, this is obviously true: there are no
79            //   prior iterations, and `global_exprs_iter` hasn't produced
80            //   anything yet. At the bottom of the loop, we'll claim that it's
81            //   true for `th`/`t` as well, so the condition remains true when
82            //   we advance to the next type.
83            //
84            // - All expressions behind `global_exprs_iter` refer only to
85            //   previously visited types.
86            //
87            //   Again, trivially true at the start, and we'll show it's true
88            //   about each expression that `global_exprs_iter` produces.
89            //
90            // Once we also check that arena elements only refer to prior
91            // elements in that arena, we can see that `th`/`t` does not
92            // participate in a cycle: it only refers to previously visited
93            // types and expressions behind `global_exprs_iter`, and none of
94            // those refer to `th`/`t`, because they passed the same checks
95            // before we reached `th`/`t`.
96            if let Some(max_expr) = Self::validate_type_handles((th, t), overrides)? {
97                max_expr.check_valid_for(global_expressions)?;
98                // Since `t` refers to `max_expr`, if we want our invariants to
99                // remain true, we must advance `global_exprs_iter` beyond
100                // `max_expr`.
101                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                        // Show that `eh` refers only to previously visited types.
106                        th.check_dep(max_type)?;
107                    }
108                    // We've advanced `global_exprs_iter` past `eh` already. But
109                    // since we now know that `eh` refers only to previously
110                    // visited types, it is again true that all expressions
111                    // behind `global_exprs_iter` refer only to previously
112                    // visited types. So we can continue to the next expression.
113                }
114            }
115
116            // Here we know that if `th` refers to any expressions at all,
117            // `max_expr` is the latest one. And we know that `max_expr` is
118            // behind `global_exprs_iter`. So `th` refers only to expressions
119            // behind `global_exprs_iter`, and the invariants will still be
120            // true on the next iteration.
121        }
122
123        // Since we also enforced the usual intra-arena rules that expressions
124        // refer only to prior expressions, expressions can only form cycles if
125        // they include types. But we've shown that all types are acyclic, so
126        // all expressions must be acyclic as well.
127        //
128        // Validate the remaining expressions normally.
129        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    /// Validate all handles that occur in `ty`, whose handle is `handle`.
299    ///
300    /// If `ty` refers to any expressions, return the highest-indexed expression
301    /// handle that it uses. This is used for detecting cycles between the
302    /// expression and type arenas.
303    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    /// Validate all handles that occur in `expression`, whose handle is `handle`.
347    ///
348    /// If `expression` refers to any `Type`s, return the highest-indexed type
349    /// handle that it uses. This is used for detecting cycles between the
350    /// expression and type arenas.
351    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        // The handle of the current function or `None` if it's an entry point
393        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    // This error is used for many `Handle` types, but there's no point in making this generic, so
793    // we just flatten them all to `Handle<()>` here.
794    subject: Handle<()>,
795    subject_kind: &'static str,
796    depends_on: Handle<()>,
797    depends_on_kind: &'static str,
798}
799
800impl<T> Handle<T> {
801    /// Check that `self` is valid within `arena` using [`Arena::check_contains_handle`].
802    pub(self) fn check_valid_for(self, arena: &Arena<T>) -> Result<(), InvalidHandleError> {
803        arena.check_contains_handle(self)?;
804        Ok(())
805    }
806
807    /// Check that `self` is valid within `arena` using [`UniqueArena::check_contains_handle`].
808    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    /// Check that `depends_on` was constructed before `self` by comparing handle indices.
820    ///
821    /// If `self` is a valid handle (i.e., it has been validated using [`Self::check_valid_for`])
822    /// and this function returns [`Ok`], then it may be assumed that `depends_on` is also valid.
823    /// In [`naga`](crate)'s current arena-based implementation, this is useful for validating
824    /// recursive definitions of arena-based values in linear time.
825    ///
826    /// # Errors
827    ///
828    /// If `depends_on`'s handle is from the same [`Arena`] as `self'`s, but not constructed earlier
829    /// than `self`'s, this function returns an error.
830    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    /// Like [`Self::check_dep`], except for [`Option`]al handle values.
847    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    /// Like [`Self::check_dep`], except for [`Iterator`]s over handle values.
852    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    // Construct a self-referential constant by misusing a handle to
890    // fun_exprs as a constant initializer.
891    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    // Everything should be okay now.
954    assert!(Validator::validate_module_handles(&m).is_ok());
955
956    // Mutate `ex_zero`'s type to `ty_arr`, introducing a cycle.
957    // Validation should catch the cycle.
958    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    // Mutate `r#override`'s initializer to `ex_arr`, introducing a cycle.
1041    // Validation should catch the cycle.
1042    m.overrides[r#override].init = Some(ex_arr);
1043    assert!(Validator::validate_module_handles(&m).is_err());
1044}