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