1use crate::arena::{Arena, UniqueArena};
2use crate::arena::{Handle, HandleSet};
3
4use super::validate_atomic_compare_exchange_struct;
5
6use super::{
7 analyzer::{UniformityDisruptor, UniformityRequirements},
8 ExpressionError, FunctionInfo, ModuleInfo,
9};
10use crate::span::WithSpan;
11use crate::span::{AddSpan as _, MapErrWithSpan as _};
12
13#[derive(Clone, Debug, thiserror::Error)]
14#[cfg_attr(test, derive(PartialEq))]
15pub enum CallError {
16 #[error("Argument {index} expression is invalid")]
17 Argument {
18 index: usize,
19 source: ExpressionError,
20 },
21 #[error("Result expression {0:?} has already been introduced earlier")]
22 ResultAlreadyInScope(Handle<crate::Expression>),
23 #[error("Result expression {0:?} is populated by multiple `Call` statements")]
24 ResultAlreadyPopulated(Handle<crate::Expression>),
25 #[error("Result value is invalid")]
26 ResultValue(#[source] ExpressionError),
27 #[error("Requires {required} arguments, but {seen} are provided")]
28 ArgumentCount { required: usize, seen: usize },
29 #[error("Argument {index} value {seen_expression:?} doesn't match the type {required:?}")]
30 ArgumentType {
31 index: usize,
32 required: Handle<crate::Type>,
33 seen_expression: Handle<crate::Expression>,
34 },
35 #[error("The emitted expression doesn't match the call")]
36 ExpressionMismatch(Option<Handle<crate::Expression>>),
37}
38
39#[derive(Clone, Debug, thiserror::Error)]
40#[cfg_attr(test, derive(PartialEq))]
41pub enum AtomicError {
42 #[error("Pointer {0:?} to atomic is invalid.")]
43 InvalidPointer(Handle<crate::Expression>),
44 #[error("Address space {0:?} does not support 64bit atomics.")]
45 InvalidAddressSpace(crate::AddressSpace),
46 #[error("Operand {0:?} has invalid type.")]
47 InvalidOperand(Handle<crate::Expression>),
48 #[error("Result expression {0:?} is not an `AtomicResult` expression")]
49 InvalidResultExpression(Handle<crate::Expression>),
50 #[error("Result expression {0:?} is marked as an `exchange`")]
51 ResultExpressionExchange(Handle<crate::Expression>),
52 #[error("Result expression {0:?} is not marked as an `exchange`")]
53 ResultExpressionNotExchange(Handle<crate::Expression>),
54 #[error("Result type for {0:?} doesn't match the statement")]
55 ResultTypeMismatch(Handle<crate::Expression>),
56 #[error("Exchange operations must return a value")]
57 MissingReturnValue,
58 #[error("Capability {0:?} is required")]
59 MissingCapability(super::Capabilities),
60 #[error("Result expression {0:?} is populated by multiple `Atomic` statements")]
61 ResultAlreadyPopulated(Handle<crate::Expression>),
62}
63
64#[derive(Clone, Debug, thiserror::Error)]
65#[cfg_attr(test, derive(PartialEq))]
66pub enum SubgroupError {
67 #[error("Operand {0:?} has invalid type.")]
68 InvalidOperand(Handle<crate::Expression>),
69 #[error("Result type for {0:?} doesn't match the statement")]
70 ResultTypeMismatch(Handle<crate::Expression>),
71 #[error("Support for subgroup operation {0:?} is required")]
72 UnsupportedOperation(super::SubgroupOperationSet),
73 #[error("Unknown operation")]
74 UnknownOperation,
75}
76
77#[derive(Clone, Debug, thiserror::Error)]
78#[cfg_attr(test, derive(PartialEq))]
79pub enum LocalVariableError {
80 #[error("Local variable has a type {0:?} that can't be stored in a local variable.")]
81 InvalidType(Handle<crate::Type>),
82 #[error("Initializer doesn't match the variable type")]
83 InitializerType,
84 #[error("Initializer is not a const or override expression")]
85 NonConstOrOverrideInitializer,
86}
87
88#[derive(Clone, Debug, thiserror::Error)]
89#[cfg_attr(test, derive(PartialEq))]
90pub enum FunctionError {
91 #[error("Expression {handle:?} is invalid")]
92 Expression {
93 handle: Handle<crate::Expression>,
94 source: ExpressionError,
95 },
96 #[error("Expression {0:?} can't be introduced - it's already in scope")]
97 ExpressionAlreadyInScope(Handle<crate::Expression>),
98 #[error("Local variable {handle:?} '{name}' is invalid")]
99 LocalVariable {
100 handle: Handle<crate::LocalVariable>,
101 name: String,
102 source: LocalVariableError,
103 },
104 #[error("Argument '{name}' at index {index} has a type that can't be passed into functions.")]
105 InvalidArgumentType { index: usize, name: String },
106 #[error("The function's given return type cannot be returned from functions")]
107 NonConstructibleReturnType,
108 #[error("Argument '{name}' at index {index} is a pointer of space {space:?}, which can't be passed into functions.")]
109 InvalidArgumentPointerSpace {
110 index: usize,
111 name: String,
112 space: crate::AddressSpace,
113 },
114 #[error("There are instructions after `return`/`break`/`continue`")]
115 InstructionsAfterReturn,
116 #[error("The `break` is used outside of a `loop` or `switch` context")]
117 BreakOutsideOfLoopOrSwitch,
118 #[error("The `continue` is used outside of a `loop` context")]
119 ContinueOutsideOfLoop,
120 #[error("The `return` is called within a `continuing` block")]
121 InvalidReturnSpot,
122 #[error("The `return` value {0:?} does not match the function return value")]
123 InvalidReturnType(Option<Handle<crate::Expression>>),
124 #[error("The `if` condition {0:?} is not a boolean scalar")]
125 InvalidIfType(Handle<crate::Expression>),
126 #[error("The `switch` value {0:?} is not an integer scalar")]
127 InvalidSwitchType(Handle<crate::Expression>),
128 #[error("Multiple `switch` cases for {0:?} are present")]
129 ConflictingSwitchCase(crate::SwitchValue),
130 #[error("The `switch` contains cases with conflicting types")]
131 ConflictingCaseType,
132 #[error("The `switch` is missing a `default` case")]
133 MissingDefaultCase,
134 #[error("Multiple `default` cases are present")]
135 MultipleDefaultCases,
136 #[error("The last `switch` case contains a `fallthrough`")]
137 LastCaseFallTrough,
138 #[error("The pointer {0:?} doesn't relate to a valid destination for a store")]
139 InvalidStorePointer(Handle<crate::Expression>),
140 #[error("The value {0:?} can not be stored")]
141 InvalidStoreValue(Handle<crate::Expression>),
142 #[error("The type of {value:?} doesn't match the type stored in {pointer:?}")]
143 InvalidStoreTypes {
144 pointer: Handle<crate::Expression>,
145 value: Handle<crate::Expression>,
146 },
147 #[error("Image store parameters are invalid")]
148 InvalidImageStore(#[source] ExpressionError),
149 #[error("Call to {function:?} is invalid")]
150 InvalidCall {
151 function: Handle<crate::Function>,
152 #[source]
153 error: CallError,
154 },
155 #[error("Atomic operation is invalid")]
156 InvalidAtomic(#[from] AtomicError),
157 #[error("Ray Query {0:?} is not a local variable")]
158 InvalidRayQueryExpression(Handle<crate::Expression>),
159 #[error("Acceleration structure {0:?} is not a matching expression")]
160 InvalidAccelerationStructure(Handle<crate::Expression>),
161 #[error("Ray descriptor {0:?} is not a matching expression")]
162 InvalidRayDescriptor(Handle<crate::Expression>),
163 #[error("Ray Query {0:?} does not have a matching type")]
164 InvalidRayQueryType(Handle<crate::Type>),
165 #[error("Shader requires capability {0:?}")]
166 MissingCapability(super::Capabilities),
167 #[error(
168 "Required uniformity of control flow for {0:?} in {1:?} is not fulfilled because of {2:?}"
169 )]
170 NonUniformControlFlow(
171 UniformityRequirements,
172 Handle<crate::Expression>,
173 UniformityDisruptor,
174 ),
175 #[error("Functions that are not entry points cannot have `@location` or `@builtin` attributes on their arguments: \"{name}\" has attributes")]
176 PipelineInputRegularFunction { name: String },
177 #[error("Functions that are not entry points cannot have `@location` or `@builtin` attributes on their return value types")]
178 PipelineOutputRegularFunction,
179 #[error("Required uniformity for WorkGroupUniformLoad is not fulfilled because of {0:?}")]
180 NonUniformWorkgroupUniformLoad(UniformityDisruptor),
182 #[error("The expression {0:?} for a WorkGroupUniformLoad isn't a WorkgroupUniformLoadResult")]
184 WorkgroupUniformLoadExpressionMismatch(Handle<crate::Expression>),
185 #[error("The expression {0:?} is not valid as a WorkGroupUniformLoad argument. It should be a Pointer in Workgroup address space")]
186 WorkgroupUniformLoadInvalidPointer(Handle<crate::Expression>),
187 #[error("Subgroup operation is invalid")]
188 InvalidSubgroup(#[from] SubgroupError),
189 #[error("Emit statement should not cover \"result\" expressions like {0:?}")]
190 EmitResult(Handle<crate::Expression>),
191 #[error("Expression not visited by the appropriate statement")]
192 UnvisitedExpression(Handle<crate::Expression>),
193}
194
195bitflags::bitflags! {
196 #[repr(transparent)]
197 #[derive(Clone, Copy)]
198 struct ControlFlowAbility: u8 {
199 const RETURN = 0x1;
201 const BREAK = 0x2;
203 const CONTINUE = 0x4;
205 }
206}
207
208struct BlockInfo {
209 stages: super::ShaderStages,
210 finished: bool,
211}
212
213struct BlockContext<'a> {
214 abilities: ControlFlowAbility,
215 info: &'a FunctionInfo,
216 expressions: &'a Arena<crate::Expression>,
217 types: &'a UniqueArena<crate::Type>,
218 local_vars: &'a Arena<crate::LocalVariable>,
219 global_vars: &'a Arena<crate::GlobalVariable>,
220 functions: &'a Arena<crate::Function>,
221 special_types: &'a crate::SpecialTypes,
222 prev_infos: &'a [FunctionInfo],
223 return_type: Option<Handle<crate::Type>>,
224}
225
226impl<'a> BlockContext<'a> {
227 fn new(
228 fun: &'a crate::Function,
229 module: &'a crate::Module,
230 info: &'a FunctionInfo,
231 prev_infos: &'a [FunctionInfo],
232 ) -> Self {
233 Self {
234 abilities: ControlFlowAbility::RETURN,
235 info,
236 expressions: &fun.expressions,
237 types: &module.types,
238 local_vars: &fun.local_variables,
239 global_vars: &module.global_variables,
240 functions: &module.functions,
241 special_types: &module.special_types,
242 prev_infos,
243 return_type: fun.result.as_ref().map(|fr| fr.ty),
244 }
245 }
246
247 const fn with_abilities(&self, abilities: ControlFlowAbility) -> Self {
248 BlockContext { abilities, ..*self }
249 }
250
251 fn get_expression(&self, handle: Handle<crate::Expression>) -> &'a crate::Expression {
252 &self.expressions[handle]
253 }
254
255 fn resolve_type_impl(
256 &self,
257 handle: Handle<crate::Expression>,
258 valid_expressions: &HandleSet<crate::Expression>,
259 ) -> Result<&crate::TypeInner, WithSpan<ExpressionError>> {
260 if !valid_expressions.contains(handle) {
261 Err(ExpressionError::NotInScope.with_span_handle(handle, self.expressions))
262 } else {
263 Ok(self.info[handle].ty.inner_with(self.types))
264 }
265 }
266
267 fn resolve_type(
268 &self,
269 handle: Handle<crate::Expression>,
270 valid_expressions: &HandleSet<crate::Expression>,
271 ) -> Result<&crate::TypeInner, WithSpan<FunctionError>> {
272 self.resolve_type_impl(handle, valid_expressions)
273 .map_err_inner(|source| FunctionError::Expression { handle, source }.with_span())
274 }
275
276 fn resolve_pointer_type(&self, handle: Handle<crate::Expression>) -> &crate::TypeInner {
277 self.info[handle].ty.inner_with(self.types)
278 }
279}
280
281impl super::Validator {
282 fn validate_call(
283 &mut self,
284 function: Handle<crate::Function>,
285 arguments: &[Handle<crate::Expression>],
286 result: Option<Handle<crate::Expression>>,
287 context: &BlockContext,
288 ) -> Result<super::ShaderStages, WithSpan<CallError>> {
289 let fun = &context.functions[function];
290 if fun.arguments.len() != arguments.len() {
291 return Err(CallError::ArgumentCount {
292 required: fun.arguments.len(),
293 seen: arguments.len(),
294 }
295 .with_span());
296 }
297 for (index, (arg, &expr)) in fun.arguments.iter().zip(arguments).enumerate() {
298 let ty = context
299 .resolve_type_impl(expr, &self.valid_expression_set)
300 .map_err_inner(|source| {
301 CallError::Argument { index, source }
302 .with_span_handle(expr, context.expressions)
303 })?;
304 let arg_inner = &context.types[arg.ty].inner;
305 if !ty.equivalent(arg_inner, context.types) {
306 return Err(CallError::ArgumentType {
307 index,
308 required: arg.ty,
309 seen_expression: expr,
310 }
311 .with_span_handle(expr, context.expressions));
312 }
313 }
314
315 if let Some(expr) = result {
316 if self.valid_expression_set.insert(expr) {
317 self.valid_expression_list.push(expr);
318 } else {
319 return Err(CallError::ResultAlreadyInScope(expr)
320 .with_span_handle(expr, context.expressions));
321 }
322 match context.expressions[expr] {
323 crate::Expression::CallResult(callee)
324 if fun.result.is_some() && callee == function =>
325 {
326 if !self.needs_visit.remove(expr) {
327 return Err(CallError::ResultAlreadyPopulated(expr)
328 .with_span_handle(expr, context.expressions));
329 }
330 }
331 _ => {
332 return Err(CallError::ExpressionMismatch(result)
333 .with_span_handle(expr, context.expressions))
334 }
335 }
336 } else if fun.result.is_some() {
337 return Err(CallError::ExpressionMismatch(result).with_span());
338 }
339
340 let callee_info = &context.prev_infos[function.index()];
341 Ok(callee_info.available_stages)
342 }
343
344 fn emit_expression(
345 &mut self,
346 handle: Handle<crate::Expression>,
347 context: &BlockContext,
348 ) -> Result<(), WithSpan<FunctionError>> {
349 if self.valid_expression_set.insert(handle) {
350 self.valid_expression_list.push(handle);
351 Ok(())
352 } else {
353 Err(FunctionError::ExpressionAlreadyInScope(handle)
354 .with_span_handle(handle, context.expressions))
355 }
356 }
357
358 fn validate_atomic(
359 &mut self,
360 pointer: Handle<crate::Expression>,
361 fun: &crate::AtomicFunction,
362 value: Handle<crate::Expression>,
363 result: Option<Handle<crate::Expression>>,
364 span: crate::Span,
365 context: &BlockContext,
366 ) -> Result<(), WithSpan<FunctionError>> {
367 let pointer_inner = context.resolve_type(pointer, &self.valid_expression_set)?;
369 let crate::TypeInner::Pointer {
370 base: pointer_base,
371 space: pointer_space,
372 } = *pointer_inner
373 else {
374 log::error!("Atomic operation on type {:?}", *pointer_inner);
375 return Err(AtomicError::InvalidPointer(pointer)
376 .with_span_handle(pointer, context.expressions)
377 .into_other());
378 };
379 let crate::TypeInner::Atomic(pointer_scalar) = context.types[pointer_base].inner else {
380 log::error!(
381 "Atomic pointer to type {:?}",
382 context.types[pointer_base].inner
383 );
384 return Err(AtomicError::InvalidPointer(pointer)
385 .with_span_handle(pointer, context.expressions)
386 .into_other());
387 };
388
389 let value_inner = context.resolve_type(value, &self.valid_expression_set)?;
391 let crate::TypeInner::Scalar(value_scalar) = *value_inner else {
392 log::error!("Atomic operand type {:?}", *value_inner);
393 return Err(AtomicError::InvalidOperand(value)
394 .with_span_handle(value, context.expressions)
395 .into_other());
396 };
397 if pointer_scalar != value_scalar {
398 log::error!("Atomic operand type {:?}", *value_inner);
399 return Err(AtomicError::InvalidOperand(value)
400 .with_span_handle(value, context.expressions)
401 .into_other());
402 }
403
404 if pointer_scalar.width == 8 {
410 if self
413 .capabilities
414 .contains(super::Capabilities::SHADER_INT64_ATOMIC_ALL_OPS)
415 {
416 } else {
418 if matches!(
421 *fun,
422 crate::AtomicFunction::Min | crate::AtomicFunction::Max
423 ) && matches!(pointer_space, crate::AddressSpace::Storage { .. })
424 && result.is_none()
425 {
426 if !self
427 .capabilities
428 .contains(super::Capabilities::SHADER_INT64_ATOMIC_MIN_MAX)
429 {
430 log::error!("Int64 min-max atomic operations are not supported");
431 return Err(AtomicError::MissingCapability(
432 super::Capabilities::SHADER_INT64_ATOMIC_MIN_MAX,
433 )
434 .with_span_handle(value, context.expressions)
435 .into_other());
436 }
437 } else {
438 log::error!("Int64 atomic operations are not supported");
440 return Err(AtomicError::MissingCapability(
441 super::Capabilities::SHADER_INT64_ATOMIC_ALL_OPS,
442 )
443 .with_span_handle(value, context.expressions)
444 .into_other());
445 }
446 }
447 }
448
449 match result {
451 Some(result) => {
452 let crate::Expression::AtomicResult {
454 ty: result_ty,
455 comparison,
456 } = context.expressions[result]
457 else {
458 return Err(AtomicError::InvalidResultExpression(result)
459 .with_span_handle(result, context.expressions)
460 .into_other());
461 };
462
463 if !self.needs_visit.remove(result) {
466 return Err(AtomicError::ResultAlreadyPopulated(result)
467 .with_span_handle(result, context.expressions)
468 .into_other());
469 }
470
471 if let crate::AtomicFunction::Exchange {
473 compare: Some(compare),
474 } = *fun
475 {
476 let compare_inner =
479 context.resolve_type(compare, &self.valid_expression_set)?;
480 if !compare_inner.equivalent(value_inner, context.types) {
481 log::error!(
482 "Atomic exchange comparison has a different type from the value"
483 );
484 return Err(AtomicError::InvalidOperand(compare)
485 .with_span_handle(compare, context.expressions)
486 .into_other());
487 }
488
489 let crate::TypeInner::Struct { ref members, .. } =
493 context.types[result_ty].inner
494 else {
495 return Err(AtomicError::ResultTypeMismatch(result)
496 .with_span_handle(result, context.expressions)
497 .into_other());
498 };
499 if !validate_atomic_compare_exchange_struct(
500 context.types,
501 members,
502 |ty: &crate::TypeInner| *ty == crate::TypeInner::Scalar(pointer_scalar),
503 ) {
504 return Err(AtomicError::ResultTypeMismatch(result)
505 .with_span_handle(result, context.expressions)
506 .into_other());
507 }
508
509 if !comparison {
511 return Err(AtomicError::ResultExpressionNotExchange(result)
512 .with_span_handle(result, context.expressions)
513 .into_other());
514 }
515 } else {
516 let result_inner = &context.types[result_ty].inner;
519 if !result_inner.equivalent(value_inner, context.types) {
520 return Err(AtomicError::ResultTypeMismatch(result)
521 .with_span_handle(result, context.expressions)
522 .into_other());
523 }
524
525 if comparison {
527 return Err(AtomicError::ResultExpressionExchange(result)
528 .with_span_handle(result, context.expressions)
529 .into_other());
530 }
531 }
532 self.emit_expression(result, context)?;
533 }
534
535 None => {
536 if let crate::AtomicFunction::Exchange { compare: None } = *fun {
538 log::error!("Atomic exchange's value is unused");
539 return Err(AtomicError::MissingReturnValue
540 .with_span_static(span, "atomic exchange operation")
541 .into_other());
542 }
543 }
544 }
545
546 Ok(())
547 }
548 fn validate_subgroup_operation(
549 &mut self,
550 op: &crate::SubgroupOperation,
551 collective_op: &crate::CollectiveOperation,
552 argument: Handle<crate::Expression>,
553 result: Handle<crate::Expression>,
554 context: &BlockContext,
555 ) -> Result<(), WithSpan<FunctionError>> {
556 let argument_inner = context.resolve_type(argument, &self.valid_expression_set)?;
557
558 let (is_scalar, scalar) = match *argument_inner {
559 crate::TypeInner::Scalar(scalar) => (true, scalar),
560 crate::TypeInner::Vector { scalar, .. } => (false, scalar),
561 _ => {
562 log::error!("Subgroup operand type {:?}", argument_inner);
563 return Err(SubgroupError::InvalidOperand(argument)
564 .with_span_handle(argument, context.expressions)
565 .into_other());
566 }
567 };
568
569 use crate::ScalarKind as sk;
570 use crate::SubgroupOperation as sg;
571 match (scalar.kind, *op) {
572 (sk::Bool, sg::All | sg::Any) if is_scalar => {}
573 (sk::Sint | sk::Uint | sk::Float, sg::Add | sg::Mul | sg::Min | sg::Max) => {}
574 (sk::Sint | sk::Uint, sg::And | sg::Or | sg::Xor) => {}
575
576 (_, _) => {
577 log::error!("Subgroup operand type {:?}", argument_inner);
578 return Err(SubgroupError::InvalidOperand(argument)
579 .with_span_handle(argument, context.expressions)
580 .into_other());
581 }
582 };
583
584 use crate::CollectiveOperation as co;
585 match (*collective_op, *op) {
586 (
587 co::Reduce,
588 sg::All
589 | sg::Any
590 | sg::Add
591 | sg::Mul
592 | sg::Min
593 | sg::Max
594 | sg::And
595 | sg::Or
596 | sg::Xor,
597 ) => {}
598 (co::InclusiveScan | co::ExclusiveScan, sg::Add | sg::Mul) => {}
599
600 (_, _) => {
601 return Err(SubgroupError::UnknownOperation.with_span().into_other());
602 }
603 };
604
605 self.emit_expression(result, context)?;
606 match context.expressions[result] {
607 crate::Expression::SubgroupOperationResult { ty }
608 if { &context.types[ty].inner == argument_inner } => {}
609 _ => {
610 return Err(SubgroupError::ResultTypeMismatch(result)
611 .with_span_handle(result, context.expressions)
612 .into_other())
613 }
614 }
615 Ok(())
616 }
617 fn validate_subgroup_gather(
618 &mut self,
619 mode: &crate::GatherMode,
620 argument: Handle<crate::Expression>,
621 result: Handle<crate::Expression>,
622 context: &BlockContext,
623 ) -> Result<(), WithSpan<FunctionError>> {
624 match *mode {
625 crate::GatherMode::BroadcastFirst => {}
626 crate::GatherMode::Broadcast(index)
627 | crate::GatherMode::Shuffle(index)
628 | crate::GatherMode::ShuffleDown(index)
629 | crate::GatherMode::ShuffleUp(index)
630 | crate::GatherMode::ShuffleXor(index) => {
631 let index_ty = context.resolve_type(index, &self.valid_expression_set)?;
632 match *index_ty {
633 crate::TypeInner::Scalar(crate::Scalar::U32) => {}
634 _ => {
635 log::error!(
636 "Subgroup gather index type {:?}, expected unsigned int",
637 index_ty
638 );
639 return Err(SubgroupError::InvalidOperand(argument)
640 .with_span_handle(index, context.expressions)
641 .into_other());
642 }
643 }
644 }
645 }
646 let argument_inner = context.resolve_type(argument, &self.valid_expression_set)?;
647 if !matches!(*argument_inner,
648 crate::TypeInner::Scalar ( scalar, .. ) | crate::TypeInner::Vector { scalar, .. }
649 if matches!(scalar.kind, crate::ScalarKind::Uint | crate::ScalarKind::Sint | crate::ScalarKind::Float)
650 ) {
651 log::error!("Subgroup gather operand type {:?}", argument_inner);
652 return Err(SubgroupError::InvalidOperand(argument)
653 .with_span_handle(argument, context.expressions)
654 .into_other());
655 }
656
657 self.emit_expression(result, context)?;
658 match context.expressions[result] {
659 crate::Expression::SubgroupOperationResult { ty }
660 if { &context.types[ty].inner == argument_inner } => {}
661 _ => {
662 return Err(SubgroupError::ResultTypeMismatch(result)
663 .with_span_handle(result, context.expressions)
664 .into_other())
665 }
666 }
667 Ok(())
668 }
669
670 fn validate_block_impl(
671 &mut self,
672 statements: &crate::Block,
673 context: &BlockContext,
674 ) -> Result<BlockInfo, WithSpan<FunctionError>> {
675 use crate::{AddressSpace, Statement as S, TypeInner as Ti};
676 let mut finished = false;
677 let mut stages = super::ShaderStages::all();
678 for (statement, &span) in statements.span_iter() {
679 if finished {
680 return Err(FunctionError::InstructionsAfterReturn
681 .with_span_static(span, "instructions after return"));
682 }
683 match *statement {
684 S::Emit(ref range) => {
685 for handle in range.clone() {
686 use crate::Expression as Ex;
687 match context.expressions[handle] {
688 Ex::Literal(_)
689 | Ex::Constant(_)
690 | Ex::Override(_)
691 | Ex::ZeroValue(_)
692 | Ex::Compose { .. }
693 | Ex::Access { .. }
694 | Ex::AccessIndex { .. }
695 | Ex::Splat { .. }
696 | Ex::Swizzle { .. }
697 | Ex::FunctionArgument(_)
698 | Ex::GlobalVariable(_)
699 | Ex::LocalVariable(_)
700 | Ex::Load { .. }
701 | Ex::ImageSample { .. }
702 | Ex::ImageLoad { .. }
703 | Ex::ImageQuery { .. }
704 | Ex::Unary { .. }
705 | Ex::Binary { .. }
706 | Ex::Select { .. }
707 | Ex::Derivative { .. }
708 | Ex::Relational { .. }
709 | Ex::Math { .. }
710 | Ex::As { .. }
711 | Ex::ArrayLength(_)
712 | Ex::RayQueryGetIntersection { .. } => {
713 self.emit_expression(handle, context)?
714 }
715 Ex::CallResult(_)
716 | Ex::AtomicResult { .. }
717 | Ex::WorkGroupUniformLoadResult { .. }
718 | Ex::RayQueryProceedResult
719 | Ex::SubgroupBallotResult
720 | Ex::SubgroupOperationResult { .. } => {
721 return Err(FunctionError::EmitResult(handle)
722 .with_span_handle(handle, context.expressions));
723 }
724 }
725 }
726 }
727 S::Block(ref block) => {
728 let info = self.validate_block(block, context)?;
729 stages &= info.stages;
730 finished = info.finished;
731 }
732 S::If {
733 condition,
734 ref accept,
735 ref reject,
736 } => {
737 match *context.resolve_type(condition, &self.valid_expression_set)? {
738 Ti::Scalar(crate::Scalar {
739 kind: crate::ScalarKind::Bool,
740 width: _,
741 }) => {}
742 _ => {
743 return Err(FunctionError::InvalidIfType(condition)
744 .with_span_handle(condition, context.expressions))
745 }
746 }
747 stages &= self.validate_block(accept, context)?.stages;
748 stages &= self.validate_block(reject, context)?.stages;
749 }
750 S::Switch {
751 selector,
752 ref cases,
753 } => {
754 let uint = match context
755 .resolve_type(selector, &self.valid_expression_set)?
756 .scalar_kind()
757 {
758 Some(crate::ScalarKind::Uint) => true,
759 Some(crate::ScalarKind::Sint) => false,
760 _ => {
761 return Err(FunctionError::InvalidSwitchType(selector)
762 .with_span_handle(selector, context.expressions))
763 }
764 };
765 self.switch_values.clear();
766 for case in cases {
767 match case.value {
768 crate::SwitchValue::I32(_) if !uint => {}
769 crate::SwitchValue::U32(_) if uint => {}
770 crate::SwitchValue::Default => {}
771 _ => {
772 return Err(FunctionError::ConflictingCaseType.with_span_static(
773 case.body
774 .span_iter()
775 .next()
776 .map_or(Default::default(), |(_, s)| *s),
777 "conflicting switch arm here",
778 ));
779 }
780 };
781 if !self.switch_values.insert(case.value) {
782 return Err(match case.value {
783 crate::SwitchValue::Default => FunctionError::MultipleDefaultCases
784 .with_span_static(
785 case.body
786 .span_iter()
787 .next()
788 .map_or(Default::default(), |(_, s)| *s),
789 "duplicated switch arm here",
790 ),
791 _ => FunctionError::ConflictingSwitchCase(case.value)
792 .with_span_static(
793 case.body
794 .span_iter()
795 .next()
796 .map_or(Default::default(), |(_, s)| *s),
797 "conflicting switch arm here",
798 ),
799 });
800 }
801 }
802 if !self.switch_values.contains(&crate::SwitchValue::Default) {
803 return Err(FunctionError::MissingDefaultCase
804 .with_span_static(span, "missing default case"));
805 }
806 if let Some(case) = cases.last() {
807 if case.fall_through {
808 return Err(FunctionError::LastCaseFallTrough.with_span_static(
809 case.body
810 .span_iter()
811 .next()
812 .map_or(Default::default(), |(_, s)| *s),
813 "bad switch arm here",
814 ));
815 }
816 }
817 let pass_through_abilities = context.abilities
818 & (ControlFlowAbility::RETURN | ControlFlowAbility::CONTINUE);
819 let sub_context =
820 context.with_abilities(pass_through_abilities | ControlFlowAbility::BREAK);
821 for case in cases {
822 stages &= self.validate_block(&case.body, &sub_context)?.stages;
823 }
824 }
825 S::Loop {
826 ref body,
827 ref continuing,
828 break_if,
829 } => {
830 let base_expression_count = self.valid_expression_list.len();
833 let pass_through_abilities = context.abilities & ControlFlowAbility::RETURN;
834 stages &= self
835 .validate_block_impl(
836 body,
837 &context.with_abilities(
838 pass_through_abilities
839 | ControlFlowAbility::BREAK
840 | ControlFlowAbility::CONTINUE,
841 ),
842 )?
843 .stages;
844 stages &= self
845 .validate_block_impl(
846 continuing,
847 &context.with_abilities(ControlFlowAbility::empty()),
848 )?
849 .stages;
850
851 if let Some(condition) = break_if {
852 match *context.resolve_type(condition, &self.valid_expression_set)? {
853 Ti::Scalar(crate::Scalar {
854 kind: crate::ScalarKind::Bool,
855 width: _,
856 }) => {}
857 _ => {
858 return Err(FunctionError::InvalidIfType(condition)
859 .with_span_handle(condition, context.expressions))
860 }
861 }
862 }
863
864 for handle in self.valid_expression_list.drain(base_expression_count..) {
865 self.valid_expression_set.remove(handle);
866 }
867 }
868 S::Break => {
869 if !context.abilities.contains(ControlFlowAbility::BREAK) {
870 return Err(FunctionError::BreakOutsideOfLoopOrSwitch
871 .with_span_static(span, "invalid break"));
872 }
873 finished = true;
874 }
875 S::Continue => {
876 if !context.abilities.contains(ControlFlowAbility::CONTINUE) {
877 return Err(FunctionError::ContinueOutsideOfLoop
878 .with_span_static(span, "invalid continue"));
879 }
880 finished = true;
881 }
882 S::Return { value } => {
883 if !context.abilities.contains(ControlFlowAbility::RETURN) {
884 return Err(FunctionError::InvalidReturnSpot
885 .with_span_static(span, "invalid return"));
886 }
887 let value_ty = value
888 .map(|expr| context.resolve_type(expr, &self.valid_expression_set))
889 .transpose()?;
890 let expected_ty = context.return_type.map(|ty| &context.types[ty].inner);
891 let okay = match (value_ty, expected_ty) {
894 (None, None) => true,
895 (Some(value_inner), Some(expected_inner)) => {
896 value_inner.equivalent(expected_inner, context.types)
897 }
898 (_, _) => false,
899 };
900
901 if !okay {
902 log::error!(
903 "Returning {:?} where {:?} is expected",
904 value_ty,
905 expected_ty
906 );
907 if let Some(handle) = value {
908 return Err(FunctionError::InvalidReturnType(value)
909 .with_span_handle(handle, context.expressions));
910 } else {
911 return Err(FunctionError::InvalidReturnType(value)
912 .with_span_static(span, "invalid return"));
913 }
914 }
915 finished = true;
916 }
917 S::Kill => {
918 stages &= super::ShaderStages::FRAGMENT;
919 finished = true;
920 }
921 S::Barrier(barrier) => {
922 stages &= super::ShaderStages::COMPUTE;
923 if barrier.contains(crate::Barrier::SUB_GROUP) {
924 if !self.capabilities.contains(
925 super::Capabilities::SUBGROUP | super::Capabilities::SUBGROUP_BARRIER,
926 ) {
927 return Err(FunctionError::MissingCapability(
928 super::Capabilities::SUBGROUP
929 | super::Capabilities::SUBGROUP_BARRIER,
930 )
931 .with_span_static(span, "missing capability for this operation"));
932 }
933 if !self
934 .subgroup_operations
935 .contains(super::SubgroupOperationSet::BASIC)
936 {
937 return Err(FunctionError::InvalidSubgroup(
938 SubgroupError::UnsupportedOperation(
939 super::SubgroupOperationSet::BASIC,
940 ),
941 )
942 .with_span_static(span, "support for this operation is not present"));
943 }
944 }
945 }
946 S::Store { pointer, value } => {
947 let mut current = pointer;
948 loop {
949 match context.expressions[current] {
950 crate::Expression::Access { base, .. }
951 | crate::Expression::AccessIndex { base, .. } => current = base,
952 crate::Expression::LocalVariable(_)
953 | crate::Expression::GlobalVariable(_)
954 | crate::Expression::FunctionArgument(_) => break,
955 _ => {
956 return Err(FunctionError::InvalidStorePointer(current)
957 .with_span_handle(pointer, context.expressions))
958 }
959 }
960 }
961
962 let value_ty = context.resolve_type(value, &self.valid_expression_set)?;
963 match *value_ty {
964 Ti::Image { .. } | Ti::Sampler { .. } => {
965 return Err(FunctionError::InvalidStoreValue(value)
966 .with_span_handle(value, context.expressions));
967 }
968 _ => {}
969 }
970
971 let pointer_ty = context.resolve_pointer_type(pointer);
972
973 let good = match *pointer_ty {
974 Ti::Pointer { base, space: _ } => match context.types[base].inner {
975 Ti::Atomic(scalar) => *value_ty == Ti::Scalar(scalar),
976 ref other => value_ty == other,
977 },
978 Ti::ValuePointer {
979 size: Some(size),
980 scalar,
981 space: _,
982 } => *value_ty == Ti::Vector { size, scalar },
983 Ti::ValuePointer {
984 size: None,
985 scalar,
986 space: _,
987 } => *value_ty == Ti::Scalar(scalar),
988 _ => false,
989 };
990 if !good {
991 return Err(FunctionError::InvalidStoreTypes { pointer, value }
992 .with_span()
993 .with_handle(pointer, context.expressions)
994 .with_handle(value, context.expressions));
995 }
996
997 if let Some(space) = pointer_ty.pointer_space() {
998 if !space.access().contains(crate::StorageAccess::STORE) {
999 return Err(FunctionError::InvalidStorePointer(pointer)
1000 .with_span_static(
1001 context.expressions.get_span(pointer),
1002 "writing to this location is not permitted",
1003 ));
1004 }
1005 }
1006 }
1007 S::ImageStore {
1008 image,
1009 coordinate,
1010 array_index,
1011 value,
1012 } => {
1013 let var = match *context.get_expression(image) {
1016 crate::Expression::GlobalVariable(var_handle) => {
1017 &context.global_vars[var_handle]
1018 }
1019 crate::Expression::Access { base, .. }
1021 | crate::Expression::AccessIndex { base, .. } => {
1022 match *context.get_expression(base) {
1023 crate::Expression::GlobalVariable(var_handle) => {
1024 &context.global_vars[var_handle]
1025 }
1026 _ => {
1027 return Err(FunctionError::InvalidImageStore(
1028 ExpressionError::ExpectedGlobalVariable,
1029 )
1030 .with_span_handle(image, context.expressions))
1031 }
1032 }
1033 }
1034 _ => {
1035 return Err(FunctionError::InvalidImageStore(
1036 ExpressionError::ExpectedGlobalVariable,
1037 )
1038 .with_span_handle(image, context.expressions))
1039 }
1040 };
1041
1042 let global_ty = match context.types[var.ty].inner {
1044 Ti::BindingArray { base, .. } => &context.types[base].inner,
1045 ref inner => inner,
1046 };
1047
1048 let value_ty = match *global_ty {
1049 Ti::Image {
1050 class,
1051 arrayed,
1052 dim,
1053 } => {
1054 match context
1055 .resolve_type(coordinate, &self.valid_expression_set)?
1056 .image_storage_coordinates()
1057 {
1058 Some(coord_dim) if coord_dim == dim => {}
1059 _ => {
1060 return Err(FunctionError::InvalidImageStore(
1061 ExpressionError::InvalidImageCoordinateType(
1062 dim, coordinate,
1063 ),
1064 )
1065 .with_span_handle(coordinate, context.expressions));
1066 }
1067 };
1068 if arrayed != array_index.is_some() {
1069 return Err(FunctionError::InvalidImageStore(
1070 ExpressionError::InvalidImageArrayIndex,
1071 )
1072 .with_span_handle(coordinate, context.expressions));
1073 }
1074 if let Some(expr) = array_index {
1075 match *context.resolve_type(expr, &self.valid_expression_set)? {
1076 Ti::Scalar(crate::Scalar {
1077 kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint,
1078 width: _,
1079 }) => {}
1080 _ => {
1081 return Err(FunctionError::InvalidImageStore(
1082 ExpressionError::InvalidImageArrayIndexType(expr),
1083 )
1084 .with_span_handle(expr, context.expressions));
1085 }
1086 }
1087 }
1088 match class {
1089 crate::ImageClass::Storage { format, .. } => {
1090 crate::TypeInner::Vector {
1091 size: crate::VectorSize::Quad,
1092 scalar: format.into(),
1093 }
1094 }
1095 _ => {
1096 return Err(FunctionError::InvalidImageStore(
1097 ExpressionError::InvalidImageClass(class),
1098 )
1099 .with_span_handle(image, context.expressions));
1100 }
1101 }
1102 }
1103 _ => {
1104 return Err(FunctionError::InvalidImageStore(
1105 ExpressionError::ExpectedImageType(var.ty),
1106 )
1107 .with_span()
1108 .with_handle(var.ty, context.types)
1109 .with_handle(image, context.expressions))
1110 }
1111 };
1112
1113 if *context.resolve_type(value, &self.valid_expression_set)? != value_ty {
1114 return Err(FunctionError::InvalidStoreValue(value)
1115 .with_span_handle(value, context.expressions));
1116 }
1117 }
1118 S::Call {
1119 function,
1120 ref arguments,
1121 result,
1122 } => match self.validate_call(function, arguments, result, context) {
1123 Ok(callee_stages) => stages &= callee_stages,
1124 Err(error) => {
1125 return Err(error.and_then(|error| {
1126 FunctionError::InvalidCall { function, error }
1127 .with_span_static(span, "invalid function call")
1128 }))
1129 }
1130 },
1131 S::Atomic {
1132 pointer,
1133 ref fun,
1134 value,
1135 result,
1136 } => {
1137 self.validate_atomic(pointer, fun, value, result, span, context)?;
1138 }
1139 S::WorkGroupUniformLoad { pointer, result } => {
1140 stages &= super::ShaderStages::COMPUTE;
1141 let pointer_inner =
1142 context.resolve_type(pointer, &self.valid_expression_set)?;
1143 match *pointer_inner {
1144 Ti::Pointer {
1145 space: AddressSpace::WorkGroup,
1146 ..
1147 } => {}
1148 Ti::ValuePointer {
1149 space: AddressSpace::WorkGroup,
1150 ..
1151 } => {}
1152 _ => {
1153 return Err(FunctionError::WorkgroupUniformLoadInvalidPointer(pointer)
1154 .with_span_static(span, "WorkGroupUniformLoad"))
1155 }
1156 }
1157 self.emit_expression(result, context)?;
1158 let ty = match &context.expressions[result] {
1159 &crate::Expression::WorkGroupUniformLoadResult { ty } => ty,
1160 _ => {
1161 return Err(FunctionError::WorkgroupUniformLoadExpressionMismatch(
1162 result,
1163 )
1164 .with_span_static(span, "WorkGroupUniformLoad"));
1165 }
1166 };
1167 let expected_pointer_inner = Ti::Pointer {
1168 base: ty,
1169 space: AddressSpace::WorkGroup,
1170 };
1171 if !expected_pointer_inner.equivalent(pointer_inner, context.types) {
1172 return Err(FunctionError::WorkgroupUniformLoadInvalidPointer(pointer)
1173 .with_span_static(span, "WorkGroupUniformLoad"));
1174 }
1175 }
1176 S::RayQuery { query, ref fun } => {
1177 let query_var = match *context.get_expression(query) {
1178 crate::Expression::LocalVariable(var) => &context.local_vars[var],
1179 ref other => {
1180 log::error!("Unexpected ray query expression {other:?}");
1181 return Err(FunctionError::InvalidRayQueryExpression(query)
1182 .with_span_static(span, "invalid query expression"));
1183 }
1184 };
1185 match context.types[query_var.ty].inner {
1186 Ti::RayQuery => {}
1187 ref other => {
1188 log::error!("Unexpected ray query type {other:?}");
1189 return Err(FunctionError::InvalidRayQueryType(query_var.ty)
1190 .with_span_static(span, "invalid query type"));
1191 }
1192 }
1193 match *fun {
1194 crate::RayQueryFunction::Initialize {
1195 acceleration_structure,
1196 descriptor,
1197 } => {
1198 match *context
1199 .resolve_type(acceleration_structure, &self.valid_expression_set)?
1200 {
1201 Ti::AccelerationStructure => {}
1202 _ => {
1203 return Err(FunctionError::InvalidAccelerationStructure(
1204 acceleration_structure,
1205 )
1206 .with_span_static(span, "invalid acceleration structure"))
1207 }
1208 }
1209 let desc_ty_given =
1210 context.resolve_type(descriptor, &self.valid_expression_set)?;
1211 let desc_ty_expected = context
1212 .special_types
1213 .ray_desc
1214 .map(|handle| &context.types[handle].inner);
1215 if Some(desc_ty_given) != desc_ty_expected {
1216 return Err(FunctionError::InvalidRayDescriptor(descriptor)
1217 .with_span_static(span, "invalid ray descriptor"));
1218 }
1219 }
1220 crate::RayQueryFunction::Proceed { result } => {
1221 self.emit_expression(result, context)?;
1222 }
1223 crate::RayQueryFunction::Terminate => {}
1224 }
1225 }
1226 S::SubgroupBallot { result, predicate } => {
1227 stages &= self.subgroup_stages;
1228 if !self.capabilities.contains(super::Capabilities::SUBGROUP) {
1229 return Err(FunctionError::MissingCapability(
1230 super::Capabilities::SUBGROUP,
1231 )
1232 .with_span_static(span, "missing capability for this operation"));
1233 }
1234 if !self
1235 .subgroup_operations
1236 .contains(super::SubgroupOperationSet::BALLOT)
1237 {
1238 return Err(FunctionError::InvalidSubgroup(
1239 SubgroupError::UnsupportedOperation(
1240 super::SubgroupOperationSet::BALLOT,
1241 ),
1242 )
1243 .with_span_static(span, "support for this operation is not present"));
1244 }
1245 if let Some(predicate) = predicate {
1246 let predicate_inner =
1247 context.resolve_type(predicate, &self.valid_expression_set)?;
1248 if !matches!(
1249 *predicate_inner,
1250 crate::TypeInner::Scalar(crate::Scalar::BOOL,)
1251 ) {
1252 log::error!(
1253 "Subgroup ballot predicate type {:?} expected bool",
1254 predicate_inner
1255 );
1256 return Err(SubgroupError::InvalidOperand(predicate)
1257 .with_span_handle(predicate, context.expressions)
1258 .into_other());
1259 }
1260 }
1261 self.emit_expression(result, context)?;
1262 }
1263 S::SubgroupCollectiveOperation {
1264 ref op,
1265 ref collective_op,
1266 argument,
1267 result,
1268 } => {
1269 stages &= self.subgroup_stages;
1270 if !self.capabilities.contains(super::Capabilities::SUBGROUP) {
1271 return Err(FunctionError::MissingCapability(
1272 super::Capabilities::SUBGROUP,
1273 )
1274 .with_span_static(span, "missing capability for this operation"));
1275 }
1276 let operation = op.required_operations();
1277 if !self.subgroup_operations.contains(operation) {
1278 return Err(FunctionError::InvalidSubgroup(
1279 SubgroupError::UnsupportedOperation(operation),
1280 )
1281 .with_span_static(span, "support for this operation is not present"));
1282 }
1283 self.validate_subgroup_operation(op, collective_op, argument, result, context)?;
1284 }
1285 S::SubgroupGather {
1286 ref mode,
1287 argument,
1288 result,
1289 } => {
1290 stages &= self.subgroup_stages;
1291 if !self.capabilities.contains(super::Capabilities::SUBGROUP) {
1292 return Err(FunctionError::MissingCapability(
1293 super::Capabilities::SUBGROUP,
1294 )
1295 .with_span_static(span, "missing capability for this operation"));
1296 }
1297 let operation = mode.required_operations();
1298 if !self.subgroup_operations.contains(operation) {
1299 return Err(FunctionError::InvalidSubgroup(
1300 SubgroupError::UnsupportedOperation(operation),
1301 )
1302 .with_span_static(span, "support for this operation is not present"));
1303 }
1304 self.validate_subgroup_gather(mode, argument, result, context)?;
1305 }
1306 }
1307 }
1308 Ok(BlockInfo { stages, finished })
1309 }
1310
1311 fn validate_block(
1312 &mut self,
1313 statements: &crate::Block,
1314 context: &BlockContext,
1315 ) -> Result<BlockInfo, WithSpan<FunctionError>> {
1316 let base_expression_count = self.valid_expression_list.len();
1317 let info = self.validate_block_impl(statements, context)?;
1318 for handle in self.valid_expression_list.drain(base_expression_count..) {
1319 self.valid_expression_set.remove(handle);
1320 }
1321 Ok(info)
1322 }
1323
1324 fn validate_local_var(
1325 &self,
1326 var: &crate::LocalVariable,
1327 gctx: crate::proc::GlobalCtx,
1328 fun_info: &FunctionInfo,
1329 local_expr_kind: &crate::proc::ExpressionKindTracker,
1330 ) -> Result<(), LocalVariableError> {
1331 log::debug!("var {:?}", var);
1332 let type_info = self
1333 .types
1334 .get(var.ty.index())
1335 .ok_or(LocalVariableError::InvalidType(var.ty))?;
1336 if !type_info.flags.contains(super::TypeFlags::CONSTRUCTIBLE) {
1337 return Err(LocalVariableError::InvalidType(var.ty));
1338 }
1339
1340 if let Some(init) = var.init {
1341 let decl_ty = &gctx.types[var.ty].inner;
1342 let init_ty = fun_info[init].ty.inner_with(gctx.types);
1343 if !decl_ty.equivalent(init_ty, gctx.types) {
1344 return Err(LocalVariableError::InitializerType);
1345 }
1346
1347 if !local_expr_kind.is_const_or_override(init) {
1348 return Err(LocalVariableError::NonConstOrOverrideInitializer);
1349 }
1350 }
1351
1352 Ok(())
1353 }
1354
1355 pub(super) fn validate_function(
1356 &mut self,
1357 fun: &crate::Function,
1358 module: &crate::Module,
1359 mod_info: &ModuleInfo,
1360 entry_point: bool,
1361 global_expr_kind: &crate::proc::ExpressionKindTracker,
1362 ) -> Result<FunctionInfo, WithSpan<FunctionError>> {
1363 let mut info = mod_info.process_function(fun, module, self.flags, self.capabilities)?;
1364
1365 let local_expr_kind = crate::proc::ExpressionKindTracker::from_arena(&fun.expressions);
1366
1367 for (var_handle, var) in fun.local_variables.iter() {
1368 self.validate_local_var(var, module.to_ctx(), &info, &local_expr_kind)
1369 .map_err(|source| {
1370 FunctionError::LocalVariable {
1371 handle: var_handle,
1372 name: var.name.clone().unwrap_or_default(),
1373 source,
1374 }
1375 .with_span_handle(var.ty, &module.types)
1376 .with_handle(var_handle, &fun.local_variables)
1377 })?;
1378 }
1379
1380 for (index, argument) in fun.arguments.iter().enumerate() {
1381 match module.types[argument.ty].inner.pointer_space() {
1382 Some(crate::AddressSpace::Private | crate::AddressSpace::Function) | None => {}
1383 Some(other) => {
1384 return Err(FunctionError::InvalidArgumentPointerSpace {
1385 index,
1386 name: argument.name.clone().unwrap_or_default(),
1387 space: other,
1388 }
1389 .with_span_handle(argument.ty, &module.types))
1390 }
1391 }
1392 if !self.types[argument.ty.index()]
1394 .flags
1395 .contains(super::TypeFlags::ARGUMENT)
1396 {
1397 return Err(FunctionError::InvalidArgumentType {
1398 index,
1399 name: argument.name.clone().unwrap_or_default(),
1400 }
1401 .with_span_handle(argument.ty, &module.types));
1402 }
1403
1404 if !entry_point && argument.binding.is_some() {
1405 return Err(FunctionError::PipelineInputRegularFunction {
1406 name: argument.name.clone().unwrap_or_default(),
1407 }
1408 .with_span_handle(argument.ty, &module.types));
1409 }
1410 }
1411
1412 if let Some(ref result) = fun.result {
1413 if !self.types[result.ty.index()]
1414 .flags
1415 .contains(super::TypeFlags::CONSTRUCTIBLE)
1416 {
1417 return Err(FunctionError::NonConstructibleReturnType
1418 .with_span_handle(result.ty, &module.types));
1419 }
1420
1421 if !entry_point && result.binding.is_some() {
1422 return Err(FunctionError::PipelineOutputRegularFunction
1423 .with_span_handle(result.ty, &module.types));
1424 }
1425 }
1426
1427 self.valid_expression_set.clear_for_arena(&fun.expressions);
1428 self.valid_expression_list.clear();
1429 self.needs_visit.clear_for_arena(&fun.expressions);
1430 for (handle, expr) in fun.expressions.iter() {
1431 if expr.needs_pre_emit() {
1432 self.valid_expression_set.insert(handle);
1433 }
1434 if self.flags.contains(super::ValidationFlags::EXPRESSIONS) {
1435 if let crate::Expression::CallResult(_) | crate::Expression::AtomicResult { .. } =
1438 *expr
1439 {
1440 self.needs_visit.insert(handle);
1441 }
1442
1443 match self.validate_expression(
1444 handle,
1445 expr,
1446 fun,
1447 module,
1448 &info,
1449 mod_info,
1450 global_expr_kind,
1451 ) {
1452 Ok(stages) => info.available_stages &= stages,
1453 Err(source) => {
1454 return Err(FunctionError::Expression { handle, source }
1455 .with_span_handle(handle, &fun.expressions))
1456 }
1457 }
1458 }
1459 }
1460
1461 if self.flags.contains(super::ValidationFlags::BLOCKS) {
1462 let stages = self
1463 .validate_block(
1464 &fun.body,
1465 &BlockContext::new(fun, module, &info, &mod_info.functions),
1466 )?
1467 .stages;
1468 info.available_stages &= stages;
1469
1470 if self.flags.contains(super::ValidationFlags::EXPRESSIONS) {
1471 if let Some(handle) = self.needs_visit.iter().next() {
1472 return Err(FunctionError::UnvisitedExpression(handle)
1473 .with_span_handle(handle, &fun.expressions));
1474 }
1475 }
1476 }
1477 Ok(info)
1478 }
1479}