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