1use alloc::string::String;
2
3use super::Capabilities;
4use crate::{arena::Handle, proc::Alignment};
5
6bitflags::bitflags! {
7 #[cfg_attr(feature = "serialize", derive(serde::Serialize))]
12 #[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
13 #[repr(transparent)]
14 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
15 pub struct TypeFlags: u8 {
16 const DATA = 0x1;
28
29 const SIZED = 0x2;
43
44 const COPY = 0x4;
46
47 const IO_SHAREABLE = 0x8;
55
56 const HOST_SHAREABLE = 0x10;
58
59 const CREATION_RESOLVED = 0x20;
62
63 const ARGUMENT = 0x40;
65
66 const CONSTRUCTIBLE = 0x80;
74 }
75}
76
77#[derive(Clone, Copy, Debug, thiserror::Error)]
78#[cfg_attr(test, derive(PartialEq))]
79pub enum Disalignment {
80 #[error("The array stride {stride} is not a multiple of the required alignment {alignment}")]
81 ArrayStride { stride: u32, alignment: Alignment },
82 #[error("The struct span {span}, is not a multiple of the required alignment {alignment}")]
83 StructSpan { span: u32, alignment: Alignment },
84 #[error("The struct member[{index}] offset {offset} is not a multiple of the required alignment {alignment}")]
85 MemberOffset {
86 index: u32,
87 offset: u32,
88 alignment: Alignment,
89 },
90 #[error("The struct member[{index}] offset {offset} must be at least {expected}")]
91 MemberOffsetAfterStruct {
92 index: u32,
93 offset: u32,
94 expected: u32,
95 },
96 #[error("The struct member[{index}] is not statically sized")]
97 UnsizedMember { index: u32 },
98 #[error("The type is not host-shareable")]
99 NonHostShareable,
100}
101
102#[derive(Clone, Debug, thiserror::Error)]
103#[cfg_attr(test, derive(PartialEq))]
104pub enum TypeError {
105 #[error("Capability {0:?} is required")]
106 MissingCapability(Capabilities),
107 #[error("The {0:?} scalar width {1} is not supported for an atomic")]
108 InvalidAtomicWidth(crate::ScalarKind, crate::Bytes),
109 #[error("Invalid type for pointer target {0:?}")]
110 InvalidPointerBase(Handle<crate::Type>),
111 #[error("Unsized types like {base:?} must be in the `Storage` address space, not `{space:?}`")]
112 InvalidPointerToUnsized {
113 base: Handle<crate::Type>,
114 space: crate::AddressSpace,
115 },
116 #[error("Expected data type, found {0:?}")]
117 InvalidData(Handle<crate::Type>),
118 #[error("Base type {0:?} for the array is invalid")]
119 InvalidArrayBaseType(Handle<crate::Type>),
120 #[error("Matrix elements must always be floating-point types")]
121 MatrixElementNotFloat,
122 #[error("The constant {0:?} is specialized, and cannot be used as an array size")]
123 UnsupportedSpecializedArrayLength(Handle<crate::Constant>),
124 #[error("{} of dimensionality {dim:?} and class {class:?} are not supported", if *.arrayed {"Arrayed images"} else {"Images"})]
125 UnsupportedImageType {
126 dim: crate::ImageDimension,
127 arrayed: bool,
128 class: crate::ImageClass,
129 },
130 #[error("Array stride {stride} does not match the expected {expected}")]
131 InvalidArrayStride { stride: u32, expected: u32 },
132 #[error("Field '{0}' can't be dynamically-sized, has type {1:?}")]
133 InvalidDynamicArray(String, Handle<crate::Type>),
134 #[error("The base handle {0:?} has to be a struct")]
135 BindingArrayBaseTypeNotStruct(Handle<crate::Type>),
136 #[error("Binding arrays of external textures are not yet supported")]
137 BindingArrayBaseExternalTextures,
138 #[error("Structure member[{index}] at {offset} overlaps the previous member")]
139 MemberOverlap { index: u32, offset: u32 },
140 #[error(
141 "Structure member[{index}] at {offset} and size {size} crosses the structure boundary of size {span}"
142 )]
143 MemberOutOfBounds {
144 index: u32,
145 offset: u32,
146 size: u32,
147 span: u32,
148 },
149 #[error("Structure types must have at least one member")]
150 EmptyStruct,
151 #[error(transparent)]
152 WidthError(#[from] WidthError),
153 #[error(
154 "The base handle {0:?} has an override-expression that didn't get resolved to a constant"
155 )]
156 UnresolvedOverride(Handle<crate::Type>),
157 #[error("Override-sized array type {0:?} does not have a positive size")]
158 InvalidArraySize(Handle<crate::Type>),
159}
160
161#[derive(Clone, Debug, thiserror::Error)]
162#[cfg_attr(test, derive(PartialEq))]
163pub enum WidthError {
164 #[error("The {0:?} scalar width {1} is not supported")]
165 Invalid(crate::ScalarKind, crate::Bytes),
166 #[error("Using `{name}` values requires the `naga::valid::Capabilities::{flag}` flag")]
167 MissingCapability {
168 name: &'static str,
169 flag: &'static str,
170 },
171
172 #[error("Abstract types may only appear in constant expressions")]
173 Abstract,
174}
175
176#[derive(Clone, Debug, thiserror::Error)]
177#[cfg_attr(test, derive(PartialEq))]
178pub enum ImmediateError {
179 #[error("The scalar type {0:?} is not supported in immediates")]
180 InvalidScalar(crate::Scalar),
181}
182
183type LayoutCompatibility = Result<Alignment, (Handle<crate::Type>, Disalignment)>;
185type ImmediateCompatibility = Result<(), ImmediateError>;
186
187fn check_member_layout(
188 accum: &mut LayoutCompatibility,
189 member: &crate::StructMember,
190 member_index: u32,
191 member_layout: LayoutCompatibility,
192 parent_handle: Handle<crate::Type>,
193) {
194 *accum = match (*accum, member_layout) {
195 (Ok(cur_alignment), Ok(alignment)) => {
196 if alignment.is_aligned(member.offset) {
197 Ok(cur_alignment.max(alignment))
198 } else {
199 Err((
200 parent_handle,
201 Disalignment::MemberOffset {
202 index: member_index,
203 offset: member.offset,
204 alignment,
205 },
206 ))
207 }
208 }
209 (Err(e), _) | (_, Err(e)) => Err(e),
210 };
211}
212
213const fn ptr_space_argument_flag(space: crate::AddressSpace) -> TypeFlags {
222 use crate::AddressSpace as As;
223 match space {
224 As::Function | As::Private => TypeFlags::ARGUMENT,
225 As::Uniform
226 | As::Storage { .. }
227 | As::Handle
228 | As::Immediate
229 | As::WorkGroup
230 | As::TaskPayload => TypeFlags::empty(),
231 }
232}
233
234#[derive(Clone, Debug)]
235pub(super) struct TypeInfo {
236 pub flags: TypeFlags,
237 pub uniform_layout: LayoutCompatibility,
238 pub storage_layout: LayoutCompatibility,
239 pub immediates_compatibility: ImmediateCompatibility,
240}
241
242impl TypeInfo {
243 const fn dummy() -> Self {
244 TypeInfo {
245 flags: TypeFlags::empty(),
246 uniform_layout: Ok(Alignment::ONE),
247 storage_layout: Ok(Alignment::ONE),
248 immediates_compatibility: Ok(()),
249 }
250 }
251
252 const fn new(flags: TypeFlags, alignment: Alignment) -> Self {
253 TypeInfo {
254 flags,
255 uniform_layout: Ok(alignment),
256 storage_layout: Ok(alignment),
257 immediates_compatibility: Ok(()),
258 }
259 }
260}
261
262impl super::Validator {
263 const fn require_type_capability(&self, capability: Capabilities) -> Result<(), TypeError> {
264 if self.capabilities.contains(capability) {
265 Ok(())
266 } else {
267 Err(TypeError::MissingCapability(capability))
268 }
269 }
270
271 pub(super) const fn check_width(
281 &self,
282 scalar: crate::Scalar,
283 ) -> Result<ImmediateCompatibility, WidthError> {
284 let mut immediates_compatibility = Ok(());
285 let good = match scalar.kind {
286 crate::ScalarKind::Bool => scalar.width == crate::BOOL_WIDTH,
287 crate::ScalarKind::Float => match scalar.width {
288 8 => {
289 if !self.capabilities.contains(Capabilities::FLOAT64) {
290 return Err(WidthError::MissingCapability {
291 name: "f64",
292 flag: "FLOAT64",
293 });
294 }
295 true
296 }
297 2 => {
298 if !self.capabilities.contains(Capabilities::SHADER_FLOAT16) {
299 return Err(WidthError::MissingCapability {
300 name: "f16",
301 flag: "FLOAT16",
302 });
303 }
304
305 immediates_compatibility = Err(ImmediateError::InvalidScalar(scalar));
306
307 true
308 }
309 _ => scalar.width == 4,
310 },
311 crate::ScalarKind::Sint => {
312 if scalar.width == 8 {
313 if !self.capabilities.contains(Capabilities::SHADER_INT64) {
314 return Err(WidthError::MissingCapability {
315 name: "i64",
316 flag: "SHADER_INT64",
317 });
318 }
319 true
320 } else {
321 scalar.width == 4
322 }
323 }
324 crate::ScalarKind::Uint => {
325 if scalar.width == 8 {
326 if !self.capabilities.contains(Capabilities::SHADER_INT64) {
327 return Err(WidthError::MissingCapability {
328 name: "u64",
329 flag: "SHADER_INT64",
330 });
331 }
332 true
333 } else {
334 scalar.width == 4
335 }
336 }
337 crate::ScalarKind::AbstractInt | crate::ScalarKind::AbstractFloat => {
338 return Err(WidthError::Abstract);
339 }
340 };
341 if good {
342 Ok(immediates_compatibility)
343 } else {
344 Err(WidthError::Invalid(scalar.kind, scalar.width))
345 }
346 }
347
348 pub(super) fn reset_types(&mut self, size: usize) {
349 self.types.clear();
350 self.types.resize(size, TypeInfo::dummy());
351 self.layouter.clear();
352 }
353
354 pub(super) fn validate_type(
355 &self,
356 handle: Handle<crate::Type>,
357 gctx: crate::proc::GlobalCtx,
358 ) -> Result<TypeInfo, TypeError> {
359 use crate::TypeInner as Ti;
360 Ok(match gctx.types[handle].inner {
361 Ti::Scalar(scalar) => {
362 let immediates_compatibility = self.check_width(scalar)?;
363 let shareable = if scalar.kind.is_numeric() {
364 TypeFlags::IO_SHAREABLE | TypeFlags::HOST_SHAREABLE
365 } else {
366 TypeFlags::empty()
367 };
368 let mut type_info = TypeInfo::new(
369 TypeFlags::DATA
370 | TypeFlags::SIZED
371 | TypeFlags::COPY
372 | TypeFlags::ARGUMENT
373 | TypeFlags::CONSTRUCTIBLE
374 | TypeFlags::CREATION_RESOLVED
375 | shareable,
376 Alignment::from_width(scalar.width),
377 );
378 type_info.immediates_compatibility = immediates_compatibility;
379 type_info
380 }
381 Ti::Vector { size, scalar } => {
382 let immediates_compatibility = self.check_width(scalar)?;
383 let shareable = if scalar.kind.is_numeric() {
384 TypeFlags::IO_SHAREABLE | TypeFlags::HOST_SHAREABLE
385 } else {
386 TypeFlags::empty()
387 };
388 let mut type_info = TypeInfo::new(
389 TypeFlags::DATA
390 | TypeFlags::SIZED
391 | TypeFlags::COPY
392 | TypeFlags::ARGUMENT
393 | TypeFlags::CONSTRUCTIBLE
394 | TypeFlags::CREATION_RESOLVED
395 | shareable,
396 Alignment::from(size) * Alignment::from_width(scalar.width),
397 );
398 type_info.immediates_compatibility = immediates_compatibility;
399 type_info
400 }
401 Ti::Matrix {
402 columns: _,
403 rows,
404 scalar,
405 } => {
406 if scalar.kind != crate::ScalarKind::Float {
407 return Err(TypeError::MatrixElementNotFloat);
408 }
409 let immediates_compatibility = self.check_width(scalar)?;
410 let mut type_info = TypeInfo::new(
411 TypeFlags::DATA
412 | TypeFlags::SIZED
413 | TypeFlags::COPY
414 | TypeFlags::HOST_SHAREABLE
415 | TypeFlags::ARGUMENT
416 | TypeFlags::CONSTRUCTIBLE
417 | TypeFlags::CREATION_RESOLVED,
418 Alignment::from(rows) * Alignment::from_width(scalar.width),
419 );
420 type_info.immediates_compatibility = immediates_compatibility;
421 type_info
422 }
423 Ti::CooperativeMatrix {
424 columns: _,
425 rows: _,
426 scalar,
427 role: _,
428 } => {
429 self.require_type_capability(Capabilities::COOPERATIVE_MATRIX)?;
430 if scalar.kind != crate::ScalarKind::Float
432 || (scalar.width != 2 && scalar.width != 4)
433 {
434 return Err(TypeError::MatrixElementNotFloat);
435 }
436 TypeInfo::new(
437 TypeFlags::DATA
438 | TypeFlags::SIZED
439 | TypeFlags::COPY
440 | TypeFlags::HOST_SHAREABLE
441 | TypeFlags::ARGUMENT
442 | TypeFlags::CONSTRUCTIBLE
443 | TypeFlags::CREATION_RESOLVED,
444 Alignment::from_width(scalar.width),
445 )
446 }
447 Ti::Atomic(scalar) => {
448 match scalar {
449 crate::Scalar {
450 kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint,
451 width: _,
452 } => {
453 if scalar.width == 8
454 && !self.capabilities.intersects(
455 Capabilities::SHADER_INT64_ATOMIC_ALL_OPS
456 | Capabilities::SHADER_INT64_ATOMIC_MIN_MAX,
457 )
458 {
459 return Err(TypeError::MissingCapability(
460 Capabilities::SHADER_INT64_ATOMIC_ALL_OPS,
461 ));
462 }
463 }
464 crate::Scalar::F32 => {
465 if !self
466 .capabilities
467 .contains(Capabilities::SHADER_FLOAT32_ATOMIC)
468 {
469 return Err(TypeError::MissingCapability(
470 Capabilities::SHADER_FLOAT32_ATOMIC,
471 ));
472 }
473 }
474 _ => return Err(TypeError::InvalidAtomicWidth(scalar.kind, scalar.width)),
475 };
476 TypeInfo::new(
477 TypeFlags::DATA
478 | TypeFlags::SIZED
479 | TypeFlags::HOST_SHAREABLE
480 | TypeFlags::CREATION_RESOLVED,
481 Alignment::from_width(scalar.width),
482 )
483 }
484 Ti::Pointer { base, space } => {
485 use crate::AddressSpace as As;
486
487 let base_info = &self.types[base.index()];
488 if !base_info.flags.contains(TypeFlags::DATA) {
489 return Err(TypeError::InvalidPointerBase(base));
490 }
491
492 if !base_info.flags.contains(TypeFlags::SIZED) {
504 match space {
505 As::Storage { .. } => {}
506 _ => {
507 return Err(TypeError::InvalidPointerToUnsized { base, space });
508 }
509 }
510 }
511
512 let argument_flag = ptr_space_argument_flag(space);
517
518 TypeInfo::new(
521 argument_flag
522 | TypeFlags::SIZED
523 | TypeFlags::COPY
524 | TypeFlags::CREATION_RESOLVED,
525 Alignment::ONE,
526 )
527 }
528 Ti::ValuePointer {
529 size: _,
530 scalar,
531 space,
532 } => {
533 let _ = self.check_width(scalar)?;
541
542 let argument_flag = ptr_space_argument_flag(space);
547
548 TypeInfo::new(
551 argument_flag
552 | TypeFlags::SIZED
553 | TypeFlags::COPY
554 | TypeFlags::CREATION_RESOLVED,
555 Alignment::ONE,
556 )
557 }
558 Ti::Array { base, size, stride } => {
559 let base_info = &self.types[base.index()];
560 if !base_info
561 .flags
562 .contains(TypeFlags::DATA | TypeFlags::SIZED | TypeFlags::CREATION_RESOLVED)
563 {
564 return Err(TypeError::InvalidArrayBaseType(base));
565 }
566
567 if self.overrides_resolved {
568 if let crate::ArraySize::Pending(_) = size {
571 size.resolve(gctx)
572 .map_err(|_| TypeError::InvalidArraySize(handle))?;
573 }
574 }
575
576 let base_layout = self.layouter[base];
577 let general_alignment = base_layout.alignment;
578 let uniform_layout = match base_info.uniform_layout {
579 Ok(base_alignment) => {
580 let alignment = base_alignment
581 .max(general_alignment)
582 .max(Alignment::MIN_UNIFORM);
583 if alignment.is_aligned(stride) {
584 Ok(alignment)
585 } else {
586 Err((handle, Disalignment::ArrayStride { stride, alignment }))
587 }
588 }
589 Err(e) => Err(e),
590 };
591 let storage_layout = match base_info.storage_layout {
592 Ok(base_alignment) => {
593 let alignment = base_alignment.max(general_alignment);
594 if alignment.is_aligned(stride) {
595 Ok(alignment)
596 } else {
597 Err((handle, Disalignment::ArrayStride { stride, alignment }))
598 }
599 }
600 Err(e) => Err(e),
601 };
602
603 let type_info_mask = match size {
604 crate::ArraySize::Constant(_) => {
605 TypeFlags::DATA
606 | TypeFlags::SIZED
607 | TypeFlags::COPY
608 | TypeFlags::HOST_SHAREABLE
609 | TypeFlags::ARGUMENT
610 | TypeFlags::CONSTRUCTIBLE
611 | TypeFlags::CREATION_RESOLVED
612 }
613 crate::ArraySize::Pending(_) => {
614 TypeFlags::DATA
615 | TypeFlags::SIZED
616 | TypeFlags::COPY
617 | TypeFlags::HOST_SHAREABLE
618 | TypeFlags::ARGUMENT
619 }
620 crate::ArraySize::Dynamic => {
621 TypeFlags::DATA
625 | TypeFlags::COPY
626 | TypeFlags::HOST_SHAREABLE
627 | TypeFlags::CREATION_RESOLVED
628 }
629 };
630
631 TypeInfo {
632 flags: base_info.flags & type_info_mask,
633 uniform_layout,
634 storage_layout,
635 immediates_compatibility: base_info.immediates_compatibility.clone(),
636 }
637 }
638 Ti::Struct { ref members, span } => {
639 if members.is_empty() {
640 return Err(TypeError::EmptyStruct);
641 }
642
643 let mut ti = TypeInfo::new(
644 TypeFlags::DATA
645 | TypeFlags::SIZED
646 | TypeFlags::COPY
647 | TypeFlags::HOST_SHAREABLE
648 | TypeFlags::IO_SHAREABLE
649 | TypeFlags::ARGUMENT
650 | TypeFlags::CONSTRUCTIBLE
651 | TypeFlags::CREATION_RESOLVED,
652 Alignment::ONE,
653 );
654 ti.uniform_layout = Ok(Alignment::MIN_UNIFORM);
655
656 let mut min_offset = 0;
657 let mut prev_struct_data: Option<(u32, u32)> = None;
658
659 for (i, member) in members.iter().enumerate() {
660 let base_info = &self.types[member.ty.index()];
661 if !base_info
662 .flags
663 .contains(TypeFlags::DATA | TypeFlags::CREATION_RESOLVED)
664 {
665 return Err(TypeError::InvalidData(member.ty));
666 }
667 if !base_info.flags.contains(TypeFlags::HOST_SHAREABLE) {
668 if ti.uniform_layout.is_ok() {
669 ti.uniform_layout = Err((member.ty, Disalignment::NonHostShareable));
670 }
671 if ti.storage_layout.is_ok() {
672 ti.storage_layout = Err((member.ty, Disalignment::NonHostShareable));
673 }
674 }
675 ti.flags &= base_info.flags;
676
677 if member.offset < min_offset {
678 if member.offset == 0 {
682 ti.flags.set(TypeFlags::HOST_SHAREABLE, false);
683 } else {
684 return Err(TypeError::MemberOverlap {
685 index: i as u32,
686 offset: member.offset,
687 });
688 }
689 }
690
691 let base_size = gctx.types[member.ty].inner.size(gctx);
692 min_offset = member.offset + base_size;
693 if min_offset > span {
694 return Err(TypeError::MemberOutOfBounds {
695 index: i as u32,
696 offset: member.offset,
697 size: base_size,
698 span,
699 });
700 }
701
702 check_member_layout(
703 &mut ti.uniform_layout,
704 member,
705 i as u32,
706 base_info.uniform_layout,
707 handle,
708 );
709 check_member_layout(
710 &mut ti.storage_layout,
711 member,
712 i as u32,
713 base_info.storage_layout,
714 handle,
715 );
716 if base_info.immediates_compatibility.is_err() {
717 ti.immediates_compatibility = base_info.immediates_compatibility.clone();
718 }
719
720 if let Some((span, offset)) = prev_struct_data {
724 let diff = member.offset - offset;
725 let min = Alignment::MIN_UNIFORM.round_up(span);
726 if diff < min {
727 ti.uniform_layout = Err((
728 handle,
729 Disalignment::MemberOffsetAfterStruct {
730 index: i as u32,
731 offset: member.offset,
732 expected: offset + min,
733 },
734 ));
735 }
736 };
737
738 prev_struct_data = match gctx.types[member.ty].inner {
739 crate::TypeInner::Struct { span, .. } => Some((span, member.offset)),
740 _ => None,
741 };
742
743 if !base_info.flags.contains(TypeFlags::SIZED) {
745 let is_array = match gctx.types[member.ty].inner {
746 crate::TypeInner::Array { .. } => true,
747 _ => false,
748 };
749 if !is_array || i + 1 != members.len() {
750 let name = member.name.clone().unwrap_or_default();
751 return Err(TypeError::InvalidDynamicArray(name, member.ty));
752 }
753 if ti.uniform_layout.is_ok() {
754 ti.uniform_layout =
755 Err((handle, Disalignment::UnsizedMember { index: i as u32 }));
756 }
757 }
758 }
759
760 let alignment = self.layouter[handle].alignment;
761 if !alignment.is_aligned(span) {
762 ti.uniform_layout = Err((handle, Disalignment::StructSpan { span, alignment }));
763 ti.storage_layout = Err((handle, Disalignment::StructSpan { span, alignment }));
764 }
765
766 ti
767 }
768 Ti::Image {
769 dim,
770 arrayed,
771 class,
772 } => {
773 if arrayed && matches!(dim, crate::ImageDimension::D3) {
774 return Err(TypeError::UnsupportedImageType {
775 dim,
776 arrayed,
777 class,
778 });
779 }
780 if arrayed && matches!(dim, crate::ImageDimension::Cube) {
781 self.require_type_capability(Capabilities::CUBE_ARRAY_TEXTURES)?;
782 }
783 if matches!(class, crate::ImageClass::External) {
784 if dim != crate::ImageDimension::D2 || arrayed {
785 return Err(TypeError::UnsupportedImageType {
786 dim,
787 arrayed,
788 class,
789 });
790 }
791 self.require_type_capability(Capabilities::TEXTURE_EXTERNAL)?;
792 }
793 TypeInfo::new(
794 TypeFlags::ARGUMENT | TypeFlags::CREATION_RESOLVED,
795 Alignment::ONE,
796 )
797 }
798 Ti::Sampler { .. } => TypeInfo::new(
799 TypeFlags::ARGUMENT | TypeFlags::CREATION_RESOLVED,
800 Alignment::ONE,
801 ),
802 Ti::AccelerationStructure { vertex_return } => {
803 self.require_type_capability(Capabilities::RAY_QUERY)?;
804 if vertex_return {
805 self.require_type_capability(Capabilities::RAY_HIT_VERTEX_POSITION)?;
806 }
807 TypeInfo::new(
808 TypeFlags::ARGUMENT | TypeFlags::CREATION_RESOLVED,
809 Alignment::ONE,
810 )
811 }
812 Ti::RayQuery { vertex_return } => {
813 self.require_type_capability(Capabilities::RAY_QUERY)?;
814 if vertex_return {
815 self.require_type_capability(Capabilities::RAY_HIT_VERTEX_POSITION)?;
816 }
817 TypeInfo::new(
818 TypeFlags::DATA
819 | TypeFlags::CONSTRUCTIBLE
820 | TypeFlags::SIZED
821 | TypeFlags::CREATION_RESOLVED,
822 Alignment::ONE,
823 )
824 }
825 Ti::BindingArray { base, size } => {
826 let type_info_mask = match size {
827 crate::ArraySize::Constant(_) => {
828 TypeFlags::SIZED | TypeFlags::HOST_SHAREABLE | TypeFlags::CREATION_RESOLVED
829 }
830 crate::ArraySize::Pending(_) => TypeFlags::SIZED | TypeFlags::HOST_SHAREABLE,
831 crate::ArraySize::Dynamic => {
832 TypeFlags::HOST_SHAREABLE | TypeFlags::CREATION_RESOLVED
834 }
835 };
836 let base_info = &self.types[base.index()];
837
838 if base_info.flags.contains(TypeFlags::DATA) {
839 match gctx.types[base].inner {
842 crate::TypeInner::Struct { .. } => {}
843 _ => return Err(TypeError::BindingArrayBaseTypeNotStruct(base)),
844 };
845 }
846 if matches!(
847 gctx.types[base].inner,
848 crate::TypeInner::Image {
849 class: crate::ImageClass::External,
850 ..
851 }
852 ) {
853 return Err(TypeError::BindingArrayBaseExternalTextures);
857 }
858
859 if !base_info.flags.contains(TypeFlags::CREATION_RESOLVED) {
860 return Err(TypeError::InvalidData(base));
861 }
862
863 TypeInfo::new(base_info.flags & type_info_mask, Alignment::ONE)
864 }
865 })
866 }
867}