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}
158
159#[derive(Clone, Debug, thiserror::Error)]
160#[cfg_attr(test, derive(PartialEq))]
161pub enum WidthError {
162 #[error("The {0:?} scalar width {1} is not supported")]
163 Invalid(crate::ScalarKind, crate::Bytes),
164 #[error("Using `{name}` values requires the `naga::valid::Capabilities::{flag}` flag")]
165 MissingCapability {
166 name: &'static str,
167 flag: &'static str,
168 },
169
170 #[error("Abstract types may only appear in constant expressions")]
171 Abstract,
172}
173
174#[derive(Clone, Debug, thiserror::Error)]
175#[cfg_attr(test, derive(PartialEq))]
176pub enum PushConstantError {
177 #[error("The scalar type {0:?} is not supported in push constants")]
178 InvalidScalar(crate::Scalar),
179}
180
181type LayoutCompatibility = Result<Alignment, (Handle<crate::Type>, Disalignment)>;
183type PushConstantCompatibility = Result<(), PushConstantError>;
184
185fn check_member_layout(
186 accum: &mut LayoutCompatibility,
187 member: &crate::StructMember,
188 member_index: u32,
189 member_layout: LayoutCompatibility,
190 parent_handle: Handle<crate::Type>,
191) {
192 *accum = match (*accum, member_layout) {
193 (Ok(cur_alignment), Ok(alignment)) => {
194 if alignment.is_aligned(member.offset) {
195 Ok(cur_alignment.max(alignment))
196 } else {
197 Err((
198 parent_handle,
199 Disalignment::MemberOffset {
200 index: member_index,
201 offset: member.offset,
202 alignment,
203 },
204 ))
205 }
206 }
207 (Err(e), _) | (_, Err(e)) => Err(e),
208 };
209}
210
211const fn ptr_space_argument_flag(space: crate::AddressSpace) -> TypeFlags {
220 use crate::AddressSpace as As;
221 match space {
222 As::Function | As::Private => TypeFlags::ARGUMENT,
223 As::Uniform
224 | As::Storage { .. }
225 | As::Handle
226 | As::PushConstant
227 | As::WorkGroup
228 | As::TaskPayload => TypeFlags::empty(),
229 }
230}
231
232#[derive(Clone, Debug)]
233pub(super) struct TypeInfo {
234 pub flags: TypeFlags,
235 pub uniform_layout: LayoutCompatibility,
236 pub storage_layout: LayoutCompatibility,
237 pub push_constant_compatibility: PushConstantCompatibility,
238}
239
240impl TypeInfo {
241 const fn dummy() -> Self {
242 TypeInfo {
243 flags: TypeFlags::empty(),
244 uniform_layout: Ok(Alignment::ONE),
245 storage_layout: Ok(Alignment::ONE),
246 push_constant_compatibility: Ok(()),
247 }
248 }
249
250 const fn new(flags: TypeFlags, alignment: Alignment) -> Self {
251 TypeInfo {
252 flags,
253 uniform_layout: Ok(alignment),
254 storage_layout: Ok(alignment),
255 push_constant_compatibility: Ok(()),
256 }
257 }
258}
259
260impl super::Validator {
261 const fn require_type_capability(&self, capability: Capabilities) -> Result<(), TypeError> {
262 if self.capabilities.contains(capability) {
263 Ok(())
264 } else {
265 Err(TypeError::MissingCapability(capability))
266 }
267 }
268
269 pub(super) const fn check_width(
279 &self,
280 scalar: crate::Scalar,
281 ) -> Result<PushConstantCompatibility, WidthError> {
282 let mut push_constant_compatibility = Ok(());
283 let good = match scalar.kind {
284 crate::ScalarKind::Bool => scalar.width == crate::BOOL_WIDTH,
285 crate::ScalarKind::Float => match scalar.width {
286 8 => {
287 if !self.capabilities.contains(Capabilities::FLOAT64) {
288 return Err(WidthError::MissingCapability {
289 name: "f64",
290 flag: "FLOAT64",
291 });
292 }
293 true
294 }
295 2 => {
296 if !self.capabilities.contains(Capabilities::SHADER_FLOAT16) {
297 return Err(WidthError::MissingCapability {
298 name: "f16",
299 flag: "FLOAT16",
300 });
301 }
302
303 push_constant_compatibility = Err(PushConstantError::InvalidScalar(scalar));
304
305 true
306 }
307 _ => scalar.width == 4,
308 },
309 crate::ScalarKind::Sint => {
310 if scalar.width == 8 {
311 if !self.capabilities.contains(Capabilities::SHADER_INT64) {
312 return Err(WidthError::MissingCapability {
313 name: "i64",
314 flag: "SHADER_INT64",
315 });
316 }
317 true
318 } else {
319 scalar.width == 4
320 }
321 }
322 crate::ScalarKind::Uint => {
323 if scalar.width == 8 {
324 if !self.capabilities.contains(Capabilities::SHADER_INT64) {
325 return Err(WidthError::MissingCapability {
326 name: "u64",
327 flag: "SHADER_INT64",
328 });
329 }
330 true
331 } else {
332 scalar.width == 4
333 }
334 }
335 crate::ScalarKind::AbstractInt | crate::ScalarKind::AbstractFloat => {
336 return Err(WidthError::Abstract);
337 }
338 };
339 if good {
340 Ok(push_constant_compatibility)
341 } else {
342 Err(WidthError::Invalid(scalar.kind, scalar.width))
343 }
344 }
345
346 pub(super) fn reset_types(&mut self, size: usize) {
347 self.types.clear();
348 self.types.resize(size, TypeInfo::dummy());
349 self.layouter.clear();
350 }
351
352 pub(super) fn validate_type(
353 &self,
354 handle: Handle<crate::Type>,
355 gctx: crate::proc::GlobalCtx,
356 ) -> Result<TypeInfo, TypeError> {
357 use crate::TypeInner as Ti;
358 Ok(match gctx.types[handle].inner {
359 Ti::Scalar(scalar) => {
360 let push_constant_compatibility = self.check_width(scalar)?;
361 let shareable = if scalar.kind.is_numeric() {
362 TypeFlags::IO_SHAREABLE | TypeFlags::HOST_SHAREABLE
363 } else {
364 TypeFlags::empty()
365 };
366 let mut type_info = TypeInfo::new(
367 TypeFlags::DATA
368 | TypeFlags::SIZED
369 | TypeFlags::COPY
370 | TypeFlags::ARGUMENT
371 | TypeFlags::CONSTRUCTIBLE
372 | TypeFlags::CREATION_RESOLVED
373 | shareable,
374 Alignment::from_width(scalar.width),
375 );
376 type_info.push_constant_compatibility = push_constant_compatibility;
377 type_info
378 }
379 Ti::Vector { size, scalar } => {
380 let push_constant_compatibility = self.check_width(scalar)?;
381 let shareable = if scalar.kind.is_numeric() {
382 TypeFlags::IO_SHAREABLE | TypeFlags::HOST_SHAREABLE
383 } else {
384 TypeFlags::empty()
385 };
386 let mut type_info = TypeInfo::new(
387 TypeFlags::DATA
388 | TypeFlags::SIZED
389 | TypeFlags::COPY
390 | TypeFlags::ARGUMENT
391 | TypeFlags::CONSTRUCTIBLE
392 | TypeFlags::CREATION_RESOLVED
393 | shareable,
394 Alignment::from(size) * Alignment::from_width(scalar.width),
395 );
396 type_info.push_constant_compatibility = push_constant_compatibility;
397 type_info
398 }
399 Ti::Matrix {
400 columns: _,
401 rows,
402 scalar,
403 } => {
404 if scalar.kind != crate::ScalarKind::Float {
405 return Err(TypeError::MatrixElementNotFloat);
406 }
407 let push_constant_compatibility = self.check_width(scalar)?;
408 let mut type_info = TypeInfo::new(
409 TypeFlags::DATA
410 | TypeFlags::SIZED
411 | TypeFlags::COPY
412 | TypeFlags::HOST_SHAREABLE
413 | TypeFlags::ARGUMENT
414 | TypeFlags::CONSTRUCTIBLE
415 | TypeFlags::CREATION_RESOLVED,
416 Alignment::from(rows) * Alignment::from_width(scalar.width),
417 );
418 type_info.push_constant_compatibility = push_constant_compatibility;
419 type_info
420 }
421 Ti::Atomic(scalar) => {
422 match scalar {
423 crate::Scalar {
424 kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint,
425 width: _,
426 } => {
427 if scalar.width == 8
428 && !self.capabilities.intersects(
429 Capabilities::SHADER_INT64_ATOMIC_ALL_OPS
430 | Capabilities::SHADER_INT64_ATOMIC_MIN_MAX,
431 )
432 {
433 return Err(TypeError::MissingCapability(
434 Capabilities::SHADER_INT64_ATOMIC_ALL_OPS,
435 ));
436 }
437 }
438 crate::Scalar::F32 => {
439 if !self
440 .capabilities
441 .contains(Capabilities::SHADER_FLOAT32_ATOMIC)
442 {
443 return Err(TypeError::MissingCapability(
444 Capabilities::SHADER_FLOAT32_ATOMIC,
445 ));
446 }
447 }
448 _ => return Err(TypeError::InvalidAtomicWidth(scalar.kind, scalar.width)),
449 };
450 TypeInfo::new(
451 TypeFlags::DATA
452 | TypeFlags::SIZED
453 | TypeFlags::HOST_SHAREABLE
454 | TypeFlags::CREATION_RESOLVED,
455 Alignment::from_width(scalar.width),
456 )
457 }
458 Ti::Pointer { base, space } => {
459 use crate::AddressSpace as As;
460
461 let base_info = &self.types[base.index()];
462 if !base_info.flags.contains(TypeFlags::DATA) {
463 return Err(TypeError::InvalidPointerBase(base));
464 }
465
466 if !base_info.flags.contains(TypeFlags::SIZED) {
478 match space {
479 As::Storage { .. } => {}
480 _ => {
481 return Err(TypeError::InvalidPointerToUnsized { base, space });
482 }
483 }
484 }
485
486 let argument_flag = ptr_space_argument_flag(space);
491
492 TypeInfo::new(
495 argument_flag
496 | TypeFlags::SIZED
497 | TypeFlags::COPY
498 | TypeFlags::CREATION_RESOLVED,
499 Alignment::ONE,
500 )
501 }
502 Ti::ValuePointer {
503 size: _,
504 scalar,
505 space,
506 } => {
507 let _ = self.check_width(scalar)?;
515
516 let argument_flag = ptr_space_argument_flag(space);
521
522 TypeInfo::new(
525 argument_flag
526 | TypeFlags::SIZED
527 | TypeFlags::COPY
528 | TypeFlags::CREATION_RESOLVED,
529 Alignment::ONE,
530 )
531 }
532 Ti::Array { base, size, stride } => {
533 let base_info = &self.types[base.index()];
534 if !base_info
535 .flags
536 .contains(TypeFlags::DATA | TypeFlags::SIZED | TypeFlags::CREATION_RESOLVED)
537 {
538 return Err(TypeError::InvalidArrayBaseType(base));
539 }
540
541 let base_layout = self.layouter[base];
542 let general_alignment = base_layout.alignment;
543 let uniform_layout = match base_info.uniform_layout {
544 Ok(base_alignment) => {
545 let alignment = base_alignment
546 .max(general_alignment)
547 .max(Alignment::MIN_UNIFORM);
548 if alignment.is_aligned(stride) {
549 Ok(alignment)
550 } else {
551 Err((handle, Disalignment::ArrayStride { stride, alignment }))
552 }
553 }
554 Err(e) => Err(e),
555 };
556 let storage_layout = match base_info.storage_layout {
557 Ok(base_alignment) => {
558 let alignment = base_alignment.max(general_alignment);
559 if alignment.is_aligned(stride) {
560 Ok(alignment)
561 } else {
562 Err((handle, Disalignment::ArrayStride { stride, alignment }))
563 }
564 }
565 Err(e) => Err(e),
566 };
567
568 let type_info_mask = match size {
569 crate::ArraySize::Constant(_) => {
570 TypeFlags::DATA
571 | TypeFlags::SIZED
572 | TypeFlags::COPY
573 | TypeFlags::HOST_SHAREABLE
574 | TypeFlags::ARGUMENT
575 | TypeFlags::CONSTRUCTIBLE
576 | TypeFlags::CREATION_RESOLVED
577 }
578 crate::ArraySize::Pending(_) => {
579 TypeFlags::DATA
580 | TypeFlags::SIZED
581 | TypeFlags::COPY
582 | TypeFlags::HOST_SHAREABLE
583 | TypeFlags::ARGUMENT
584 }
585 crate::ArraySize::Dynamic => {
586 TypeFlags::DATA
590 | TypeFlags::COPY
591 | TypeFlags::HOST_SHAREABLE
592 | TypeFlags::CREATION_RESOLVED
593 }
594 };
595
596 TypeInfo {
597 flags: base_info.flags & type_info_mask,
598 uniform_layout,
599 storage_layout,
600 push_constant_compatibility: base_info.push_constant_compatibility.clone(),
601 }
602 }
603 Ti::Struct { ref members, span } => {
604 if members.is_empty() {
605 return Err(TypeError::EmptyStruct);
606 }
607
608 let mut ti = TypeInfo::new(
609 TypeFlags::DATA
610 | TypeFlags::SIZED
611 | TypeFlags::COPY
612 | TypeFlags::HOST_SHAREABLE
613 | TypeFlags::IO_SHAREABLE
614 | TypeFlags::ARGUMENT
615 | TypeFlags::CONSTRUCTIBLE
616 | TypeFlags::CREATION_RESOLVED,
617 Alignment::ONE,
618 );
619 ti.uniform_layout = Ok(Alignment::MIN_UNIFORM);
620
621 let mut min_offset = 0;
622 let mut prev_struct_data: Option<(u32, u32)> = None;
623
624 for (i, member) in members.iter().enumerate() {
625 let base_info = &self.types[member.ty.index()];
626 if !base_info
627 .flags
628 .contains(TypeFlags::DATA | TypeFlags::CREATION_RESOLVED)
629 {
630 return Err(TypeError::InvalidData(member.ty));
631 }
632 if !base_info.flags.contains(TypeFlags::HOST_SHAREABLE) {
633 if ti.uniform_layout.is_ok() {
634 ti.uniform_layout = Err((member.ty, Disalignment::NonHostShareable));
635 }
636 if ti.storage_layout.is_ok() {
637 ti.storage_layout = Err((member.ty, Disalignment::NonHostShareable));
638 }
639 }
640 ti.flags &= base_info.flags;
641
642 if member.offset < min_offset {
643 if member.offset == 0 {
647 ti.flags.set(TypeFlags::HOST_SHAREABLE, false);
648 } else {
649 return Err(TypeError::MemberOverlap {
650 index: i as u32,
651 offset: member.offset,
652 });
653 }
654 }
655
656 let base_size = gctx.types[member.ty].inner.size(gctx);
657 min_offset = member.offset + base_size;
658 if min_offset > span {
659 return Err(TypeError::MemberOutOfBounds {
660 index: i as u32,
661 offset: member.offset,
662 size: base_size,
663 span,
664 });
665 }
666
667 check_member_layout(
668 &mut ti.uniform_layout,
669 member,
670 i as u32,
671 base_info.uniform_layout,
672 handle,
673 );
674 check_member_layout(
675 &mut ti.storage_layout,
676 member,
677 i as u32,
678 base_info.storage_layout,
679 handle,
680 );
681 if base_info.push_constant_compatibility.is_err() {
682 ti.push_constant_compatibility =
683 base_info.push_constant_compatibility.clone();
684 }
685
686 if let Some((span, offset)) = prev_struct_data {
690 let diff = member.offset - offset;
691 let min = Alignment::MIN_UNIFORM.round_up(span);
692 if diff < min {
693 ti.uniform_layout = Err((
694 handle,
695 Disalignment::MemberOffsetAfterStruct {
696 index: i as u32,
697 offset: member.offset,
698 expected: offset + min,
699 },
700 ));
701 }
702 };
703
704 prev_struct_data = match gctx.types[member.ty].inner {
705 crate::TypeInner::Struct { span, .. } => Some((span, member.offset)),
706 _ => None,
707 };
708
709 if !base_info.flags.contains(TypeFlags::SIZED) {
711 let is_array = match gctx.types[member.ty].inner {
712 crate::TypeInner::Array { .. } => true,
713 _ => false,
714 };
715 if !is_array || i + 1 != members.len() {
716 let name = member.name.clone().unwrap_or_default();
717 return Err(TypeError::InvalidDynamicArray(name, member.ty));
718 }
719 if ti.uniform_layout.is_ok() {
720 ti.uniform_layout =
721 Err((handle, Disalignment::UnsizedMember { index: i as u32 }));
722 }
723 }
724 }
725
726 let alignment = self.layouter[handle].alignment;
727 if !alignment.is_aligned(span) {
728 ti.uniform_layout = Err((handle, Disalignment::StructSpan { span, alignment }));
729 ti.storage_layout = Err((handle, Disalignment::StructSpan { span, alignment }));
730 }
731
732 ti
733 }
734 Ti::Image {
735 dim,
736 arrayed,
737 class,
738 } => {
739 if arrayed && matches!(dim, crate::ImageDimension::D3) {
740 return Err(TypeError::UnsupportedImageType {
741 dim,
742 arrayed,
743 class,
744 });
745 }
746 if arrayed && matches!(dim, crate::ImageDimension::Cube) {
747 self.require_type_capability(Capabilities::CUBE_ARRAY_TEXTURES)?;
748 }
749 if matches!(class, crate::ImageClass::External) {
750 if dim != crate::ImageDimension::D2 || arrayed {
751 return Err(TypeError::UnsupportedImageType {
752 dim,
753 arrayed,
754 class,
755 });
756 }
757 self.require_type_capability(Capabilities::TEXTURE_EXTERNAL)?;
758 }
759 TypeInfo::new(
760 TypeFlags::ARGUMENT | TypeFlags::CREATION_RESOLVED,
761 Alignment::ONE,
762 )
763 }
764 Ti::Sampler { .. } => TypeInfo::new(
765 TypeFlags::ARGUMENT | TypeFlags::CREATION_RESOLVED,
766 Alignment::ONE,
767 ),
768 Ti::AccelerationStructure { vertex_return } => {
769 self.require_type_capability(Capabilities::RAY_QUERY)?;
770 if vertex_return {
771 self.require_type_capability(Capabilities::RAY_HIT_VERTEX_POSITION)?;
772 }
773 TypeInfo::new(
774 TypeFlags::ARGUMENT | TypeFlags::CREATION_RESOLVED,
775 Alignment::ONE,
776 )
777 }
778 Ti::RayQuery { vertex_return } => {
779 self.require_type_capability(Capabilities::RAY_QUERY)?;
780 if vertex_return {
781 self.require_type_capability(Capabilities::RAY_HIT_VERTEX_POSITION)?;
782 }
783 TypeInfo::new(
784 TypeFlags::DATA
785 | TypeFlags::CONSTRUCTIBLE
786 | TypeFlags::SIZED
787 | TypeFlags::CREATION_RESOLVED,
788 Alignment::ONE,
789 )
790 }
791 Ti::BindingArray { base, size } => {
792 let type_info_mask = match size {
793 crate::ArraySize::Constant(_) => {
794 TypeFlags::SIZED | TypeFlags::HOST_SHAREABLE | TypeFlags::CREATION_RESOLVED
795 }
796 crate::ArraySize::Pending(_) => TypeFlags::SIZED | TypeFlags::HOST_SHAREABLE,
797 crate::ArraySize::Dynamic => {
798 TypeFlags::HOST_SHAREABLE | TypeFlags::CREATION_RESOLVED
800 }
801 };
802 let base_info = &self.types[base.index()];
803
804 if base_info.flags.contains(TypeFlags::DATA) {
805 match gctx.types[base].inner {
807 crate::TypeInner::Struct { .. } => {}
808 _ => return Err(TypeError::BindingArrayBaseTypeNotStruct(base)),
809 };
810 }
811 if matches!(
812 gctx.types[base].inner,
813 crate::TypeInner::Image {
814 class: crate::ImageClass::External,
815 ..
816 }
817 ) {
818 return Err(TypeError::BindingArrayBaseExternalTextures);
821 }
822
823 if !base_info.flags.contains(TypeFlags::CREATION_RESOLVED) {
824 return Err(TypeError::InvalidData(base));
825 }
826
827 TypeInfo::new(base_info.flags & type_info_mask, Alignment::ONE)
828 }
829 })
830 }
831}