1use itertools::Itertools;
15use num_traits::{One, ToPrimitive, Zero};
16
17use crate::{
18 CallSignature, Error, ShaderStage,
19 conv::{Convert, convert_all, convert_all_inner_to, convert_all_to, convert_all_ty},
20 f16,
21 inst::{
22 ArrayInstance, AtomicInstance, Instance, LiteralInstance, MatInstance, StructInstance,
23 VecInstance,
24 },
25 tplt::{ArrayTemplate, MatTemplate, TpltParam, VecTemplate},
26 ty::{StructType, Ty, Type},
27};
28
29type E = Error;
30
31pub fn is_ctor(name: &str) -> bool {
36 match name {
37 "array" | "bool" | "i32" | "u32" | "f32" | "f16" | "mat2x2" | "mat2x3" | "mat2x4"
38 | "mat3x2" | "mat3x3" | "mat3x4" | "mat4x2" | "mat4x3" | "mat4x4" | "vec2" | "vec3"
39 | "vec4" => true,
40 #[cfg(feature = "naga-ext")]
41 "i64" | "u64" | "f64" => true,
42 _ => false,
43 }
44}
45
46pub fn array_t(tplt_ty: &Type, tplt_n: usize, args: &[Instance]) -> Result<Instance, E> {
55 let args = args
56 .iter()
57 .map(|a| {
58 a.convert_to(tplt_ty)
59 .ok_or_else(|| E::ParamType(tplt_ty.clone(), a.ty()))
60 })
61 .collect::<Result<Vec<_>, _>>()?;
62
63 if args.len() != tplt_n {
64 return Err(E::ParamCount("array".to_string(), tplt_n, args.len()));
65 }
66
67 Ok(ArrayInstance::new(args, false).into())
68}
69
70pub fn array(args: &[Instance]) -> Result<Instance, E> {
74 if args.is_empty() {
75 return Err(E::Builtin("array constructor expects at least 1 argument"));
76 }
77
78 let args = convert_all(args).ok_or(E::Builtin("array elements are incompatible"))?;
79
80 Ok(ArrayInstance::new(args, false).into())
81}
82
83pub fn bool(a1: &Instance) -> Result<Instance, E> {
87 match a1 {
88 Instance::Literal(l) => {
89 let zero = LiteralInstance::zero_value(&l.ty())?;
90 Ok(LiteralInstance::Bool(*l != zero).into())
91 }
92 _ => Err(E::Builtin("bool constructor expects a scalar argument")),
93 }
94}
95
96pub fn i32(a1: &Instance) -> Result<Instance, E> {
100 match a1 {
101 Instance::Literal(l) => {
102 let val = match l {
103 LiteralInstance::Bool(n) => Some(n.then_some(1).unwrap_or(0)),
104 LiteralInstance::AbstractInt(n) => n.to_i32(), LiteralInstance::AbstractFloat(n) => Some(*n as i32), LiteralInstance::I32(n) => Some(*n), LiteralInstance::U32(n) => Some(*n as i32), LiteralInstance::F32(n) => Some((*n as i32).min(2147483520)), LiteralInstance::F16(n) => Some((f16::to_f32(*n) as i32).clamp(-65504, 65504)), #[cfg(feature = "naga-ext")]
111 LiteralInstance::I64(n) => n.to_i32(), #[cfg(feature = "naga-ext")]
113 LiteralInstance::U64(n) => n.to_i32(), #[cfg(feature = "naga-ext")]
115 LiteralInstance::F64(n) => Some(*n as i32), }
117 .ok_or(E::ConvOverflow(*l, Type::I32))?;
118 Ok(LiteralInstance::I32(val).into())
119 }
120 _ => Err(E::Builtin("i32 constructor expects a scalar argument")),
121 }
122}
123
124pub fn u32(a1: &Instance) -> Result<Instance, E> {
128 match a1 {
129 Instance::Literal(l) => {
130 let val = match l {
131 LiteralInstance::Bool(n) => Some(n.then_some(1).unwrap_or(0)),
132 LiteralInstance::AbstractInt(n) => n.to_u32(), LiteralInstance::AbstractFloat(n) => Some(*n as u32), LiteralInstance::I32(n) => Some(*n as u32), LiteralInstance::U32(n) => Some(*n), LiteralInstance::F32(n) => Some((*n as u32).min(4294967040)), LiteralInstance::F16(n) => Some((f16::to_f32(*n) as u32).min(65504)), #[cfg(feature = "naga-ext")]
139 LiteralInstance::I64(n) => n.to_u32(), #[cfg(feature = "naga-ext")]
141 LiteralInstance::U64(n) => n.to_u32(), #[cfg(feature = "naga-ext")]
143 LiteralInstance::F64(n) => Some(*n as u32), }
145 .ok_or(E::ConvOverflow(*l, Type::U32))?;
146 Ok(LiteralInstance::U32(val).into())
147 }
148 _ => Err(E::Builtin("u32 constructor expects a scalar argument")),
149 }
150}
151
152pub fn f32(a1: &Instance, stage: ShaderStage) -> Result<Instance, E> {
156 match a1 {
157 Instance::Literal(l) => {
158 let val = match l {
159 LiteralInstance::Bool(n) => Some(n.then_some(1f32).unwrap_or(0f32)),
160 LiteralInstance::AbstractInt(n) => Some(*n as f32), LiteralInstance::AbstractFloat(n) => {
162 let range = f32::MIN as f64..=f32::MAX as f64;
164 if stage == ShaderStage::Const && !range.contains(n) {
165 None
166 } else {
167 Some(*n as f32)
168 }
169 }
170 LiteralInstance::I32(n) => Some(*n as f32), LiteralInstance::U32(n) => Some(*n as f32), LiteralInstance::F32(n) => Some(*n), LiteralInstance::F16(n) => Some(f16::to_f32(*n)), #[cfg(feature = "naga-ext")]
175 LiteralInstance::I64(n) => Some(*n as f32), #[cfg(feature = "naga-ext")]
177 LiteralInstance::U64(n) => Some(*n as f32), #[cfg(feature = "naga-ext")]
179 LiteralInstance::F64(n) => {
180 let range = f32::MIN as f64..=f32::MAX as f64;
182 if stage == ShaderStage::Const && !range.contains(n) {
183 None
184 } else {
185 Some(*n as f32)
186 }
187 }
188 }
189 .ok_or(E::ConvOverflow(*l, Type::F32))?;
190
191 Ok(LiteralInstance::F32(val).into())
192 }
193 _ => Err(E::Builtin("f32 constructor expects a scalar argument")),
194 }
195}
196
197pub fn f16(a1: &Instance, stage: ShaderStage) -> Result<Instance, E> {
201 match a1 {
202 Instance::Literal(l) => {
203 let val = match l {
204 LiteralInstance::Bool(n) => Some(n.then_some(f16::one()).unwrap_or(f16::zero())),
205 LiteralInstance::AbstractInt(n) => {
206 let range = f16::MIN.to_i64().unwrap()..=f16::MAX.to_i64().unwrap();
208 if stage == ShaderStage::Const && !range.contains(n) {
209 None
210 } else {
211 Some(f16::from_f32(*n as f32))
212 }
213 }
214 LiteralInstance::AbstractFloat(n) => {
215 let range = f16::MIN.to_f64()..=f16::MAX.to_f64();
217 if stage == ShaderStage::Const && !range.contains(n) {
218 None
219 } else {
220 Some(f16::from_f32(*n as f32))
221 }
222 }
223 LiteralInstance::I32(n) => {
224 let range = f16::MIN.to_i32().unwrap()..=f16::MAX.to_i32().unwrap();
226 if stage == ShaderStage::Const && !range.contains(n) {
227 None
228 } else {
229 Some(f16::from_f32(*n as f32))
230 }
231 }
232 LiteralInstance::U32(n) => {
233 let range = 0..=f16::MAX.to_u32().unwrap();
235 if stage == ShaderStage::Const && !range.contains(n) {
236 None
237 } else {
238 Some(f16::from_f32(*n as f32))
239 }
240 }
241 LiteralInstance::F32(n) => {
242 let range = f16::MIN.to_f32()..=f16::MAX.to_f32();
244 if stage == ShaderStage::Const && !range.contains(n) {
245 None
246 } else {
247 Some(f16::from_f32(*n))
248 }
249 }
250 LiteralInstance::F16(n) => Some(*n), #[cfg(feature = "naga-ext")]
252 LiteralInstance::I64(n) => {
253 let range = f16::MIN.to_i64().unwrap()..=f16::MAX.to_i64().unwrap();
255 if stage == ShaderStage::Const && !range.contains(n) {
256 None
257 } else {
258 Some(f16::from_f32(*n as f32))
259 }
260 }
261 #[cfg(feature = "naga-ext")]
262 LiteralInstance::U64(n) => {
263 let range = 0..=f16::MAX.to_u64().unwrap();
265 if stage == ShaderStage::Const && !range.contains(n) {
266 None
267 } else {
268 Some(f16::from_f32(*n as f32))
269 }
270 }
271 #[cfg(feature = "naga-ext")]
272 LiteralInstance::F64(n) => {
273 let range = f16::MIN.to_f64()..=f16::MAX.to_f64();
275 if stage == ShaderStage::Const && !range.contains(n) {
276 None
277 } else {
278 Some(f16::from_f32(*n as f32))
279 }
280 }
281 }
282 .ok_or(E::ConvOverflow(*l, Type::F16))?;
283 Ok(LiteralInstance::F16(val).into())
284 }
285 _ => Err(E::Builtin("f16 constructor expects a scalar argument")),
286 }
287}
288
289#[cfg(feature = "naga-ext")]
293pub fn i64(_a1: &Instance) -> Result<Instance, E> {
294 Err(E::Todo("i64".to_string()))
295}
296
297#[cfg(feature = "naga-ext")]
301pub fn u64(_a1: &Instance) -> Result<Instance, E> {
302 Err(E::Todo("u64".to_string()))
303}
304
305#[cfg(feature = "naga-ext")]
309pub fn f64(_a1: &Instance, _stage: ShaderStage) -> Result<Instance, E> {
310 Err(E::Todo("f64".to_string()))
311}
312
313pub fn mat_t(
319 c: usize,
320 r: usize,
321 tplt_ty: &Type,
322 args: &[Instance],
323 stage: ShaderStage,
324) -> Result<Instance, E> {
325 if let [Instance::Mat(m)] = args {
327 if m.c() != c || m.r() != r {
328 return Err(E::Conversion(
329 m.ty(),
330 Type::Mat(c as u8, r as u8, Box::new(tplt_ty.clone())),
331 ));
332 }
333
334 let conv_fn = match tplt_ty {
335 Type::F32 => f32,
336 Type::F16 => f16,
337 _ => return Err(E::Builtin("matrix type must be a f32 or f16")),
338 };
339
340 let comps = m
341 .iter_cols()
342 .map(|v| {
343 v.unwrap_vec_ref()
344 .iter()
345 .map(|n| conv_fn(n, stage))
346 .collect::<Result<Vec<_>, _>>()
347 .map(|s| Instance::Vec(VecInstance::new(s)))
348 })
349 .collect::<Result<Vec<_>, _>>()?;
350
351 Ok(MatInstance::from_cols(comps).into())
352 } else {
353 let ty = args
354 .first()
355 .ok_or(E::Builtin("matrix constructor expects arguments"))?
356 .ty();
357 let ty = ty
358 .convert_inner_to(tplt_ty)
359 .ok_or(E::Conversion(ty.inner_ty(), tplt_ty.clone()))?;
360 let args =
361 convert_all_to(args, &ty).ok_or(E::Builtin("matrix components are incompatible"))?;
362
363 if let Type::Vec(n, _) = ty {
365 if n as usize != r {
366 return Err(E::Builtin(
367 "column vector dimension does not match matrix row dimension",
368 ));
369 }
370 if args.len() != c {
371 return Err(E::ParamCount(format!("mat{c}x{r}"), c, args.len()));
372 }
373
374 Ok(MatInstance::from_cols(args).into())
375 }
376 else if ty.is_float() {
378 if args.len() != c * r {
379 return Err(E::ParamCount(format!("mat{c}x{r}"), c * r, args.len()));
380 }
381
382 let args = args
383 .chunks(r)
384 .map(|v| Instance::Vec(VecInstance::new(v.to_vec())))
385 .collect_vec();
386
387 Ok(MatInstance::from_cols(args).into())
388 } else {
389 Err(E::Builtin(
390 "matrix constructor expects float or vector of float arguments",
391 ))
392 }
393 }
394}
395
396pub fn mat(c: usize, r: usize, args: &[Instance]) -> Result<Instance, E> {
400 if let [Instance::Mat(m)] = args {
402 if m.c() != c || m.r() != r {
403 let ty2 = Type::Mat(c as u8, r as u8, m.inner_ty().into());
404 return Err(E::Conversion(m.ty(), ty2));
405 }
406 Ok(m.clone().into())
408 } else {
409 if args.is_empty() {
410 return Err(E::Builtin(
411 "zero-value matrix constructor requires a template",
412 ));
413 }
414 let tys = args.iter().map(|a| a.ty()).collect_vec();
415 let ty = convert_all_ty(&tys).ok_or(E::Builtin("matrix components are incompatible"))?;
416 let mut inner_ty = ty.inner_ty();
417
418 if inner_ty.is_abstract_int() {
419 inner_ty = Type::AbstractFloat;
421 } else if !inner_ty.is_float() {
422 return Err(E::Builtin(
423 "matrix constructor expects float or vector of float arguments",
424 ));
425 }
426
427 let args = convert_all_inner_to(args, &inner_ty)
428 .ok_or(E::Builtin("matrix components are incompatible"))?;
429
430 if ty.is_vec() {
432 if args.len() != c {
433 return Err(E::ParamCount(format!("mat{c}x{r}"), c, args.len()));
434 }
435
436 Ok(MatInstance::from_cols(args).into())
437 }
438 else if ty.is_float() || ty.is_abstract_int() {
440 if args.len() != c * r {
441 return Err(E::ParamCount(format!("mat{c}x{r}"), c * r, args.len()));
442 }
443 let args = args
444 .chunks(r)
445 .map(|v| Instance::Vec(VecInstance::new(v.to_vec())))
446 .collect_vec();
447
448 Ok(MatInstance::from_cols(args).into())
449 } else {
450 Err(E::Builtin(
451 "matrix constructor expects float or vector of float arguments",
452 ))
453 }
454 }
455}
456
457pub fn vec_t(
463 n: usize,
464 tplt_ty: &Type,
465 args: &[Instance],
466 stage: ShaderStage,
467) -> Result<Instance, E> {
468 if let [Instance::Literal(l)] = args {
470 let val = l
471 .convert_to(tplt_ty)
472 .map(Instance::Literal)
473 .ok_or_else(|| E::ParamType(tplt_ty.clone(), l.ty()))?;
474 let comps = (0..n).map(|_| val.clone()).collect_vec();
475 Ok(VecInstance::new(comps).into())
476 }
477 else if let [Instance::Vec(v)] = args {
479 let ty = Type::Vec(n as u8, Box::new(tplt_ty.clone()));
480 if v.n() != n {
481 return Err(E::Conversion(v.ty(), ty));
482 }
483
484 let conv_fn = match ty.inner_ty() {
485 Type::Bool => |n, _| bool(n),
486 Type::I32 => |n, _| i32(n),
487 Type::U32 => |n, _| u32(n),
488 Type::F32 => |n, stage| f32(n, stage),
489 Type::F16 => |n, stage| f16(n, stage),
490 #[cfg(feature = "naga-ext")]
491 Type::I64 => |n, _| i64(n),
492 #[cfg(feature = "naga-ext")]
493 Type::U64 => |n, _| u64(n),
494 #[cfg(feature = "naga-ext")]
495 Type::F64 => |n, stage| f64(n, stage),
496 _ => return Err(E::Builtin("vector type must be a scalar")),
497 };
498
499 let comps = v
500 .iter()
501 .map(|n| conv_fn(n, stage))
502 .collect::<Result<Vec<_>, _>>()?;
503
504 Ok(VecInstance::new(comps).into())
505 }
506 else {
508 let args = args
510 .iter()
511 .flat_map(|a| -> Box<dyn Iterator<Item = &Instance>> {
512 match a {
513 Instance::Vec(v) => Box::new(v.iter()),
514 _ => Box::new(std::iter::once(a)),
515 }
516 })
517 .collect_vec();
518 if args.len() != n {
519 return Err(E::ParamCount(format!("vec{n}"), n, args.len()));
520 }
521
522 let comps = args
523 .iter()
524 .map(|a| {
525 a.convert_to(tplt_ty)
526 .ok_or_else(|| E::ParamType(tplt_ty.clone(), a.ty()))
527 })
528 .collect::<Result<Vec<_>, _>>()?;
529
530 Ok(VecInstance::new(comps).into())
531 }
532}
533
534pub fn vec(n: usize, args: &[Instance]) -> Result<Instance, E> {
538 if let [Instance::Literal(l)] = args {
540 let ty = l.ty();
541 if !ty.is_scalar() {
542 return Err(E::Builtin("vec constructor expects scalar arguments"));
543 }
544 let val = Instance::Literal(*l);
545 let comps = (0..n).map(|_| val.clone()).collect_vec();
546 Ok(VecInstance::new(comps).into())
547 }
548 else if let [Instance::Vec(v)] = args {
550 if v.n() != n {
551 let ty = v.ty();
552 let ty2 = Type::Vec(n as u8, ty.inner_ty().into());
553 return Err(E::Conversion(ty, ty2));
554 }
555 Ok(v.clone().into())
557 }
558 else if !args.is_empty() {
560 let args = args
562 .iter()
563 .flat_map(|a| -> Box<dyn Iterator<Item = &Instance>> {
564 match a {
565 Instance::Vec(v) => Box::new(v.iter()),
566 _ => Box::new(std::iter::once(a)),
567 }
568 })
569 .cloned()
570 .collect_vec();
571 if args.len() != n {
572 return Err(E::ParamCount(format!("vec{n}"), n, args.len()));
573 }
574
575 let comps = convert_all(&args).ok_or(E::Builtin("vector components are incompatible"))?;
576
577 if !comps.first().unwrap().ty().is_scalar() {
578 return Err(E::Builtin("vec constructor expects scalar arguments"));
579 }
580 Ok(VecInstance::new(comps).into())
581 }
582 else {
584 VecInstance::zero_value(n as u8, &Type::AbstractInt).map(Into::into)
585 }
586}
587
588pub fn struct_ctor(struct_ty: &StructType, args: &[Instance]) -> Result<StructInstance, E> {
590 if args.is_empty() {
591 return StructInstance::zero_value(struct_ty);
592 }
593
594 if args.len() != struct_ty.members.len() {
595 return Err(E::ParamCount(
596 struct_ty.name.clone(),
597 struct_ty.members.len(),
598 args.len(),
599 ));
600 }
601
602 let members = struct_ty
603 .members
604 .iter()
605 .zip(args)
606 .map(|(m_ty, inst)| {
607 let inst = inst
608 .convert_to(&m_ty.ty)
609 .ok_or_else(|| E::ParamType(m_ty.ty.clone(), inst.ty()))?;
610 Ok(inst)
611 })
612 .collect::<Result<Vec<_>, E>>()?;
613
614 Ok(StructInstance::new(struct_ty.clone(), members))
615}
616
617pub fn typecheck_struct_ctor(struct_ty: &StructType, args: &[Type]) -> Result<(), E> {
621 if args.is_empty() {
622 return Ok(());
624 }
625
626 if args.len() != struct_ty.members.len() {
627 return Err(E::ParamCount(
628 struct_ty.name.clone(),
629 struct_ty.members.len(),
630 args.len(),
631 ));
632 }
633
634 for (m_ty, a_ty) in struct_ty.members.iter().zip(args) {
635 if !a_ty.is_convertible_to(&m_ty.ty) {
636 return Err(E::ParamType(m_ty.ty.clone(), a_ty.ty()));
637 }
638 }
639
640 Ok(())
641}
642
643fn array_ctor_ty_t(tplt_ty: &Type, tplt_n: usize, args: &[Type]) -> Result<Type, E> {
653 if let Some(arg) = args.iter().find(|arg| !arg.is_convertible_to(tplt_ty)) {
654 Err(E::Conversion(arg.clone(), tplt_ty.clone()))
655 } else {
656 Ok(Type::Array(Box::new(tplt_ty.clone()), Some(tplt_n)))
657 }
658}
659
660fn array_ctor_ty(args: &[Type]) -> Result<Type, E> {
664 let ty = convert_all_ty(args).ok_or(E::Builtin("array elements are incompatible"))?;
665 Ok(Type::Array(Box::new(ty.clone()), Some(args.len())))
666}
667
668fn mat_ctor_ty_t(c: u8, r: u8, tplt_ty: &Type, args: &[Type]) -> Result<Type, E> {
674 if let [ty @ Type::Mat(c2, r2, _)] = args {
676 if *c2 != c || *r2 != r {
678 return Err(E::Conversion(
679 ty.clone(),
680 Type::Mat(c, r, Box::new(tplt_ty.clone())),
681 ));
682 }
683 } else {
684 if args.is_empty() {
685 return Err(E::Builtin("matrix constructor expects arguments"));
686 }
687 let ty = convert_all_ty(args).ok_or(E::Builtin("matrix components are incompatible"))?;
688 let ty = ty
689 .convert_inner_to(tplt_ty)
690 .ok_or(E::Conversion(ty.inner_ty(), tplt_ty.clone()))?;
691
692 if let Type::Vec(n, _) = ty {
694 if n != r {
695 return Err(E::Builtin(
696 "column vector dimension does not match matrix row dimension",
697 ));
698 }
699 if args.len() != c as usize {
700 return Err(E::ParamCount(format!("mat{c}x{r}"), c as usize, args.len()));
701 }
702 }
703 else if ty.is_float() {
705 let n = c as usize * r as usize;
706 if args.len() != n {
707 return Err(E::ParamCount(format!("mat{c}x{r}"), n, args.len()));
708 }
709 } else {
710 return Err(E::Builtin(
711 "matrix constructor expects float or vector of float arguments",
712 ));
713 }
714 }
715
716 Ok(Type::Mat(c, r, Box::new(tplt_ty.clone())))
717}
718
719fn mat_ctor_ty(c: u8, r: u8, args: &[Type]) -> Result<Type, E> {
723 if let [ty @ Type::Mat(c2, r2, ty2)] = args {
725 if *c2 != c || *r2 != r {
727 return Err(E::Conversion(ty.clone(), Type::Mat(c, r, ty2.clone())));
728 }
729 Ok(ty.clone())
730 } else {
731 if args.is_empty() {
732 return Err(E::Builtin(
733 "zero-value matrix constructor requires a template",
734 ));
735 }
736 let ty = convert_all_ty(args).ok_or(E::Builtin("matrix components are incompatible"))?;
737 let mut inner_ty = ty.inner_ty();
738
739 if inner_ty.is_abstract_int() {
740 inner_ty = Type::AbstractFloat;
742 } else if !inner_ty.is_float() {
743 return Err(E::Builtin(
744 "matrix constructor expects float or vector of float arguments",
745 ));
746 }
747
748 if ty.is_vec() {
750 if args.len() != c as usize {
751 return Err(E::ParamCount(format!("mat{c}x{r}"), c as usize, args.len()));
752 }
753 }
754 else if ty.is_float() || ty.is_abstract_int() {
756 let n = c as usize * r as usize;
757 if args.len() != n {
758 return Err(E::ParamCount(format!("mat{c}x{r}"), n, args.len()));
759 }
760 } else {
761 return Err(E::Builtin(
762 "matrix constructor expects float or vector of float arguments",
763 ));
764 }
765
766 Ok(Type::Mat(c, r, inner_ty.into()))
767 }
768}
769
770fn vec_ctor_ty_t(n: u8, tplt_ty: &Type, args: &[Type]) -> Result<Type, E> {
776 if let [arg] = args {
777 if arg.is_scalar() {
779 if !arg.is_convertible_to(tplt_ty) {
780 return Err(E::Conversion(arg.clone(), tplt_ty.clone()));
781 }
782 }
783 else if let Type::Vec(arg_n, _) = arg
785 && n == *arg_n
786 {
787 } else {
789 return Err(E::Conversion(arg.clone(), tplt_ty.clone()));
790 }
791 }
792 else {
794 let n2 = args
796 .iter()
797 .try_fold(0, |acc, arg| match arg {
798 ty if ty.is_scalar() => ty.is_convertible_to(tplt_ty).then_some(acc + 1),
799 Type::Vec(n, ty) => ty.is_convertible_to(tplt_ty).then_some(acc + n),
800 _ => None,
801 })
802 .ok_or(E::Builtin(
803 "vector constructor expects scalar or vector arguments",
804 ))?;
805 if n2 != n {
806 return Err(E::ParamCount(format!("vec{n}"), n as usize, args.len()));
807 }
808 }
809
810 Ok(Type::Vec(n, Box::new(tplt_ty.clone())))
811}
812
813fn vec_ctor_ty(n: u8, args: &[Type]) -> Result<Type, E> {
817 if let [arg] = args {
818 if arg.is_scalar() {
820 }
821 else if let Type::Vec(arg_n, _) = arg
823 && n == *arg_n
824 {
825 } else {
827 return Err(E::Builtin(
828 "vector constructor expects scalar or vector arguments",
829 ));
830 }
831 Ok(Type::Vec(n, arg.inner_ty().into()))
832 }
833 else if !args.is_empty() {
835 let n2 = args
837 .iter()
838 .try_fold(0, |acc, arg| match arg {
839 ty if ty.is_scalar() => Some(acc + 1),
840 Type::Vec(n, _) => Some(acc + n),
841 _ => None,
842 })
843 .ok_or(E::Builtin(
844 "vector constructor expects scalar or vector arguments",
845 ))?;
846 if n2 != n {
847 return Err(E::ParamCount(format!("vec{n}"), n as usize, args.len()));
848 }
849
850 let tys = args.iter().map(|arg| arg.inner_ty()).collect_vec();
851 let ty = convert_all_ty(&tys).ok_or(E::Builtin("vector components are incompatible"))?;
852
853 Ok(Type::Vec(n, ty.clone().into()))
854 }
855 else {
857 Ok(Type::Vec(n, Type::AbstractInt.into()))
858 }
859}
860
861pub fn type_ctor(name: &str, tplt: Option<&[TpltParam]>, args: &[Type]) -> Result<Type, E> {
869 match (name, tplt, args) {
870 ("array", Some(t), []) => {
871 let tplt = ArrayTemplate::parse(t)?;
872 tplt.n()
873 .is_some()
874 .then(|| tplt.ty())
875 .ok_or(E::TemplateArgs("array"))
876 }
877 ("array", Some(t), a) => {
878 let tplt = ArrayTemplate::parse(t)?;
879 array_ctor_ty_t(
880 &tplt.inner_ty(),
881 tplt.n().ok_or(E::TemplateArgs("array"))?,
882 a,
883 )
884 }
885 ("array", None, _) => array_ctor_ty(args),
886 ("bool", None, []) => Ok(Type::Bool),
887 ("bool", None, [a]) if a.is_scalar() => Ok(Type::Bool),
888 ("i32", None, []) => Ok(Type::I32),
889 ("i32", None, [a]) if a.is_scalar() => Ok(Type::I32),
890 ("u32", None, []) => Ok(Type::U32),
891 ("u32", None, [a]) if a.is_scalar() => Ok(Type::U32),
892 ("f32", None, []) => Ok(Type::F32),
893 ("f32", None, [a]) if a.is_scalar() => Ok(Type::F32),
894 ("f16", None, []) => Ok(Type::F16),
895 ("f16", None, [a]) if a.is_scalar() => Ok(Type::F16),
896 ("mat2x2", Some(t), []) => Ok(MatTemplate::parse(t)?.ty(2, 2)),
897 ("mat2x2", Some(t), _) => mat_ctor_ty_t(2, 2, MatTemplate::parse(t)?.inner_ty(), args),
898 ("mat2x2", None, _) => mat_ctor_ty(2, 2, args),
899 ("mat2x3", Some(t), []) => Ok(MatTemplate::parse(t)?.ty(2, 3)),
900 ("mat2x3", Some(t), _) => mat_ctor_ty_t(2, 3, MatTemplate::parse(t)?.inner_ty(), args),
901 ("mat2x3", None, _) => mat_ctor_ty(2, 3, args),
902 ("mat2x4", Some(t), []) => Ok(MatTemplate::parse(t)?.ty(2, 4)),
903 ("mat2x4", Some(t), _) => mat_ctor_ty_t(2, 4, MatTemplate::parse(t)?.inner_ty(), args),
904 ("mat2x4", None, _) => mat_ctor_ty(2, 4, args),
905 ("mat3x2", Some(t), []) => Ok(MatTemplate::parse(t)?.ty(3, 2)),
906 ("mat3x2", Some(t), _) => mat_ctor_ty_t(3, 2, MatTemplate::parse(t)?.inner_ty(), args),
907 ("mat3x2", None, _) => mat_ctor_ty(3, 2, args),
908 ("mat3x3", Some(t), []) => Ok(MatTemplate::parse(t)?.ty(3, 3)),
909 ("mat3x3", Some(t), _) => mat_ctor_ty_t(3, 3, MatTemplate::parse(t)?.inner_ty(), args),
910 ("mat3x3", None, _) => mat_ctor_ty(3, 3, args),
911 ("mat3x4", Some(t), []) => Ok(MatTemplate::parse(t)?.ty(3, 4)),
912 ("mat3x4", Some(t), _) => mat_ctor_ty_t(3, 4, MatTemplate::parse(t)?.inner_ty(), args),
913 ("mat3x4", None, _) => mat_ctor_ty(3, 4, args),
914 ("mat4x2", Some(t), []) => Ok(MatTemplate::parse(t)?.ty(4, 2)),
915 ("mat4x2", Some(t), _) => mat_ctor_ty_t(4, 2, MatTemplate::parse(t)?.inner_ty(), args),
916 ("mat4x2", None, _) => mat_ctor_ty(4, 2, args),
917 ("mat4x3", Some(t), []) => Ok(MatTemplate::parse(t)?.ty(4, 3)),
918 ("mat4x3", Some(t), _) => mat_ctor_ty_t(4, 3, MatTemplate::parse(t)?.inner_ty(), args),
919 ("mat4x3", None, _) => mat_ctor_ty(4, 3, args),
920 ("mat4x4", Some(t), []) => Ok(MatTemplate::parse(t)?.ty(4, 4)),
921 ("mat4x4", Some(t), _) => mat_ctor_ty_t(4, 4, MatTemplate::parse(t)?.inner_ty(), args),
922 ("mat4x4", None, _) => mat_ctor_ty(4, 4, args),
923 ("vec2", Some(t), []) => Ok(VecTemplate::parse(t)?.ty(2)),
924 ("vec2", Some(t), _) => vec_ctor_ty_t(2, VecTemplate::parse(t)?.inner_ty(), args),
925 ("vec2", None, _) => vec_ctor_ty(2, args),
926 ("vec3", Some(t), []) => Ok(VecTemplate::parse(t)?.ty(3)),
927 ("vec3", Some(t), _) => vec_ctor_ty_t(3, VecTemplate::parse(t)?.inner_ty(), args),
928 ("vec3", None, _) => vec_ctor_ty(3, args),
929 ("vec4", Some(t), []) => Ok(VecTemplate::parse(t)?.ty(4)),
930 ("vec4", Some(t), _) => vec_ctor_ty_t(4, VecTemplate::parse(t)?.inner_ty(), args),
931 ("vec4", None, _) => vec_ctor_ty(4, args),
932 #[cfg(feature = "naga-ext")]
933 ("i64", None, []) => Ok(Type::I64),
934 #[cfg(feature = "naga-ext")]
935 ("i64", None, [a]) if a.is_scalar() => Ok(Type::I64),
936 #[cfg(feature = "naga-ext")]
937 ("u64", None, []) => Ok(Type::U64),
938 #[cfg(feature = "naga-ext")]
939 ("u64", None, [a]) if a.is_scalar() => Ok(Type::U64),
940 #[cfg(feature = "naga-ext")]
941 ("f64", None, []) => Ok(Type::F64),
942 #[cfg(feature = "naga-ext")]
943 ("f64", None, [a]) if a.is_scalar() => Ok(Type::F64),
944 _ => Err(E::Signature(CallSignature {
945 name: name.to_string(),
946 tplt: tplt.map(|t| t.to_vec()),
947 args: args.to_vec(),
948 })),
949 }
950}
951
952impl Instance {
958 pub fn zero_value(ty: &Type) -> Result<Self, E> {
960 match ty {
961 Type::Bool
962 | Type::AbstractInt
963 | Type::AbstractFloat
964 | Type::I32
965 | Type::U32
966 | Type::F32
967 | Type::F16 => LiteralInstance::zero_value(ty).map(Into::into),
968 Type::Struct(s) => StructInstance::zero_value(s).map(Into::into),
969 Type::Array(a_ty, Some(n)) => ArrayInstance::zero_value(a_ty, *n).map(Into::into),
970 Type::Array(_, None) => Err(E::NotConstructible(ty.clone())),
971 Type::Vec(n, v_ty) => VecInstance::zero_value(*n, v_ty).map(Into::into),
972 Type::Mat(c, r, m_ty) => MatInstance::zero_value(*c, *r, m_ty).map(Into::into),
973 Type::Atomic(_)
974 | Type::Ptr(_, _, _)
975 | Type::Ref(_, _, _)
976 | Type::Texture(_)
977 | Type::Sampler(_)
978 | Type::Unknown => Err(E::NotConstructible(ty.clone())),
979
980 #[cfg(feature = "naga-ext")]
981 Type::I64 | Type::U64 | Type::F64 => LiteralInstance::zero_value(ty).map(Into::into),
982 #[cfg(feature = "naga-ext")]
983 Type::BindingArray(_, _) | Type::RayQuery(_) | Type::AccelerationStructure(_) => {
984 Err(E::NotConstructible(ty.clone()))
985 }
986 }
987 }
988
989 pub fn storable_zero_value(ty: &Type) -> Result<Self, E> {
1001 match ty {
1002 Type::Struct(s) => StructInstance::storable_zero_value(s).map(Into::into),
1003 Type::Array(a_ty, Some(n)) => {
1004 ArrayInstance::storable_zero_value(a_ty, *n).map(Into::into)
1005 }
1006 Type::Atomic(a_ty) => AtomicInstance::storable_zero_value(a_ty).map(Into::into),
1007 _ => Self::zero_value(ty),
1008 }
1009 }
1010}
1011
1012impl LiteralInstance {
1013 pub fn zero_value(ty: &Type) -> Result<Self, E> {
1015 match ty {
1016 Type::Bool => Ok(LiteralInstance::Bool(false)),
1017 Type::AbstractInt => Ok(LiteralInstance::AbstractInt(0)),
1018 Type::AbstractFloat => Ok(LiteralInstance::AbstractFloat(0.0)),
1019 Type::I32 => Ok(LiteralInstance::I32(0)),
1020 Type::U32 => Ok(LiteralInstance::U32(0)),
1021 Type::F32 => Ok(LiteralInstance::F32(0.0)),
1022 Type::F16 => Ok(LiteralInstance::F16(f16::zero())),
1023 #[cfg(feature = "naga-ext")]
1024 Type::I64 => Ok(LiteralInstance::I64(0)),
1025 #[cfg(feature = "naga-ext")]
1026 Type::U64 => Ok(LiteralInstance::U64(0)),
1027 #[cfg(feature = "naga-ext")]
1028 Type::F64 => Ok(LiteralInstance::F64(0.0)),
1029 _ => Err(E::NotScalar(ty.clone())),
1030 }
1031 }
1032}
1033
1034impl StructInstance {
1035 pub fn zero_value(s: &StructType) -> Result<Self, E> {
1037 let members = s
1038 .members
1039 .iter()
1040 .map(|mem| {
1041 let val = Instance::zero_value(&mem.ty)?;
1042 Ok(val)
1043 })
1044 .collect::<Result<Vec<_>, _>>()?;
1045
1046 Ok(StructInstance::new(s.clone(), members))
1047 }
1048
1049 pub fn storable_zero_value(s: &StructType) -> Result<Self, E> {
1051 let members = s
1052 .members
1053 .iter()
1054 .map(|mem| {
1055 let val = Instance::storable_zero_value(&mem.ty)?;
1056 Ok(val)
1057 })
1058 .collect::<Result<Vec<_>, _>>()?;
1059
1060 Ok(StructInstance::new(s.clone(), members))
1061 }
1062}
1063
1064impl ArrayInstance {
1065 pub fn zero_value(ty: &Type, n: usize) -> Result<Self, E> {
1067 let zero = Instance::zero_value(ty)?;
1068 let comps = (0..n).map(|_| zero.clone()).collect_vec();
1069 Ok(ArrayInstance::new(comps, false))
1070 }
1071
1072 pub fn storable_zero_value(ty: &Type, n: usize) -> Result<Self, E> {
1074 let zero = Instance::storable_zero_value(ty)?;
1075 let comps = (0..n).map(|_| zero.clone()).collect_vec();
1076 Ok(ArrayInstance::new(comps, false))
1077 }
1078}
1079
1080impl VecInstance {
1081 pub fn zero_value(n: u8, ty: &Type) -> Result<Self, E> {
1083 let zero = Instance::Literal(LiteralInstance::zero_value(ty)?);
1084 let comps = (0..n).map(|_| zero.clone()).collect_vec();
1085 Ok(VecInstance::new(comps))
1086 }
1087}
1088
1089impl MatInstance {
1090 pub fn zero_value(c: u8, r: u8, ty: &Type) -> Result<Self, E> {
1092 let zero = Instance::Literal(LiteralInstance::zero_value(ty)?);
1093 let zero_col = Instance::Vec(VecInstance::new((0..r).map(|_| zero.clone()).collect_vec()));
1094 let comps = (0..c).map(|_| zero_col.clone()).collect_vec();
1095 Ok(MatInstance::from_cols(comps))
1096 }
1097}
1098
1099impl AtomicInstance {
1100 pub fn storable_zero_value(ty: &Type) -> Result<Self, E> {
1102 let zero = Instance::zero_value(ty)?;
1103 Ok(AtomicInstance::new(zero))
1104 }
1105}