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, .. } => 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 {
1317                convert,
1318                expr,
1319                kind,
1320            } => {
1321                let expr = self.check_and_get(expr)?;
1322
1323                match convert {
1324                    Some(width) => self.cast(expr, crate::Scalar { kind, width }, span),
1325                    None => Err(ConstantEvaluatorError::NotImplemented(
1326                        "bitcast built-in function".into(),
1327                    )),
1328                }
1329            }
1330            Expression::Select {
1331                reject,
1332                accept,
1333                condition,
1334            } => {
1335                let mut arg = |expr| self.check_and_get(expr);
1336
1337                let reject = arg(reject)?;
1338                let accept = arg(accept)?;
1339                let condition = arg(condition)?;
1340
1341                self.select(reject, accept, condition, span)
1342            }
1343            Expression::Relational { fun, argument } => {
1344                let argument = self.check_and_get(argument)?;
1345                self.relational(fun, argument, span)
1346            }
1347            Expression::ArrayLength(expr) => match self.behavior {
1348                Behavior::Wgsl(_) => Err(ConstantEvaluatorError::ArrayLength),
1349                Behavior::Glsl(_) => {
1350                    let expr = self.check_and_get(expr)?;
1351                    self.array_length(expr, span)
1352                }
1353            },
1354            Expression::Load { .. } => Err(ConstantEvaluatorError::Load),
1355            Expression::LocalVariable(_) => Err(ConstantEvaluatorError::LocalVariable),
1356            Expression::Derivative { .. } => Err(ConstantEvaluatorError::Derivative),
1357            Expression::CallResult { .. } => Err(ConstantEvaluatorError::Call),
1358            Expression::WorkGroupUniformLoadResult { .. } => {
1359                Err(ConstantEvaluatorError::WorkGroupUniformLoadResult)
1360            }
1361            Expression::AtomicResult { .. } => Err(ConstantEvaluatorError::Atomic),
1362            Expression::FunctionArgument(_) => Err(ConstantEvaluatorError::FunctionArg),
1363            Expression::GlobalVariable(_) => Err(ConstantEvaluatorError::GlobalVariable),
1364            Expression::ImageSample { .. }
1365            | Expression::ImageLoad { .. }
1366            | Expression::ImageQuery { .. } => Err(ConstantEvaluatorError::ImageExpression),
1367            Expression::RayQueryProceedResult
1368            | Expression::RayQueryGetIntersection { .. }
1369            | Expression::RayQueryVertexPositions { .. } => {
1370                Err(ConstantEvaluatorError::RayQueryExpression)
1371            }
1372            Expression::SubgroupBallotResult => Err(ConstantEvaluatorError::SubgroupExpression),
1373            Expression::SubgroupOperationResult { .. } => {
1374                Err(ConstantEvaluatorError::SubgroupExpression)
1375            }
1376            Expression::CooperativeLoad { .. } | Expression::CooperativeMultiplyAdd { .. } => {
1377                Err(ConstantEvaluatorError::CooperativeOperation)
1378            }
1379        }
1380    }
1381
1382    /// Splat `value` to `size`, without using [`Splat`] expressions.
1383    ///
1384    /// This constructs [`Compose`] or [`ZeroValue`] expressions to
1385    /// build a vector with the given `size` whose components are all
1386    /// `value`.
1387    ///
1388    /// Use `span` as the span of the inserted expressions and
1389    /// resulting types.
1390    ///
1391    /// [`Splat`]: Expression::Splat
1392    /// [`Compose`]: Expression::Compose
1393    /// [`ZeroValue`]: Expression::ZeroValue
1394    fn splat(
1395        &mut self,
1396        value: Handle<Expression>,
1397        size: crate::VectorSize,
1398        span: Span,
1399    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1400        match self.expressions[value] {
1401            Expression::Literal(literal) => {
1402                let scalar = literal.scalar();
1403                let ty = self.types.insert(
1404                    Type {
1405                        name: None,
1406                        inner: TypeInner::Vector { size, scalar },
1407                    },
1408                    span,
1409                );
1410                let expr = Expression::Compose {
1411                    ty,
1412                    components: vec![value; size as usize],
1413                };
1414                self.register_evaluated_expr(expr, span)
1415            }
1416            Expression::ZeroValue(ty) => {
1417                let inner = match self.types[ty].inner {
1418                    TypeInner::Scalar(scalar) => TypeInner::Vector { size, scalar },
1419                    _ => return Err(ConstantEvaluatorError::SplatScalarOnly),
1420                };
1421                let res_ty = self.types.insert(Type { name: None, inner }, span);
1422                let expr = Expression::ZeroValue(res_ty);
1423                self.register_evaluated_expr(expr, span)
1424            }
1425            _ => Err(ConstantEvaluatorError::SplatScalarOnly),
1426        }
1427    }
1428
1429    fn swizzle(
1430        &mut self,
1431        size: crate::VectorSize,
1432        span: Span,
1433        src_constant: Handle<Expression>,
1434        pattern: [crate::SwizzleComponent; 4],
1435    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1436        let mut get_dst_ty = |ty| match self.types[ty].inner {
1437            TypeInner::Vector { size: _, scalar } => Ok(self.types.insert(
1438                Type {
1439                    name: None,
1440                    inner: TypeInner::Vector { size, scalar },
1441                },
1442                span,
1443            )),
1444            _ => Err(ConstantEvaluatorError::SwizzleVectorOnly),
1445        };
1446
1447        match self.expressions[src_constant] {
1448            Expression::ZeroValue(ty) => {
1449                let dst_ty = get_dst_ty(ty)?;
1450                let expr = Expression::ZeroValue(dst_ty);
1451                self.register_evaluated_expr(expr, span)
1452            }
1453            Expression::Splat { value, .. } => {
1454                let expr = Expression::Splat { size, value };
1455                self.register_evaluated_expr(expr, span)
1456            }
1457            Expression::Compose { ty, ref components } => {
1458                let dst_ty = get_dst_ty(ty)?;
1459
1460                let mut flattened = [src_constant; 4]; // dummy value
1461                let len =
1462                    crate::proc::flatten_compose(ty, components, self.expressions, self.types)
1463                        .zip(flattened.iter_mut())
1464                        .map(|(component, elt)| *elt = component)
1465                        .count();
1466                let flattened = &flattened[..len];
1467
1468                let swizzled_components = pattern[..size as usize]
1469                    .iter()
1470                    .map(|&sc| {
1471                        let sc = sc as usize;
1472                        if let Some(elt) = flattened.get(sc) {
1473                            Ok(*elt)
1474                        } else {
1475                            Err(ConstantEvaluatorError::SwizzleOutOfBounds)
1476                        }
1477                    })
1478                    .collect::<Result<Vec<Handle<Expression>>, _>>()?;
1479                let expr = Expression::Compose {
1480                    ty: dst_ty,
1481                    components: swizzled_components,
1482                };
1483                self.register_evaluated_expr(expr, span)
1484            }
1485            _ => Err(ConstantEvaluatorError::SwizzleVectorOnly),
1486        }
1487    }
1488
1489    fn math(
1490        &mut self,
1491        arg: Handle<Expression>,
1492        arg1: Option<Handle<Expression>>,
1493        arg2: Option<Handle<Expression>>,
1494        arg3: Option<Handle<Expression>>,
1495        fun: crate::MathFunction,
1496        span: Span,
1497    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1498        let expected = fun.argument_count();
1499        let given = Some(arg)
1500            .into_iter()
1501            .chain(arg1)
1502            .chain(arg2)
1503            .chain(arg3)
1504            .count();
1505        if expected != given {
1506            return Err(ConstantEvaluatorError::InvalidMathArgCount(
1507                fun, expected, given,
1508            ));
1509        }
1510
1511        // NOTE: We try to match the declaration order of `MathFunction` here.
1512        match fun {
1513            // comparison
1514            crate::MathFunction::Abs => {
1515                component_wise_scalar(self, span, [arg], |args| match args {
1516                    Scalar::AbstractFloat([e]) => Ok(Scalar::AbstractFloat([e.abs()])),
1517                    Scalar::F32([e]) => Ok(Scalar::F32([e.abs()])),
1518                    Scalar::F16([e]) => Ok(Scalar::F16([e.abs()])),
1519                    Scalar::AbstractInt([e]) => Ok(Scalar::AbstractInt([e.wrapping_abs()])),
1520                    Scalar::I32([e]) => Ok(Scalar::I32([e.wrapping_abs()])),
1521                    Scalar::U32([e]) => Ok(Scalar::U32([e])), // TODO: just re-use the expression, ezpz
1522                    Scalar::I64([e]) => Ok(Scalar::I64([e.wrapping_abs()])),
1523                    Scalar::U64([e]) => Ok(Scalar::U64([e])),
1524                })
1525            }
1526            crate::MathFunction::Min => {
1527                component_wise_scalar!(self, span, [arg, arg1.unwrap()], |e1, e2| {
1528                    Ok([e1.min(e2)])
1529                })
1530            }
1531            crate::MathFunction::Max => {
1532                component_wise_scalar!(self, span, [arg, arg1.unwrap()], |e1, e2| {
1533                    Ok([e1.max(e2)])
1534                })
1535            }
1536            crate::MathFunction::Clamp => {
1537                component_wise_scalar!(
1538                    self,
1539                    span,
1540                    [arg, arg1.unwrap(), arg2.unwrap()],
1541                    |e, low, high| {
1542                        if low > high {
1543                            Err(ConstantEvaluatorError::InvalidClamp)
1544                        } else {
1545                            Ok([e.clamp(low, high)])
1546                        }
1547                    }
1548                )
1549            }
1550            crate::MathFunction::Saturate => component_wise_float(self, span, [arg], |e| match e {
1551                Float::F16([e]) => Ok(Float::F16(
1552                    [e.clamp(f16::from_f32(0.0), f16::from_f32(1.0))],
1553                )),
1554                Float::F32([e]) => Ok(Float::F32([e.clamp(0., 1.)])),
1555                Float::Abstract([e]) => Ok(Float::Abstract([e.clamp(0., 1.)])),
1556            }),
1557
1558            // trigonometry
1559            crate::MathFunction::Cos => {
1560                component_wise_float!(self, span, [arg], |e| { Ok([e.cos()]) })
1561            }
1562            crate::MathFunction::Cosh => {
1563                component_wise_float!(self, span, [arg], |e| {
1564                    let result = e.cosh();
1565                    if result.is_finite() {
1566                        Ok([result])
1567                    } else {
1568                        Err(ConstantEvaluatorError::Overflow("cosh".into()))
1569                    }
1570                })
1571            }
1572            crate::MathFunction::Sin => {
1573                component_wise_float!(self, span, [arg], |e| { Ok([e.sin()]) })
1574            }
1575            crate::MathFunction::Sinh => {
1576                component_wise_float!(self, span, [arg], |e| {
1577                    let result = e.sinh();
1578                    if result.is_finite() {
1579                        Ok([result])
1580                    } else {
1581                        Err(ConstantEvaluatorError::Overflow("sinh".into()))
1582                    }
1583                })
1584            }
1585            crate::MathFunction::Tan => {
1586                component_wise_float!(self, span, [arg], |e| { Ok([e.tan()]) })
1587            }
1588            crate::MathFunction::Tanh => {
1589                component_wise_float!(self, span, [arg], |e| { Ok([e.tanh()]) })
1590            }
1591            crate::MathFunction::Acos => {
1592                component_wise_float!(self, span, [arg], |e| {
1593                    if e.abs() <= One::one() {
1594                        Ok([e.acos()])
1595                    } else {
1596                        Err(ConstantEvaluatorError::InvalidMathArgValue("acos".into()))
1597                    }
1598                })
1599            }
1600            crate::MathFunction::Asin => {
1601                component_wise_float!(self, span, [arg], |e| {
1602                    if e.abs() <= One::one() {
1603                        Ok([e.asin()])
1604                    } else {
1605                        Err(ConstantEvaluatorError::InvalidMathArgValue("asin".into()))
1606                    }
1607                })
1608            }
1609            crate::MathFunction::Atan => {
1610                component_wise_float!(self, span, [arg], |e| { Ok([e.atan()]) })
1611            }
1612            crate::MathFunction::Atan2 => {
1613                component_wise_float!(self, span, [arg, arg1.unwrap()], |y, x| {
1614                    Ok([y.atan2(x)])
1615                })
1616            }
1617            crate::MathFunction::Asinh => component_wise_float(self, span, [arg], |e| match e {
1618                Float::Abstract([e]) => Ok(Float::Abstract([libm::asinh(e)])),
1619                Float::F32([e]) => Ok(Float::F32([(e as f64).asinh() as f32])),
1620                Float::F16([e]) => Ok(Float::F16([e.asinh()])),
1621            }),
1622            crate::MathFunction::Acosh => component_wise_float(self, span, [arg], |e| match e {
1623                Float::Abstract([e]) if e >= One::one() => Ok(Float::Abstract([libm::acosh(e)])),
1624                Float::F32([e]) if e >= One::one() => Ok(Float::F32([(e as f64).acosh() as f32])),
1625                Float::F16([e]) if e >= One::one() => Ok(Float::F16([e.acosh()])),
1626                _ => Err(ConstantEvaluatorError::InvalidMathArgValue("acosh".into())),
1627            }),
1628            crate::MathFunction::Atanh => {
1629                component_wise_float!(self, span, [arg], |e| {
1630                    if e.abs() < One::one() {
1631                        Ok([e.atanh()])
1632                    } else {
1633                        Err(ConstantEvaluatorError::InvalidMathArgValue("atanh".into()))
1634                    }
1635                })
1636            }
1637            crate::MathFunction::Radians => {
1638                component_wise_float!(self, span, [arg], |e1| { Ok([e1.to_radians()]) })
1639            }
1640            crate::MathFunction::Degrees => {
1641                component_wise_float!(self, span, [arg], |e| {
1642                    let result = e.to_degrees();
1643                    if result.is_finite() {
1644                        Ok([result])
1645                    } else {
1646                        Err(ConstantEvaluatorError::Overflow("degrees".into()))
1647                    }
1648                })
1649            }
1650
1651            // decomposition
1652            crate::MathFunction::Ceil => {
1653                component_wise_float!(self, span, [arg], |e| { Ok([e.ceil()]) })
1654            }
1655            crate::MathFunction::Floor => {
1656                component_wise_float!(self, span, [arg], |e| { Ok([e.floor()]) })
1657            }
1658            crate::MathFunction::Round => {
1659                component_wise_float(self, span, [arg], |e| match e {
1660                    Float::Abstract([e]) => Ok(Float::Abstract([libm::rint(e)])),
1661                    Float::F32([e]) => Ok(Float::F32([libm::rintf(e)])),
1662                    Float::F16([e]) => {
1663                        // TODO: `round_ties_even` is not available on `half::f16` yet.
1664                        //
1665                        // This polyfill is shamelessly [~~stolen from~~ inspired by `ndarray-image`][polyfill source],
1666                        // which has licensing compatible with ours. See also
1667                        // <https://github.com/rust-lang/rust/issues/96710>.
1668                        //
1669                        // [polyfill source]: https://github.com/imeka/ndarray-ndimage/blob/8b14b4d6ecfbc96a8a052f802e342a7049c68d8f/src/lib.rs#L98
1670                        fn round_ties_even(x: f64) -> f64 {
1671                            let i = x as i64;
1672                            let f = (x - i as f64).abs();
1673                            if f == 0.5 {
1674                                if i & 1 == 1 {
1675                                    // -1.5, 1.5, 3.5, ...
1676                                    (x.abs() + 0.5).copysign(x)
1677                                } else {
1678                                    (x.abs() - 0.5).copysign(x)
1679                                }
1680                            } else {
1681                                x.round()
1682                            }
1683                        }
1684
1685                        Ok(Float::F16([(f16::from_f64(round_ties_even(f64::from(e))))]))
1686                    }
1687                })
1688            }
1689            crate::MathFunction::Fract => {
1690                component_wise_float!(self, span, [arg], |e| {
1691                    // N.B., Rust's definition of `fract` is `e - e.trunc()`, so we can't use that
1692                    // here.
1693                    Ok([e - e.floor()])
1694                })
1695            }
1696            crate::MathFunction::Trunc => {
1697                component_wise_float!(self, span, [arg], |e| { Ok([e.trunc()]) })
1698            }
1699
1700            // exponent
1701            crate::MathFunction::Exp => {
1702                component_wise_float!(self, span, [arg], |e| {
1703                    let result = e.exp();
1704                    if result.is_finite() {
1705                        Ok([result])
1706                    } else {
1707                        Err(ConstantEvaluatorError::Overflow("exp".into()))
1708                    }
1709                })
1710            }
1711            crate::MathFunction::Exp2 => {
1712                component_wise_float!(self, span, [arg], |e| {
1713                    let result = e.exp2();
1714                    if result.is_finite() {
1715                        Ok([result])
1716                    } else {
1717                        Err(ConstantEvaluatorError::Overflow("exp2".into()))
1718                    }
1719                })
1720            }
1721            crate::MathFunction::Log => {
1722                component_wise_float!(self, span, [arg], |e| {
1723                    if e > Zero::zero() {
1724                        Ok([e.ln()])
1725                    } else {
1726                        Err(ConstantEvaluatorError::InvalidMathArgValue("log".into()))
1727                    }
1728                })
1729            }
1730            crate::MathFunction::Log2 => {
1731                component_wise_float!(self, span, [arg], |e| {
1732                    if e > Zero::zero() {
1733                        Ok([e.log2()])
1734                    } else {
1735                        Err(ConstantEvaluatorError::InvalidMathArgValue("log2".into()))
1736                    }
1737                })
1738            }
1739            crate::MathFunction::Pow => {
1740                component_wise_float!(self, span, [arg, arg1.unwrap()], |e1, e2| {
1741                    // 0.pow(0) is an error since exp2(0 * log2(0)) is NaN.
1742                    // https://www.w3.org/TR/WGSL/#pow-builtin
1743                    if e1 < Zero::zero()
1744                        || e1.is_one() && e2.is_infinite()
1745                        || e1.is_infinite() && e2.is_zero()
1746                        || e1.is_zero() && e2.is_zero()
1747                    {
1748                        Err(ConstantEvaluatorError::InvalidMathArgValue("pow".into()))
1749                    } else {
1750                        let result = e1.powf(e2);
1751                        if result.is_finite() {
1752                            Ok([result])
1753                        } else {
1754                            Err(ConstantEvaluatorError::Overflow("pow".into()))
1755                        }
1756                    }
1757                })
1758            }
1759
1760            // computational
1761            crate::MathFunction::Sign => {
1762                component_wise_signed!(self, span, [arg], |e| {
1763                    Ok([if e.is_zero() {
1764                        Zero::zero()
1765                    } else {
1766                        e.signum()
1767                    }])
1768                })
1769            }
1770            crate::MathFunction::Fma => {
1771                component_wise_float!(
1772                    self,
1773                    span,
1774                    [arg, arg1.unwrap(), arg2.unwrap()],
1775                    |e1, e2, e3| { Ok([e1.mul_add(e2, e3)]) }
1776                )
1777            }
1778            crate::MathFunction::Step => {
1779                component_wise_float(self, span, [arg, arg1.unwrap()], |x| match x {
1780                    Float::Abstract([edge, x]) => {
1781                        Ok(Float::Abstract([if edge <= x { 1.0 } else { 0.0 }]))
1782                    }
1783                    Float::F32([edge, x]) => Ok(Float::F32([if edge <= x { 1.0 } else { 0.0 }])),
1784                    Float::F16([edge, x]) => Ok(Float::F16([if edge <= x {
1785                        f16::one()
1786                    } else {
1787                        f16::zero()
1788                    }])),
1789                })
1790            }
1791            crate::MathFunction::Sqrt => {
1792                component_wise_float!(self, span, [arg], |e| {
1793                    if e >= Zero::zero() {
1794                        Ok([e.sqrt()])
1795                    } else {
1796                        Err(ConstantEvaluatorError::InvalidMathArgValue("sqrt".into()))
1797                    }
1798                })
1799            }
1800            crate::MathFunction::InverseSqrt => {
1801                component_wise_float(self, span, [arg], |e| match e {
1802                    Float::Abstract([e]) => Ok(Float::Abstract([1. / e.sqrt()])),
1803                    Float::F32([e]) => Ok(Float::F32([1. / e.sqrt()])),
1804                    Float::F16([e]) => Ok(Float::F16([f16::from_f32(1. / f32::from(e).sqrt())])),
1805                })
1806            }
1807
1808            // bits
1809            crate::MathFunction::CountTrailingZeros => {
1810                component_wise_concrete_int!(self, span, [arg], |e| {
1811                    #[allow(clippy::useless_conversion)]
1812                    Ok([e
1813                        .trailing_zeros()
1814                        .try_into()
1815                        .expect("bit count overflowed 32 bits, somehow!?")])
1816                })
1817            }
1818            crate::MathFunction::CountLeadingZeros => {
1819                component_wise_concrete_int!(self, span, [arg], |e| {
1820                    #[allow(clippy::useless_conversion)]
1821                    Ok([e
1822                        .leading_zeros()
1823                        .try_into()
1824                        .expect("bit count overflowed 32 bits, somehow!?")])
1825                })
1826            }
1827            crate::MathFunction::CountOneBits => {
1828                component_wise_concrete_int!(self, span, [arg], |e| {
1829                    #[allow(clippy::useless_conversion)]
1830                    Ok([e
1831                        .count_ones()
1832                        .try_into()
1833                        .expect("bit count overflowed 32 bits, somehow!?")])
1834                })
1835            }
1836            crate::MathFunction::ReverseBits => {
1837                component_wise_concrete_int!(self, span, [arg], |e| { Ok([e.reverse_bits()]) })
1838            }
1839            crate::MathFunction::ExtractBits => {
1840                // https://www.w3.org/TR/WGSL/#extractBits-signed-builtin
1841                let (offset, count) = self.bitfield_range(arg1.unwrap(), arg2.unwrap(), span)?;
1842                let e = self.extract_vec(arg, true)?;
1843
1844                let result = match_literal_vector!(match e => LiteralVector {
1845                    I16 => |e| { extract_bits(e, offset, count)? },
1846                    U16 => |e| { extract_bits(e, offset, count)? },
1847                    I32 => |e| { extract_bits(e, offset, count)? },
1848                    U32 => |e| { extract_bits(e, offset, count)? },
1849                    I64 => |e| { extract_bits(e, offset, count)? },
1850                    U64 => |e| { extract_bits(e, offset, count)? },
1851                })?;
1852                result.register_as_evaluated_expr(self, span)
1853            }
1854            crate::MathFunction::InsertBits => {
1855                // https://www.w3.org/TR/WGSL/#insertBits-builtin
1856                let (offset, count) = self.bitfield_range(arg2.unwrap(), arg3.unwrap(), span)?;
1857                let e = self.extract_vec(arg, true)?;
1858                let newbits = self.extract_vec(arg1.unwrap(), true)?;
1859                if e.len() != newbits.len() {
1860                    return Err(ConstantEvaluatorError::InvalidMathArg);
1861                }
1862
1863                let result = match_literal_vector!(match (e, newbits) => LiteralVector {
1864                    I16 => |e, n| { insert_bits(e, n, offset, count)? },
1865                    U16 => |e, n| { insert_bits(e, n, offset, count)? },
1866                    I32 => |e, n| { insert_bits(e, n, offset, count)? },
1867                    U32 => |e, n| { insert_bits(e, n, offset, count)? },
1868                    I64 => |e, n| { insert_bits(e, n, offset, count)? },
1869                    U64 => |e, n| { insert_bits(e, n, offset, count)? },
1870                })?;
1871                result.register_as_evaluated_expr(self, span)
1872            }
1873            crate::MathFunction::FirstTrailingBit => {
1874                component_wise_concrete_int(self, span, [arg], |ci| Ok(first_trailing_bit(ci)))
1875            }
1876            crate::MathFunction::FirstLeadingBit => {
1877                component_wise_concrete_int(self, span, [arg], |ci| Ok(first_leading_bit(ci)))
1878            }
1879
1880            // vector
1881            crate::MathFunction::Dot4I8Packed => {
1882                self.packed_dot_product(arg, arg1.unwrap(), span, true)
1883            }
1884            crate::MathFunction::Dot4U8Packed => {
1885                self.packed_dot_product(arg, arg1.unwrap(), span, false)
1886            }
1887            crate::MathFunction::Cross => self.cross_product(arg, arg1.unwrap(), span),
1888            crate::MathFunction::Dot => {
1889                // https://www.w3.org/TR/WGSL/#dot-builtin
1890                let e1 = self.extract_vec(arg, false)?;
1891                let e2 = self.extract_vec(arg1.unwrap(), false)?;
1892                if e1.len() != e2.len() {
1893                    return Err(ConstantEvaluatorError::InvalidMathArg);
1894                }
1895
1896                fn int_dot_checked<P>(a: &[P], b: &[P]) -> Result<P, ConstantEvaluatorError>
1897                where
1898                    P: num_traits::PrimInt + num_traits::CheckedAdd + num_traits::CheckedMul,
1899                {
1900                    a.iter()
1901                        .zip(b.iter())
1902                        .map(|(&aa, bb)| aa.checked_mul(bb))
1903                        .try_fold(P::zero(), |acc, x| {
1904                            if let Some(x) = x {
1905                                acc.checked_add(&x)
1906                            } else {
1907                                None
1908                            }
1909                        })
1910                        .ok_or(ConstantEvaluatorError::Overflow(
1911                            "in dot built-in".to_string(),
1912                        ))
1913                }
1914
1915                fn int_dot_wrapping<P>(a: &[P], b: &[P]) -> P
1916                where
1917                    P: num_traits::PrimInt + num_traits::WrappingAdd + num_traits::WrappingMul,
1918                {
1919                    a.iter()
1920                        .zip(b.iter())
1921                        .map(|(&aa, bb)| aa.wrapping_mul(bb))
1922                        .fold(P::zero(), |acc, x| acc.wrapping_add(&x))
1923                }
1924
1925                let result = match_literal_vector!(match (e1, e2) => Literal {
1926                    Float => |e1, e2| {
1927                        float_dot(e1, e2).ok_or_else(|| {
1928                            ConstantEvaluatorError::Overflow("in mathfunction::dot".into())
1929                        })?
1930                    },
1931                    AbstractInt => |e1, e2 | { int_dot_checked(e1, e2)? },
1932                    I32 => |e1, e2| { int_dot_wrapping(e1, e2) },
1933                    U32 => |e1, e2| { int_dot_wrapping(e1, e2) },
1934                })?;
1935                self.register_evaluated_expr(Expression::Literal(result), span)
1936            }
1937            crate::MathFunction::Length => {
1938                // https://www.w3.org/TR/WGSL/#length-builtin
1939                let e1 = self.extract_vec(arg, true)?;
1940
1941                let result = match_literal_vector!(match e1 => Literal {
1942                    Float => |e1| {
1943                        float_length(e1).ok_or_else(|| ConstantEvaluatorError::Overflow("length".into()))?
1944                    },
1945                })?;
1946                self.register_evaluated_expr(Expression::Literal(result), span)
1947            }
1948            crate::MathFunction::Distance => {
1949                // https://www.w3.org/TR/WGSL/#distance-builtin
1950                let e1 = self.extract_vec(arg, true)?;
1951                let e2 = self.extract_vec(arg1.unwrap(), true)?;
1952                if e1.len() != e2.len() {
1953                    return Err(ConstantEvaluatorError::InvalidMathArg);
1954                }
1955
1956                fn float_distance<F>(a: &[F], b: &[F]) -> F
1957                where
1958                    F: core::ops::Mul<F>,
1959                    F: num_traits::Float + iter::Sum + core::ops::Sub,
1960                {
1961                    if a.len() == 1 {
1962                        // Avoids possible overflow in squaring
1963                        (a[0] - b[0]).abs()
1964                    } else {
1965                        a.iter()
1966                            .zip(b.iter())
1967                            .map(|(&aa, &bb)| aa - bb)
1968                            .map(|ei| ei * ei)
1969                            .sum::<F>()
1970                            .sqrt()
1971                    }
1972                }
1973                let result = match_literal_vector!(match (e1, e2) => Literal {
1974                    Float => |e1, e2| { float_distance(e1, e2) },
1975                })?;
1976                self.register_evaluated_expr(Expression::Literal(result), span)
1977            }
1978            crate::MathFunction::Normalize => {
1979                // https://www.w3.org/TR/WGSL/#normalize-builtin
1980                let e1 = self.extract_vec(arg, true)?;
1981
1982                fn float_normalize<F>(
1983                    e: &[F],
1984                ) -> Result<ArrayVec<F, { crate::VectorSize::MAX }>, ConstantEvaluatorError>
1985                where
1986                    F: core::ops::Mul<F>,
1987                    F: num_traits::Float + iter::Sum,
1988                {
1989                    let len = match float_length(e) {
1990                        Some(len) if !len.is_zero() => Ok(len),
1991                        Some(_) => Err(ConstantEvaluatorError::InvalidMathArgValue(
1992                            "normalize".into(),
1993                        )),
1994                        None => Err(ConstantEvaluatorError::Overflow("normalize".into())),
1995                    }?;
1996
1997                    let mut out = ArrayVec::new();
1998                    for &ei in e {
1999                        out.push(ei / len);
2000                    }
2001                    Ok(out)
2002                }
2003
2004                let result = match_literal_vector!(match e1 => LiteralVector {
2005                    Float => |e1| { float_normalize(e1)? },
2006                })?;
2007                result.register_as_evaluated_expr(self, span)
2008            }
2009            crate::MathFunction::FaceForward => {
2010                // https://www.w3.org/TR/WGSL/#faceForward-builtin
2011                let e1 = self.extract_vec(arg, false)?;
2012                let e2 = self.extract_vec(arg1.unwrap(), false)?;
2013                let e3 = self.extract_vec(arg2.unwrap(), false)?;
2014                if e1.len() != e2.len() || e1.len() != e3.len() {
2015                    return Err(ConstantEvaluatorError::InvalidMathArg);
2016                }
2017
2018                let result = match_literal_vector!(match (e1, e2, e3) => LiteralVector {
2019                    Float => |e1, e2, e3| {
2020                        float_face_forward(e1, e2, e3).ok_or_else(|| {
2021                            ConstantEvaluatorError::Overflow("in mathfunction::faceforward".into())
2022                        })?
2023                    },
2024                })?;
2025                result.register_as_evaluated_expr(self, span)
2026            }
2027            crate::MathFunction::Reflect => {
2028                // https://www.w3.org/TR/WGSL/#reflect-builtin
2029                let e1 = self.extract_vec(arg, false)?;
2030                let e2 = self.extract_vec(arg1.unwrap(), false)?;
2031                if e1.len() != e2.len() {
2032                    return Err(ConstantEvaluatorError::InvalidMathArg);
2033                }
2034
2035                let result = match_literal_vector!(match (e1, e2) => LiteralVector {
2036                    Float => |e1, e2| {
2037                        float_reflect(e1, e2)
2038                            .ok_or_else(|| ConstantEvaluatorError::Overflow("in mathfunction::reflect".into()))?
2039                    },
2040                })?;
2041                result.register_as_evaluated_expr(self, span)
2042            }
2043            crate::MathFunction::Refract => {
2044                // https://www.w3.org/TR/WGSL/#refract-builtin
2045                let e1 = self.extract_vec(arg, false)?;
2046                let e2 = self.extract_vec(arg1.unwrap(), false)?;
2047                // `e3` is the scalar ratio of indices of refraction, extracted
2048                // as a LiteralVector like `e1` and `e2`.
2049                let e3 = self.extract_vec(arg2.unwrap(), true)?;
2050                if e1.len() != e2.len() || e3.len() != 1 {
2051                    return Err(ConstantEvaluatorError::InvalidMathArg);
2052                }
2053
2054                let result = match_literal_vector!(match (e1, e2, e3) => LiteralVector {
2055                    Float => |e1, e2, e3| {
2056                        float_refract(e1, e2, e3[0])
2057                            .ok_or_else(|| ConstantEvaluatorError::Overflow("in mathfunction::refract".into()))?
2058                    },
2059                })?;
2060                result.register_as_evaluated_expr(self, span)
2061            }
2062
2063            // unimplemented
2064            crate::MathFunction::Modf
2065            | crate::MathFunction::Frexp
2066            | crate::MathFunction::Ldexp
2067            | crate::MathFunction::Outer
2068            | crate::MathFunction::Mix
2069            | crate::MathFunction::SmoothStep
2070            | crate::MathFunction::Inverse
2071            | crate::MathFunction::Transpose
2072            | crate::MathFunction::Determinant
2073            | crate::MathFunction::QuantizeToF16
2074            | crate::MathFunction::Pack4x8snorm
2075            | crate::MathFunction::Pack4x8unorm
2076            | crate::MathFunction::Pack2x16snorm
2077            | crate::MathFunction::Pack2x16unorm
2078            | crate::MathFunction::Pack2x16float
2079            | crate::MathFunction::Pack4xI8
2080            | crate::MathFunction::Pack4xU8
2081            | crate::MathFunction::Pack4xI8Clamp
2082            | crate::MathFunction::Pack4xU8Clamp
2083            | crate::MathFunction::Unpack4x8snorm
2084            | crate::MathFunction::Unpack4x8unorm
2085            | crate::MathFunction::Unpack2x16snorm
2086            | crate::MathFunction::Unpack2x16unorm
2087            | crate::MathFunction::Unpack2x16float
2088            | crate::MathFunction::Unpack4xI8
2089            | crate::MathFunction::Unpack4xU8 => Err(ConstantEvaluatorError::NotImplemented(
2090                format!("{fun:?} built-in function"),
2091            )),
2092        }
2093    }
2094
2095    /// Dot product of two packed vectors (`dot4I8Packed` and `dot4U8Packed`)
2096    fn packed_dot_product(
2097        &mut self,
2098        a: Handle<Expression>,
2099        b: Handle<Expression>,
2100        span: Span,
2101        signed: bool,
2102    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2103        let Expression::Literal(Literal::U32(a)) = self.expressions[a] else {
2104            return Err(ConstantEvaluatorError::InvalidMathArg);
2105        };
2106        let Expression::Literal(Literal::U32(b)) = self.expressions[b] else {
2107            return Err(ConstantEvaluatorError::InvalidMathArg);
2108        };
2109
2110        let result = if signed {
2111            Literal::I32(
2112                (a & 0xFF) as i8 as i32 * (b & 0xFF) as i8 as i32
2113                    + ((a >> 8) & 0xFF) as i8 as i32 * ((b >> 8) & 0xFF) as i8 as i32
2114                    + ((a >> 16) & 0xFF) as i8 as i32 * ((b >> 16) & 0xFF) as i8 as i32
2115                    + ((a >> 24) & 0xFF) as i8 as i32 * ((b >> 24) & 0xFF) as i8 as i32,
2116            )
2117        } else {
2118            Literal::U32(
2119                (a & 0xFF) * (b & 0xFF)
2120                    + ((a >> 8) & 0xFF) * ((b >> 8) & 0xFF)
2121                    + ((a >> 16) & 0xFF) * ((b >> 16) & 0xFF)
2122                    + ((a >> 24) & 0xFF) * ((b >> 24) & 0xFF),
2123            )
2124        };
2125
2126        self.register_evaluated_expr(Expression::Literal(result), span)
2127    }
2128
2129    /// Vector cross product.
2130    fn cross_product(
2131        &mut self,
2132        a: Handle<Expression>,
2133        b: Handle<Expression>,
2134        span: Span,
2135    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2136        use Literal as Li;
2137
2138        let (a, ty) = self.extract_vec_with_size::<3>(a)?;
2139        let (b, _) = self.extract_vec_with_size::<3>(b)?;
2140
2141        let product = match (a, b) {
2142            (
2143                [Li::AbstractInt(a0), Li::AbstractInt(a1), Li::AbstractInt(a2)],
2144                [Li::AbstractInt(b0), Li::AbstractInt(b1), Li::AbstractInt(b2)],
2145            ) => {
2146                // `cross` has no overload for AbstractInt, so AbstractInt
2147                // arguments are automatically converted to AbstractFloat. Since
2148                // `f64` has a much wider range than `i64`, there's no danger of
2149                // overflow here.
2150                let p = cross_product(
2151                    [a0 as f64, a1 as f64, a2 as f64],
2152                    [b0 as f64, b1 as f64, b2 as f64],
2153                );
2154                [
2155                    Li::AbstractFloat(p[0]),
2156                    Li::AbstractFloat(p[1]),
2157                    Li::AbstractFloat(p[2]),
2158                ]
2159            }
2160            (
2161                [Li::AbstractFloat(a0), Li::AbstractFloat(a1), Li::AbstractFloat(a2)],
2162                [Li::AbstractFloat(b0), Li::AbstractFloat(b1), Li::AbstractFloat(b2)],
2163            ) => {
2164                let p = cross_product([a0, a1, a2], [b0, b1, b2]);
2165                [
2166                    Li::AbstractFloat(p[0]),
2167                    Li::AbstractFloat(p[1]),
2168                    Li::AbstractFloat(p[2]),
2169                ]
2170            }
2171            ([Li::F16(a0), Li::F16(a1), Li::F16(a2)], [Li::F16(b0), Li::F16(b1), Li::F16(b2)]) => {
2172                let p = cross_product([a0, a1, a2], [b0, b1, b2]);
2173                [Li::F16(p[0]), Li::F16(p[1]), Li::F16(p[2])]
2174            }
2175            ([Li::F32(a0), Li::F32(a1), Li::F32(a2)], [Li::F32(b0), Li::F32(b1), Li::F32(b2)]) => {
2176                let p = cross_product([a0, a1, a2], [b0, b1, b2]);
2177                [Li::F32(p[0]), Li::F32(p[1]), Li::F32(p[2])]
2178            }
2179            ([Li::F64(a0), Li::F64(a1), Li::F64(a2)], [Li::F64(b0), Li::F64(b1), Li::F64(b2)]) => {
2180                let p = cross_product([a0, a1, a2], [b0, b1, b2]);
2181                [Li::F64(p[0]), Li::F64(p[1]), Li::F64(p[2])]
2182            }
2183            _ => return Err(ConstantEvaluatorError::InvalidMathArg),
2184        };
2185
2186        let p0 = self.register_evaluated_expr(Expression::Literal(product[0]), span)?;
2187        let p1 = self.register_evaluated_expr(Expression::Literal(product[1]), span)?;
2188        let p2 = self.register_evaluated_expr(Expression::Literal(product[2]), span)?;
2189
2190        self.register_evaluated_expr(
2191            Expression::Compose {
2192                ty,
2193                components: vec![p0, p1, p2],
2194            },
2195            span,
2196        )
2197    }
2198
2199    /// Extract the values of a `vecN` from `expr`.
2200    ///
2201    /// Return the value of `expr`, whose type is `vecN<S>` for some
2202    /// vector size `N` and scalar `S`, as an array of `N` [`Literal`]
2203    /// values.
2204    ///
2205    /// Also return the type handle from the `Compose` expression.
2206    fn extract_vec_with_size<const N: usize>(
2207        &mut self,
2208        expr: Handle<Expression>,
2209    ) -> Result<([Literal; N], Handle<Type>), ConstantEvaluatorError> {
2210        let span = self.expressions.get_span(expr);
2211        let expr = self.eval_zero_value_and_splat(expr, span)?;
2212        let Expression::Compose { ty, ref components } = self.expressions[expr] else {
2213            return Err(ConstantEvaluatorError::InvalidMathArg);
2214        };
2215
2216        let mut value = [Literal::Bool(false); N];
2217        for (component, elt) in
2218            crate::proc::flatten_compose(ty, components, self.expressions, self.types)
2219                .zip(value.iter_mut())
2220        {
2221            let Expression::Literal(literal) = self.expressions[component] else {
2222                return Err(ConstantEvaluatorError::InvalidMathArg);
2223            };
2224            *elt = literal;
2225        }
2226
2227        Ok((value, ty))
2228    }
2229
2230    /// Extract the values of a `vecN` from `expr`.
2231    ///
2232    /// Return the value of `expr`, whose type is `vecN<S>` for some
2233    /// vector size `N` and scalar `S`, as an array of `N` [`Literal`]
2234    /// values.
2235    ///
2236    /// Also return the type handle from the `Compose` expression.
2237    fn extract_vec(
2238        &mut self,
2239        expr: Handle<Expression>,
2240        allow_single: bool,
2241    ) -> Result<LiteralVector, ConstantEvaluatorError> {
2242        let span = self.expressions.get_span(expr);
2243        let expr = self.eval_zero_value_and_splat(expr, span)?;
2244
2245        match self.expressions[expr] {
2246            Expression::Literal(literal) if allow_single => {
2247                Ok(LiteralVector::from_literal(literal))
2248            }
2249            Expression::Compose { ty, ref components } => {
2250                let mut components_out = ArrayVec::<Literal, { crate::VectorSize::MAX }>::new();
2251                for expr in
2252                    crate::proc::flatten_compose(ty, components, self.expressions, self.types)
2253                {
2254                    match self.expressions[expr] {
2255                        Expression::Literal(l) => components_out.push(l),
2256                        _ => return Err(ConstantEvaluatorError::InvalidMathArg),
2257                    }
2258                }
2259                LiteralVector::from_literal_vec(components_out)
2260            }
2261            _ => Err(ConstantEvaluatorError::InvalidMathArg),
2262        }
2263    }
2264
2265    /// Extract the `offset` and `count` arguments shared by the `extractBits`
2266    /// and `insertBits` built ins, both of which are `u32` scalars.
2267    fn bitfield_range(
2268        &mut self,
2269        offset: Handle<Expression>,
2270        count: Handle<Expression>,
2271        span: Span,
2272    ) -> Result<(u32, u32), ConstantEvaluatorError> {
2273        let offset = self.eval_zero_value_and_splat(offset, span)?;
2274        let count = self.eval_zero_value_and_splat(count, span)?;
2275
2276        match (&self.expressions[offset], &self.expressions[count]) {
2277            (
2278                &Expression::Literal(Literal::U32(offset)),
2279                &Expression::Literal(Literal::U32(count)),
2280            ) => Ok((offset, count)),
2281            _ => Err(ConstantEvaluatorError::InvalidMathArg),
2282        }
2283    }
2284
2285    fn array_length(
2286        &mut self,
2287        array: Handle<Expression>,
2288        span: Span,
2289    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2290        match self.expressions[array] {
2291            Expression::ZeroValue(ty) | Expression::Compose { ty, .. } => {
2292                match self.types[ty].inner {
2293                    TypeInner::Array { size, .. } => match size {
2294                        ArraySize::Constant(len) => {
2295                            let expr = Expression::Literal(Literal::U32(len.get()));
2296                            self.register_evaluated_expr(expr, span)
2297                        }
2298                        ArraySize::Pending(_) => Err(ConstantEvaluatorError::ArrayLengthOverridden),
2299                        ArraySize::Dynamic => Err(ConstantEvaluatorError::ArrayLengthDynamic),
2300                    },
2301                    _ => Err(ConstantEvaluatorError::InvalidArrayLengthArg),
2302                }
2303            }
2304            _ => Err(ConstantEvaluatorError::InvalidArrayLengthArg),
2305        }
2306    }
2307
2308    fn access(
2309        &mut self,
2310        base: Handle<Expression>,
2311        index: usize,
2312        span: Span,
2313    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2314        match self.expressions[base] {
2315            Expression::ZeroValue(ty) => {
2316                let ty_inner = &self.types[ty].inner;
2317                let components = ty_inner
2318                    .components()
2319                    .ok_or(ConstantEvaluatorError::InvalidAccessBase)?;
2320
2321                if index >= components as usize {
2322                    Err(ConstantEvaluatorError::InvalidAccessBase)
2323                } else {
2324                    let ty_res = ty_inner
2325                        .component_type(index)
2326                        .ok_or(ConstantEvaluatorError::InvalidAccessIndex)?;
2327                    let ty = match ty_res {
2328                        crate::proc::TypeResolution::Handle(ty) => ty,
2329                        crate::proc::TypeResolution::Value(inner) => {
2330                            self.types.insert(Type { name: None, inner }, span)
2331                        }
2332                    };
2333                    self.register_evaluated_expr(Expression::ZeroValue(ty), span)
2334                }
2335            }
2336            Expression::Splat { size, value } => {
2337                if index >= size as usize {
2338                    Err(ConstantEvaluatorError::InvalidAccessBase)
2339                } else {
2340                    Ok(value)
2341                }
2342            }
2343            Expression::Compose { ty, ref components } => {
2344                let _ = self.types[ty]
2345                    .inner
2346                    .components()
2347                    .ok_or(ConstantEvaluatorError::InvalidAccessBase)?;
2348
2349                crate::proc::flatten_compose(ty, components, self.expressions, self.types)
2350                    .nth(index)
2351                    .ok_or(ConstantEvaluatorError::InvalidAccessIndex)
2352            }
2353            _ => Err(ConstantEvaluatorError::InvalidAccessBase),
2354        }
2355    }
2356
2357    /// Lower [`ZeroValue`] and [`Splat`] expressions to [`Literal`] and [`Compose`] expressions.
2358    ///
2359    /// [`ZeroValue`]: Expression::ZeroValue
2360    /// [`Splat`]: Expression::Splat
2361    /// [`Literal`]: Expression::Literal
2362    /// [`Compose`]: Expression::Compose
2363    fn eval_zero_value_and_splat(
2364        &mut self,
2365        mut expr: Handle<Expression>,
2366        span: Span,
2367    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2368        // If expr is a Compose expression, eliminate ZeroValue and Splat expressions for
2369        // each of its components.
2370        if let Expression::Compose { ty, ref components } = self.expressions[expr] {
2371            let components = components
2372                .clone()
2373                .iter()
2374                .map(|component| self.eval_zero_value_and_splat(*component, span))
2375                .collect::<Result<_, _>>()?;
2376            expr = self.register_evaluated_expr(Expression::Compose { ty, components }, span)?;
2377        }
2378
2379        // The result of the splat() for a Splat of a scalar ZeroValue is a
2380        // vector ZeroValue, so we must call eval_zero_value_impl() after
2381        // splat() in order to ensure we have no ZeroValues remaining.
2382        if let Expression::Splat { size, value } = self.expressions[expr] {
2383            expr = self.splat(value, size, span)?;
2384        }
2385        if let Expression::ZeroValue(ty) = self.expressions[expr] {
2386            expr = self.eval_zero_value_impl(ty, span)?;
2387        }
2388        Ok(expr)
2389    }
2390
2391    /// Lower [`ZeroValue`] expressions to [`Literal`] and [`Compose`] expressions.
2392    ///
2393    /// [`ZeroValue`]: Expression::ZeroValue
2394    /// [`Literal`]: Expression::Literal
2395    /// [`Compose`]: Expression::Compose
2396    fn eval_zero_value(
2397        &mut self,
2398        expr: Handle<Expression>,
2399        span: Span,
2400    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2401        match self.expressions[expr] {
2402            Expression::ZeroValue(ty) => self.eval_zero_value_impl(ty, span),
2403            _ => Ok(expr),
2404        }
2405    }
2406
2407    /// Lower [`ZeroValue`] expressions to [`Literal`] and [`Compose`] expressions.
2408    ///
2409    /// [`ZeroValue`]: Expression::ZeroValue
2410    /// [`Literal`]: Expression::Literal
2411    /// [`Compose`]: Expression::Compose
2412    fn eval_zero_value_impl(
2413        &mut self,
2414        ty: Handle<Type>,
2415        span: Span,
2416    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2417        match self.types[ty].inner {
2418            TypeInner::Scalar(scalar) => {
2419                let expr = Expression::Literal(
2420                    Literal::zero(scalar).ok_or(ConstantEvaluatorError::TypeNotConstructible)?,
2421                );
2422                self.register_evaluated_expr(expr, span)
2423            }
2424            TypeInner::Vector { size, scalar } => {
2425                let scalar_ty = self.types.insert(
2426                    Type {
2427                        name: None,
2428                        inner: TypeInner::Scalar(scalar),
2429                    },
2430                    span,
2431                );
2432                let el = self.eval_zero_value_impl(scalar_ty, span)?;
2433                let expr = Expression::Compose {
2434                    ty,
2435                    components: vec![el; size as usize],
2436                };
2437                self.register_evaluated_expr(expr, span)
2438            }
2439            TypeInner::Matrix {
2440                columns,
2441                rows,
2442                scalar,
2443            } => {
2444                let vec_ty = self.types.insert(
2445                    Type {
2446                        name: None,
2447                        inner: TypeInner::Vector { size: rows, scalar },
2448                    },
2449                    span,
2450                );
2451                let el = self.eval_zero_value_impl(vec_ty, span)?;
2452                let expr = Expression::Compose {
2453                    ty,
2454                    components: vec![el; columns as usize],
2455                };
2456                self.register_evaluated_expr(expr, span)
2457            }
2458            TypeInner::Array {
2459                base,
2460                size: ArraySize::Constant(size),
2461                ..
2462            } => {
2463                let el = self.eval_zero_value_impl(base, span)?;
2464                let expr = Expression::Compose {
2465                    ty,
2466                    components: vec![el; size.get() as usize],
2467                };
2468                self.register_evaluated_expr(expr, span)
2469            }
2470            TypeInner::Struct { ref members, .. } => {
2471                let types: Vec<_> = members.iter().map(|m| m.ty).collect();
2472                let mut components = Vec::with_capacity(members.len());
2473                for ty in types {
2474                    components.push(self.eval_zero_value_impl(ty, span)?);
2475                }
2476                let expr = Expression::Compose { ty, components };
2477                self.register_evaluated_expr(expr, span)
2478            }
2479            _ => Err(ConstantEvaluatorError::TypeNotConstructible),
2480        }
2481    }
2482
2483    /// Convert the scalar components of `expr` to `target`.
2484    ///
2485    /// Treat `span` as the location of the resulting expression.
2486    pub fn cast(
2487        &mut self,
2488        expr: Handle<Expression>,
2489        target: crate::Scalar,
2490        span: Span,
2491    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2492        use crate::Scalar as Sc;
2493
2494        let expr = self.eval_zero_value(expr, span)?;
2495
2496        let make_error = || -> Result<_, ConstantEvaluatorError> {
2497            let from = format!("{:?} {:?}", expr, self.expressions[expr]);
2498
2499            #[cfg(feature = "wgsl-in")]
2500            let to = target.to_wgsl_for_diagnostics();
2501
2502            #[cfg(not(feature = "wgsl-in"))]
2503            let to = format!("{target:?}");
2504
2505            Err(ConstantEvaluatorError::InvalidCastArg { from, to })
2506        };
2507
2508        use crate::proc::type_methods::IntFloatLimits;
2509
2510        let expr = match self.expressions[expr] {
2511            Expression::Literal(literal) => {
2512                let literal = match target {
2513                    Sc::I16 => Literal::I16(match literal {
2514                        Literal::I16(v) => v,
2515                        Literal::U16(v) => v as i16,
2516                        Literal::I32(v) => v as i16,
2517                        Literal::U32(v) => v as i16,
2518                        Literal::F32(v) => v.clamp(i16::MIN as f32, i16::MAX as f32) as i16,
2519                        Literal::F16(v) => {
2520                            f16::to_f32(v).clamp(i16::MIN as f32, i16::MAX as f32) as i16
2521                        }
2522                        Literal::Bool(v) => v as i16,
2523                        Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2524                            return make_error();
2525                        }
2526                        Literal::AbstractInt(v) => v as i16,
2527                        Literal::AbstractFloat(v) => v as i16,
2528                    }),
2529                    Sc::U16 => Literal::U16(match literal {
2530                        Literal::I16(v) => v as u16,
2531                        Literal::U16(v) => v,
2532                        Literal::I32(v) => v as u16,
2533                        Literal::U32(v) => v as u16,
2534                        Literal::F32(v) => v.clamp(u16::MIN as f32, u16::MAX as f32) as u16,
2535                        Literal::F16(v) => f16::to_u16(&v.max(f16::ZERO)).unwrap(),
2536                        Literal::Bool(v) => v as u16,
2537                        Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2538                            return make_error();
2539                        }
2540                        Literal::AbstractInt(v) => v as u16,
2541                        Literal::AbstractFloat(v) => v as u16,
2542                    }),
2543                    Sc::I32 => Literal::I32(match literal {
2544                        Literal::I16(v) => v as i32,
2545                        Literal::U16(v) => v as i32,
2546                        Literal::I32(v) => v,
2547                        Literal::U32(v) => v as i32,
2548                        Literal::F32(v) => v.clamp(i32::min_float(), i32::max_float()) as i32,
2549                        Literal::F16(v) => f16::to_i32(&v).unwrap(), //Only None on NaN or Inf
2550                        Literal::Bool(v) => v as i32,
2551                        Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2552                            return make_error();
2553                        }
2554                        Literal::AbstractInt(v) => i32::try_from_abstract(v)?,
2555                        Literal::AbstractFloat(v) => i32::try_from_abstract(v)?,
2556                    }),
2557                    Sc::U32 => Literal::U32(match literal {
2558                        Literal::I16(v) => v as u32,
2559                        Literal::U16(v) => v as u32,
2560                        Literal::I32(v) => v as u32,
2561                        Literal::U32(v) => v,
2562                        Literal::F32(v) => v.clamp(u32::min_float(), u32::max_float()) as u32,
2563                        // max(0) avoids None due to negative, therefore only None on NaN or Inf
2564                        Literal::F16(v) => f16::to_u32(&v.max(f16::ZERO)).unwrap(),
2565                        Literal::Bool(v) => v as u32,
2566                        Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2567                            return make_error();
2568                        }
2569                        Literal::AbstractInt(v) => u32::try_from_abstract(v)?,
2570                        Literal::AbstractFloat(v) => u32::try_from_abstract(v)?,
2571                    }),
2572                    Sc::I64 => Literal::I64(match literal {
2573                        Literal::I16(v) => v as i64,
2574                        Literal::U16(v) => v as i64,
2575                        Literal::I32(v) => v as i64,
2576                        Literal::U32(v) => v as i64,
2577                        Literal::F32(v) => v.clamp(i64::min_float(), i64::max_float()) as i64,
2578                        Literal::Bool(v) => v as i64,
2579                        Literal::F64(v) => v.clamp(i64::min_float(), i64::max_float()) as i64,
2580                        Literal::I64(v) => v,
2581                        Literal::U64(v) => v as i64,
2582                        Literal::F16(v) => f16::to_i64(&v).unwrap(), //Only None on NaN or Inf
2583                        Literal::AbstractInt(v) => i64::try_from_abstract(v)?,
2584                        Literal::AbstractFloat(v) => i64::try_from_abstract(v)?,
2585                    }),
2586                    Sc::U64 => Literal::U64(match literal {
2587                        Literal::I16(v) => v as u64,
2588                        Literal::U16(v) => v as u64,
2589                        Literal::I32(v) => v as u64,
2590                        Literal::U32(v) => v as u64,
2591                        Literal::F32(v) => v.clamp(u64::min_float(), u64::max_float()) as u64,
2592                        Literal::Bool(v) => v as u64,
2593                        Literal::F64(v) => v.clamp(u64::min_float(), u64::max_float()) as u64,
2594                        Literal::I64(v) => v as u64,
2595                        Literal::U64(v) => v,
2596                        // max(0) avoids None due to negative, therefore only None on NaN or Inf
2597                        Literal::F16(v) => f16::to_u64(&v.max(f16::ZERO)).unwrap(),
2598                        Literal::AbstractInt(v) => u64::try_from_abstract(v)?,
2599                        Literal::AbstractFloat(v) => u64::try_from_abstract(v)?,
2600                    }),
2601                    Sc::F16 => Literal::F16(match literal {
2602                        Literal::F16(v) => v,
2603                        Literal::F32(v) => f16::from_f32(v),
2604                        Literal::F64(v) => f16::from_f64(v),
2605                        Literal::Bool(v) => f16::from_u32(v as u32).unwrap(),
2606                        Literal::I16(v) => f16::from_f32(v as f32),
2607                        Literal::U16(v) => f16::from_f32(v as f32),
2608                        Literal::I64(v) => f16::from_i64(v).unwrap(),
2609                        Literal::U64(v) => f16::from_u64(v).unwrap(),
2610                        Literal::I32(v) => f16::from_i32(v).unwrap(),
2611                        Literal::U32(v) => f16::from_u32(v).unwrap(),
2612                        Literal::AbstractFloat(v) => f16::try_from_abstract(v)?,
2613                        Literal::AbstractInt(v) => f16::try_from_abstract(v)?,
2614                    }),
2615                    Sc::F32 => Literal::F32(match literal {
2616                        Literal::I16(v) => v as f32,
2617                        Literal::U16(v) => v as f32,
2618                        Literal::I32(v) => v as f32,
2619                        Literal::U32(v) => v as f32,
2620                        Literal::F32(v) => v,
2621                        Literal::Bool(v) => v as u32 as f32,
2622                        Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2623                            return make_error();
2624                        }
2625                        Literal::F16(v) => f16::to_f32(v),
2626                        Literal::AbstractInt(v) => f32::try_from_abstract(v)?,
2627                        Literal::AbstractFloat(v) => f32::try_from_abstract(v)?,
2628                    }),
2629                    Sc::F64 => Literal::F64(match literal {
2630                        Literal::I16(v) => v as f64,
2631                        Literal::U16(v) => v as f64,
2632                        Literal::I32(v) => v as f64,
2633                        Literal::U32(v) => v as f64,
2634                        Literal::F16(v) => f16::to_f64(v),
2635                        Literal::F32(v) => v as f64,
2636                        Literal::F64(v) => v,
2637                        Literal::Bool(v) => v as u32 as f64,
2638                        Literal::I64(_) | Literal::U64(_) => return make_error(),
2639                        Literal::AbstractInt(v) => f64::try_from_abstract(v)?,
2640                        Literal::AbstractFloat(v) => f64::try_from_abstract(v)?,
2641                    }),
2642                    Sc::BOOL => Literal::Bool(match literal {
2643                        Literal::I16(v) => v != 0,
2644                        Literal::U16(v) => v != 0,
2645                        Literal::I32(v) => v != 0,
2646                        Literal::U32(v) => v != 0,
2647                        Literal::F32(v) => v != 0.0,
2648                        Literal::F16(v) => v != f16::zero(),
2649                        Literal::Bool(v) => v,
2650                        Literal::AbstractInt(v) => v != 0,
2651                        Literal::AbstractFloat(v) => v != 0.0,
2652                        Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2653                            return make_error();
2654                        }
2655                    }),
2656                    Sc::ABSTRACT_FLOAT => Literal::AbstractFloat(match literal {
2657                        Literal::AbstractInt(v) => {
2658                            // Overflow is forbidden, but inexact conversions
2659                            // are fine. The range of f64 is far larger than
2660                            // that of i64, so we don't have to check anything
2661                            // here.
2662                            v as f64
2663                        }
2664                        Literal::AbstractFloat(v) => v,
2665                        _ => return make_error(),
2666                    }),
2667                    Sc::ABSTRACT_INT => Literal::AbstractInt(match literal {
2668                        Literal::AbstractInt(v) => v,
2669                        _ => return make_error(),
2670                    }),
2671                    _ => {
2672                        log::debug!("Constant evaluator refused to convert value to {target:?}");
2673                        return make_error();
2674                    }
2675                };
2676                Expression::Literal(literal)
2677            }
2678            Expression::Compose {
2679                ty,
2680                components: ref src_components,
2681            } => {
2682                let ty_inner = match self.types[ty].inner {
2683                    TypeInner::Vector { size, .. } => TypeInner::Vector {
2684                        size,
2685                        scalar: target,
2686                    },
2687                    TypeInner::Matrix { columns, rows, .. } => TypeInner::Matrix {
2688                        columns,
2689                        rows,
2690                        scalar: target,
2691                    },
2692                    _ => return make_error(),
2693                };
2694
2695                let mut components = src_components.clone();
2696                for component in &mut components {
2697                    *component = self.cast(*component, target, span)?;
2698                }
2699
2700                let ty = self.types.insert(
2701                    Type {
2702                        name: None,
2703                        inner: ty_inner,
2704                    },
2705                    span,
2706                );
2707
2708                Expression::Compose { ty, components }
2709            }
2710            Expression::Splat { size, value } => {
2711                let value_span = self.expressions.get_span(value);
2712                let cast_value = self.cast(value, target, value_span)?;
2713                Expression::Splat {
2714                    size,
2715                    value: cast_value,
2716                }
2717            }
2718            _ => return make_error(),
2719        };
2720
2721        self.register_evaluated_expr(expr, span)
2722    }
2723
2724    /// Convert the scalar leaves of  `expr` to `target`, handling arrays.
2725    ///
2726    /// `expr` must be a `Compose` expression whose type is a scalar, vector,
2727    /// matrix, or nested arrays of such.
2728    ///
2729    /// This is basically the same as the [`cast`] method, except that that
2730    /// should only handle Naga [`As`] expressions, which cannot convert arrays.
2731    ///
2732    /// Treat `span` as the location of the resulting expression.
2733    ///
2734    /// [`cast`]: ConstantEvaluator::cast
2735    /// [`As`]: crate::Expression::As
2736    pub fn cast_array(
2737        &mut self,
2738        expr: Handle<Expression>,
2739        target: crate::Scalar,
2740        span: Span,
2741    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2742        let expr = self.check_and_get(expr)?;
2743
2744        let Expression::Compose { ty, ref components } = self.expressions[expr] else {
2745            return self.cast(expr, target, span);
2746        };
2747
2748        let TypeInner::Array {
2749            base: _,
2750            size,
2751            stride: _,
2752        } = self.types[ty].inner
2753        else {
2754            return self.cast(expr, target, span);
2755        };
2756
2757        let mut components = components.clone();
2758        for component in &mut components {
2759            *component = self.cast_array(*component, target, span)?;
2760        }
2761
2762        let first = components.first().unwrap();
2763        let new_base = match self.resolve_type(*first)? {
2764            crate::proc::TypeResolution::Handle(ty) => ty,
2765            crate::proc::TypeResolution::Value(inner) => {
2766                self.types.insert(Type { name: None, inner }, span)
2767            }
2768        };
2769        let mut layouter = core::mem::take(self.layouter);
2770        layouter.update(self.to_ctx()).map_err(|err| {
2771            // The layouter operates lazily, so the error
2772            // could be for any pending type.
2773            let crate::proc::LayoutErrorInner::TooLarge = err.inner else {
2774                unreachable!("unexpected layout error: {err:?}");
2775            };
2776            ConstantEvaluatorError::TypeTooLarge(err.ty)
2777        })?;
2778        *self.layouter = layouter;
2779
2780        let new_base_stride = self.layouter[new_base].to_stride();
2781        let new_array_ty = self.types.insert(
2782            Type {
2783                name: None,
2784                inner: TypeInner::Array {
2785                    base: new_base,
2786                    size,
2787                    stride: new_base_stride,
2788                },
2789            },
2790            span,
2791        );
2792
2793        let compose = Expression::Compose {
2794            ty: new_array_ty,
2795            components,
2796        };
2797        self.register_evaluated_expr(compose, span)
2798    }
2799
2800    fn unary_op(
2801        &mut self,
2802        op: UnaryOperator,
2803        expr: Handle<Expression>,
2804        span: Span,
2805    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2806        let expr = self.eval_zero_value_and_splat(expr, span)?;
2807
2808        let expr = match self.expressions[expr] {
2809            Expression::Literal(value) => Expression::Literal(match op {
2810                UnaryOperator::Negate => match value {
2811                    Literal::I16(v) => Literal::I16(v.wrapping_neg()),
2812                    Literal::I32(v) => Literal::I32(v.wrapping_neg()),
2813                    Literal::I64(v) => Literal::I64(v.wrapping_neg()),
2814                    Literal::F32(v) => Literal::F32(-v),
2815                    Literal::F16(v) => Literal::F16(-v),
2816                    Literal::F64(v) => Literal::F64(-v),
2817                    Literal::AbstractInt(v) => Literal::AbstractInt(v.wrapping_neg()),
2818                    Literal::AbstractFloat(v) => Literal::AbstractFloat(-v),
2819                    _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2820                },
2821                UnaryOperator::LogicalNot => match value {
2822                    Literal::Bool(v) => Literal::Bool(!v),
2823                    _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2824                },
2825                UnaryOperator::BitwiseNot => match value {
2826                    Literal::I16(v) => Literal::I16(!v),
2827                    Literal::I32(v) => Literal::I32(!v),
2828                    Literal::I64(v) => Literal::I64(!v),
2829                    Literal::U16(v) => Literal::U16(!v),
2830                    Literal::U32(v) => Literal::U32(!v),
2831                    Literal::U64(v) => Literal::U64(!v),
2832                    Literal::AbstractInt(v) => Literal::AbstractInt(!v),
2833                    _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2834                },
2835            }),
2836            Expression::Compose {
2837                ty,
2838                components: ref src_components,
2839            } => {
2840                match self.types[ty].inner {
2841                    TypeInner::Vector { .. } => (),
2842                    _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2843                }
2844
2845                let mut components = src_components.clone();
2846                for component in &mut components {
2847                    *component = self.unary_op(op, *component, span)?;
2848                }
2849
2850                Expression::Compose { ty, components }
2851            }
2852            _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2853        };
2854
2855        self.register_evaluated_expr(expr, span)
2856    }
2857
2858    fn binary_op(
2859        &mut self,
2860        op: BinaryOperator,
2861        left: Handle<Expression>,
2862        right: Handle<Expression>,
2863        span: Span,
2864    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2865        let left = self.eval_zero_value_and_splat(left, span)?;
2866        let right = self.eval_zero_value_and_splat(right, span)?;
2867
2868        // Note: in most cases constant evaluation checks for overflow, but for
2869        // i32/u32, it uses wrapping arithmetic. See
2870        // <https://gpuweb.github.io/gpuweb/wgsl/#integer-types>.
2871
2872        let expr = match (&self.expressions[left], &self.expressions[right]) {
2873            (&Expression::Literal(left_value), &Expression::Literal(right_value)) => {
2874                if !matches!(op, BinaryOperator::ShiftLeft | BinaryOperator::ShiftRight)
2875                    && core::mem::discriminant(&left_value) != core::mem::discriminant(&right_value)
2876                {
2877                    return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
2878                }
2879
2880                if matches!(
2881                    (left_value, op),
2882                    (
2883                        Literal::Bool(_),
2884                        BinaryOperator::Less
2885                            | BinaryOperator::LessEqual
2886                            | BinaryOperator::Greater
2887                            | BinaryOperator::GreaterEqual
2888                    )
2889                ) {
2890                    return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
2891                }
2892
2893                let literal = match op {
2894                    BinaryOperator::Equal => Literal::Bool(left_value == right_value),
2895                    BinaryOperator::NotEqual => Literal::Bool(left_value != right_value),
2896                    BinaryOperator::Less => Literal::Bool(left_value < right_value),
2897                    BinaryOperator::LessEqual => Literal::Bool(left_value <= right_value),
2898                    BinaryOperator::Greater => Literal::Bool(left_value > right_value),
2899                    BinaryOperator::GreaterEqual => Literal::Bool(left_value >= right_value),
2900
2901                    _ => match (left_value, right_value) {
2902                        (Literal::I16(a), Literal::I16(b)) => Literal::I16(match op {
2903                            BinaryOperator::Add => a.wrapping_add(b),
2904                            BinaryOperator::Subtract => a.wrapping_sub(b),
2905                            BinaryOperator::Multiply => a.wrapping_mul(b),
2906                            BinaryOperator::Divide => a.checked_div(b).ok_or_else(|| {
2907                                if b == 0 {
2908                                    ConstantEvaluatorError::DivisionByZero
2909                                } else {
2910                                    ConstantEvaluatorError::Overflow("division".into())
2911                                }
2912                            })?,
2913                            BinaryOperator::Modulo => a.checked_rem(b).ok_or_else(|| {
2914                                if b == 0 {
2915                                    ConstantEvaluatorError::RemainderByZero
2916                                } else {
2917                                    ConstantEvaluatorError::Overflow("remainder".into())
2918                                }
2919                            })?,
2920                            BinaryOperator::And => a & b,
2921                            BinaryOperator::ExclusiveOr => a ^ b,
2922                            BinaryOperator::InclusiveOr => a | b,
2923                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2924                        }),
2925                        (Literal::I16(a), Literal::U32(b)) => Literal::I16(match op {
2926                            BinaryOperator::ShiftLeft => {
2927                                if (if a.is_negative() { !a } else { a }).leading_zeros() <= b {
2928                                    return Err(ConstantEvaluatorError::Overflow("<<".to_string()));
2929                                }
2930                                a.checked_shl(b)
2931                                    .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?
2932                            }
2933                            BinaryOperator::ShiftRight => a
2934                                .checked_shr(b)
2935                                .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
2936                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2937                        }),
2938                        (Literal::U16(a), Literal::U16(b)) => Literal::U16(match op {
2939                            BinaryOperator::Add => a.wrapping_add(b),
2940                            BinaryOperator::Subtract => a.wrapping_sub(b),
2941                            BinaryOperator::Multiply => a.wrapping_mul(b),
2942                            BinaryOperator::Divide => a
2943                                .checked_div(b)
2944                                .ok_or(ConstantEvaluatorError::DivisionByZero)?,
2945                            BinaryOperator::Modulo => a
2946                                .checked_rem(b)
2947                                .ok_or(ConstantEvaluatorError::RemainderByZero)?,
2948                            BinaryOperator::And => a & b,
2949                            BinaryOperator::ExclusiveOr => a ^ b,
2950                            BinaryOperator::InclusiveOr => a | b,
2951                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2952                        }),
2953                        (Literal::U16(a), Literal::U32(b)) => Literal::U16(match op {
2954                            BinaryOperator::ShiftLeft => a
2955                                .checked_mul(
2956                                    1u16.checked_shl(b)
2957                                        .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
2958                                )
2959                                .ok_or(ConstantEvaluatorError::Overflow("<<".to_string()))?,
2960                            BinaryOperator::ShiftRight => a
2961                                .checked_shr(b)
2962                                .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
2963                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2964                        }),
2965                        (Literal::I32(a), Literal::I32(b)) => Literal::I32(match op {
2966                            BinaryOperator::Add => a.wrapping_add(b),
2967                            BinaryOperator::Subtract => a.wrapping_sub(b),
2968                            BinaryOperator::Multiply => a.wrapping_mul(b),
2969                            BinaryOperator::Divide => a.checked_div(b).ok_or_else(|| {
2970                                if b == 0 {
2971                                    ConstantEvaluatorError::DivisionByZero
2972                                } else {
2973                                    ConstantEvaluatorError::Overflow("division".into())
2974                                }
2975                            })?,
2976                            BinaryOperator::Modulo => a.checked_rem(b).ok_or_else(|| {
2977                                if b == 0 {
2978                                    ConstantEvaluatorError::RemainderByZero
2979                                } else {
2980                                    ConstantEvaluatorError::Overflow("remainder".into())
2981                                }
2982                            })?,
2983                            BinaryOperator::And => a & b,
2984                            BinaryOperator::ExclusiveOr => a ^ b,
2985                            BinaryOperator::InclusiveOr => a | b,
2986                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2987                        }),
2988                        (Literal::I32(a), Literal::U32(b)) => Literal::I32(match op {
2989                            BinaryOperator::ShiftLeft => {
2990                                if (if a.is_negative() { !a } else { a }).leading_zeros() <= b {
2991                                    return Err(ConstantEvaluatorError::Overflow("<<".to_string()));
2992                                }
2993                                a.checked_shl(b)
2994                                    .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?
2995                            }
2996                            BinaryOperator::ShiftRight => a
2997                                .checked_shr(b)
2998                                .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
2999                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3000                        }),
3001                        (Literal::U32(a), Literal::U32(b)) => Literal::U32(match op {
3002                            BinaryOperator::Add => a.wrapping_add(b),
3003                            BinaryOperator::Subtract => a.wrapping_sub(b),
3004                            BinaryOperator::Multiply => a.wrapping_mul(b),
3005                            BinaryOperator::Divide => a
3006                                .checked_div(b)
3007                                .ok_or(ConstantEvaluatorError::DivisionByZero)?,
3008                            BinaryOperator::Modulo => a
3009                                .checked_rem(b)
3010                                .ok_or(ConstantEvaluatorError::RemainderByZero)?,
3011                            BinaryOperator::And => a & b,
3012                            BinaryOperator::ExclusiveOr => a ^ b,
3013                            BinaryOperator::InclusiveOr => a | b,
3014                            BinaryOperator::ShiftLeft => a
3015                                .checked_mul(
3016                                    1u32.checked_shl(b)
3017                                        .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
3018                                )
3019                                .ok_or(ConstantEvaluatorError::Overflow("<<".to_string()))?,
3020                            BinaryOperator::ShiftRight => a
3021                                .checked_shr(b)
3022                                .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
3023                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3024                        }),
3025                        (Literal::F32(a), Literal::F32(b)) => Literal::F32(match op {
3026                            BinaryOperator::Add => a + b,
3027                            BinaryOperator::Subtract => a - b,
3028                            BinaryOperator::Multiply => a * b,
3029                            BinaryOperator::Divide => a / b,
3030                            BinaryOperator::Modulo => a % b,
3031                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3032                        }),
3033                        (Literal::AbstractInt(a), Literal::U32(b)) => {
3034                            Literal::AbstractInt(match op {
3035                                BinaryOperator::ShiftLeft => {
3036                                    if (if a.is_negative() { !a } else { a }).leading_zeros() <= b {
3037                                        return Err(ConstantEvaluatorError::Overflow(
3038                                            "<<".to_string(),
3039                                        ));
3040                                    }
3041                                    a.checked_shl(b).unwrap_or(0)
3042                                }
3043                                BinaryOperator::ShiftRight => a.checked_shr(b).unwrap_or(0),
3044                                _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3045                            })
3046                        }
3047                        (Literal::F16(a), Literal::F16(b)) => {
3048                            let result = match op {
3049                                BinaryOperator::Add => a + b,
3050                                BinaryOperator::Subtract => a - b,
3051                                BinaryOperator::Multiply => a * b,
3052                                BinaryOperator::Divide => a / b,
3053                                BinaryOperator::Modulo => a % b,
3054                                _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3055                            };
3056                            if !result.is_finite() {
3057                                return Err(ConstantEvaluatorError::Overflow(format!("{op:?}")));
3058                            }
3059                            Literal::F16(result)
3060                        }
3061                        (Literal::AbstractInt(a), Literal::AbstractInt(b)) => {
3062                            Literal::AbstractInt(match op {
3063                                BinaryOperator::Add => a.checked_add(b).ok_or_else(|| {
3064                                    ConstantEvaluatorError::Overflow("addition".into())
3065                                })?,
3066                                BinaryOperator::Subtract => a.checked_sub(b).ok_or_else(|| {
3067                                    ConstantEvaluatorError::Overflow("subtraction".into())
3068                                })?,
3069                                BinaryOperator::Multiply => a.checked_mul(b).ok_or_else(|| {
3070                                    ConstantEvaluatorError::Overflow("multiplication".into())
3071                                })?,
3072                                BinaryOperator::Divide => a.checked_div(b).ok_or_else(|| {
3073                                    if b == 0 {
3074                                        ConstantEvaluatorError::DivisionByZero
3075                                    } else {
3076                                        ConstantEvaluatorError::Overflow("division".into())
3077                                    }
3078                                })?,
3079                                BinaryOperator::Modulo => a.checked_rem(b).ok_or_else(|| {
3080                                    if b == 0 {
3081                                        ConstantEvaluatorError::RemainderByZero
3082                                    } else {
3083                                        ConstantEvaluatorError::Overflow("remainder".into())
3084                                    }
3085                                })?,
3086                                BinaryOperator::And => a & b,
3087                                BinaryOperator::ExclusiveOr => a ^ b,
3088                                BinaryOperator::InclusiveOr => a | b,
3089                                _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3090                            })
3091                        }
3092                        (Literal::AbstractFloat(a), Literal::AbstractFloat(b)) => {
3093                            let result = match op {
3094                                BinaryOperator::Add => a + b,
3095                                BinaryOperator::Subtract => a - b,
3096                                BinaryOperator::Multiply => a * b,
3097                                BinaryOperator::Divide => a / b,
3098                                BinaryOperator::Modulo => a % b,
3099                                _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3100                            };
3101                            if !result.is_finite() {
3102                                return Err(ConstantEvaluatorError::Overflow(format!("{op:?}")));
3103                            }
3104                            Literal::AbstractFloat(result)
3105                        }
3106                        (Literal::Bool(a), Literal::Bool(b)) => Literal::Bool(match op {
3107                            BinaryOperator::LogicalAnd => a && b,
3108                            BinaryOperator::LogicalOr => a || b,
3109                            BinaryOperator::And => a & b,
3110                            BinaryOperator::InclusiveOr => a | b,
3111                            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3112                        }),
3113                        _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3114                    },
3115                };
3116                Expression::Literal(literal)
3117            }
3118            (
3119                &Expression::Compose {
3120                    components: ref src_components,
3121                    ty,
3122                },
3123                &Expression::Literal(_),
3124            ) => {
3125                if !is_allowed_compose_literal_op(&self.types[ty].inner, op) {
3126                    return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
3127                }
3128                let mut components = src_components.clone();
3129                for component in &mut components {
3130                    *component = self.binary_op(op, *component, right, span)?;
3131                }
3132                Expression::Compose { ty, components }
3133            }
3134            (
3135                &Expression::Literal(_),
3136                &Expression::Compose {
3137                    components: ref src_components,
3138                    ty,
3139                },
3140            ) => {
3141                if !is_allowed_compose_literal_op(&self.types[ty].inner, op) {
3142                    return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
3143                }
3144                let mut components = src_components.clone();
3145                for component in &mut components {
3146                    *component = self.binary_op(op, left, *component, span)?;
3147                }
3148                Expression::Compose { ty, components }
3149            }
3150            (
3151                &Expression::Compose {
3152                    components: ref left_components,
3153                    ty: left_ty,
3154                },
3155                &Expression::Compose {
3156                    components: ref right_components,
3157                    ty: right_ty,
3158                },
3159            ) => {
3160                // We have to make a copy of the component lists, because the
3161                // call to `binary_op_vector` needs `&mut self`, but `self` owns
3162                // the component lists.
3163                let left_flattened = crate::proc::flatten_compose(
3164                    left_ty,
3165                    left_components,
3166                    self.expressions,
3167                    self.types,
3168                )
3169                .collect::<Vec<_>>();
3170                let right_flattened = crate::proc::flatten_compose(
3171                    right_ty,
3172                    right_components,
3173                    self.expressions,
3174                    self.types,
3175                )
3176                .collect::<Vec<_>>();
3177
3178                self.binary_op_compose(
3179                    op,
3180                    &left_flattened,
3181                    &right_flattened,
3182                    left_ty,
3183                    right_ty,
3184                    span,
3185                )?
3186            }
3187            _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3188        };
3189
3190        return self.register_evaluated_expr(expr, span);
3191
3192        fn is_allowed_compose_literal_op(compose_ty: &TypeInner, op: BinaryOperator) -> bool {
3193            let is_numeric_vec = matches!(
3194                compose_ty, TypeInner::Vector { scalar, .. }
3195                if scalar.kind != ScalarKind::Bool
3196            );
3197            let is_allowed_vec_scalar_op = matches!(
3198                op,
3199                BinaryOperator::Add
3200                    | BinaryOperator::Subtract
3201                    | BinaryOperator::Multiply
3202                    | BinaryOperator::Divide
3203                    | BinaryOperator::Modulo
3204            );
3205            let is_mat = matches!(compose_ty, TypeInner::Matrix { .. });
3206            let is_allowed_mat_scalar_op = matches!(op, BinaryOperator::Multiply);
3207            is_numeric_vec && is_allowed_vec_scalar_op || is_mat && is_allowed_mat_scalar_op
3208        }
3209    }
3210
3211    fn binary_op_compose(
3212        &mut self,
3213        op: BinaryOperator,
3214        left_components: &[Handle<Expression>],
3215        right_components: &[Handle<Expression>],
3216        left_ty: Handle<Type>,
3217        right_ty: Handle<Type>,
3218        span: Span,
3219    ) -> Result<Expression, ConstantEvaluatorError> {
3220        match (&self.types[left_ty].inner, &self.types[right_ty].inner) {
3221            // Binary operation on vector-vector
3222            (
3223                &TypeInner::Vector {
3224                    size: left_size, ..
3225                },
3226                &TypeInner::Vector {
3227                    size: right_size, ..
3228                },
3229            ) if left_size == right_size => self.binary_op_vector(
3230                op,
3231                left_size,
3232                left_components,
3233                right_components,
3234                left_ty,
3235                span,
3236            ),
3237            // Binary operation on vector-matrix
3238            (
3239                &TypeInner::Vector { size, .. },
3240                &TypeInner::Matrix {
3241                    columns,
3242                    rows,
3243                    scalar,
3244                },
3245            ) if op == BinaryOperator::Multiply && size == rows => self.multiply_vector_matrix(
3246                left_components,
3247                right_components,
3248                columns,
3249                scalar,
3250                span,
3251            ),
3252            // Binary operation on matrix-vector
3253            (
3254                &TypeInner::Matrix {
3255                    columns,
3256                    rows,
3257                    scalar,
3258                },
3259                &TypeInner::Vector { size, .. },
3260            ) if op == BinaryOperator::Multiply && size == columns => {
3261                self.multiply_matrix_vector(left_components, right_components, rows, scalar, span)
3262            }
3263            // Binary operation on matrix-matrix
3264            (
3265                &TypeInner::Matrix {
3266                    columns: left_columns,
3267                    rows: left_rows,
3268                    scalar,
3269                },
3270                &TypeInner::Matrix {
3271                    columns: right_columns,
3272                    rows: right_rows,
3273                    ..
3274                },
3275            ) => match op {
3276                BinaryOperator::Add | BinaryOperator::Subtract
3277                    if left_columns == right_columns && left_rows == right_rows =>
3278                {
3279                    let components = left_components
3280                        .iter()
3281                        .zip(right_components)
3282                        .map(|(&left, &right)| self.binary_op(op, left, right, span))
3283                        .collect::<Result<Vec<_>, _>>()?;
3284                    Ok(Expression::Compose {
3285                        ty: left_ty,
3286                        components,
3287                    })
3288                }
3289                BinaryOperator::Multiply if left_columns == right_rows => self
3290                    .multiply_matrix_matrix(
3291                        left_components,
3292                        right_components,
3293                        left_rows,
3294                        right_columns,
3295                        scalar,
3296                        span,
3297                    ),
3298                _ => Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3299            },
3300            _ => Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3301        }
3302    }
3303
3304    fn binary_op_vector(
3305        &mut self,
3306        op: BinaryOperator,
3307        size: crate::VectorSize,
3308        left_components: &[Handle<Expression>],
3309        right_components: &[Handle<Expression>],
3310        left_ty: Handle<Type>,
3311        span: Span,
3312    ) -> Result<Expression, ConstantEvaluatorError> {
3313        let ty = match op {
3314            // Relational operators produce vectors of booleans.
3315            BinaryOperator::Equal
3316            | BinaryOperator::NotEqual
3317            | BinaryOperator::Less
3318            | BinaryOperator::LessEqual
3319            | BinaryOperator::Greater
3320            | BinaryOperator::GreaterEqual => self.types.insert(
3321                Type {
3322                    name: None,
3323                    inner: TypeInner::Vector {
3324                        size,
3325                        scalar: crate::Scalar::BOOL,
3326                    },
3327                },
3328                span,
3329            ),
3330
3331            // Other operators produce the same type as their left
3332            // operand.
3333            BinaryOperator::Add
3334            | BinaryOperator::Subtract
3335            | BinaryOperator::Multiply
3336            | BinaryOperator::Divide
3337            | BinaryOperator::Modulo
3338            | BinaryOperator::And
3339            | BinaryOperator::ExclusiveOr
3340            | BinaryOperator::InclusiveOr
3341            | BinaryOperator::ShiftLeft
3342            | BinaryOperator::ShiftRight => left_ty,
3343
3344            BinaryOperator::LogicalAnd | BinaryOperator::LogicalOr => {
3345                // Not supported on vectors
3346                return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
3347            }
3348        };
3349
3350        let components = left_components
3351            .iter()
3352            .zip(right_components)
3353            .map(|(&left, &right)| self.binary_op(op, left, right, span))
3354            .collect::<Result<Vec<_>, _>>()?;
3355
3356        Ok(Expression::Compose { ty, components })
3357    }
3358
3359    fn multiply_vector_matrix(
3360        &mut self,
3361        vec_components: &[Handle<Expression>],
3362        mat_components: &[Handle<Expression>],
3363        mat_columns: crate::VectorSize,
3364        scalar: crate::Scalar,
3365        span: Span,
3366    ) -> Result<Expression, ConstantEvaluatorError> {
3367        let ty = self.types.insert(
3368            Type {
3369                name: None,
3370                inner: TypeInner::Vector {
3371                    size: mat_columns,
3372                    scalar,
3373                },
3374            },
3375            span,
3376        );
3377        let components = mat_components
3378            .iter()
3379            .map(|&column| {
3380                let Expression::Compose { ref components, .. } = self.expressions[column] else {
3381                    unreachable!()
3382                };
3383                self.dot_exprs(
3384                    vec_components.iter().cloned(),
3385                    components.clone().into_iter(),
3386                    span,
3387                )
3388            })
3389            .collect::<Result<Vec<_>, _>>()?;
3390        Ok(Expression::Compose { ty, components })
3391    }
3392
3393    fn multiply_matrix_vector(
3394        &mut self,
3395        mat_components: &[Handle<Expression>],
3396        vec_components: &[Handle<Expression>],
3397        mat_rows: crate::VectorSize,
3398        scalar: crate::Scalar,
3399        span: Span,
3400    ) -> Result<Expression, ConstantEvaluatorError> {
3401        let ty = self.types.insert(
3402            Type {
3403                name: None,
3404                inner: TypeInner::Vector {
3405                    size: mat_rows,
3406                    scalar,
3407                },
3408            },
3409            span,
3410        );
3411
3412        let flatten = self.flatten_matrix(mat_components);
3413        let nr = mat_rows as usize;
3414        let components = (0..nr)
3415            .map(|r| {
3416                let row = flatten.iter().skip(r).step_by(nr).cloned();
3417                self.dot_exprs(row, vec_components.iter().cloned(), span)
3418            })
3419            .collect::<Result<Vec<_>, _>>()?;
3420        Ok(Expression::Compose { ty, components })
3421    }
3422
3423    fn multiply_matrix_matrix(
3424        &mut self,
3425        left_components: &[Handle<Expression>],
3426        right_components: &[Handle<Expression>],
3427        left_rows: crate::VectorSize,
3428        right_columns: crate::VectorSize,
3429        scalar: crate::Scalar,
3430        span: Span,
3431    ) -> Result<Expression, ConstantEvaluatorError> {
3432        let left_nc = left_components.len();
3433        let left_nr = left_rows as usize;
3434        let right_nc = right_columns as usize;
3435        let right_nr = left_nc;
3436
3437        let mut result = Vec::with_capacity(right_nc);
3438        let result_ty = self.types.insert(
3439            Type {
3440                name: None,
3441                inner: TypeInner::Matrix {
3442                    columns: right_columns,
3443                    rows: left_rows,
3444                    scalar,
3445                },
3446            },
3447            span,
3448        );
3449        let result_column_ty = self.types.insert(
3450            Type {
3451                name: None,
3452                inner: TypeInner::Vector {
3453                    size: left_rows,
3454                    scalar,
3455                },
3456            },
3457            span,
3458        );
3459
3460        let left_flattened = self.flatten_matrix(left_components);
3461        let right_flattened = self.flatten_matrix(right_components);
3462        for c in 0..right_nc {
3463            let result_column = (0..left_nr)
3464                .map(|r| {
3465                    let row = left_flattened.iter().skip(r).step_by(left_nr);
3466                    let column = right_flattened.iter().skip(c * right_nr).take(right_nr);
3467                    self.dot_exprs(row.cloned(), column.cloned(), span)
3468                })
3469                .collect::<Result<Vec<_>, _>>()?;
3470            let expr = Expression::Compose {
3471                ty: result_column_ty,
3472                components: result_column,
3473            };
3474            let handle = self.register_evaluated_expr(expr, span)?;
3475            result.push(handle);
3476        }
3477        Ok(Expression::Compose {
3478            ty: result_ty,
3479            components: result,
3480        })
3481    }
3482
3483    fn flatten_matrix(&self, columns: &[Handle<Expression>]) -> ArrayVec<Handle<Expression>, 16> {
3484        let mut flattened = ArrayVec::<_, 16>::new();
3485        for &column in columns {
3486            let Expression::Compose { ref components, .. } = self.expressions[column] else {
3487                unreachable!()
3488            };
3489            flattened.extend(components.iter().cloned());
3490        }
3491        flattened
3492    }
3493
3494    fn dot_exprs(
3495        &mut self,
3496        left: impl Iterator<Item = Handle<Expression>>,
3497        right: impl Iterator<Item = Handle<Expression>>,
3498        span: Span,
3499    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3500        let mut acc = None;
3501        for (l, r) in left.zip(right) {
3502            let result = self.binary_op(BinaryOperator::Multiply, l, r, span)?;
3503            match acc.as_mut() {
3504                Some(acc) => *acc = self.binary_op(BinaryOperator::Add, *acc, result, span)?,
3505                None => acc = Some(result),
3506            }
3507        }
3508        Ok(acc.unwrap())
3509    }
3510
3511    fn relational(
3512        &mut self,
3513        fun: RelationalFunction,
3514        arg: Handle<Expression>,
3515        span: Span,
3516    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3517        let arg = self.eval_zero_value_and_splat(arg, span)?;
3518        match fun {
3519            RelationalFunction::All | RelationalFunction::Any => match self.expressions[arg] {
3520                Expression::Literal(Literal::Bool(_)) => Ok(arg),
3521                Expression::Compose { ty, ref components }
3522                    if matches!(self.types[ty].inner, TypeInner::Vector { .. }) =>
3523                {
3524                    let mut bool_components = ArrayVec::<bool, { crate::VectorSize::MAX }>::new();
3525                    for component in
3526                        crate::proc::flatten_compose(ty, components, self.expressions, self.types)
3527                    {
3528                        match self.expressions[component] {
3529                            Expression::Literal(Literal::Bool(val)) => {
3530                                bool_components.push(val);
3531                            }
3532                            _ => {
3533                                return Err(ConstantEvaluatorError::InvalidRelationalArg(fun));
3534                            }
3535                        }
3536                    }
3537                    let components = bool_components;
3538                    let result = match fun {
3539                        RelationalFunction::All => components.iter().all(|c| *c),
3540                        RelationalFunction::Any => components.iter().any(|c| *c),
3541                        _ => unreachable!(),
3542                    };
3543                    self.register_evaluated_expr(Expression::Literal(Literal::Bool(result)), span)
3544                }
3545                _ => Err(ConstantEvaluatorError::InvalidRelationalArg(fun)),
3546            },
3547            _ => Err(ConstantEvaluatorError::NotImplemented(format!(
3548                "{fun:?} built-in function"
3549            ))),
3550        }
3551    }
3552
3553    /// Deep copy `expr` from `expressions` into `self.expressions`.
3554    ///
3555    /// Return the root of the new copy.
3556    ///
3557    /// This is used when we're evaluating expressions in a function's
3558    /// expression arena that refer to a constant: we need to copy the
3559    /// constant's value into the function's arena so we can operate on it.
3560    fn copy_from(
3561        &mut self,
3562        expr: Handle<Expression>,
3563        expressions: &Arena<Expression>,
3564    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3565        let span = expressions.get_span(expr);
3566        match expressions[expr] {
3567            ref expr @ (Expression::Literal(_)
3568            | Expression::Constant(_)
3569            | Expression::ZeroValue(_)) => self.register_evaluated_expr(expr.clone(), span),
3570            Expression::Compose { ty, ref components } => {
3571                let mut components = components.clone();
3572                for component in &mut components {
3573                    *component = self.copy_from(*component, expressions)?;
3574                }
3575                self.register_evaluated_expr(Expression::Compose { ty, components }, span)
3576            }
3577            Expression::Splat { size, value } => {
3578                let value = self.copy_from(value, expressions)?;
3579                self.register_evaluated_expr(Expression::Splat { size, value }, span)
3580            }
3581            _ => {
3582                log::debug!("copy_from: SubexpressionsAreNotConstant");
3583                Err(ConstantEvaluatorError::SubexpressionsAreNotConstant)
3584            }
3585        }
3586    }
3587
3588    /// Returns the total number of components, after flattening, of a vector compose expression.
3589    fn vector_compose_flattened_size(
3590        &self,
3591        components: &[Handle<Expression>],
3592    ) -> Result<usize, ConstantEvaluatorError> {
3593        components
3594            .iter()
3595            .try_fold(0, |acc, c| -> Result<_, ConstantEvaluatorError> {
3596                let size = match *self.resolve_type(*c)?.inner_with(self.types) {
3597                    TypeInner::Scalar(_) => 1,
3598                    // We trust that the vector size of `component` is correct,
3599                    // as it will have already been validated when `component`
3600                    // was registered.
3601                    TypeInner::Vector { size, .. } => size as usize,
3602                    _ => return Err(ConstantEvaluatorError::InvalidVectorComposeComponent),
3603                };
3604                Ok(acc + size)
3605            })
3606    }
3607
3608    fn register_evaluated_expr(
3609        &mut self,
3610        expr: Expression,
3611        span: Span,
3612    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3613        // It suffices to only check_literal_value() for `Literal` expressions,
3614        // since we only register one expression at a time, `Compose`
3615        // expressions can only refer to other expressions, and `ZeroValue`
3616        // expressions are always okay.
3617        if let Expression::Literal(literal) = expr {
3618            crate::valid::check_literal_value(literal)?;
3619        }
3620
3621        // Ensure vector composes contain the correct number of components. We
3622        // do so here when each compose is registered to avoid having to deal
3623        // with the mess each time the compose is used in another expression.
3624        if let Expression::Compose { ty, ref components } = expr {
3625            if let TypeInner::Vector { size, scalar: _ } = self.types[ty].inner {
3626                let expected = size as usize;
3627                let actual = self.vector_compose_flattened_size(components)?;
3628                if expected != actual {
3629                    return Err(ConstantEvaluatorError::InvalidVectorComposeLength {
3630                        expected,
3631                        actual,
3632                    });
3633                }
3634            }
3635        }
3636
3637        Ok(self.append_expr(expr, span, ExpressionKind::Const))
3638    }
3639
3640    fn append_expr(
3641        &mut self,
3642        expr: Expression,
3643        span: Span,
3644        expr_type: ExpressionKind,
3645    ) -> Handle<Expression> {
3646        let h = match self.behavior {
3647            Behavior::Wgsl(
3648                WgslRestrictions::Runtime(ref mut function_local_data)
3649                | WgslRestrictions::Const(Some(ref mut function_local_data)),
3650            )
3651            | Behavior::Glsl(GlslRestrictions::Runtime(ref mut function_local_data)) => {
3652                let is_running = function_local_data.emitter.is_running();
3653                let needs_pre_emit = expr.needs_pre_emit();
3654                if is_running && needs_pre_emit {
3655                    function_local_data
3656                        .block
3657                        .extend(function_local_data.emitter.finish(self.expressions));
3658                    let h = self.expressions.append(expr, span);
3659                    function_local_data.emitter.start(self.expressions);
3660                    h
3661                } else {
3662                    self.expressions.append(expr, span)
3663                }
3664            }
3665            _ => self.expressions.append(expr, span),
3666        };
3667        self.expression_kind_tracker.insert(h, expr_type);
3668        h
3669    }
3670
3671    /// Resolve the type of `expr` if it is a constant expression.
3672    ///
3673    /// If `expr` was evaluated to a constant, returns its type.
3674    /// Otherwise, returns an error.
3675    fn resolve_type(
3676        &self,
3677        expr: Handle<Expression>,
3678    ) -> Result<crate::proc::TypeResolution, ConstantEvaluatorError> {
3679        use crate::proc::TypeResolution as Tr;
3680        use crate::Expression as Ex;
3681        let resolution = match self.expressions[expr] {
3682            Ex::Literal(ref literal) => Tr::Value(literal.ty_inner()),
3683            Ex::Constant(c) => Tr::Handle(self.constants[c].ty),
3684            Ex::ZeroValue(ty) | Ex::Compose { ty, .. } => Tr::Handle(ty),
3685            Ex::Splat { size, value } => {
3686                let Tr::Value(TypeInner::Scalar(scalar)) = self.resolve_type(value)? else {
3687                    return Err(ConstantEvaluatorError::SplatScalarOnly);
3688                };
3689                Tr::Value(TypeInner::Vector { scalar, size })
3690            }
3691            _ => {
3692                log::debug!("resolve_type: SubexpressionsAreNotConstant");
3693                return Err(ConstantEvaluatorError::SubexpressionsAreNotConstant);
3694            }
3695        };
3696
3697        Ok(resolution)
3698    }
3699
3700    fn select(
3701        &mut self,
3702        reject: Handle<Expression>,
3703        accept: Handle<Expression>,
3704        condition: Handle<Expression>,
3705        span: Span,
3706    ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3707        let mut arg = |arg| self.eval_zero_value_and_splat(arg, span);
3708
3709        let reject = arg(reject)?;
3710        let accept = arg(accept)?;
3711        let condition = arg(condition)?;
3712
3713        let select_single_component =
3714            |this: &mut Self, reject_scalar, reject, accept, condition| {
3715                let accept = this.cast(accept, reject_scalar, span)?;
3716                if condition {
3717                    Ok(accept)
3718                } else {
3719                    Ok(reject)
3720                }
3721            };
3722
3723        match (&self.expressions[reject], &self.expressions[accept]) {
3724            (&Expression::Literal(reject_lit), &Expression::Literal(_accept_lit)) => {
3725                let reject_scalar = reject_lit.scalar();
3726                let &Expression::Literal(Literal::Bool(condition)) = &self.expressions[condition]
3727                else {
3728                    return Err(ConstantEvaluatorError::SelectScalarConditionNotABool);
3729                };
3730                select_single_component(self, reject_scalar, reject, accept, condition)
3731            }
3732            (
3733                &Expression::Compose {
3734                    ty: reject_ty,
3735                    components: ref reject_components,
3736                },
3737                &Expression::Compose {
3738                    ty: accept_ty,
3739                    components: ref accept_components,
3740                },
3741            ) => {
3742                let ty_deets = |ty| {
3743                    self.types[ty]
3744                        .inner
3745                        .vector_size_and_scalar()
3746                        .map(|(size, scalar)| {
3747                            (size.expect("expected vector type, not scalar type"), scalar)
3748                        })
3749                };
3750
3751                let expected_vec_size = {
3752                    let [(reject_vec_size, _), (accept_vec_size, _)] =
3753                        [reject_ty, accept_ty].map(|ty| ty_deets(ty).unwrap());
3754
3755                    if reject_vec_size != accept_vec_size {
3756                        return Err(ConstantEvaluatorError::SelectVecRejectAcceptSizeMismatch {
3757                            reject: reject_vec_size,
3758                            accept: accept_vec_size,
3759                        });
3760                    }
3761                    reject_vec_size
3762                };
3763
3764                let condition_components = match self.expressions[condition] {
3765                    Expression::Literal(Literal::Bool(condition)) => {
3766                        vec![condition; (expected_vec_size as u8).into()]
3767                    }
3768                    Expression::Compose {
3769                        ty: condition_ty,
3770                        components: ref condition_components,
3771                    } => {
3772                        let Some((condition_vec_size, condition_scalar)) = ty_deets(condition_ty)
3773                        else {
3774                            return Err(ConstantEvaluatorError::SelectConditionNotAVecBool);
3775                        };
3776                        if condition_scalar.kind != ScalarKind::Bool {
3777                            return Err(ConstantEvaluatorError::SelectConditionNotAVecBool);
3778                        }
3779                        if condition_vec_size != expected_vec_size {
3780                            return Err(ConstantEvaluatorError::SelectConditionVecSizeMismatch);
3781                        }
3782                        condition_components
3783                            .iter()
3784                            .copied()
3785                            .map(|component| match &self.expressions[component] {
3786                                &Expression::Literal(Literal::Bool(condition)) => condition,
3787                                _ => unreachable!(),
3788                            })
3789                            .collect()
3790                    }
3791
3792                    _ => return Err(ConstantEvaluatorError::SelectConditionNotAVecBool),
3793                };
3794
3795                let evaluated = Expression::Compose {
3796                    ty: reject_ty,
3797                    components: reject_components
3798                        .clone()
3799                        .into_iter()
3800                        .zip(accept_components.clone())
3801                        .zip(condition_components)
3802                        .map(|((reject, accept), condition)| {
3803                            let reject_scalar = match &self.expressions[reject] {
3804                                &Expression::Literal(lit) => lit.scalar(),
3805                                _ => unreachable!(),
3806                            };
3807                            select_single_component(self, reject_scalar, reject, accept, condition)
3808                        })
3809                        .collect::<Result<_, _>>()?,
3810                };
3811                self.register_evaluated_expr(evaluated, span)
3812            }
3813            _ => Err(ConstantEvaluatorError::SelectAcceptRejectTypeMismatch),
3814        }
3815    }
3816}
3817
3818/// If `dot(e2, e3)` is negative, `e1` returns, otherwise `-e1`.
3819fn float_face_forward<F>(
3820    e1: &[F],
3821    e2: &[F],
3822    e3: &[F],
3823) -> Option<ArrayVec<F, { crate::VectorSize::MAX }>>
3824where
3825    F: num_traits::Float,
3826{
3827    let d = float_dot(e2, e3)?;
3828
3829    let mut out = ArrayVec::new();
3830    for &e in e1 {
3831        out.push(if d < F::zero() { e } else { -e });
3832    }
3833    Some(out)
3834}
3835
3836/// The reflection of incident vector `e1` off a surface oriented `e2`,
3837/// `e1 - 2 * dot(e2, e1) * e2`.
3838fn float_reflect<F>(e1: &[F], e2: &[F]) -> Option<ArrayVec<F, { crate::VectorSize::MAX }>>
3839where
3840    F: num_traits::Float,
3841{
3842    let d = float_dot(e2, e1)?;
3843    let two = F::one() + F::one();
3844
3845    let mut out = ArrayVec::new();
3846    for (&a, &b) in e1.iter().zip(e2) {
3847        let r = a - two * d * b;
3848        if !r.is_finite() {
3849            return None;
3850        }
3851        out.push(r);
3852    }
3853    Some(out)
3854}
3855
3856/// The refraction of incident vector `e1` through a surface with normal `e2`,
3857/// for a ratio of indices of refraction `e3`.
3858fn float_refract<F>(e1: &[F], e2: &[F], e3: F) -> Option<ArrayVec<F, { crate::VectorSize::MAX }>>
3859where
3860    F: num_traits::Float,
3861{
3862    let d = float_dot(e2, e1)?;
3863    let one = F::one();
3864
3865    let k = one - e3 * e3 * (one - d * d);
3866    if !k.is_finite() {
3867        return None;
3868    }
3869
3870    let mut out = ArrayVec::new();
3871
3872    // If there is total internal reflection, returns zero vector.
3873    if k < F::zero() {
3874        for _ in e1 {
3875            out.push(F::zero());
3876        }
3877        return Some(out);
3878    }
3879
3880    let scale = e3 * d + k.sqrt();
3881    for (&a, &b) in e1.iter().zip(e2) {
3882        let r = e3 * a - scale * b;
3883        if !r.is_finite() {
3884            return None;
3885        }
3886        out.push(r);
3887    }
3888    Some(out)
3889}
3890
3891#[test]
3892fn face_forward_smoke() {
3893    #[track_caller]
3894    fn ff(e1: &[f32], e2: &[f32], e3: &[f32]) -> Vec<f32> {
3895        float_face_forward(e1, e2, e3).unwrap().to_vec()
3896    }
3897
3898    // If `dot(e2, e3)` is negative, return `e1`, otherwise return `-e1`.
3899    assert_eq!(ff(&[1.0, 2.0], &[-1.0, 0.0], &[1.0, 0.0]), [1.0, 2.0]);
3900    assert_eq!(ff(&[1.0, 2.0], &[1.0, 0.0], &[1.0, 0.0]), [-1.0, -2.0]);
3901
3902    // Zero = flip `e1`.
3903    assert_eq!(ff(&[1.0, 2.0], &[0.0, 1.0], &[1.0, 0.0]), [-1.0, -2.0]);
3904
3905    assert_eq!(
3906        ff(&[1.0, 2.0, 3.0], &[-1.0, 0.0, 0.0], &[1.0, 0.0, 0.0]),
3907        [1.0, 2.0, 3.0]
3908    );
3909
3910    // Return None if `dot(e2, e3)` is too big to compute.
3911    assert!(float_face_forward(&[1.0f32, 0.0], &[f32::MAX, 0.0], &[f32::MAX, 0.0]).is_none());
3912}
3913
3914#[test]
3915fn reflect_smoke() {
3916    #[track_caller]
3917    fn rf(e1: &[f32], e2: &[f32]) -> Vec<f32> {
3918        float_reflect(e1, e2).unwrap().to_vec()
3919    }
3920
3921    // Bouncing off a floor flips the component along the normal.
3922    assert_eq!(rf(&[1.0, -1.0], &[0.0, 1.0]), [1.0, 1.0]);
3923    assert_eq!(rf(&[1.0, -1.0, 0.0], &[0.0, 1.0, 0.0]), [1.0, 1.0, 0.0]);
3924
3925    // Head-on reverses the vector entirely.
3926    assert_eq!(rf(&[1.0, 0.0], &[1.0, 0.0]), [-1.0, 0.0]);
3927
3928    // A surface parallel to the incident vector leaves it alone.
3929    assert_eq!(rf(&[1.0, 0.0], &[0.0, 1.0]), [1.0, 0.0]);
3930
3931    assert!(float_reflect(&[1.0f32, 0.0], &[f32::MAX, 0.0]).is_none());
3932}
3933
3934#[test]
3935fn refract_smoke() {
3936    #[track_caller]
3937    fn rr(e1: &[f32], e2: &[f32], e3: f32) -> Vec<f32> {
3938        float_refract(e1, e2, e3).unwrap().to_vec()
3939    }
3940
3941    // No change if blending ratio is 1 and a straight surface collision.
3942    assert_eq!(rr(&[0.0, -1.0], &[0.0, 1.0], 1.0), [0.0, -1.0]);
3943    assert_eq!(rr(&[0.5, -0.5], &[0.0, 1.0], 1.0), [0.5, -0.5]);
3944
3945    // A normal facing the opposite way will bend vector to other side.
3946    assert_eq!(rr(&[0.5, -0.5], &[0.0, -1.0], 1.0), [0.5, 0.5]);
3947
3948    // Ratios below 1 shorten the transmitted vector.
3949    assert_eq!(rr(&[0.0, -1.0], &[0.0, 1.0], 0.5), [0.0, -1.0]);
3950
3951    // ‘no refraction possible’ means k goes negative and result is zero.
3952    assert_eq!(rr(&[0.8, -0.6], &[0.0, 1.0], 2.0), [0.0, 0.0]);
3953    assert_eq!(
3954        rr(&[0.8, -0.6, 0.0], &[0.0, 1.0, 0.0], 2.0),
3955        [0.0, 0.0, 0.0]
3956    );
3957
3958    assert!(float_refract(&[1.0f32, 0.0], &[f32::MAX, 0.0], 1.0).is_none());
3959    assert!(float_refract(&[1.0f32, 0.0], &[0.0, 1.0], f32::MAX).is_none());
3960}
3961
3962/// Return a u32 according to the number of bits in `T`, the `w` of the
3963/// `extractBits` and `insertBits` specifications.
3964const fn bit_width<T>() -> u32 {
3965    size_of::<T>() as u32 * 8
3966}
3967
3968/// Reject the `offset` and `count` arguments of `extractBits` and `insertBits`
3969/// if they select bits outside an operand `width` bits wide.
3970///
3971/// The WGSL specification says that this is a shader creation error if `offset`
3972/// and `count` are const expressions, *even if the operand is not*, so the WGSL
3973/// front end will fail immediately if it sees both are const.
3974pub fn check_bitfield_range(
3975    builtin: &'static str,
3976    offset: u32,
3977    count: u32,
3978    width: u32,
3979) -> Result<(), ConstantEvaluatorError> {
3980    if u64::from(offset) + u64::from(count) > u64::from(width) {
3981        return Err(ConstantEvaluatorError::BitfieldRangeTooLarge {
3982            builtin,
3983            offset,
3984            count,
3985            width,
3986        });
3987    }
3988    Ok(())
3989}
3990
3991fn extract_bits<T>(
3992    e: &[T],
3993    offset: u32,
3994    count: u32,
3995) -> Result<ArrayVec<T, { crate::VectorSize::MAX }>, ConstantEvaluatorError>
3996where
3997    T: num_traits::PrimInt,
3998{
3999    check_bitfield_range("extractBits", offset, count, bit_width::<T>())?;
4000    let w = bit_width::<T>();
4001
4002    let mut out = ArrayVec::new();
4003    for &e in e {
4004        out.push(if count == 0 {
4005            T::zero()
4006        } else {
4007            // Shift field up then shift back down.
4008            // - if signed, the empty space fills with the field's top bit
4009            // - if unsigned, the empty space will fill with zeroes
4010            // count is never zero here
4011            (e << (w - offset - count) as usize) >> (w - count) as usize
4012        });
4013    }
4014    Ok(out)
4015}
4016
4017fn insert_bits<T>(
4018    e: &[T],
4019    newbits: &[T],
4020    offset: u32,
4021    count: u32,
4022) -> Result<ArrayVec<T, { crate::VectorSize::MAX }>, ConstantEvaluatorError>
4023where
4024    T: num_traits::PrimInt,
4025{
4026    check_bitfield_range("insertBits", offset, count, bit_width::<T>())?;
4027    let w = bit_width::<T>();
4028
4029    let mut out = ArrayVec::new();
4030    for (&e, &newbits) in e.iter().zip(newbits) {
4031        out.push(if count == 0 {
4032            e
4033        } else {
4034            let mask = (!T::zero()).unsigned_shr(w - count) << offset as usize;
4035            (e & !mask) | ((newbits << offset as usize) & mask)
4036        });
4037    }
4038    Ok(out)
4039}
4040
4041#[cfg(test)]
4042fn extract_bits_scalar<T: num_traits::PrimInt>(e: T, offset: u32, count: u32) -> T {
4043    extract_bits(&[e], offset, count).unwrap()[0]
4044}
4045
4046#[cfg(test)]
4047fn insert_bits_scalar<T: num_traits::PrimInt>(e: T, newbits: T, offset: u32, count: u32) -> T {
4048    insert_bits(&[e], &[newbits], offset, count).unwrap()[0]
4049}
4050
4051#[test]
4052fn extract_bits_smoke() {
4053    // `count` of zero always yields zero, whatever `offset` selects.
4054    assert_eq!(extract_bits_scalar(0xffffffff_u32, 0, 0), 0);
4055    assert_eq!(extract_bits_scalar(-1_i32, 32, 0), 0);
4056
4057    // Selecting the whole width is the identity.
4058    assert_eq!(extract_bits_scalar(0x12345678_u32, 0, 32), 0x12345678);
4059    assert_eq!(extract_bits_scalar(i32::MIN, 0, 32), i32::MIN);
4060
4061    // Unsigned extraction fills the bits above the field with zero.
4062    assert_eq!(extract_bits_scalar(0x12345678_u32, 8, 8), 0x56);
4063    assert_eq!(extract_bits_scalar(0xf0000000_u32, 28, 4), 0xf);
4064    assert_eq!(extract_bits_scalar(0x12345678_u32, 31, 1), 0);
4065
4066    // Signed extraction fills them from the top bit of the field instead.
4067    assert_eq!(extract_bits_scalar(0x12345678_i32, 8, 8), 0x56);
4068    assert_eq!(extract_bits_scalar(0x8_i32, 3, 1), -1);
4069    assert_eq!(extract_bits_scalar(0xf0000000_u32 as i32, 28, 4), -1);
4070    assert_eq!(extract_bits_scalar(0x70000000_i32, 28, 4), 7);
4071
4072    // Widths other than 32 use their own `w`.
4073    assert_eq!(extract_bits_scalar(0x1234_u16, 4, 8), 0x23);
4074    assert_eq!(extract_bits_scalar(-1_i16, 0, 16), -1);
4075    assert_eq!(
4076        extract_bits_scalar(0x123456789abcdef0_u64, 32, 32),
4077        0x12345678
4078    );
4079    assert_eq!(extract_bits_scalar(-1_i64, 63, 1), -1);
4080
4081    // `offset + count` past the end of the type is a shader creation error.
4082    assert!(extract_bits(&[0_u32], 30, 8).is_err());
4083    assert!(extract_bits(&[0_u32], 33, 0).is_err());
4084    assert!(extract_bits(&[0_u16], 8, 16).is_err());
4085    assert!(extract_bits(&[0_u32], u32::MAX, u32::MAX).is_err());
4086    assert!(extract_bits(&[0_u32], 32, 0).is_ok());
4087}
4088
4089#[test]
4090fn insert_bits_smoke() {
4091    // `count` of zero leaves `e` untouched.
4092    assert_eq!(
4093        insert_bits_scalar(0x12345678_u32, 0xffffffff, 0, 0),
4094        0x12345678
4095    );
4096    assert_eq!(insert_bits_scalar(-1_i32, 0, 32, 0), -1);
4097
4098    // Covering the whole width will replace `e` entirely.
4099    assert_eq!(
4100        insert_bits_scalar(0x12345678_u32, 0xdeadbeef, 0, 32),
4101        0xdeadbeef
4102    );
4103    assert_eq!(insert_bits_scalar(0_i32, i32::MIN, 0, 32), i32::MIN);
4104
4105    // Only bits `offset..offset + count` are taken from `newbits`, and only its
4106    // low `count` bits are used.
4107    assert_eq!(insert_bits_scalar(0x12345678_u32, 0xff, 8, 8), 0x1234ff78);
4108    assert_eq!(insert_bits_scalar(0x12345678_u32, 0xabcd, 8, 8), 0x1234cd78);
4109    assert_eq!(insert_bits_scalar(0_u32, 0xf, 28, 4), 0xf0000000);
4110    assert_eq!(insert_bits_scalar(0_u32, 1, 31, 1), 0x80000000);
4111
4112    // Signed operands set the sign bit like any other.
4113    assert_eq!(insert_bits_scalar(0_i32, -1, 31, 1), i32::MIN);
4114    assert_eq!(insert_bits_scalar(-1_i32, 0, 0, 31), i32::MIN);
4115
4116    // Widths other than 32 use their own `w`.
4117    assert_eq!(insert_bits_scalar(0x1234_u16, 0xf, 4, 4), 0x12f4);
4118    assert_eq!(insert_bits_scalar(0_i16, -1, 15, 1), i16::MIN);
4119    assert_eq!(
4120        insert_bits_scalar(0_u64, 0xffffffff, 32, 32),
4121        0xffffffff00000000
4122    );
4123
4124    // `offset + count` past the end of the type is a shader creation error.
4125    assert!(insert_bits(&[0_u32], &[0], 30, 8).is_err());
4126    assert!(insert_bits(&[0_u32], &[0], 33, 0).is_err());
4127    assert!(insert_bits(&[0_u16], &[0], 8, 16).is_err());
4128    assert!(insert_bits(&[0_u32], &[0], u32::MAX, u32::MAX).is_err());
4129    assert!(insert_bits(&[0_u32], &[0], 32, 0).is_ok());
4130}
4131
4132fn first_trailing_bit(concrete_int: ConcreteInt<1>) -> ConcreteInt<1> {
4133    // NOTE: Bit indices for this built-in start at 0 at the "right" (or LSB). For example, a value
4134    // of 1 means the least significant bit is set. Therefore, an input of `0x[80 00…]` would
4135    // return a right-to-left bit index of 0.
4136    let trailing_zeros_to_bit_idx = |e: u32| -> u32 {
4137        match e {
4138            idx @ 0..=31 => idx,
4139            32 => u32::MAX,
4140            _ => unreachable!(),
4141        }
4142    };
4143    match concrete_int {
4144        ConcreteInt::U32([e]) => ConcreteInt::U32([trailing_zeros_to_bit_idx(e.trailing_zeros())]),
4145        ConcreteInt::I32([e]) => {
4146            ConcreteInt::I32([trailing_zeros_to_bit_idx(e.trailing_zeros()) as i32])
4147        }
4148    }
4149}
4150
4151#[test]
4152fn first_trailing_bit_smoke() {
4153    assert_eq!(
4154        first_trailing_bit(ConcreteInt::I32([0])),
4155        ConcreteInt::I32([-1])
4156    );
4157    assert_eq!(
4158        first_trailing_bit(ConcreteInt::I32([1])),
4159        ConcreteInt::I32([0])
4160    );
4161    assert_eq!(
4162        first_trailing_bit(ConcreteInt::I32([2])),
4163        ConcreteInt::I32([1])
4164    );
4165    assert_eq!(
4166        first_trailing_bit(ConcreteInt::I32([-1])),
4167        ConcreteInt::I32([0]),
4168    );
4169    assert_eq!(
4170        first_trailing_bit(ConcreteInt::I32([i32::MIN])),
4171        ConcreteInt::I32([31]),
4172    );
4173    assert_eq!(
4174        first_trailing_bit(ConcreteInt::I32([i32::MAX])),
4175        ConcreteInt::I32([0]),
4176    );
4177    for idx in 0..32 {
4178        assert_eq!(
4179            first_trailing_bit(ConcreteInt::I32([1 << idx])),
4180            ConcreteInt::I32([idx])
4181        )
4182    }
4183
4184    assert_eq!(
4185        first_trailing_bit(ConcreteInt::U32([0])),
4186        ConcreteInt::U32([u32::MAX])
4187    );
4188    assert_eq!(
4189        first_trailing_bit(ConcreteInt::U32([1])),
4190        ConcreteInt::U32([0])
4191    );
4192    assert_eq!(
4193        first_trailing_bit(ConcreteInt::U32([2])),
4194        ConcreteInt::U32([1])
4195    );
4196    assert_eq!(
4197        first_trailing_bit(ConcreteInt::U32([1 << 31])),
4198        ConcreteInt::U32([31]),
4199    );
4200    assert_eq!(
4201        first_trailing_bit(ConcreteInt::U32([u32::MAX])),
4202        ConcreteInt::U32([0]),
4203    );
4204    for idx in 0..32 {
4205        assert_eq!(
4206            first_trailing_bit(ConcreteInt::U32([1 << idx])),
4207            ConcreteInt::U32([idx])
4208        )
4209    }
4210}
4211
4212fn first_leading_bit(concrete_int: ConcreteInt<1>) -> ConcreteInt<1> {
4213    // NOTE: Bit indices for this built-in start at 0 at the "right" (or LSB). For example, 1 means
4214    // the least significant bit is set. Therefore, an input of 1 would return a right-to-left bit
4215    // index of 0.
4216    let rtl_to_ltr_bit_idx = |e: u32| -> u32 {
4217        match e {
4218            idx @ 0..=31 => 31 - idx,
4219            32 => u32::MAX,
4220            _ => unreachable!(),
4221        }
4222    };
4223    match concrete_int {
4224        ConcreteInt::I32([e]) => ConcreteInt::I32([{
4225            let rtl_bit_index = if e.is_negative() {
4226                e.leading_ones()
4227            } else {
4228                e.leading_zeros()
4229            };
4230            rtl_to_ltr_bit_idx(rtl_bit_index) as i32
4231        }]),
4232        ConcreteInt::U32([e]) => ConcreteInt::U32([rtl_to_ltr_bit_idx(e.leading_zeros())]),
4233    }
4234}
4235
4236#[test]
4237fn first_leading_bit_smoke() {
4238    assert_eq!(
4239        first_leading_bit(ConcreteInt::I32([-1])),
4240        ConcreteInt::I32([-1])
4241    );
4242    assert_eq!(
4243        first_leading_bit(ConcreteInt::I32([0])),
4244        ConcreteInt::I32([-1])
4245    );
4246    assert_eq!(
4247        first_leading_bit(ConcreteInt::I32([1])),
4248        ConcreteInt::I32([0])
4249    );
4250    assert_eq!(
4251        first_leading_bit(ConcreteInt::I32([-2])),
4252        ConcreteInt::I32([0])
4253    );
4254    assert_eq!(
4255        first_leading_bit(ConcreteInt::I32([1234 + 4567])),
4256        ConcreteInt::I32([12])
4257    );
4258    assert_eq!(
4259        first_leading_bit(ConcreteInt::I32([i32::MAX])),
4260        ConcreteInt::I32([30])
4261    );
4262    assert_eq!(
4263        first_leading_bit(ConcreteInt::I32([i32::MIN])),
4264        ConcreteInt::I32([30])
4265    );
4266    // NOTE: Ignore the sign bit, which is a separate (above) case.
4267    for idx in 0..(32 - 1) {
4268        assert_eq!(
4269            first_leading_bit(ConcreteInt::I32([1 << idx])),
4270            ConcreteInt::I32([idx])
4271        );
4272    }
4273    for idx in 1..(32 - 1) {
4274        assert_eq!(
4275            first_leading_bit(ConcreteInt::I32([-(1 << idx)])),
4276            ConcreteInt::I32([idx - 1])
4277        );
4278    }
4279
4280    assert_eq!(
4281        first_leading_bit(ConcreteInt::U32([0])),
4282        ConcreteInt::U32([u32::MAX])
4283    );
4284    assert_eq!(
4285        first_leading_bit(ConcreteInt::U32([1])),
4286        ConcreteInt::U32([0])
4287    );
4288    assert_eq!(
4289        first_leading_bit(ConcreteInt::U32([u32::MAX])),
4290        ConcreteInt::U32([31])
4291    );
4292    for idx in 0..32 {
4293        assert_eq!(
4294            first_leading_bit(ConcreteInt::U32([1 << idx])),
4295            ConcreteInt::U32([idx])
4296        )
4297    }
4298}
4299
4300/// Trait for conversions of abstract values to concrete types.
4301trait TryFromAbstract<T>: Sized {
4302    /// Convert an abstract literal `value` to `Self`.
4303    ///
4304    /// Since Naga's [`AbstractInt`] and [`AbstractFloat`] exist to support
4305    /// WGSL, we follow WGSL's conversion rules here:
4306    ///
4307    /// - WGSL §6.1.2. Conversion Rank says that automatic conversions
4308    ///   from [`AbstractInt`] to an integer type are either lossless or an
4309    ///   error.
4310    ///
4311    /// - WGSL §15.7.6 Floating Point Conversion says that conversions
4312    ///   to floating point in constant expressions and override
4313    ///   expressions are errors if the value is out of range for the
4314    ///   destination type, but rounding is okay.
4315    ///
4316    /// - WGSL §17.1.2 i32()/u32() constructors treat AbstractFloat as any
4317    ///   other floating point type, following the scalar floating point to
4318    ///   integral conversion algorithm (§15.7.6). There is no automatic
4319    ///   conversion from AbstractFloat to integer types.
4320    ///
4321    /// [`AbstractInt`]: crate::Literal::AbstractInt
4322    /// [`AbstractFloat`]: crate::Literal::AbstractFloat
4323    fn try_from_abstract(value: T) -> Result<Self, ConstantEvaluatorError>;
4324}
4325
4326impl TryFromAbstract<i64> for i32 {
4327    fn try_from_abstract(value: i64) -> Result<i32, ConstantEvaluatorError> {
4328        i32::try_from(value).map_err(|_| ConstantEvaluatorError::AutomaticConversionLossy {
4329            value: format!("{value:?}"),
4330            to_type: "i32",
4331        })
4332    }
4333}
4334
4335impl TryFromAbstract<i64> for u32 {
4336    fn try_from_abstract(value: i64) -> Result<u32, ConstantEvaluatorError> {
4337        u32::try_from(value).map_err(|_| ConstantEvaluatorError::AutomaticConversionLossy {
4338            value: format!("{value:?}"),
4339            to_type: "u32",
4340        })
4341    }
4342}
4343
4344impl TryFromAbstract<i64> for u64 {
4345    fn try_from_abstract(value: i64) -> Result<u64, ConstantEvaluatorError> {
4346        u64::try_from(value).map_err(|_| ConstantEvaluatorError::AutomaticConversionLossy {
4347            value: format!("{value:?}"),
4348            to_type: "u64",
4349        })
4350    }
4351}
4352
4353impl TryFromAbstract<i64> for i64 {
4354    fn try_from_abstract(value: i64) -> Result<i64, ConstantEvaluatorError> {
4355        Ok(value)
4356    }
4357}
4358
4359impl TryFromAbstract<i64> for f32 {
4360    fn try_from_abstract(value: i64) -> Result<Self, ConstantEvaluatorError> {
4361        let f = value as f32;
4362        // The range of `i64` is roughly ±18 × 10¹⁸, whereas the range of
4363        // `f32` is roughly ±3.4 × 10³⁸, so there's no opportunity for
4364        // overflow here.
4365        Ok(f)
4366    }
4367}
4368
4369impl TryFromAbstract<f64> for f32 {
4370    fn try_from_abstract(value: f64) -> Result<f32, ConstantEvaluatorError> {
4371        let f = value as f32;
4372        if f.is_infinite() {
4373            return Err(ConstantEvaluatorError::AutomaticConversionLossy {
4374                value: format!("{value:?}"),
4375                to_type: "f32",
4376            });
4377        }
4378        Ok(f)
4379    }
4380}
4381
4382impl TryFromAbstract<i64> for f64 {
4383    fn try_from_abstract(value: i64) -> Result<Self, ConstantEvaluatorError> {
4384        let f = value as f64;
4385        // The range of `i64` is roughly ±18 × 10¹⁸, whereas the range of
4386        // `f64` is roughly ±1.8 × 10³⁰⁸, so there's no opportunity for
4387        // overflow here.
4388        Ok(f)
4389    }
4390}
4391
4392impl TryFromAbstract<f64> for f64 {
4393    fn try_from_abstract(value: f64) -> Result<f64, ConstantEvaluatorError> {
4394        Ok(value)
4395    }
4396}
4397
4398impl TryFromAbstract<f64> for i32 {
4399    fn try_from_abstract(value: f64) -> Result<Self, ConstantEvaluatorError> {
4400        // https://www.w3.org/TR/WGSL/#floating-point-conversion
4401        // To convert a floating point scalar value X to an integer scalar type T:
4402        // * If X is a NaN, the result is an indeterminate value in T.
4403        // * If X is exactly representable in the target type T, then the
4404        //   result is that value.
4405        // * Otherwise, the result is the value in T closest to truncate(X) and
4406        //   also exactly representable in the original floating point type.
4407        //
4408        // A rust cast satisfies these requirements apart from "the result
4409        // is... exactly representable in the original floating point type".
4410        // However, i32::MIN and i32::MAX are exactly representable by f64, so
4411        // we're all good.
4412        Ok(value as i32)
4413    }
4414}
4415
4416impl TryFromAbstract<f64> for u32 {
4417    fn try_from_abstract(value: f64) -> Result<Self, ConstantEvaluatorError> {
4418        // As above, u32::MIN and u32::MAX are exactly representable by f64,
4419        // so a simple rust cast is sufficient.
4420        Ok(value as u32)
4421    }
4422}
4423
4424impl TryFromAbstract<f64> for i64 {
4425    fn try_from_abstract(value: f64) -> Result<Self, ConstantEvaluatorError> {
4426        // As above, except we clamp to the minimum and maximum values
4427        // representable by both f64 and i64.
4428        use crate::proc::type_methods::IntFloatLimits;
4429        Ok(value.clamp(i64::min_float(), i64::max_float()) as i64)
4430    }
4431}
4432
4433impl TryFromAbstract<f64> for u64 {
4434    fn try_from_abstract(value: f64) -> Result<Self, ConstantEvaluatorError> {
4435        // As above, this time clamping to the minimum and maximum values
4436        // representable by both f64 and u64.
4437        use crate::proc::type_methods::IntFloatLimits;
4438        Ok(value.clamp(u64::min_float(), u64::max_float()) as u64)
4439    }
4440}
4441
4442impl TryFromAbstract<f64> for f16 {
4443    fn try_from_abstract(value: f64) -> Result<f16, ConstantEvaluatorError> {
4444        let f = f16::from_f64(value);
4445        if f.is_infinite() {
4446            return Err(ConstantEvaluatorError::AutomaticConversionLossy {
4447                value: format!("{value:?}"),
4448                to_type: "f16",
4449            });
4450        }
4451        Ok(f)
4452    }
4453}
4454
4455impl TryFromAbstract<i64> for f16 {
4456    fn try_from_abstract(value: i64) -> Result<f16, ConstantEvaluatorError> {
4457        let f = f16::from_i64(value);
4458        if f.is_none() {
4459            return Err(ConstantEvaluatorError::AutomaticConversionLossy {
4460                value: format!("{value:?}"),
4461                to_type: "f16",
4462            });
4463        }
4464        Ok(f.unwrap())
4465    }
4466}
4467
4468fn cross_product<T>(a: [T; 3], b: [T; 3]) -> [T; 3]
4469where
4470    T: Copy,
4471    T: core::ops::Mul<T, Output = T>,
4472    T: core::ops::Sub<T, Output = T>,
4473{
4474    [
4475        a[1] * b[2] - a[2] * b[1],
4476        a[2] * b[0] - a[0] * b[2],
4477        a[0] * b[1] - a[1] * b[0],
4478    ]
4479}
4480
4481#[cfg(test)]
4482mod tests {
4483    use alloc::{vec, vec::Vec};
4484
4485    use crate::{
4486        Arena, BinaryOperator, Constant, Expression, FastHashMap, Handle, Literal, ScalarKind,
4487        Type, TypeInner, UnaryOperator, UniqueArena, VectorSize,
4488    };
4489
4490    use super::{Behavior, ConstantEvaluator, ExpressionKindTracker, WgslRestrictions};
4491
4492    #[test]
4493    fn unary_op() {
4494        let mut types = UniqueArena::new();
4495        let mut constants = Arena::new();
4496        let overrides = Arena::new();
4497        let mut global_expressions = Arena::new();
4498
4499        let scalar_ty = types.insert(
4500            Type {
4501                name: None,
4502                inner: TypeInner::Scalar(crate::Scalar::I32),
4503            },
4504            Default::default(),
4505        );
4506
4507        let vec_ty = types.insert(
4508            Type {
4509                name: None,
4510                inner: TypeInner::Vector {
4511                    size: VectorSize::Bi,
4512                    scalar: crate::Scalar::I32,
4513                },
4514            },
4515            Default::default(),
4516        );
4517
4518        let h = constants.append(
4519            Constant {
4520                name: None,
4521                ty: scalar_ty,
4522                init: global_expressions
4523                    .append(Expression::Literal(Literal::I32(4)), Default::default()),
4524            },
4525            Default::default(),
4526        );
4527
4528        let h1 = constants.append(
4529            Constant {
4530                name: None,
4531                ty: scalar_ty,
4532                init: global_expressions
4533                    .append(Expression::Literal(Literal::I32(8)), Default::default()),
4534            },
4535            Default::default(),
4536        );
4537
4538        let vec_h = constants.append(
4539            Constant {
4540                name: None,
4541                ty: vec_ty,
4542                init: global_expressions.append(
4543                    Expression::Compose {
4544                        ty: vec_ty,
4545                        components: vec![constants[h].init, constants[h1].init],
4546                    },
4547                    Default::default(),
4548                ),
4549            },
4550            Default::default(),
4551        );
4552
4553        let expr = global_expressions.append(Expression::Constant(h), Default::default());
4554        let expr1 = global_expressions.append(Expression::Constant(vec_h), Default::default());
4555
4556        let expr2 = Expression::Unary {
4557            op: UnaryOperator::Negate,
4558            expr,
4559        };
4560
4561        let expr3 = Expression::Unary {
4562            op: UnaryOperator::BitwiseNot,
4563            expr,
4564        };
4565
4566        let expr4 = Expression::Unary {
4567            op: UnaryOperator::BitwiseNot,
4568            expr: expr1,
4569        };
4570
4571        let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
4572        let mut solver = ConstantEvaluator {
4573            behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4574            types: &mut types,
4575            constants: &constants,
4576            overrides: &overrides,
4577            expressions: &mut global_expressions,
4578            expression_kind_tracker,
4579            layouter: &mut crate::proc::Layouter::default(),
4580        };
4581
4582        let res1 = solver
4583            .try_eval_and_append(expr2, Default::default())
4584            .unwrap();
4585        let res2 = solver
4586            .try_eval_and_append(expr3, Default::default())
4587            .unwrap();
4588        let res3 = solver
4589            .try_eval_and_append(expr4, Default::default())
4590            .unwrap();
4591
4592        assert_eq!(
4593            global_expressions[res1],
4594            Expression::Literal(Literal::I32(-4))
4595        );
4596
4597        assert_eq!(
4598            global_expressions[res2],
4599            Expression::Literal(Literal::I32(!4))
4600        );
4601
4602        let res3_inner = &global_expressions[res3];
4603
4604        match *res3_inner {
4605            Expression::Compose {
4606                ref ty,
4607                ref components,
4608            } => {
4609                assert_eq!(*ty, vec_ty);
4610                let mut components_iter = components.iter().copied();
4611                assert_eq!(
4612                    global_expressions[components_iter.next().unwrap()],
4613                    Expression::Literal(Literal::I32(!4))
4614                );
4615                assert_eq!(
4616                    global_expressions[components_iter.next().unwrap()],
4617                    Expression::Literal(Literal::I32(!8))
4618                );
4619                assert!(components_iter.next().is_none());
4620            }
4621            _ => panic!("Expected vector"),
4622        }
4623    }
4624
4625    #[test]
4626    fn matrix_op() {
4627        let mut helper = MatrixTestHelper::new();
4628
4629        for nc in 2..=4 {
4630            for nr in 2..=4 {
4631                // Validates multiplication on vector-matrix.
4632                // vecR(0, 1, .., r) * matCxR(0, 1, .., nc * nr)
4633                let evaluated = helper.eval_vector_multiply_matrix(nc, nr);
4634                let expected = (0..nc)
4635                    .map(|c| (0..nr).map(|r| (r * (c * nr + r)) as f32).sum())
4636                    .collect::<Vec<f32>>();
4637                assert_eq!(evaluated, expected);
4638
4639                // Validates multiplication on matrix-vector.
4640                // matCxR(0, 1, .., nc * nr) * vecC(0, 1, .., nc)
4641                let evaluated = helper.eval_matrix_multiply_vector(nc, nr);
4642                let expected = (0..nr)
4643                    .map(|r| (0..nc).map(|c| (c * (c * nr + r)) as f32).sum())
4644                    .collect::<Vec<f32>>();
4645                assert_eq!(evaluated, expected);
4646
4647                for k in 2..=4 {
4648                    // Validates multiplication on matrix-matrix.
4649                    // matKxR(0, 1, .., k * nr) * matCxK(0, 1, .., nc * k)
4650                    let evaluated = helper.eval_matrix_multiply_matrix(nr, nc, k);
4651                    let expected = (0..nc)
4652                        .flat_map(|c| {
4653                            (0..nr).map(move |r| {
4654                                (0..k).map(|v| ((v * nr + r) * (c * k + v)) as f32).sum()
4655                            })
4656                        })
4657                        .collect::<Vec<f32>>();
4658                    assert_eq!(evaluated, expected);
4659                }
4660            }
4661        }
4662    }
4663
4664    /// Test fixture providing pre-built f32 vector and matrix constant
4665    /// expressions with sequential element values, used to evaluate and verify
4666    /// matrix operations.
4667    struct MatrixTestHelper {
4668        types: UniqueArena<Type>,
4669        expressions: Arena<Expression>,
4670        /// Vector expressions from [0, 1] to [0, 1, 2, 3].
4671        vec_exprs: FastHashMap<usize, Handle<Expression>>,
4672        /// Matrix expressions from [0, .., 3] to [0, .., 15].
4673        mat_exprs: FastHashMap<(usize, usize), Handle<Expression>>,
4674    }
4675
4676    impl MatrixTestHelper {
4677        fn new() -> Self {
4678            let mut types = UniqueArena::new();
4679            let mut expressions = Arena::new();
4680            let span = crate::Span::default();
4681
4682            let (mut vec_tys, mut mat_tys) = (FastHashMap::default(), FastHashMap::default());
4683            for c in 2..=4 {
4684                let vec_ty = types.insert(
4685                    Type {
4686                        name: None,
4687                        inner: TypeInner::Vector {
4688                            size: Self::int_to_vector_size(c),
4689                            scalar: crate::Scalar::F32,
4690                        },
4691                    },
4692                    span,
4693                );
4694                vec_tys.insert(c, vec_ty);
4695                for r in 2..=4 {
4696                    let mat_ty = types.insert(
4697                        Type {
4698                            name: None,
4699                            inner: TypeInner::Matrix {
4700                                columns: Self::int_to_vector_size(c),
4701                                rows: Self::int_to_vector_size(r),
4702                                scalar: crate::Scalar::F32,
4703                            },
4704                        },
4705                        span,
4706                    );
4707                    mat_tys.insert((c, r), mat_ty);
4708                }
4709            }
4710
4711            let mut lit_exprs = FastHashMap::default();
4712            for i in 0..16 {
4713                let expr = expressions.append(Expression::Literal(Literal::F32(i as f32)), span);
4714                lit_exprs.insert(i, expr);
4715            }
4716
4717            let mut vec_exprs = FastHashMap::default();
4718            for c in 2..=4 {
4719                let expr = expressions.append(
4720                    Expression::Compose {
4721                        ty: *vec_tys.get(&c).unwrap(),
4722                        components: (0..c)
4723                            .map(|i| *lit_exprs.get(&i).unwrap())
4724                            .collect::<Vec<_>>(),
4725                    },
4726                    span,
4727                );
4728                vec_exprs.insert(c, expr);
4729            }
4730
4731            let mut mat_exprs = FastHashMap::default();
4732            for c in 2..=4 {
4733                for r in 2..=4 {
4734                    let mut columns = Vec::with_capacity(c);
4735                    for cc in 0..c {
4736                        let start = cc * r;
4737                        let expr = expressions.append(
4738                            Expression::Compose {
4739                                ty: *vec_tys.get(&r).unwrap(),
4740                                components: (start..start + r)
4741                                    .map(|i| *lit_exprs.get(&i).unwrap())
4742                                    .collect::<Vec<_>>(),
4743                            },
4744                            span,
4745                        );
4746                        columns.push(expr);
4747                    }
4748
4749                    let expr = expressions.append(
4750                        Expression::Compose {
4751                            ty: *mat_tys.get(&(c, r)).unwrap(),
4752                            components: columns,
4753                        },
4754                        span,
4755                    );
4756                    mat_exprs.insert((c, r), expr);
4757                }
4758            }
4759
4760            Self {
4761                types,
4762                expressions,
4763                vec_exprs,
4764                mat_exprs,
4765            }
4766        }
4767
4768        /// Evaluates vec[0..nr] * mat[0..nc*nr] and returns the result as f32s.
4769        fn eval_vector_multiply_matrix(&mut self, nc: usize, nr: usize) -> Vec<f32> {
4770            let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&self.expressions);
4771            let mut solver = ConstantEvaluator {
4772                behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4773                types: &mut self.types,
4774                constants: &Arena::new(),
4775                overrides: &Arena::new(),
4776                expressions: &mut self.expressions,
4777                expression_kind_tracker,
4778                layouter: &mut crate::proc::Layouter::default(),
4779            };
4780
4781            let result = solver
4782                .try_eval_and_append(
4783                    Expression::Binary {
4784                        op: BinaryOperator::Multiply,
4785                        left: *self.vec_exprs.get(&nr).unwrap(),
4786                        right: *self.mat_exprs.get(&(nc, nr)).unwrap(),
4787                    },
4788                    Default::default(),
4789                )
4790                .unwrap();
4791            self.flatten(result)
4792        }
4793
4794        /// Evaluates mat[0..nc*nr] * vec[0..nc] and returns the result as f32s.
4795        fn eval_matrix_multiply_vector(&mut self, nc: usize, nr: usize) -> Vec<f32> {
4796            let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&self.expressions);
4797            let mut solver = ConstantEvaluator {
4798                behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4799                types: &mut self.types,
4800                constants: &Arena::new(),
4801                overrides: &Arena::new(),
4802                expressions: &mut self.expressions,
4803                expression_kind_tracker,
4804                layouter: &mut crate::proc::Layouter::default(),
4805            };
4806
4807            let result = solver
4808                .try_eval_and_append(
4809                    Expression::Binary {
4810                        op: BinaryOperator::Multiply,
4811                        left: *self.mat_exprs.get(&(nc, nr)).unwrap(),
4812                        right: *self.vec_exprs.get(&nc).unwrap(),
4813                    },
4814                    Default::default(),
4815                )
4816                .unwrap();
4817            self.flatten(result)
4818        }
4819
4820        /// Evaluates mat[0..k*l_nr] * mat[0..r_nc*k] and returns the result as
4821        /// f32s.
4822        fn eval_matrix_multiply_matrix(&mut self, l_nr: usize, r_nc: usize, k: usize) -> Vec<f32> {
4823            let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&self.expressions);
4824            let mut solver = ConstantEvaluator {
4825                behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4826                types: &mut self.types,
4827                constants: &Arena::new(),
4828                overrides: &Arena::new(),
4829                expressions: &mut self.expressions,
4830                expression_kind_tracker,
4831                layouter: &mut crate::proc::Layouter::default(),
4832            };
4833
4834            let result = solver
4835                .try_eval_and_append(
4836                    Expression::Binary {
4837                        op: BinaryOperator::Multiply,
4838                        left: *self.mat_exprs.get(&(k, l_nr)).unwrap(),
4839                        right: *self.mat_exprs.get(&(r_nc, k)).unwrap(),
4840                    },
4841                    Default::default(),
4842                )
4843                .unwrap();
4844            self.flatten(result)
4845        }
4846
4847        fn flatten(&self, expr: Handle<Expression>) -> Vec<f32> {
4848            let Expression::Compose {
4849                ref components,
4850                ref ty,
4851            } = self.expressions[expr]
4852            else {
4853                unreachable!()
4854            };
4855
4856            match self.types[*ty].inner {
4857                TypeInner::Vector { .. } => components
4858                    .iter()
4859                    .map(|&comp| {
4860                        let Expression::Literal(Literal::F32(v)) = self.expressions[comp] else {
4861                            unreachable!()
4862                        };
4863                        v
4864                    })
4865                    .collect(),
4866                TypeInner::Matrix { .. } => components
4867                    .iter()
4868                    .flat_map(|&comp| self.flatten(comp))
4869                    .collect(),
4870                _ => unreachable!(),
4871            }
4872        }
4873
4874        fn int_to_vector_size(int: usize) -> VectorSize {
4875            match int {
4876                2 => VectorSize::Bi,
4877                3 => VectorSize::Tri,
4878                4 => VectorSize::Quad,
4879                _ => unreachable!(),
4880            }
4881        }
4882    }
4883
4884    #[test]
4885    fn cast() {
4886        let mut types = UniqueArena::new();
4887        let mut constants = Arena::new();
4888        let overrides = Arena::new();
4889        let mut global_expressions = Arena::new();
4890
4891        let scalar_ty = types.insert(
4892            Type {
4893                name: None,
4894                inner: TypeInner::Scalar(crate::Scalar::I32),
4895            },
4896            Default::default(),
4897        );
4898
4899        let h = constants.append(
4900            Constant {
4901                name: None,
4902                ty: scalar_ty,
4903                init: global_expressions
4904                    .append(Expression::Literal(Literal::I32(4)), Default::default()),
4905            },
4906            Default::default(),
4907        );
4908
4909        let expr = global_expressions.append(Expression::Constant(h), Default::default());
4910
4911        let root = Expression::As {
4912            expr,
4913            kind: ScalarKind::Bool,
4914            convert: Some(crate::BOOL_WIDTH),
4915        };
4916
4917        let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
4918        let mut solver = ConstantEvaluator {
4919            behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4920            types: &mut types,
4921            constants: &constants,
4922            overrides: &overrides,
4923            expressions: &mut global_expressions,
4924            expression_kind_tracker,
4925            layouter: &mut crate::proc::Layouter::default(),
4926        };
4927
4928        let res = solver
4929            .try_eval_and_append(root, Default::default())
4930            .unwrap();
4931
4932        assert_eq!(
4933            global_expressions[res],
4934            Expression::Literal(Literal::Bool(true))
4935        );
4936    }
4937
4938    #[test]
4939    fn access() {
4940        let mut types = UniqueArena::new();
4941        let mut constants = Arena::new();
4942        let overrides = Arena::new();
4943        let mut global_expressions = Arena::new();
4944
4945        let matrix_ty = types.insert(
4946            Type {
4947                name: None,
4948                inner: TypeInner::Matrix {
4949                    columns: VectorSize::Bi,
4950                    rows: VectorSize::Tri,
4951                    scalar: crate::Scalar::F32,
4952                },
4953            },
4954            Default::default(),
4955        );
4956
4957        let vec_ty = types.insert(
4958            Type {
4959                name: None,
4960                inner: TypeInner::Vector {
4961                    size: VectorSize::Tri,
4962                    scalar: crate::Scalar::F32,
4963                },
4964            },
4965            Default::default(),
4966        );
4967
4968        let mut vec1_components = Vec::with_capacity(3);
4969        let mut vec2_components = Vec::with_capacity(3);
4970
4971        for i in 0..3 {
4972            let h = global_expressions.append(
4973                Expression::Literal(Literal::F32(i as f32)),
4974                Default::default(),
4975            );
4976
4977            vec1_components.push(h)
4978        }
4979
4980        for i in 3..6 {
4981            let h = global_expressions.append(
4982                Expression::Literal(Literal::F32(i as f32)),
4983                Default::default(),
4984            );
4985
4986            vec2_components.push(h)
4987        }
4988
4989        let vec1 = constants.append(
4990            Constant {
4991                name: None,
4992                ty: vec_ty,
4993                init: global_expressions.append(
4994                    Expression::Compose {
4995                        ty: vec_ty,
4996                        components: vec1_components,
4997                    },
4998                    Default::default(),
4999                ),
5000            },
5001            Default::default(),
5002        );
5003
5004        let vec2 = constants.append(
5005            Constant {
5006                name: None,
5007                ty: vec_ty,
5008                init: global_expressions.append(
5009                    Expression::Compose {
5010                        ty: vec_ty,
5011                        components: vec2_components,
5012                    },
5013                    Default::default(),
5014                ),
5015            },
5016            Default::default(),
5017        );
5018
5019        let h = constants.append(
5020            Constant {
5021                name: None,
5022                ty: matrix_ty,
5023                init: global_expressions.append(
5024                    Expression::Compose {
5025                        ty: matrix_ty,
5026                        components: vec![constants[vec1].init, constants[vec2].init],
5027                    },
5028                    Default::default(),
5029                ),
5030            },
5031            Default::default(),
5032        );
5033
5034        let base = global_expressions.append(Expression::Constant(h), Default::default());
5035
5036        let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
5037        let mut solver = ConstantEvaluator {
5038            behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
5039            types: &mut types,
5040            constants: &constants,
5041            overrides: &overrides,
5042            expressions: &mut global_expressions,
5043            expression_kind_tracker,
5044            layouter: &mut crate::proc::Layouter::default(),
5045        };
5046
5047        let root1 = Expression::AccessIndex { base, index: 1 };
5048
5049        let res1 = solver
5050            .try_eval_and_append(root1, Default::default())
5051            .unwrap();
5052
5053        let root2 = Expression::AccessIndex {
5054            base: res1,
5055            index: 2,
5056        };
5057
5058        let res2 = solver
5059            .try_eval_and_append(root2, Default::default())
5060            .unwrap();
5061
5062        match global_expressions[res1] {
5063            Expression::Compose {
5064                ref ty,
5065                ref components,
5066            } => {
5067                assert_eq!(*ty, vec_ty);
5068                let mut components_iter = components.iter().copied();
5069                assert_eq!(
5070                    global_expressions[components_iter.next().unwrap()],
5071                    Expression::Literal(Literal::F32(3.))
5072                );
5073                assert_eq!(
5074                    global_expressions[components_iter.next().unwrap()],
5075                    Expression::Literal(Literal::F32(4.))
5076                );
5077                assert_eq!(
5078                    global_expressions[components_iter.next().unwrap()],
5079                    Expression::Literal(Literal::F32(5.))
5080                );
5081                assert!(components_iter.next().is_none());
5082            }
5083            _ => panic!("Expected vector"),
5084        }
5085
5086        assert_eq!(
5087            global_expressions[res2],
5088            Expression::Literal(Literal::F32(5.))
5089        );
5090    }
5091
5092    #[test]
5093    fn compose_of_constants() {
5094        let mut types = UniqueArena::new();
5095        let mut constants = Arena::new();
5096        let overrides = Arena::new();
5097        let mut global_expressions = Arena::new();
5098
5099        let i32_ty = types.insert(
5100            Type {
5101                name: None,
5102                inner: TypeInner::Scalar(crate::Scalar::I32),
5103            },
5104            Default::default(),
5105        );
5106
5107        let vec2_i32_ty = types.insert(
5108            Type {
5109                name: None,
5110                inner: TypeInner::Vector {
5111                    size: VectorSize::Bi,
5112                    scalar: crate::Scalar::I32,
5113                },
5114            },
5115            Default::default(),
5116        );
5117
5118        let h = constants.append(
5119            Constant {
5120                name: None,
5121                ty: i32_ty,
5122                init: global_expressions
5123                    .append(Expression::Literal(Literal::I32(4)), Default::default()),
5124            },
5125            Default::default(),
5126        );
5127
5128        let h_expr = global_expressions.append(Expression::Constant(h), Default::default());
5129
5130        let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
5131        let mut solver = ConstantEvaluator {
5132            behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
5133            types: &mut types,
5134            constants: &constants,
5135            overrides: &overrides,
5136            expressions: &mut global_expressions,
5137            expression_kind_tracker,
5138            layouter: &mut crate::proc::Layouter::default(),
5139        };
5140
5141        let solved_compose = solver
5142            .try_eval_and_append(
5143                Expression::Compose {
5144                    ty: vec2_i32_ty,
5145                    components: vec![h_expr, h_expr],
5146                },
5147                Default::default(),
5148            )
5149            .unwrap();
5150        let solved_negate = solver
5151            .try_eval_and_append(
5152                Expression::Unary {
5153                    op: UnaryOperator::Negate,
5154                    expr: solved_compose,
5155                },
5156                Default::default(),
5157            )
5158            .unwrap();
5159
5160        let pass = match global_expressions[solved_negate] {
5161            Expression::Compose { ty, ref components } => {
5162                ty == vec2_i32_ty
5163                    && components.iter().all(|&component| {
5164                        let component = &global_expressions[component];
5165                        matches!(*component, Expression::Literal(Literal::I32(-4)))
5166                    })
5167            }
5168            _ => false,
5169        };
5170        if !pass {
5171            panic!("unexpected evaluation result")
5172        }
5173    }
5174
5175    #[test]
5176    fn splat_of_constant() {
5177        let mut types = UniqueArena::new();
5178        let mut constants = Arena::new();
5179        let overrides = Arena::new();
5180        let mut global_expressions = Arena::new();
5181
5182        let i32_ty = types.insert(
5183            Type {
5184                name: None,
5185                inner: TypeInner::Scalar(crate::Scalar::I32),
5186            },
5187            Default::default(),
5188        );
5189
5190        let vec2_i32_ty = types.insert(
5191            Type {
5192                name: None,
5193                inner: TypeInner::Vector {
5194                    size: VectorSize::Bi,
5195                    scalar: crate::Scalar::I32,
5196                },
5197            },
5198            Default::default(),
5199        );
5200
5201        let h = constants.append(
5202            Constant {
5203                name: None,
5204                ty: i32_ty,
5205                init: global_expressions
5206                    .append(Expression::Literal(Literal::I32(4)), Default::default()),
5207            },
5208            Default::default(),
5209        );
5210
5211        let h_expr = global_expressions.append(Expression::Constant(h), Default::default());
5212
5213        let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
5214        let mut solver = ConstantEvaluator {
5215            behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
5216            types: &mut types,
5217            constants: &constants,
5218            overrides: &overrides,
5219            expressions: &mut global_expressions,
5220            expression_kind_tracker,
5221            layouter: &mut crate::proc::Layouter::default(),
5222        };
5223
5224        let solved_compose = solver
5225            .try_eval_and_append(
5226                Expression::Splat {
5227                    size: VectorSize::Bi,
5228                    value: h_expr,
5229                },
5230                Default::default(),
5231            )
5232            .unwrap();
5233        let solved_negate = solver
5234            .try_eval_and_append(
5235                Expression::Unary {
5236                    op: UnaryOperator::Negate,
5237                    expr: solved_compose,
5238                },
5239                Default::default(),
5240            )
5241            .unwrap();
5242
5243        let pass = match global_expressions[solved_negate] {
5244            Expression::Compose { ty, ref components } => {
5245                ty == vec2_i32_ty
5246                    && components.iter().all(|&component| {
5247                        let component = &global_expressions[component];
5248                        matches!(*component, Expression::Literal(Literal::I32(-4)))
5249                    })
5250            }
5251            _ => false,
5252        };
5253        if !pass {
5254            panic!("unexpected evaluation result")
5255        }
5256    }
5257
5258    #[test]
5259    fn splat_of_zero_value() {
5260        let mut types = UniqueArena::new();
5261        let constants = Arena::new();
5262        let overrides = Arena::new();
5263        let mut global_expressions = Arena::new();
5264
5265        let f32_ty = types.insert(
5266            Type {
5267                name: None,
5268                inner: TypeInner::Scalar(crate::Scalar::F32),
5269            },
5270            Default::default(),
5271        );
5272
5273        let vec2_f32_ty = types.insert(
5274            Type {
5275                name: None,
5276                inner: TypeInner::Vector {
5277                    size: VectorSize::Bi,
5278                    scalar: crate::Scalar::F32,
5279                },
5280            },
5281            Default::default(),
5282        );
5283
5284        let five =
5285            global_expressions.append(Expression::Literal(Literal::F32(5.0)), Default::default());
5286        let five_splat = global_expressions.append(
5287            Expression::Splat {
5288                size: VectorSize::Bi,
5289                value: five,
5290            },
5291            Default::default(),
5292        );
5293        let zero = global_expressions.append(Expression::ZeroValue(f32_ty), Default::default());
5294        let zero_splat = global_expressions.append(
5295            Expression::Splat {
5296                size: VectorSize::Bi,
5297                value: zero,
5298            },
5299            Default::default(),
5300        );
5301
5302        let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
5303        let mut solver = ConstantEvaluator {
5304            behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
5305            types: &mut types,
5306            constants: &constants,
5307            overrides: &overrides,
5308            expressions: &mut global_expressions,
5309            expression_kind_tracker,
5310            layouter: &mut crate::proc::Layouter::default(),
5311        };
5312
5313        let solved_add = solver
5314            .try_eval_and_append(
5315                Expression::Binary {
5316                    op: BinaryOperator::Add,
5317                    left: zero_splat,
5318                    right: five_splat,
5319                },
5320                Default::default(),
5321            )
5322            .unwrap();
5323
5324        let pass = match global_expressions[solved_add] {
5325            Expression::Compose { ty, ref components } => {
5326                ty == vec2_f32_ty
5327                    && components.iter().all(|&component| {
5328                        let component = &global_expressions[component];
5329                        matches!(*component, Expression::Literal(Literal::F32(5.0)))
5330                    })
5331            }
5332            _ => false,
5333        };
5334        if !pass {
5335            panic!("unexpected evaluation result")
5336        }
5337    }
5338}