naga/front/wgsl/lower/
mod.rs

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