Skip to main content

naga/proc/
constant_evaluator.rs

1// Code in this file intentionally uses `for` loops and `.push()` rather than
2// `ArrayVec::from_iter`, because the latter is monomorphized by all three of
3// the item type, the capacity, and the iterator type, which can easily bloat
4// the compiled executable (by ~260 KiB, when it was removed).
5
6use alloc::{
7    format,
8    string::{String, ToString},
9    vec,
10    vec::Vec,
11};
12use core::iter;
13
14use arrayvec::ArrayVec;
15use half::f16;
16use num_traits::{real::Real, FromPrimitive, One, ToPrimitive, Zero};
17
18use crate::{
19    arena::{Arena, Handle, HandleVec, UniqueArena},
20    ArraySize, BinaryOperator, Constant, Expression, Literal, Override, RelationalFunction,
21    ScalarKind, Span, Type, TypeInner, UnaryOperator,
22};
23
24#[cfg(feature = "wgsl-in")]
25use crate::common::wgsl::TryToWgsl;
26
27/// A macro that allows dollar signs (`$`) to be emitted by other macros. Useful for generating
28/// `macro_rules!` items that, in turn, emit their own `macro_rules!` items.
29///
30/// Technique stolen directly from
31/// <https://github.com/rust-lang/rust/issues/35853#issuecomment-415993963>.
32macro_rules! with_dollar_sign {
33    ($($body:tt)*) => {
34        macro_rules! __with_dollar_sign { $($body)* }
35        __with_dollar_sign!($);
36    }
37}
38
39macro_rules! gen_component_wise_extractor {
40    (
41        $ident:ident -> $target:ident,
42        literals: [$( $literal:ident => $mapping:ident: $ty:ident ),+ $(,)?],
43        scalar_kinds: [$( $scalar_kind:ident ),* $(,)?],
44    ) => {
45        /// A subset of [`Literal`]s intended to be used for implementing numeric built-ins.
46        #[derive(Debug)]
47        #[cfg_attr(test, derive(PartialEq))]
48        enum $target<const N: usize> {
49            $(
50                #[doc = concat!(
51                    "Maps to [`Literal::",
52                    stringify!($literal),
53                    "`]",
54                )]
55                $mapping([$ty; N]),
56            )+
57        }
58
59        impl From<$target<1>> for Expression {
60            fn from(value: $target<1>) -> Self {
61                match value {
62                    $(
63                        $target::$mapping([value]) => {
64                            Expression::Literal(Literal::$literal(value))
65                        }
66                    )+
67                }
68            }
69        }
70
71        #[doc = concat!(
72            "Attempts to evaluate multiple `exprs` as a combined [`",
73            stringify!($target),
74            "`] to pass to `handler`. ",
75        )]
76        /// If `exprs` are vectors of the same length, `handler` is called for each corresponding
77        /// component of each vector.
78        ///
79        /// `handler`'s output is registered as a new expression. If `exprs` are vectors of the
80        /// same length, a new vector expression is registered, composed of each component emitted
81        /// by `handler`.
82        fn $ident<const N: usize, const M: usize>(
83            eval: &mut ConstantEvaluator<'_>,
84            span: Span,
85            exprs: [Handle<Expression>; N],
86            handler: fn($target<N>) -> Result<$target<M>, ConstantEvaluatorError>,
87        ) -> Result<Handle<Expression>, ConstantEvaluatorError>
88        where
89            $target<M>: Into<Expression>,
90        {
91            assert!(N > 0);
92            let err = ConstantEvaluatorError::InvalidMathArg;
93            let mut exprs = exprs.into_iter();
94
95            macro_rules! sanitize {
96                ($expr:expr) => {
97                    eval.eval_zero_value_and_splat($expr, span)
98                        .map(|expr| &eval.expressions[expr])
99                };
100            }
101
102            let new_expr: Result<Expression, ConstantEvaluatorError> = match sanitize!(exprs.next().unwrap())? {
103                $(
104                    &Expression::Literal(Literal::$literal(x)) => {
105                        let mut arr = ArrayVec::<_, N>::new();
106                        arr.push(x);
107                        for expr in exprs {
108                            match sanitize!(expr)? {
109                                &Expression::Literal(Literal::$literal(val)) => arr.push(val),
110                                _ => return Err(err),
111                            }
112                        }
113                        let comps = $target::$mapping(arr.into_inner().unwrap());
114                        Ok(handler(comps)?.into())
115                    },
116                )+
117                &Expression::Compose { ty, ref components } => match &eval.types[ty].inner {
118                    &TypeInner::Vector { size, scalar } => match scalar.kind {
119                        $(ScalarKind::$scalar_kind)|* => {
120                            let first_ty = ty;
121                            let mut component_groups =
122                                ArrayVec::<ArrayVec<_, { crate::VectorSize::MAX }>, N>::new();
123                            {
124                                let mut inner = ArrayVec::new();
125                                for item in crate::proc::flatten_compose(
126                                    first_ty,
127                                    components,
128                                    eval.expressions,
129                                    eval.types,
130                                ) {
131                                    inner.push(item);
132                                }
133                                component_groups.push(inner);
134                            }
135                            for expr in exprs {
136                                match sanitize!(expr)? {
137                                    &Expression::Compose { ty, ref components }
138                                        if &eval.types[ty].inner
139                                            == &eval.types[first_ty].inner =>
140                                    {
141                                        let mut inner = ArrayVec::new();
142                                        for item in crate::proc::flatten_compose(
143                                            ty,
144                                            components,
145                                            eval.expressions,
146                                            eval.types,
147                                        ) {
148                                            inner.push(item);
149                                        }
150                                        component_groups.push(inner);
151                                    }
152                                    _ => return Err(err),
153                                }
154                            }
155                            let component_groups = component_groups.into_inner().unwrap();
156                            let mut new_components =
157                                ArrayVec::<_, { crate::VectorSize::MAX }>::new();
158                            for idx in 0..(size as u8).into() {
159                                let mut group_arr = ArrayVec::<_, N>::new();
160                                for cs in component_groups.iter() {
161                                    group_arr.push(
162                                        cs.get(idx).cloned().ok_or_else(|| err.clone())?,
163                                    );
164                                }
165                                let group = group_arr.into_inner().unwrap();
166                                new_components.push($ident(
167                                    eval,
168                                    span,
169                                    group,
170                                    handler,
171                                )?);
172                            }
173                            Ok(Expression::Compose {
174                                ty: first_ty,
175                                components: new_components.into_iter().collect(),
176                            })
177                        }
178                        _ => return Err(err),
179                    },
180                    _ => return Err(err),
181                },
182                _ => return Err(err),
183            };
184            eval.register_evaluated_expr(new_expr?, span)
185        }
186
187        with_dollar_sign! {
188            ($d:tt) => {
189                #[allow(unused)]
190                #[doc = concat!(
191                    "A convenience macro for using the same RHS for each [`",
192                    stringify!($target),
193                    "`] variant in a call to [`",
194                    stringify!($ident),
195                    "`].",
196                )]
197                macro_rules! $ident {
198                    (
199                        $eval:expr,
200                        $span:expr,
201                        [$d ($d expr:expr),+ $d (,)?],
202                        |$d ($d arg:ident),+| $d tt:tt
203                    ) => {
204                        $ident($eval, $span, [$d ($d expr),+], |args| match args {
205                            $(
206                                $target::$mapping([$d ($d arg),+]) => {
207                                    let res = $d tt;
208                                    Result::map(res, $target::$mapping)
209                                },
210                            )+
211                        })
212                    };
213                }
214            };
215        }
216    };
217}
218
219gen_component_wise_extractor! {
220    component_wise_scalar -> Scalar,
221    literals: [
222        AbstractFloat => AbstractFloat: f64,
223        F32 => F32: f32,
224        F16 => F16: f16,
225        AbstractInt => AbstractInt: i64,
226        U32 => U32: u32,
227        I32 => I32: i32,
228        U64 => U64: u64,
229        I64 => I64: i64,
230    ],
231    scalar_kinds: [
232        Float,
233        AbstractFloat,
234        Sint,
235        Uint,
236        AbstractInt,
237    ],
238}
239
240gen_component_wise_extractor! {
241    component_wise_float -> Float,
242    literals: [
243        AbstractFloat => Abstract: f64,
244        F32 => F32: f32,
245        F16 => F16: f16,
246    ],
247    scalar_kinds: [
248        Float,
249        AbstractFloat,
250    ],
251}
252
253gen_component_wise_extractor! {
254    component_wise_concrete_int -> ConcreteInt,
255    literals: [
256        U32 => U32: u32,
257        I32 => I32: i32,
258    ],
259    scalar_kinds: [
260        Sint,
261        Uint,
262    ],
263}
264
265gen_component_wise_extractor! {
266    component_wise_signed -> Signed,
267    literals: [
268        AbstractFloat => AbstractFloat: f64,
269        AbstractInt => AbstractInt: i64,
270        F32 => F32: f32,
271        F16 => F16: f16,
272        I32 => I32: i32,
273    ],
274    scalar_kinds: [
275        Sint,
276        AbstractInt,
277        Float,
278        AbstractFloat,
279    ],
280}
281
282/// Vectors with a concrete element type.
283#[derive(Debug)]
284enum LiteralVector {
285    F64(ArrayVec<f64, { crate::VectorSize::MAX }>),
286    F32(ArrayVec<f32, { crate::VectorSize::MAX }>),
287    F16(ArrayVec<f16, { crate::VectorSize::MAX }>),
288    U16(ArrayVec<u16, { crate::VectorSize::MAX }>),
289    I16(ArrayVec<i16, { crate::VectorSize::MAX }>),
290    U32(ArrayVec<u32, { crate::VectorSize::MAX }>),
291    I32(ArrayVec<i32, { crate::VectorSize::MAX }>),
292    U64(ArrayVec<u64, { crate::VectorSize::MAX }>),
293    I64(ArrayVec<i64, { crate::VectorSize::MAX }>),
294    Bool(ArrayVec<bool, { crate::VectorSize::MAX }>),
295    AbstractInt(ArrayVec<i64, { crate::VectorSize::MAX }>),
296    AbstractFloat(ArrayVec<f64, { crate::VectorSize::MAX }>),
297}
298
299impl LiteralVector {
300    #[allow(clippy::missing_const_for_fn, reason = "MSRV")]
301    fn len(&self) -> usize {
302        match *self {
303            LiteralVector::F64(ref v) => v.len(),
304            LiteralVector::F32(ref v) => v.len(),
305            LiteralVector::F16(ref v) => v.len(),
306            LiteralVector::U16(ref v) => v.len(),
307            LiteralVector::I16(ref v) => v.len(),
308            LiteralVector::U32(ref v) => v.len(),
309            LiteralVector::I32(ref v) => v.len(),
310            LiteralVector::U64(ref v) => v.len(),
311            LiteralVector::I64(ref v) => v.len(),
312            LiteralVector::Bool(ref v) => v.len(),
313            LiteralVector::AbstractInt(ref v) => v.len(),
314            LiteralVector::AbstractFloat(ref v) => v.len(),
315        }
316    }
317
318    /// Creates [`LiteralVector`] of size 1 from single [`Literal`]
319    fn from_literal(literal: Literal) -> Self {
320        fn arrayvec_of<T, const N: usize>(val: T) -> ArrayVec<T, N> {
321            let mut v = ArrayVec::new();
322            v.push(val);
323            v
324        }
325        match literal {
326            Literal::F64(e) => Self::F64(arrayvec_of(e)),
327            Literal::F32(e) => Self::F32(arrayvec_of(e)),
328            Literal::U16(e) => Self::U16(arrayvec_of(e)),
329            Literal::I16(e) => Self::I16(arrayvec_of(e)),
330            Literal::U32(e) => Self::U32(arrayvec_of(e)),
331            Literal::I32(e) => Self::I32(arrayvec_of(e)),
332            Literal::U64(e) => Self::U64(arrayvec_of(e)),
333            Literal::I64(e) => Self::I64(arrayvec_of(e)),
334            Literal::Bool(e) => Self::Bool(arrayvec_of(e)),
335            Literal::AbstractInt(e) => Self::AbstractInt(arrayvec_of(e)),
336            Literal::AbstractFloat(e) => Self::AbstractFloat(arrayvec_of(e)),
337            Literal::F16(e) => Self::F16(arrayvec_of(e)),
338        }
339    }
340
341    /// Creates [`LiteralVector`] from [`ArrayVec`] of [`Literal`]s.
342    /// Returns error if components types do not match.
343    /// # Panics
344    /// Panics if vector is empty
345    fn from_literal_vec(
346        components: ArrayVec<Literal, { crate::VectorSize::MAX }>,
347    ) -> Result<Self, ConstantEvaluatorError> {
348        assert!(!components.is_empty());
349        // TODO: should a vector of i32 be constructible from abstract int?
350        macro_rules! compose_literals {
351            ($components:expr, $variant:ident, $self_variant:ident) => {{
352                let mut out = ArrayVec::new();
353                for l in &$components {
354                    match l {
355                        &Literal::$variant(v) => out.push(v),
356                        _ => return Err(ConstantEvaluatorError::InvalidMathArg),
357                    }
358                }
359                Self::$self_variant(out)
360            }};
361        }
362        Ok(match components[0] {
363            Literal::I16(_) => compose_literals!(components, I16, I16),
364            Literal::U16(_) => compose_literals!(components, U16, U16),
365            Literal::I32(_) => compose_literals!(components, I32, I32),
366            Literal::U32(_) => compose_literals!(components, U32, U32),
367            Literal::I64(_) => compose_literals!(components, I64, I64),
368            Literal::U64(_) => compose_literals!(components, U64, U64),
369            Literal::F32(_) => compose_literals!(components, F32, F32),
370            Literal::F64(_) => compose_literals!(components, F64, F64),
371            Literal::Bool(_) => compose_literals!(components, Bool, Bool),
372            Literal::AbstractInt(_) => compose_literals!(components, AbstractInt, AbstractInt),
373            Literal::AbstractFloat(_) => {
374                compose_literals!(components, AbstractFloat, AbstractFloat)
375            }
376            Literal::F16(_) => compose_literals!(components, F16, F16),
377        })
378    }
379
380    #[allow(dead_code)]
381    /// Returns [`ArrayVec`] of [`Literal`]s
382    fn to_literal_vec(&self) -> ArrayVec<Literal, { crate::VectorSize::MAX }> {
383        macro_rules! decompose_literals {
384            ($v:expr, $variant:ident) => {{
385                let mut out = ArrayVec::new();
386                for e in $v {
387                    out.push(Literal::$variant(*e));
388                }
389                out
390            }};
391        }
392        match *self {
393            LiteralVector::F64(ref v) => decompose_literals!(v, F64),
394            LiteralVector::F32(ref v) => decompose_literals!(v, F32),
395            LiteralVector::F16(ref v) => decompose_literals!(v, F16),
396            LiteralVector::U16(ref v) => decompose_literals!(v, U16),
397            LiteralVector::I16(ref v) => decompose_literals!(v, I16),
398            LiteralVector::U32(ref v) => decompose_literals!(v, U32),
399            LiteralVector::I32(ref v) => decompose_literals!(v, I32),
400            LiteralVector::U64(ref v) => decompose_literals!(v, U64),
401            LiteralVector::I64(ref v) => decompose_literals!(v, I64),
402            LiteralVector::Bool(ref v) => decompose_literals!(v, Bool),
403            LiteralVector::AbstractInt(ref v) => decompose_literals!(v, AbstractInt),
404            LiteralVector::AbstractFloat(ref v) => decompose_literals!(v, AbstractFloat),
405        }
406    }
407
408    #[allow(dead_code)]
409    /// Puts self into eval's expressions arena and returns handle to it
410    fn register_as_evaluated_expr(
411        &self,
412        eval: &mut ConstantEvaluator<'_>,
413        span: Span,
414    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
415        let lit_vec = self.to_literal_vec();
416        assert!(!lit_vec.is_empty());
417        let expr = if lit_vec.len() == 1 {
418            Expression::Literal(lit_vec[0])
419        } else {
420            Expression::Compose {
421                ty: eval.types.insert(
422                    Type {
423                        name: None,
424                        inner: TypeInner::Vector {
425                            size: match lit_vec.len() {
426                                2 => crate::VectorSize::Bi,
427                                3 => crate::VectorSize::Tri,
428                                4 => crate::VectorSize::Quad,
429                                _ => unreachable!(),
430                            },
431                            scalar: lit_vec[0].scalar(),
432                        },
433                    },
434                    Span::UNDEFINED,
435                ),
436                components: lit_vec
437                    .iter()
438                    .map(|&l| eval.register_evaluated_expr(Expression::Literal(l), span))
439                    .collect::<Result<_, _>>()?,
440            }
441        };
442        eval.register_evaluated_expr(expr, span)
443    }
444}
445
446/// A macro for matching on [`LiteralVector`] variants.
447///
448/// `Float` variant expands to `F16`, `F32`, `F64` and `AbstractFloat`.
449/// `Integer` variant expands to `I32`, `I64`, `U32`, `U64` and `AbstractInt`.
450///
451/// For output both [`Literal`] (fold) and [`LiteralVector`] (map) are supported.
452///
453/// Example usage:
454///
455/// ```rust,ignore
456/// match_literal_vector!(match v => Literal {
457///     F16 => |v| {v.sum()},
458///     Integer => |v| {v.sum()},
459///     U32 => |v| -> I32 {v.sum()}, // optionally override return type
460/// })
461/// ```
462///
463/// ```rust,ignore
464/// match_literal_vector!(match (e1, e2) => LiteralVector {
465///     F16 => |e1, e2| {e1+e2},
466///     Integer => |e1, e2| {e1+e2},
467///     U32 => |e1, e2| -> I32 {e1+e2}, // optionally override return type
468/// })
469/// ```
470macro_rules! match_literal_vector {
471    (match $lit_vec:expr => $out:ident {
472        $(
473            $ty:ident => |$($var:ident),+| $(-> $ret:ident)? { $body:expr }
474        ),+
475        $(,)?
476    }) => {
477        match_literal_vector!(@inner_start $lit_vec; $out; [$($ty),+]; [$({ $($var),+ ; $($ret)? ; $body }),+])
478    };
479
480    (@inner_start
481        $lit_vec:expr;
482        $out:ident;
483        [$($ty:ident),+];
484        [$({ $($var:ident),+ ; $($ret:ident)? ; $body:expr }),+]
485    ) => {
486        match_literal_vector!(@inner
487            $lit_vec;
488            $out;
489            [$($ty),+];
490            [] <> [$({ $($var),+ ; $($ret)? ; $body }),+]
491        )
492    };
493
494    (@inner
495        $lit_vec:expr;
496        $out:ident;
497        [$ty:ident $(, $ty1:ident)*];
498        [$({$_ty:ident ; $($_var:ident),+ ; $($_ret:ident)? ; $_body:expr}),*] <>
499        [$({ $($var:ident),+ ; $($ret:ident)? ; $body:expr }),+]
500    ) => {
501        match_literal_vector!(@inner
502            $ty;
503            $lit_vec;
504            $out;
505            [$($ty1),*];
506            [$({$_ty ; $($_var),+ ; $($_ret)? ; $_body}),*] <>
507            [$({ $($var),+ ; $($ret)? ; $body }),+]
508        )
509    };
510    (@inner
511        Integer;
512        $lit_vec:expr;
513        $out:ident;
514        [$($ty:ident),*];
515        [$({$_ty:ident ; $($_var:ident),+ ; $($_ret:ident)? ; $_body:expr}),*] <>
516        [
517            { $($var:ident),+ ; $($ret:ident)? ; $body:expr }
518            $(,{ $($var1:ident),+ ; $($ret1:ident)? ; $body1:expr })*
519        ]
520    ) => {
521        match_literal_vector!(@inner
522            $lit_vec;
523            $out;
524            [U32, I32, U64, I64, AbstractInt $(, $ty)*];
525            [$({$_ty ; $($_var),+ ; $($_ret)? ; $_body}),*] <>
526            [
527                { $($var),+ ; $($ret)? ; $body }, // U32
528                { $($var),+ ; $($ret)? ; $body }, // I32
529                { $($var),+ ; $($ret)? ; $body }, // U64
530                { $($var),+ ; $($ret)? ; $body }, // I64
531                { $($var),+ ; $($ret)? ; $body }  // AbstractInt
532                $(,{ $($var1),+ ; $($ret1)? ; $body1 })*
533            ]
534        )
535    };
536    (@inner
537        Float;
538        $lit_vec:expr;
539        $out:ident;
540        [$($ty:ident),*];
541        [$({$_ty:ident ; $($_var:ident),+ ; $($_ret:ident)? ; $_body:expr}),*] <>
542        [
543            { $($var:ident),+ ; $($ret:ident)? ; $body:expr }
544            $(,{ $($var1:ident),+ ; $($ret1:ident)? ; $body1:expr })*
545        ]
546    ) => {
547        match_literal_vector!(@inner
548            $lit_vec;
549            $out;
550            [F16, F32, F64, AbstractFloat $(, $ty)*];
551            [$({$_ty ; $($_var),+ ; $($_ret)? ; $_body}),*] <>
552            [
553                { $($var),+ ; $($ret)? ; $body }, // F16
554                { $($var),+ ; $($ret)? ; $body }, // F32
555                { $($var),+ ; $($ret)? ; $body }, // F64
556                { $($var),+ ; $($ret)? ; $body }  // AbstractFloat
557                $(,{ $($var1),+ ; $($ret1)? ; $body1 })*
558            ]
559        )
560    };
561    (@inner
562        $ty:ident;
563        $lit_vec:expr;
564        $out:ident;
565        [$ty1:ident $(,$ty2:ident)*];
566        [$({$_ty:ident ; $($_var:ident),+ ; $($_ret:ident)? ; $_body:expr}),*] <> [
567            { $($var:ident),+ ; $($ret:ident)? ; $body:expr }
568            $(, { $($var1:ident),+ ; $($ret1:ident)? ; $body1:expr })*
569        ]
570    ) => {
571        match_literal_vector!(@inner
572            $ty1;
573            $lit_vec;
574            $out;
575            [$($ty2),*];
576            [
577                $({$_ty ; $($_var),+ ; $($_ret)? ; $_body},)*
578                { $ty; $($var),+ ; $($ret)? ; $body }
579            ] <>
580            [$({ $($var1),+ ; $($ret1)? ; $body1 }),*]
581
582        )
583    };
584    (@inner
585        $ty:ident;
586        $lit_vec:expr;
587        $out:ident;
588        [];
589        [$({$_ty:ident ; $($_var:ident),+ ; $($_ret:ident)? ; $_body:expr}),*] <>
590        [{ $($var:ident),+ ; $($ret:ident)? ; $body:expr }]
591    ) => {
592        match_literal_vector!(@inner_finish
593            $lit_vec;
594            $out;
595            [
596                $({ $_ty ; $($_var),+ ; $($_ret)? ; $_body },)*
597                { $ty; $($var),+ ; $($ret)? ; $body }
598            ]
599        )
600    };
601    (@inner_finish
602        $lit_vec:expr;
603        $out:ident;
604        [$({$ty:ident ; $($var:ident),+ ; $($ret:ident)? ; $body:expr}),+]
605    ) => {
606        match $lit_vec {
607            $(
608                #[allow(unused_parens)]
609                ($(LiteralVector::$ty(ref $var)),+) => { Ok(match_literal_vector!(@expand_ret $out; $ty $(; $ret)? ; $body)) }
610            )+
611            _ => Err(ConstantEvaluatorError::InvalidMathArg),
612        }
613    };
614    (@expand_ret $out:ident; $ty:ident; $body:expr) => {
615        $out::$ty($body)
616    };
617    (@expand_ret $out:ident; $_ty:ident; $ret:ident; $body:expr) => {
618        $out::$ret($body)
619    };
620}
621
622fn float_length<F>(e: &[F]) -> Option<F>
623where
624    F: core::ops::Mul<F> + num_traits::Float + iter::Sum,
625{
626    if e.len() == 1 {
627        // Avoids possible overflow in squaring
628        Some(e[0].abs())
629    } else {
630        let result = e.iter().map(|&ei| ei * ei).sum::<F>().sqrt();
631        result.is_finite().then_some(result)
632    }
633}
634
635/// The dot product of `a` and `b`.  Return `None` if it is not finite.
636fn float_dot<F>(a: &[F], b: &[F]) -> Option<F>
637where
638    F: num_traits::Float,
639{
640    let result = a
641        .iter()
642        .zip(b.iter())
643        .map(|(&aa, &bb)| aa * bb)
644        .fold(F::zero(), |acc, x| acc + x);
645    result.is_finite().then_some(result)
646}
647
648#[derive(Debug)]
649enum Behavior<'a> {
650    Wgsl(WgslRestrictions<'a>),
651    Glsl(GlslRestrictions<'a>),
652}
653
654impl Behavior<'_> {
655    /// Returns `true` if the inner WGSL/GLSL restrictions are runtime restrictions.
656    const fn has_runtime_restrictions(&self) -> bool {
657        matches!(
658            self,
659            &Behavior::Wgsl(WgslRestrictions::Runtime(_))
660                | &Behavior::Glsl(GlslRestrictions::Runtime(_))
661        )
662    }
663}
664
665/// A context for evaluating constant expressions.
666///
667/// A `ConstantEvaluator` points at an expression arena to which it can append
668/// newly evaluated expressions: you pass [`try_eval_and_append`] whatever kind
669/// of Naga [`Expression`] you like, and if its value can be computed at compile
670/// time, `try_eval_and_append` appends an expression representing the computed
671/// value - a tree of [`Literal`], [`Compose`], [`ZeroValue`], and [`Swizzle`]
672/// expressions - to the arena. See the [`try_eval_and_append`] method for details.
673///
674/// A `ConstantEvaluator` also holds whatever information we need to carry out
675/// that evaluation: types, other constants, and so on.
676///
677/// [`try_eval_and_append`]: ConstantEvaluator::try_eval_and_append
678/// [`Compose`]: Expression::Compose
679/// [`ZeroValue`]: Expression::ZeroValue
680/// [`Literal`]: Expression::Literal
681/// [`Swizzle`]: Expression::Swizzle
682#[derive(Debug)]
683pub struct ConstantEvaluator<'a> {
684    /// Which language's evaluation rules we should follow.
685    behavior: Behavior<'a>,
686
687    /// The module's type arena.
688    ///
689    /// Because expressions like [`Splat`] contain type handles, we need to be
690    /// able to add new types to produce those expressions.
691    ///
692    /// [`Splat`]: Expression::Splat
693    types: &'a mut UniqueArena<Type>,
694
695    /// The module's constant arena.
696    constants: &'a Arena<Constant>,
697
698    /// The module's override arena.
699    overrides: &'a Arena<Override>,
700
701    /// The arena to which we are contributing expressions.
702    expressions: &'a mut Arena<Expression>,
703
704    /// Tracks the constness of expressions residing in [`Self::expressions`]
705    expression_kind_tracker: &'a mut ExpressionKindTracker,
706
707    layouter: &'a mut crate::proc::Layouter,
708}
709
710#[derive(Debug)]
711enum WgslRestrictions<'a> {
712    /// - const-expressions will be evaluated and inserted in the arena
713    Const(Option<FunctionLocalData<'a>>),
714    /// - const-expressions will be evaluated and inserted in the arena
715    /// - override-expressions will be inserted in the arena
716    Override,
717    /// - const-expressions will be evaluated and inserted in the arena
718    /// - override-expressions will be inserted in the arena
719    /// - runtime-expressions will be inserted in the arena
720    Runtime(FunctionLocalData<'a>),
721}
722
723#[derive(Debug)]
724enum GlslRestrictions<'a> {
725    /// - const-expressions will be evaluated and inserted in the arena
726    Const,
727    /// - const-expressions will be evaluated and inserted in the arena
728    /// - override-expressions will be inserted in the arena
729    /// - runtime-expressions will be inserted in the arena
730    Runtime(FunctionLocalData<'a>),
731}
732
733#[derive(Debug)]
734struct FunctionLocalData<'a> {
735    /// Global constant expressions
736    global_expressions: &'a Arena<Expression>,
737    emitter: &'a mut super::Emitter,
738    block: &'a mut crate::Block,
739}
740
741#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
742pub enum ExpressionKind {
743    Const,
744    Override,
745    Runtime,
746}
747
748#[derive(Debug)]
749pub struct ExpressionKindTracker {
750    inner: HandleVec<Expression, ExpressionKind>,
751}
752
753impl ExpressionKindTracker {
754    pub const fn new() -> Self {
755        Self {
756            inner: HandleVec::new(),
757        }
758    }
759
760    /// Forces the the expression to not be const
761    pub fn force_non_const(&mut self, value: Handle<Expression>) {
762        self.inner[value] = ExpressionKind::Runtime;
763    }
764
765    pub fn insert(&mut self, value: Handle<Expression>, expr_type: ExpressionKind) {
766        self.inner.insert(value, expr_type);
767    }
768
769    pub fn is_const(&self, h: Handle<Expression>) -> bool {
770        matches!(self.type_of(h), ExpressionKind::Const)
771    }
772
773    pub fn is_const_or_override(&self, h: Handle<Expression>) -> bool {
774        matches!(
775            self.type_of(h),
776            ExpressionKind::Const | ExpressionKind::Override
777        )
778    }
779
780    fn type_of(&self, value: Handle<Expression>) -> ExpressionKind {
781        self.inner[value]
782    }
783
784    pub fn from_arena(arena: &Arena<Expression>) -> Self {
785        let mut tracker = Self {
786            inner: HandleVec::with_capacity(arena.len()),
787        };
788        for (handle, expr) in arena.iter() {
789            tracker
790                .inner
791                .insert(handle, tracker.type_of_with_expr(expr));
792        }
793        tracker
794    }
795
796    fn type_of_with_expr(&self, expr: &Expression) -> ExpressionKind {
797        match *expr {
798            Expression::Literal(_) | Expression::ZeroValue(_) | Expression::Constant(_) => {
799                ExpressionKind::Const
800            }
801            Expression::Override(_) => ExpressionKind::Override,
802            Expression::Compose { ref components, .. } => {
803                let mut expr_type = ExpressionKind::Const;
804                for component in components {
805                    expr_type = expr_type.max(self.type_of(*component))
806                }
807                expr_type
808            }
809            Expression::Splat { value, .. } => self.type_of(value),
810            Expression::AccessIndex { base, .. } => self.type_of(base),
811            Expression::Access { base, index } => self.type_of(base).max(self.type_of(index)),
812            Expression::Swizzle { vector, .. } => self.type_of(vector),
813            Expression::Unary { expr, .. } => self.type_of(expr),
814            Expression::Binary { left, right, .. } => self.type_of(left).max(self.type_of(right)),
815            Expression::Math {
816                arg,
817                arg1,
818                arg2,
819                arg3,
820                ..
821            } => self
822                .type_of(arg)
823                .max(
824                    arg1.map(|arg| self.type_of(arg))
825                        .unwrap_or(ExpressionKind::Const),
826                )
827                .max(
828                    arg2.map(|arg| self.type_of(arg))
829                        .unwrap_or(ExpressionKind::Const),
830                )
831                .max(
832                    arg3.map(|arg| self.type_of(arg))
833                        .unwrap_or(ExpressionKind::Const),
834                ),
835            Expression::As { expr, .. } | Expression::Bitcast { expr, .. } => self.type_of(expr),
836            Expression::Select {
837                condition,
838                accept,
839                reject,
840            } => self
841                .type_of(condition)
842                .max(self.type_of(accept))
843                .max(self.type_of(reject)),
844            Expression::Relational { argument, .. } => self.type_of(argument),
845            Expression::ArrayLength(expr) => self.type_of(expr),
846            _ => ExpressionKind::Runtime,
847        }
848    }
849}
850
851#[derive(Clone, Debug, thiserror::Error)]
852#[cfg_attr(test, derive(PartialEq))]
853pub enum ConstantEvaluatorError {
854    #[error("Constants cannot access function arguments")]
855    FunctionArg,
856    #[error("Constants cannot access global variables")]
857    GlobalVariable,
858    #[error("Constants cannot access local variables")]
859    LocalVariable,
860    #[error("Cannot get the array length of a non array type")]
861    InvalidArrayLengthArg,
862    #[error("Constants cannot get the array length of a dynamically sized array")]
863    ArrayLengthDynamic,
864    #[error("Cannot call arrayLength on array sized by override-expression")]
865    ArrayLengthOverridden,
866    #[error("Constants cannot call functions")]
867    Call,
868    #[error("Constants don't support workGroupUniformLoad")]
869    WorkGroupUniformLoadResult,
870    #[error("Constants don't support atomic functions")]
871    Atomic,
872    #[error("Constants don't support derivative functions")]
873    Derivative,
874    #[error("Constants don't support load expressions")]
875    Load,
876    #[error("Constants don't support image expressions")]
877    ImageExpression,
878    #[error("Constants don't support ray query expressions")]
879    RayQueryExpression,
880    #[error("Constants don't support subgroup expressions")]
881    SubgroupExpression,
882    #[error("Cannot access the type")]
883    InvalidAccessBase,
884    #[error("Cannot access at the index")]
885    InvalidAccessIndex,
886    #[error("Cannot access with index of type")]
887    InvalidAccessIndexTy,
888    #[error("Constants don't support array length expressions")]
889    ArrayLength,
890    #[error("Cannot cast scalar components of expression `{from}` to type `{to}`")]
891    InvalidCastArg { from: String, to: String },
892    #[error("Cannot apply the unary op to the argument")]
893    InvalidUnaryOpArg,
894    #[error("Cannot apply the binary op to the arguments")]
895    InvalidBinaryOpArgs,
896    #[error("Cannot apply math function to type")]
897    InvalidMathArg,
898    #[error("{0:?} built-in function expects {1:?} arguments but {2:?} were supplied")]
899    InvalidMathArgCount(crate::MathFunction, usize, usize),
900    #[error("{0} built-in function argument is out of valid range")]
901    InvalidMathArgValue(String),
902    #[error(
903        "`offset` + `count` must be at most {width}, the bit width of the operand of the \
904         {builtin} built-in function, but {offset} + {count} is greater"
905    )]
906    BitfieldRangeTooLarge {
907        builtin: &'static str,
908        offset: u32,
909        count: u32,
910        width: u32,
911    },
912    #[error("Cannot apply relational function to type")]
913    InvalidRelationalArg(RelationalFunction),
914    #[error("value of `low` is greater than `high` for clamp built-in function")]
915    InvalidClamp,
916    #[error("Constructor expects {expected} components, found {actual}")]
917    InvalidVectorComposeLength { expected: usize, actual: usize },
918    #[error("Constructor must only contain vector or scalar arguments")]
919    InvalidVectorComposeComponent,
920    #[error("Splat is defined only on scalar values")]
921    SplatScalarOnly,
922    #[error("Can only swizzle vector constants")]
923    SwizzleVectorOnly,
924    #[error("swizzle component not present in source expression")]
925    SwizzleOutOfBounds,
926    #[error("Type is not constructible")]
927    TypeNotConstructible,
928    #[error("Subexpression(s) are not constant")]
929    SubexpressionsAreNotConstant,
930    #[error("Not implemented as constant expression: {0}")]
931    NotImplemented(String),
932    #[error("{0} operation overflowed")]
933    Overflow(String),
934    #[error(
935        "the concrete type `{to_type}` cannot represent the abstract value `{value}` accurately"
936    )]
937    AutomaticConversionLossy {
938        value: String,
939        to_type: &'static str,
940    },
941    #[error("Division by zero")]
942    DivisionByZero,
943    #[error("Remainder by zero")]
944    RemainderByZero,
945    #[error("RHS of shift operation is greater than or equal to 32")]
946    ShiftedMoreThan32Bits,
947    #[error(transparent)]
948    Literal(#[from] crate::valid::LiteralError),
949    #[error("Can't use pipeline-overridable constants in const-expressions")]
950    Override,
951    #[error("Unexpected runtime-expression")]
952    RuntimeExpr,
953    #[error("Unexpected override-expression")]
954    OverrideExpr,
955    #[error("Expected boolean expression for condition argument of `select`, got something else")]
956    SelectScalarConditionNotABool,
957    #[error(
958        "Expected vectors of the same size for reject and accept args., got {:?} and {:?}",
959        reject,
960        accept
961    )]
962    SelectVecRejectAcceptSizeMismatch {
963        reject: crate::VectorSize,
964        accept: crate::VectorSize,
965    },
966    #[error("Expected boolean vector for condition arg., got something else")]
967    SelectConditionNotAVecBool,
968    #[error(
969        "Expected same number of vector components between condition, accept, and reject args., got something else",
970    )]
971    SelectConditionVecSizeMismatch,
972    #[error(
973        "Expected reject and accept args. to be scalars of vectors of the same type, got something else",
974    )]
975    SelectAcceptRejectTypeMismatch,
976    #[error("Cooperative operations can't be constant")]
977    CooperativeOperation,
978    #[error("Type is too large")]
979    TypeTooLarge(Handle<Type>),
980}
981
982impl<'a> ConstantEvaluator<'a> {
983    /// Return a [`ConstantEvaluator`] that will add expressions to `module`'s
984    /// constant expression arena.
985    ///
986    /// Report errors according to WGSL's rules for constant evaluation.
987    pub const fn for_wgsl_module(
988        module: &'a mut crate::Module,
989        global_expression_kind_tracker: &'a mut ExpressionKindTracker,
990        layouter: &'a mut crate::proc::Layouter,
991        in_override_ctx: bool,
992    ) -> Self {
993        Self::for_module(
994            Behavior::Wgsl(if in_override_ctx {
995                WgslRestrictions::Override
996            } else {
997                WgslRestrictions::Const(None)
998            }),
999            module,
1000            global_expression_kind_tracker,
1001            layouter,
1002        )
1003    }
1004
1005    /// Return a [`ConstantEvaluator`] that will add expressions to `module`'s
1006    /// constant expression arena.
1007    ///
1008    /// Report errors according to GLSL's rules for constant evaluation.
1009    pub const fn for_glsl_module(
1010        module: &'a mut crate::Module,
1011        global_expression_kind_tracker: &'a mut ExpressionKindTracker,
1012        layouter: &'a mut crate::proc::Layouter,
1013    ) -> Self {
1014        Self::for_module(
1015            Behavior::Glsl(GlslRestrictions::Const),
1016            module,
1017            global_expression_kind_tracker,
1018            layouter,
1019        )
1020    }
1021
1022    const fn for_module(
1023        behavior: Behavior<'a>,
1024        module: &'a mut crate::Module,
1025        global_expression_kind_tracker: &'a mut ExpressionKindTracker,
1026        layouter: &'a mut crate::proc::Layouter,
1027    ) -> Self {
1028        Self {
1029            behavior,
1030            types: &mut module.types,
1031            constants: &module.constants,
1032            overrides: &module.overrides,
1033            expressions: &mut module.global_expressions,
1034            expression_kind_tracker: global_expression_kind_tracker,
1035            layouter,
1036        }
1037    }
1038
1039    /// Return a [`ConstantEvaluator`] that will add expressions to `function`'s
1040    /// expression arena.
1041    ///
1042    /// Report errors according to WGSL's rules for constant evaluation.
1043    pub const fn for_wgsl_function(
1044        module: &'a mut crate::Module,
1045        expressions: &'a mut Arena<Expression>,
1046        local_expression_kind_tracker: &'a mut ExpressionKindTracker,
1047        layouter: &'a mut crate::proc::Layouter,
1048        emitter: &'a mut super::Emitter,
1049        block: &'a mut crate::Block,
1050        is_const: bool,
1051    ) -> Self {
1052        let local_data = FunctionLocalData {
1053            global_expressions: &module.global_expressions,
1054            emitter,
1055            block,
1056        };
1057        Self {
1058            behavior: Behavior::Wgsl(if is_const {
1059                WgslRestrictions::Const(Some(local_data))
1060            } else {
1061                WgslRestrictions::Runtime(local_data)
1062            }),
1063            types: &mut module.types,
1064            constants: &module.constants,
1065            overrides: &module.overrides,
1066            expressions,
1067            expression_kind_tracker: local_expression_kind_tracker,
1068            layouter,
1069        }
1070    }
1071
1072    /// Return a [`ConstantEvaluator`] that will add expressions to `function`'s
1073    /// expression arena.
1074    ///
1075    /// Report errors according to GLSL's rules for constant evaluation.
1076    pub const fn for_glsl_function(
1077        module: &'a mut crate::Module,
1078        expressions: &'a mut Arena<Expression>,
1079        local_expression_kind_tracker: &'a mut ExpressionKindTracker,
1080        layouter: &'a mut crate::proc::Layouter,
1081        emitter: &'a mut super::Emitter,
1082        block: &'a mut crate::Block,
1083    ) -> Self {
1084        Self {
1085            behavior: Behavior::Glsl(GlslRestrictions::Runtime(FunctionLocalData {
1086                global_expressions: &module.global_expressions,
1087                emitter,
1088                block,
1089            })),
1090            types: &mut module.types,
1091            constants: &module.constants,
1092            overrides: &module.overrides,
1093            expressions,
1094            expression_kind_tracker: local_expression_kind_tracker,
1095            layouter,
1096        }
1097    }
1098
1099    pub const fn to_ctx(&self) -> crate::proc::GlobalCtx<'_> {
1100        crate::proc::GlobalCtx {
1101            types: self.types,
1102            constants: self.constants,
1103            overrides: self.overrides,
1104            global_expressions: match self.function_local_data() {
1105                Some(data) => data.global_expressions,
1106                None => self.expressions,
1107            },
1108        }
1109    }
1110
1111    fn check(&self, expr: Handle<Expression>) -> Result<(), ConstantEvaluatorError> {
1112        if !self.expression_kind_tracker.is_const(expr) {
1113            log::debug!("check: SubexpressionsAreNotConstant");
1114            return Err(ConstantEvaluatorError::SubexpressionsAreNotConstant);
1115        }
1116        Ok(())
1117    }
1118
1119    fn check_and_get(
1120        &mut self,
1121        expr: Handle<Expression>,
1122    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1123        match self.expressions[expr] {
1124            Expression::Constant(c) => {
1125                // Are we working in a function's expression arena, or the
1126                // module's constant expression arena?
1127                if let Some(function_local_data) = self.function_local_data() {
1128                    // Deep-copy the constant's value into our arena.
1129                    self.copy_from(
1130                        self.constants[c].init,
1131                        function_local_data.global_expressions,
1132                    )
1133                } else {
1134                    // "See through" the constant and use its initializer.
1135                    Ok(self.constants[c].init)
1136                }
1137            }
1138            _ => {
1139                self.check(expr)?;
1140                Ok(expr)
1141            }
1142        }
1143    }
1144
1145    /// Try to evaluate `expr` at compile time.
1146    ///
1147    /// The `expr` argument can be any sort of Naga [`Expression`] you like. If
1148    /// we can determine its value at compile time, we append an expression
1149    /// representing its value - a tree of [`Literal`], [`Compose`],
1150    /// [`ZeroValue`], and [`Swizzle`] expressions - to the expression arena
1151    /// `self` contributes to.
1152    ///
1153    /// If `expr`'s value cannot be determined at compile time, and `self` is
1154    /// contributing to some function's expression arena, then append `expr` to
1155    /// that arena unchanged (and thus unevaluated). Otherwise, `self` must be
1156    /// contributing to the module's constant expression arena; since `expr`'s
1157    /// value is not a constant, return an error.
1158    ///
1159    /// We only consider `expr` itself, without recursing into its operands. Its
1160    /// operands must all have been produced by prior calls to
1161    /// `try_eval_and_append`, to ensure that they have already been reduced to
1162    /// an evaluated form if possible.
1163    ///
1164    /// [`Literal`]: Expression::Literal
1165    /// [`Compose`]: Expression::Compose
1166    /// [`ZeroValue`]: Expression::ZeroValue
1167    /// [`Swizzle`]: Expression::Swizzle
1168    pub fn try_eval_and_append(
1169        &mut self,
1170        expr: Expression,
1171        span: Span,
1172    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1173        match self.expression_kind_tracker.type_of_with_expr(&expr) {
1174            ExpressionKind::Const => {
1175                let eval_result = self.try_eval_and_append_impl(&expr, span);
1176                // We should be able to evaluate `Const` expressions at this
1177                // point. If we failed to, then that probably means we just
1178                // haven't implemented that part of constant evaluation. Work
1179                // around this by simply emitting it as a run-time expression.
1180                if self.behavior.has_runtime_restrictions()
1181                    && matches!(
1182                        eval_result,
1183                        Err(ConstantEvaluatorError::NotImplemented(_)
1184                            | ConstantEvaluatorError::InvalidBinaryOpArgs,)
1185                    )
1186                {
1187                    Ok(self.append_expr(expr, span, ExpressionKind::Runtime))
1188                } else {
1189                    eval_result
1190                }
1191            }
1192            ExpressionKind::Override => match self.behavior {
1193                Behavior::Wgsl(WgslRestrictions::Override | WgslRestrictions::Runtime(_)) => {
1194                    Ok(self.append_expr(expr, span, ExpressionKind::Override))
1195                }
1196                Behavior::Wgsl(WgslRestrictions::Const(_)) => {
1197                    Err(ConstantEvaluatorError::OverrideExpr)
1198                }
1199
1200                // GLSL specialization constants (constant_id) become Override expressions
1201                Behavior::Glsl(GlslRestrictions::Runtime(_)) => {
1202                    Ok(self.append_expr(expr, span, ExpressionKind::Override))
1203                }
1204                Behavior::Glsl(GlslRestrictions::Const) => {
1205                    Err(ConstantEvaluatorError::OverrideExpr)
1206                }
1207            },
1208            ExpressionKind::Runtime => {
1209                if self.behavior.has_runtime_restrictions() {
1210                    Ok(self.append_expr(expr, span, ExpressionKind::Runtime))
1211                } else {
1212                    Err(ConstantEvaluatorError::RuntimeExpr)
1213                }
1214            }
1215        }
1216    }
1217
1218    /// Is the [`Self::expressions`] arena the global module expression arena?
1219    const fn is_global_arena(&self) -> bool {
1220        matches!(
1221            self.behavior,
1222            Behavior::Wgsl(WgslRestrictions::Const(None) | WgslRestrictions::Override)
1223                | Behavior::Glsl(GlslRestrictions::Const)
1224        )
1225    }
1226
1227    const fn function_local_data(&self) -> Option<&FunctionLocalData<'a>> {
1228        match self.behavior {
1229            Behavior::Wgsl(
1230                WgslRestrictions::Runtime(ref function_local_data)
1231                | WgslRestrictions::Const(Some(ref function_local_data)),
1232            )
1233            | Behavior::Glsl(GlslRestrictions::Runtime(ref function_local_data)) => {
1234                Some(function_local_data)
1235            }
1236            _ => None,
1237        }
1238    }
1239
1240    fn try_eval_and_append_impl(
1241        &mut self,
1242        expr: &Expression,
1243        span: Span,
1244    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1245        log::trace!("try_eval_and_append: {expr:?}");
1246        match *expr {
1247            Expression::Constant(c) if self.is_global_arena() => {
1248                // "See through" the constant and use its initializer.
1249                // This is mainly done to avoid having constants pointing to other constants.
1250                Ok(self.constants[c].init)
1251            }
1252            Expression::Override(_) => Err(ConstantEvaluatorError::Override),
1253            Expression::Literal(_) | Expression::ZeroValue(_) | Expression::Constant(_) => {
1254                self.register_evaluated_expr(expr.clone(), span)
1255            }
1256            Expression::Compose { ty, ref components } => {
1257                let components = components
1258                    .iter()
1259                    .map(|component| self.check_and_get(*component))
1260                    .collect::<Result<Vec<_>, _>>()?;
1261                self.register_evaluated_expr(Expression::Compose { ty, components }, span)
1262            }
1263            Expression::Splat { size, value } => {
1264                let value = self.check_and_get(value)?;
1265                self.register_evaluated_expr(Expression::Splat { size, value }, span)
1266            }
1267            Expression::AccessIndex { base, index } => {
1268                let base = self.check_and_get(base)?;
1269
1270                self.access(base, index as usize, span)
1271            }
1272            Expression::Access { base, index } => {
1273                let base = self.check_and_get(base)?;
1274                let index = self.check_and_get(index)?;
1275
1276                let index_val: u32 = self
1277                    .to_ctx()
1278                    .get_const_val_from(index, self.expressions)
1279                    .map_err(|_| ConstantEvaluatorError::InvalidAccessIndexTy)?;
1280                self.access(base, index_val as usize, span)
1281            }
1282            Expression::Swizzle {
1283                size,
1284                vector,
1285                pattern,
1286            } => {
1287                let vector = self.check_and_get(vector)?;
1288
1289                self.swizzle(size, span, vector, pattern)
1290            }
1291            Expression::Unary { expr, op } => {
1292                let expr = self.check_and_get(expr)?;
1293
1294                self.unary_op(op, expr, span)
1295            }
1296            Expression::Binary { left, right, op } => {
1297                let left = self.check_and_get(left)?;
1298                let right = self.check_and_get(right)?;
1299
1300                self.binary_op(op, left, right, span)
1301            }
1302            Expression::Math {
1303                fun,
1304                arg,
1305                arg1,
1306                arg2,
1307                arg3,
1308            } => {
1309                let arg = self.check_and_get(arg)?;
1310                let arg1 = arg1.map(|arg| self.check_and_get(arg)).transpose()?;
1311                let arg2 = arg2.map(|arg| self.check_and_get(arg)).transpose()?;
1312                let arg3 = arg3.map(|arg| self.check_and_get(arg)).transpose()?;
1313
1314                self.math(arg, arg1, arg2, arg3, fun, span)
1315            }
1316            Expression::As { expr, target } => {
1317                let expr = self.check_and_get(expr)?;
1318                self.cast(expr, target, span)
1319            }
1320            Expression::Bitcast { .. } => Err(ConstantEvaluatorError::NotImplemented(
1321                "bitcast built-in function".into(),
1322            )),
1323            Expression::Select {
1324                reject,
1325                accept,
1326                condition,
1327            } => {
1328                let mut arg = |expr| self.check_and_get(expr);
1329
1330                let reject = arg(reject)?;
1331                let accept = arg(accept)?;
1332                let condition = arg(condition)?;
1333
1334                self.select(reject, accept, condition, span)
1335            }
1336            Expression::Relational { fun, argument } => {
1337                let argument = self.check_and_get(argument)?;
1338                self.relational(fun, argument, span)
1339            }
1340            Expression::ArrayLength(expr) => match self.behavior {
1341                Behavior::Wgsl(_) => Err(ConstantEvaluatorError::ArrayLength),
1342                Behavior::Glsl(_) => {
1343                    let expr = self.check_and_get(expr)?;
1344                    self.array_length(expr, span)
1345                }
1346            },
1347            Expression::Load { .. } => Err(ConstantEvaluatorError::Load),
1348            Expression::LocalVariable(_) => Err(ConstantEvaluatorError::LocalVariable),
1349            Expression::Derivative { .. } => Err(ConstantEvaluatorError::Derivative),
1350            Expression::CallResult { .. } => Err(ConstantEvaluatorError::Call),
1351            Expression::WorkGroupUniformLoadResult { .. } => {
1352                Err(ConstantEvaluatorError::WorkGroupUniformLoadResult)
1353            }
1354            Expression::AtomicResult { .. } => Err(ConstantEvaluatorError::Atomic),
1355            Expression::FunctionArgument(_) => Err(ConstantEvaluatorError::FunctionArg),
1356            Expression::GlobalVariable(_) => Err(ConstantEvaluatorError::GlobalVariable),
1357            Expression::ImageSample { .. }
1358            | Expression::ImageLoad { .. }
1359            | Expression::ImageQuery { .. } => Err(ConstantEvaluatorError::ImageExpression),
1360            Expression::RayQueryProceedResult
1361            | Expression::RayQueryGetIntersection { .. }
1362            | Expression::RayQueryVertexPositions { .. } => {
1363                Err(ConstantEvaluatorError::RayQueryExpression)
1364            }
1365            Expression::SubgroupBallotResult => Err(ConstantEvaluatorError::SubgroupExpression),
1366            Expression::SubgroupOperationResult { .. } => {
1367                Err(ConstantEvaluatorError::SubgroupExpression)
1368            }
1369            Expression::CooperativeLoad { .. } | Expression::CooperativeMultiplyAdd { .. } => {
1370                Err(ConstantEvaluatorError::CooperativeOperation)
1371            }
1372        }
1373    }
1374
1375    /// Splat `value` to `size`, without using [`Splat`] expressions.
1376    ///
1377    /// This constructs [`Compose`] or [`ZeroValue`] expressions to
1378    /// build a vector with the given `size` whose components are all
1379    /// `value`.
1380    ///
1381    /// Use `span` as the span of the inserted expressions and
1382    /// resulting types.
1383    ///
1384    /// [`Splat`]: Expression::Splat
1385    /// [`Compose`]: Expression::Compose
1386    /// [`ZeroValue`]: Expression::ZeroValue
1387    fn splat(
1388        &mut self,
1389        value: Handle<Expression>,
1390        size: crate::VectorSize,
1391        span: Span,
1392    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1393        match self.expressions[value] {
1394            Expression::Literal(literal) => {
1395                let scalar = literal.scalar();
1396                let ty = self.types.insert(
1397                    Type {
1398                        name: None,
1399                        inner: TypeInner::Vector { size, scalar },
1400                    },
1401                    span,
1402                );
1403                let expr = Expression::Compose {
1404                    ty,
1405                    components: vec![value; size as usize],
1406                };
1407                self.register_evaluated_expr(expr, span)
1408            }
1409            Expression::ZeroValue(ty) => {
1410                let inner = match self.types[ty].inner {
1411                    TypeInner::Scalar(scalar) => TypeInner::Vector { size, scalar },
1412                    _ => return Err(ConstantEvaluatorError::SplatScalarOnly),
1413                };
1414                let res_ty = self.types.insert(Type { name: None, inner }, span);
1415                let expr = Expression::ZeroValue(res_ty);
1416                self.register_evaluated_expr(expr, span)
1417            }
1418            _ => Err(ConstantEvaluatorError::SplatScalarOnly),
1419        }
1420    }
1421
1422    fn swizzle(
1423        &mut self,
1424        size: crate::VectorSize,
1425        span: Span,
1426        src_constant: Handle<Expression>,
1427        pattern: [crate::SwizzleComponent; 4],
1428    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1429        let mut get_dst_ty = |ty| match self.types[ty].inner {
1430            TypeInner::Vector { size: _, scalar } => Ok(self.types.insert(
1431                Type {
1432                    name: None,
1433                    inner: TypeInner::Vector { size, scalar },
1434                },
1435                span,
1436            )),
1437            _ => Err(ConstantEvaluatorError::SwizzleVectorOnly),
1438        };
1439
1440        match self.expressions[src_constant] {
1441            Expression::ZeroValue(ty) => {
1442                let dst_ty = get_dst_ty(ty)?;
1443                let expr = Expression::ZeroValue(dst_ty);
1444                self.register_evaluated_expr(expr, span)
1445            }
1446            Expression::Splat { value, .. } => {
1447                let expr = Expression::Splat { size, value };
1448                self.register_evaluated_expr(expr, span)
1449            }
1450            Expression::Compose { ty, ref components } => {
1451                let dst_ty = get_dst_ty(ty)?;
1452
1453                let mut flattened = [src_constant; 4]; // dummy value
1454                let len =
1455                    crate::proc::flatten_compose(ty, components, self.expressions, self.types)
1456                        .zip(flattened.iter_mut())
1457                        .map(|(component, elt)| *elt = component)
1458                        .count();
1459                let flattened = &flattened[..len];
1460
1461                let swizzled_components = pattern[..size as usize]
1462                    .iter()
1463                    .map(|&sc| {
1464                        let sc = sc as usize;
1465                        if let Some(elt) = flattened.get(sc) {
1466                            Ok(*elt)
1467                        } else {
1468                            Err(ConstantEvaluatorError::SwizzleOutOfBounds)
1469                        }
1470                    })
1471                    .collect::<Result<Vec<Handle<Expression>>, _>>()?;
1472                let expr = Expression::Compose {
1473                    ty: dst_ty,
1474                    components: swizzled_components,
1475                };
1476                self.register_evaluated_expr(expr, span)
1477            }
1478            _ => Err(ConstantEvaluatorError::SwizzleVectorOnly),
1479        }
1480    }
1481
1482    fn math(
1483        &mut self,
1484        arg: Handle<Expression>,
1485        arg1: Option<Handle<Expression>>,
1486        arg2: Option<Handle<Expression>>,
1487        arg3: Option<Handle<Expression>>,
1488        fun: crate::MathFunction,
1489        span: Span,
1490    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1491        let expected = fun.argument_count();
1492        let given = Some(arg)
1493            .into_iter()
1494            .chain(arg1)
1495            .chain(arg2)
1496            .chain(arg3)
1497            .count();
1498        if expected != given {
1499            return Err(ConstantEvaluatorError::InvalidMathArgCount(
1500                fun, expected, given,
1501            ));
1502        }
1503
1504        // NOTE: We try to match the declaration order of `MathFunction` here.
1505        match fun {
1506            // comparison
1507            crate::MathFunction::Abs => {
1508                component_wise_scalar(self, span, [arg], |args| match args {
1509                    Scalar::AbstractFloat([e]) => Ok(Scalar::AbstractFloat([e.abs()])),
1510                    Scalar::F32([e]) => Ok(Scalar::F32([e.abs()])),
1511                    Scalar::F16([e]) => Ok(Scalar::F16([e.abs()])),
1512                    Scalar::AbstractInt([e]) => Ok(Scalar::AbstractInt([e.wrapping_abs()])),
1513                    Scalar::I32([e]) => Ok(Scalar::I32([e.wrapping_abs()])),
1514                    Scalar::U32([e]) => Ok(Scalar::U32([e])), // TODO: just re-use the expression, ezpz
1515                    Scalar::I64([e]) => Ok(Scalar::I64([e.wrapping_abs()])),
1516                    Scalar::U64([e]) => Ok(Scalar::U64([e])),
1517                })
1518            }
1519            crate::MathFunction::Min => {
1520                component_wise_scalar!(self, span, [arg, arg1.unwrap()], |e1, e2| {
1521                    Ok([e1.min(e2)])
1522                })
1523            }
1524            crate::MathFunction::Max => {
1525                component_wise_scalar!(self, span, [arg, arg1.unwrap()], |e1, e2| {
1526                    Ok([e1.max(e2)])
1527                })
1528            }
1529            crate::MathFunction::Clamp => {
1530                component_wise_scalar!(
1531                    self,
1532                    span,
1533                    [arg, arg1.unwrap(), arg2.unwrap()],
1534                    |e, low, high| {
1535                        if low > high {
1536                            Err(ConstantEvaluatorError::InvalidClamp)
1537                        } else {
1538                            Ok([e.clamp(low, high)])
1539                        }
1540                    }
1541                )
1542            }
1543            crate::MathFunction::Saturate => component_wise_float(self, span, [arg], |e| match e {
1544                Float::F16([e]) => Ok(Float::F16(
1545                    [e.clamp(f16::from_f32(0.0), f16::from_f32(1.0))],
1546                )),
1547                Float::F32([e]) => Ok(Float::F32([e.clamp(0., 1.)])),
1548                Float::Abstract([e]) => Ok(Float::Abstract([e.clamp(0., 1.)])),
1549            }),
1550
1551            // trigonometry
1552            crate::MathFunction::Cos => {
1553                component_wise_float!(self, span, [arg], |e| { Ok([e.cos()]) })
1554            }
1555            crate::MathFunction::Cosh => {
1556                component_wise_float!(self, span, [arg], |e| {
1557                    let result = e.cosh();
1558                    if result.is_finite() {
1559                        Ok([result])
1560                    } else {
1561                        Err(ConstantEvaluatorError::Overflow("cosh".into()))
1562                    }
1563                })
1564            }
1565            crate::MathFunction::Sin => {
1566                component_wise_float!(self, span, [arg], |e| { Ok([e.sin()]) })
1567            }
1568            crate::MathFunction::Sinh => {
1569                component_wise_float!(self, span, [arg], |e| {
1570                    let result = e.sinh();
1571                    if result.is_finite() {
1572                        Ok([result])
1573                    } else {
1574                        Err(ConstantEvaluatorError::Overflow("sinh".into()))
1575                    }
1576                })
1577            }
1578            crate::MathFunction::Tan => {
1579                component_wise_float!(self, span, [arg], |e| { Ok([e.tan()]) })
1580            }
1581            crate::MathFunction::Tanh => {
1582                component_wise_float!(self, span, [arg], |e| { Ok([e.tanh()]) })
1583            }
1584            crate::MathFunction::Acos => {
1585                component_wise_float!(self, span, [arg], |e| {
1586                    if e.abs() <= One::one() {
1587                        Ok([e.acos()])
1588                    } else {
1589                        Err(ConstantEvaluatorError::InvalidMathArgValue("acos".into()))
1590                    }
1591                })
1592            }
1593            crate::MathFunction::Asin => {
1594                component_wise_float!(self, span, [arg], |e| {
1595                    if e.abs() <= One::one() {
1596                        Ok([e.asin()])
1597                    } else {
1598                        Err(ConstantEvaluatorError::InvalidMathArgValue("asin".into()))
1599                    }
1600                })
1601            }
1602            crate::MathFunction::Atan => {
1603                component_wise_float!(self, span, [arg], |e| { Ok([e.atan()]) })
1604            }
1605            crate::MathFunction::Atan2 => {
1606                component_wise_float!(self, span, [arg, arg1.unwrap()], |y, x| {
1607                    Ok([y.atan2(x)])
1608                })
1609            }
1610            crate::MathFunction::Asinh => component_wise_float(self, span, [arg], |e| match e {
1611                Float::Abstract([e]) => Ok(Float::Abstract([libm::asinh(e)])),
1612                Float::F32([e]) => Ok(Float::F32([(e as f64).asinh() as f32])),
1613                Float::F16([e]) => Ok(Float::F16([e.asinh()])),
1614            }),
1615            crate::MathFunction::Acosh => component_wise_float(self, span, [arg], |e| match e {
1616                Float::Abstract([e]) if e >= One::one() => Ok(Float::Abstract([libm::acosh(e)])),
1617                Float::F32([e]) if e >= One::one() => Ok(Float::F32([(e as f64).acosh() as f32])),
1618                Float::F16([e]) if e >= One::one() => Ok(Float::F16([e.acosh()])),
1619                _ => Err(ConstantEvaluatorError::InvalidMathArgValue("acosh".into())),
1620            }),
1621            crate::MathFunction::Atanh => {
1622                component_wise_float!(self, span, [arg], |e| {
1623                    if e.abs() < One::one() {
1624                        Ok([e.atanh()])
1625                    } else {
1626                        Err(ConstantEvaluatorError::InvalidMathArgValue("atanh".into()))
1627                    }
1628                })
1629            }
1630            crate::MathFunction::Radians => {
1631                component_wise_float!(self, span, [arg], |e1| { Ok([e1.to_radians()]) })
1632            }
1633            crate::MathFunction::Degrees => {
1634                component_wise_float!(self, span, [arg], |e| {
1635                    let result = e.to_degrees();
1636                    if result.is_finite() {
1637                        Ok([result])
1638                    } else {
1639                        Err(ConstantEvaluatorError::Overflow("degrees".into()))
1640                    }
1641                })
1642            }
1643
1644            // decomposition
1645            crate::MathFunction::Ceil => {
1646                component_wise_float!(self, span, [arg], |e| { Ok([e.ceil()]) })
1647            }
1648            crate::MathFunction::Floor => {
1649                component_wise_float!(self, span, [arg], |e| { Ok([e.floor()]) })
1650            }
1651            crate::MathFunction::Round => {
1652                component_wise_float(self, span, [arg], |e| match e {
1653                    Float::Abstract([e]) => Ok(Float::Abstract([libm::rint(e)])),
1654                    Float::F32([e]) => Ok(Float::F32([libm::rintf(e)])),
1655                    Float::F16([e]) => {
1656                        // TODO: `round_ties_even` is not available on `half::f16` yet.
1657                        //
1658                        // This polyfill is shamelessly [~~stolen from~~ inspired by `ndarray-image`][polyfill source],
1659                        // which has licensing compatible with ours. See also
1660                        // <https://github.com/rust-lang/rust/issues/96710>.
1661                        //
1662                        // [polyfill source]: https://github.com/imeka/ndarray-ndimage/blob/8b14b4d6ecfbc96a8a052f802e342a7049c68d8f/src/lib.rs#L98
1663                        fn round_ties_even(x: f64) -> f64 {
1664                            let i = x as i64;
1665                            let f = (x - i as f64).abs();
1666                            if f == 0.5 {
1667                                if i & 1 == 1 {
1668                                    // -1.5, 1.5, 3.5, ...
1669                                    (x.abs() + 0.5).copysign(x)
1670                                } else {
1671                                    (x.abs() - 0.5).copysign(x)
1672                                }
1673                            } else {
1674                                x.round()
1675                            }
1676                        }
1677
1678                        Ok(Float::F16([(f16::from_f64(round_ties_even(f64::from(e))))]))
1679                    }
1680                })
1681            }
1682            crate::MathFunction::Fract => {
1683                component_wise_float!(self, span, [arg], |e| {
1684                    // N.B., Rust's definition of `fract` is `e - e.trunc()`, so we can't use that
1685                    // here.
1686                    Ok([e - e.floor()])
1687                })
1688            }
1689            crate::MathFunction::Trunc => {
1690                component_wise_float!(self, span, [arg], |e| { Ok([e.trunc()]) })
1691            }
1692
1693            // exponent
1694            crate::MathFunction::Exp => {
1695                component_wise_float!(self, span, [arg], |e| {
1696                    let result = e.exp();
1697                    if result.is_finite() {
1698                        Ok([result])
1699                    } else {
1700                        Err(ConstantEvaluatorError::Overflow("exp".into()))
1701                    }
1702                })
1703            }
1704            crate::MathFunction::Exp2 => {
1705                component_wise_float!(self, span, [arg], |e| {
1706                    let result = e.exp2();
1707                    if result.is_finite() {
1708                        Ok([result])
1709                    } else {
1710                        Err(ConstantEvaluatorError::Overflow("exp2".into()))
1711                    }
1712                })
1713            }
1714            crate::MathFunction::Log => {
1715                component_wise_float!(self, span, [arg], |e| {
1716                    if e > Zero::zero() {
1717                        Ok([e.ln()])
1718                    } else {
1719                        Err(ConstantEvaluatorError::InvalidMathArgValue("log".into()))
1720                    }
1721                })
1722            }
1723            crate::MathFunction::Log2 => {
1724                component_wise_float!(self, span, [arg], |e| {
1725                    if e > Zero::zero() {
1726                        Ok([e.log2()])
1727                    } else {
1728                        Err(ConstantEvaluatorError::InvalidMathArgValue("log2".into()))
1729                    }
1730                })
1731            }
1732            crate::MathFunction::Pow => {
1733                component_wise_float!(self, span, [arg, arg1.unwrap()], |e1, e2| {
1734                    // 0.pow(0) is an error since exp2(0 * log2(0)) is NaN.
1735                    // https://www.w3.org/TR/WGSL/#pow-builtin
1736                    if e1 < Zero::zero()
1737                        || e1.is_one() && e2.is_infinite()
1738                        || e1.is_infinite() && e2.is_zero()
1739                        || e1.is_zero() && e2.is_zero()
1740                    {
1741                        Err(ConstantEvaluatorError::InvalidMathArgValue("pow".into()))
1742                    } else {
1743                        let result = e1.powf(e2);
1744                        if result.is_finite() {
1745                            Ok([result])
1746                        } else {
1747                            Err(ConstantEvaluatorError::Overflow("pow".into()))
1748                        }
1749                    }
1750                })
1751            }
1752
1753            // computational
1754            crate::MathFunction::Sign => {
1755                component_wise_signed!(self, span, [arg], |e| {
1756                    Ok([if e.is_zero() {
1757                        Zero::zero()
1758                    } else {
1759                        e.signum()
1760                    }])
1761                })
1762            }
1763            crate::MathFunction::Fma => {
1764                component_wise_float!(
1765                    self,
1766                    span,
1767                    [arg, arg1.unwrap(), arg2.unwrap()],
1768                    |e1, e2, e3| { Ok([e1.mul_add(e2, e3)]) }
1769                )
1770            }
1771            crate::MathFunction::Step => {
1772                component_wise_float(self, span, [arg, arg1.unwrap()], |x| match x {
1773                    Float::Abstract([edge, x]) => {
1774                        Ok(Float::Abstract([if edge <= x { 1.0 } else { 0.0 }]))
1775                    }
1776                    Float::F32([edge, x]) => Ok(Float::F32([if edge <= x { 1.0 } else { 0.0 }])),
1777                    Float::F16([edge, x]) => Ok(Float::F16([if edge <= x {
1778                        f16::one()
1779                    } else {
1780                        f16::zero()
1781                    }])),
1782                })
1783            }
1784            crate::MathFunction::Sqrt => {
1785                component_wise_float!(self, span, [arg], |e| {
1786                    if e >= Zero::zero() {
1787                        Ok([e.sqrt()])
1788                    } else {
1789                        Err(ConstantEvaluatorError::InvalidMathArgValue("sqrt".into()))
1790                    }
1791                })
1792            }
1793            crate::MathFunction::InverseSqrt => {
1794                component_wise_float(self, span, [arg], |e| match e {
1795                    Float::Abstract([e]) => Ok(Float::Abstract([1. / e.sqrt()])),
1796                    Float::F32([e]) => Ok(Float::F32([1. / e.sqrt()])),
1797                    Float::F16([e]) => Ok(Float::F16([f16::from_f32(1. / f32::from(e).sqrt())])),
1798                })
1799            }
1800
1801            // bits
1802            crate::MathFunction::CountTrailingZeros => {
1803                component_wise_concrete_int!(self, span, [arg], |e| {
1804                    #[allow(clippy::useless_conversion)]
1805                    Ok([e
1806                        .trailing_zeros()
1807                        .try_into()
1808                        .expect("bit count overflowed 32 bits, somehow!?")])
1809                })
1810            }
1811            crate::MathFunction::CountLeadingZeros => {
1812                component_wise_concrete_int!(self, span, [arg], |e| {
1813                    #[allow(clippy::useless_conversion)]
1814                    Ok([e
1815                        .leading_zeros()
1816                        .try_into()
1817                        .expect("bit count overflowed 32 bits, somehow!?")])
1818                })
1819            }
1820            crate::MathFunction::CountOneBits => {
1821                component_wise_concrete_int!(self, span, [arg], |e| {
1822                    #[allow(clippy::useless_conversion)]
1823                    Ok([e
1824                        .count_ones()
1825                        .try_into()
1826                        .expect("bit count overflowed 32 bits, somehow!?")])
1827                })
1828            }
1829            crate::MathFunction::ReverseBits => {
1830                component_wise_concrete_int!(self, span, [arg], |e| { Ok([e.reverse_bits()]) })
1831            }
1832            crate::MathFunction::ExtractBits => {
1833                // https://www.w3.org/TR/WGSL/#extractBits-signed-builtin
1834                let (offset, count) = self.bitfield_range(arg1.unwrap(), arg2.unwrap(), span)?;
1835                let e = self.extract_vec(arg, true)?;
1836
1837                let result = match_literal_vector!(match e => LiteralVector {
1838                    I16 => |e| { extract_bits(e, offset, count)? },
1839                    U16 => |e| { extract_bits(e, offset, count)? },
1840                    I32 => |e| { extract_bits(e, offset, count)? },
1841                    U32 => |e| { extract_bits(e, offset, count)? },
1842                    I64 => |e| { extract_bits(e, offset, count)? },
1843                    U64 => |e| { extract_bits(e, offset, count)? },
1844                })?;
1845                result.register_as_evaluated_expr(self, span)
1846            }
1847            crate::MathFunction::InsertBits => {
1848                // https://www.w3.org/TR/WGSL/#insertBits-builtin
1849                let (offset, count) = self.bitfield_range(arg2.unwrap(), arg3.unwrap(), span)?;
1850                let e = self.extract_vec(arg, true)?;
1851                let newbits = self.extract_vec(arg1.unwrap(), true)?;
1852                if e.len() != newbits.len() {
1853                    return Err(ConstantEvaluatorError::InvalidMathArg);
1854                }
1855
1856                let result = match_literal_vector!(match (e, newbits) => LiteralVector {
1857                    I16 => |e, n| { insert_bits(e, n, offset, count)? },
1858                    U16 => |e, n| { insert_bits(e, n, offset, count)? },
1859                    I32 => |e, n| { insert_bits(e, n, offset, count)? },
1860                    U32 => |e, n| { insert_bits(e, n, offset, count)? },
1861                    I64 => |e, n| { insert_bits(e, n, offset, count)? },
1862                    U64 => |e, n| { insert_bits(e, n, offset, count)? },
1863                })?;
1864                result.register_as_evaluated_expr(self, span)
1865            }
1866            crate::MathFunction::FirstTrailingBit => {
1867                component_wise_concrete_int(self, span, [arg], |ci| Ok(first_trailing_bit(ci)))
1868            }
1869            crate::MathFunction::FirstLeadingBit => {
1870                component_wise_concrete_int(self, span, [arg], |ci| Ok(first_leading_bit(ci)))
1871            }
1872
1873            // vector
1874            crate::MathFunction::Dot4I8Packed => {
1875                self.packed_dot_product(arg, arg1.unwrap(), span, true)
1876            }
1877            crate::MathFunction::Dot4U8Packed => {
1878                self.packed_dot_product(arg, arg1.unwrap(), span, false)
1879            }
1880            crate::MathFunction::Cross => self.cross_product(arg, arg1.unwrap(), span),
1881            crate::MathFunction::Dot => {
1882                // https://www.w3.org/TR/WGSL/#dot-builtin
1883                let e1 = self.extract_vec(arg, false)?;
1884                let e2 = self.extract_vec(arg1.unwrap(), false)?;
1885                if e1.len() != e2.len() {
1886                    return Err(ConstantEvaluatorError::InvalidMathArg);
1887                }
1888
1889                fn int_dot_checked<P>(a: &[P], b: &[P]) -> Result<P, ConstantEvaluatorError>
1890                where
1891                    P: num_traits::PrimInt + num_traits::CheckedAdd + num_traits::CheckedMul,
1892                {
1893                    a.iter()
1894                        .zip(b.iter())
1895                        .map(|(&aa, bb)| aa.checked_mul(bb))
1896                        .try_fold(P::zero(), |acc, x| {
1897                            if let Some(x) = x {
1898                                acc.checked_add(&x)
1899                            } else {
1900                                None
1901                            }
1902                        })
1903                        .ok_or(ConstantEvaluatorError::Overflow(
1904                            "in dot built-in".to_string(),
1905                        ))
1906                }
1907
1908                fn int_dot_wrapping<P>(a: &[P], b: &[P]) -> P
1909                where
1910                    P: num_traits::PrimInt + num_traits::WrappingAdd + num_traits::WrappingMul,
1911                {
1912                    a.iter()
1913                        .zip(b.iter())
1914                        .map(|(&aa, bb)| aa.wrapping_mul(bb))
1915                        .fold(P::zero(), |acc, x| acc.wrapping_add(&x))
1916                }
1917
1918                let result = match_literal_vector!(match (e1, e2) => Literal {
1919                    Float => |e1, e2| {
1920                        float_dot(e1, e2).ok_or_else(|| {
1921                            ConstantEvaluatorError::Overflow("in mathfunction::dot".into())
1922                        })?
1923                    },
1924                    AbstractInt => |e1, e2 | { int_dot_checked(e1, e2)? },
1925                    I32 => |e1, e2| { int_dot_wrapping(e1, e2) },
1926                    U32 => |e1, e2| { int_dot_wrapping(e1, e2) },
1927                })?;
1928                self.register_evaluated_expr(Expression::Literal(result), span)
1929            }
1930            crate::MathFunction::Length => {
1931                // https://www.w3.org/TR/WGSL/#length-builtin
1932                let e1 = self.extract_vec(arg, true)?;
1933
1934                let result = match_literal_vector!(match e1 => Literal {
1935                    Float => |e1| {
1936                        float_length(e1).ok_or_else(|| ConstantEvaluatorError::Overflow("length".into()))?
1937                    },
1938                })?;
1939                self.register_evaluated_expr(Expression::Literal(result), span)
1940            }
1941            crate::MathFunction::Distance => {
1942                // https://www.w3.org/TR/WGSL/#distance-builtin
1943                let e1 = self.extract_vec(arg, true)?;
1944                let e2 = self.extract_vec(arg1.unwrap(), true)?;
1945                if e1.len() != e2.len() {
1946                    return Err(ConstantEvaluatorError::InvalidMathArg);
1947                }
1948
1949                fn float_distance<F>(a: &[F], b: &[F]) -> F
1950                where
1951                    F: core::ops::Mul<F>,
1952                    F: num_traits::Float + iter::Sum + core::ops::Sub,
1953                {
1954                    if a.len() == 1 {
1955                        // Avoids possible overflow in squaring
1956                        (a[0] - b[0]).abs()
1957                    } else {
1958                        a.iter()
1959                            .zip(b.iter())
1960                            .map(|(&aa, &bb)| aa - bb)
1961                            .map(|ei| ei * ei)
1962                            .sum::<F>()
1963                            .sqrt()
1964                    }
1965                }
1966                let result = match_literal_vector!(match (e1, e2) => Literal {
1967                    Float => |e1, e2| { float_distance(e1, e2) },
1968                })?;
1969                self.register_evaluated_expr(Expression::Literal(result), span)
1970            }
1971            crate::MathFunction::Normalize => {
1972                // https://www.w3.org/TR/WGSL/#normalize-builtin
1973                let e1 = self.extract_vec(arg, true)?;
1974
1975                fn float_normalize<F>(
1976                    e: &[F],
1977                ) -> Result<ArrayVec<F, { crate::VectorSize::MAX }>, ConstantEvaluatorError>
1978                where
1979                    F: core::ops::Mul<F>,
1980                    F: num_traits::Float + iter::Sum,
1981                {
1982                    let len = match float_length(e) {
1983                        Some(len) if !len.is_zero() => Ok(len),
1984                        Some(_) => Err(ConstantEvaluatorError::InvalidMathArgValue(
1985                            "normalize".into(),
1986                        )),
1987                        None => Err(ConstantEvaluatorError::Overflow("normalize".into())),
1988                    }?;
1989
1990                    let mut out = ArrayVec::new();
1991                    for &ei in e {
1992                        out.push(ei / len);
1993                    }
1994                    Ok(out)
1995                }
1996
1997                let result = match_literal_vector!(match e1 => LiteralVector {
1998                    Float => |e1| { float_normalize(e1)? },
1999                })?;
2000                result.register_as_evaluated_expr(self, span)
2001            }
2002            crate::MathFunction::FaceForward => {
2003                // https://www.w3.org/TR/WGSL/#faceForward-builtin
2004                let e1 = self.extract_vec(arg, false)?;
2005                let e2 = self.extract_vec(arg1.unwrap(), false)?;
2006                let e3 = self.extract_vec(arg2.unwrap(), false)?;
2007                if e1.len() != e2.len() || e1.len() != e3.len() {
2008                    return Err(ConstantEvaluatorError::InvalidMathArg);
2009                }
2010
2011                let result = match_literal_vector!(match (e1, e2, e3) => LiteralVector {
2012                    Float => |e1, e2, e3| {
2013                        float_face_forward(e1, e2, e3).ok_or_else(|| {
2014                            ConstantEvaluatorError::Overflow("in mathfunction::faceforward".into())
2015                        })?
2016                    },
2017                })?;
2018                result.register_as_evaluated_expr(self, span)
2019            }
2020            crate::MathFunction::Reflect => {
2021                // https://www.w3.org/TR/WGSL/#reflect-builtin
2022                let e1 = self.extract_vec(arg, false)?;
2023                let e2 = self.extract_vec(arg1.unwrap(), false)?;
2024                if e1.len() != e2.len() {
2025                    return Err(ConstantEvaluatorError::InvalidMathArg);
2026                }
2027
2028                let result = match_literal_vector!(match (e1, e2) => LiteralVector {
2029                    Float => |e1, e2| {
2030                        float_reflect(e1, e2)
2031                            .ok_or_else(|| ConstantEvaluatorError::Overflow("in mathfunction::reflect".into()))?
2032                    },
2033                })?;
2034                result.register_as_evaluated_expr(self, span)
2035            }
2036            crate::MathFunction::Refract => {
2037                // https://www.w3.org/TR/WGSL/#refract-builtin
2038                let e1 = self.extract_vec(arg, false)?;
2039                let e2 = self.extract_vec(arg1.unwrap(), false)?;
2040                // `e3` is the scalar ratio of indices of refraction, extracted
2041                // as a LiteralVector like `e1` and `e2`.
2042                let e3 = self.extract_vec(arg2.unwrap(), true)?;
2043                if e1.len() != e2.len() || e3.len() != 1 {
2044                    return Err(ConstantEvaluatorError::InvalidMathArg);
2045                }
2046
2047                let result = match_literal_vector!(match (e1, e2, e3) => LiteralVector {
2048                    Float => |e1, e2, e3| {
2049                        float_refract(e1, e2, e3[0])
2050                            .ok_or_else(|| ConstantEvaluatorError::Overflow("in mathfunction::refract".into()))?
2051                    },
2052                })?;
2053                result.register_as_evaluated_expr(self, span)
2054            }
2055
2056            // unimplemented
2057            crate::MathFunction::Modf
2058            | crate::MathFunction::Frexp
2059            | crate::MathFunction::Ldexp
2060            | crate::MathFunction::Outer
2061            | crate::MathFunction::Mix
2062            | crate::MathFunction::SmoothStep
2063            | crate::MathFunction::Inverse
2064            | crate::MathFunction::Transpose
2065            | crate::MathFunction::Determinant
2066            | crate::MathFunction::QuantizeToF16
2067            | crate::MathFunction::Pack4x8snorm
2068            | crate::MathFunction::Pack4x8unorm
2069            | crate::MathFunction::Pack2x16snorm
2070            | crate::MathFunction::Pack2x16unorm
2071            | crate::MathFunction::Pack2x16float
2072            | crate::MathFunction::Pack4xI8
2073            | crate::MathFunction::Pack4xU8
2074            | crate::MathFunction::Pack4xI8Clamp
2075            | crate::MathFunction::Pack4xU8Clamp
2076            | crate::MathFunction::Unpack4x8snorm
2077            | crate::MathFunction::Unpack4x8unorm
2078            | crate::MathFunction::Unpack2x16snorm
2079            | crate::MathFunction::Unpack2x16unorm
2080            | crate::MathFunction::Unpack2x16float
2081            | crate::MathFunction::Unpack4xI8
2082            | crate::MathFunction::Unpack4xU8 => Err(ConstantEvaluatorError::NotImplemented(
2083                format!("{fun:?} built-in function"),
2084            )),
2085        }
2086    }
2087
2088    /// Dot product of two packed vectors (`dot4I8Packed` and `dot4U8Packed`)
2089    fn packed_dot_product(
2090        &mut self,
2091        a: Handle<Expression>,
2092        b: Handle<Expression>,
2093        span: Span,
2094        signed: bool,
2095    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2096        let Expression::Literal(Literal::U32(a)) = self.expressions[a] else {
2097            return Err(ConstantEvaluatorError::InvalidMathArg);
2098        };
2099        let Expression::Literal(Literal::U32(b)) = self.expressions[b] else {
2100            return Err(ConstantEvaluatorError::InvalidMathArg);
2101        };
2102
2103        let result = if signed {
2104            Literal::I32(
2105                (a & 0xFF) as i8 as i32 * (b & 0xFF) as i8 as i32
2106                    + ((a >> 8) & 0xFF) as i8 as i32 * ((b >> 8) & 0xFF) as i8 as i32
2107                    + ((a >> 16) & 0xFF) as i8 as i32 * ((b >> 16) & 0xFF) as i8 as i32
2108                    + ((a >> 24) & 0xFF) as i8 as i32 * ((b >> 24) & 0xFF) as i8 as i32,
2109            )
2110        } else {
2111            Literal::U32(
2112                (a & 0xFF) * (b & 0xFF)
2113                    + ((a >> 8) & 0xFF) * ((b >> 8) & 0xFF)
2114                    + ((a >> 16) & 0xFF) * ((b >> 16) & 0xFF)
2115                    + ((a >> 24) & 0xFF) * ((b >> 24) & 0xFF),
2116            )
2117        };
2118
2119        self.register_evaluated_expr(Expression::Literal(result), span)
2120    }
2121
2122    /// Vector cross product.
2123    fn cross_product(
2124        &mut self,
2125        a: Handle<Expression>,
2126        b: Handle<Expression>,
2127        span: Span,
2128    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2129        use Literal as Li;
2130
2131        let (a, ty) = self.extract_vec_with_size::<3>(a)?;
2132        let (b, _) = self.extract_vec_with_size::<3>(b)?;
2133
2134        let product = match (a, b) {
2135            (
2136                [Li::AbstractInt(a0), Li::AbstractInt(a1), Li::AbstractInt(a2)],
2137                [Li::AbstractInt(b0), Li::AbstractInt(b1), Li::AbstractInt(b2)],
2138            ) => {
2139                // `cross` has no overload for AbstractInt, so AbstractInt
2140                // arguments are automatically converted to AbstractFloat. Since
2141                // `f64` has a much wider range than `i64`, there's no danger of
2142                // overflow here.
2143                let p = cross_product(
2144                    [a0 as f64, a1 as f64, a2 as f64],
2145                    [b0 as f64, b1 as f64, b2 as f64],
2146                );
2147                [
2148                    Li::AbstractFloat(p[0]),
2149                    Li::AbstractFloat(p[1]),
2150                    Li::AbstractFloat(p[2]),
2151                ]
2152            }
2153            (
2154                [Li::AbstractFloat(a0), Li::AbstractFloat(a1), Li::AbstractFloat(a2)],
2155                [Li::AbstractFloat(b0), Li::AbstractFloat(b1), Li::AbstractFloat(b2)],
2156            ) => {
2157                let p = cross_product([a0, a1, a2], [b0, b1, b2]);
2158                [
2159                    Li::AbstractFloat(p[0]),
2160                    Li::AbstractFloat(p[1]),
2161                    Li::AbstractFloat(p[2]),
2162                ]
2163            }
2164            ([Li::F16(a0), Li::F16(a1), Li::F16(a2)], [Li::F16(b0), Li::F16(b1), Li::F16(b2)]) => {
2165                let p = cross_product([a0, a1, a2], [b0, b1, b2]);
2166                [Li::F16(p[0]), Li::F16(p[1]), Li::F16(p[2])]
2167            }
2168            ([Li::F32(a0), Li::F32(a1), Li::F32(a2)], [Li::F32(b0), Li::F32(b1), Li::F32(b2)]) => {
2169                let p = cross_product([a0, a1, a2], [b0, b1, b2]);
2170                [Li::F32(p[0]), Li::F32(p[1]), Li::F32(p[2])]
2171            }
2172            ([Li::F64(a0), Li::F64(a1), Li::F64(a2)], [Li::F64(b0), Li::F64(b1), Li::F64(b2)]) => {
2173                let p = cross_product([a0, a1, a2], [b0, b1, b2]);
2174                [Li::F64(p[0]), Li::F64(p[1]), Li::F64(p[2])]
2175            }
2176            _ => return Err(ConstantEvaluatorError::InvalidMathArg),
2177        };
2178
2179        let p0 = self.register_evaluated_expr(Expression::Literal(product[0]), span)?;
2180        let p1 = self.register_evaluated_expr(Expression::Literal(product[1]), span)?;
2181        let p2 = self.register_evaluated_expr(Expression::Literal(product[2]), span)?;
2182
2183        self.register_evaluated_expr(
2184            Expression::Compose {
2185                ty,
2186                components: vec![p0, p1, p2],
2187            },
2188            span,
2189        )
2190    }
2191
2192    /// Extract the values of a `vecN` from `expr`.
2193    ///
2194    /// Return the value of `expr`, whose type is `vecN<S>` for some
2195    /// vector size `N` and scalar `S`, as an array of `N` [`Literal`]
2196    /// values.
2197    ///
2198    /// Also return the type handle from the `Compose` expression.
2199    fn extract_vec_with_size<const N: usize>(
2200        &mut self,
2201        expr: Handle<Expression>,
2202    ) -> Result<([Literal; N], Handle<Type>), ConstantEvaluatorError> {
2203        let span = self.expressions.get_span(expr);
2204        let expr = self.eval_zero_value_and_splat(expr, span)?;
2205        let Expression::Compose { ty, ref components } = self.expressions[expr] else {
2206            return Err(ConstantEvaluatorError::InvalidMathArg);
2207        };
2208
2209        let mut value = [Literal::Bool(false); N];
2210        for (component, elt) in
2211            crate::proc::flatten_compose(ty, components, self.expressions, self.types)
2212                .zip(value.iter_mut())
2213        {
2214            let Expression::Literal(literal) = self.expressions[component] else {
2215                return Err(ConstantEvaluatorError::InvalidMathArg);
2216            };
2217            *elt = literal;
2218        }
2219
2220        Ok((value, ty))
2221    }
2222
2223    /// Extract the values of a `vecN` from `expr`.
2224    ///
2225    /// Return the value of `expr`, whose type is `vecN<S>` for some
2226    /// vector size `N` and scalar `S`, as an array of `N` [`Literal`]
2227    /// values.
2228    ///
2229    /// Also return the type handle from the `Compose` expression.
2230    fn extract_vec(
2231        &mut self,
2232        expr: Handle<Expression>,
2233        allow_single: bool,
2234    ) -> Result<LiteralVector, ConstantEvaluatorError> {
2235        let span = self.expressions.get_span(expr);
2236        let expr = self.eval_zero_value_and_splat(expr, span)?;
2237
2238        match self.expressions[expr] {
2239            Expression::Literal(literal) if allow_single => {
2240                Ok(LiteralVector::from_literal(literal))
2241            }
2242            Expression::Compose { ty, ref components } => {
2243                let mut components_out = ArrayVec::<Literal, { crate::VectorSize::MAX }>::new();
2244                for expr in
2245                    crate::proc::flatten_compose(ty, components, self.expressions, self.types)
2246                {
2247                    match self.expressions[expr] {
2248                        Expression::Literal(l) => components_out.push(l),
2249                        _ => return Err(ConstantEvaluatorError::InvalidMathArg),
2250                    }
2251                }
2252                LiteralVector::from_literal_vec(components_out)
2253            }
2254            _ => Err(ConstantEvaluatorError::InvalidMathArg),
2255        }
2256    }
2257
2258    /// Extract the `offset` and `count` arguments shared by the `extractBits`
2259    /// and `insertBits` built ins, both of which are `u32` scalars.
2260    fn bitfield_range(
2261        &mut self,
2262        offset: Handle<Expression>,
2263        count: Handle<Expression>,
2264        span: Span,
2265    ) -> Result<(u32, u32), ConstantEvaluatorError> {
2266        let offset = self.eval_zero_value_and_splat(offset, span)?;
2267        let count = self.eval_zero_value_and_splat(count, span)?;
2268
2269        match (&self.expressions[offset], &self.expressions[count]) {
2270            (
2271                &Expression::Literal(Literal::U32(offset)),
2272                &Expression::Literal(Literal::U32(count)),
2273            ) => Ok((offset, count)),
2274            _ => Err(ConstantEvaluatorError::InvalidMathArg),
2275        }
2276    }
2277
2278    fn array_length(
2279        &mut self,
2280        array: Handle<Expression>,
2281        span: Span,
2282    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2283        match self.expressions[array] {
2284            Expression::ZeroValue(ty) | Expression::Compose { ty, .. } => {
2285                match self.types[ty].inner {
2286                    TypeInner::Array { size, .. } => match size {
2287                        ArraySize::Constant(len) => {
2288                            let expr = Expression::Literal(Literal::U32(len.get()));
2289                            self.register_evaluated_expr(expr, span)
2290                        }
2291                        ArraySize::Pending(_) => Err(ConstantEvaluatorError::ArrayLengthOverridden),
2292                        ArraySize::Dynamic => Err(ConstantEvaluatorError::ArrayLengthDynamic),
2293                    },
2294                    _ => Err(ConstantEvaluatorError::InvalidArrayLengthArg),
2295                }
2296            }
2297            _ => Err(ConstantEvaluatorError::InvalidArrayLengthArg),
2298        }
2299    }
2300
2301    fn access(
2302        &mut self,
2303        base: Handle<Expression>,
2304        index: usize,
2305        span: Span,
2306    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2307        match self.expressions[base] {
2308            Expression::ZeroValue(ty) => {
2309                let ty_inner = &self.types[ty].inner;
2310                let components = ty_inner
2311                    .components()
2312                    .ok_or(ConstantEvaluatorError::InvalidAccessBase)?;
2313
2314                if index >= components as usize {
2315                    Err(ConstantEvaluatorError::InvalidAccessBase)
2316                } else {
2317                    let ty_res = ty_inner
2318                        .component_type(index)
2319                        .ok_or(ConstantEvaluatorError::InvalidAccessIndex)?;
2320                    let ty = match ty_res {
2321                        crate::proc::TypeResolution::Handle(ty) => ty,
2322                        crate::proc::TypeResolution::Value(inner) => {
2323                            self.types.insert(Type { name: None, inner }, span)
2324                        }
2325                    };
2326                    self.register_evaluated_expr(Expression::ZeroValue(ty), span)
2327                }
2328            }
2329            Expression::Splat { size, value } => {
2330                if index >= size as usize {
2331                    Err(ConstantEvaluatorError::InvalidAccessBase)
2332                } else {
2333                    Ok(value)
2334                }
2335            }
2336            Expression::Compose { ty, ref components } => {
2337                let _ = self.types[ty]
2338                    .inner
2339                    .components()
2340                    .ok_or(ConstantEvaluatorError::InvalidAccessBase)?;
2341
2342                crate::proc::flatten_compose(ty, components, self.expressions, self.types)
2343                    .nth(index)
2344                    .ok_or(ConstantEvaluatorError::InvalidAccessIndex)
2345            }
2346            _ => Err(ConstantEvaluatorError::InvalidAccessBase),
2347        }
2348    }
2349
2350    /// Lower [`ZeroValue`] and [`Splat`] expressions to [`Literal`] and [`Compose`] expressions.
2351    ///
2352    /// [`ZeroValue`]: Expression::ZeroValue
2353    /// [`Splat`]: Expression::Splat
2354    /// [`Literal`]: Expression::Literal
2355    /// [`Compose`]: Expression::Compose
2356    fn eval_zero_value_and_splat(
2357        &mut self,
2358        mut expr: Handle<Expression>,
2359        span: Span,
2360    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2361        // If expr is a Compose expression, eliminate ZeroValue and Splat expressions for
2362        // each of its components.
2363        if let Expression::Compose { ty, ref components } = self.expressions[expr] {
2364            let components = components
2365                .clone()
2366                .iter()
2367                .map(|component| self.eval_zero_value_and_splat(*component, span))
2368                .collect::<Result<_, _>>()?;
2369            expr = self.register_evaluated_expr(Expression::Compose { ty, components }, span)?;
2370        }
2371
2372        // The result of the splat() for a Splat of a scalar ZeroValue is a
2373        // vector ZeroValue, so we must call eval_zero_value_impl() after
2374        // splat() in order to ensure we have no ZeroValues remaining.
2375        if let Expression::Splat { size, value } = self.expressions[expr] {
2376            expr = self.splat(value, size, span)?;
2377        }
2378        if let Expression::ZeroValue(ty) = self.expressions[expr] {
2379            expr = self.eval_zero_value_impl(ty, span)?;
2380        }
2381        Ok(expr)
2382    }
2383
2384    /// Lower [`ZeroValue`] expressions to [`Literal`] and [`Compose`] expressions.
2385    ///
2386    /// [`ZeroValue`]: Expression::ZeroValue
2387    /// [`Literal`]: Expression::Literal
2388    /// [`Compose`]: Expression::Compose
2389    fn eval_zero_value(
2390        &mut self,
2391        expr: Handle<Expression>,
2392        span: Span,
2393    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2394        match self.expressions[expr] {
2395            Expression::ZeroValue(ty) => self.eval_zero_value_impl(ty, span),
2396            _ => Ok(expr),
2397        }
2398    }
2399
2400    /// Lower [`ZeroValue`] expressions to [`Literal`] and [`Compose`] expressions.
2401    ///
2402    /// [`ZeroValue`]: Expression::ZeroValue
2403    /// [`Literal`]: Expression::Literal
2404    /// [`Compose`]: Expression::Compose
2405    fn eval_zero_value_impl(
2406        &mut self,
2407        ty: Handle<Type>,
2408        span: Span,
2409    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2410        match self.types[ty].inner {
2411            TypeInner::Scalar(scalar) => {
2412                let expr = Expression::Literal(
2413                    Literal::zero(scalar).ok_or(ConstantEvaluatorError::TypeNotConstructible)?,
2414                );
2415                self.register_evaluated_expr(expr, span)
2416            }
2417            TypeInner::Vector { size, scalar } => {
2418                let scalar_ty = self.types.insert(
2419                    Type {
2420                        name: None,
2421                        inner: TypeInner::Scalar(scalar),
2422                    },
2423                    span,
2424                );
2425                let el = self.eval_zero_value_impl(scalar_ty, span)?;
2426                let expr = Expression::Compose {
2427                    ty,
2428                    components: vec![el; size as usize],
2429                };
2430                self.register_evaluated_expr(expr, span)
2431            }
2432            TypeInner::Matrix {
2433                columns,
2434                rows,
2435                scalar,
2436            } => {
2437                let vec_ty = self.types.insert(
2438                    Type {
2439                        name: None,
2440                        inner: TypeInner::Vector { size: rows, scalar },
2441                    },
2442                    span,
2443                );
2444                let el = self.eval_zero_value_impl(vec_ty, span)?;
2445                let expr = Expression::Compose {
2446                    ty,
2447                    components: vec![el; columns as usize],
2448                };
2449                self.register_evaluated_expr(expr, span)
2450            }
2451            TypeInner::Array {
2452                base,
2453                size: ArraySize::Constant(size),
2454                ..
2455            } => {
2456                let el = self.eval_zero_value_impl(base, span)?;
2457                let expr = Expression::Compose {
2458                    ty,
2459                    components: vec![el; size.get() as usize],
2460                };
2461                self.register_evaluated_expr(expr, span)
2462            }
2463            TypeInner::Struct { ref members, .. } => {
2464                let types: Vec<_> = members.iter().map(|m| m.ty).collect();
2465                let mut components = Vec::with_capacity(members.len());
2466                for ty in types {
2467                    components.push(self.eval_zero_value_impl(ty, span)?);
2468                }
2469                let expr = Expression::Compose { ty, components };
2470                self.register_evaluated_expr(expr, span)
2471            }
2472            _ => Err(ConstantEvaluatorError::TypeNotConstructible),
2473        }
2474    }
2475
2476    /// Convert the scalar components of `expr` to `target`.
2477    ///
2478    /// Treat `span` as the location of the resulting expression.
2479    pub fn cast(
2480        &mut self,
2481        expr: Handle<Expression>,
2482        target: crate::Scalar,
2483        span: Span,
2484    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2485        use crate::Scalar as Sc;
2486
2487        let expr = self.eval_zero_value(expr, span)?;
2488
2489        let make_error = || -> Result<_, ConstantEvaluatorError> {
2490            let from = format!("{:?} {:?}", expr, self.expressions[expr]);
2491
2492            #[cfg(feature = "wgsl-in")]
2493            let to = target.to_wgsl_for_diagnostics();
2494
2495            #[cfg(not(feature = "wgsl-in"))]
2496            let to = format!("{target:?}");
2497
2498            Err(ConstantEvaluatorError::InvalidCastArg { from, to })
2499        };
2500
2501        use crate::proc::type_methods::IntFloatLimits;
2502
2503        let expr = match self.expressions[expr] {
2504            Expression::Literal(literal) => {
2505                let literal = match target {
2506                    Sc::I16 => Literal::I16(match literal {
2507                        Literal::I16(v) => v,
2508                        Literal::U16(v) => v as i16,
2509                        Literal::I32(v) => v as i16,
2510                        Literal::U32(v) => v as i16,
2511                        Literal::F32(v) => v.clamp(i16::MIN as f32, i16::MAX as f32) as i16,
2512                        Literal::F16(v) => {
2513                            f16::to_f32(v).clamp(i16::MIN as f32, i16::MAX as f32) as i16
2514                        }
2515                        Literal::Bool(v) => v as i16,
2516                        Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2517                            return make_error();
2518                        }
2519                        Literal::AbstractInt(v) => v as i16,
2520                        Literal::AbstractFloat(v) => v as i16,
2521                    }),
2522                    Sc::U16 => Literal::U16(match literal {
2523                        Literal::I16(v) => v as u16,
2524                        Literal::U16(v) => v,
2525                        Literal::I32(v) => v as u16,
2526                        Literal::U32(v) => v as u16,
2527                        Literal::F32(v) => v.clamp(u16::MIN as f32, u16::MAX as f32) as u16,
2528                        Literal::F16(v) => f16::to_u16(&v.max(f16::ZERO)).unwrap(),
2529                        Literal::Bool(v) => v as u16,
2530                        Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2531                            return make_error();
2532                        }
2533                        Literal::AbstractInt(v) => v as u16,
2534                        Literal::AbstractFloat(v) => v as u16,
2535                    }),
2536                    Sc::I32 => Literal::I32(match literal {
2537                        Literal::I16(v) => v as i32,
2538                        Literal::U16(v) => v as i32,
2539                        Literal::I32(v) => v,
2540                        Literal::U32(v) => v as i32,
2541                        Literal::F32(v) => v.clamp(i32::min_float(), i32::max_float()) as i32,
2542                        Literal::F16(v) => f16::to_i32(&v).unwrap(), //Only None on NaN or Inf
2543                        Literal::Bool(v) => v as i32,
2544                        Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2545                            return make_error();
2546                        }
2547                        Literal::AbstractInt(v) => i32::try_from_abstract(v)?,
2548                        Literal::AbstractFloat(v) => i32::try_from_abstract(v)?,
2549                    }),
2550                    Sc::U32 => Literal::U32(match literal {
2551                        Literal::I16(v) => v as u32,
2552                        Literal::U16(v) => v as u32,
2553                        Literal::I32(v) => v as u32,
2554                        Literal::U32(v) => v,
2555                        Literal::F32(v) => v.clamp(u32::min_float(), u32::max_float()) as u32,
2556                        // max(0) avoids None due to negative, therefore only None on NaN or Inf
2557                        Literal::F16(v) => f16::to_u32(&v.max(f16::ZERO)).unwrap(),
2558                        Literal::Bool(v) => v as u32,
2559                        Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2560                            return make_error();
2561                        }
2562                        Literal::AbstractInt(v) => u32::try_from_abstract(v)?,
2563                        Literal::AbstractFloat(v) => u32::try_from_abstract(v)?,
2564                    }),
2565                    Sc::I64 => Literal::I64(match literal {
2566                        Literal::I16(v) => v as i64,
2567                        Literal::U16(v) => v as i64,
2568                        Literal::I32(v) => v as i64,
2569                        Literal::U32(v) => v as i64,
2570                        Literal::F32(v) => v.clamp(i64::min_float(), i64::max_float()) as i64,
2571                        Literal::Bool(v) => v as i64,
2572                        Literal::F64(v) => v.clamp(i64::min_float(), i64::max_float()) as i64,
2573                        Literal::I64(v) => v,
2574                        Literal::U64(v) => v as i64,
2575                        Literal::F16(v) => f16::to_i64(&v).unwrap(), //Only None on NaN or Inf
2576                        Literal::AbstractInt(v) => i64::try_from_abstract(v)?,
2577                        Literal::AbstractFloat(v) => i64::try_from_abstract(v)?,
2578                    }),
2579                    Sc::U64 => Literal::U64(match literal {
2580                        Literal::I16(v) => v as u64,
2581                        Literal::U16(v) => v as u64,
2582                        Literal::I32(v) => v as u64,
2583                        Literal::U32(v) => v as u64,
2584                        Literal::F32(v) => v.clamp(u64::min_float(), u64::max_float()) as u64,
2585                        Literal::Bool(v) => v as u64,
2586                        Literal::F64(v) => v.clamp(u64::min_float(), u64::max_float()) as u64,
2587                        Literal::I64(v) => v as u64,
2588                        Literal::U64(v) => v,
2589                        // max(0) avoids None due to negative, therefore only None on NaN or Inf
2590                        Literal::F16(v) => f16::to_u64(&v.max(f16::ZERO)).unwrap(),
2591                        Literal::AbstractInt(v) => u64::try_from_abstract(v)?,
2592                        Literal::AbstractFloat(v) => u64::try_from_abstract(v)?,
2593                    }),
2594                    Sc::F16 => Literal::F16(match literal {
2595                        Literal::F16(v) => v,
2596                        Literal::F32(v) => f16::from_f32(v),
2597                        Literal::F64(v) => f16::from_f64(v),
2598                        Literal::Bool(v) => f16::from_u32(v as u32).unwrap(),
2599                        Literal::I16(v) => f16::from_f32(v as f32),
2600                        Literal::U16(v) => f16::from_f32(v as f32),
2601                        Literal::I64(v) => f16::from_i64(v).unwrap(),
2602                        Literal::U64(v) => f16::from_u64(v).unwrap(),
2603                        Literal::I32(v) => f16::from_i32(v).unwrap(),
2604                        Literal::U32(v) => f16::from_u32(v).unwrap(),
2605                        Literal::AbstractFloat(v) => f16::try_from_abstract(v)?,
2606                        Literal::AbstractInt(v) => f16::try_from_abstract(v)?,
2607                    }),
2608                    Sc::F32 => Literal::F32(match literal {
2609                        Literal::I16(v) => v as f32,
2610                        Literal::U16(v) => v as f32,
2611                        Literal::I32(v) => v as f32,
2612                        Literal::U32(v) => v as f32,
2613                        Literal::F32(v) => v,
2614                        Literal::Bool(v) => v as u32 as f32,
2615                        Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2616                            return make_error();
2617                        }
2618                        Literal::F16(v) => f16::to_f32(v),
2619                        Literal::AbstractInt(v) => f32::try_from_abstract(v)?,
2620                        Literal::AbstractFloat(v) => f32::try_from_abstract(v)?,
2621                    }),
2622                    Sc::F64 => Literal::F64(match literal {
2623                        Literal::I16(v) => v as f64,
2624                        Literal::U16(v) => v as f64,
2625                        Literal::I32(v) => v as f64,
2626                        Literal::U32(v) => v as f64,
2627                        Literal::F16(v) => f16::to_f64(v),
2628                        Literal::F32(v) => v as f64,
2629                        Literal::F64(v) => v,
2630                        Literal::Bool(v) => v as u32 as f64,
2631                        Literal::I64(_) | Literal::U64(_) => return make_error(),
2632                        Literal::AbstractInt(v) => f64::try_from_abstract(v)?,
2633                        Literal::AbstractFloat(v) => f64::try_from_abstract(v)?,
2634                    }),
2635                    Sc::BOOL => Literal::Bool(match literal {
2636                        Literal::I16(v) => v != 0,
2637                        Literal::U16(v) => v != 0,
2638                        Literal::I32(v) => v != 0,
2639                        Literal::U32(v) => v != 0,
2640                        Literal::F32(v) => v != 0.0,
2641                        Literal::F16(v) => v != f16::zero(),
2642                        Literal::Bool(v) => v,
2643                        Literal::AbstractInt(v) => v != 0,
2644                        Literal::AbstractFloat(v) => v != 0.0,
2645                        Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2646                            return make_error();
2647                        }
2648                    }),
2649                    Sc::ABSTRACT_FLOAT => Literal::AbstractFloat(match literal {
2650                        Literal::AbstractInt(v) => {
2651                            // Overflow is forbidden, but inexact conversions
2652                            // are fine. The range of f64 is far larger than
2653                            // that of i64, so we don't have to check anything
2654                            // here.
2655                            v as f64
2656                        }
2657                        Literal::AbstractFloat(v) => v,
2658                        _ => return make_error(),
2659                    }),
2660                    Sc::ABSTRACT_INT => Literal::AbstractInt(match literal {
2661                        Literal::AbstractInt(v) => v,
2662                        _ => return make_error(),
2663                    }),
2664                    _ => {
2665                        log::debug!("Constant evaluator refused to convert value to {target:?}");
2666                        return make_error();
2667                    }
2668                };
2669                Expression::Literal(literal)
2670            }
2671            Expression::Compose {
2672                ty,
2673                components: ref src_components,
2674            } => {
2675                let ty_inner = match self.types[ty].inner {
2676                    TypeInner::Vector { size, .. } => TypeInner::Vector {
2677                        size,
2678                        scalar: target,
2679                    },
2680                    TypeInner::Matrix { columns, rows, .. } => TypeInner::Matrix {
2681                        columns,
2682                        rows,
2683                        scalar: target,
2684                    },
2685                    _ => return make_error(),
2686                };
2687
2688                let mut components = src_components.clone();
2689                for component in &mut components {
2690                    *component = self.cast(*component, target, span)?;
2691                }
2692
2693                let ty = self.types.insert(
2694                    Type {
2695                        name: None,
2696                        inner: ty_inner,
2697                    },
2698                    span,
2699                );
2700
2701                Expression::Compose { ty, components }
2702            }
2703            Expression::Splat { size, value } => {
2704                let value_span = self.expressions.get_span(value);
2705                let cast_value = self.cast(value, target, value_span)?;
2706                Expression::Splat {
2707                    size,
2708                    value: cast_value,
2709                }
2710            }
2711            _ => return make_error(),
2712        };
2713
2714        self.register_evaluated_expr(expr, span)
2715    }
2716
2717    /// Convert the scalar leaves of  `expr` to `target`, handling arrays.
2718    ///
2719    /// `expr` must be a `Compose` expression whose type is a scalar, vector,
2720    /// matrix, or nested arrays of such.
2721    ///
2722    /// This is basically the same as the [`cast`] method, except that that
2723    /// should only handle Naga [`As`] expressions, which cannot convert arrays.
2724    ///
2725    /// Treat `span` as the location of the resulting expression.
2726    ///
2727    /// [`cast`]: ConstantEvaluator::cast
2728    /// [`As`]: crate::Expression::As
2729    pub fn cast_array(
2730        &mut self,
2731        expr: Handle<Expression>,
2732        target: crate::Scalar,
2733        span: Span,
2734    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2735        let expr = self.check_and_get(expr)?;
2736
2737        let Expression::Compose { ty, ref components } = self.expressions[expr] else {
2738            return self.cast(expr, target, span);
2739        };
2740
2741        let TypeInner::Array {
2742            base: _,
2743            size,
2744            stride: _,
2745        } = self.types[ty].inner
2746        else {
2747            return self.cast(expr, target, span);
2748        };
2749
2750        let mut components = components.clone();
2751        for component in &mut components {
2752            *component = self.cast_array(*component, target, span)?;
2753        }
2754
2755        let first = components.first().unwrap();
2756        let new_base = match self.resolve_type(*first)? {
2757            crate::proc::TypeResolution::Handle(ty) => ty,
2758            crate::proc::TypeResolution::Value(inner) => {
2759                self.types.insert(Type { name: None, inner }, span)
2760            }
2761        };
2762        let mut layouter = core::mem::take(self.layouter);
2763        layouter.update(self.to_ctx()).map_err(|err| {
2764            // The layouter operates lazily, so the error
2765            // could be for any pending type.
2766            let crate::proc::LayoutErrorInner::TooLarge = err.inner else {
2767                unreachable!("unexpected layout error: {err:?}");
2768            };
2769            ConstantEvaluatorError::TypeTooLarge(err.ty)
2770        })?;
2771        *self.layouter = layouter;
2772
2773        let new_base_stride = self.layouter[new_base].to_stride();
2774        let new_array_ty = self.types.insert(
2775            Type {
2776                name: None,
2777                inner: TypeInner::Array {
2778                    base: new_base,
2779                    size,
2780                    stride: new_base_stride,
2781                },
2782            },
2783            span,
2784        );
2785
2786        let compose = Expression::Compose {
2787            ty: new_array_ty,
2788            components,
2789        };
2790        self.register_evaluated_expr(compose, span)
2791    }
2792
2793    fn unary_op(
2794        &mut self,
2795        op: UnaryOperator,
2796        expr: Handle<Expression>,
2797        span: Span,
2798    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2799        let expr = self.eval_zero_value_and_splat(expr, span)?;
2800
2801        let expr = match self.expressions[expr] {
2802            Expression::Literal(value) => Expression::Literal(match op {
2803                UnaryOperator::Negate => match value {
2804                    Literal::I16(v) => Literal::I16(v.wrapping_neg()),
2805                    Literal::I32(v) => Literal::I32(v.wrapping_neg()),
2806                    Literal::I64(v) => Literal::I64(v.wrapping_neg()),
2807                    Literal::F32(v) => Literal::F32(-v),
2808                    Literal::F16(v) => Literal::F16(-v),
2809                    Literal::F64(v) => Literal::F64(-v),
2810                    Literal::AbstractInt(v) => Literal::AbstractInt(v.wrapping_neg()),
2811                    Literal::AbstractFloat(v) => Literal::AbstractFloat(-v),
2812                    _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2813                },
2814                UnaryOperator::LogicalNot => match value {
2815                    Literal::Bool(v) => Literal::Bool(!v),
2816                    _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2817                },
2818                UnaryOperator::BitwiseNot => match value {
2819                    Literal::I16(v) => Literal::I16(!v),
2820                    Literal::I32(v) => Literal::I32(!v),
2821                    Literal::I64(v) => Literal::I64(!v),
2822                    Literal::U16(v) => Literal::U16(!v),
2823                    Literal::U32(v) => Literal::U32(!v),
2824                    Literal::U64(v) => Literal::U64(!v),
2825                    Literal::AbstractInt(v) => Literal::AbstractInt(!v),
2826                    _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2827                },
2828            }),
2829            Expression::Compose {
2830                ty,
2831                components: ref src_components,
2832            } => {
2833                match self.types[ty].inner {
2834                    TypeInner::Vector { .. } => (),
2835                    _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2836                }
2837
2838                let mut components = src_components.clone();
2839                for component in &mut components {
2840                    *component = self.unary_op(op, *component, span)?;
2841                }
2842
2843                Expression::Compose { ty, components }
2844            }
2845            _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2846        };
2847
2848        self.register_evaluated_expr(expr, span)
2849    }
2850
2851    fn binary_op(
2852        &mut self,
2853        op: BinaryOperator,
2854        left: Handle<Expression>,
2855        right: Handle<Expression>,
2856        span: Span,
2857    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2858        let left = self.eval_zero_value_and_splat(left, span)?;
2859        let right = self.eval_zero_value_and_splat(right, span)?;
2860
2861        // Note: in most cases constant evaluation checks for overflow, but for
2862        // i32/u32, it uses wrapping arithmetic. See
2863        // <https://gpuweb.github.io/gpuweb/wgsl/#integer-types>.
2864
2865        let expr = match (&self.expressions[left], &self.expressions[right]) {
2866            (&Expression::Literal(left_value), &Expression::Literal(right_value)) => {
2867                if !matches!(op, BinaryOperator::ShiftLeft | BinaryOperator::ShiftRight)
2868                    && core::mem::discriminant(&left_value) != core::mem::discriminant(&right_value)
2869                {
2870                    return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
2871                }
2872
2873                if matches!(
2874                    (left_value, op),
2875                    (
2876                        Literal::Bool(_),
2877                        BinaryOperator::Less
2878                            | BinaryOperator::LessEqual
2879                            | BinaryOperator::Greater
2880                            | BinaryOperator::GreaterEqual
2881                    )
2882                ) {
2883                    return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
2884                }
2885
2886                let literal = match op {
2887                    BinaryOperator::Equal => Literal::Bool(left_value == right_value),
2888                    BinaryOperator::NotEqual => Literal::Bool(left_value != right_value),
2889                    BinaryOperator::Less => Literal::Bool(left_value < right_value),
2890                    BinaryOperator::LessEqual => Literal::Bool(left_value <= right_value),
2891                    BinaryOperator::Greater => Literal::Bool(left_value > right_value),
2892                    BinaryOperator::GreaterEqual => Literal::Bool(left_value >= right_value),
2893
2894                    _ => match (left_value, right_value) {
2895                        (Literal::I16(a), Literal::I16(b)) => Literal::I16(match op {
2896                            BinaryOperator::Add => a.wrapping_add(b),
2897                            BinaryOperator::Subtract => a.wrapping_sub(b),
2898                            BinaryOperator::Multiply => a.wrapping_mul(b),
2899                            BinaryOperator::Divide => a.checked_div(b).ok_or_else(|| {
2900                                if b == 0 {
2901                                    ConstantEvaluatorError::DivisionByZero
2902                                } else {
2903                                    ConstantEvaluatorError::Overflow("division".into())
2904                                }
2905                            })?,
2906                            BinaryOperator::Modulo => a.checked_rem(b).ok_or_else(|| {
2907                                if b == 0 {
2908                                    ConstantEvaluatorError::RemainderByZero
2909                                } else {
2910                                    ConstantEvaluatorError::Overflow("remainder".into())
2911                                }
2912                            })?,
2913                            BinaryOperator::And => a & b,
2914                            BinaryOperator::ExclusiveOr => a ^ b,
2915                            BinaryOperator::InclusiveOr => a | b,
2916                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2917                        }),
2918                        (Literal::I16(a), Literal::U32(b)) => Literal::I16(match op {
2919                            BinaryOperator::ShiftLeft => {
2920                                if (if a.is_negative() { !a } else { a }).leading_zeros() <= b {
2921                                    return Err(ConstantEvaluatorError::Overflow("<<".to_string()));
2922                                }
2923                                a.checked_shl(b)
2924                                    .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?
2925                            }
2926                            BinaryOperator::ShiftRight => a
2927                                .checked_shr(b)
2928                                .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
2929                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2930                        }),
2931                        (Literal::U16(a), Literal::U16(b)) => Literal::U16(match op {
2932                            BinaryOperator::Add => a.wrapping_add(b),
2933                            BinaryOperator::Subtract => a.wrapping_sub(b),
2934                            BinaryOperator::Multiply => a.wrapping_mul(b),
2935                            BinaryOperator::Divide => a
2936                                .checked_div(b)
2937                                .ok_or(ConstantEvaluatorError::DivisionByZero)?,
2938                            BinaryOperator::Modulo => a
2939                                .checked_rem(b)
2940                                .ok_or(ConstantEvaluatorError::RemainderByZero)?,
2941                            BinaryOperator::And => a & b,
2942                            BinaryOperator::ExclusiveOr => a ^ b,
2943                            BinaryOperator::InclusiveOr => a | b,
2944                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2945                        }),
2946                        (Literal::U16(a), Literal::U32(b)) => Literal::U16(match op {
2947                            BinaryOperator::ShiftLeft => a
2948                                .checked_mul(
2949                                    1u16.checked_shl(b)
2950                                        .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
2951                                )
2952                                .ok_or(ConstantEvaluatorError::Overflow("<<".to_string()))?,
2953                            BinaryOperator::ShiftRight => a
2954                                .checked_shr(b)
2955                                .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
2956                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2957                        }),
2958                        (Literal::I32(a), Literal::I32(b)) => Literal::I32(match op {
2959                            BinaryOperator::Add => a.wrapping_add(b),
2960                            BinaryOperator::Subtract => a.wrapping_sub(b),
2961                            BinaryOperator::Multiply => a.wrapping_mul(b),
2962                            BinaryOperator::Divide => a.checked_div(b).ok_or_else(|| {
2963                                if b == 0 {
2964                                    ConstantEvaluatorError::DivisionByZero
2965                                } else {
2966                                    ConstantEvaluatorError::Overflow("division".into())
2967                                }
2968                            })?,
2969                            BinaryOperator::Modulo => a.checked_rem(b).ok_or_else(|| {
2970                                if b == 0 {
2971                                    ConstantEvaluatorError::RemainderByZero
2972                                } else {
2973                                    ConstantEvaluatorError::Overflow("remainder".into())
2974                                }
2975                            })?,
2976                            BinaryOperator::And => a & b,
2977                            BinaryOperator::ExclusiveOr => a ^ b,
2978                            BinaryOperator::InclusiveOr => a | b,
2979                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2980                        }),
2981                        (Literal::I32(a), Literal::U32(b)) => Literal::I32(match op {
2982                            BinaryOperator::ShiftLeft => {
2983                                if (if a.is_negative() { !a } else { a }).leading_zeros() <= b {
2984                                    return Err(ConstantEvaluatorError::Overflow("<<".to_string()));
2985                                }
2986                                a.checked_shl(b)
2987                                    .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?
2988                            }
2989                            BinaryOperator::ShiftRight => a
2990                                .checked_shr(b)
2991                                .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
2992                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2993                        }),
2994                        (Literal::U32(a), Literal::U32(b)) => Literal::U32(match op {
2995                            BinaryOperator::Add => a.wrapping_add(b),
2996                            BinaryOperator::Subtract => a.wrapping_sub(b),
2997                            BinaryOperator::Multiply => a.wrapping_mul(b),
2998                            BinaryOperator::Divide => a
2999                                .checked_div(b)
3000                                .ok_or(ConstantEvaluatorError::DivisionByZero)?,
3001                            BinaryOperator::Modulo => a
3002                                .checked_rem(b)
3003                                .ok_or(ConstantEvaluatorError::RemainderByZero)?,
3004                            BinaryOperator::And => a & b,
3005                            BinaryOperator::ExclusiveOr => a ^ b,
3006                            BinaryOperator::InclusiveOr => a | b,
3007                            BinaryOperator::ShiftLeft => a
3008                                .checked_mul(
3009                                    1u32.checked_shl(b)
3010                                        .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
3011                                )
3012                                .ok_or(ConstantEvaluatorError::Overflow("<<".to_string()))?,
3013                            BinaryOperator::ShiftRight => a
3014                                .checked_shr(b)
3015                                .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
3016                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3017                        }),
3018                        (Literal::F32(a), Literal::F32(b)) => Literal::F32(match op {
3019                            BinaryOperator::Add => a + b,
3020                            BinaryOperator::Subtract => a - b,
3021                            BinaryOperator::Multiply => a * b,
3022                            BinaryOperator::Divide => a / b,
3023                            BinaryOperator::Modulo => a % b,
3024                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3025                        }),
3026                        (Literal::AbstractInt(a), Literal::U32(b)) => {
3027                            Literal::AbstractInt(match op {
3028                                BinaryOperator::ShiftLeft => {
3029                                    if (if a.is_negative() { !a } else { a }).leading_zeros() <= b {
3030                                        return Err(ConstantEvaluatorError::Overflow(
3031                                            "<<".to_string(),
3032                                        ));
3033                                    }
3034                                    a.checked_shl(b).unwrap_or(0)
3035                                }
3036                                BinaryOperator::ShiftRight => a.checked_shr(b).unwrap_or(0),
3037                                _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3038                            })
3039                        }
3040                        (Literal::F16(a), Literal::F16(b)) => {
3041                            let result = match op {
3042                                BinaryOperator::Add => a + b,
3043                                BinaryOperator::Subtract => a - b,
3044                                BinaryOperator::Multiply => a * b,
3045                                BinaryOperator::Divide => a / b,
3046                                BinaryOperator::Modulo => a % b,
3047                                _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3048                            };
3049                            if !result.is_finite() {
3050                                return Err(ConstantEvaluatorError::Overflow(format!("{op:?}")));
3051                            }
3052                            Literal::F16(result)
3053                        }
3054                        (Literal::AbstractInt(a), Literal::AbstractInt(b)) => {
3055                            Literal::AbstractInt(match op {
3056                                BinaryOperator::Add => a.checked_add(b).ok_or_else(|| {
3057                                    ConstantEvaluatorError::Overflow("addition".into())
3058                                })?,
3059                                BinaryOperator::Subtract => a.checked_sub(b).ok_or_else(|| {
3060                                    ConstantEvaluatorError::Overflow("subtraction".into())
3061                                })?,
3062                                BinaryOperator::Multiply => a.checked_mul(b).ok_or_else(|| {
3063                                    ConstantEvaluatorError::Overflow("multiplication".into())
3064                                })?,
3065                                BinaryOperator::Divide => a.checked_div(b).ok_or_else(|| {
3066                                    if b == 0 {
3067                                        ConstantEvaluatorError::DivisionByZero
3068                                    } else {
3069                                        ConstantEvaluatorError::Overflow("division".into())
3070                                    }
3071                                })?,
3072                                BinaryOperator::Modulo => a.checked_rem(b).ok_or_else(|| {
3073                                    if b == 0 {
3074                                        ConstantEvaluatorError::RemainderByZero
3075                                    } else {
3076                                        ConstantEvaluatorError::Overflow("remainder".into())
3077                                    }
3078                                })?,
3079                                BinaryOperator::And => a & b,
3080                                BinaryOperator::ExclusiveOr => a ^ b,
3081                                BinaryOperator::InclusiveOr => a | b,
3082                                _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3083                            })
3084                        }
3085                        (Literal::AbstractFloat(a), Literal::AbstractFloat(b)) => {
3086                            let result = match op {
3087                                BinaryOperator::Add => a + b,
3088                                BinaryOperator::Subtract => a - b,
3089                                BinaryOperator::Multiply => a * b,
3090                                BinaryOperator::Divide => a / b,
3091                                BinaryOperator::Modulo => a % b,
3092                                _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3093                            };
3094                            if !result.is_finite() {
3095                                return Err(ConstantEvaluatorError::Overflow(format!("{op:?}")));
3096                            }
3097                            Literal::AbstractFloat(result)
3098                        }
3099                        (Literal::Bool(a), Literal::Bool(b)) => Literal::Bool(match op {
3100                            BinaryOperator::LogicalAnd => a && b,
3101                            BinaryOperator::LogicalOr => a || b,
3102                            BinaryOperator::And => a & b,
3103                            BinaryOperator::InclusiveOr => a | b,
3104                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3105                        }),
3106                        _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3107                    },
3108                };
3109                Expression::Literal(literal)
3110            }
3111            (
3112                &Expression::Compose {
3113                    components: ref src_components,
3114                    ty,
3115                },
3116                &Expression::Literal(_),
3117            ) => {
3118                if !is_allowed_compose_literal_op(&self.types[ty].inner, op) {
3119                    return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
3120                }
3121                let mut components = src_components.clone();
3122                for component in &mut components {
3123                    *component = self.binary_op(op, *component, right, span)?;
3124                }
3125                Expression::Compose { ty, components }
3126            }
3127            (
3128                &Expression::Literal(_),
3129                &Expression::Compose {
3130                    components: ref src_components,
3131                    ty,
3132                },
3133            ) => {
3134                if !is_allowed_compose_literal_op(&self.types[ty].inner, op) {
3135                    return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
3136                }
3137                let mut components = src_components.clone();
3138                for component in &mut components {
3139                    *component = self.binary_op(op, left, *component, span)?;
3140                }
3141                Expression::Compose { ty, components }
3142            }
3143            (
3144                &Expression::Compose {
3145                    components: ref left_components,
3146                    ty: left_ty,
3147                },
3148                &Expression::Compose {
3149                    components: ref right_components,
3150                    ty: right_ty,
3151                },
3152            ) => {
3153                // We have to make a copy of the component lists, because the
3154                // call to `binary_op_vector` needs `&mut self`, but `self` owns
3155                // the component lists.
3156                let left_flattened = crate::proc::flatten_compose(
3157                    left_ty,
3158                    left_components,
3159                    self.expressions,
3160                    self.types,
3161                )
3162                .collect::<Vec<_>>();
3163                let right_flattened = crate::proc::flatten_compose(
3164                    right_ty,
3165                    right_components,
3166                    self.expressions,
3167                    self.types,
3168                )
3169                .collect::<Vec<_>>();
3170
3171                self.binary_op_compose(
3172                    op,
3173                    &left_flattened,
3174                    &right_flattened,
3175                    left_ty,
3176                    right_ty,
3177                    span,
3178                )?
3179            }
3180            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3181        };
3182
3183        return self.register_evaluated_expr(expr, span);
3184
3185        fn is_allowed_compose_literal_op(compose_ty: &TypeInner, op: BinaryOperator) -> bool {
3186            let is_numeric_vec = matches!(
3187                compose_ty, TypeInner::Vector { scalar, .. }
3188                if scalar.kind != ScalarKind::Bool
3189            );
3190            let is_allowed_vec_scalar_op = matches!(
3191                op,
3192                BinaryOperator::Add
3193                    | BinaryOperator::Subtract
3194                    | BinaryOperator::Multiply
3195                    | BinaryOperator::Divide
3196                    | BinaryOperator::Modulo
3197            );
3198            let is_mat = matches!(compose_ty, TypeInner::Matrix { .. });
3199            let is_allowed_mat_scalar_op = matches!(op, BinaryOperator::Multiply);
3200            is_numeric_vec && is_allowed_vec_scalar_op || is_mat && is_allowed_mat_scalar_op
3201        }
3202    }
3203
3204    fn binary_op_compose(
3205        &mut self,
3206        op: BinaryOperator,
3207        left_components: &[Handle<Expression>],
3208        right_components: &[Handle<Expression>],
3209        left_ty: Handle<Type>,
3210        right_ty: Handle<Type>,
3211        span: Span,
3212    ) -> Result<Expression, ConstantEvaluatorError> {
3213        match (&self.types[left_ty].inner, &self.types[right_ty].inner) {
3214            // Binary operation on vector-vector
3215            (
3216                &TypeInner::Vector {
3217                    size: left_size, ..
3218                },
3219                &TypeInner::Vector {
3220                    size: right_size, ..
3221                },
3222            ) if left_size == right_size => self.binary_op_vector(
3223                op,
3224                left_size,
3225                left_components,
3226                right_components,
3227                left_ty,
3228                span,
3229            ),
3230            // Binary operation on vector-matrix
3231            (
3232                &TypeInner::Vector { size, .. },
3233                &TypeInner::Matrix {
3234                    columns,
3235                    rows,
3236                    scalar,
3237                },
3238            ) if op == BinaryOperator::Multiply && size == rows => self.multiply_vector_matrix(
3239                left_components,
3240                right_components,
3241                columns,
3242                scalar,
3243                span,
3244            ),
3245            // Binary operation on matrix-vector
3246            (
3247                &TypeInner::Matrix {
3248                    columns,
3249                    rows,
3250                    scalar,
3251                },
3252                &TypeInner::Vector { size, .. },
3253            ) if op == BinaryOperator::Multiply && size == columns => {
3254                self.multiply_matrix_vector(left_components, right_components, rows, scalar, span)
3255            }
3256            // Binary operation on matrix-matrix
3257            (
3258                &TypeInner::Matrix {
3259                    columns: left_columns,
3260                    rows: left_rows,
3261                    scalar,
3262                },
3263                &TypeInner::Matrix {
3264                    columns: right_columns,
3265                    rows: right_rows,
3266                    ..
3267                },
3268            ) => match op {
3269                BinaryOperator::Add | BinaryOperator::Subtract
3270                    if left_columns == right_columns && left_rows == right_rows =>
3271                {
3272                    let components = left_components
3273                        .iter()
3274                        .zip(right_components)
3275                        .map(|(&left, &right)| self.binary_op(op, left, right, span))
3276                        .collect::<Result<Vec<_>, _>>()?;
3277                    Ok(Expression::Compose {
3278                        ty: left_ty,
3279                        components,
3280                    })
3281                }
3282                BinaryOperator::Multiply if left_columns == right_rows => self
3283                    .multiply_matrix_matrix(
3284                        left_components,
3285                        right_components,
3286                        left_rows,
3287                        right_columns,
3288                        scalar,
3289                        span,
3290                    ),
3291                _ => Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3292            },
3293            _ => Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3294        }
3295    }
3296
3297    fn binary_op_vector(
3298        &mut self,
3299        op: BinaryOperator,
3300        size: crate::VectorSize,
3301        left_components: &[Handle<Expression>],
3302        right_components: &[Handle<Expression>],
3303        left_ty: Handle<Type>,
3304        span: Span,
3305    ) -> Result<Expression, ConstantEvaluatorError> {
3306        let ty = match op {
3307            // Relational operators produce vectors of booleans.
3308            BinaryOperator::Equal
3309            | BinaryOperator::NotEqual
3310            | BinaryOperator::Less
3311            | BinaryOperator::LessEqual
3312            | BinaryOperator::Greater
3313            | BinaryOperator::GreaterEqual => self.types.insert(
3314                Type {
3315                    name: None,
3316                    inner: TypeInner::Vector {
3317                        size,
3318                        scalar: crate::Scalar::BOOL,
3319                    },
3320                },
3321                span,
3322            ),
3323
3324            // Other operators produce the same type as their left
3325            // operand.
3326            BinaryOperator::Add
3327            | BinaryOperator::Subtract
3328            | BinaryOperator::Multiply
3329            | BinaryOperator::Divide
3330            | BinaryOperator::Modulo
3331            | BinaryOperator::And
3332            | BinaryOperator::ExclusiveOr
3333            | BinaryOperator::InclusiveOr
3334            | BinaryOperator::ShiftLeft
3335            | BinaryOperator::ShiftRight => left_ty,
3336
3337            BinaryOperator::LogicalAnd | BinaryOperator::LogicalOr => {
3338                // Not supported on vectors
3339                return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
3340            }
3341        };
3342
3343        let components = left_components
3344            .iter()
3345            .zip(right_components)
3346            .map(|(&left, &right)| self.binary_op(op, left, right, span))
3347            .collect::<Result<Vec<_>, _>>()?;
3348
3349        Ok(Expression::Compose { ty, components })
3350    }
3351
3352    fn multiply_vector_matrix(
3353        &mut self,
3354        vec_components: &[Handle<Expression>],
3355        mat_components: &[Handle<Expression>],
3356        mat_columns: crate::VectorSize,
3357        scalar: crate::Scalar,
3358        span: Span,
3359    ) -> Result<Expression, ConstantEvaluatorError> {
3360        let ty = self.types.insert(
3361            Type {
3362                name: None,
3363                inner: TypeInner::Vector {
3364                    size: mat_columns,
3365                    scalar,
3366                },
3367            },
3368            span,
3369        );
3370        let components = mat_components
3371            .iter()
3372            .map(|&column| {
3373                let Expression::Compose { ref components, .. } = self.expressions[column] else {
3374                    unreachable!()
3375                };
3376                self.dot_exprs(
3377                    vec_components.iter().cloned(),
3378                    components.clone().into_iter(),
3379                    span,
3380                )
3381            })
3382            .collect::<Result<Vec<_>, _>>()?;
3383        Ok(Expression::Compose { ty, components })
3384    }
3385
3386    fn multiply_matrix_vector(
3387        &mut self,
3388        mat_components: &[Handle<Expression>],
3389        vec_components: &[Handle<Expression>],
3390        mat_rows: crate::VectorSize,
3391        scalar: crate::Scalar,
3392        span: Span,
3393    ) -> Result<Expression, ConstantEvaluatorError> {
3394        let ty = self.types.insert(
3395            Type {
3396                name: None,
3397                inner: TypeInner::Vector {
3398                    size: mat_rows,
3399                    scalar,
3400                },
3401            },
3402            span,
3403        );
3404
3405        let flatten = self.flatten_matrix(mat_components);
3406        let nr = mat_rows as usize;
3407        let components = (0..nr)
3408            .map(|r| {
3409                let row = flatten.iter().skip(r).step_by(nr).cloned();
3410                self.dot_exprs(row, vec_components.iter().cloned(), span)
3411            })
3412            .collect::<Result<Vec<_>, _>>()?;
3413        Ok(Expression::Compose { ty, components })
3414    }
3415
3416    fn multiply_matrix_matrix(
3417        &mut self,
3418        left_components: &[Handle<Expression>],
3419        right_components: &[Handle<Expression>],
3420        left_rows: crate::VectorSize,
3421        right_columns: crate::VectorSize,
3422        scalar: crate::Scalar,
3423        span: Span,
3424    ) -> Result<Expression, ConstantEvaluatorError> {
3425        let left_nc = left_components.len();
3426        let left_nr = left_rows as usize;
3427        let right_nc = right_columns as usize;
3428        let right_nr = left_nc;
3429
3430        let mut result = Vec::with_capacity(right_nc);
3431        let result_ty = self.types.insert(
3432            Type {
3433                name: None,
3434                inner: TypeInner::Matrix {
3435                    columns: right_columns,
3436                    rows: left_rows,
3437                    scalar,
3438                },
3439            },
3440            span,
3441        );
3442        let result_column_ty = self.types.insert(
3443            Type {
3444                name: None,
3445                inner: TypeInner::Vector {
3446                    size: left_rows,
3447                    scalar,
3448                },
3449            },
3450            span,
3451        );
3452
3453        let left_flattened = self.flatten_matrix(left_components);
3454        let right_flattened = self.flatten_matrix(right_components);
3455        for c in 0..right_nc {
3456            let result_column = (0..left_nr)
3457                .map(|r| {
3458                    let row = left_flattened.iter().skip(r).step_by(left_nr);
3459                    let column = right_flattened.iter().skip(c * right_nr).take(right_nr);
3460                    self.dot_exprs(row.cloned(), column.cloned(), span)
3461                })
3462                .collect::<Result<Vec<_>, _>>()?;
3463            let expr = Expression::Compose {
3464                ty: result_column_ty,
3465                components: result_column,
3466            };
3467            let handle = self.register_evaluated_expr(expr, span)?;
3468            result.push(handle);
3469        }
3470        Ok(Expression::Compose {
3471            ty: result_ty,
3472            components: result,
3473        })
3474    }
3475
3476    fn flatten_matrix(&self, columns: &[Handle<Expression>]) -> ArrayVec<Handle<Expression>, 16> {
3477        let mut flattened = ArrayVec::<_, 16>::new();
3478        for &column in columns {
3479            let Expression::Compose { ref components, .. } = self.expressions[column] else {
3480                unreachable!()
3481            };
3482            flattened.extend(components.iter().cloned());
3483        }
3484        flattened
3485    }
3486
3487    fn dot_exprs(
3488        &mut self,
3489        left: impl Iterator<Item = Handle<Expression>>,
3490        right: impl Iterator<Item = Handle<Expression>>,
3491        span: Span,
3492    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3493        let mut acc = None;
3494        for (l, r) in left.zip(right) {
3495            let result = self.binary_op(BinaryOperator::Multiply, l, r, span)?;
3496            match acc.as_mut() {
3497                Some(acc) => *acc = self.binary_op(BinaryOperator::Add, *acc, result, span)?,
3498                None => acc = Some(result),
3499            }
3500        }
3501        Ok(acc.unwrap())
3502    }
3503
3504    fn relational(
3505        &mut self,
3506        fun: RelationalFunction,
3507        arg: Handle<Expression>,
3508        span: Span,
3509    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3510        let arg = self.eval_zero_value_and_splat(arg, span)?;
3511        match fun {
3512            RelationalFunction::All | RelationalFunction::Any => match self.expressions[arg] {
3513                Expression::Literal(Literal::Bool(_)) => Ok(arg),
3514                Expression::Compose { ty, ref components }
3515                    if matches!(self.types[ty].inner, TypeInner::Vector { .. }) =>
3516                {
3517                    let mut bool_components = ArrayVec::<bool, { crate::VectorSize::MAX }>::new();
3518                    for component in
3519                        crate::proc::flatten_compose(ty, components, self.expressions, self.types)
3520                    {
3521                        match self.expressions[component] {
3522                            Expression::Literal(Literal::Bool(val)) => {
3523                                bool_components.push(val);
3524                            }
3525                            _ => {
3526                                return Err(ConstantEvaluatorError::InvalidRelationalArg(fun));
3527                            }
3528                        }
3529                    }
3530                    let components = bool_components;
3531                    let result = match fun {
3532                        RelationalFunction::All => components.iter().all(|c| *c),
3533                        RelationalFunction::Any => components.iter().any(|c| *c),
3534                        _ => unreachable!(),
3535                    };
3536                    self.register_evaluated_expr(Expression::Literal(Literal::Bool(result)), span)
3537                }
3538                _ => Err(ConstantEvaluatorError::InvalidRelationalArg(fun)),
3539            },
3540            _ => Err(ConstantEvaluatorError::NotImplemented(format!(
3541                "{fun:?} built-in function"
3542            ))),
3543        }
3544    }
3545
3546    /// Deep copy `expr` from `expressions` into `self.expressions`.
3547    ///
3548    /// Return the root of the new copy.
3549    ///
3550    /// This is used when we're evaluating expressions in a function's
3551    /// expression arena that refer to a constant: we need to copy the
3552    /// constant's value into the function's arena so we can operate on it.
3553    fn copy_from(
3554        &mut self,
3555        expr: Handle<Expression>,
3556        expressions: &Arena<Expression>,
3557    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3558        let span = expressions.get_span(expr);
3559        match expressions[expr] {
3560            ref expr @ (Expression::Literal(_)
3561            | Expression::Constant(_)
3562            | Expression::ZeroValue(_)) => self.register_evaluated_expr(expr.clone(), span),
3563            Expression::Compose { ty, ref components } => {
3564                let mut components = components.clone();
3565                for component in &mut components {
3566                    *component = self.copy_from(*component, expressions)?;
3567                }
3568                self.register_evaluated_expr(Expression::Compose { ty, components }, span)
3569            }
3570            Expression::Splat { size, value } => {
3571                let value = self.copy_from(value, expressions)?;
3572                self.register_evaluated_expr(Expression::Splat { size, value }, span)
3573            }
3574            _ => {
3575                log::debug!("copy_from: SubexpressionsAreNotConstant");
3576                Err(ConstantEvaluatorError::SubexpressionsAreNotConstant)
3577            }
3578        }
3579    }
3580
3581    /// Returns the total number of components, after flattening, of a vector compose expression.
3582    fn vector_compose_flattened_size(
3583        &self,
3584        components: &[Handle<Expression>],
3585    ) -> Result<usize, ConstantEvaluatorError> {
3586        components
3587            .iter()
3588            .try_fold(0, |acc, c| -> Result<_, ConstantEvaluatorError> {
3589                let size = match *self.resolve_type(*c)?.inner_with(self.types) {
3590                    TypeInner::Scalar(_) => 1,
3591                    // We trust that the vector size of `component` is correct,
3592                    // as it will have already been validated when `component`
3593                    // was registered.
3594                    TypeInner::Vector { size, .. } => size as usize,
3595                    _ => return Err(ConstantEvaluatorError::InvalidVectorComposeComponent),
3596                };
3597                Ok(acc + size)
3598            })
3599    }
3600
3601    fn register_evaluated_expr(
3602        &mut self,
3603        expr: Expression,
3604        span: Span,
3605    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3606        // It suffices to only check_literal_value() for `Literal` expressions,
3607        // since we only register one expression at a time, `Compose`
3608        // expressions can only refer to other expressions, and `ZeroValue`
3609        // expressions are always okay.
3610        if let Expression::Literal(literal) = expr {
3611            crate::valid::check_literal_value(literal)?;
3612        }
3613
3614        // Ensure vector composes contain the correct number of components. We
3615        // do so here when each compose is registered to avoid having to deal
3616        // with the mess each time the compose is used in another expression.
3617        if let Expression::Compose { ty, ref components } = expr {
3618            if let TypeInner::Vector { size, scalar: _ } = self.types[ty].inner {
3619                let expected = size as usize;
3620                let actual = self.vector_compose_flattened_size(components)?;
3621                if expected != actual {
3622                    return Err(ConstantEvaluatorError::InvalidVectorComposeLength {
3623                        expected,
3624                        actual,
3625                    });
3626                }
3627            }
3628        }
3629
3630        Ok(self.append_expr(expr, span, ExpressionKind::Const))
3631    }
3632
3633    fn append_expr(
3634        &mut self,
3635        expr: Expression,
3636        span: Span,
3637        expr_type: ExpressionKind,
3638    ) -> Handle<Expression> {
3639        let h = match self.behavior {
3640            Behavior::Wgsl(
3641                WgslRestrictions::Runtime(ref mut function_local_data)
3642                | WgslRestrictions::Const(Some(ref mut function_local_data)),
3643            )
3644            | Behavior::Glsl(GlslRestrictions::Runtime(ref mut function_local_data)) => {
3645                let is_running = function_local_data.emitter.is_running();
3646                let needs_pre_emit = expr.needs_pre_emit();
3647                if is_running && needs_pre_emit {
3648                    function_local_data
3649                        .block
3650                        .extend(function_local_data.emitter.finish(self.expressions));
3651                    let h = self.expressions.append(expr, span);
3652                    function_local_data.emitter.start(self.expressions);
3653                    h
3654                } else {
3655                    self.expressions.append(expr, span)
3656                }
3657            }
3658            _ => self.expressions.append(expr, span),
3659        };
3660        self.expression_kind_tracker.insert(h, expr_type);
3661        h
3662    }
3663
3664    /// Resolve the type of `expr` if it is a constant expression.
3665    ///
3666    /// If `expr` was evaluated to a constant, returns its type.
3667    /// Otherwise, returns an error.
3668    fn resolve_type(
3669        &self,
3670        expr: Handle<Expression>,
3671    ) -> Result<crate::proc::TypeResolution, ConstantEvaluatorError> {
3672        use crate::proc::TypeResolution as Tr;
3673        use crate::Expression as Ex;
3674        let resolution = match self.expressions[expr] {
3675            Ex::Literal(ref literal) => Tr::Value(literal.ty_inner()),
3676            Ex::Constant(c) => Tr::Handle(self.constants[c].ty),
3677            Ex::ZeroValue(ty) | Ex::Compose { ty, .. } => Tr::Handle(ty),
3678            Ex::Splat { size, value } => {
3679                let Tr::Value(TypeInner::Scalar(scalar)) = self.resolve_type(value)? else {
3680                    return Err(ConstantEvaluatorError::SplatScalarOnly);
3681                };
3682                Tr::Value(TypeInner::Vector { scalar, size })
3683            }
3684            _ => {
3685                log::debug!("resolve_type: SubexpressionsAreNotConstant");
3686                return Err(ConstantEvaluatorError::SubexpressionsAreNotConstant);
3687            }
3688        };
3689
3690        Ok(resolution)
3691    }
3692
3693    fn select(
3694        &mut self,
3695        reject: Handle<Expression>,
3696        accept: Handle<Expression>,
3697        condition: Handle<Expression>,
3698        span: Span,
3699    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3700        let mut arg = |arg| self.eval_zero_value_and_splat(arg, span);
3701
3702        let reject = arg(reject)?;
3703        let accept = arg(accept)?;
3704        let condition = arg(condition)?;
3705
3706        let select_single_component =
3707            |this: &mut Self, reject_scalar, reject, accept, condition| {
3708                let accept = this.cast(accept, reject_scalar, span)?;
3709                if condition {
3710                    Ok(accept)
3711                } else {
3712                    Ok(reject)
3713                }
3714            };
3715
3716        match (&self.expressions[reject], &self.expressions[accept]) {
3717            (&Expression::Literal(reject_lit), &Expression::Literal(_accept_lit)) => {
3718                let reject_scalar = reject_lit.scalar();
3719                let &Expression::Literal(Literal::Bool(condition)) = &self.expressions[condition]
3720                else {
3721                    return Err(ConstantEvaluatorError::SelectScalarConditionNotABool);
3722                };
3723                select_single_component(self, reject_scalar, reject, accept, condition)
3724            }
3725            (
3726                &Expression::Compose {
3727                    ty: reject_ty,
3728                    components: ref reject_components,
3729                },
3730                &Expression::Compose {
3731                    ty: accept_ty,
3732                    components: ref accept_components,
3733                },
3734            ) => {
3735                let ty_deets = |ty| {
3736                    self.types[ty]
3737                        .inner
3738                        .vector_size_and_scalar()
3739                        .map(|(size, scalar)| {
3740                            (size.expect("expected vector type, not scalar type"), scalar)
3741                        })
3742                };
3743
3744                let expected_vec_size = {
3745                    let [(reject_vec_size, _), (accept_vec_size, _)] =
3746                        [reject_ty, accept_ty].map(|ty| ty_deets(ty).unwrap());
3747
3748                    if reject_vec_size != accept_vec_size {
3749                        return Err(ConstantEvaluatorError::SelectVecRejectAcceptSizeMismatch {
3750                            reject: reject_vec_size,
3751                            accept: accept_vec_size,
3752                        });
3753                    }
3754                    reject_vec_size
3755                };
3756
3757                let condition_components = match self.expressions[condition] {
3758                    Expression::Literal(Literal::Bool(condition)) => {
3759                        vec![condition; (expected_vec_size as u8).into()]
3760                    }
3761                    Expression::Compose {
3762                        ty: condition_ty,
3763                        components: ref condition_components,
3764                    } => {
3765                        let Some((condition_vec_size, condition_scalar)) = ty_deets(condition_ty)
3766                        else {
3767                            return Err(ConstantEvaluatorError::SelectConditionNotAVecBool);
3768                        };
3769                        if condition_scalar.kind != ScalarKind::Bool {
3770                            return Err(ConstantEvaluatorError::SelectConditionNotAVecBool);
3771                        }
3772                        if condition_vec_size != expected_vec_size {
3773                            return Err(ConstantEvaluatorError::SelectConditionVecSizeMismatch);
3774                        }
3775                        condition_components
3776                            .iter()
3777                            .copied()
3778                            .map(|component| match &self.expressions[component] {
3779                                &Expression::Literal(Literal::Bool(condition)) => condition,
3780                                _ => unreachable!(),
3781                            })
3782                            .collect()
3783                    }
3784
3785                    _ => return Err(ConstantEvaluatorError::SelectConditionNotAVecBool),
3786                };
3787
3788                let evaluated = Expression::Compose {
3789                    ty: reject_ty,
3790                    components: reject_components
3791                        .clone()
3792                        .into_iter()
3793                        .zip(accept_components.clone())
3794                        .zip(condition_components)
3795                        .map(|((reject, accept), condition)| {
3796                            let reject_scalar = match &self.expressions[reject] {
3797                                &Expression::Literal(lit) => lit.scalar(),
3798                                _ => unreachable!(),
3799                            };
3800                            select_single_component(self, reject_scalar, reject, accept, condition)
3801                        })
3802                        .collect::<Result<_, _>>()?,
3803                };
3804                self.register_evaluated_expr(evaluated, span)
3805            }
3806            _ => Err(ConstantEvaluatorError::SelectAcceptRejectTypeMismatch),
3807        }
3808    }
3809}
3810
3811/// If `dot(e2, e3)` is negative, `e1` returns, otherwise `-e1`.
3812fn float_face_forward<F>(
3813    e1: &[F],
3814    e2: &[F],
3815    e3: &[F],
3816) -> Option<ArrayVec<F, { crate::VectorSize::MAX }>>
3817where
3818    F: num_traits::Float,
3819{
3820    let d = float_dot(e2, e3)?;
3821
3822    let mut out = ArrayVec::new();
3823    for &e in e1 {
3824        out.push(if d < F::zero() { e } else { -e });
3825    }
3826    Some(out)
3827}
3828
3829/// The reflection of incident vector `e1` off a surface oriented `e2`,
3830/// `e1 - 2 * dot(e2, e1) * e2`.
3831fn float_reflect<F>(e1: &[F], e2: &[F]) -> Option<ArrayVec<F, { crate::VectorSize::MAX }>>
3832where
3833    F: num_traits::Float,
3834{
3835    let d = float_dot(e2, e1)?;
3836    let two = F::one() + F::one();
3837
3838    let mut out = ArrayVec::new();
3839    for (&a, &b) in e1.iter().zip(e2) {
3840        let r = a - two * d * b;
3841        if !r.is_finite() {
3842            return None;
3843        }
3844        out.push(r);
3845    }
3846    Some(out)
3847}
3848
3849/// The refraction of incident vector `e1` through a surface with normal `e2`,
3850/// for a ratio of indices of refraction `e3`.
3851fn float_refract<F>(e1: &[F], e2: &[F], e3: F) -> Option<ArrayVec<F, { crate::VectorSize::MAX }>>
3852where
3853    F: num_traits::Float,
3854{
3855    let d = float_dot(e2, e1)?;
3856    let one = F::one();
3857
3858    let k = one - e3 * e3 * (one - d * d);
3859    if !k.is_finite() {
3860        return None;
3861    }
3862
3863    let mut out = ArrayVec::new();
3864
3865    // If there is total internal reflection, returns zero vector.
3866    if k < F::zero() {
3867        for _ in e1 {
3868            out.push(F::zero());
3869        }
3870        return Some(out);
3871    }
3872
3873    let scale = e3 * d + k.sqrt();
3874    for (&a, &b) in e1.iter().zip(e2) {
3875        let r = e3 * a - scale * b;
3876        if !r.is_finite() {
3877            return None;
3878        }
3879        out.push(r);
3880    }
3881    Some(out)
3882}
3883
3884#[test]
3885fn face_forward_smoke() {
3886    #[track_caller]
3887    fn ff(e1: &[f32], e2: &[f32], e3: &[f32]) -> Vec<f32> {
3888        float_face_forward(e1, e2, e3).unwrap().to_vec()
3889    }
3890
3891    // If `dot(e2, e3)` is negative, return `e1`, otherwise return `-e1`.
3892    assert_eq!(ff(&[1.0, 2.0], &[-1.0, 0.0], &[1.0, 0.0]), [1.0, 2.0]);
3893    assert_eq!(ff(&[1.0, 2.0], &[1.0, 0.0], &[1.0, 0.0]), [-1.0, -2.0]);
3894
3895    // Zero = flip `e1`.
3896    assert_eq!(ff(&[1.0, 2.0], &[0.0, 1.0], &[1.0, 0.0]), [-1.0, -2.0]);
3897
3898    assert_eq!(
3899        ff(&[1.0, 2.0, 3.0], &[-1.0, 0.0, 0.0], &[1.0, 0.0, 0.0]),
3900        [1.0, 2.0, 3.0]
3901    );
3902
3903    // Return None if `dot(e2, e3)` is too big to compute.
3904    assert!(float_face_forward(&[1.0f32, 0.0], &[f32::MAX, 0.0], &[f32::MAX, 0.0]).is_none());
3905}
3906
3907#[test]
3908fn reflect_smoke() {
3909    #[track_caller]
3910    fn rf(e1: &[f32], e2: &[f32]) -> Vec<f32> {
3911        float_reflect(e1, e2).unwrap().to_vec()
3912    }
3913
3914    // Bouncing off a floor flips the component along the normal.
3915    assert_eq!(rf(&[1.0, -1.0], &[0.0, 1.0]), [1.0, 1.0]);
3916    assert_eq!(rf(&[1.0, -1.0, 0.0], &[0.0, 1.0, 0.0]), [1.0, 1.0, 0.0]);
3917
3918    // Head-on reverses the vector entirely.
3919    assert_eq!(rf(&[1.0, 0.0], &[1.0, 0.0]), [-1.0, 0.0]);
3920
3921    // A surface parallel to the incident vector leaves it alone.
3922    assert_eq!(rf(&[1.0, 0.0], &[0.0, 1.0]), [1.0, 0.0]);
3923
3924    assert!(float_reflect(&[1.0f32, 0.0], &[f32::MAX, 0.0]).is_none());
3925}
3926
3927#[test]
3928fn refract_smoke() {
3929    #[track_caller]
3930    fn rr(e1: &[f32], e2: &[f32], e3: f32) -> Vec<f32> {
3931        float_refract(e1, e2, e3).unwrap().to_vec()
3932    }
3933
3934    // No change if blending ratio is 1 and a straight surface collision.
3935    assert_eq!(rr(&[0.0, -1.0], &[0.0, 1.0], 1.0), [0.0, -1.0]);
3936    assert_eq!(rr(&[0.5, -0.5], &[0.0, 1.0], 1.0), [0.5, -0.5]);
3937
3938    // A normal facing the opposite way will bend vector to other side.
3939    assert_eq!(rr(&[0.5, -0.5], &[0.0, -1.0], 1.0), [0.5, 0.5]);
3940
3941    // Ratios below 1 shorten the transmitted vector.
3942    assert_eq!(rr(&[0.0, -1.0], &[0.0, 1.0], 0.5), [0.0, -1.0]);
3943
3944    // ‘no refraction possible’ means k goes negative and result is zero.
3945    assert_eq!(rr(&[0.8, -0.6], &[0.0, 1.0], 2.0), [0.0, 0.0]);
3946    assert_eq!(
3947        rr(&[0.8, -0.6, 0.0], &[0.0, 1.0, 0.0], 2.0),
3948        [0.0, 0.0, 0.0]
3949    );
3950
3951    assert!(float_refract(&[1.0f32, 0.0], &[f32::MAX, 0.0], 1.0).is_none());
3952    assert!(float_refract(&[1.0f32, 0.0], &[0.0, 1.0], f32::MAX).is_none());
3953}
3954
3955/// Return a u32 according to the number of bits in `T`, the `w` of the
3956/// `extractBits` and `insertBits` specifications.
3957const fn bit_width<T>() -> u32 {
3958    size_of::<T>() as u32 * 8
3959}
3960
3961/// Reject the `offset` and `count` arguments of `extractBits` and `insertBits`
3962/// if they select bits outside an operand `width` bits wide.
3963///
3964/// The WGSL specification says that this is a shader creation error if `offset`
3965/// and `count` are const expressions, *even if the operand is not*, so the WGSL
3966/// front end will fail immediately if it sees both are const.
3967pub fn check_bitfield_range(
3968    builtin: &'static str,
3969    offset: u32,
3970    count: u32,
3971    width: u32,
3972) -> Result<(), ConstantEvaluatorError> {
3973    if u64::from(offset) + u64::from(count) > u64::from(width) {
3974        return Err(ConstantEvaluatorError::BitfieldRangeTooLarge {
3975            builtin,
3976            offset,
3977            count,
3978            width,
3979        });
3980    }
3981    Ok(())
3982}
3983
3984fn extract_bits<T>(
3985    e: &[T],
3986    offset: u32,
3987    count: u32,
3988) -> Result<ArrayVec<T, { crate::VectorSize::MAX }>, ConstantEvaluatorError>
3989where
3990    T: num_traits::PrimInt,
3991{
3992    check_bitfield_range("extractBits", offset, count, bit_width::<T>())?;
3993    let w = bit_width::<T>();
3994
3995    let mut out = ArrayVec::new();
3996    for &e in e {
3997        out.push(if count == 0 {
3998            T::zero()
3999        } else {
4000            // Shift field up then shift back down.
4001            // - if signed, the empty space fills with the field's top bit
4002            // - if unsigned, the empty space will fill with zeroes
4003            // count is never zero here
4004            (e << (w - offset - count) as usize) >> (w - count) as usize
4005        });
4006    }
4007    Ok(out)
4008}
4009
4010fn insert_bits<T>(
4011    e: &[T],
4012    newbits: &[T],
4013    offset: u32,
4014    count: u32,
4015) -> Result<ArrayVec<T, { crate::VectorSize::MAX }>, ConstantEvaluatorError>
4016where
4017    T: num_traits::PrimInt,
4018{
4019    check_bitfield_range("insertBits", offset, count, bit_width::<T>())?;
4020    let w = bit_width::<T>();
4021
4022    let mut out = ArrayVec::new();
4023    for (&e, &newbits) in e.iter().zip(newbits) {
4024        out.push(if count == 0 {
4025            e
4026        } else {
4027            let mask = (!T::zero()).unsigned_shr(w - count) << offset as usize;
4028            (e & !mask) | ((newbits << offset as usize) & mask)
4029        });
4030    }
4031    Ok(out)
4032}
4033
4034#[cfg(test)]
4035fn extract_bits_scalar<T: num_traits::PrimInt>(e: T, offset: u32, count: u32) -> T {
4036    extract_bits(&[e], offset, count).unwrap()[0]
4037}
4038
4039#[cfg(test)]
4040fn insert_bits_scalar<T: num_traits::PrimInt>(e: T, newbits: T, offset: u32, count: u32) -> T {
4041    insert_bits(&[e], &[newbits], offset, count).unwrap()[0]
4042}
4043
4044#[test]
4045fn extract_bits_smoke() {
4046    // `count` of zero always yields zero, whatever `offset` selects.
4047    assert_eq!(extract_bits_scalar(0xffffffff_u32, 0, 0), 0);
4048    assert_eq!(extract_bits_scalar(-1_i32, 32, 0), 0);
4049
4050    // Selecting the whole width is the identity.
4051    assert_eq!(extract_bits_scalar(0x12345678_u32, 0, 32), 0x12345678);
4052    assert_eq!(extract_bits_scalar(i32::MIN, 0, 32), i32::MIN);
4053
4054    // Unsigned extraction fills the bits above the field with zero.
4055    assert_eq!(extract_bits_scalar(0x12345678_u32, 8, 8), 0x56);
4056    assert_eq!(extract_bits_scalar(0xf0000000_u32, 28, 4), 0xf);
4057    assert_eq!(extract_bits_scalar(0x12345678_u32, 31, 1), 0);
4058
4059    // Signed extraction fills them from the top bit of the field instead.
4060    assert_eq!(extract_bits_scalar(0x12345678_i32, 8, 8), 0x56);
4061    assert_eq!(extract_bits_scalar(0x8_i32, 3, 1), -1);
4062    assert_eq!(extract_bits_scalar(0xf0000000_u32 as i32, 28, 4), -1);
4063    assert_eq!(extract_bits_scalar(0x70000000_i32, 28, 4), 7);
4064
4065    // Widths other than 32 use their own `w`.
4066    assert_eq!(extract_bits_scalar(0x1234_u16, 4, 8), 0x23);
4067    assert_eq!(extract_bits_scalar(-1_i16, 0, 16), -1);
4068    assert_eq!(
4069        extract_bits_scalar(0x123456789abcdef0_u64, 32, 32),
4070        0x12345678
4071    );
4072    assert_eq!(extract_bits_scalar(-1_i64, 63, 1), -1);
4073
4074    // `offset + count` past the end of the type is a shader creation error.
4075    assert!(extract_bits(&[0_u32], 30, 8).is_err());
4076    assert!(extract_bits(&[0_u32], 33, 0).is_err());
4077    assert!(extract_bits(&[0_u16], 8, 16).is_err());
4078    assert!(extract_bits(&[0_u32], u32::MAX, u32::MAX).is_err());
4079    assert!(extract_bits(&[0_u32], 32, 0).is_ok());
4080}
4081
4082#[test]
4083fn insert_bits_smoke() {
4084    // `count` of zero leaves `e` untouched.
4085    assert_eq!(
4086        insert_bits_scalar(0x12345678_u32, 0xffffffff, 0, 0),
4087        0x12345678
4088    );
4089    assert_eq!(insert_bits_scalar(-1_i32, 0, 32, 0), -1);
4090
4091    // Covering the whole width will replace `e` entirely.
4092    assert_eq!(
4093        insert_bits_scalar(0x12345678_u32, 0xdeadbeef, 0, 32),
4094        0xdeadbeef
4095    );
4096    assert_eq!(insert_bits_scalar(0_i32, i32::MIN, 0, 32), i32::MIN);
4097
4098    // Only bits `offset..offset + count` are taken from `newbits`, and only its
4099    // low `count` bits are used.
4100    assert_eq!(insert_bits_scalar(0x12345678_u32, 0xff, 8, 8), 0x1234ff78);
4101    assert_eq!(insert_bits_scalar(0x12345678_u32, 0xabcd, 8, 8), 0x1234cd78);
4102    assert_eq!(insert_bits_scalar(0_u32, 0xf, 28, 4), 0xf0000000);
4103    assert_eq!(insert_bits_scalar(0_u32, 1, 31, 1), 0x80000000);
4104
4105    // Signed operands set the sign bit like any other.
4106    assert_eq!(insert_bits_scalar(0_i32, -1, 31, 1), i32::MIN);
4107    assert_eq!(insert_bits_scalar(-1_i32, 0, 0, 31), i32::MIN);
4108
4109    // Widths other than 32 use their own `w`.
4110    assert_eq!(insert_bits_scalar(0x1234_u16, 0xf, 4, 4), 0x12f4);
4111    assert_eq!(insert_bits_scalar(0_i16, -1, 15, 1), i16::MIN);
4112    assert_eq!(
4113        insert_bits_scalar(0_u64, 0xffffffff, 32, 32),
4114        0xffffffff00000000
4115    );
4116
4117    // `offset + count` past the end of the type is a shader creation error.
4118    assert!(insert_bits(&[0_u32], &[0], 30, 8).is_err());
4119    assert!(insert_bits(&[0_u32], &[0], 33, 0).is_err());
4120    assert!(insert_bits(&[0_u16], &[0], 8, 16).is_err());
4121    assert!(insert_bits(&[0_u32], &[0], u32::MAX, u32::MAX).is_err());
4122    assert!(insert_bits(&[0_u32], &[0], 32, 0).is_ok());
4123}
4124
4125fn first_trailing_bit(concrete_int: ConcreteInt<1>) -> ConcreteInt<1> {
4126    // NOTE: Bit indices for this built-in start at 0 at the "right" (or LSB). For example, a value
4127    // of 1 means the least significant bit is set. Therefore, an input of `0x[80 00…]` would
4128    // return a right-to-left bit index of 0.
4129    let trailing_zeros_to_bit_idx = |e: u32| -> u32 {
4130        match e {
4131            idx @ 0..=31 => idx,
4132            32 => u32::MAX,
4133            _ => unreachable!(),
4134        }
4135    };
4136    match concrete_int {
4137        ConcreteInt::U32([e]) => ConcreteInt::U32([trailing_zeros_to_bit_idx(e.trailing_zeros())]),
4138        ConcreteInt::I32([e]) => {
4139            ConcreteInt::I32([trailing_zeros_to_bit_idx(e.trailing_zeros()) as i32])
4140        }
4141    }
4142}
4143
4144#[test]
4145fn first_trailing_bit_smoke() {
4146    assert_eq!(
4147        first_trailing_bit(ConcreteInt::I32([0])),
4148        ConcreteInt::I32([-1])
4149    );
4150    assert_eq!(
4151        first_trailing_bit(ConcreteInt::I32([1])),
4152        ConcreteInt::I32([0])
4153    );
4154    assert_eq!(
4155        first_trailing_bit(ConcreteInt::I32([2])),
4156        ConcreteInt::I32([1])
4157    );
4158    assert_eq!(
4159        first_trailing_bit(ConcreteInt::I32([-1])),
4160        ConcreteInt::I32([0]),
4161    );
4162    assert_eq!(
4163        first_trailing_bit(ConcreteInt::I32([i32::MIN])),
4164        ConcreteInt::I32([31]),
4165    );
4166    assert_eq!(
4167        first_trailing_bit(ConcreteInt::I32([i32::MAX])),
4168        ConcreteInt::I32([0]),
4169    );
4170    for idx in 0..32 {
4171        assert_eq!(
4172            first_trailing_bit(ConcreteInt::I32([1 << idx])),
4173            ConcreteInt::I32([idx])
4174        )
4175    }
4176
4177    assert_eq!(
4178        first_trailing_bit(ConcreteInt::U32([0])),
4179        ConcreteInt::U32([u32::MAX])
4180    );
4181    assert_eq!(
4182        first_trailing_bit(ConcreteInt::U32([1])),
4183        ConcreteInt::U32([0])
4184    );
4185    assert_eq!(
4186        first_trailing_bit(ConcreteInt::U32([2])),
4187        ConcreteInt::U32([1])
4188    );
4189    assert_eq!(
4190        first_trailing_bit(ConcreteInt::U32([1 << 31])),
4191        ConcreteInt::U32([31]),
4192    );
4193    assert_eq!(
4194        first_trailing_bit(ConcreteInt::U32([u32::MAX])),
4195        ConcreteInt::U32([0]),
4196    );
4197    for idx in 0..32 {
4198        assert_eq!(
4199            first_trailing_bit(ConcreteInt::U32([1 << idx])),
4200            ConcreteInt::U32([idx])
4201        )
4202    }
4203}
4204
4205fn first_leading_bit(concrete_int: ConcreteInt<1>) -> ConcreteInt<1> {
4206    // NOTE: Bit indices for this built-in start at 0 at the "right" (or LSB). For example, 1 means
4207    // the least significant bit is set. Therefore, an input of 1 would return a right-to-left bit
4208    // index of 0.
4209    let rtl_to_ltr_bit_idx = |e: u32| -> u32 {
4210        match e {
4211            idx @ 0..=31 => 31 - idx,
4212            32 => u32::MAX,
4213            _ => unreachable!(),
4214        }
4215    };
4216    match concrete_int {
4217        ConcreteInt::I32([e]) => ConcreteInt::I32([{
4218            let rtl_bit_index = if e.is_negative() {
4219                e.leading_ones()
4220            } else {
4221                e.leading_zeros()
4222            };
4223            rtl_to_ltr_bit_idx(rtl_bit_index) as i32
4224        }]),
4225        ConcreteInt::U32([e]) => ConcreteInt::U32([rtl_to_ltr_bit_idx(e.leading_zeros())]),
4226    }
4227}
4228
4229#[test]
4230fn first_leading_bit_smoke() {
4231    assert_eq!(
4232        first_leading_bit(ConcreteInt::I32([-1])),
4233        ConcreteInt::I32([-1])
4234    );
4235    assert_eq!(
4236        first_leading_bit(ConcreteInt::I32([0])),
4237        ConcreteInt::I32([-1])
4238    );
4239    assert_eq!(
4240        first_leading_bit(ConcreteInt::I32([1])),
4241        ConcreteInt::I32([0])
4242    );
4243    assert_eq!(
4244        first_leading_bit(ConcreteInt::I32([-2])),
4245        ConcreteInt::I32([0])
4246    );
4247    assert_eq!(
4248        first_leading_bit(ConcreteInt::I32([1234 + 4567])),
4249        ConcreteInt::I32([12])
4250    );
4251    assert_eq!(
4252        first_leading_bit(ConcreteInt::I32([i32::MAX])),
4253        ConcreteInt::I32([30])
4254    );
4255    assert_eq!(
4256        first_leading_bit(ConcreteInt::I32([i32::MIN])),
4257        ConcreteInt::I32([30])
4258    );
4259    // NOTE: Ignore the sign bit, which is a separate (above) case.
4260    for idx in 0..(32 - 1) {
4261        assert_eq!(
4262            first_leading_bit(ConcreteInt::I32([1 << idx])),
4263            ConcreteInt::I32([idx])
4264        );
4265    }
4266    for idx in 1..(32 - 1) {
4267        assert_eq!(
4268            first_leading_bit(ConcreteInt::I32([-(1 << idx)])),
4269            ConcreteInt::I32([idx - 1])
4270        );
4271    }
4272
4273    assert_eq!(
4274        first_leading_bit(ConcreteInt::U32([0])),
4275        ConcreteInt::U32([u32::MAX])
4276    );
4277    assert_eq!(
4278        first_leading_bit(ConcreteInt::U32([1])),
4279        ConcreteInt::U32([0])
4280    );
4281    assert_eq!(
4282        first_leading_bit(ConcreteInt::U32([u32::MAX])),
4283        ConcreteInt::U32([31])
4284    );
4285    for idx in 0..32 {
4286        assert_eq!(
4287            first_leading_bit(ConcreteInt::U32([1 << idx])),
4288            ConcreteInt::U32([idx])
4289        )
4290    }
4291}
4292
4293/// Trait for conversions of abstract values to concrete types.
4294trait TryFromAbstract<T>: Sized {
4295    /// Convert an abstract literal `value` to `Self`.
4296    ///
4297    /// Since Naga's [`AbstractInt`] and [`AbstractFloat`] exist to support
4298    /// WGSL, we follow WGSL's conversion rules here:
4299    ///
4300    /// - WGSL §6.1.2. Conversion Rank says that automatic conversions
4301    ///   from [`AbstractInt`] to an integer type are either lossless or an
4302    ///   error.
4303    ///
4304    /// - WGSL §15.7.6 Floating Point Conversion says that conversions
4305    ///   to floating point in constant expressions and override
4306    ///   expressions are errors if the value is out of range for the
4307    ///   destination type, but rounding is okay.
4308    ///
4309    /// - WGSL §17.1.2 i32()/u32() constructors treat AbstractFloat as any
4310    ///   other floating point type, following the scalar floating point to
4311    ///   integral conversion algorithm (§15.7.6). There is no automatic
4312    ///   conversion from AbstractFloat to integer types.
4313    ///
4314    /// [`AbstractInt`]: crate::Literal::AbstractInt
4315    /// [`AbstractFloat`]: crate::Literal::AbstractFloat
4316    fn try_from_abstract(value: T) -> Result<Self, ConstantEvaluatorError>;
4317}
4318
4319impl TryFromAbstract<i64> for i32 {
4320    fn try_from_abstract(value: i64) -> Result<i32, ConstantEvaluatorError> {
4321        i32::try_from(value).map_err(|_| ConstantEvaluatorError::AutomaticConversionLossy {
4322            value: format!("{value:?}"),
4323            to_type: "i32",
4324        })
4325    }
4326}
4327
4328impl TryFromAbstract<i64> for u32 {
4329    fn try_from_abstract(value: i64) -> Result<u32, ConstantEvaluatorError> {
4330        u32::try_from(value).map_err(|_| ConstantEvaluatorError::AutomaticConversionLossy {
4331            value: format!("{value:?}"),
4332            to_type: "u32",
4333        })
4334    }
4335}
4336
4337impl TryFromAbstract<i64> for u64 {
4338    fn try_from_abstract(value: i64) -> Result<u64, ConstantEvaluatorError> {
4339        u64::try_from(value).map_err(|_| ConstantEvaluatorError::AutomaticConversionLossy {
4340            value: format!("{value:?}"),
4341            to_type: "u64",
4342        })
4343    }
4344}
4345
4346impl TryFromAbstract<i64> for i64 {
4347    fn try_from_abstract(value: i64) -> Result<i64, ConstantEvaluatorError> {
4348        Ok(value)
4349    }
4350}
4351
4352impl TryFromAbstract<i64> for f32 {
4353    fn try_from_abstract(value: i64) -> Result<Self, ConstantEvaluatorError> {
4354        let f = value as f32;
4355        // The range of `i64` is roughly ±18 × 10¹⁸, whereas the range of
4356        // `f32` is roughly ±3.4 × 10³⁸, so there's no opportunity for
4357        // overflow here.
4358        Ok(f)
4359    }
4360}
4361
4362impl TryFromAbstract<f64> for f32 {
4363    fn try_from_abstract(value: f64) -> Result<f32, ConstantEvaluatorError> {
4364        let f = value as f32;
4365        if f.is_infinite() {
4366            return Err(ConstantEvaluatorError::AutomaticConversionLossy {
4367                value: format!("{value:?}"),
4368                to_type: "f32",
4369            });
4370        }
4371        Ok(f)
4372    }
4373}
4374
4375impl TryFromAbstract<i64> for f64 {
4376    fn try_from_abstract(value: i64) -> Result<Self, ConstantEvaluatorError> {
4377        let f = value as f64;
4378        // The range of `i64` is roughly ±18 × 10¹⁸, whereas the range of
4379        // `f64` is roughly ±1.8 × 10³⁰⁸, so there's no opportunity for
4380        // overflow here.
4381        Ok(f)
4382    }
4383}
4384
4385impl TryFromAbstract<f64> for f64 {
4386    fn try_from_abstract(value: f64) -> Result<f64, ConstantEvaluatorError> {
4387        Ok(value)
4388    }
4389}
4390
4391impl TryFromAbstract<f64> for i32 {
4392    fn try_from_abstract(value: f64) -> Result<Self, ConstantEvaluatorError> {
4393        // https://www.w3.org/TR/WGSL/#floating-point-conversion
4394        // To convert a floating point scalar value X to an integer scalar type T:
4395        // * If X is a NaN, the result is an indeterminate value in T.
4396        // * If X is exactly representable in the target type T, then the
4397        //   result is that value.
4398        // * Otherwise, the result is the value in T closest to truncate(X) and
4399        //   also exactly representable in the original floating point type.
4400        //
4401        // A rust cast satisfies these requirements apart from "the result
4402        // is... exactly representable in the original floating point type".
4403        // However, i32::MIN and i32::MAX are exactly representable by f64, so
4404        // we're all good.
4405        Ok(value as i32)
4406    }
4407}
4408
4409impl TryFromAbstract<f64> for u32 {
4410    fn try_from_abstract(value: f64) -> Result<Self, ConstantEvaluatorError> {
4411        // As above, u32::MIN and u32::MAX are exactly representable by f64,
4412        // so a simple rust cast is sufficient.
4413        Ok(value as u32)
4414    }
4415}
4416
4417impl TryFromAbstract<f64> for i64 {
4418    fn try_from_abstract(value: f64) -> Result<Self, ConstantEvaluatorError> {
4419        // As above, except we clamp to the minimum and maximum values
4420        // representable by both f64 and i64.
4421        use crate::proc::type_methods::IntFloatLimits;
4422        Ok(value.clamp(i64::min_float(), i64::max_float()) as i64)
4423    }
4424}
4425
4426impl TryFromAbstract<f64> for u64 {
4427    fn try_from_abstract(value: f64) -> Result<Self, ConstantEvaluatorError> {
4428        // As above, this time clamping to the minimum and maximum values
4429        // representable by both f64 and u64.
4430        use crate::proc::type_methods::IntFloatLimits;
4431        Ok(value.clamp(u64::min_float(), u64::max_float()) as u64)
4432    }
4433}
4434
4435impl TryFromAbstract<f64> for f16 {
4436    fn try_from_abstract(value: f64) -> Result<f16, ConstantEvaluatorError> {
4437        let f = f16::from_f64(value);
4438        if f.is_infinite() {
4439            return Err(ConstantEvaluatorError::AutomaticConversionLossy {
4440                value: format!("{value:?}"),
4441                to_type: "f16",
4442            });
4443        }
4444        Ok(f)
4445    }
4446}
4447
4448impl TryFromAbstract<i64> for f16 {
4449    fn try_from_abstract(value: i64) -> Result<f16, ConstantEvaluatorError> {
4450        let f = f16::from_i64(value);
4451        if f.is_none() {
4452            return Err(ConstantEvaluatorError::AutomaticConversionLossy {
4453                value: format!("{value:?}"),
4454                to_type: "f16",
4455            });
4456        }
4457        Ok(f.unwrap())
4458    }
4459}
4460
4461fn cross_product<T>(a: [T; 3], b: [T; 3]) -> [T; 3]
4462where
4463    T: Copy,
4464    T: core::ops::Mul<T, Output = T>,
4465    T: core::ops::Sub<T, Output = T>,
4466{
4467    [
4468        a[1] * b[2] - a[2] * b[1],
4469        a[2] * b[0] - a[0] * b[2],
4470        a[0] * b[1] - a[1] * b[0],
4471    ]
4472}
4473
4474#[cfg(test)]
4475mod tests {
4476    use alloc::{vec, vec::Vec};
4477
4478    use crate::{
4479        Arena, BinaryOperator, Constant, Expression, FastHashMap, Handle, Literal, Type, TypeInner,
4480        UnaryOperator, UniqueArena, VectorSize,
4481    };
4482
4483    use super::{Behavior, ConstantEvaluator, ExpressionKindTracker, WgslRestrictions};
4484
4485    #[test]
4486    fn unary_op() {
4487        let mut types = UniqueArena::new();
4488        let mut constants = Arena::new();
4489        let overrides = Arena::new();
4490        let mut global_expressions = Arena::new();
4491
4492        let scalar_ty = types.insert(
4493            Type {
4494                name: None,
4495                inner: TypeInner::Scalar(crate::Scalar::I32),
4496            },
4497            Default::default(),
4498        );
4499
4500        let vec_ty = types.insert(
4501            Type {
4502                name: None,
4503                inner: TypeInner::Vector {
4504                    size: VectorSize::Bi,
4505                    scalar: crate::Scalar::I32,
4506                },
4507            },
4508            Default::default(),
4509        );
4510
4511        let h = constants.append(
4512            Constant {
4513                name: None,
4514                ty: scalar_ty,
4515                init: global_expressions
4516                    .append(Expression::Literal(Literal::I32(4)), Default::default()),
4517            },
4518            Default::default(),
4519        );
4520
4521        let h1 = constants.append(
4522            Constant {
4523                name: None,
4524                ty: scalar_ty,
4525                init: global_expressions
4526                    .append(Expression::Literal(Literal::I32(8)), Default::default()),
4527            },
4528            Default::default(),
4529        );
4530
4531        let vec_h = constants.append(
4532            Constant {
4533                name: None,
4534                ty: vec_ty,
4535                init: global_expressions.append(
4536                    Expression::Compose {
4537                        ty: vec_ty,
4538                        components: vec![constants[h].init, constants[h1].init],
4539                    },
4540                    Default::default(),
4541                ),
4542            },
4543            Default::default(),
4544        );
4545
4546        let expr = global_expressions.append(Expression::Constant(h), Default::default());
4547        let expr1 = global_expressions.append(Expression::Constant(vec_h), Default::default());
4548
4549        let expr2 = Expression::Unary {
4550            op: UnaryOperator::Negate,
4551            expr,
4552        };
4553
4554        let expr3 = Expression::Unary {
4555            op: UnaryOperator::BitwiseNot,
4556            expr,
4557        };
4558
4559        let expr4 = Expression::Unary {
4560            op: UnaryOperator::BitwiseNot,
4561            expr: expr1,
4562        };
4563
4564        let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
4565        let mut solver = ConstantEvaluator {
4566            behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4567            types: &mut types,
4568            constants: &constants,
4569            overrides: &overrides,
4570            expressions: &mut global_expressions,
4571            expression_kind_tracker,
4572            layouter: &mut crate::proc::Layouter::default(),
4573        };
4574
4575        let res1 = solver
4576            .try_eval_and_append(expr2, Default::default())
4577            .unwrap();
4578        let res2 = solver
4579            .try_eval_and_append(expr3, Default::default())
4580            .unwrap();
4581        let res3 = solver
4582            .try_eval_and_append(expr4, Default::default())
4583            .unwrap();
4584
4585        assert_eq!(
4586            global_expressions[res1],
4587            Expression::Literal(Literal::I32(-4))
4588        );
4589
4590        assert_eq!(
4591            global_expressions[res2],
4592            Expression::Literal(Literal::I32(!4))
4593        );
4594
4595        let res3_inner = &global_expressions[res3];
4596
4597        match *res3_inner {
4598            Expression::Compose {
4599                ref ty,
4600                ref components,
4601            } => {
4602                assert_eq!(*ty, vec_ty);
4603                let mut components_iter = components.iter().copied();
4604                assert_eq!(
4605                    global_expressions[components_iter.next().unwrap()],
4606                    Expression::Literal(Literal::I32(!4))
4607                );
4608                assert_eq!(
4609                    global_expressions[components_iter.next().unwrap()],
4610                    Expression::Literal(Literal::I32(!8))
4611                );
4612                assert!(components_iter.next().is_none());
4613            }
4614            _ => panic!("Expected vector"),
4615        }
4616    }
4617
4618    #[test]
4619    fn matrix_op() {
4620        let mut helper = MatrixTestHelper::new();
4621
4622        for nc in 2..=4 {
4623            for nr in 2..=4 {
4624                // Validates multiplication on vector-matrix.
4625                // vecR(0, 1, .., r) * matCxR(0, 1, .., nc * nr)
4626                let evaluated = helper.eval_vector_multiply_matrix(nc, nr);
4627                let expected = (0..nc)
4628                    .map(|c| (0..nr).map(|r| (r * (c * nr + r)) as f32).sum())
4629                    .collect::<Vec<f32>>();
4630                assert_eq!(evaluated, expected);
4631
4632                // Validates multiplication on matrix-vector.
4633                // matCxR(0, 1, .., nc * nr) * vecC(0, 1, .., nc)
4634                let evaluated = helper.eval_matrix_multiply_vector(nc, nr);
4635                let expected = (0..nr)
4636                    .map(|r| (0..nc).map(|c| (c * (c * nr + r)) as f32).sum())
4637                    .collect::<Vec<f32>>();
4638                assert_eq!(evaluated, expected);
4639
4640                for k in 2..=4 {
4641                    // Validates multiplication on matrix-matrix.
4642                    // matKxR(0, 1, .., k * nr) * matCxK(0, 1, .., nc * k)
4643                    let evaluated = helper.eval_matrix_multiply_matrix(nr, nc, k);
4644                    let expected = (0..nc)
4645                        .flat_map(|c| {
4646                            (0..nr).map(move |r| {
4647                                (0..k).map(|v| ((v * nr + r) * (c * k + v)) as f32).sum()
4648                            })
4649                        })
4650                        .collect::<Vec<f32>>();
4651                    assert_eq!(evaluated, expected);
4652                }
4653            }
4654        }
4655    }
4656
4657    /// Test fixture providing pre-built f32 vector and matrix constant
4658    /// expressions with sequential element values, used to evaluate and verify
4659    /// matrix operations.
4660    struct MatrixTestHelper {
4661        types: UniqueArena<Type>,
4662        expressions: Arena<Expression>,
4663        /// Vector expressions from [0, 1] to [0, 1, 2, 3].
4664        vec_exprs: FastHashMap<usize, Handle<Expression>>,
4665        /// Matrix expressions from [0, .., 3] to [0, .., 15].
4666        mat_exprs: FastHashMap<(usize, usize), Handle<Expression>>,
4667    }
4668
4669    impl MatrixTestHelper {
4670        fn new() -> Self {
4671            let mut types = UniqueArena::new();
4672            let mut expressions = Arena::new();
4673            let span = crate::Span::default();
4674
4675            let (mut vec_tys, mut mat_tys) = (FastHashMap::default(), FastHashMap::default());
4676            for c in 2..=4 {
4677                let vec_ty = types.insert(
4678                    Type {
4679                        name: None,
4680                        inner: TypeInner::Vector {
4681                            size: Self::int_to_vector_size(c),
4682                            scalar: crate::Scalar::F32,
4683                        },
4684                    },
4685                    span,
4686                );
4687                vec_tys.insert(c, vec_ty);
4688                for r in 2..=4 {
4689                    let mat_ty = types.insert(
4690                        Type {
4691                            name: None,
4692                            inner: TypeInner::Matrix {
4693                                columns: Self::int_to_vector_size(c),
4694                                rows: Self::int_to_vector_size(r),
4695                                scalar: crate::Scalar::F32,
4696                            },
4697                        },
4698                        span,
4699                    );
4700                    mat_tys.insert((c, r), mat_ty);
4701                }
4702            }
4703
4704            let mut lit_exprs = FastHashMap::default();
4705            for i in 0..16 {
4706                let expr = expressions.append(Expression::Literal(Literal::F32(i as f32)), span);
4707                lit_exprs.insert(i, expr);
4708            }
4709
4710            let mut vec_exprs = FastHashMap::default();
4711            for c in 2..=4 {
4712                let expr = expressions.append(
4713                    Expression::Compose {
4714                        ty: *vec_tys.get(&c).unwrap(),
4715                        components: (0..c)
4716                            .map(|i| *lit_exprs.get(&i).unwrap())
4717                            .collect::<Vec<_>>(),
4718                    },
4719                    span,
4720                );
4721                vec_exprs.insert(c, expr);
4722            }
4723
4724            let mut mat_exprs = FastHashMap::default();
4725            for c in 2..=4 {
4726                for r in 2..=4 {
4727                    let mut columns = Vec::with_capacity(c);
4728                    for cc in 0..c {
4729                        let start = cc * r;
4730                        let expr = expressions.append(
4731                            Expression::Compose {
4732                                ty: *vec_tys.get(&r).unwrap(),
4733                                components: (start..start + r)
4734                                    .map(|i| *lit_exprs.get(&i).unwrap())
4735                                    .collect::<Vec<_>>(),
4736                            },
4737                            span,
4738                        );
4739                        columns.push(expr);
4740                    }
4741
4742                    let expr = expressions.append(
4743                        Expression::Compose {
4744                            ty: *mat_tys.get(&(c, r)).unwrap(),
4745                            components: columns,
4746                        },
4747                        span,
4748                    );
4749                    mat_exprs.insert((c, r), expr);
4750                }
4751            }
4752
4753            Self {
4754                types,
4755                expressions,
4756                vec_exprs,
4757                mat_exprs,
4758            }
4759        }
4760
4761        /// Evaluates vec[0..nr] * mat[0..nc*nr] and returns the result as f32s.
4762        fn eval_vector_multiply_matrix(&mut self, nc: usize, nr: usize) -> Vec<f32> {
4763            let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&self.expressions);
4764            let mut solver = ConstantEvaluator {
4765                behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4766                types: &mut self.types,
4767                constants: &Arena::new(),
4768                overrides: &Arena::new(),
4769                expressions: &mut self.expressions,
4770                expression_kind_tracker,
4771                layouter: &mut crate::proc::Layouter::default(),
4772            };
4773
4774            let result = solver
4775                .try_eval_and_append(
4776                    Expression::Binary {
4777                        op: BinaryOperator::Multiply,
4778                        left: *self.vec_exprs.get(&nr).unwrap(),
4779                        right: *self.mat_exprs.get(&(nc, nr)).unwrap(),
4780                    },
4781                    Default::default(),
4782                )
4783                .unwrap();
4784            self.flatten(result)
4785        }
4786
4787        /// Evaluates mat[0..nc*nr] * vec[0..nc] and returns the result as f32s.
4788        fn eval_matrix_multiply_vector(&mut self, nc: usize, nr: usize) -> Vec<f32> {
4789            let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&self.expressions);
4790            let mut solver = ConstantEvaluator {
4791                behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4792                types: &mut self.types,
4793                constants: &Arena::new(),
4794                overrides: &Arena::new(),
4795                expressions: &mut self.expressions,
4796                expression_kind_tracker,
4797                layouter: &mut crate::proc::Layouter::default(),
4798            };
4799
4800            let result = solver
4801                .try_eval_and_append(
4802                    Expression::Binary {
4803                        op: BinaryOperator::Multiply,
4804                        left: *self.mat_exprs.get(&(nc, nr)).unwrap(),
4805                        right: *self.vec_exprs.get(&nc).unwrap(),
4806                    },
4807                    Default::default(),
4808                )
4809                .unwrap();
4810            self.flatten(result)
4811        }
4812
4813        /// Evaluates mat[0..k*l_nr] * mat[0..r_nc*k] and returns the result as
4814        /// f32s.
4815        fn eval_matrix_multiply_matrix(&mut self, l_nr: usize, r_nc: usize, k: usize) -> Vec<f32> {
4816            let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&self.expressions);
4817            let mut solver = ConstantEvaluator {
4818                behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4819                types: &mut self.types,
4820                constants: &Arena::new(),
4821                overrides: &Arena::new(),
4822                expressions: &mut self.expressions,
4823                expression_kind_tracker,
4824                layouter: &mut crate::proc::Layouter::default(),
4825            };
4826
4827            let result = solver
4828                .try_eval_and_append(
4829                    Expression::Binary {
4830                        op: BinaryOperator::Multiply,
4831                        left: *self.mat_exprs.get(&(k, l_nr)).unwrap(),
4832                        right: *self.mat_exprs.get(&(r_nc, k)).unwrap(),
4833                    },
4834                    Default::default(),
4835                )
4836                .unwrap();
4837            self.flatten(result)
4838        }
4839
4840        fn flatten(&self, expr: Handle<Expression>) -> Vec<f32> {
4841            let Expression::Compose {
4842                ref components,
4843                ref ty,
4844            } = self.expressions[expr]
4845            else {
4846                unreachable!()
4847            };
4848
4849            match self.types[*ty].inner {
4850                TypeInner::Vector { .. } => components
4851                    .iter()
4852                    .map(|&comp| {
4853                        let Expression::Literal(Literal::F32(v)) = self.expressions[comp] else {
4854                            unreachable!()
4855                        };
4856                        v
4857                    })
4858                    .collect(),
4859                TypeInner::Matrix { .. } => components
4860                    .iter()
4861                    .flat_map(|&comp| self.flatten(comp))
4862                    .collect(),
4863                _ => unreachable!(),
4864            }
4865        }
4866
4867        fn int_to_vector_size(int: usize) -> VectorSize {
4868            match int {
4869                2 => VectorSize::Bi,
4870                3 => VectorSize::Tri,
4871                4 => VectorSize::Quad,
4872                _ => unreachable!(),
4873            }
4874        }
4875    }
4876
4877    #[test]
4878    fn cast() {
4879        let mut types = UniqueArena::new();
4880        let mut constants = Arena::new();
4881        let overrides = Arena::new();
4882        let mut global_expressions = Arena::new();
4883
4884        let scalar_ty = types.insert(
4885            Type {
4886                name: None,
4887                inner: TypeInner::Scalar(crate::Scalar::I32),
4888            },
4889            Default::default(),
4890        );
4891
4892        let h = constants.append(
4893            Constant {
4894                name: None,
4895                ty: scalar_ty,
4896                init: global_expressions
4897                    .append(Expression::Literal(Literal::I32(4)), Default::default()),
4898            },
4899            Default::default(),
4900        );
4901
4902        let expr = global_expressions.append(Expression::Constant(h), Default::default());
4903
4904        let root = Expression::As {
4905            expr,
4906            target: crate::Scalar::BOOL,
4907        };
4908
4909        let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
4910        let mut solver = ConstantEvaluator {
4911            behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4912            types: &mut types,
4913            constants: &constants,
4914            overrides: &overrides,
4915            expressions: &mut global_expressions,
4916            expression_kind_tracker,
4917            layouter: &mut crate::proc::Layouter::default(),
4918        };
4919
4920        let res = solver
4921            .try_eval_and_append(root, Default::default())
4922            .unwrap();
4923
4924        assert_eq!(
4925            global_expressions[res],
4926            Expression::Literal(Literal::Bool(true))
4927        );
4928    }
4929
4930    #[test]
4931    fn access() {
4932        let mut types = UniqueArena::new();
4933        let mut constants = Arena::new();
4934        let overrides = Arena::new();
4935        let mut global_expressions = Arena::new();
4936
4937        let matrix_ty = types.insert(
4938            Type {
4939                name: None,
4940                inner: TypeInner::Matrix {
4941                    columns: VectorSize::Bi,
4942                    rows: VectorSize::Tri,
4943                    scalar: crate::Scalar::F32,
4944                },
4945            },
4946            Default::default(),
4947        );
4948
4949        let vec_ty = types.insert(
4950            Type {
4951                name: None,
4952                inner: TypeInner::Vector {
4953                    size: VectorSize::Tri,
4954                    scalar: crate::Scalar::F32,
4955                },
4956            },
4957            Default::default(),
4958        );
4959
4960        let mut vec1_components = Vec::with_capacity(3);
4961        let mut vec2_components = Vec::with_capacity(3);
4962
4963        for i in 0..3 {
4964            let h = global_expressions.append(
4965                Expression::Literal(Literal::F32(i as f32)),
4966                Default::default(),
4967            );
4968
4969            vec1_components.push(h)
4970        }
4971
4972        for i in 3..6 {
4973            let h = global_expressions.append(
4974                Expression::Literal(Literal::F32(i as f32)),
4975                Default::default(),
4976            );
4977
4978            vec2_components.push(h)
4979        }
4980
4981        let vec1 = constants.append(
4982            Constant {
4983                name: None,
4984                ty: vec_ty,
4985                init: global_expressions.append(
4986                    Expression::Compose {
4987                        ty: vec_ty,
4988                        components: vec1_components,
4989                    },
4990                    Default::default(),
4991                ),
4992            },
4993            Default::default(),
4994        );
4995
4996        let vec2 = constants.append(
4997            Constant {
4998                name: None,
4999                ty: vec_ty,
5000                init: global_expressions.append(
5001                    Expression::Compose {
5002                        ty: vec_ty,
5003                        components: vec2_components,
5004                    },
5005                    Default::default(),
5006                ),
5007            },
5008            Default::default(),
5009        );
5010
5011        let h = constants.append(
5012            Constant {
5013                name: None,
5014                ty: matrix_ty,
5015                init: global_expressions.append(
5016                    Expression::Compose {
5017                        ty: matrix_ty,
5018                        components: vec![constants[vec1].init, constants[vec2].init],
5019                    },
5020                    Default::default(),
5021                ),
5022            },
5023            Default::default(),
5024        );
5025
5026        let base = global_expressions.append(Expression::Constant(h), Default::default());
5027
5028        let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
5029        let mut solver = ConstantEvaluator {
5030            behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
5031            types: &mut types,
5032            constants: &constants,
5033            overrides: &overrides,
5034            expressions: &mut global_expressions,
5035            expression_kind_tracker,
5036            layouter: &mut crate::proc::Layouter::default(),
5037        };
5038
5039        let root1 = Expression::AccessIndex { base, index: 1 };
5040
5041        let res1 = solver
5042            .try_eval_and_append(root1, Default::default())
5043            .unwrap();
5044
5045        let root2 = Expression::AccessIndex {
5046            base: res1,
5047            index: 2,
5048        };
5049
5050        let res2 = solver
5051            .try_eval_and_append(root2, Default::default())
5052            .unwrap();
5053
5054        match global_expressions[res1] {
5055            Expression::Compose {
5056                ref ty,
5057                ref components,
5058            } => {
5059                assert_eq!(*ty, vec_ty);
5060                let mut components_iter = components.iter().copied();
5061                assert_eq!(
5062                    global_expressions[components_iter.next().unwrap()],
5063                    Expression::Literal(Literal::F32(3.))
5064                );
5065                assert_eq!(
5066                    global_expressions[components_iter.next().unwrap()],
5067                    Expression::Literal(Literal::F32(4.))
5068                );
5069                assert_eq!(
5070                    global_expressions[components_iter.next().unwrap()],
5071                    Expression::Literal(Literal::F32(5.))
5072                );
5073                assert!(components_iter.next().is_none());
5074            }
5075            _ => panic!("Expected vector"),
5076        }
5077
5078        assert_eq!(
5079            global_expressions[res2],
5080            Expression::Literal(Literal::F32(5.))
5081        );
5082    }
5083
5084    #[test]
5085    fn compose_of_constants() {
5086        let mut types = UniqueArena::new();
5087        let mut constants = Arena::new();
5088        let overrides = Arena::new();
5089        let mut global_expressions = Arena::new();
5090
5091        let i32_ty = types.insert(
5092            Type {
5093                name: None,
5094                inner: TypeInner::Scalar(crate::Scalar::I32),
5095            },
5096            Default::default(),
5097        );
5098
5099        let vec2_i32_ty = types.insert(
5100            Type {
5101                name: None,
5102                inner: TypeInner::Vector {
5103                    size: VectorSize::Bi,
5104                    scalar: crate::Scalar::I32,
5105                },
5106            },
5107            Default::default(),
5108        );
5109
5110        let h = constants.append(
5111            Constant {
5112                name: None,
5113                ty: i32_ty,
5114                init: global_expressions
5115                    .append(Expression::Literal(Literal::I32(4)), Default::default()),
5116            },
5117            Default::default(),
5118        );
5119
5120        let h_expr = global_expressions.append(Expression::Constant(h), Default::default());
5121
5122        let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
5123        let mut solver = ConstantEvaluator {
5124            behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
5125            types: &mut types,
5126            constants: &constants,
5127            overrides: &overrides,
5128            expressions: &mut global_expressions,
5129            expression_kind_tracker,
5130            layouter: &mut crate::proc::Layouter::default(),
5131        };
5132
5133        let solved_compose = solver
5134            .try_eval_and_append(
5135                Expression::Compose {
5136                    ty: vec2_i32_ty,
5137                    components: vec![h_expr, h_expr],
5138                },
5139                Default::default(),
5140            )
5141            .unwrap();
5142        let solved_negate = solver
5143            .try_eval_and_append(
5144                Expression::Unary {
5145                    op: UnaryOperator::Negate,
5146                    expr: solved_compose,
5147                },
5148                Default::default(),
5149            )
5150            .unwrap();
5151
5152        let pass = match global_expressions[solved_negate] {
5153            Expression::Compose { ty, ref components } => {
5154                ty == vec2_i32_ty
5155                    && components.iter().all(|&component| {
5156                        let component = &global_expressions[component];
5157                        matches!(*component, Expression::Literal(Literal::I32(-4)))
5158                    })
5159            }
5160            _ => false,
5161        };
5162        if !pass {
5163            panic!("unexpected evaluation result")
5164        }
5165    }
5166
5167    #[test]
5168    fn splat_of_constant() {
5169        let mut types = UniqueArena::new();
5170        let mut constants = Arena::new();
5171        let overrides = Arena::new();
5172        let mut global_expressions = Arena::new();
5173
5174        let i32_ty = types.insert(
5175            Type {
5176                name: None,
5177                inner: TypeInner::Scalar(crate::Scalar::I32),
5178            },
5179            Default::default(),
5180        );
5181
5182        let vec2_i32_ty = types.insert(
5183            Type {
5184                name: None,
5185                inner: TypeInner::Vector {
5186                    size: VectorSize::Bi,
5187                    scalar: crate::Scalar::I32,
5188                },
5189            },
5190            Default::default(),
5191        );
5192
5193        let h = constants.append(
5194            Constant {
5195                name: None,
5196                ty: i32_ty,
5197                init: global_expressions
5198                    .append(Expression::Literal(Literal::I32(4)), Default::default()),
5199            },
5200            Default::default(),
5201        );
5202
5203        let h_expr = global_expressions.append(Expression::Constant(h), Default::default());
5204
5205        let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
5206        let mut solver = ConstantEvaluator {
5207            behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
5208            types: &mut types,
5209            constants: &constants,
5210            overrides: &overrides,
5211            expressions: &mut global_expressions,
5212            expression_kind_tracker,
5213            layouter: &mut crate::proc::Layouter::default(),
5214        };
5215
5216        let solved_compose = solver
5217            .try_eval_and_append(
5218                Expression::Splat {
5219                    size: VectorSize::Bi,
5220                    value: h_expr,
5221                },
5222                Default::default(),
5223            )
5224            .unwrap();
5225        let solved_negate = solver
5226            .try_eval_and_append(
5227                Expression::Unary {
5228                    op: UnaryOperator::Negate,
5229                    expr: solved_compose,
5230                },
5231                Default::default(),
5232            )
5233            .unwrap();
5234
5235        let pass = match global_expressions[solved_negate] {
5236            Expression::Compose { ty, ref components } => {
5237                ty == vec2_i32_ty
5238                    && components.iter().all(|&component| {
5239                        let component = &global_expressions[component];
5240                        matches!(*component, Expression::Literal(Literal::I32(-4)))
5241                    })
5242            }
5243            _ => false,
5244        };
5245        if !pass {
5246            panic!("unexpected evaluation result")
5247        }
5248    }
5249
5250    #[test]
5251    fn splat_of_zero_value() {
5252        let mut types = UniqueArena::new();
5253        let constants = Arena::new();
5254        let overrides = Arena::new();
5255        let mut global_expressions = Arena::new();
5256
5257        let f32_ty = types.insert(
5258            Type {
5259                name: None,
5260                inner: TypeInner::Scalar(crate::Scalar::F32),
5261            },
5262            Default::default(),
5263        );
5264
5265        let vec2_f32_ty = types.insert(
5266            Type {
5267                name: None,
5268                inner: TypeInner::Vector {
5269                    size: VectorSize::Bi,
5270                    scalar: crate::Scalar::F32,
5271                },
5272            },
5273            Default::default(),
5274        );
5275
5276        let five =
5277            global_expressions.append(Expression::Literal(Literal::F32(5.0)), Default::default());
5278        let five_splat = global_expressions.append(
5279            Expression::Splat {
5280                size: VectorSize::Bi,
5281                value: five,
5282            },
5283            Default::default(),
5284        );
5285        let zero = global_expressions.append(Expression::ZeroValue(f32_ty), Default::default());
5286        let zero_splat = global_expressions.append(
5287            Expression::Splat {
5288                size: VectorSize::Bi,
5289                value: zero,
5290            },
5291            Default::default(),
5292        );
5293
5294        let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
5295        let mut solver = ConstantEvaluator {
5296            behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
5297            types: &mut types,
5298            constants: &constants,
5299            overrides: &overrides,
5300            expressions: &mut global_expressions,
5301            expression_kind_tracker,
5302            layouter: &mut crate::proc::Layouter::default(),
5303        };
5304
5305        let solved_add = solver
5306            .try_eval_and_append(
5307                Expression::Binary {
5308                    op: BinaryOperator::Add,
5309                    left: zero_splat,
5310                    right: five_splat,
5311                },
5312                Default::default(),
5313            )
5314            .unwrap();
5315
5316        let pass = match global_expressions[solved_add] {
5317            Expression::Compose { ty, ref components } => {
5318                ty == vec2_f32_ty
5319                    && components.iter().all(|&component| {
5320                        let component = &global_expressions[component];
5321                        matches!(*component, Expression::Literal(Literal::F32(5.0)))
5322                    })
5323            }
5324            _ => false,
5325        };
5326        if !pass {
5327            panic!("unexpected evaluation result")
5328        }
5329    }
5330}