naga/front/wgsl/lower/
mod.rs

1use alloc::{
2    borrow::ToOwned,
3    boxed::Box,
4    string::{String, ToString},
5    vec::Vec,
6};
7use core::num::NonZeroU32;
8
9use crate::common::wgsl::{TryToWgsl, TypeContext};
10use crate::common::ForDebugWithTypes;
11use crate::front::wgsl::error::{Error, ExpectedToken, InvalidAssignmentType};
12use crate::front::wgsl::index::Index;
13use crate::front::wgsl::parse::number::Number;
14use crate::front::wgsl::parse::{ast, conv};
15use crate::front::wgsl::Result;
16use crate::front::Typifier;
17use crate::proc::{
18    ensure_block_returns, Alignment, ConstantEvaluator, Emitter, Layouter, ResolveContext,
19};
20use crate::{Arena, FastHashMap, FastIndexMap, Handle, Span};
21
22mod construction;
23mod conversion;
24
25/// Resolves the inner type of a given expression.
26///
27/// Expects a &mut [`ExpressionContext`] and a [`Handle<Expression>`].
28///
29/// Returns a &[`crate::TypeInner`].
30///
31/// Ideally, we would simply have a function that takes a `&mut ExpressionContext`
32/// and returns a `&TypeResolution`. Unfortunately, this leads the borrow checker
33/// to conclude that the mutable borrow lasts for as long as we are using the
34/// `&TypeResolution`, so we can't use the `ExpressionContext` for anything else -
35/// like, say, resolving another operand's type. Using a macro that expands to
36/// two separate calls, only the first of which needs a `&mut`,
37/// lets the borrow checker see that the mutable borrow is over.
38macro_rules! resolve_inner {
39    ($ctx:ident, $expr:expr) => {{
40        $ctx.grow_types($expr)?;
41        $ctx.typifier()[$expr].inner_with(&$ctx.module.types)
42    }};
43}
44pub(super) use resolve_inner;
45
46/// Resolves the inner types of two given expressions.
47///
48/// Expects a &mut [`ExpressionContext`] and two [`Handle<Expression>`]s.
49///
50/// Returns a tuple containing two &[`crate::TypeInner`].
51///
52/// See the documentation of [`resolve_inner!`] for why this macro is necessary.
53macro_rules! resolve_inner_binary {
54    ($ctx:ident, $left:expr, $right:expr) => {{
55        $ctx.grow_types($left)?;
56        $ctx.grow_types($right)?;
57        (
58            $ctx.typifier()[$left].inner_with(&$ctx.module.types),
59            $ctx.typifier()[$right].inner_with(&$ctx.module.types),
60        )
61    }};
62}
63
64/// Resolves the type of a given expression.
65///
66/// Expects a &mut [`ExpressionContext`] and a [`Handle<Expression>`].
67///
68/// Returns a &[`TypeResolution`].
69///
70/// See the documentation of [`resolve_inner!`] for why this macro is necessary.
71///
72/// [`TypeResolution`]: crate::proc::TypeResolution
73macro_rules! resolve {
74    ($ctx:ident, $expr:expr) => {{
75        $ctx.grow_types($expr)?;
76        &$ctx.typifier()[$expr]
77    }};
78}
79pub(super) use resolve;
80
81/// State for constructing a `crate::Module`.
82pub struct GlobalContext<'source, 'temp, 'out> {
83    /// The `TranslationUnit`'s expressions arena.
84    ast_expressions: &'temp Arena<ast::Expression<'source>>,
85
86    /// The `TranslationUnit`'s types arena.
87    types: &'temp Arena<ast::Type<'source>>,
88
89    // Naga IR values.
90    /// The map from the names of module-scope declarations to the Naga IR
91    /// `Handle`s we have built for them, owned by `Lowerer::lower`.
92    globals: &'temp mut FastHashMap<&'source str, LoweredGlobalDecl>,
93
94    /// The module we're constructing.
95    module: &'out mut crate::Module,
96
97    const_typifier: &'temp mut Typifier,
98
99    layouter: &'temp mut Layouter,
100
101    global_expression_kind_tracker: &'temp mut crate::proc::ExpressionKindTracker,
102}
103
104impl<'source> GlobalContext<'source, '_, '_> {
105    fn as_const(&mut self) -> ExpressionContext<'source, '_, '_> {
106        ExpressionContext {
107            ast_expressions: self.ast_expressions,
108            globals: self.globals,
109            types: self.types,
110            module: self.module,
111            const_typifier: self.const_typifier,
112            layouter: self.layouter,
113            expr_type: ExpressionContextType::Constant(None),
114            global_expression_kind_tracker: self.global_expression_kind_tracker,
115        }
116    }
117
118    fn as_override(&mut self) -> ExpressionContext<'source, '_, '_> {
119        ExpressionContext {
120            ast_expressions: self.ast_expressions,
121            globals: self.globals,
122            types: self.types,
123            module: self.module,
124            const_typifier: self.const_typifier,
125            layouter: self.layouter,
126            expr_type: ExpressionContextType::Override,
127            global_expression_kind_tracker: self.global_expression_kind_tracker,
128        }
129    }
130
131    fn ensure_type_exists(
132        &mut self,
133        name: Option<String>,
134        inner: crate::TypeInner,
135    ) -> Handle<crate::Type> {
136        self.module
137            .types
138            .insert(crate::Type { inner, name }, Span::UNDEFINED)
139    }
140}
141
142/// State for lowering a statement within a function.
143pub struct StatementContext<'source, 'temp, 'out> {
144    // WGSL AST values.
145    /// A reference to [`TranslationUnit::expressions`] for the translation unit
146    /// we're lowering.
147    ///
148    /// [`TranslationUnit::expressions`]: ast::TranslationUnit::expressions
149    ast_expressions: &'temp Arena<ast::Expression<'source>>,
150
151    /// A reference to [`TranslationUnit::types`] for the translation unit
152    /// we're lowering.
153    ///
154    /// [`TranslationUnit::types`]: ast::TranslationUnit::types
155    types: &'temp Arena<ast::Type<'source>>,
156
157    // Naga IR values.
158    /// The map from the names of module-scope declarations to the Naga IR
159    /// `Handle`s we have built for them, owned by `Lowerer::lower`.
160    globals: &'temp mut FastHashMap<&'source str, LoweredGlobalDecl>,
161
162    /// A map from each `ast::Local` handle to the Naga expression
163    /// we've built for it:
164    ///
165    /// - WGSL function arguments become Naga [`FunctionArgument`] expressions.
166    ///
167    /// - WGSL `var` declarations become Naga [`LocalVariable`] expressions.
168    ///
169    /// - WGSL `let` declararations become arbitrary Naga expressions.
170    ///
171    /// This always borrows the `local_table` local variable in
172    /// [`Lowerer::function`].
173    ///
174    /// [`LocalVariable`]: crate::Expression::LocalVariable
175    /// [`FunctionArgument`]: crate::Expression::FunctionArgument
176    local_table:
177        &'temp mut FastHashMap<Handle<ast::Local>, Declared<Typed<Handle<crate::Expression>>>>,
178
179    const_typifier: &'temp mut Typifier,
180    typifier: &'temp mut Typifier,
181    layouter: &'temp mut Layouter,
182    function: &'out mut crate::Function,
183    /// Stores the names of expressions that are assigned in `let` statement
184    /// Also stores the spans of the names, for use in errors.
185    named_expressions: &'out mut FastIndexMap<Handle<crate::Expression>, (String, Span)>,
186    module: &'out mut crate::Module,
187
188    /// Which `Expression`s in `self.naga_expressions` are const expressions, in
189    /// the WGSL sense.
190    ///
191    /// According to the WGSL spec, a const expression must not refer to any
192    /// `let` declarations, even if those declarations' initializers are
193    /// themselves const expressions. So this tracker is not simply concerned
194    /// with the form of the expressions; it is also tracking whether WGSL says
195    /// we should consider them to be const. See the use of `force_non_const` in
196    /// the code for lowering `let` bindings.
197    local_expression_kind_tracker: &'temp mut crate::proc::ExpressionKindTracker,
198    global_expression_kind_tracker: &'temp mut crate::proc::ExpressionKindTracker,
199}
200
201impl<'a, 'temp> StatementContext<'a, 'temp, '_> {
202    fn as_const<'t>(
203        &'t mut self,
204        block: &'t mut crate::Block,
205        emitter: &'t mut Emitter,
206    ) -> ExpressionContext<'a, 't, 't>
207    where
208        'temp: 't,
209    {
210        ExpressionContext {
211            globals: self.globals,
212            types: self.types,
213            ast_expressions: self.ast_expressions,
214            const_typifier: self.const_typifier,
215            layouter: self.layouter,
216            global_expression_kind_tracker: self.global_expression_kind_tracker,
217            module: self.module,
218            expr_type: ExpressionContextType::Constant(Some(LocalExpressionContext {
219                local_table: self.local_table,
220                function: self.function,
221                block,
222                emitter,
223                typifier: self.typifier,
224                local_expression_kind_tracker: self.local_expression_kind_tracker,
225            })),
226        }
227    }
228
229    fn as_expression<'t>(
230        &'t mut self,
231        block: &'t mut crate::Block,
232        emitter: &'t mut Emitter,
233    ) -> ExpressionContext<'a, 't, 't>
234    where
235        'temp: 't,
236    {
237        ExpressionContext {
238            globals: self.globals,
239            types: self.types,
240            ast_expressions: self.ast_expressions,
241            const_typifier: self.const_typifier,
242            layouter: self.layouter,
243            global_expression_kind_tracker: self.global_expression_kind_tracker,
244            module: self.module,
245            expr_type: ExpressionContextType::Runtime(LocalExpressionContext {
246                local_table: self.local_table,
247                function: self.function,
248                block,
249                emitter,
250                typifier: self.typifier,
251                local_expression_kind_tracker: self.local_expression_kind_tracker,
252            }),
253        }
254    }
255
256    #[allow(dead_code)]
257    fn as_global(&mut self) -> GlobalContext<'a, '_, '_> {
258        GlobalContext {
259            ast_expressions: self.ast_expressions,
260            globals: self.globals,
261            types: self.types,
262            module: self.module,
263            const_typifier: self.const_typifier,
264            layouter: self.layouter,
265            global_expression_kind_tracker: self.global_expression_kind_tracker,
266        }
267    }
268
269    fn invalid_assignment_type(&self, expr: Handle<crate::Expression>) -> InvalidAssignmentType {
270        if let Some(&(_, span)) = self.named_expressions.get(&expr) {
271            InvalidAssignmentType::ImmutableBinding(span)
272        } else {
273            match self.function.expressions[expr] {
274                crate::Expression::Swizzle { .. } => InvalidAssignmentType::Swizzle,
275                crate::Expression::Access { base, .. } => self.invalid_assignment_type(base),
276                crate::Expression::AccessIndex { base, .. } => self.invalid_assignment_type(base),
277                _ => InvalidAssignmentType::Other,
278            }
279        }
280    }
281}
282
283pub struct LocalExpressionContext<'temp, 'out> {
284    /// A map from [`ast::Local`] handles to the Naga expressions we've built for them.
285    ///
286    /// This is always [`StatementContext::local_table`] for the
287    /// enclosing statement; see that documentation for details.
288    local_table: &'temp FastHashMap<Handle<ast::Local>, Declared<Typed<Handle<crate::Expression>>>>,
289
290    function: &'out mut crate::Function,
291    block: &'temp mut crate::Block,
292    emitter: &'temp mut Emitter,
293    typifier: &'temp mut Typifier,
294
295    /// Which `Expression`s in `self.naga_expressions` are const expressions, in
296    /// the WGSL sense.
297    ///
298    /// See [`StatementContext::local_expression_kind_tracker`] for details.
299    local_expression_kind_tracker: &'temp mut crate::proc::ExpressionKindTracker,
300}
301
302/// The type of Naga IR expression we are lowering an [`ast::Expression`] to.
303pub enum ExpressionContextType<'temp, 'out> {
304    /// We are lowering to an arbitrary runtime expression, to be
305    /// included in a function's body.
306    ///
307    /// The given [`LocalExpressionContext`] holds information about local
308    /// variables, arguments, and other definitions available only to runtime
309    /// expressions, not constant or override expressions.
310    Runtime(LocalExpressionContext<'temp, 'out>),
311
312    /// We are lowering to a constant expression, to be included in the module's
313    /// constant expression arena.
314    ///
315    /// Everything global constant expressions are allowed to refer to is
316    /// available in the [`ExpressionContext`], but local constant expressions can
317    /// also refer to other
318    Constant(Option<LocalExpressionContext<'temp, 'out>>),
319
320    /// We are lowering to an override expression, to be included in the module's
321    /// constant expression arena.
322    ///
323    /// Everything override expressions are allowed to refer to is
324    /// available in the [`ExpressionContext`], so this variant
325    /// carries no further information.
326    Override,
327}
328
329/// State for lowering an [`ast::Expression`] to Naga IR.
330///
331/// [`ExpressionContext`]s come in two kinds, distinguished by
332/// the value of the [`expr_type`] field:
333///
334/// - A [`Runtime`] context contributes [`naga::Expression`]s to a [`naga::Function`]'s
335///   runtime expression arena.
336///
337/// - A [`Constant`] context contributes [`naga::Expression`]s to a [`naga::Module`]'s
338///   constant expression arena.
339///
340/// [`ExpressionContext`]s are constructed in restricted ways:
341///
342/// - To get a [`Runtime`] [`ExpressionContext`], call
343///   [`StatementContext::as_expression`].
344///
345/// - To get a [`Constant`] [`ExpressionContext`], call
346///   [`GlobalContext::as_const`].
347///
348/// - You can demote a [`Runtime`] context to a [`Constant`] context
349///   by calling [`as_const`], but there's no way to go in the other
350///   direction, producing a runtime context from a constant one. This
351///   is because runtime expressions can refer to constant
352///   expressions, via [`Expression::Constant`], but constant
353///   expressions can't refer to a function's expressions.
354///
355/// Not to be confused with `wgsl::parse::ExpressionContext`, which is
356/// for parsing the `ast::Expression` in the first place.
357///
358/// [`expr_type`]: ExpressionContext::expr_type
359/// [`Runtime`]: ExpressionContextType::Runtime
360/// [`naga::Expression`]: crate::Expression
361/// [`naga::Function`]: crate::Function
362/// [`Constant`]: ExpressionContextType::Constant
363/// [`naga::Module`]: crate::Module
364/// [`as_const`]: ExpressionContext::as_const
365/// [`Expression::Constant`]: crate::Expression::Constant
366pub struct ExpressionContext<'source, 'temp, 'out> {
367    // WGSL AST values.
368    ast_expressions: &'temp Arena<ast::Expression<'source>>,
369    types: &'temp Arena<ast::Type<'source>>,
370
371    // Naga IR values.
372    /// The map from the names of module-scope declarations to the Naga IR
373    /// `Handle`s we have built for them, owned by `Lowerer::lower`.
374    globals: &'temp mut FastHashMap<&'source str, LoweredGlobalDecl>,
375
376    /// The IR [`Module`] we're constructing.
377    ///
378    /// [`Module`]: crate::Module
379    module: &'out mut crate::Module,
380
381    /// Type judgments for [`module::global_expressions`].
382    ///
383    /// [`module::global_expressions`]: crate::Module::global_expressions
384    const_typifier: &'temp mut Typifier,
385    layouter: &'temp mut Layouter,
386    global_expression_kind_tracker: &'temp mut crate::proc::ExpressionKindTracker,
387
388    /// Whether we are lowering a constant expression or a general
389    /// runtime expression, and the data needed in each case.
390    expr_type: ExpressionContextType<'temp, 'out>,
391}
392
393impl TypeContext for ExpressionContext<'_, '_, '_> {
394    fn lookup_type(&self, handle: Handle<crate::Type>) -> &crate::Type {
395        &self.module.types[handle]
396    }
397
398    fn type_name(&self, handle: Handle<crate::Type>) -> &str {
399        self.module.types[handle]
400            .name
401            .as_deref()
402            .unwrap_or("{anonymous type}")
403    }
404
405    fn write_override<W: core::fmt::Write>(
406        &self,
407        handle: Handle<crate::Override>,
408        out: &mut W,
409    ) -> core::fmt::Result {
410        match self.module.overrides[handle].name {
411            Some(ref name) => out.write_str(name),
412            None => write!(out, "{{anonymous override {handle:?}}}"),
413        }
414    }
415
416    fn write_unnamed_struct<W: core::fmt::Write>(
417        &self,
418        _: &crate::TypeInner,
419        _: &mut W,
420    ) -> core::fmt::Result {
421        unreachable!("the WGSL front end should always know the type name");
422    }
423}
424
425impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> {
426    #[allow(dead_code)]
427    fn as_const(&mut self) -> ExpressionContext<'source, '_, '_> {
428        ExpressionContext {
429            globals: self.globals,
430            types: self.types,
431            ast_expressions: self.ast_expressions,
432            const_typifier: self.const_typifier,
433            layouter: self.layouter,
434            module: self.module,
435            expr_type: ExpressionContextType::Constant(match self.expr_type {
436                ExpressionContextType::Runtime(ref mut local_expression_context)
437                | ExpressionContextType::Constant(Some(ref mut local_expression_context)) => {
438                    Some(LocalExpressionContext {
439                        local_table: local_expression_context.local_table,
440                        function: local_expression_context.function,
441                        block: local_expression_context.block,
442                        emitter: local_expression_context.emitter,
443                        typifier: local_expression_context.typifier,
444                        local_expression_kind_tracker: local_expression_context
445                            .local_expression_kind_tracker,
446                    })
447                }
448                ExpressionContextType::Constant(None) | ExpressionContextType::Override => None,
449            }),
450            global_expression_kind_tracker: self.global_expression_kind_tracker,
451        }
452    }
453
454    fn as_global(&mut self) -> GlobalContext<'source, '_, '_> {
455        GlobalContext {
456            ast_expressions: self.ast_expressions,
457            globals: self.globals,
458            types: self.types,
459            module: self.module,
460            const_typifier: self.const_typifier,
461            layouter: self.layouter,
462            global_expression_kind_tracker: self.global_expression_kind_tracker,
463        }
464    }
465
466    fn as_const_evaluator(&mut self) -> ConstantEvaluator {
467        match self.expr_type {
468            ExpressionContextType::Runtime(ref mut rctx) => ConstantEvaluator::for_wgsl_function(
469                self.module,
470                &mut rctx.function.expressions,
471                rctx.local_expression_kind_tracker,
472                self.layouter,
473                rctx.emitter,
474                rctx.block,
475                false,
476            ),
477            ExpressionContextType::Constant(Some(ref mut rctx)) => {
478                ConstantEvaluator::for_wgsl_function(
479                    self.module,
480                    &mut rctx.function.expressions,
481                    rctx.local_expression_kind_tracker,
482                    self.layouter,
483                    rctx.emitter,
484                    rctx.block,
485                    true,
486                )
487            }
488            ExpressionContextType::Constant(None) => ConstantEvaluator::for_wgsl_module(
489                self.module,
490                self.global_expression_kind_tracker,
491                self.layouter,
492                false,
493            ),
494            ExpressionContextType::Override => ConstantEvaluator::for_wgsl_module(
495                self.module,
496                self.global_expression_kind_tracker,
497                self.layouter,
498                true,
499            ),
500        }
501    }
502
503    /// Return a wrapper around `value` suitable for formatting.
504    ///
505    /// Return a wrapper around `value` that implements
506    /// [`core::fmt::Display`] in a form suitable for use in
507    /// diagnostic messages.
508    fn as_diagnostic_display<T>(
509        &self,
510        value: T,
511    ) -> crate::common::DiagnosticDisplay<(T, crate::proc::GlobalCtx)> {
512        let ctx = self.module.to_ctx();
513        crate::common::DiagnosticDisplay((value, ctx))
514    }
515
516    fn append_expression(
517        &mut self,
518        expr: crate::Expression,
519        span: Span,
520    ) -> Result<'source, Handle<crate::Expression>> {
521        let mut eval = self.as_const_evaluator();
522        eval.try_eval_and_append(expr, span)
523            .map_err(|e| Box::new(Error::ConstantEvaluatorError(e.into(), span)))
524    }
525
526    fn const_eval_expr_to_u32(
527        &self,
528        handle: Handle<crate::Expression>,
529    ) -> core::result::Result<u32, crate::proc::U32EvalError> {
530        match self.expr_type {
531            ExpressionContextType::Runtime(ref ctx) => {
532                if !ctx.local_expression_kind_tracker.is_const(handle) {
533                    return Err(crate::proc::U32EvalError::NonConst);
534                }
535
536                self.module
537                    .to_ctx()
538                    .eval_expr_to_u32_from(handle, &ctx.function.expressions)
539            }
540            ExpressionContextType::Constant(Some(ref ctx)) => {
541                assert!(ctx.local_expression_kind_tracker.is_const(handle));
542                self.module
543                    .to_ctx()
544                    .eval_expr_to_u32_from(handle, &ctx.function.expressions)
545            }
546            ExpressionContextType::Constant(None) => self.module.to_ctx().eval_expr_to_u32(handle),
547            ExpressionContextType::Override => Err(crate::proc::U32EvalError::NonConst),
548        }
549    }
550
551    /// Return `true` if `handle` is a constant expression.
552    fn is_const(&self, handle: Handle<crate::Expression>) -> bool {
553        use ExpressionContextType as Ect;
554        match self.expr_type {
555            Ect::Runtime(ref ctx) | Ect::Constant(Some(ref ctx)) => {
556                ctx.local_expression_kind_tracker.is_const(handle)
557            }
558            Ect::Constant(None) | Ect::Override => {
559                self.global_expression_kind_tracker.is_const(handle)
560            }
561        }
562    }
563
564    fn get_expression_span(&self, handle: Handle<crate::Expression>) -> Span {
565        match self.expr_type {
566            ExpressionContextType::Runtime(ref ctx)
567            | ExpressionContextType::Constant(Some(ref ctx)) => {
568                ctx.function.expressions.get_span(handle)
569            }
570            ExpressionContextType::Constant(None) | ExpressionContextType::Override => {
571                self.module.global_expressions.get_span(handle)
572            }
573        }
574    }
575
576    fn typifier(&self) -> &Typifier {
577        match self.expr_type {
578            ExpressionContextType::Runtime(ref ctx)
579            | ExpressionContextType::Constant(Some(ref ctx)) => ctx.typifier,
580            ExpressionContextType::Constant(None) | ExpressionContextType::Override => {
581                self.const_typifier
582            }
583        }
584    }
585
586    fn local(
587        &mut self,
588        local: &Handle<ast::Local>,
589        span: Span,
590    ) -> Result<'source, Typed<Handle<crate::Expression>>> {
591        match self.expr_type {
592            ExpressionContextType::Runtime(ref ctx) => Ok(ctx.local_table[local].runtime()),
593            ExpressionContextType::Constant(Some(ref ctx)) => ctx.local_table[local]
594                .const_time()
595                .ok_or(Box::new(Error::UnexpectedOperationInConstContext(span))),
596            _ => Err(Box::new(Error::UnexpectedOperationInConstContext(span))),
597        }
598    }
599
600    fn runtime_expression_ctx(
601        &mut self,
602        span: Span,
603    ) -> Result<'source, &mut LocalExpressionContext<'temp, 'out>> {
604        match self.expr_type {
605            ExpressionContextType::Runtime(ref mut ctx) => Ok(ctx),
606            ExpressionContextType::Constant(_) | ExpressionContextType::Override => {
607                Err(Box::new(Error::UnexpectedOperationInConstContext(span)))
608            }
609        }
610    }
611
612    fn gather_component(
613        &mut self,
614        expr: Handle<crate::Expression>,
615        component_span: Span,
616        gather_span: Span,
617    ) -> Result<'source, crate::SwizzleComponent> {
618        match self.expr_type {
619            ExpressionContextType::Runtime(ref rctx) => {
620                if !rctx.local_expression_kind_tracker.is_const(expr) {
621                    return Err(Box::new(Error::ExpectedConstExprConcreteIntegerScalar(
622                        component_span,
623                    )));
624                }
625
626                let index = self
627                    .module
628                    .to_ctx()
629                    .eval_expr_to_u32_from(expr, &rctx.function.expressions)
630                    .map_err(|err| match err {
631                        crate::proc::U32EvalError::NonConst => {
632                            Error::ExpectedConstExprConcreteIntegerScalar(component_span)
633                        }
634                        crate::proc::U32EvalError::Negative => {
635                            Error::ExpectedNonNegative(component_span)
636                        }
637                    })?;
638                crate::SwizzleComponent::XYZW
639                    .get(index as usize)
640                    .copied()
641                    .ok_or(Box::new(Error::InvalidGatherComponent(component_span)))
642            }
643            // This means a `gather` operation appeared in a constant expression.
644            // This error refers to the `gather` itself, not its "component" argument.
645            ExpressionContextType::Constant(_) | ExpressionContextType::Override => Err(Box::new(
646                Error::UnexpectedOperationInConstContext(gather_span),
647            )),
648        }
649    }
650
651    /// Determine the type of `handle`, and add it to the module's arena.
652    ///
653    /// If you just need a `TypeInner` for `handle`'s type, use the
654    /// [`resolve_inner!`] macro instead. This function
655    /// should only be used when the type of `handle` needs to appear
656    /// in the module's final `Arena<Type>`, for example, if you're
657    /// creating a [`LocalVariable`] whose type is inferred from its
658    /// initializer.
659    ///
660    /// [`LocalVariable`]: crate::LocalVariable
661    fn register_type(
662        &mut self,
663        handle: Handle<crate::Expression>,
664    ) -> Result<'source, Handle<crate::Type>> {
665        self.grow_types(handle)?;
666        // This is equivalent to calling ExpressionContext::typifier(),
667        // except that this lets the borrow checker see that it's okay
668        // to also borrow self.module.types mutably below.
669        let typifier = match self.expr_type {
670            ExpressionContextType::Runtime(ref ctx)
671            | ExpressionContextType::Constant(Some(ref ctx)) => ctx.typifier,
672            ExpressionContextType::Constant(None) | ExpressionContextType::Override => {
673                &*self.const_typifier
674            }
675        };
676        Ok(typifier.register_type(handle, &mut self.module.types))
677    }
678
679    /// Resolve the types of all expressions up through `handle`.
680    ///
681    /// Ensure that [`self.typifier`] has a [`TypeResolution`] for
682    /// every expression in [`self.function.expressions`].
683    ///
684    /// This does not add types to any arena. The [`Typifier`]
685    /// documentation explains the steps we take to avoid filling
686    /// arenas with intermediate types.
687    ///
688    /// This function takes `&mut self`, so it can't conveniently
689    /// return a shared reference to the resulting `TypeResolution`:
690    /// the shared reference would extend the mutable borrow, and you
691    /// wouldn't be able to use `self` for anything else. Instead, you
692    /// should use [`register_type`] or one of [`resolve!`],
693    /// [`resolve_inner!`] or [`resolve_inner_binary!`].
694    ///
695    /// [`self.typifier`]: ExpressionContext::typifier
696    /// [`TypeResolution`]: crate::proc::TypeResolution
697    /// [`register_type`]: Self::register_type
698    /// [`Typifier`]: Typifier
699    fn grow_types(&mut self, handle: Handle<crate::Expression>) -> Result<'source, &mut Self> {
700        let empty_arena = Arena::new();
701        let resolve_ctx;
702        let typifier;
703        let expressions;
704        match self.expr_type {
705            ExpressionContextType::Runtime(ref mut ctx)
706            | ExpressionContextType::Constant(Some(ref mut ctx)) => {
707                resolve_ctx = ResolveContext::with_locals(
708                    self.module,
709                    &ctx.function.local_variables,
710                    &ctx.function.arguments,
711                );
712                typifier = &mut *ctx.typifier;
713                expressions = &ctx.function.expressions;
714            }
715            ExpressionContextType::Constant(None) | ExpressionContextType::Override => {
716                resolve_ctx = ResolveContext::with_locals(self.module, &empty_arena, &[]);
717                typifier = self.const_typifier;
718                expressions = &self.module.global_expressions;
719            }
720        };
721        typifier
722            .grow(handle, expressions, &resolve_ctx)
723            .map_err(Error::InvalidResolve)?;
724
725        Ok(self)
726    }
727
728    fn image_data(
729        &mut self,
730        image: Handle<crate::Expression>,
731        span: Span,
732    ) -> Result<'source, (crate::ImageClass, bool)> {
733        match *resolve_inner!(self, image) {
734            crate::TypeInner::Image { class, arrayed, .. } => Ok((class, arrayed)),
735            _ => Err(Box::new(Error::BadTexture(span))),
736        }
737    }
738
739    fn prepare_args<'b>(
740        &mut self,
741        args: &'b [Handle<ast::Expression<'source>>],
742        min_args: u32,
743        span: Span,
744    ) -> ArgumentContext<'b, 'source> {
745        ArgumentContext {
746            args: args.iter(),
747            min_args,
748            args_used: 0,
749            total_args: args.len() as u32,
750            span,
751        }
752    }
753
754    /// Insert splats, if needed by the non-'*' operations.
755    ///
756    /// See the "Binary arithmetic expressions with mixed scalar and vector operands"
757    /// table in the WebGPU Shading Language specification for relevant operators.
758    ///
759    /// Multiply is not handled here as backends are expected to handle vec*scalar
760    /// operations, so inserting splats into the IR increases size needlessly.
761    fn binary_op_splat(
762        &mut self,
763        op: crate::BinaryOperator,
764        left: &mut Handle<crate::Expression>,
765        right: &mut Handle<crate::Expression>,
766    ) -> Result<'source, ()> {
767        if matches!(
768            op,
769            crate::BinaryOperator::Add
770                | crate::BinaryOperator::Subtract
771                | crate::BinaryOperator::Divide
772                | crate::BinaryOperator::Modulo
773        ) {
774            match resolve_inner_binary!(self, *left, *right) {
775                (&crate::TypeInner::Vector { size, .. }, &crate::TypeInner::Scalar { .. }) => {
776                    *right = self.append_expression(
777                        crate::Expression::Splat {
778                            size,
779                            value: *right,
780                        },
781                        self.get_expression_span(*right),
782                    )?;
783                }
784                (&crate::TypeInner::Scalar { .. }, &crate::TypeInner::Vector { size, .. }) => {
785                    *left = self.append_expression(
786                        crate::Expression::Splat { size, value: *left },
787                        self.get_expression_span(*left),
788                    )?;
789                }
790                _ => {}
791            }
792        }
793
794        Ok(())
795    }
796
797    /// Add a single expression to the expression table that is not covered by `self.emitter`.
798    ///
799    /// This is useful for `CallResult` and `AtomicResult` expressions, which should not be covered by
800    /// `Emit` statements.
801    fn interrupt_emitter(
802        &mut self,
803        expression: crate::Expression,
804        span: Span,
805    ) -> Result<'source, Handle<crate::Expression>> {
806        match self.expr_type {
807            ExpressionContextType::Runtime(ref mut rctx)
808            | ExpressionContextType::Constant(Some(ref mut rctx)) => {
809                rctx.block
810                    .extend(rctx.emitter.finish(&rctx.function.expressions));
811            }
812            ExpressionContextType::Constant(None) | ExpressionContextType::Override => {}
813        }
814        let result = self.append_expression(expression, span);
815        match self.expr_type {
816            ExpressionContextType::Runtime(ref mut rctx)
817            | ExpressionContextType::Constant(Some(ref mut rctx)) => {
818                rctx.emitter.start(&rctx.function.expressions);
819            }
820            ExpressionContextType::Constant(None) | ExpressionContextType::Override => {}
821        }
822        result
823    }
824
825    /// Apply the WGSL Load Rule to `expr`.
826    ///
827    /// If `expr` is has type `ref<SC, T, A>`, perform a load to produce a value of type
828    /// `T`. Otherwise, return `expr` unchanged.
829    fn apply_load_rule(
830        &mut self,
831        expr: Typed<Handle<crate::Expression>>,
832    ) -> Result<'source, Handle<crate::Expression>> {
833        match expr {
834            Typed::Reference(pointer) => {
835                let load = crate::Expression::Load { pointer };
836                let span = self.get_expression_span(pointer);
837                self.append_expression(load, span)
838            }
839            Typed::Plain(handle) => Ok(handle),
840        }
841    }
842
843    fn ensure_type_exists(&mut self, inner: crate::TypeInner) -> Handle<crate::Type> {
844        self.as_global().ensure_type_exists(None, inner)
845    }
846}
847
848struct ArgumentContext<'ctx, 'source> {
849    args: core::slice::Iter<'ctx, Handle<ast::Expression<'source>>>,
850    min_args: u32,
851    args_used: u32,
852    total_args: u32,
853    span: Span,
854}
855
856impl<'source> ArgumentContext<'_, 'source> {
857    pub fn finish(self) -> Result<'source, ()> {
858        if self.args.len() == 0 {
859            Ok(())
860        } else {
861            Err(Box::new(Error::WrongArgumentCount {
862                found: self.total_args,
863                expected: self.min_args..self.args_used + 1,
864                span: self.span,
865            }))
866        }
867    }
868
869    pub fn next(&mut self) -> Result<'source, Handle<ast::Expression<'source>>> {
870        match self.args.next().copied() {
871            Some(arg) => {
872                self.args_used += 1;
873                Ok(arg)
874            }
875            None => Err(Box::new(Error::WrongArgumentCount {
876                found: self.total_args,
877                expected: self.min_args..self.args_used + 1,
878                span: self.span,
879            })),
880        }
881    }
882}
883
884#[derive(Debug, Copy, Clone)]
885enum Declared<T> {
886    /// Value declared as const
887    Const(T),
888
889    /// Value declared as non-const
890    Runtime(T),
891}
892
893impl<T> Declared<T> {
894    fn runtime(self) -> T {
895        match self {
896            Declared::Const(t) | Declared::Runtime(t) => t,
897        }
898    }
899
900    fn const_time(self) -> Option<T> {
901        match self {
902            Declared::Const(t) => Some(t),
903            Declared::Runtime(_) => None,
904        }
905    }
906}
907
908/// WGSL type annotations on expressions, types, values, etc.
909///
910/// Naga and WGSL types are very close, but Naga lacks WGSL's `ref` types, which
911/// we need to know to apply the Load Rule. This enum carries some WGSL or Naga
912/// datum along with enough information to determine its corresponding WGSL
913/// type.
914///
915/// The `T` type parameter can be any expression-like thing:
916///
917/// - `Typed<Handle<crate::Type>>` can represent a full WGSL type. For example,
918///   given some Naga `Pointer` type `ptr`, a WGSL reference type is a
919///   `Typed::Reference(ptr)` whereas a WGSL pointer type is a
920///   `Typed::Plain(ptr)`.
921///
922/// - `Typed<crate::Expression>` or `Typed<Handle<crate::Expression>>` can
923///   represent references similarly.
924///
925/// Use the `map` and `try_map` methods to convert from one expression
926/// representation to another.
927///
928/// [`Expression`]: crate::Expression
929#[derive(Debug, Copy, Clone)]
930enum Typed<T> {
931    /// A WGSL reference.
932    Reference(T),
933
934    /// A WGSL plain type.
935    Plain(T),
936}
937
938impl<T> Typed<T> {
939    fn map<U>(self, mut f: impl FnMut(T) -> U) -> Typed<U> {
940        match self {
941            Self::Reference(v) => Typed::Reference(f(v)),
942            Self::Plain(v) => Typed::Plain(f(v)),
943        }
944    }
945
946    fn try_map<U, E>(
947        self,
948        mut f: impl FnMut(T) -> core::result::Result<U, E>,
949    ) -> core::result::Result<Typed<U>, E> {
950        Ok(match self {
951            Self::Reference(expr) => Typed::Reference(f(expr)?),
952            Self::Plain(expr) => Typed::Plain(f(expr)?),
953        })
954    }
955}
956
957/// A single vector component or swizzle.
958///
959/// This represents the things that can appear after the `.` in a vector access
960/// expression: either a single component name, or a series of them,
961/// representing a swizzle.
962enum Components {
963    Single(u32),
964    Swizzle {
965        size: crate::VectorSize,
966        pattern: [crate::SwizzleComponent; 4],
967    },
968}
969
970impl Components {
971    const fn letter_component(letter: char) -> Option<crate::SwizzleComponent> {
972        use crate::SwizzleComponent as Sc;
973        match letter {
974            'x' | 'r' => Some(Sc::X),
975            'y' | 'g' => Some(Sc::Y),
976            'z' | 'b' => Some(Sc::Z),
977            'w' | 'a' => Some(Sc::W),
978            _ => None,
979        }
980    }
981
982    fn single_component(name: &str, name_span: Span) -> Result<u32> {
983        let ch = name.chars().next().ok_or(Error::BadAccessor(name_span))?;
984        match Self::letter_component(ch) {
985            Some(sc) => Ok(sc as u32),
986            None => Err(Box::new(Error::BadAccessor(name_span))),
987        }
988    }
989
990    /// Construct a `Components` value from a 'member' name, like `"wzy"` or `"x"`.
991    ///
992    /// Use `name_span` for reporting errors in parsing the component string.
993    fn new(name: &str, name_span: Span) -> Result<Self> {
994        let size = match name.len() {
995            1 => return Ok(Components::Single(Self::single_component(name, name_span)?)),
996            2 => crate::VectorSize::Bi,
997            3 => crate::VectorSize::Tri,
998            4 => crate::VectorSize::Quad,
999            _ => return Err(Box::new(Error::BadAccessor(name_span))),
1000        };
1001
1002        let mut pattern = [crate::SwizzleComponent::X; 4];
1003        for (comp, ch) in pattern.iter_mut().zip(name.chars()) {
1004            *comp = Self::letter_component(ch).ok_or(Error::BadAccessor(name_span))?;
1005        }
1006
1007        if name.chars().all(|c| matches!(c, 'x' | 'y' | 'z' | 'w'))
1008            || name.chars().all(|c| matches!(c, 'r' | 'g' | 'b' | 'a'))
1009        {
1010            Ok(Components::Swizzle { size, pattern })
1011        } else {
1012            Err(Box::new(Error::BadAccessor(name_span)))
1013        }
1014    }
1015}
1016
1017/// An `ast::GlobalDecl` for which we have built the Naga IR equivalent.
1018enum LoweredGlobalDecl {
1019    Function {
1020        handle: Handle<crate::Function>,
1021        must_use: bool,
1022    },
1023    Var(Handle<crate::GlobalVariable>),
1024    Const(Handle<crate::Constant>),
1025    Override(Handle<crate::Override>),
1026    Type(Handle<crate::Type>),
1027    EntryPoint,
1028}
1029
1030enum Texture {
1031    Gather,
1032    GatherCompare,
1033
1034    Sample,
1035    SampleBias,
1036    SampleCompare,
1037    SampleCompareLevel,
1038    SampleGrad,
1039    SampleLevel,
1040    // SampleBaseClampToEdge,
1041}
1042
1043impl Texture {
1044    pub fn map(word: &str) -> Option<Self> {
1045        Some(match word {
1046            "textureGather" => Self::Gather,
1047            "textureGatherCompare" => Self::GatherCompare,
1048
1049            "textureSample" => Self::Sample,
1050            "textureSampleBias" => Self::SampleBias,
1051            "textureSampleCompare" => Self::SampleCompare,
1052            "textureSampleCompareLevel" => Self::SampleCompareLevel,
1053            "textureSampleGrad" => Self::SampleGrad,
1054            "textureSampleLevel" => Self::SampleLevel,
1055            // "textureSampleBaseClampToEdge" => Some(Self::SampleBaseClampToEdge),
1056            _ => return None,
1057        })
1058    }
1059
1060    pub const fn min_argument_count(&self) -> u32 {
1061        match *self {
1062            Self::Gather => 3,
1063            Self::GatherCompare => 4,
1064
1065            Self::Sample => 3,
1066            Self::SampleBias => 5,
1067            Self::SampleCompare => 5,
1068            Self::SampleCompareLevel => 5,
1069            Self::SampleGrad => 6,
1070            Self::SampleLevel => 5,
1071            // Self::SampleBaseClampToEdge => 3,
1072        }
1073    }
1074}
1075
1076enum SubgroupGather {
1077    BroadcastFirst,
1078    Broadcast,
1079    Shuffle,
1080    ShuffleDown,
1081    ShuffleUp,
1082    ShuffleXor,
1083}
1084
1085impl SubgroupGather {
1086    pub fn map(word: &str) -> Option<Self> {
1087        Some(match word {
1088            "subgroupBroadcastFirst" => Self::BroadcastFirst,
1089            "subgroupBroadcast" => Self::Broadcast,
1090            "subgroupShuffle" => Self::Shuffle,
1091            "subgroupShuffleDown" => Self::ShuffleDown,
1092            "subgroupShuffleUp" => Self::ShuffleUp,
1093            "subgroupShuffleXor" => Self::ShuffleXor,
1094            _ => return None,
1095        })
1096    }
1097}
1098
1099/// Whether a declaration accepts abstract types, or concretizes.
1100enum AbstractRule {
1101    /// This declaration concretizes its initialization expression.
1102    Concretize,
1103
1104    /// This declaration can accept initializers with abstract types.
1105    Allow,
1106}
1107
1108pub struct Lowerer<'source, 'temp> {
1109    index: &'temp Index<'source>,
1110}
1111
1112impl<'source, 'temp> Lowerer<'source, 'temp> {
1113    pub const fn new(index: &'temp Index<'source>) -> Self {
1114        Self { index }
1115    }
1116
1117    pub fn lower(&mut self, tu: ast::TranslationUnit<'source>) -> Result<'source, crate::Module> {
1118        let mut module = crate::Module {
1119            diagnostic_filters: tu.diagnostic_filters,
1120            diagnostic_filter_leaf: tu.diagnostic_filter_leaf,
1121            ..Default::default()
1122        };
1123
1124        let mut ctx = GlobalContext {
1125            ast_expressions: &tu.expressions,
1126            globals: &mut FastHashMap::default(),
1127            types: &tu.types,
1128            module: &mut module,
1129            const_typifier: &mut Typifier::new(),
1130            layouter: &mut Layouter::default(),
1131            global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker::new(),
1132        };
1133
1134        for decl_handle in self.index.visit_ordered() {
1135            let span = tu.decls.get_span(decl_handle);
1136            let decl = &tu.decls[decl_handle];
1137
1138            match decl.kind {
1139                ast::GlobalDeclKind::Fn(ref f) => {
1140                    let lowered_decl = self.function(f, span, &mut ctx)?;
1141                    ctx.globals.insert(f.name.name, lowered_decl);
1142                }
1143                ast::GlobalDeclKind::Var(ref v) => {
1144                    let explicit_ty =
1145                        v.ty.map(|ast| self.resolve_ast_type(ast, &mut ctx.as_const()))
1146                            .transpose()?;
1147
1148                    let (ty, initializer) = self.type_and_init(
1149                        v.name,
1150                        v.init,
1151                        explicit_ty,
1152                        AbstractRule::Concretize,
1153                        &mut ctx.as_override(),
1154                    )?;
1155
1156                    let binding = if let Some(ref binding) = v.binding {
1157                        Some(crate::ResourceBinding {
1158                            group: self.const_u32(binding.group, &mut ctx.as_const())?.0,
1159                            binding: self.const_u32(binding.binding, &mut ctx.as_const())?.0,
1160                        })
1161                    } else {
1162                        None
1163                    };
1164
1165                    let handle = ctx.module.global_variables.append(
1166                        crate::GlobalVariable {
1167                            name: Some(v.name.name.to_string()),
1168                            space: v.space,
1169                            binding,
1170                            ty,
1171                            init: initializer,
1172                        },
1173                        span,
1174                    );
1175
1176                    ctx.globals
1177                        .insert(v.name.name, LoweredGlobalDecl::Var(handle));
1178                }
1179                ast::GlobalDeclKind::Const(ref c) => {
1180                    let mut ectx = ctx.as_const();
1181
1182                    let explicit_ty =
1183                        c.ty.map(|ast| self.resolve_ast_type(ast, &mut ectx))
1184                            .transpose()?;
1185
1186                    let (ty, init) = self.type_and_init(
1187                        c.name,
1188                        Some(c.init),
1189                        explicit_ty,
1190                        AbstractRule::Allow,
1191                        &mut ectx,
1192                    )?;
1193                    let init = init.expect("Global const must have init");
1194
1195                    let handle = ctx.module.constants.append(
1196                        crate::Constant {
1197                            name: Some(c.name.name.to_string()),
1198                            ty,
1199                            init,
1200                        },
1201                        span,
1202                    );
1203
1204                    ctx.globals
1205                        .insert(c.name.name, LoweredGlobalDecl::Const(handle));
1206                }
1207                ast::GlobalDeclKind::Override(ref o) => {
1208                    let explicit_ty =
1209                        o.ty.map(|ast| self.resolve_ast_type(ast, &mut ctx.as_const()))
1210                            .transpose()?;
1211
1212                    let mut ectx = ctx.as_override();
1213
1214                    let (ty, init) = self.type_and_init(
1215                        o.name,
1216                        o.init,
1217                        explicit_ty,
1218                        AbstractRule::Concretize,
1219                        &mut ectx,
1220                    )?;
1221
1222                    let id =
1223                        o.id.map(|id| self.const_u32(id, &mut ctx.as_const()))
1224                            .transpose()?;
1225
1226                    let id = if let Some((id, id_span)) = id {
1227                        Some(
1228                            u16::try_from(id)
1229                                .map_err(|_| Error::PipelineConstantIDValue(id_span))?,
1230                        )
1231                    } else {
1232                        None
1233                    };
1234
1235                    let handle = ctx.module.overrides.append(
1236                        crate::Override {
1237                            name: Some(o.name.name.to_string()),
1238                            id,
1239                            ty,
1240                            init,
1241                        },
1242                        span,
1243                    );
1244
1245                    ctx.globals
1246                        .insert(o.name.name, LoweredGlobalDecl::Override(handle));
1247                }
1248                ast::GlobalDeclKind::Struct(ref s) => {
1249                    let handle = self.r#struct(s, span, &mut ctx)?;
1250                    ctx.globals
1251                        .insert(s.name.name, LoweredGlobalDecl::Type(handle));
1252                }
1253                ast::GlobalDeclKind::Type(ref alias) => {
1254                    let ty = self.resolve_named_ast_type(
1255                        alias.ty,
1256                        Some(alias.name.name.to_string()),
1257                        &mut ctx.as_const(),
1258                    )?;
1259                    ctx.globals
1260                        .insert(alias.name.name, LoweredGlobalDecl::Type(ty));
1261                }
1262                ast::GlobalDeclKind::ConstAssert(condition) => {
1263                    let condition = self.expression(condition, &mut ctx.as_const())?;
1264
1265                    let span = ctx.module.global_expressions.get_span(condition);
1266                    match ctx
1267                        .module
1268                        .to_ctx()
1269                        .eval_expr_to_bool_from(condition, &ctx.module.global_expressions)
1270                    {
1271                        Some(true) => Ok(()),
1272                        Some(false) => Err(Error::ConstAssertFailed(span)),
1273                        _ => Err(Error::NotBool(span)),
1274                    }?;
1275                }
1276            }
1277        }
1278
1279        // Constant evaluation may leave abstract-typed literals and
1280        // compositions in expression arenas, so we need to compact the module
1281        // to remove unused expressions and types.
1282        crate::compact::compact(&mut module);
1283
1284        Ok(module)
1285    }
1286
1287    /// Obtain (inferred) type and initializer after automatic conversion
1288    fn type_and_init(
1289        &mut self,
1290        name: ast::Ident<'source>,
1291        init: Option<Handle<ast::Expression<'source>>>,
1292        explicit_ty: Option<Handle<crate::Type>>,
1293        abstract_rule: AbstractRule,
1294        ectx: &mut ExpressionContext<'source, '_, '_>,
1295    ) -> Result<'source, (Handle<crate::Type>, Option<Handle<crate::Expression>>)> {
1296        let ty;
1297        let initializer;
1298        match (init, explicit_ty) {
1299            (Some(init), Some(explicit_ty)) => {
1300                let init = self.expression_for_abstract(init, ectx)?;
1301                let ty_res = crate::proc::TypeResolution::Handle(explicit_ty);
1302                let init = ectx
1303                    .try_automatic_conversions(init, &ty_res, name.span)
1304                    .map_err(|error| match *error {
1305                        Error::AutoConversion(e) => Box::new(Error::InitializationTypeMismatch {
1306                            name: name.span,
1307                            expected: e.dest_type,
1308                            got: e.source_type,
1309                        }),
1310                        _ => error,
1311                    })?;
1312
1313                let init_ty = ectx.register_type(init)?;
1314                let explicit_inner = &ectx.module.types[explicit_ty].inner;
1315                let init_inner = &ectx.module.types[init_ty].inner;
1316                if !explicit_inner.equivalent(init_inner, &ectx.module.types) {
1317                    return Err(Box::new(Error::InitializationTypeMismatch {
1318                        name: name.span,
1319                        expected: ectx.type_to_string(explicit_ty),
1320                        got: ectx.type_to_string(init_ty),
1321                    }));
1322                }
1323                ty = explicit_ty;
1324                initializer = Some(init);
1325            }
1326            (Some(init), None) => {
1327                let mut init = self.expression_for_abstract(init, ectx)?;
1328                if let AbstractRule::Concretize = abstract_rule {
1329                    init = ectx.concretize(init)?;
1330                }
1331                ty = ectx.register_type(init)?;
1332                initializer = Some(init);
1333            }
1334            (None, Some(explicit_ty)) => {
1335                ty = explicit_ty;
1336                initializer = None;
1337            }
1338            (None, None) => return Err(Box::new(Error::DeclMissingTypeAndInit(name.span))),
1339        }
1340        Ok((ty, initializer))
1341    }
1342
1343    fn function(
1344        &mut self,
1345        f: &ast::Function<'source>,
1346        span: Span,
1347        ctx: &mut GlobalContext<'source, '_, '_>,
1348    ) -> Result<'source, LoweredGlobalDecl> {
1349        let mut local_table = FastHashMap::default();
1350        let mut expressions = Arena::new();
1351        let mut named_expressions = FastIndexMap::default();
1352        let mut local_expression_kind_tracker = crate::proc::ExpressionKindTracker::new();
1353
1354        let arguments = f
1355            .arguments
1356            .iter()
1357            .enumerate()
1358            .map(|(i, arg)| -> Result<'_, _> {
1359                let ty = self.resolve_ast_type(arg.ty, &mut ctx.as_const())?;
1360                let expr = expressions
1361                    .append(crate::Expression::FunctionArgument(i as u32), arg.name.span);
1362                local_table.insert(arg.handle, Declared::Runtime(Typed::Plain(expr)));
1363                named_expressions.insert(expr, (arg.name.name.to_string(), arg.name.span));
1364                local_expression_kind_tracker.insert(expr, crate::proc::ExpressionKind::Runtime);
1365
1366                Ok(crate::FunctionArgument {
1367                    name: Some(arg.name.name.to_string()),
1368                    ty,
1369                    binding: self.binding(&arg.binding, ty, ctx)?,
1370                })
1371            })
1372            .collect::<Result<Vec<_>>>()?;
1373
1374        let result = f
1375            .result
1376            .as_ref()
1377            .map(|res| -> Result<'_, _> {
1378                let ty = self.resolve_ast_type(res.ty, &mut ctx.as_const())?;
1379                Ok(crate::FunctionResult {
1380                    ty,
1381                    binding: self.binding(&res.binding, ty, ctx)?,
1382                })
1383            })
1384            .transpose()?;
1385
1386        let mut function = crate::Function {
1387            name: Some(f.name.name.to_string()),
1388            arguments,
1389            result,
1390            local_variables: Arena::new(),
1391            expressions,
1392            named_expressions: crate::NamedExpressions::default(),
1393            body: crate::Block::default(),
1394            diagnostic_filter_leaf: f.diagnostic_filter_leaf,
1395        };
1396
1397        let mut typifier = Typifier::default();
1398        let mut stmt_ctx = StatementContext {
1399            local_table: &mut local_table,
1400            globals: ctx.globals,
1401            ast_expressions: ctx.ast_expressions,
1402            const_typifier: ctx.const_typifier,
1403            typifier: &mut typifier,
1404            layouter: ctx.layouter,
1405            function: &mut function,
1406            named_expressions: &mut named_expressions,
1407            types: ctx.types,
1408            module: ctx.module,
1409            local_expression_kind_tracker: &mut local_expression_kind_tracker,
1410            global_expression_kind_tracker: ctx.global_expression_kind_tracker,
1411        };
1412        let mut body = self.block(&f.body, false, &mut stmt_ctx)?;
1413        ensure_block_returns(&mut body);
1414
1415        function.body = body;
1416        function.named_expressions = named_expressions
1417            .into_iter()
1418            .map(|(key, (name, _))| (key, name))
1419            .collect();
1420
1421        if let Some(ref entry) = f.entry_point {
1422            let workgroup_size_info = if let Some(workgroup_size) = entry.workgroup_size {
1423                // TODO: replace with try_map once stabilized
1424                let mut workgroup_size_out = [1; 3];
1425                let mut workgroup_size_overrides_out = [None; 3];
1426                for (i, size) in workgroup_size.into_iter().enumerate() {
1427                    if let Some(size_expr) = size {
1428                        match self.const_u32(size_expr, &mut ctx.as_const()) {
1429                            Ok(value) => {
1430                                workgroup_size_out[i] = value.0;
1431                            }
1432                            Err(err) => {
1433                                if let Error::ConstantEvaluatorError(ref ty, _) = *err {
1434                                    match **ty {
1435                                        crate::proc::ConstantEvaluatorError::OverrideExpr => {
1436                                            workgroup_size_overrides_out[i] =
1437                                                Some(self.workgroup_size_override(
1438                                                    size_expr,
1439                                                    &mut ctx.as_override(),
1440                                                )?);
1441                                        }
1442                                        _ => {
1443                                            return Err(err);
1444                                        }
1445                                    }
1446                                } else {
1447                                    return Err(err);
1448                                }
1449                            }
1450                        }
1451                    }
1452                }
1453                if workgroup_size_overrides_out.iter().all(|x| x.is_none()) {
1454                    (workgroup_size_out, None)
1455                } else {
1456                    (workgroup_size_out, Some(workgroup_size_overrides_out))
1457                }
1458            } else {
1459                ([0; 3], None)
1460            };
1461
1462            let (workgroup_size, workgroup_size_overrides) = workgroup_size_info;
1463            ctx.module.entry_points.push(crate::EntryPoint {
1464                name: f.name.name.to_string(),
1465                stage: entry.stage,
1466                early_depth_test: entry.early_depth_test,
1467                workgroup_size,
1468                workgroup_size_overrides,
1469                function,
1470            });
1471            Ok(LoweredGlobalDecl::EntryPoint)
1472        } else {
1473            let handle = ctx.module.functions.append(function, span);
1474            Ok(LoweredGlobalDecl::Function {
1475                handle,
1476                must_use: f.result.as_ref().is_some_and(|res| res.must_use),
1477            })
1478        }
1479    }
1480
1481    fn workgroup_size_override(
1482        &mut self,
1483        size_expr: Handle<ast::Expression<'source>>,
1484        ctx: &mut ExpressionContext<'source, '_, '_>,
1485    ) -> Result<'source, Handle<crate::Expression>> {
1486        let span = ctx.ast_expressions.get_span(size_expr);
1487        let expr = self.expression(size_expr, ctx)?;
1488        match resolve_inner!(ctx, expr).scalar_kind().ok_or(0) {
1489            Ok(crate::ScalarKind::Sint) | Ok(crate::ScalarKind::Uint) => Ok(expr),
1490            _ => Err(Box::new(Error::ExpectedConstExprConcreteIntegerScalar(
1491                span,
1492            ))),
1493        }
1494    }
1495
1496    fn block(
1497        &mut self,
1498        b: &ast::Block<'source>,
1499        is_inside_loop: bool,
1500        ctx: &mut StatementContext<'source, '_, '_>,
1501    ) -> Result<'source, crate::Block> {
1502        let mut block = crate::Block::default();
1503
1504        for stmt in b.stmts.iter() {
1505            self.statement(stmt, &mut block, is_inside_loop, ctx)?;
1506        }
1507
1508        Ok(block)
1509    }
1510
1511    fn statement(
1512        &mut self,
1513        stmt: &ast::Statement<'source>,
1514        block: &mut crate::Block,
1515        is_inside_loop: bool,
1516        ctx: &mut StatementContext<'source, '_, '_>,
1517    ) -> Result<'source, ()> {
1518        let out = match stmt.kind {
1519            ast::StatementKind::Block(ref block) => {
1520                let block = self.block(block, is_inside_loop, ctx)?;
1521                crate::Statement::Block(block)
1522            }
1523            ast::StatementKind::LocalDecl(ref decl) => match *decl {
1524                ast::LocalDecl::Let(ref l) => {
1525                    let mut emitter = Emitter::default();
1526                    emitter.start(&ctx.function.expressions);
1527
1528                    let explicit_ty = l
1529                        .ty
1530                        .map(|ty| self.resolve_ast_type(ty, &mut ctx.as_const(block, &mut emitter)))
1531                        .transpose()?;
1532
1533                    let mut ectx = ctx.as_expression(block, &mut emitter);
1534
1535                    let (_ty, initializer) = self.type_and_init(
1536                        l.name,
1537                        Some(l.init),
1538                        explicit_ty,
1539                        AbstractRule::Concretize,
1540                        &mut ectx,
1541                    )?;
1542
1543                    // We passed `Some()` to `type_and_init`, so we
1544                    // will get a lowered initializer expression back.
1545                    let initializer =
1546                        initializer.expect("type_and_init did not return an initializer");
1547
1548                    // The WGSL spec says that any expression that refers to a
1549                    // `let`-bound variable is not a const expression. This
1550                    // affects when errors must be reported, so we can't even
1551                    // treat suitable `let` bindings as constant as an
1552                    // optimization.
1553                    ctx.local_expression_kind_tracker
1554                        .force_non_const(initializer);
1555
1556                    block.extend(emitter.finish(&ctx.function.expressions));
1557                    ctx.local_table
1558                        .insert(l.handle, Declared::Runtime(Typed::Plain(initializer)));
1559                    ctx.named_expressions
1560                        .insert(initializer, (l.name.name.to_string(), l.name.span));
1561
1562                    return Ok(());
1563                }
1564                ast::LocalDecl::Var(ref v) => {
1565                    let mut emitter = Emitter::default();
1566                    emitter.start(&ctx.function.expressions);
1567
1568                    let explicit_ty =
1569                        v.ty.map(|ast| {
1570                            self.resolve_ast_type(ast, &mut ctx.as_const(block, &mut emitter))
1571                        })
1572                        .transpose()?;
1573
1574                    let mut ectx = ctx.as_expression(block, &mut emitter);
1575                    let (ty, initializer) = self.type_and_init(
1576                        v.name,
1577                        v.init,
1578                        explicit_ty,
1579                        AbstractRule::Concretize,
1580                        &mut ectx,
1581                    )?;
1582
1583                    let (const_initializer, initializer) = {
1584                        match initializer {
1585                            Some(init) => {
1586                                // It's not correct to hoist the initializer up
1587                                // to the top of the function if:
1588                                // - the initialization is inside a loop, and should
1589                                //   take place on every iteration, or
1590                                // - the initialization is not a constant
1591                                //   expression, so its value depends on the
1592                                //   state at the point of initialization.
1593                                if is_inside_loop
1594                                    || !ctx.local_expression_kind_tracker.is_const_or_override(init)
1595                                {
1596                                    (None, Some(init))
1597                                } else {
1598                                    (Some(init), None)
1599                                }
1600                            }
1601                            None => (None, None),
1602                        }
1603                    };
1604
1605                    let var = ctx.function.local_variables.append(
1606                        crate::LocalVariable {
1607                            name: Some(v.name.name.to_string()),
1608                            ty,
1609                            init: const_initializer,
1610                        },
1611                        stmt.span,
1612                    );
1613
1614                    let handle = ctx.as_expression(block, &mut emitter).interrupt_emitter(
1615                        crate::Expression::LocalVariable(var),
1616                        Span::UNDEFINED,
1617                    )?;
1618                    block.extend(emitter.finish(&ctx.function.expressions));
1619                    ctx.local_table
1620                        .insert(v.handle, Declared::Runtime(Typed::Reference(handle)));
1621
1622                    match initializer {
1623                        Some(initializer) => crate::Statement::Store {
1624                            pointer: handle,
1625                            value: initializer,
1626                        },
1627                        None => return Ok(()),
1628                    }
1629                }
1630                ast::LocalDecl::Const(ref c) => {
1631                    let mut emitter = Emitter::default();
1632                    emitter.start(&ctx.function.expressions);
1633
1634                    let ectx = &mut ctx.as_const(block, &mut emitter);
1635
1636                    let explicit_ty =
1637                        c.ty.map(|ast| self.resolve_ast_type(ast, &mut ectx.as_const()))
1638                            .transpose()?;
1639
1640                    let (_ty, init) = self.type_and_init(
1641                        c.name,
1642                        Some(c.init),
1643                        explicit_ty,
1644                        AbstractRule::Allow,
1645                        &mut ectx.as_const(),
1646                    )?;
1647                    let init = init.expect("Local const must have init");
1648
1649                    block.extend(emitter.finish(&ctx.function.expressions));
1650                    ctx.local_table
1651                        .insert(c.handle, Declared::Const(Typed::Plain(init)));
1652                    return Ok(());
1653                }
1654            },
1655            ast::StatementKind::If {
1656                condition,
1657                ref accept,
1658                ref reject,
1659            } => {
1660                let mut emitter = Emitter::default();
1661                emitter.start(&ctx.function.expressions);
1662
1663                let condition =
1664                    self.expression(condition, &mut ctx.as_expression(block, &mut emitter))?;
1665                block.extend(emitter.finish(&ctx.function.expressions));
1666
1667                let accept = self.block(accept, is_inside_loop, ctx)?;
1668                let reject = self.block(reject, is_inside_loop, ctx)?;
1669
1670                crate::Statement::If {
1671                    condition,
1672                    accept,
1673                    reject,
1674                }
1675            }
1676            ast::StatementKind::Switch {
1677                selector,
1678                ref cases,
1679            } => {
1680                let mut emitter = Emitter::default();
1681                emitter.start(&ctx.function.expressions);
1682
1683                let mut ectx = ctx.as_expression(block, &mut emitter);
1684
1685                // Determine the scalar type of the selector and case expressions, find the
1686                // consensus type for automatic conversion, then convert them.
1687                let (mut exprs, spans) = core::iter::once(selector)
1688                    .chain(cases.iter().filter_map(|case| match case.value {
1689                        ast::SwitchValue::Expr(expr) => Some(expr),
1690                        ast::SwitchValue::Default => None,
1691                    }))
1692                    .enumerate()
1693                    .map(|(i, expr)| {
1694                        let span = ectx.ast_expressions.get_span(expr);
1695                        let expr = self.expression_for_abstract(expr, &mut ectx)?;
1696                        let ty = resolve_inner!(ectx, expr);
1697                        match *ty {
1698                            crate::TypeInner::Scalar(
1699                                crate::Scalar::I32
1700                                | crate::Scalar::U32
1701                                | crate::Scalar::ABSTRACT_INT,
1702                            ) => Ok((expr, span)),
1703                            _ => match i {
1704                                0 => Err(Box::new(Error::InvalidSwitchSelector { span })),
1705                                _ => Err(Box::new(Error::InvalidSwitchCase { span })),
1706                            },
1707                        }
1708                    })
1709                    .collect::<Result<(Vec<_>, Vec<_>)>>()?;
1710
1711                let mut consensus =
1712                    ectx.automatic_conversion_consensus(&exprs)
1713                        .map_err(|span_idx| Error::SwitchCaseTypeMismatch {
1714                            span: spans[span_idx],
1715                        })?;
1716                // Concretize to I32 if the selector and all cases were abstract
1717                if consensus == crate::Scalar::ABSTRACT_INT {
1718                    consensus = crate::Scalar::I32;
1719                }
1720                for expr in &mut exprs {
1721                    ectx.convert_to_leaf_scalar(expr, consensus)?;
1722                }
1723
1724                block.extend(emitter.finish(&ctx.function.expressions));
1725
1726                let mut exprs = exprs.into_iter();
1727                let selector = exprs
1728                    .next()
1729                    .expect("First element should be selector expression");
1730
1731                let cases = cases
1732                    .iter()
1733                    .map(|case| {
1734                        Ok(crate::SwitchCase {
1735                            value: match case.value {
1736                                ast::SwitchValue::Expr(expr) => {
1737                                    let span = ctx.ast_expressions.get_span(expr);
1738                                    let expr = exprs.next().expect(
1739                                        "Should yield expression for each SwitchValue::Expr case",
1740                                    );
1741                                    match ctx
1742                                        .module
1743                                        .to_ctx()
1744                                        .eval_expr_to_literal_from(expr, &ctx.function.expressions)
1745                                    {
1746                                        Some(crate::Literal::I32(value)) => {
1747                                            crate::SwitchValue::I32(value)
1748                                        }
1749                                        Some(crate::Literal::U32(value)) => {
1750                                            crate::SwitchValue::U32(value)
1751                                        }
1752                                        _ => {
1753                                            return Err(Box::new(Error::InvalidSwitchCase {
1754                                                span,
1755                                            }));
1756                                        }
1757                                    }
1758                                }
1759                                ast::SwitchValue::Default => crate::SwitchValue::Default,
1760                            },
1761                            body: self.block(&case.body, is_inside_loop, ctx)?,
1762                            fall_through: case.fall_through,
1763                        })
1764                    })
1765                    .collect::<Result<_>>()?;
1766
1767                crate::Statement::Switch { selector, cases }
1768            }
1769            ast::StatementKind::Loop {
1770                ref body,
1771                ref continuing,
1772                break_if,
1773            } => {
1774                let body = self.block(body, true, ctx)?;
1775                let mut continuing = self.block(continuing, true, ctx)?;
1776
1777                let mut emitter = Emitter::default();
1778                emitter.start(&ctx.function.expressions);
1779                let break_if = break_if
1780                    .map(|expr| {
1781                        self.expression(expr, &mut ctx.as_expression(&mut continuing, &mut emitter))
1782                    })
1783                    .transpose()?;
1784                continuing.extend(emitter.finish(&ctx.function.expressions));
1785
1786                crate::Statement::Loop {
1787                    body,
1788                    continuing,
1789                    break_if,
1790                }
1791            }
1792            ast::StatementKind::Break => crate::Statement::Break,
1793            ast::StatementKind::Continue => crate::Statement::Continue,
1794            ast::StatementKind::Return { value: ast_value } => {
1795                let mut emitter = Emitter::default();
1796                emitter.start(&ctx.function.expressions);
1797
1798                let value;
1799                if let Some(ast_expr) = ast_value {
1800                    let result_ty = ctx.function.result.as_ref().map(|r| r.ty);
1801                    let mut ectx = ctx.as_expression(block, &mut emitter);
1802                    let expr = self.expression_for_abstract(ast_expr, &mut ectx)?;
1803
1804                    if let Some(result_ty) = result_ty {
1805                        let mut ectx = ctx.as_expression(block, &mut emitter);
1806                        let resolution = crate::proc::TypeResolution::Handle(result_ty);
1807                        let converted =
1808                            ectx.try_automatic_conversions(expr, &resolution, Span::default())?;
1809                        value = Some(converted);
1810                    } else {
1811                        value = Some(expr);
1812                    }
1813                } else {
1814                    value = None;
1815                }
1816                block.extend(emitter.finish(&ctx.function.expressions));
1817
1818                crate::Statement::Return { value }
1819            }
1820            ast::StatementKind::Kill => crate::Statement::Kill,
1821            ast::StatementKind::Call {
1822                ref function,
1823                ref arguments,
1824            } => {
1825                let mut emitter = Emitter::default();
1826                emitter.start(&ctx.function.expressions);
1827
1828                let _ = self.call(
1829                    stmt.span,
1830                    function,
1831                    arguments,
1832                    &mut ctx.as_expression(block, &mut emitter),
1833                    true,
1834                )?;
1835                block.extend(emitter.finish(&ctx.function.expressions));
1836                return Ok(());
1837            }
1838            ast::StatementKind::Assign {
1839                target: ast_target,
1840                op,
1841                value,
1842            } => {
1843                let mut emitter = Emitter::default();
1844                emitter.start(&ctx.function.expressions);
1845                let target_span = ctx.ast_expressions.get_span(ast_target);
1846
1847                let mut ectx = ctx.as_expression(block, &mut emitter);
1848                let target = self.expression_for_reference(ast_target, &mut ectx)?;
1849                let target_handle = match target {
1850                    Typed::Reference(handle) => handle,
1851                    Typed::Plain(handle) => {
1852                        let ty = ctx.invalid_assignment_type(handle);
1853                        return Err(Box::new(Error::InvalidAssignment {
1854                            span: target_span,
1855                            ty,
1856                        }));
1857                    }
1858                };
1859
1860                // Usually the value needs to be converted to match the type of
1861                // the memory view you're assigning it to. The bit shift
1862                // operators are exceptions, in that the right operand is always
1863                // a `u32` or `vecN<u32>`.
1864                let target_scalar = match op {
1865                    Some(crate::BinaryOperator::ShiftLeft | crate::BinaryOperator::ShiftRight) => {
1866                        Some(crate::Scalar::U32)
1867                    }
1868                    _ => resolve_inner!(ectx, target_handle)
1869                        .pointer_automatically_convertible_scalar(&ectx.module.types),
1870                };
1871
1872                let value = self.expression_for_abstract(value, &mut ectx)?;
1873                let mut value = match target_scalar {
1874                    Some(target_scalar) => ectx.try_automatic_conversion_for_leaf_scalar(
1875                        value,
1876                        target_scalar,
1877                        target_span,
1878                    )?,
1879                    None => value,
1880                };
1881
1882                let value = match op {
1883                    Some(op) => {
1884                        let mut left = ectx.apply_load_rule(target)?;
1885                        ectx.binary_op_splat(op, &mut left, &mut value)?;
1886                        ectx.append_expression(
1887                            crate::Expression::Binary {
1888                                op,
1889                                left,
1890                                right: value,
1891                            },
1892                            stmt.span,
1893                        )?
1894                    }
1895                    None => value,
1896                };
1897                block.extend(emitter.finish(&ctx.function.expressions));
1898
1899                crate::Statement::Store {
1900                    pointer: target_handle,
1901                    value,
1902                }
1903            }
1904            ast::StatementKind::Increment(value) | ast::StatementKind::Decrement(value) => {
1905                let mut emitter = Emitter::default();
1906                emitter.start(&ctx.function.expressions);
1907
1908                let op = match stmt.kind {
1909                    ast::StatementKind::Increment(_) => crate::BinaryOperator::Add,
1910                    ast::StatementKind::Decrement(_) => crate::BinaryOperator::Subtract,
1911                    _ => unreachable!(),
1912                };
1913
1914                let value_span = ctx.ast_expressions.get_span(value);
1915                let target = self
1916                    .expression_for_reference(value, &mut ctx.as_expression(block, &mut emitter))?;
1917                let target_handle = match target {
1918                    Typed::Reference(handle) => handle,
1919                    Typed::Plain(_) => {
1920                        return Err(Box::new(Error::BadIncrDecrReferenceType(value_span)))
1921                    }
1922                };
1923
1924                let mut ectx = ctx.as_expression(block, &mut emitter);
1925                let scalar = match *resolve_inner!(ectx, target_handle) {
1926                    crate::TypeInner::ValuePointer {
1927                        size: None, scalar, ..
1928                    } => scalar,
1929                    crate::TypeInner::Pointer { base, .. } => match ectx.module.types[base].inner {
1930                        crate::TypeInner::Scalar(scalar) => scalar,
1931                        _ => return Err(Box::new(Error::BadIncrDecrReferenceType(value_span))),
1932                    },
1933                    _ => return Err(Box::new(Error::BadIncrDecrReferenceType(value_span))),
1934                };
1935                let literal = match scalar.kind {
1936                    crate::ScalarKind::Sint | crate::ScalarKind::Uint => {
1937                        crate::Literal::one(scalar)
1938                            .ok_or(Error::BadIncrDecrReferenceType(value_span))?
1939                    }
1940                    _ => return Err(Box::new(Error::BadIncrDecrReferenceType(value_span))),
1941                };
1942
1943                let right =
1944                    ectx.interrupt_emitter(crate::Expression::Literal(literal), Span::UNDEFINED)?;
1945                let rctx = ectx.runtime_expression_ctx(stmt.span)?;
1946                let left = rctx.function.expressions.append(
1947                    crate::Expression::Load {
1948                        pointer: target_handle,
1949                    },
1950                    value_span,
1951                );
1952                let value = rctx
1953                    .function
1954                    .expressions
1955                    .append(crate::Expression::Binary { op, left, right }, stmt.span);
1956                rctx.local_expression_kind_tracker
1957                    .insert(left, crate::proc::ExpressionKind::Runtime);
1958                rctx.local_expression_kind_tracker
1959                    .insert(value, crate::proc::ExpressionKind::Runtime);
1960
1961                block.extend(emitter.finish(&ctx.function.expressions));
1962                crate::Statement::Store {
1963                    pointer: target_handle,
1964                    value,
1965                }
1966            }
1967            ast::StatementKind::ConstAssert(condition) => {
1968                let mut emitter = Emitter::default();
1969                emitter.start(&ctx.function.expressions);
1970
1971                let condition =
1972                    self.expression(condition, &mut ctx.as_const(block, &mut emitter))?;
1973
1974                let span = ctx.function.expressions.get_span(condition);
1975                match ctx
1976                    .module
1977                    .to_ctx()
1978                    .eval_expr_to_bool_from(condition, &ctx.function.expressions)
1979                {
1980                    Some(true) => Ok(()),
1981                    Some(false) => Err(Error::ConstAssertFailed(span)),
1982                    _ => Err(Error::NotBool(span)),
1983                }?;
1984
1985                block.extend(emitter.finish(&ctx.function.expressions));
1986
1987                return Ok(());
1988            }
1989            ast::StatementKind::Phony(expr) => {
1990                let mut emitter = Emitter::default();
1991                emitter.start(&ctx.function.expressions);
1992
1993                let value = self.expression(expr, &mut ctx.as_expression(block, &mut emitter))?;
1994                block.extend(emitter.finish(&ctx.function.expressions));
1995                ctx.named_expressions
1996                    .insert(value, ("phony".to_string(), stmt.span));
1997                return Ok(());
1998            }
1999        };
2000
2001        block.push(out, stmt.span);
2002
2003        Ok(())
2004    }
2005
2006    /// Lower `expr` and apply the Load Rule if possible.
2007    ///
2008    /// For the time being, this concretizes abstract values, to support
2009    /// consumers that haven't been adapted to consume them yet. Consumers
2010    /// prepared for abstract values can call [`expression_for_abstract`].
2011    ///
2012    /// [`expression_for_abstract`]: Lowerer::expression_for_abstract
2013    fn expression(
2014        &mut self,
2015        expr: Handle<ast::Expression<'source>>,
2016        ctx: &mut ExpressionContext<'source, '_, '_>,
2017    ) -> Result<'source, Handle<crate::Expression>> {
2018        let expr = self.expression_for_abstract(expr, ctx)?;
2019        ctx.concretize(expr)
2020    }
2021
2022    fn expression_for_abstract(
2023        &mut self,
2024        expr: Handle<ast::Expression<'source>>,
2025        ctx: &mut ExpressionContext<'source, '_, '_>,
2026    ) -> Result<'source, Handle<crate::Expression>> {
2027        let expr = self.expression_for_reference(expr, ctx)?;
2028        ctx.apply_load_rule(expr)
2029    }
2030
2031    fn expression_for_reference(
2032        &mut self,
2033        expr: Handle<ast::Expression<'source>>,
2034        ctx: &mut ExpressionContext<'source, '_, '_>,
2035    ) -> Result<'source, Typed<Handle<crate::Expression>>> {
2036        let span = ctx.ast_expressions.get_span(expr);
2037        let expr = &ctx.ast_expressions[expr];
2038
2039        let expr: Typed<crate::Expression> = match *expr {
2040            ast::Expression::Literal(literal) => {
2041                let literal = match literal {
2042                    ast::Literal::Number(Number::F16(f)) => crate::Literal::F16(f),
2043                    ast::Literal::Number(Number::F32(f)) => crate::Literal::F32(f),
2044                    ast::Literal::Number(Number::I32(i)) => crate::Literal::I32(i),
2045                    ast::Literal::Number(Number::U32(u)) => crate::Literal::U32(u),
2046                    ast::Literal::Number(Number::I64(i)) => crate::Literal::I64(i),
2047                    ast::Literal::Number(Number::U64(u)) => crate::Literal::U64(u),
2048                    ast::Literal::Number(Number::F64(f)) => crate::Literal::F64(f),
2049                    ast::Literal::Number(Number::AbstractInt(i)) => crate::Literal::AbstractInt(i),
2050                    ast::Literal::Number(Number::AbstractFloat(f)) => {
2051                        crate::Literal::AbstractFloat(f)
2052                    }
2053                    ast::Literal::Bool(b) => crate::Literal::Bool(b),
2054                };
2055                let handle = ctx.interrupt_emitter(crate::Expression::Literal(literal), span)?;
2056                return Ok(Typed::Plain(handle));
2057            }
2058            ast::Expression::Ident(ast::IdentExpr::Local(local)) => {
2059                return ctx.local(&local, span);
2060            }
2061            ast::Expression::Ident(ast::IdentExpr::Unresolved(name)) => {
2062                let global = ctx
2063                    .globals
2064                    .get(name)
2065                    .ok_or(Error::UnknownIdent(span, name))?;
2066                let expr = match *global {
2067                    LoweredGlobalDecl::Var(handle) => {
2068                        let expr = crate::Expression::GlobalVariable(handle);
2069                        match ctx.module.global_variables[handle].space {
2070                            crate::AddressSpace::Handle => Typed::Plain(expr),
2071                            _ => Typed::Reference(expr),
2072                        }
2073                    }
2074                    LoweredGlobalDecl::Const(handle) => {
2075                        Typed::Plain(crate::Expression::Constant(handle))
2076                    }
2077                    LoweredGlobalDecl::Override(handle) => {
2078                        Typed::Plain(crate::Expression::Override(handle))
2079                    }
2080                    LoweredGlobalDecl::Function { .. }
2081                    | LoweredGlobalDecl::Type(_)
2082                    | LoweredGlobalDecl::EntryPoint => {
2083                        return Err(Box::new(Error::Unexpected(span, ExpectedToken::Variable)));
2084                    }
2085                };
2086
2087                return expr.try_map(|handle| ctx.interrupt_emitter(handle, span));
2088            }
2089            ast::Expression::Construct {
2090                ref ty,
2091                ty_span,
2092                ref components,
2093            } => {
2094                let handle = self.construct(span, ty, ty_span, components, ctx)?;
2095                return Ok(Typed::Plain(handle));
2096            }
2097            ast::Expression::Unary { op, expr } => {
2098                let expr = self.expression_for_abstract(expr, ctx)?;
2099                Typed::Plain(crate::Expression::Unary { op, expr })
2100            }
2101            ast::Expression::AddrOf(expr) => {
2102                // The `&` operator simply converts a reference to a pointer. And since a
2103                // reference is required, the Load Rule is not applied.
2104                match self.expression_for_reference(expr, ctx)? {
2105                    Typed::Reference(handle) => {
2106                        let expr = &ctx.runtime_expression_ctx(span)?.function.expressions[handle];
2107                        if let &crate::Expression::Access { base, .. }
2108                        | &crate::Expression::AccessIndex { base, .. } = expr
2109                        {
2110                            if let Some(ty) = resolve_inner!(ctx, base).pointer_base_type() {
2111                                if matches!(
2112                                    *ty.inner_with(&ctx.module.types),
2113                                    crate::TypeInner::Vector { .. },
2114                                ) {
2115                                    return Err(Box::new(Error::InvalidAddrOfOperand(
2116                                        ctx.get_expression_span(handle),
2117                                    )));
2118                                }
2119                            }
2120                        }
2121                        // No code is generated. We just declare the reference a pointer now.
2122                        return Ok(Typed::Plain(handle));
2123                    }
2124                    Typed::Plain(_) => {
2125                        return Err(Box::new(Error::NotReference(
2126                            "the operand of the `&` operator",
2127                            span,
2128                        )));
2129                    }
2130                }
2131            }
2132            ast::Expression::Deref(expr) => {
2133                // The pointer we dereference must be loaded.
2134                let pointer = self.expression(expr, ctx)?;
2135
2136                if resolve_inner!(ctx, pointer).pointer_space().is_none() {
2137                    return Err(Box::new(Error::NotPointer(span)));
2138                }
2139
2140                // No code is generated. We just declare the pointer a reference now.
2141                return Ok(Typed::Reference(pointer));
2142            }
2143            ast::Expression::Binary { op, left, right } => {
2144                self.binary(op, left, right, span, ctx)?
2145            }
2146            ast::Expression::Call {
2147                ref function,
2148                ref arguments,
2149            } => {
2150                let handle = self
2151                    .call(span, function, arguments, ctx, false)?
2152                    .ok_or(Error::FunctionReturnsVoid(function.span))?;
2153                return Ok(Typed::Plain(handle));
2154            }
2155            ast::Expression::Index { base, index } => {
2156                let mut lowered_base = self.expression_for_reference(base, ctx)?;
2157                let index = self.expression(index, ctx)?;
2158
2159                // <https://www.w3.org/TR/WGSL/#language_extension-pointer_composite_access>
2160                // Declare pointer as reference
2161                if let Typed::Plain(handle) = lowered_base {
2162                    if resolve_inner!(ctx, handle).pointer_space().is_some() {
2163                        lowered_base = Typed::Reference(handle);
2164                    }
2165                }
2166
2167                lowered_base.try_map(|base| match ctx.const_eval_expr_to_u32(index).ok() {
2168                    Some(index) => {
2169                        Ok::<_, Box<Error>>(crate::Expression::AccessIndex { base, index })
2170                    }
2171                    None => {
2172                        // When an abstract array value e is indexed by an expression
2173                        // that is not a const-expression, then the array is concretized
2174                        // before the index is applied.
2175                        // https://www.w3.org/TR/WGSL/#array-access-expr
2176                        // Also applies to vectors and matrices.
2177                        let base = ctx.concretize(base)?;
2178                        Ok(crate::Expression::Access { base, index })
2179                    }
2180                })?
2181            }
2182            ast::Expression::Member { base, ref field } => {
2183                let mut lowered_base = self.expression_for_reference(base, ctx)?;
2184
2185                // <https://www.w3.org/TR/WGSL/#language_extension-pointer_composite_access>
2186                // Declare pointer as reference
2187                if let Typed::Plain(handle) = lowered_base {
2188                    if resolve_inner!(ctx, handle).pointer_space().is_some() {
2189                        lowered_base = Typed::Reference(handle);
2190                    }
2191                }
2192
2193                let temp_ty;
2194                let composite_type: &crate::TypeInner = match lowered_base {
2195                    Typed::Reference(handle) => {
2196                        temp_ty = resolve_inner!(ctx, handle)
2197                            .pointer_base_type()
2198                            .expect("In Typed::Reference(handle), handle must be a Naga pointer");
2199                        temp_ty.inner_with(&ctx.module.types)
2200                    }
2201
2202                    Typed::Plain(handle) => {
2203                        resolve_inner!(ctx, handle)
2204                    }
2205                };
2206
2207                let access = match *composite_type {
2208                    crate::TypeInner::Struct { ref members, .. } => {
2209                        let index = members
2210                            .iter()
2211                            .position(|m| m.name.as_deref() == Some(field.name))
2212                            .ok_or(Error::BadAccessor(field.span))?
2213                            as u32;
2214
2215                        lowered_base.map(|base| crate::Expression::AccessIndex { base, index })
2216                    }
2217                    crate::TypeInner::Vector { .. } => {
2218                        match Components::new(field.name, field.span)? {
2219                            Components::Swizzle { size, pattern } => {
2220                                Typed::Plain(crate::Expression::Swizzle {
2221                                    size,
2222                                    vector: ctx.apply_load_rule(lowered_base)?,
2223                                    pattern,
2224                                })
2225                            }
2226                            Components::Single(index) => lowered_base
2227                                .map(|base| crate::Expression::AccessIndex { base, index }),
2228                        }
2229                    }
2230                    _ => return Err(Box::new(Error::BadAccessor(field.span))),
2231                };
2232
2233                access
2234            }
2235            ast::Expression::Bitcast { expr, to, ty_span } => {
2236                let expr = self.expression(expr, ctx)?;
2237                let to_resolved = self.resolve_ast_type(to, &mut ctx.as_const())?;
2238
2239                let element_scalar = match ctx.module.types[to_resolved].inner {
2240                    crate::TypeInner::Scalar(scalar) => scalar,
2241                    crate::TypeInner::Vector { scalar, .. } => scalar,
2242                    _ => {
2243                        let ty = resolve!(ctx, expr);
2244                        return Err(Box::new(Error::BadTypeCast {
2245                            from_type: ctx.type_resolution_to_string(ty),
2246                            span: ty_span,
2247                            to_type: ctx.type_to_string(to_resolved),
2248                        }));
2249                    }
2250                };
2251
2252                Typed::Plain(crate::Expression::As {
2253                    expr,
2254                    kind: element_scalar.kind,
2255                    convert: None,
2256                })
2257            }
2258        };
2259
2260        expr.try_map(|handle| ctx.append_expression(handle, span))
2261    }
2262
2263    fn binary(
2264        &mut self,
2265        op: crate::BinaryOperator,
2266        left: Handle<ast::Expression<'source>>,
2267        right: Handle<ast::Expression<'source>>,
2268        span: Span,
2269        ctx: &mut ExpressionContext<'source, '_, '_>,
2270    ) -> Result<'source, Typed<crate::Expression>> {
2271        // Load both operands.
2272        let mut left = self.expression_for_abstract(left, ctx)?;
2273        let mut right = self.expression_for_abstract(right, ctx)?;
2274
2275        // Convert `scalar op vector` to `vector op vector` by introducing
2276        // `Splat` expressions.
2277        ctx.binary_op_splat(op, &mut left, &mut right)?;
2278
2279        // Apply automatic conversions.
2280        match op {
2281            crate::BinaryOperator::ShiftLeft | crate::BinaryOperator::ShiftRight => {
2282                // Shift operators require the right operand to be `u32` or
2283                // `vecN<u32>`. We can let the validator sort out vector length
2284                // issues, but the right operand must be, or convert to, a u32 leaf
2285                // scalar.
2286                right =
2287                    ctx.try_automatic_conversion_for_leaf_scalar(right, crate::Scalar::U32, span)?;
2288
2289                // Additionally, we must concretize the left operand if the right operand
2290                // is not a const-expression.
2291                // See https://www.w3.org/TR/WGSL/#overload-resolution-section.
2292                //
2293                // 2. Eliminate any candidate where one of its subexpressions resolves to
2294                // an abstract type after feasible automatic conversions, but another of
2295                // the candidate’s subexpressions is not a const-expression.
2296                //
2297                // We only have to explicitly do so for shifts as their operands may be
2298                // of different types - for other binary ops this is achieved by finding
2299                // the conversion consensus for both operands.
2300                if !ctx.is_const(right) {
2301                    left = ctx.concretize(left)?;
2302                }
2303            }
2304
2305            // All other operators follow the same pattern: reconcile the
2306            // scalar leaf types. If there's no reconciliation possible,
2307            // leave the expressions as they are: validation will report the
2308            // problem.
2309            _ => {
2310                ctx.grow_types(left)?;
2311                ctx.grow_types(right)?;
2312                if let Ok(consensus_scalar) =
2313                    ctx.automatic_conversion_consensus([left, right].iter())
2314                {
2315                    ctx.convert_to_leaf_scalar(&mut left, consensus_scalar)?;
2316                    ctx.convert_to_leaf_scalar(&mut right, consensus_scalar)?;
2317                }
2318            }
2319        }
2320
2321        Ok(Typed::Plain(crate::Expression::Binary { op, left, right }))
2322    }
2323
2324    /// Generate Naga IR for call expressions and statements, and type
2325    /// constructor expressions.
2326    ///
2327    /// The "function" being called is simply an `Ident` that we know refers to
2328    /// some module-scope definition.
2329    ///
2330    /// - If it is the name of a type, then the expression is a type constructor
2331    ///   expression: either constructing a value from components, a conversion
2332    ///   expression, or a zero value expression.
2333    ///
2334    /// - If it is the name of a function, then we're generating a [`Call`]
2335    ///   statement. We may be in the midst of generating code for an
2336    ///   expression, in which case we must generate an `Emit` statement to
2337    ///   force evaluation of the IR expressions we've generated so far, add the
2338    ///   `Call` statement to the current block, and then resume generating
2339    ///   expressions.
2340    ///
2341    /// [`Call`]: crate::Statement::Call
2342    fn call(
2343        &mut self,
2344        span: Span,
2345        function: &ast::Ident<'source>,
2346        arguments: &[Handle<ast::Expression<'source>>],
2347        ctx: &mut ExpressionContext<'source, '_, '_>,
2348        is_statement: bool,
2349    ) -> Result<'source, Option<Handle<crate::Expression>>> {
2350        let function_span = function.span;
2351        match ctx.globals.get(function.name) {
2352            Some(&LoweredGlobalDecl::Type(ty)) => {
2353                let handle = self.construct(
2354                    span,
2355                    &ast::ConstructorType::Type(ty),
2356                    function_span,
2357                    arguments,
2358                    ctx,
2359                )?;
2360                Ok(Some(handle))
2361            }
2362            Some(
2363                &LoweredGlobalDecl::Const(_)
2364                | &LoweredGlobalDecl::Override(_)
2365                | &LoweredGlobalDecl::Var(_),
2366            ) => Err(Box::new(Error::Unexpected(
2367                function_span,
2368                ExpectedToken::Function,
2369            ))),
2370            Some(&LoweredGlobalDecl::EntryPoint) => {
2371                Err(Box::new(Error::CalledEntryPoint(function_span)))
2372            }
2373            Some(&LoweredGlobalDecl::Function {
2374                handle: function,
2375                must_use,
2376            }) => {
2377                let arguments = arguments
2378                    .iter()
2379                    .enumerate()
2380                    .map(|(i, &arg)| {
2381                        // Try to convert abstract values to the known argument types
2382                        let Some(&crate::FunctionArgument {
2383                            ty: parameter_ty, ..
2384                        }) = ctx.module.functions[function].arguments.get(i)
2385                        else {
2386                            // Wrong number of arguments... just concretize the type here
2387                            // and let the validator report the error.
2388                            return self.expression(arg, ctx);
2389                        };
2390
2391                        let expr = self.expression_for_abstract(arg, ctx)?;
2392                        ctx.try_automatic_conversions(
2393                            expr,
2394                            &crate::proc::TypeResolution::Handle(parameter_ty),
2395                            ctx.ast_expressions.get_span(arg),
2396                        )
2397                    })
2398                    .collect::<Result<Vec<_>>>()?;
2399
2400                let has_result = ctx.module.functions[function].result.is_some();
2401
2402                if must_use && is_statement {
2403                    return Err(Box::new(Error::FunctionMustUseUnused(function_span)));
2404                }
2405
2406                let rctx = ctx.runtime_expression_ctx(span)?;
2407                // we need to always do this before a fn call since all arguments need to be emitted before the fn call
2408                rctx.block
2409                    .extend(rctx.emitter.finish(&rctx.function.expressions));
2410                let result = has_result.then(|| {
2411                    let result = rctx
2412                        .function
2413                        .expressions
2414                        .append(crate::Expression::CallResult(function), span);
2415                    rctx.local_expression_kind_tracker
2416                        .insert(result, crate::proc::ExpressionKind::Runtime);
2417                    result
2418                });
2419                rctx.emitter.start(&rctx.function.expressions);
2420                rctx.block.push(
2421                    crate::Statement::Call {
2422                        function,
2423                        arguments,
2424                        result,
2425                    },
2426                    span,
2427                );
2428
2429                Ok(result)
2430            }
2431            None => {
2432                let span = function_span;
2433                let expr = if let Some(fun) = conv::map_relational_fun(function.name) {
2434                    let mut args = ctx.prepare_args(arguments, 1, span);
2435                    let argument = self.expression(args.next()?, ctx)?;
2436                    args.finish()?;
2437
2438                    // Check for no-op all(bool) and any(bool):
2439                    let argument_unmodified = matches!(
2440                        fun,
2441                        crate::RelationalFunction::All | crate::RelationalFunction::Any
2442                    ) && {
2443                        matches!(
2444                            resolve_inner!(ctx, argument),
2445                            &crate::TypeInner::Scalar(crate::Scalar {
2446                                kind: crate::ScalarKind::Bool,
2447                                ..
2448                            })
2449                        )
2450                    };
2451
2452                    if argument_unmodified {
2453                        return Ok(Some(argument));
2454                    } else {
2455                        crate::Expression::Relational { fun, argument }
2456                    }
2457                } else if let Some((axis, ctrl)) = conv::map_derivative(function.name) {
2458                    let mut args = ctx.prepare_args(arguments, 1, span);
2459                    let expr = self.expression(args.next()?, ctx)?;
2460                    args.finish()?;
2461
2462                    crate::Expression::Derivative { axis, ctrl, expr }
2463                } else if let Some(fun) = conv::map_standard_fun(function.name) {
2464                    self.math_function_helper(span, fun, arguments, ctx)?
2465                } else if let Some(fun) = Texture::map(function.name) {
2466                    self.texture_sample_helper(fun, arguments, span, ctx)?
2467                } else if let Some((op, cop)) = conv::map_subgroup_operation(function.name) {
2468                    return Ok(Some(
2469                        self.subgroup_operation_helper(span, op, cop, arguments, ctx)?,
2470                    ));
2471                } else if let Some(mode) = SubgroupGather::map(function.name) {
2472                    return Ok(Some(
2473                        self.subgroup_gather_helper(span, mode, arguments, ctx)?,
2474                    ));
2475                } else if let Some(fun) = crate::AtomicFunction::map(function.name) {
2476                    return self.atomic_helper(span, fun, arguments, is_statement, ctx);
2477                } else {
2478                    match function.name {
2479                        "select" => {
2480                            let mut args = ctx.prepare_args(arguments, 3, span);
2481
2482                            let reject = self.expression(args.next()?, ctx)?;
2483                            let accept = self.expression(args.next()?, ctx)?;
2484                            let condition = self.expression(args.next()?, ctx)?;
2485
2486                            args.finish()?;
2487
2488                            crate::Expression::Select {
2489                                reject,
2490                                accept,
2491                                condition,
2492                            }
2493                        }
2494                        "arrayLength" => {
2495                            let mut args = ctx.prepare_args(arguments, 1, span);
2496                            let expr = self.expression(args.next()?, ctx)?;
2497                            args.finish()?;
2498
2499                            crate::Expression::ArrayLength(expr)
2500                        }
2501                        "atomicLoad" => {
2502                            let mut args = ctx.prepare_args(arguments, 1, span);
2503                            let pointer = self.atomic_pointer(args.next()?, ctx)?;
2504                            args.finish()?;
2505
2506                            crate::Expression::Load { pointer }
2507                        }
2508                        "atomicStore" => {
2509                            let mut args = ctx.prepare_args(arguments, 2, span);
2510                            let pointer = self.atomic_pointer(args.next()?, ctx)?;
2511                            let value = self.expression(args.next()?, ctx)?;
2512                            args.finish()?;
2513
2514                            let rctx = ctx.runtime_expression_ctx(span)?;
2515                            rctx.block
2516                                .extend(rctx.emitter.finish(&rctx.function.expressions));
2517                            rctx.emitter.start(&rctx.function.expressions);
2518                            rctx.block
2519                                .push(crate::Statement::Store { pointer, value }, span);
2520                            return Ok(None);
2521                        }
2522                        "atomicCompareExchangeWeak" => {
2523                            let mut args = ctx.prepare_args(arguments, 3, span);
2524
2525                            let pointer = self.atomic_pointer(args.next()?, ctx)?;
2526
2527                            let compare = self.expression(args.next()?, ctx)?;
2528
2529                            let value = args.next()?;
2530                            let value_span = ctx.ast_expressions.get_span(value);
2531                            let value = self.expression(value, ctx)?;
2532
2533                            args.finish()?;
2534
2535                            let expression = match *resolve_inner!(ctx, value) {
2536                                crate::TypeInner::Scalar(scalar) => {
2537                                    crate::Expression::AtomicResult {
2538                                        ty: ctx.module.generate_predeclared_type(
2539                                            crate::PredeclaredType::AtomicCompareExchangeWeakResult(
2540                                                scalar,
2541                                            ),
2542                                        ),
2543                                        comparison: true,
2544                                    }
2545                                }
2546                                _ => {
2547                                    return Err(Box::new(Error::InvalidAtomicOperandType(
2548                                        value_span,
2549                                    )))
2550                                }
2551                            };
2552
2553                            let result = ctx.interrupt_emitter(expression, span)?;
2554                            let rctx = ctx.runtime_expression_ctx(span)?;
2555                            rctx.block.push(
2556                                crate::Statement::Atomic {
2557                                    pointer,
2558                                    fun: crate::AtomicFunction::Exchange {
2559                                        compare: Some(compare),
2560                                    },
2561                                    value,
2562                                    result: Some(result),
2563                                },
2564                                span,
2565                            );
2566                            return Ok(Some(result));
2567                        }
2568                        "textureAtomicMin" | "textureAtomicMax" | "textureAtomicAdd"
2569                        | "textureAtomicAnd" | "textureAtomicOr" | "textureAtomicXor" => {
2570                            let mut args = ctx.prepare_args(arguments, 3, span);
2571
2572                            let image = args.next()?;
2573                            let image_span = ctx.ast_expressions.get_span(image);
2574                            let image = self.expression(image, ctx)?;
2575
2576                            let coordinate = self.expression(args.next()?, ctx)?;
2577
2578                            let (_, arrayed) = ctx.image_data(image, image_span)?;
2579                            let array_index = arrayed
2580                                .then(|| {
2581                                    args.min_args += 1;
2582                                    self.expression(args.next()?, ctx)
2583                                })
2584                                .transpose()?;
2585
2586                            let value = self.expression(args.next()?, ctx)?;
2587
2588                            args.finish()?;
2589
2590                            let rctx = ctx.runtime_expression_ctx(span)?;
2591                            rctx.block
2592                                .extend(rctx.emitter.finish(&rctx.function.expressions));
2593                            rctx.emitter.start(&rctx.function.expressions);
2594                            let stmt = crate::Statement::ImageAtomic {
2595                                image,
2596                                coordinate,
2597                                array_index,
2598                                fun: match function.name {
2599                                    "textureAtomicMin" => crate::AtomicFunction::Min,
2600                                    "textureAtomicMax" => crate::AtomicFunction::Max,
2601                                    "textureAtomicAdd" => crate::AtomicFunction::Add,
2602                                    "textureAtomicAnd" => crate::AtomicFunction::And,
2603                                    "textureAtomicOr" => crate::AtomicFunction::InclusiveOr,
2604                                    "textureAtomicXor" => crate::AtomicFunction::ExclusiveOr,
2605                                    _ => unreachable!(),
2606                                },
2607                                value,
2608                            };
2609                            rctx.block.push(stmt, span);
2610                            return Ok(None);
2611                        }
2612                        "storageBarrier" => {
2613                            ctx.prepare_args(arguments, 0, span).finish()?;
2614
2615                            let rctx = ctx.runtime_expression_ctx(span)?;
2616                            rctx.block
2617                                .push(crate::Statement::Barrier(crate::Barrier::STORAGE), span);
2618                            return Ok(None);
2619                        }
2620                        "workgroupBarrier" => {
2621                            ctx.prepare_args(arguments, 0, span).finish()?;
2622
2623                            let rctx = ctx.runtime_expression_ctx(span)?;
2624                            rctx.block
2625                                .push(crate::Statement::Barrier(crate::Barrier::WORK_GROUP), span);
2626                            return Ok(None);
2627                        }
2628                        "subgroupBarrier" => {
2629                            ctx.prepare_args(arguments, 0, span).finish()?;
2630
2631                            let rctx = ctx.runtime_expression_ctx(span)?;
2632                            rctx.block
2633                                .push(crate::Statement::Barrier(crate::Barrier::SUB_GROUP), span);
2634                            return Ok(None);
2635                        }
2636                        "textureBarrier" => {
2637                            ctx.prepare_args(arguments, 0, span).finish()?;
2638
2639                            let rctx = ctx.runtime_expression_ctx(span)?;
2640                            rctx.block
2641                                .push(crate::Statement::Barrier(crate::Barrier::TEXTURE), span);
2642                            return Ok(None);
2643                        }
2644                        "workgroupUniformLoad" => {
2645                            let mut args = ctx.prepare_args(arguments, 1, span);
2646                            let expr = args.next()?;
2647                            args.finish()?;
2648
2649                            let pointer = self.expression(expr, ctx)?;
2650                            let result_ty = match *resolve_inner!(ctx, pointer) {
2651                                crate::TypeInner::Pointer {
2652                                    base,
2653                                    space: crate::AddressSpace::WorkGroup,
2654                                } => base,
2655                                ref other => {
2656                                    log::error!("Type {other:?} passed to workgroupUniformLoad");
2657                                    let span = ctx.ast_expressions.get_span(expr);
2658                                    return Err(Box::new(Error::InvalidWorkGroupUniformLoad(span)));
2659                                }
2660                            };
2661                            let result = ctx.interrupt_emitter(
2662                                crate::Expression::WorkGroupUniformLoadResult { ty: result_ty },
2663                                span,
2664                            )?;
2665                            let rctx = ctx.runtime_expression_ctx(span)?;
2666                            rctx.block.push(
2667                                crate::Statement::WorkGroupUniformLoad { pointer, result },
2668                                span,
2669                            );
2670
2671                            return Ok(Some(result));
2672                        }
2673                        "textureStore" => {
2674                            let mut args = ctx.prepare_args(arguments, 3, span);
2675
2676                            let image = args.next()?;
2677                            let image_span = ctx.ast_expressions.get_span(image);
2678                            let image = self.expression(image, ctx)?;
2679
2680                            let coordinate = self.expression(args.next()?, ctx)?;
2681
2682                            let (_, arrayed) = ctx.image_data(image, image_span)?;
2683                            let array_index = arrayed
2684                                .then(|| {
2685                                    args.min_args += 1;
2686                                    self.expression(args.next()?, ctx)
2687                                })
2688                                .transpose()?;
2689
2690                            let value = self.expression(args.next()?, ctx)?;
2691
2692                            args.finish()?;
2693
2694                            let rctx = ctx.runtime_expression_ctx(span)?;
2695                            rctx.block
2696                                .extend(rctx.emitter.finish(&rctx.function.expressions));
2697                            rctx.emitter.start(&rctx.function.expressions);
2698                            let stmt = crate::Statement::ImageStore {
2699                                image,
2700                                coordinate,
2701                                array_index,
2702                                value,
2703                            };
2704                            rctx.block.push(stmt, span);
2705                            return Ok(None);
2706                        }
2707                        "textureLoad" => {
2708                            let mut args = ctx.prepare_args(arguments, 2, span);
2709
2710                            let image = args.next()?;
2711                            let image_span = ctx.ast_expressions.get_span(image);
2712                            let image = self.expression(image, ctx)?;
2713
2714                            let coordinate = self.expression(args.next()?, ctx)?;
2715
2716                            let (class, arrayed) = ctx.image_data(image, image_span)?;
2717                            let array_index = arrayed
2718                                .then(|| {
2719                                    args.min_args += 1;
2720                                    self.expression(args.next()?, ctx)
2721                                })
2722                                .transpose()?;
2723
2724                            let level = class
2725                                .is_mipmapped()
2726                                .then(|| {
2727                                    args.min_args += 1;
2728                                    self.expression(args.next()?, ctx)
2729                                })
2730                                .transpose()?;
2731
2732                            let sample = class
2733                                .is_multisampled()
2734                                .then(|| self.expression(args.next()?, ctx))
2735                                .transpose()?;
2736
2737                            args.finish()?;
2738
2739                            crate::Expression::ImageLoad {
2740                                image,
2741                                coordinate,
2742                                array_index,
2743                                level,
2744                                sample,
2745                            }
2746                        }
2747                        "textureDimensions" => {
2748                            let mut args = ctx.prepare_args(arguments, 1, span);
2749                            let image = self.expression(args.next()?, ctx)?;
2750                            let level = args
2751                                .next()
2752                                .map(|arg| self.expression(arg, ctx))
2753                                .ok()
2754                                .transpose()?;
2755                            args.finish()?;
2756
2757                            crate::Expression::ImageQuery {
2758                                image,
2759                                query: crate::ImageQuery::Size { level },
2760                            }
2761                        }
2762                        "textureNumLevels" => {
2763                            let mut args = ctx.prepare_args(arguments, 1, span);
2764                            let image = self.expression(args.next()?, ctx)?;
2765                            args.finish()?;
2766
2767                            crate::Expression::ImageQuery {
2768                                image,
2769                                query: crate::ImageQuery::NumLevels,
2770                            }
2771                        }
2772                        "textureNumLayers" => {
2773                            let mut args = ctx.prepare_args(arguments, 1, span);
2774                            let image = self.expression(args.next()?, ctx)?;
2775                            args.finish()?;
2776
2777                            crate::Expression::ImageQuery {
2778                                image,
2779                                query: crate::ImageQuery::NumLayers,
2780                            }
2781                        }
2782                        "textureNumSamples" => {
2783                            let mut args = ctx.prepare_args(arguments, 1, span);
2784                            let image = self.expression(args.next()?, ctx)?;
2785                            args.finish()?;
2786
2787                            crate::Expression::ImageQuery {
2788                                image,
2789                                query: crate::ImageQuery::NumSamples,
2790                            }
2791                        }
2792                        "rayQueryInitialize" => {
2793                            let mut args = ctx.prepare_args(arguments, 3, span);
2794                            let query = self.ray_query_pointer(args.next()?, ctx)?;
2795                            let acceleration_structure = self.expression(args.next()?, ctx)?;
2796                            let descriptor = self.expression(args.next()?, ctx)?;
2797                            args.finish()?;
2798
2799                            let _ = ctx.module.generate_ray_desc_type();
2800                            let fun = crate::RayQueryFunction::Initialize {
2801                                acceleration_structure,
2802                                descriptor,
2803                            };
2804
2805                            let rctx = ctx.runtime_expression_ctx(span)?;
2806                            rctx.block
2807                                .extend(rctx.emitter.finish(&rctx.function.expressions));
2808                            rctx.emitter.start(&rctx.function.expressions);
2809                            rctx.block
2810                                .push(crate::Statement::RayQuery { query, fun }, span);
2811                            return Ok(None);
2812                        }
2813                        "getCommittedHitVertexPositions" => {
2814                            let mut args = ctx.prepare_args(arguments, 1, span);
2815                            let query = self.ray_query_pointer(args.next()?, ctx)?;
2816                            args.finish()?;
2817
2818                            let _ = ctx.module.generate_vertex_return_type();
2819
2820                            crate::Expression::RayQueryVertexPositions {
2821                                query,
2822                                committed: true,
2823                            }
2824                        }
2825                        "getCandidateHitVertexPositions" => {
2826                            let mut args = ctx.prepare_args(arguments, 1, span);
2827                            let query = self.ray_query_pointer(args.next()?, ctx)?;
2828                            args.finish()?;
2829
2830                            let _ = ctx.module.generate_vertex_return_type();
2831
2832                            crate::Expression::RayQueryVertexPositions {
2833                                query,
2834                                committed: false,
2835                            }
2836                        }
2837                        "rayQueryProceed" => {
2838                            let mut args = ctx.prepare_args(arguments, 1, span);
2839                            let query = self.ray_query_pointer(args.next()?, ctx)?;
2840                            args.finish()?;
2841
2842                            let result = ctx.interrupt_emitter(
2843                                crate::Expression::RayQueryProceedResult,
2844                                span,
2845                            )?;
2846                            let fun = crate::RayQueryFunction::Proceed { result };
2847                            let rctx = ctx.runtime_expression_ctx(span)?;
2848                            rctx.block
2849                                .push(crate::Statement::RayQuery { query, fun }, span);
2850                            return Ok(Some(result));
2851                        }
2852                        "rayQueryGenerateIntersection" => {
2853                            let mut args = ctx.prepare_args(arguments, 2, span);
2854                            let query = self.ray_query_pointer(args.next()?, ctx)?;
2855                            let hit_t = self.expression(args.next()?, ctx)?;
2856                            args.finish()?;
2857
2858                            let fun = crate::RayQueryFunction::GenerateIntersection { hit_t };
2859                            let rctx = ctx.runtime_expression_ctx(span)?;
2860                            rctx.block
2861                                .push(crate::Statement::RayQuery { query, fun }, span);
2862                            return Ok(None);
2863                        }
2864                        "rayQueryConfirmIntersection" => {
2865                            let mut args = ctx.prepare_args(arguments, 1, span);
2866                            let query = self.ray_query_pointer(args.next()?, ctx)?;
2867                            args.finish()?;
2868
2869                            let fun = crate::RayQueryFunction::ConfirmIntersection;
2870                            let rctx = ctx.runtime_expression_ctx(span)?;
2871                            rctx.block
2872                                .push(crate::Statement::RayQuery { query, fun }, span);
2873                            return Ok(None);
2874                        }
2875                        "rayQueryTerminate" => {
2876                            let mut args = ctx.prepare_args(arguments, 1, span);
2877                            let query = self.ray_query_pointer(args.next()?, ctx)?;
2878                            args.finish()?;
2879
2880                            let fun = crate::RayQueryFunction::Terminate;
2881                            let rctx = ctx.runtime_expression_ctx(span)?;
2882                            rctx.block
2883                                .push(crate::Statement::RayQuery { query, fun }, span);
2884                            return Ok(None);
2885                        }
2886                        "rayQueryGetCommittedIntersection" => {
2887                            let mut args = ctx.prepare_args(arguments, 1, span);
2888                            let query = self.ray_query_pointer(args.next()?, ctx)?;
2889                            args.finish()?;
2890
2891                            let _ = ctx.module.generate_ray_intersection_type();
2892                            crate::Expression::RayQueryGetIntersection {
2893                                query,
2894                                committed: true,
2895                            }
2896                        }
2897                        "rayQueryGetCandidateIntersection" => {
2898                            let mut args = ctx.prepare_args(arguments, 1, span);
2899                            let query = self.ray_query_pointer(args.next()?, ctx)?;
2900                            args.finish()?;
2901
2902                            let _ = ctx.module.generate_ray_intersection_type();
2903                            crate::Expression::RayQueryGetIntersection {
2904                                query,
2905                                committed: false,
2906                            }
2907                        }
2908                        "RayDesc" => {
2909                            let ty = ctx.module.generate_ray_desc_type();
2910                            let handle = self.construct(
2911                                span,
2912                                &ast::ConstructorType::Type(ty),
2913                                function.span,
2914                                arguments,
2915                                ctx,
2916                            )?;
2917                            return Ok(Some(handle));
2918                        }
2919                        "subgroupBallot" => {
2920                            let mut args = ctx.prepare_args(arguments, 0, span);
2921                            let predicate = if arguments.len() == 1 {
2922                                Some(self.expression(args.next()?, ctx)?)
2923                            } else {
2924                                None
2925                            };
2926                            args.finish()?;
2927
2928                            let result = ctx
2929                                .interrupt_emitter(crate::Expression::SubgroupBallotResult, span)?;
2930                            let rctx = ctx.runtime_expression_ctx(span)?;
2931                            rctx.block
2932                                .push(crate::Statement::SubgroupBallot { result, predicate }, span);
2933                            return Ok(Some(result));
2934                        }
2935                        _ => {
2936                            return Err(Box::new(Error::UnknownIdent(function.span, function.name)))
2937                        }
2938                    }
2939                };
2940
2941                let expr = ctx.append_expression(expr, span)?;
2942                Ok(Some(expr))
2943            }
2944        }
2945    }
2946
2947    /// Generate a Naga IR [`Math`] expression.
2948    ///
2949    /// Generate Naga IR for a call to the [`MathFunction`] `fun`, whose
2950    /// unlowered arguments are `ast_arguments`.
2951    ///
2952    /// The `span` argument should give the span of the function name in the
2953    /// call expression.
2954    ///
2955    /// [`Math`]: crate::ir::Expression::Math
2956    /// [`MathFunction`]: crate::ir::MathFunction
2957    fn math_function_helper(
2958        &mut self,
2959        span: Span,
2960        fun: crate::ir::MathFunction,
2961        ast_arguments: &[Handle<ast::Expression<'source>>],
2962        ctx: &mut ExpressionContext<'source, '_, '_>,
2963    ) -> Result<'source, crate::ir::Expression> {
2964        let mut lowered_arguments = Vec::with_capacity(ast_arguments.len());
2965        for &arg in ast_arguments {
2966            let lowered = self.expression_for_abstract(arg, ctx)?;
2967            ctx.grow_types(lowered)?;
2968            lowered_arguments.push(lowered);
2969        }
2970
2971        let fun_overloads = fun.overloads();
2972        let rule = self.resolve_overloads(span, fun, fun_overloads, &lowered_arguments, ctx)?;
2973        self.apply_automatic_conversions_for_call(&rule, &mut lowered_arguments, ctx)?;
2974
2975        // If this function returns a predeclared type, register it
2976        // in `Module::special_types`. The typifier will expect to
2977        // be able to find it there.
2978        if let crate::proc::Conclusion::Predeclared(predeclared) = rule.conclusion {
2979            ctx.module.generate_predeclared_type(predeclared);
2980        }
2981
2982        Ok(crate::Expression::Math {
2983            fun,
2984            arg: lowered_arguments[0],
2985            arg1: lowered_arguments.get(1).cloned(),
2986            arg2: lowered_arguments.get(2).cloned(),
2987            arg3: lowered_arguments.get(3).cloned(),
2988        })
2989    }
2990
2991    /// Choose the right overload for a function call.
2992    ///
2993    /// Return a [`Rule`] representing the most preferred overload in
2994    /// `overloads` to apply to `arguments`, or return an error explaining why
2995    /// the call is not valid.
2996    ///
2997    /// Use `fun` to identify the function being called in error messages;
2998    /// `span` should be the span of the function name in the call expression.
2999    ///
3000    /// [`Rule`]: crate::proc::Rule
3001    fn resolve_overloads<O, F>(
3002        &self,
3003        span: Span,
3004        fun: F,
3005        overloads: O,
3006        arguments: &[Handle<crate::ir::Expression>],
3007        ctx: &ExpressionContext<'source, '_, '_>,
3008    ) -> Result<'source, crate::proc::Rule>
3009    where
3010        O: crate::proc::OverloadSet,
3011        F: TryToWgsl + core::fmt::Debug + Copy,
3012    {
3013        let mut remaining_overloads = overloads.clone();
3014        let min_arguments = remaining_overloads.min_arguments();
3015        let max_arguments = remaining_overloads.max_arguments();
3016        if arguments.len() < min_arguments {
3017            return Err(Box::new(Error::WrongArgumentCount {
3018                span,
3019                expected: min_arguments as u32..max_arguments as u32,
3020                found: arguments.len() as u32,
3021            }));
3022        }
3023        if arguments.len() > max_arguments {
3024            return Err(Box::new(Error::TooManyArguments {
3025                function: fun.to_wgsl_for_diagnostics(),
3026                call_span: span,
3027                arg_span: ctx.get_expression_span(arguments[max_arguments]),
3028                max_arguments: max_arguments as _,
3029            }));
3030        }
3031
3032        log::debug!(
3033            "Initial overloads: {:#?}",
3034            remaining_overloads.for_debug(&ctx.module.types)
3035        );
3036
3037        for (arg_index, &arg) in arguments.iter().enumerate() {
3038            let arg_type_resolution = &ctx.typifier()[arg];
3039            let arg_inner = arg_type_resolution.inner_with(&ctx.module.types);
3040            log::debug!(
3041                "Supplying argument {arg_index} of type {:?}",
3042                arg_type_resolution.for_debug(&ctx.module.types)
3043            );
3044            let next_remaining_overloads =
3045                remaining_overloads.arg(arg_index, arg_inner, &ctx.module.types);
3046
3047            // If any argument is not a constant expression, then no overloads
3048            // that accept abstract values should be considered.
3049            // (`OverloadSet::concrete_only` is supposed to help impose this
3050            // restriction.) However, no `MathFunction` accepts a mix of
3051            // abstract and concrete arguments, so we don't need to worry
3052            // about that here.
3053
3054            log::debug!(
3055                "Remaining overloads: {:#?}",
3056                next_remaining_overloads.for_debug(&ctx.module.types)
3057            );
3058
3059            // If the set of remaining overloads is empty, then this argument's type
3060            // was unacceptable. Diagnose the problem and produce an error message.
3061            if next_remaining_overloads.is_empty() {
3062                let function = fun.to_wgsl_for_diagnostics();
3063                let call_span = span;
3064                let arg_span = ctx.get_expression_span(arg);
3065                let arg_ty = ctx.as_diagnostic_display(arg_type_resolution).to_string();
3066
3067                // Is this type *ever* permitted for the arg_index'th argument?
3068                // For example, `bool` is never permitted for `max`.
3069                let only_this_argument = overloads.arg(arg_index, arg_inner, &ctx.module.types);
3070                if only_this_argument.is_empty() {
3071                    // No overload of `fun` accepts this type as the
3072                    // arg_index'th argument. Determine the set of types that
3073                    // would ever be allowed there.
3074                    let allowed: Vec<String> = overloads
3075                        .allowed_args(arg_index, &ctx.module.to_ctx())
3076                        .iter()
3077                        .map(|ty| ctx.type_resolution_to_string(ty))
3078                        .collect();
3079
3080                    if allowed.is_empty() {
3081                        // No overload of `fun` accepts any argument at this
3082                        // index, so it's a simple case of excess arguments.
3083                        // However, since each `MathFunction`'s overloads all
3084                        // have the same arity, we should have detected this
3085                        // earlier.
3086                        unreachable!("expected all overloads to have the same arity");
3087                    }
3088
3089                    // Some overloads of `fun` do accept this many arguments,
3090                    // but none accept one of this type.
3091                    return Err(Box::new(Error::WrongArgumentType {
3092                        function,
3093                        call_span,
3094                        arg_span,
3095                        arg_index: arg_index as u32,
3096                        arg_ty,
3097                        allowed,
3098                    }));
3099                }
3100
3101                // This argument's type is accepted by some overloads---just
3102                // not those overloads that remain, given the prior arguments.
3103                // For example, `max` accepts `f32` as its second argument -
3104                // but not if the first was `i32`.
3105
3106                // Build a list of the types that would have been accepted here,
3107                // given the prior arguments.
3108                let allowed: Vec<String> = remaining_overloads
3109                    .allowed_args(arg_index, &ctx.module.to_ctx())
3110                    .iter()
3111                    .map(|ty| ctx.type_resolution_to_string(ty))
3112                    .collect();
3113
3114                // Re-run the argument list to determine which prior argument
3115                // made this one unacceptable.
3116                let mut remaining_overloads = overloads;
3117                for (prior_index, &prior_expr) in arguments.iter().enumerate() {
3118                    let prior_type_resolution = &ctx.typifier()[prior_expr];
3119                    let prior_ty = prior_type_resolution.inner_with(&ctx.module.types);
3120                    remaining_overloads =
3121                        remaining_overloads.arg(prior_index, prior_ty, &ctx.module.types);
3122                    if remaining_overloads
3123                        .arg(arg_index, arg_inner, &ctx.module.types)
3124                        .is_empty()
3125                    {
3126                        // This is the argument that killed our dreams.
3127                        let inconsistent_span = ctx.get_expression_span(arguments[prior_index]);
3128                        let inconsistent_ty =
3129                            ctx.as_diagnostic_display(prior_type_resolution).to_string();
3130
3131                        if allowed.is_empty() {
3132                            // Some overloads did accept `ty` at `arg_index`, but
3133                            // given the arguments up through `prior_expr`, we see
3134                            // no types acceptable at `arg_index`. This means that some
3135                            // overloads expect fewer arguments than others. However,
3136                            // each `MathFunction`'s overloads have the same arity, so this
3137                            // should be impossible.
3138                            unreachable!("expected all overloads to have the same arity");
3139                        }
3140
3141                        // Report `arg`'s type as inconsistent with `prior_expr`'s
3142                        return Err(Box::new(Error::InconsistentArgumentType {
3143                            function,
3144                            call_span,
3145                            arg_span,
3146                            arg_index: arg_index as u32,
3147                            arg_ty,
3148                            inconsistent_span,
3149                            inconsistent_index: prior_index as u32,
3150                            inconsistent_ty,
3151                            allowed,
3152                        }));
3153                    }
3154                }
3155                unreachable!("Failed to eliminate argument type when re-tried");
3156            }
3157            remaining_overloads = next_remaining_overloads;
3158        }
3159
3160        // Select the most preferred type rule for this call,
3161        // given the argument types supplied above.
3162        Ok(remaining_overloads.most_preferred())
3163    }
3164
3165    /// Apply automatic type conversions for a function call.
3166    ///
3167    /// Apply whatever automatic conversions are needed to pass `arguments` to
3168    /// the function overload described by `rule`. Update `arguments` to refer
3169    /// to the converted arguments.
3170    fn apply_automatic_conversions_for_call(
3171        &self,
3172        rule: &crate::proc::Rule,
3173        arguments: &mut [Handle<crate::ir::Expression>],
3174        ctx: &mut ExpressionContext<'source, '_, '_>,
3175    ) -> Result<'source, ()> {
3176        for (i, argument) in arguments.iter_mut().enumerate() {
3177            let goal_inner = rule.arguments[i].inner_with(&ctx.module.types);
3178            let converted = match goal_inner.scalar_for_conversions(&ctx.module.types) {
3179                Some(goal_scalar) => {
3180                    let arg_span = ctx.get_expression_span(*argument);
3181                    ctx.try_automatic_conversion_for_leaf_scalar(*argument, goal_scalar, arg_span)?
3182                }
3183                // No conversion is necessary.
3184                None => *argument,
3185            };
3186
3187            *argument = converted;
3188        }
3189
3190        Ok(())
3191    }
3192
3193    fn atomic_pointer(
3194        &mut self,
3195        expr: Handle<ast::Expression<'source>>,
3196        ctx: &mut ExpressionContext<'source, '_, '_>,
3197    ) -> Result<'source, Handle<crate::Expression>> {
3198        let span = ctx.ast_expressions.get_span(expr);
3199        let pointer = self.expression(expr, ctx)?;
3200
3201        match *resolve_inner!(ctx, pointer) {
3202            crate::TypeInner::Pointer { base, .. } => match ctx.module.types[base].inner {
3203                crate::TypeInner::Atomic { .. } => Ok(pointer),
3204                ref other => {
3205                    log::error!("Pointer type to {:?} passed to atomic op", other);
3206                    Err(Box::new(Error::InvalidAtomicPointer(span)))
3207                }
3208            },
3209            ref other => {
3210                log::error!("Type {:?} passed to atomic op", other);
3211                Err(Box::new(Error::InvalidAtomicPointer(span)))
3212            }
3213        }
3214    }
3215
3216    fn atomic_helper(
3217        &mut self,
3218        span: Span,
3219        fun: crate::AtomicFunction,
3220        args: &[Handle<ast::Expression<'source>>],
3221        is_statement: bool,
3222        ctx: &mut ExpressionContext<'source, '_, '_>,
3223    ) -> Result<'source, Option<Handle<crate::Expression>>> {
3224        let mut args = ctx.prepare_args(args, 2, span);
3225
3226        let pointer = self.atomic_pointer(args.next()?, ctx)?;
3227        let value = self.expression(args.next()?, ctx)?;
3228        let value_inner = resolve_inner!(ctx, value);
3229        args.finish()?;
3230
3231        // If we don't use the return value of a 64-bit `min` or `max`
3232        // operation, generate a no-result form of the `Atomic` statement, so
3233        // that we can pass validation with only `SHADER_INT64_ATOMIC_MIN_MAX`
3234        // whenever possible.
3235        let is_64_bit_min_max =
3236            matches!(fun, crate::AtomicFunction::Min | crate::AtomicFunction::Max)
3237                && matches!(
3238                    *value_inner,
3239                    crate::TypeInner::Scalar(crate::Scalar { width: 8, .. })
3240                );
3241        let result = if is_64_bit_min_max && is_statement {
3242            let rctx = ctx.runtime_expression_ctx(span)?;
3243            rctx.block
3244                .extend(rctx.emitter.finish(&rctx.function.expressions));
3245            rctx.emitter.start(&rctx.function.expressions);
3246            None
3247        } else {
3248            let ty = ctx.register_type(value)?;
3249            Some(ctx.interrupt_emitter(
3250                crate::Expression::AtomicResult {
3251                    ty,
3252                    comparison: false,
3253                },
3254                span,
3255            )?)
3256        };
3257        let rctx = ctx.runtime_expression_ctx(span)?;
3258        rctx.block.push(
3259            crate::Statement::Atomic {
3260                pointer,
3261                fun,
3262                value,
3263                result,
3264            },
3265            span,
3266        );
3267        Ok(result)
3268    }
3269
3270    fn texture_sample_helper(
3271        &mut self,
3272        fun: Texture,
3273        args: &[Handle<ast::Expression<'source>>],
3274        span: Span,
3275        ctx: &mut ExpressionContext<'source, '_, '_>,
3276    ) -> Result<'source, crate::Expression> {
3277        let mut args = ctx.prepare_args(args, fun.min_argument_count(), span);
3278
3279        fn get_image_and_span<'source>(
3280            lowerer: &mut Lowerer<'source, '_>,
3281            args: &mut ArgumentContext<'_, 'source>,
3282            ctx: &mut ExpressionContext<'source, '_, '_>,
3283        ) -> Result<'source, (Handle<crate::Expression>, Span)> {
3284            let image = args.next()?;
3285            let image_span = ctx.ast_expressions.get_span(image);
3286            let image = lowerer.expression(image, ctx)?;
3287            Ok((image, image_span))
3288        }
3289
3290        let (image, image_span, gather) = match fun {
3291            Texture::Gather => {
3292                let image_or_component = args.next()?;
3293                let image_or_component_span = ctx.ast_expressions.get_span(image_or_component);
3294                // Gathers from depth textures don't take an initial `component` argument.
3295                let lowered_image_or_component = self.expression(image_or_component, ctx)?;
3296
3297                match *resolve_inner!(ctx, lowered_image_or_component) {
3298                    crate::TypeInner::Image {
3299                        class: crate::ImageClass::Depth { .. },
3300                        ..
3301                    } => (
3302                        lowered_image_or_component,
3303                        image_or_component_span,
3304                        Some(crate::SwizzleComponent::X),
3305                    ),
3306                    _ => {
3307                        let (image, image_span) = get_image_and_span(self, &mut args, ctx)?;
3308                        (
3309                            image,
3310                            image_span,
3311                            Some(ctx.gather_component(
3312                                lowered_image_or_component,
3313                                image_or_component_span,
3314                                span,
3315                            )?),
3316                        )
3317                    }
3318                }
3319            }
3320            Texture::GatherCompare => {
3321                let (image, image_span) = get_image_and_span(self, &mut args, ctx)?;
3322                (image, image_span, Some(crate::SwizzleComponent::X))
3323            }
3324
3325            _ => {
3326                let (image, image_span) = get_image_and_span(self, &mut args, ctx)?;
3327                (image, image_span, None)
3328            }
3329        };
3330
3331        let sampler = self.expression(args.next()?, ctx)?;
3332
3333        let coordinate = self.expression(args.next()?, ctx)?;
3334
3335        let (_, arrayed) = ctx.image_data(image, image_span)?;
3336        let array_index = arrayed
3337            .then(|| self.expression(args.next()?, ctx))
3338            .transpose()?;
3339
3340        let (level, depth_ref) = match fun {
3341            Texture::Gather => (crate::SampleLevel::Zero, None),
3342            Texture::GatherCompare => {
3343                let reference = self.expression(args.next()?, ctx)?;
3344                (crate::SampleLevel::Zero, Some(reference))
3345            }
3346
3347            Texture::Sample => (crate::SampleLevel::Auto, None),
3348            Texture::SampleBias => {
3349                let bias = self.expression(args.next()?, ctx)?;
3350                (crate::SampleLevel::Bias(bias), None)
3351            }
3352            Texture::SampleCompare => {
3353                let reference = self.expression(args.next()?, ctx)?;
3354                (crate::SampleLevel::Auto, Some(reference))
3355            }
3356            Texture::SampleCompareLevel => {
3357                let reference = self.expression(args.next()?, ctx)?;
3358                (crate::SampleLevel::Zero, Some(reference))
3359            }
3360            Texture::SampleGrad => {
3361                let x = self.expression(args.next()?, ctx)?;
3362                let y = self.expression(args.next()?, ctx)?;
3363                (crate::SampleLevel::Gradient { x, y }, None)
3364            }
3365            Texture::SampleLevel => {
3366                let level = self.expression(args.next()?, ctx)?;
3367                (crate::SampleLevel::Exact(level), None)
3368            }
3369        };
3370
3371        let offset = args
3372            .next()
3373            .map(|arg| self.expression(arg, &mut ctx.as_const()))
3374            .ok()
3375            .transpose()?;
3376
3377        args.finish()?;
3378
3379        Ok(crate::Expression::ImageSample {
3380            image,
3381            sampler,
3382            gather,
3383            coordinate,
3384            array_index,
3385            offset,
3386            level,
3387            depth_ref,
3388        })
3389    }
3390
3391    fn subgroup_operation_helper(
3392        &mut self,
3393        span: Span,
3394        op: crate::SubgroupOperation,
3395        collective_op: crate::CollectiveOperation,
3396        arguments: &[Handle<ast::Expression<'source>>],
3397        ctx: &mut ExpressionContext<'source, '_, '_>,
3398    ) -> Result<'source, Handle<crate::Expression>> {
3399        let mut args = ctx.prepare_args(arguments, 1, span);
3400
3401        let argument = self.expression(args.next()?, ctx)?;
3402        args.finish()?;
3403
3404        let ty = ctx.register_type(argument)?;
3405
3406        let result =
3407            ctx.interrupt_emitter(crate::Expression::SubgroupOperationResult { ty }, span)?;
3408        let rctx = ctx.runtime_expression_ctx(span)?;
3409        rctx.block.push(
3410            crate::Statement::SubgroupCollectiveOperation {
3411                op,
3412                collective_op,
3413                argument,
3414                result,
3415            },
3416            span,
3417        );
3418        Ok(result)
3419    }
3420
3421    fn subgroup_gather_helper(
3422        &mut self,
3423        span: Span,
3424        mode: SubgroupGather,
3425        arguments: &[Handle<ast::Expression<'source>>],
3426        ctx: &mut ExpressionContext<'source, '_, '_>,
3427    ) -> Result<'source, Handle<crate::Expression>> {
3428        let mut args = ctx.prepare_args(arguments, 2, span);
3429
3430        let argument = self.expression(args.next()?, ctx)?;
3431
3432        use SubgroupGather as Sg;
3433        let mode = if let Sg::BroadcastFirst = mode {
3434            crate::GatherMode::BroadcastFirst
3435        } else {
3436            let index = self.expression(args.next()?, ctx)?;
3437            match mode {
3438                Sg::Broadcast => crate::GatherMode::Broadcast(index),
3439                Sg::Shuffle => crate::GatherMode::Shuffle(index),
3440                Sg::ShuffleDown => crate::GatherMode::ShuffleDown(index),
3441                Sg::ShuffleUp => crate::GatherMode::ShuffleUp(index),
3442                Sg::ShuffleXor => crate::GatherMode::ShuffleXor(index),
3443                Sg::BroadcastFirst => unreachable!(),
3444            }
3445        };
3446
3447        args.finish()?;
3448
3449        let ty = ctx.register_type(argument)?;
3450
3451        let result =
3452            ctx.interrupt_emitter(crate::Expression::SubgroupOperationResult { ty }, span)?;
3453        let rctx = ctx.runtime_expression_ctx(span)?;
3454        rctx.block.push(
3455            crate::Statement::SubgroupGather {
3456                mode,
3457                argument,
3458                result,
3459            },
3460            span,
3461        );
3462        Ok(result)
3463    }
3464
3465    fn r#struct(
3466        &mut self,
3467        s: &ast::Struct<'source>,
3468        span: Span,
3469        ctx: &mut GlobalContext<'source, '_, '_>,
3470    ) -> Result<'source, Handle<crate::Type>> {
3471        let mut offset = 0;
3472        let mut struct_alignment = Alignment::ONE;
3473        let mut members = Vec::with_capacity(s.members.len());
3474
3475        for member in s.members.iter() {
3476            let ty = self.resolve_ast_type(member.ty, &mut ctx.as_const())?;
3477
3478            ctx.layouter.update(ctx.module.to_ctx()).unwrap();
3479
3480            let member_min_size = ctx.layouter[ty].size;
3481            let member_min_alignment = ctx.layouter[ty].alignment;
3482
3483            let member_size = if let Some(size_expr) = member.size {
3484                let (size, span) = self.const_u32(size_expr, &mut ctx.as_const())?;
3485                if size < member_min_size {
3486                    return Err(Box::new(Error::SizeAttributeTooLow(span, member_min_size)));
3487                } else {
3488                    size
3489                }
3490            } else {
3491                member_min_size
3492            };
3493
3494            let member_alignment = if let Some(align_expr) = member.align {
3495                let (align, span) = self.const_u32(align_expr, &mut ctx.as_const())?;
3496                if let Some(alignment) = Alignment::new(align) {
3497                    if alignment < member_min_alignment {
3498                        return Err(Box::new(Error::AlignAttributeTooLow(
3499                            span,
3500                            member_min_alignment,
3501                        )));
3502                    } else {
3503                        alignment
3504                    }
3505                } else {
3506                    return Err(Box::new(Error::NonPowerOfTwoAlignAttribute(span)));
3507                }
3508            } else {
3509                member_min_alignment
3510            };
3511
3512            let binding = self.binding(&member.binding, ty, ctx)?;
3513
3514            offset = member_alignment.round_up(offset);
3515            struct_alignment = struct_alignment.max(member_alignment);
3516
3517            members.push(crate::StructMember {
3518                name: Some(member.name.name.to_owned()),
3519                ty,
3520                binding,
3521                offset,
3522            });
3523
3524            offset += member_size;
3525        }
3526
3527        let size = struct_alignment.round_up(offset);
3528        let inner = crate::TypeInner::Struct {
3529            members,
3530            span: size,
3531        };
3532
3533        let handle = ctx.module.types.insert(
3534            crate::Type {
3535                name: Some(s.name.name.to_string()),
3536                inner,
3537            },
3538            span,
3539        );
3540        Ok(handle)
3541    }
3542
3543    fn const_u32(
3544        &mut self,
3545        expr: Handle<ast::Expression<'source>>,
3546        ctx: &mut ExpressionContext<'source, '_, '_>,
3547    ) -> Result<'source, (u32, Span)> {
3548        let span = ctx.ast_expressions.get_span(expr);
3549        let expr = self.expression(expr, ctx)?;
3550        let value = ctx
3551            .module
3552            .to_ctx()
3553            .eval_expr_to_u32(expr)
3554            .map_err(|err| match err {
3555                crate::proc::U32EvalError::NonConst => {
3556                    Error::ExpectedConstExprConcreteIntegerScalar(span)
3557                }
3558                crate::proc::U32EvalError::Negative => Error::ExpectedNonNegative(span),
3559            })?;
3560        Ok((value, span))
3561    }
3562
3563    fn array_size(
3564        &mut self,
3565        size: ast::ArraySize<'source>,
3566        ctx: &mut ExpressionContext<'source, '_, '_>,
3567    ) -> Result<'source, crate::ArraySize> {
3568        Ok(match size {
3569            ast::ArraySize::Constant(expr) => {
3570                let span = ctx.ast_expressions.get_span(expr);
3571                let const_expr = self.expression(expr, &mut ctx.as_const());
3572                match const_expr {
3573                    Ok(value) => {
3574                        let len = ctx.const_eval_expr_to_u32(value).map_err(|err| {
3575                            Box::new(match err {
3576                                crate::proc::U32EvalError::NonConst => {
3577                                    Error::ExpectedConstExprConcreteIntegerScalar(span)
3578                                }
3579                                crate::proc::U32EvalError::Negative => {
3580                                    Error::ExpectedPositiveArrayLength(span)
3581                                }
3582                            })
3583                        })?;
3584                        let size =
3585                            NonZeroU32::new(len).ok_or(Error::ExpectedPositiveArrayLength(span))?;
3586                        crate::ArraySize::Constant(size)
3587                    }
3588                    Err(err) => {
3589                        if let Error::ConstantEvaluatorError(ref ty, _) = *err {
3590                            match **ty {
3591                                crate::proc::ConstantEvaluatorError::OverrideExpr => {
3592                                    crate::ArraySize::Pending(self.array_size_override(
3593                                        expr,
3594                                        &mut ctx.as_global().as_override(),
3595                                        span,
3596                                    )?)
3597                                }
3598                                _ => {
3599                                    return Err(err);
3600                                }
3601                            }
3602                        } else {
3603                            return Err(err);
3604                        }
3605                    }
3606                }
3607            }
3608            ast::ArraySize::Dynamic => crate::ArraySize::Dynamic,
3609        })
3610    }
3611
3612    fn array_size_override(
3613        &mut self,
3614        size_expr: Handle<ast::Expression<'source>>,
3615        ctx: &mut ExpressionContext<'source, '_, '_>,
3616        span: Span,
3617    ) -> Result<'source, Handle<crate::Override>> {
3618        let expr = self.expression(size_expr, ctx)?;
3619        match resolve_inner!(ctx, expr).scalar_kind().ok_or(0) {
3620            Ok(crate::ScalarKind::Sint) | Ok(crate::ScalarKind::Uint) => Ok({
3621                if let crate::Expression::Override(handle) = ctx.module.global_expressions[expr] {
3622                    handle
3623                } else {
3624                    let ty = ctx.register_type(expr)?;
3625                    ctx.module.overrides.append(
3626                        crate::Override {
3627                            name: None,
3628                            id: None,
3629                            ty,
3630                            init: Some(expr),
3631                        },
3632                        span,
3633                    )
3634                }
3635            }),
3636            _ => Err(Box::new(Error::ExpectedConstExprConcreteIntegerScalar(
3637                span,
3638            ))),
3639        }
3640    }
3641
3642    /// Build the Naga equivalent of a named AST type.
3643    ///
3644    /// Return a Naga `Handle<Type>` representing the front-end type
3645    /// `handle`, which should be named `name`, if given.
3646    ///
3647    /// If `handle` refers to a type cached in [`SpecialTypes`],
3648    /// `name` may be ignored.
3649    ///
3650    /// [`SpecialTypes`]: crate::SpecialTypes
3651    fn resolve_named_ast_type(
3652        &mut self,
3653        handle: Handle<ast::Type<'source>>,
3654        name: Option<String>,
3655        ctx: &mut ExpressionContext<'source, '_, '_>,
3656    ) -> Result<'source, Handle<crate::Type>> {
3657        let inner = match ctx.types[handle] {
3658            ast::Type::Scalar(scalar) => scalar.to_inner_scalar(),
3659            ast::Type::Vector { size, ty, ty_span } => {
3660                let ty = self.resolve_ast_type(ty, ctx)?;
3661                let scalar = match ctx.module.types[ty].inner {
3662                    crate::TypeInner::Scalar(sc) => sc,
3663                    _ => return Err(Box::new(Error::UnknownScalarType(ty_span))),
3664                };
3665                crate::TypeInner::Vector { size, scalar }
3666            }
3667            ast::Type::Matrix {
3668                rows,
3669                columns,
3670                ty,
3671                ty_span,
3672            } => {
3673                let ty = self.resolve_ast_type(ty, ctx)?;
3674                let scalar = match ctx.module.types[ty].inner {
3675                    crate::TypeInner::Scalar(sc) => sc,
3676                    _ => return Err(Box::new(Error::UnknownScalarType(ty_span))),
3677                };
3678                match scalar.kind {
3679                    crate::ScalarKind::Float => crate::TypeInner::Matrix {
3680                        columns,
3681                        rows,
3682                        scalar,
3683                    },
3684                    _ => return Err(Box::new(Error::BadMatrixScalarKind(ty_span, scalar))),
3685                }
3686            }
3687            ast::Type::Atomic(scalar) => scalar.to_inner_atomic(),
3688            ast::Type::Pointer { base, space } => {
3689                let base = self.resolve_ast_type(base, ctx)?;
3690                crate::TypeInner::Pointer { base, space }
3691            }
3692            ast::Type::Array { base, size } => {
3693                let base = self.resolve_ast_type(base, &mut ctx.as_const())?;
3694                let size = self.array_size(size, ctx)?;
3695
3696                ctx.layouter.update(ctx.module.to_ctx()).unwrap();
3697                let stride = ctx.layouter[base].to_stride();
3698
3699                crate::TypeInner::Array { base, size, stride }
3700            }
3701            ast::Type::Image {
3702                dim,
3703                arrayed,
3704                class,
3705            } => crate::TypeInner::Image {
3706                dim,
3707                arrayed,
3708                class,
3709            },
3710            ast::Type::Sampler { comparison } => crate::TypeInner::Sampler { comparison },
3711            ast::Type::AccelerationStructure { vertex_return } => {
3712                crate::TypeInner::AccelerationStructure { vertex_return }
3713            }
3714            ast::Type::RayQuery { vertex_return } => crate::TypeInner::RayQuery { vertex_return },
3715            ast::Type::BindingArray { base, size } => {
3716                let base = self.resolve_ast_type(base, ctx)?;
3717                let size = self.array_size(size, ctx)?;
3718                crate::TypeInner::BindingArray { base, size }
3719            }
3720            ast::Type::RayDesc => {
3721                return Ok(ctx.module.generate_ray_desc_type());
3722            }
3723            ast::Type::RayIntersection => {
3724                return Ok(ctx.module.generate_ray_intersection_type());
3725            }
3726            ast::Type::User(ref ident) => {
3727                return match ctx.globals.get(ident.name) {
3728                    Some(&LoweredGlobalDecl::Type(handle)) => Ok(handle),
3729                    Some(_) => Err(Box::new(Error::Unexpected(ident.span, ExpectedToken::Type))),
3730                    None => Err(Box::new(Error::UnknownType(ident.span))),
3731                }
3732            }
3733        };
3734
3735        Ok(ctx.as_global().ensure_type_exists(name, inner))
3736    }
3737
3738    /// Return a Naga `Handle<Type>` representing the front-end type `handle`.
3739    fn resolve_ast_type(
3740        &mut self,
3741        handle: Handle<ast::Type<'source>>,
3742        ctx: &mut ExpressionContext<'source, '_, '_>,
3743    ) -> Result<'source, Handle<crate::Type>> {
3744        self.resolve_named_ast_type(handle, None, ctx)
3745    }
3746
3747    fn binding(
3748        &mut self,
3749        binding: &Option<ast::Binding<'source>>,
3750        ty: Handle<crate::Type>,
3751        ctx: &mut GlobalContext<'source, '_, '_>,
3752    ) -> Result<'source, Option<crate::Binding>> {
3753        Ok(match *binding {
3754            Some(ast::Binding::BuiltIn(b)) => Some(crate::Binding::BuiltIn(b)),
3755            Some(ast::Binding::Location {
3756                location,
3757                interpolation,
3758                sampling,
3759                blend_src,
3760            }) => {
3761                let blend_src = if let Some(blend_src) = blend_src {
3762                    Some(self.const_u32(blend_src, &mut ctx.as_const())?.0)
3763                } else {
3764                    None
3765                };
3766
3767                let mut binding = crate::Binding::Location {
3768                    location: self.const_u32(location, &mut ctx.as_const())?.0,
3769                    interpolation,
3770                    sampling,
3771                    blend_src,
3772                };
3773                binding.apply_default_interpolation(&ctx.module.types[ty].inner);
3774                Some(binding)
3775            }
3776            None => None,
3777        })
3778    }
3779
3780    fn ray_query_pointer(
3781        &mut self,
3782        expr: Handle<ast::Expression<'source>>,
3783        ctx: &mut ExpressionContext<'source, '_, '_>,
3784    ) -> Result<'source, Handle<crate::Expression>> {
3785        let span = ctx.ast_expressions.get_span(expr);
3786        let pointer = self.expression(expr, ctx)?;
3787
3788        match *resolve_inner!(ctx, pointer) {
3789            crate::TypeInner::Pointer { base, .. } => match ctx.module.types[base].inner {
3790                crate::TypeInner::RayQuery { .. } => Ok(pointer),
3791                ref other => {
3792                    log::error!("Pointer type to {:?} passed to ray query op", other);
3793                    Err(Box::new(Error::InvalidRayQueryPointer(span)))
3794                }
3795            },
3796            ref other => {
3797                log::error!("Type {:?} passed to ray query op", other);
3798                Err(Box::new(Error::InvalidRayQueryPointer(span)))
3799            }
3800        }
3801    }
3802}
3803
3804impl crate::AtomicFunction {
3805    pub fn map(word: &str) -> Option<Self> {
3806        Some(match word {
3807            "atomicAdd" => crate::AtomicFunction::Add,
3808            "atomicSub" => crate::AtomicFunction::Subtract,
3809            "atomicAnd" => crate::AtomicFunction::And,
3810            "atomicOr" => crate::AtomicFunction::InclusiveOr,
3811            "atomicXor" => crate::AtomicFunction::ExclusiveOr,
3812            "atomicMin" => crate::AtomicFunction::Min,
3813            "atomicMax" => crate::AtomicFunction::Max,
3814            "atomicExchange" => crate::AtomicFunction::Exchange { compare: None },
3815            _ => return None,
3816        })
3817    }
3818}