1use crate::common::wgsl::TryToWgsl;
4use crate::diagnostic_filter::ConflictingDiagnosticRuleError;
5use crate::error::replace_control_chars;
6use crate::proc::{Alignment, ConstantEvaluatorError, ResolveError};
7use crate::{Scalar, SourceLocation, Span};
8
9use super::parse::directive::enable_extension::{EnableExtension, UnimplementedEnableExtension};
10use super::parse::directive::language_extension::{
11 LanguageExtension, UnimplementedLanguageExtension,
12};
13use super::parse::lexer::Token;
14
15use codespan_reporting::diagnostic::{Diagnostic, Label};
16use codespan_reporting::files::SimpleFile;
17use codespan_reporting::term;
18use thiserror::Error;
19
20use alloc::{
21 borrow::Cow,
22 boxed::Box,
23 format,
24 string::{String, ToString},
25 vec,
26 vec::Vec,
27};
28use core::ops::Range;
29
30#[derive(Clone, Debug)]
31pub struct ParseError {
32 message: String,
33 labels: Vec<(Span, Cow<'static, str>)>,
35 notes: Vec<String>,
36}
37
38impl ParseError {
39 pub fn labels(&self) -> impl ExactSizeIterator<Item = (Span, &str)> + '_ {
40 self.labels
41 .iter()
42 .map(|&(span, ref msg)| (span, msg.as_ref()))
43 }
44
45 pub fn message(&self) -> &str {
46 &self.message
47 }
48
49 fn diagnostic(&self) -> Diagnostic<()> {
50 let diagnostic = Diagnostic::error()
51 .with_message(self.message.to_string())
52 .with_labels(
53 self.labels
54 .iter()
55 .filter_map(|label| label.0.to_range().map(|range| (label, range)))
56 .map(|(label, range)| {
57 Label::primary((), range).with_message(label.1.to_string())
58 })
59 .collect(),
60 )
61 .with_notes(
62 self.notes
63 .iter()
64 .map(|note| format!("note: {note}"))
65 .collect(),
66 );
67 diagnostic
68 }
69
70 #[cfg(feature = "stderr")]
72 pub fn emit_to_stderr(&self, source: &str) {
73 self.emit_to_stderr_with_path(source, "wgsl")
74 }
75
76 #[cfg(feature = "stderr")]
78 pub fn emit_to_stderr_with_path<P>(&self, source: &str, path: P)
79 where
80 P: AsRef<std::path::Path>,
81 {
82 let path = path.as_ref().display().to_string();
83 let files = SimpleFile::new(path, replace_control_chars(source));
84 let config = term::Config::default();
85
86 cfg_if::cfg_if! {
87 if #[cfg(feature = "termcolor")] {
88 let writer = term::termcolor::StandardStream::stderr(term::termcolor::ColorChoice::Auto);
89 term::emit_to_write_style(&mut writer.lock(), &config, &files, &self.diagnostic())
90 .expect("cannot write error");
91 } else {
92 let writer = std::io::stderr();
93 term::emit_to_io_write(&mut writer.lock(), &config, &files, &self.diagnostic())
94 .expect("cannot write error");
95 }
96 }
97 }
98
99 pub fn emit_to_string(&self, source: &str) -> String {
101 self.emit_to_string_with_path(source, "wgsl")
102 }
103
104 pub fn emit_to_string_with_path(&self, source: &str, path: &str) -> String {
109 let files = SimpleFile::new(path, replace_control_chars(source));
110 let config = term::Config::default();
111
112 let mut writer = crate::error::DiagnosticBuffer::new();
113 writer
114 .emit_to_self(&config, &files, &self.diagnostic())
115 .expect("cannot write error");
116 writer.into_string()
117 }
118
119 pub fn location(&self, source: &str) -> Option<SourceLocation> {
121 self.labels.first().map(|label| label.0.location(source))
122 }
123}
124
125impl core::fmt::Display for ParseError {
126 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
127 write!(f, "{}", self.message)
128 }
129}
130
131impl core::error::Error for ParseError {}
132
133#[derive(Copy, Clone, Debug, PartialEq)]
134pub enum ExpectedToken<'a> {
135 Token(Token<'a>),
136 Identifier,
137 AfterIdentListComma,
138 AfterIdentListArg,
139 LhsExpression,
141 PrimaryExpression,
143 Assignment,
145 SwitchItem,
147 WorkgroupSizeSeparator,
149 GlobalItem,
151 Variable,
153 Function,
155 DiagnosticAttribute,
157 Statement,
159 ForInit,
161 ForUpdate,
163}
164
165#[derive(Clone, Copy, Debug, Error, PartialEq)]
166pub enum NumberError {
167 #[error("invalid numeric literal format")]
168 Invalid,
169 #[error("numeric literal not representable by target type")]
170 NotRepresentable,
171}
172
173#[derive(Copy, Clone, Debug, PartialEq)]
174pub enum InvalidAssignmentType {
175 Other,
176 Swizzle,
177 ImmutableBinding(Span),
178}
179
180#[derive(Clone, Debug)]
181pub(crate) enum Error<'a> {
182 Unexpected(Span, ExpectedToken<'a>),
183 UnexpectedComponents(Span),
184 UnexpectedOperationInConstContext(Span),
185 BadNumber(Span, NumberError),
186 BadMatrixScalarKind(Span, Scalar),
187 BadAccessor(Span),
188 BadTexture(Span),
189 BadTypeCast {
190 span: Span,
191 from_type: String,
192 to_type: String,
193 },
194 NotStorageTexture(Span),
195 BadTextureSampleType {
196 span: Span,
197 scalar: Scalar,
198 },
199 BadIncrDecrReferenceType(Span),
200 InvalidResolve(ResolveError),
201 InvalidBreakIf(Span),
203 InvalidGatherComponent(Span),
204 InvalidConstructorComponentType(Span, i32),
205 InvalidIdentifierUnderscore(Span),
206 ReservedIdentifierPrefix(Span),
207 UnknownAddressSpace(Span),
208 InvalidLocalVariableAddressSpace(Span),
209 UnknownRayFlag(Span),
210 RepeatedAttribute(Span),
211 UnknownAttribute(Span),
212 UnknownBuiltin(Span),
213 UnknownAccess(Span),
214 UnknownIdent(Span, &'a str),
215 UnknownScalarType(Span),
216 UnknownStorageFormat(Span),
217 UnknownConservativeDepth(Span),
218 UnknownEnableExtension(Span, &'a str),
219 UnknownLanguageExtension(Span, &'a str),
220 UnknownDiagnosticRuleName(Span),
221 SizeAttributeTooLow(Span, u32),
222 AlignAttributeTooLow(Span, Alignment),
223 NonPowerOfTwoAlignAttribute(Span),
224 InconsistentBinding(Span),
225 TypeNotConstructible(Span),
226 TypeNotInferable(Span),
227 InitializationTypeMismatch {
228 name: Span,
229 expected: String,
230 got: String,
231 },
232 DeclMissingTypeAndInit(Span),
233 MissingAttribute(&'static str, Span),
234 InvalidAddrOfOperand(Span),
235 InvalidAtomicPointer(Span),
236 InvalidAtomicOperandType(Span),
237 InvalidAtomicAccess(Span),
238 InvalidRayQueryPointer(Span),
239 NotPointer(Span),
240 NotReference(&'static str, Span),
241 InvalidAssignment {
242 span: Span,
243 ty: InvalidAssignmentType,
244 },
245 ReservedKeyword(Span),
246 Redefinition {
248 previous: Span,
250
251 current: Span,
253 },
254 RecursiveDeclaration {
256 ident: Span,
258
259 usage: Span,
261 },
262 CyclicDeclaration {
265 ident: Span,
267
268 path: Box<[(Span, Span)]>,
275 },
276 InvalidSwitchSelector {
277 span: Span,
278 },
279 InvalidSwitchCase {
280 span: Span,
281 },
282 SwitchCaseTypeMismatch {
283 span: Span,
284 },
285 CalledEntryPoint(Span),
286 CalledLocalDecl(Span),
287 WrongArgumentCount {
288 span: Span,
289 expected: Range<u32>,
290 found: u32,
291 },
292 TooManyArguments {
294 function: String,
296
297 call_span: Span,
299
300 arg_span: Span,
302
303 max_arguments: u32,
306 },
307 WrongArgumentType {
310 function: String,
312
313 call_span: Span,
315
316 arg_span: Span,
318
319 arg_index: u32,
321
322 arg_ty: String,
324
325 allowed: Vec<String>,
328 },
329 InconsistentArgumentType {
332 function: String,
334
335 call_span: Span,
337
338 arg_span: Span,
340
341 arg_index: u32,
343
344 arg_ty: String,
346
347 inconsistent_span: Span,
350
351 inconsistent_index: u32,
353
354 inconsistent_ty: String,
356
357 allowed: Vec<String>,
360 },
361 FunctionReturnsVoid(Span),
362 FunctionMustUseUnused(Span),
363 FunctionMustUseReturnsVoid(Span, Span),
364 InvalidWorkGroupUniformLoad(Span),
365 Internal(&'static str),
366 ExpectedConstExprConcreteIntegerScalar(Span),
367 ExpectedNonNegative(Span),
368 ExpectedPositiveArrayLength(Span),
369 MissingWorkgroupSize(Span),
370 ConstantEvaluatorError(Box<ConstantEvaluatorError>, Span),
371 AutoConversion(Box<AutoConversionError>),
372 AutoConversionLeafScalar(Box<AutoConversionLeafScalarError>),
373 ConcretizationFailed(Box<ConcretizationFailedError>),
374 ExceededLimitForNestedBraces {
375 span: Span,
376 limit: u8,
377 },
378 PipelineConstantIDValue(Span),
379 NotBool(Span),
380 ConstAssertFailed(Span),
381 DirectiveAfterFirstGlobalDecl {
382 directive_span: Span,
383 },
384 EnableExtensionNotYetImplemented {
385 kind: UnimplementedEnableExtension,
386 span: Span,
387 },
388 EnableExtensionNotEnabled {
389 kind: EnableExtension,
390 span: Span,
391 },
392 EnableExtensionNotSupported {
393 kind: EnableExtension,
394 span: Span,
395 },
396 LanguageExtensionNotYetImplemented {
397 kind: UnimplementedLanguageExtension,
398 span: Span,
399 },
400 DiagnosticInvalidSeverity {
401 severity_control_name_span: Span,
402 },
403 DiagnosticDuplicateTriggeringRule(ConflictingDiagnosticRuleError),
404 DiagnosticAttributeNotYetImplementedAtParseSite {
405 site_name_plural: &'static str,
406 spans: Vec<Span>,
407 },
408 DiagnosticAttributeNotSupported {
409 on_what: DiagnosticAttributeNotSupportedPosition,
410 spans: Vec<Span>,
411 },
412 SelectUnexpectedArgumentType {
413 arg_span: Span,
414 arg_type: String,
415 },
416 SelectRejectAndAcceptHaveNoCommonType {
417 reject_span: Span,
418 reject_type: String,
419 accept_span: Span,
420 accept_type: String,
421 },
422 ExpectedGlobalVariable {
423 name_span: Span,
424 },
425 StructMemberTooLarge {
426 member_name_span: Span,
427 },
428 TypeTooLarge {
429 span: Span,
430 },
431 UnderspecifiedCooperativeMatrix,
432 InvalidCooperativeLoadType(Span),
433 UnsupportedCooperativeScalar(Span),
434 UnexpectedIdentForEnumerant(Span),
435 UnexpectedExprForEnumerant(Span),
436 UnusedArgsForTemplate(Vec<Span>),
437 UnexpectedTemplate(Span),
438 MissingTemplateArg {
439 span: Span,
440 description: &'static str,
441 },
442 UnexpectedExprForTypeExpression(Span),
443 MissingIncomingPayload(Span),
444}
445
446impl From<ConflictingDiagnosticRuleError> for Error<'_> {
447 fn from(value: ConflictingDiagnosticRuleError) -> Self {
448 Self::DiagnosticDuplicateTriggeringRule(value)
449 }
450}
451
452#[derive(Clone, Copy, Debug)]
454pub(crate) enum DiagnosticAttributeNotSupportedPosition {
455 SemicolonInModulePosition,
456 Other { display_plural: &'static str },
457}
458
459impl From<&'static str> for DiagnosticAttributeNotSupportedPosition {
460 fn from(display_plural: &'static str) -> Self {
461 Self::Other { display_plural }
462 }
463}
464
465#[derive(Clone, Debug)]
466pub(crate) struct AutoConversionError {
467 pub dest_span: Span,
468 pub dest_type: String,
469 pub source_span: Span,
470 pub source_type: String,
471}
472
473#[derive(Clone, Debug)]
474pub(crate) struct AutoConversionLeafScalarError {
475 pub dest_span: Span,
476 pub dest_scalar: String,
477 pub source_span: Span,
478 pub source_type: String,
479}
480
481#[derive(Clone, Debug)]
482pub(crate) struct ConcretizationFailedError {
483 pub expr_span: Span,
484 pub expr_type: String,
485 pub concretization_preferences: Vec<(String, ConstantEvaluatorError)>,
486}
487
488impl<'a> Error<'a> {
489 #[cold]
490 #[inline(never)]
491 pub(crate) fn as_parse_error(&self, source: &'a str) -> ParseError {
492 match *self {
493 Error::Unexpected(unexpected_span, expected) => {
494 let expected_str = match expected {
495 ExpectedToken::Token(token) => match token {
496 Token::Separator(c) => format!("`{c}`"),
497 Token::Paren(c) => format!("`{c}`"),
498 Token::Attribute => "@".to_string(),
499 Token::Number(_) => "number".to_string(),
500 Token::Word(s) => s.to_string(),
501 Token::Operation(c) => format!("operation (`{c}`)"),
502 Token::LogicalOperation(c) => format!("logical operation (`{c}`)"),
503 Token::ShiftOperation(c) => format!("bitshift (`{c}{c}`)"),
504 Token::AssignmentOperation(c) if c == '<' || c == '>' => {
505 format!("bitshift (`{c}{c}=`)")
506 }
507 Token::AssignmentOperation(c) => format!("operation (`{c}=`)"),
508 Token::IncrementOperation => "increment operation".to_string(),
509 Token::DecrementOperation => "decrement operation".to_string(),
510 Token::Arrow => "->".to_string(),
511 Token::TemplateArgsStart => "template args start".to_string(),
512 Token::TemplateArgsEnd => "template args end".to_string(),
513 Token::Unknown(c) => format!("unknown (`{c}`)"),
514 Token::Trivia => "trivia".to_string(),
515 Token::DocComment(s) => format!("doc comment ('{s}')"),
516 Token::ModuleDocComment(s) => format!("module doc comment ('{s}')"),
517 Token::End => "end".to_string(),
518 },
519 ExpectedToken::Identifier => "identifier".to_string(),
520 ExpectedToken::LhsExpression => "LHS expression (identifier component_or_swizzle_specifier?, (`lhs_expression`) component_or_swizzle_specifier?, &`lhs_expression`, *`lhs_expression`)".to_string(),
521 ExpectedToken::PrimaryExpression => "expression".to_string(),
522 ExpectedToken::Assignment => "assignment or increment/decrement".to_string(),
523 ExpectedToken::SwitchItem => concat!(
524 "switch item (`case` or `default`) or a closing curly bracket ",
525 "to signify the end of the switch statement (`}`)"
526 )
527 .to_string(),
528 ExpectedToken::WorkgroupSizeSeparator => {
529 "workgroup size separator (`,`) or a closing parenthesis".to_string()
530 }
531 ExpectedToken::GlobalItem => concat!(
532 "global item (`struct`, `const`, `var`, `alias`, ",
533 "`fn`, `diagnostic`, `enable`, `requires`, `;`) ",
534 "or the end of the file"
535 )
536 .to_string(),
537 ExpectedToken::Variable => "variable access".to_string(),
538 ExpectedToken::Function => "function name".to_string(),
539 ExpectedToken::AfterIdentListArg => {
540 "next argument, trailing comma, or end of list (`,` or `;`)".to_string()
541 }
542 ExpectedToken::AfterIdentListComma => {
543 "next argument or end of list (`;`)".to_string()
544 }
545 ExpectedToken::DiagnosticAttribute => {
546 "the `diagnostic` attribute identifier".to_string()
547 }
548 ExpectedToken::Statement => "statement".to_string(),
549 ExpectedToken::ForInit => "for loop initializer statement (`var`/`let`/`const` declaration, assignment, `i++`/`i--` statement, function call)".to_string(),
550 ExpectedToken::ForUpdate => "for loop update statement (assignment, `i++`/`i--` statement, function call)".to_string(),
551 };
552 ParseError {
553 message: format!(
554 "expected {}, found {:?}",
555 expected_str, &source[unexpected_span],
556 ),
557 labels: vec![(unexpected_span, format!("expected {expected_str}").into())],
558 notes: vec![],
559 }
560 }
561 Error::UnexpectedComponents(bad_span) => ParseError {
562 message: "unexpected components".to_string(),
563 labels: vec![(bad_span, "unexpected components".into())],
564 notes: vec![],
565 },
566 Error::UnexpectedOperationInConstContext(span) => ParseError {
567 message: "this operation is not supported in a const context".to_string(),
568 labels: vec![(span, "operation not supported here".into())],
569 notes: vec![],
570 },
571 Error::BadNumber(bad_span, ref err) => ParseError {
572 message: format!("{}: `{}`", err, &source[bad_span],),
573 labels: vec![(bad_span, err.to_string().into())],
574 notes: vec![],
575 },
576 Error::BadMatrixScalarKind(span, scalar) => ParseError {
577 message: format!(
578 "matrix scalar type must be floating-point, but found `{}`",
579 scalar.to_wgsl_for_diagnostics()
580 ),
581 labels: vec![(span, "must be floating-point (e.g. `f32`)".into())],
582 notes: vec![],
583 },
584 Error::BadAccessor(accessor_span) => ParseError {
585 message: format!("invalid field accessor `{}`", &source[accessor_span],),
586 labels: vec![(accessor_span, "invalid accessor".into())],
587 notes: vec![],
588 },
589 Error::UnknownIdent(ident_span, ident) => ParseError {
590 message: format!("no definition in scope for identifier: `{ident}`"),
591 labels: vec![(ident_span, "unknown identifier".into())],
592 notes: vec![],
593 },
594 Error::UnknownScalarType(bad_span) => ParseError {
595 message: format!("unknown scalar type: `{}`", &source[bad_span]),
596 labels: vec![(bad_span, "unknown scalar type".into())],
597 notes: vec!["Valid scalar types are f32, f64, i32, u32, bool".into()],
598 },
599 Error::NotStorageTexture(bad_span) => ParseError {
600 message: "textureStore can only be applied to storage textures".to_string(),
601 labels: vec![(bad_span, "not a storage texture".into())],
602 notes: vec![],
603 },
604 Error::BadTextureSampleType { span, scalar } => ParseError {
605 message: format!(
606 "texture sample type must be one of f32, i32 or u32, but found {}",
607 scalar.to_wgsl_for_diagnostics()
608 ),
609 labels: vec![(span, "must be one of f32, i32 or u32".into())],
610 notes: vec![],
611 },
612 Error::BadIncrDecrReferenceType(span) => ParseError {
613 message: concat!(
614 "increment/decrement operation requires ",
615 "reference type to be one of i32 or u32"
616 )
617 .to_string(),
618 labels: vec![(span, "must be a reference type of i32 or u32".into())],
619 notes: vec![],
620 },
621 Error::BadTexture(bad_span) => ParseError {
622 message: format!(
623 "expected an image, but found `{}` which is not an image",
624 &source[bad_span]
625 ),
626 labels: vec![(bad_span, "not an image".into())],
627 notes: vec![],
628 },
629 Error::BadTypeCast {
630 span,
631 ref from_type,
632 ref to_type,
633 } => {
634 let msg = format!("cannot cast a {from_type} to a {to_type}");
635 ParseError {
636 message: msg.clone(),
637 labels: vec![(span, msg.into())],
638 notes: vec![],
639 }
640 }
641 Error::InvalidResolve(ref resolve_error) => ParseError {
642 message: resolve_error.to_string(),
643 labels: vec![],
644 notes: vec![],
645 },
646 Error::InvalidBreakIf(bad_span) => ParseError {
647 message: "A break if is only allowed in a continuing block".to_string(),
648 labels: vec![(bad_span, "not in a continuing block".into())],
649 notes: vec![],
650 },
651 Error::InvalidGatherComponent(bad_span) => ParseError {
652 message: format!(
653 "textureGather component `{}` doesn't exist, must be 0, 1, 2, or 3",
654 &source[bad_span]
655 ),
656 labels: vec![(bad_span, "invalid component".into())],
657 notes: vec![],
658 },
659 Error::InvalidConstructorComponentType(bad_span, component) => ParseError {
660 message: format!("invalid type for constructor component at index [{component}]"),
661 labels: vec![(bad_span, "invalid component type".into())],
662 notes: vec![],
663 },
664 Error::InvalidIdentifierUnderscore(bad_span) => ParseError {
665 message: "Identifier can't be `_`".to_string(),
666 labels: vec![(bad_span, "invalid identifier".into())],
667 notes: vec![
668 "Use phony assignment instead (`_ =` notice the absence of `let` or `var`)"
669 .to_string(),
670 ],
671 },
672 Error::ReservedIdentifierPrefix(bad_span) => ParseError {
673 message: format!(
674 "Identifier starts with a reserved prefix: `{}`",
675 &source[bad_span]
676 ),
677 labels: vec![(bad_span, "invalid identifier".into())],
678 notes: vec![],
679 },
680 Error::UnknownAddressSpace(bad_span) => ParseError {
681 message: format!("unknown address space: `{}`", &source[bad_span]),
682 labels: vec![(bad_span, "unknown address space".into())],
683 notes: vec![],
684 },
685 Error::InvalidLocalVariableAddressSpace(bad_span) => ParseError {
686 message: format!("invalid address space for local variable: `{}`", &source[bad_span]),
687 labels: vec![(bad_span, "local variables can only use 'function' address space".into())],
688 notes: vec![],
689 },
690 Error::UnknownRayFlag(bad_span) => ParseError {
691 message: format!("unknown ray flag: `{}`", &source[bad_span]),
692 labels: vec![(bad_span, "unknown ray flag".into())],
693 notes: vec![],
694 },
695 Error::RepeatedAttribute(bad_span) => ParseError {
696 message: format!("repeated attribute: `{}`", &source[bad_span]),
697 labels: vec![(bad_span, "repeated attribute".into())],
698 notes: vec![],
699 },
700 Error::UnknownAttribute(bad_span) => ParseError {
701 message: format!("unknown attribute: `{}`", &source[bad_span]),
702 labels: vec![(bad_span, "unknown attribute".into())],
703 notes: vec![],
704 },
705 Error::UnknownBuiltin(bad_span) => ParseError {
706 message: format!("unknown builtin: `{}`", &source[bad_span]),
707 labels: vec![(bad_span, "unknown builtin".into())],
708 notes: vec![],
709 },
710 Error::UnknownAccess(bad_span) => ParseError {
711 message: format!("unknown access: `{}`", &source[bad_span]),
712 labels: vec![(bad_span, "unknown access".into())],
713 notes: vec![],
714 },
715 Error::UnknownStorageFormat(bad_span) => ParseError {
716 message: format!("unknown storage format: `{}`", &source[bad_span]),
717 labels: vec![(bad_span, "unknown storage format".into())],
718 notes: vec![],
719 },
720 Error::UnknownConservativeDepth(bad_span) => ParseError {
721 message: format!("unknown conservative depth: `{}`", &source[bad_span]),
722 labels: vec![(bad_span, "unknown conservative depth".into())],
723 notes: vec![],
724 },
725 Error::UnknownEnableExtension(span, word) => ParseError {
726 message: format!("unknown enable-extension `{word}`"),
727 labels: vec![(span, "".into())],
728 notes: vec![
729 "See available extensions at <https://www.w3.org/TR/WGSL/#enable-extension>."
730 .into(),
731 ],
732 },
733 Error::UnknownLanguageExtension(span, name) => ParseError {
734 message: format!("unknown language extension `{name}`"),
735 labels: vec![(span, "".into())],
736 notes: vec![concat!(
737 "See available extensions at ",
738 "<https://www.w3.org/TR/WGSL/#language-extensions-sec>."
739 )
740 .into()],
741 },
742 Error::UnknownDiagnosticRuleName(span) => ParseError {
743 message: format!("unknown `diagnostic(…)` rule name `{}`", &source[span]),
744 labels: vec![(span, "not a valid diagnostic rule name".into())],
745 notes: vec![concat!(
746 "See available trigger rules at ",
747 "<https://www.w3.org/TR/WGSL/#filterable-triggering-rules>."
748 )
749 .into()],
750 },
751 Error::SizeAttributeTooLow(bad_span, min_size) => ParseError {
752 message: format!("struct member size must be at least {min_size}"),
753 labels: vec![(bad_span, format!("must be at least {min_size}").into())],
754 notes: vec![],
755 },
756 Error::AlignAttributeTooLow(bad_span, min_align) => ParseError {
757 message: format!("struct member alignment must be at least {min_align}"),
758 labels: vec![(bad_span, format!("must be at least {min_align}").into())],
759 notes: vec![],
760 },
761 Error::NonPowerOfTwoAlignAttribute(bad_span) => ParseError {
762 message: "struct member alignment must be a power of 2".to_string(),
763 labels: vec![(bad_span, "must be a power of 2".into())],
764 notes: vec![],
765 },
766 Error::InconsistentBinding(span) => ParseError {
767 message: "input/output binding is not consistent".to_string(),
768 labels: vec![(span, "input/output binding is not consistent".into())],
769 notes: vec![],
770 },
771 Error::TypeNotConstructible(span) => ParseError {
772 message: format!("type `{}` is not constructible", &source[span]),
773 labels: vec![(span, "type is not constructible".into())],
774 notes: vec![],
775 },
776 Error::TypeNotInferable(span) => ParseError {
777 message: "type can't be inferred".to_string(),
778 labels: vec![(span, "type can't be inferred".into())],
779 notes: vec![],
780 },
781 Error::InitializationTypeMismatch {
782 name,
783 ref expected,
784 ref got,
785 } => ParseError {
786 message: format!(
787 "the type of `{}` is expected to be `{}`, but got `{}`",
788 &source[name], expected, got,
789 ),
790 labels: vec![(name, format!("definition of `{}`", &source[name]).into())],
791 notes: vec![],
792 },
793 Error::DeclMissingTypeAndInit(name_span) => ParseError {
794 message: format!(
795 "declaration of `{}` needs a type specifier or initializer",
796 &source[name_span]
797 ),
798 labels: vec![(name_span, "needs a type specifier or initializer".into())],
799 notes: vec![],
800 },
801 Error::MissingAttribute(name, name_span) => ParseError {
802 message: format!(
803 "variable `{}` needs a '{}' attribute",
804 &source[name_span], name
805 ),
806 labels: vec![(
807 name_span,
808 format!("definition of `{}`", &source[name_span]).into(),
809 )],
810 notes: vec![],
811 },
812 Error::InvalidAddrOfOperand(span) => ParseError {
813 message: "cannot take the address of a vector component".to_string(),
814 labels: vec![(span, "invalid operand for address-of".into())],
815 notes: vec![],
816 },
817 Error::InvalidAtomicPointer(span) => ParseError {
818 message: "atomic operation is done on a pointer to a non-atomic".to_string(),
819 labels: vec![(span, "atomic pointer is invalid".into())],
820 notes: vec![],
821 },
822 Error::InvalidAtomicOperandType(span) => ParseError {
823 message: "atomic operand type is inconsistent with the operation".to_string(),
824 labels: vec![(span, "atomic operand type is invalid".into())],
825 notes: vec![],
826 },
827 Error::InvalidAtomicAccess(span) => ParseError {
828 message: "atomic variables cannot be accessed directly; use atomic built-in functions".to_string(),
829 labels: vec![(span, "direct access to atomic variable is not allowed".into())],
830 notes: vec![],
831 },
832 Error::InvalidRayQueryPointer(span) => ParseError {
833 message: "ray query operation is done on a pointer to a non-ray-query".to_string(),
834 labels: vec![(span, "ray query pointer is invalid".into())],
835 notes: vec![],
836 },
837 Error::NotPointer(span) => ParseError {
838 message: "the operand of the `*` operator must be a pointer".to_string(),
839 labels: vec![(span, "expression is not a pointer".into())],
840 notes: vec![],
841 },
842 Error::NotReference(what, span) => ParseError {
843 message: format!("{what} must be a reference"),
844 labels: vec![(span, "expression is not a reference".into())],
845 notes: vec![],
846 },
847 Error::InvalidAssignment { span, ty } => {
848 let (extra_label, notes) = match ty {
849 InvalidAssignmentType::Swizzle => (
850 None,
851 vec![
852 "WGSL does not support assignments to swizzles".into(),
853 "consider assigning each component individually".into(),
854 ],
855 ),
856 InvalidAssignmentType::ImmutableBinding(binding_span) => (
857 Some((binding_span, "this is an immutable binding".into())),
858 vec![format!(
859 "consider declaring `{}` with `var` instead of `let`",
860 &source[binding_span]
861 )],
862 ),
863 InvalidAssignmentType::Other => (None, vec![]),
864 };
865
866 ParseError {
867 message: "invalid left-hand side of assignment".into(),
868 labels: core::iter::once((span, "cannot assign to this expression".into()))
869 .chain(extra_label)
870 .collect(),
871 notes,
872 }
873 }
874 Error::ReservedKeyword(name_span) => ParseError {
875 message: format!("name `{}` is a reserved keyword", &source[name_span]),
876 labels: vec![(
877 name_span,
878 format!("definition of `{}`", &source[name_span]).into(),
879 )],
880 notes: vec![],
881 },
882 Error::Redefinition { previous, current } => ParseError {
883 message: format!("redefinition of `{}`", &source[current]),
884 labels: vec![
885 (
886 current,
887 format!("redefinition of `{}`", &source[current]).into(),
888 ),
889 (
890 previous,
891 format!("previous definition of `{}`", &source[previous]).into(),
892 ),
893 ],
894 notes: vec![],
895 },
896 Error::RecursiveDeclaration { ident, usage } => ParseError {
897 message: format!("declaration of `{}` is recursive", &source[ident]),
898 labels: vec![(ident, "".into()), (usage, "uses itself here".into())],
899 notes: vec![],
900 },
901 Error::CyclicDeclaration { ident, ref path } => ParseError {
902 message: format!("declaration of `{}` is cyclic", &source[ident]),
903 labels: path
904 .iter()
905 .enumerate()
906 .flat_map(|(i, &(ident, usage))| {
907 [
908 (ident, "".into()),
909 (
910 usage,
911 if i == path.len() - 1 {
912 "ending the cycle".into()
913 } else {
914 format!("uses `{}`", &source[ident]).into()
915 },
916 ),
917 ]
918 })
919 .collect(),
920 notes: vec![],
921 },
922 Error::InvalidSwitchSelector { span } => ParseError {
923 message: "invalid `switch` selector".to_string(),
924 labels: vec![(
925 span,
926 "`switch` selector must be a scalar integer"
927 .into(),
928 )],
929 notes: vec![],
930 },
931 Error::InvalidSwitchCase { span } => ParseError {
932 message: "invalid `switch` case selector value".to_string(),
933 labels: vec![(
934 span,
935 "`switch` case selector must be a scalar integer const expression"
936 .into(),
937 )],
938 notes: vec![],
939 },
940 Error::SwitchCaseTypeMismatch { span } => ParseError {
941 message: "invalid `switch` case selector value".to_string(),
942 labels: vec![(
943 span,
944 "`switch` case selector must have the same type as the `switch` selector expression"
945 .into(),
946 )],
947 notes: vec![],
948 },
949 Error::CalledEntryPoint(span) => ParseError {
950 message: "entry point cannot be called".to_string(),
951 labels: vec![(span, "entry point cannot be called".into())],
952 notes: vec![],
953 },
954 Error::CalledLocalDecl(span) => ParseError {
955 message: "local declaration cannot be called".to_string(),
956 labels: vec![(span, "local declaration cannot be called".into())],
957 notes: vec![],
958 },
959 Error::WrongArgumentCount {
960 span,
961 ref expected,
962 found,
963 } => ParseError {
964 message: format!(
965 "wrong number of arguments: expected {}, found {}",
966 if expected.len() < 2 {
967 format!("{}", expected.start)
968 } else {
969 format!("{}..{}", expected.start, expected.end)
970 },
971 found
972 ),
973 labels: vec![(span, "wrong number of arguments".into())],
974 notes: vec![],
975 },
976 Error::TooManyArguments {
977 ref function,
978 call_span,
979 arg_span,
980 max_arguments,
981 } => ParseError {
982 message: format!("too many arguments passed to `{function}`"),
983 labels: vec![
984 (call_span, "".into()),
985 (arg_span, format!("unexpected argument #{}", max_arguments + 1).into())
986 ],
987 notes: vec![
988 format!("The `{function}` function accepts at most {max_arguments} argument(s)")
989 ],
990 },
991 Error::WrongArgumentType {
992 ref function,
993 call_span,
994 arg_span,
995 arg_index,
996 ref arg_ty,
997 ref allowed,
998 } => {
999 let message = format!(
1000 "wrong type passed as argument #{} to `{function}`",
1001 arg_index + 1,
1002 );
1003 let labels = vec![
1004 (call_span, "".into()),
1005 (arg_span, format!("argument #{} has type `{arg_ty}`", arg_index + 1).into())
1006 ];
1007
1008 let mut notes = vec![];
1009 notes.push(format!("`{function}` accepts the following types for argument #{}:", arg_index + 1));
1010 notes.extend(allowed.iter().map(|ty| format!("allowed type: {ty}")));
1011
1012 ParseError { message, labels, notes }
1013 },
1014 Error::InconsistentArgumentType {
1015 ref function,
1016 call_span,
1017 arg_span,
1018 arg_index,
1019 ref arg_ty,
1020 inconsistent_span,
1021 inconsistent_index,
1022 ref inconsistent_ty,
1023 ref allowed
1024 } => {
1025 let message = format!(
1026 "inconsistent type passed as argument #{} to `{function}`",
1027 arg_index + 1,
1028 );
1029 let labels = vec![
1030 (call_span, "".into()),
1031 (arg_span, format!("argument #{} has type {arg_ty}", arg_index + 1).into()),
1032 (inconsistent_span, format!(
1033 "this argument has type {inconsistent_ty}, which constrains subsequent arguments"
1034 ).into()),
1035 ];
1036 let mut notes = vec![
1037 format!("Because argument #{} has type {inconsistent_ty}, only the following types", inconsistent_index + 1),
1038 format!("(or types that automatically convert to them) are accepted for argument #{}:", arg_index + 1),
1039 ];
1040 notes.extend(allowed.iter().map(|ty| format!("allowed type: {ty}")));
1041
1042 ParseError { message, labels, notes }
1043 }
1044 Error::FunctionReturnsVoid(span) => ParseError {
1045 message: "function does not return any value".to_string(),
1046 labels: vec![(span, "".into())],
1047 notes: vec![
1048 "perhaps you meant to call the function in a separate statement?".into(),
1049 ],
1050 },
1051 Error::FunctionMustUseUnused(call) => ParseError {
1052 message: "unused return value from function annotated with @must_use".into(),
1053 labels: vec![(call, "".into())],
1054 notes: vec![
1055 format!(
1056 "function '{}' is declared with `@must_use` attribute",
1057 &source[call],
1058 ),
1059 "use a phony assignment or declare a value using the function call as the initializer".into(),
1060 ],
1061 },
1062 Error::FunctionMustUseReturnsVoid(attr, signature) => ParseError {
1063 message: "function annotated with @must_use but does not return any value".into(),
1064 labels: vec![
1065 (attr, "".into()),
1066 (signature, "".into()),
1067 ],
1068 notes: vec![
1069 "declare a return type or remove the attribute".into(),
1070 ],
1071 },
1072 Error::InvalidWorkGroupUniformLoad(span) => ParseError {
1073 message: "incorrect type passed to workgroupUniformLoad".into(),
1074 labels: vec![(span, "".into())],
1075 notes: vec!["passed type must be a workgroup pointer".into()],
1076 },
1077 Error::Internal(message) => ParseError {
1078 message: "internal WGSL front end error".to_string(),
1079 labels: vec![],
1080 notes: vec![message.into()],
1081 },
1082 Error::ExpectedConstExprConcreteIntegerScalar(span) => ParseError {
1083 message: concat!(
1084 "must be a const-expression that ",
1085 "resolves to a concrete integer scalar (`u32` or `i32`)"
1086 )
1087 .to_string(),
1088 labels: vec![(span, "must resolve to `u32` or `i32`".into())],
1089 notes: vec![],
1090 },
1091 Error::ExpectedNonNegative(span) => ParseError {
1092 message: "must be non-negative (>= 0)".to_string(),
1093 labels: vec![(span, "must be non-negative".into())],
1094 notes: vec![],
1095 },
1096 Error::ExpectedPositiveArrayLength(span) => ParseError {
1097 message: "array element count must be positive (> 0)".to_string(),
1098 labels: vec![(span, "must be positive".into())],
1099 notes: vec![],
1100 },
1101 Error::ConstantEvaluatorError(ref e, span) => ParseError {
1102 message: e.to_string(),
1103 labels: vec![(span, "see msg".into())],
1104 notes: vec![],
1105 },
1106 Error::MissingWorkgroupSize(span) => ParseError {
1107 message: "workgroup size is missing on compute shader entry point".to_string(),
1108 labels: vec![(
1109 span,
1110 "must be paired with a `@workgroup_size` attribute".into(),
1111 )],
1112 notes: vec![],
1113 },
1114 Error::AutoConversion(ref error) => {
1115 let AutoConversionError {
1117 dest_span,
1118 ref dest_type,
1119 source_span,
1120 ref source_type,
1121 } = **error;
1122 ParseError {
1123 message: format!(
1124 "automatic conversions cannot convert `{source_type}` to `{dest_type}`"
1125 ),
1126 labels: vec![
1127 (
1128 dest_span,
1129 format!("a value of type {dest_type} is required here").into(),
1130 ),
1131 (
1132 source_span,
1133 format!("this expression has type {source_type}").into(),
1134 ),
1135 ],
1136 notes: vec![],
1137 }
1138 }
1139 Error::AutoConversionLeafScalar(ref error) => {
1140 let AutoConversionLeafScalarError {
1141 dest_span,
1142 ref dest_scalar,
1143 source_span,
1144 ref source_type,
1145 } = **error;
1146 ParseError {
1147 message: format!(
1148 "automatic conversions cannot convert elements of `{source_type}` to `{dest_scalar}`"
1149 ),
1150 labels: vec![
1151 (
1152 dest_span,
1153 format!(
1154 "a value with elements of type {dest_scalar} is required here"
1155 )
1156 .into(),
1157 ),
1158 (
1159 source_span,
1160 format!("this expression has type {source_type}").into(),
1161 ),
1162 ],
1163 notes: vec![],
1164 }
1165 }
1166 Error::ConcretizationFailed(ref error) => {
1167 let ConcretizationFailedError {
1168 expr_span,
1169 ref expr_type,
1170 ref concretization_preferences,
1171 } = **error;
1172 ParseError {
1173 message: "failed to convert expression to a concrete type".to_string(),
1174 labels: vec![(
1175 expr_span,
1176 format!("this expression has type {expr_type}").into(),
1177 )],
1178 notes: concretization_preferences
1179 .iter()
1180 .map(|&(ref scalar, ref err)|
1181 format!("the expression couldn't be converted to have {scalar} scalar type: {err}")
1182 )
1183 .collect(),
1184 }
1185 }
1186 Error::ExceededLimitForNestedBraces { span, limit } => ParseError {
1187 message: "brace nesting limit reached".into(),
1188 labels: vec![(span, "limit reached at this brace".into())],
1189 notes: vec![format!("nesting limit is currently set to {limit}")],
1190 },
1191 Error::PipelineConstantIDValue(span) => ParseError {
1192 message: "pipeline constant ID must be between 0 and 65535 inclusive".to_string(),
1193 labels: vec![(span, "must be between 0 and 65535 inclusive".into())],
1194 notes: vec![],
1195 },
1196 Error::NotBool(span) => ParseError {
1197 message: "must be a const-expression that resolves to a `bool`".to_string(),
1198 labels: vec![(span, "must resolve to `bool`".into())],
1199 notes: vec![],
1200 },
1201 Error::ConstAssertFailed(span) => ParseError {
1202 message: "`const_assert` failure".to_string(),
1203 labels: vec![(span, "evaluates to `false`".into())],
1204 notes: vec![],
1205 },
1206 Error::DirectiveAfterFirstGlobalDecl { directive_span } => ParseError {
1207 message: "expected global declaration, but found a global directive".into(),
1208 labels: vec![(
1209 directive_span,
1210 "written after first global declaration".into(),
1211 )],
1212 notes: vec![concat!(
1213 "global directives are only allowed before global declarations; ",
1214 "maybe hoist this closer to the top of the shader module?"
1215 )
1216 .into()],
1217 },
1218 Error::EnableExtensionNotYetImplemented { kind, span } => ParseError {
1219 message: format!(
1220 "the `{}` enable-extension is not yet supported",
1221 EnableExtension::Unimplemented(kind).to_ident()
1222 ),
1223 labels: vec![(
1224 span,
1225 concat!(
1226 "this enable-extension specifies standard functionality ",
1227 "which is not yet implemented in Naga"
1228 )
1229 .into(),
1230 )],
1231 notes: vec![format!(
1232 concat!(
1233 "Let Naga maintainers know that you ran into this at ",
1234 "<https://github.com/gfx-rs/wgpu/issues/{}>, ",
1235 "so they can prioritize it!"
1236 ),
1237 kind.tracking_issue_num()
1238 )],
1239 },
1240 Error::EnableExtensionNotEnabled { kind, span } => ParseError {
1241 message: format!("the `{}` enable extension is not enabled", kind.to_ident()),
1242 labels: vec![(
1243 span,
1244 format!(
1245 concat!(
1246 "the `{}` \"Enable Extension\" is needed for this functionality, ",
1247 "but it is not currently enabled."
1248 ),
1249 kind.to_ident()
1250 )
1251 .into(),
1252 )],
1253 notes: if let EnableExtension::Unimplemented(kind) = kind {
1254 vec![format!(
1255 concat!(
1256 "This \"Enable Extension\" is not yet implemented. ",
1257 "Let Naga maintainers know that you ran into this at ",
1258 "<https://github.com/gfx-rs/wgpu/issues/{}>, ",
1259 "so they can prioritize it!"
1260 ),
1261 kind.tracking_issue_num()
1262 )]
1263 } else {
1264 vec![
1265 format!(
1266 "You can enable this extension by adding `enable {};` at the top of the shader, before any other items.",
1267 kind.to_ident()
1268 ),
1269 ]
1270 },
1271 },
1272 Error::EnableExtensionNotSupported { kind, span } => ParseError {
1273 message: format!(
1274 "the `{}` extension is not supported in the current environment",
1275 kind.to_ident()
1276 ),
1277 labels: vec![(
1278 span,
1279 "unsupported enable-extension".into(),
1280 )],
1281 notes: vec![],
1282 },
1283 Error::LanguageExtensionNotYetImplemented { kind, span } => ParseError {
1284 message: format!(
1285 "the `{}` language extension is not yet supported",
1286 LanguageExtension::Unimplemented(kind).to_ident()
1287 ),
1288 labels: vec![(span, "".into())],
1289 notes: vec![format!(
1290 concat!(
1291 "Let Naga maintainers know that you ran into this at ",
1292 "<https://github.com/gfx-rs/wgpu/issues/{}>, ",
1293 "so they can prioritize it!"
1294 ),
1295 kind.tracking_issue_num()
1296 )],
1297 },
1298 Error::DiagnosticInvalidSeverity {
1299 severity_control_name_span,
1300 } => ParseError {
1301 message: "invalid `diagnostic(…)` severity".into(),
1302 labels: vec![(
1303 severity_control_name_span,
1304 "not a valid severity level".into(),
1305 )],
1306 notes: vec![concat!(
1307 "See available severities at ",
1308 "<https://www.w3.org/TR/WGSL/#diagnostic-severity>."
1309 )
1310 .into()],
1311 },
1312 Error::DiagnosticDuplicateTriggeringRule(ConflictingDiagnosticRuleError {
1313 triggering_rule_spans,
1314 }) => {
1315 let [first_span, second_span] = triggering_rule_spans;
1316 ParseError {
1317 message: "found conflicting `diagnostic(…)` rule(s)".into(),
1318 labels: vec![
1319 (first_span, "first rule".into()),
1320 (second_span, "second rule".into()),
1321 ],
1322 notes: vec![
1323 concat!(
1324 "Multiple `diagnostic(…)` rules with the same rule name ",
1325 "conflict unless they are directives and the severity is the same.",
1326 )
1327 .into(),
1328 "You should delete the rule you don't want.".into(),
1329 ],
1330 }
1331 }
1332 Error::DiagnosticAttributeNotYetImplementedAtParseSite {
1333 site_name_plural,
1334 ref spans,
1335 } => ParseError {
1336 message: "`@diagnostic(…)` attribute(s) not yet implemented".into(),
1337 labels: {
1338 let mut spans = spans.iter().cloned();
1339 let first = spans
1340 .next()
1341 .map(|span| {
1342 (
1343 span,
1344 format!("can't use this on {site_name_plural} (yet)").into(),
1345 )
1346 })
1347 .expect("internal error: diag. attr. rejection on empty map");
1348 core::iter::once(first)
1349 .chain(spans.map(|span| (span, "".into())))
1350 .collect()
1351 },
1352 notes: vec![format!(concat!(
1353 "Let Naga maintainers know that you ran into this at ",
1354 "<https://github.com/gfx-rs/wgpu/issues/5320>, ",
1355 "so they can prioritize it!"
1356 ))],
1357 },
1358 Error::DiagnosticAttributeNotSupported { on_what, ref spans } => {
1359 let intended_diagnostic_directive = match on_what {
1362 DiagnosticAttributeNotSupportedPosition::SemicolonInModulePosition => true,
1363 DiagnosticAttributeNotSupportedPosition::Other { .. } => false,
1364 };
1365 let on_what_plural = match on_what {
1366 DiagnosticAttributeNotSupportedPosition::SemicolonInModulePosition => {
1367 "semicolons"
1368 }
1369 DiagnosticAttributeNotSupportedPosition::Other { display_plural } => {
1370 display_plural
1371 }
1372 };
1373 ParseError {
1374 message: format!(
1375 "`@diagnostic(…)` attribute(s) on {on_what_plural} are not supported",
1376 ),
1377 labels: spans
1378 .iter()
1379 .cloned()
1380 .map(|span| (span, "".into()))
1381 .collect(),
1382 notes: vec![
1383 concat!(
1384 "`@diagnostic(…)` attributes are only permitted on `fn`s, ",
1385 "some statements, and `switch`/`loop` bodies."
1386 )
1387 .into(),
1388 {
1389 if intended_diagnostic_directive {
1390 concat!(
1391 "If you meant to declare a diagnostic filter that ",
1392 "applies to the entire module, move this line to ",
1393 "the top of the file and remove the `@` symbol."
1394 )
1395 .into()
1396 } else {
1397 concat!(
1398 "These attributes are well-formed, ",
1399 "you likely just need to move them."
1400 )
1401 .into()
1402 }
1403 },
1404 ],
1405 }
1406 }
1407 Error::SelectUnexpectedArgumentType { arg_span, ref arg_type } => ParseError {
1408 message: "unexpected argument type for `select` call".into(),
1409 labels: vec![(arg_span, format!("this value of type {arg_type}").into())],
1410 notes: vec!["expected a scalar or a `vecN` of scalars".into()],
1411 },
1412 Error::SelectRejectAndAcceptHaveNoCommonType {
1413 reject_span,
1414 ref reject_type,
1415 accept_span,
1416 ref accept_type,
1417 } => ParseError {
1418 message: "type mismatch for reject and accept values in `select` call".into(),
1419 labels: vec![
1420 (reject_span, format!("reject value of type {reject_type}").into()),
1421 (accept_span, format!("accept value of type {accept_type}").into()),
1422 ],
1423 notes: vec![],
1424 },
1425 Error::ExpectedGlobalVariable { name_span } => ParseError {
1426 message: "expected global variable".to_string(),
1427 labels: vec![(name_span, "variable used here".into())],
1428 notes: vec![],
1429 },
1430 Error::StructMemberTooLarge { member_name_span } => ParseError {
1431 message: "struct member is too large".into(),
1432 labels: vec![(member_name_span, "this member exceeds the maximum size".into())],
1433 notes: vec![format!(
1434 "the maximum size is {} bytes",
1435 crate::valid::MAX_TYPE_SIZE
1436 )],
1437 },
1438 Error::TypeTooLarge { span } => ParseError {
1439 message: "type is too large".into(),
1440 labels: vec![(span, "this type exceeds the maximum size".into())],
1441 notes: vec![format!(
1442 "the maximum size is {} bytes",
1443 crate::valid::MAX_TYPE_SIZE
1444 )],
1445 },
1446 Error::UnderspecifiedCooperativeMatrix => ParseError {
1447 message: "cooperative matrix constructor is underspecified".into(),
1448 labels: vec![],
1449 notes: vec![format!("must be F32")],
1450 },
1451 Error::InvalidCooperativeLoadType(span) => ParseError {
1452 message: "cooperative load should have a generic type for coop_mat".into(),
1453 labels: vec![(span, "type needs the coop_mat<...>".into())],
1454 notes: vec![format!("must be a valid cooperative type")],
1455 },
1456 Error::UnsupportedCooperativeScalar(span) => ParseError {
1457 message: "cooperative scalar type is not supported".into(),
1458 labels: vec![(span, "type needs the scalar type specified".into())],
1459 notes: vec![format!("must be F32")],
1460 },
1461 Error::UnexpectedIdentForEnumerant(ident_span) => ParseError {
1462 message: format!(
1463 "identifier `{}` resolves to a declaration",
1464 &source[ident_span]
1465 ),
1466 labels: vec![(ident_span, "needs to resolve to a predeclared enumerant".into())],
1467 notes: vec![],
1468 },
1469 Error::UnexpectedExprForEnumerant(expr_span) => ParseError {
1470 message: "unexpected expression".to_string(),
1471 labels: vec![(expr_span, "needs to be an identifier resolving to a predeclared enumerant".into())],
1472 notes: vec![],
1473 },
1474 Error::UnusedArgsForTemplate(ref expr_spans) => ParseError {
1475 message: "unused expressions for template".to_string(),
1476 labels: expr_spans.iter().cloned().map(|span| -> (_, _){ (span, "unused".into()) }).collect(),
1477 notes: vec![],
1478 },
1479 Error::UnexpectedTemplate(span) => ParseError {
1480 message: "unexpected template".to_string(),
1481 labels: vec![(span, "expected identifier".into())],
1482 notes: vec![],
1483 },
1484 Error::MissingTemplateArg {
1485 span,
1486 description: arg,
1487 } => ParseError {
1488 message: format!(
1489 "`{}` needs a template argument specified: {arg}",
1490 &source[span]
1491 ),
1492 labels: vec![(span, "is missing a template argument".into())],
1493 notes: vec![],
1494 },
1495 Error::UnexpectedExprForTypeExpression(expr_span) => ParseError {
1496 message: "unexpected expression".to_string(),
1497 labels: vec![(expr_span, "needs to be an identifier resolving to a type declaration (alias or struct) or predeclared type(-generator)".into())],
1498 notes: vec![],
1499 },
1500 Error::MissingIncomingPayload(span) => ParseError {
1501 message: "incoming payload is missing on a `closest_hit`, `any_hit` or `miss` shader entry point".to_string(),
1502 labels: vec![(
1503 span,
1504 "must be paired with a `@incoming_payload` attribute".into(),
1505 )],
1506 notes: vec![],
1507 },
1508 }
1509 }
1510}