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<P>(&self, source: &str, path: P) -> String
106 where
107 P: AsRef<std::path::Path>,
108 {
109 let path = path.as_ref().display().to_string();
110 let files = SimpleFile::new(path, replace_control_chars(source));
111 let config = term::Config::default();
112
113 let mut writer = crate::error::DiagnosticBuffer::new();
114 writer
115 .emit_to_self(&config, &files, &self.diagnostic())
116 .expect("cannot write error");
117 writer.into_string()
118 }
119
120 pub fn location(&self, source: &str) -> Option<SourceLocation> {
122 self.labels.first().map(|label| label.0.location(source))
123 }
124}
125
126impl core::fmt::Display for ParseError {
127 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
128 write!(f, "{}", self.message)
129 }
130}
131
132impl core::error::Error for ParseError {}
133
134#[derive(Copy, Clone, Debug, PartialEq)]
135pub enum ExpectedToken<'a> {
136 Token(Token<'a>),
137 Identifier,
138 AfterIdentListComma,
139 AfterIdentListArg,
140 LhsExpression,
142 PrimaryExpression,
144 Assignment,
146 SwitchItem,
148 WorkgroupSizeSeparator,
150 GlobalItem,
152 Variable,
154 Function,
156 DiagnosticAttribute,
158 Statement,
160 ForInit,
162 ForUpdate,
164}
165
166#[derive(Clone, Copy, Debug, Error, PartialEq)]
167pub enum NumberError {
168 #[error("invalid numeric literal format")]
169 Invalid,
170 #[error("numeric literal not representable by target type")]
171 NotRepresentable,
172}
173
174#[derive(Copy, Clone, Debug, PartialEq)]
175pub enum InvalidAssignmentType {
176 Other,
177 Swizzle,
178 ImmutableBinding(Span),
179}
180
181#[derive(Clone, Debug)]
182pub(crate) enum Error<'a> {
183 Unexpected(Span, ExpectedToken<'a>),
184 UnexpectedComponents(Span),
185 UnexpectedOperationInConstContext(Span),
186 BadNumber(Span, NumberError),
187 BadMatrixScalarKind(Span, Scalar),
188 BadAccessor(Span),
189 BadTexture(Span),
190 BadTypeCast {
191 span: Span,
192 from_type: String,
193 to_type: String,
194 },
195 NotStorageTexture(Span),
196 BadTextureSampleType {
197 span: Span,
198 scalar: Scalar,
199 },
200 BadIncrDecrReferenceType(Span),
201 InvalidResolve(ResolveError),
202 InvalidBreakIf(Span),
204 InvalidGatherComponent(Span),
205 InvalidConstructorComponentType(Span, i32),
206 InvalidIdentifierUnderscore(Span),
207 ReservedIdentifierPrefix(Span),
208 UnknownAddressSpace(Span),
209 InvalidLocalVariableAddressSpace(Span),
210 UnknownRayFlag(Span),
211 RepeatedAttribute(Span),
212 UnknownAttribute(Span),
213 UnknownBuiltin(Span),
214 UnknownAccess(Span),
215 UnknownIdent(Span, &'a str),
216 UnknownScalarType(Span),
217 UnknownStorageFormat(Span),
218 UnknownConservativeDepth(Span),
219 UnknownEnableExtension(Span, &'a str),
220 UnknownLanguageExtension(Span, &'a str),
221 UnknownDiagnosticRuleName(Span),
222 SizeAttributeTooLow(Span, u32),
223 AlignAttributeTooLow(Span, Alignment),
224 NonPowerOfTwoAlignAttribute(Span),
225 InconsistentBinding(Span),
226 TypeNotConstructible(Span),
227 TypeNotInferable(Span),
228 InitializationTypeMismatch {
229 name: Span,
230 expected: String,
231 got: String,
232 },
233 DeclMissingTypeAndInit(Span),
234 MissingAttribute(&'static str, Span),
235 InvalidAddrOfOperand(Span),
236 InvalidAtomicPointer(Span),
237 InvalidAtomicOperandType(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::InvalidRayQueryPointer(span) => ParseError {
828 message: "ray query operation is done on a pointer to a non-ray-query".to_string(),
829 labels: vec![(span, "ray query pointer is invalid".into())],
830 notes: vec![],
831 },
832 Error::NotPointer(span) => ParseError {
833 message: "the operand of the `*` operator must be a pointer".to_string(),
834 labels: vec![(span, "expression is not a pointer".into())],
835 notes: vec![],
836 },
837 Error::NotReference(what, span) => ParseError {
838 message: format!("{what} must be a reference"),
839 labels: vec![(span, "expression is not a reference".into())],
840 notes: vec![],
841 },
842 Error::InvalidAssignment { span, ty } => {
843 let (extra_label, notes) = match ty {
844 InvalidAssignmentType::Swizzle => (
845 None,
846 vec![
847 "WGSL does not support assignments to swizzles".into(),
848 "consider assigning each component individually".into(),
849 ],
850 ),
851 InvalidAssignmentType::ImmutableBinding(binding_span) => (
852 Some((binding_span, "this is an immutable binding".into())),
853 vec![format!(
854 "consider declaring `{}` with `var` instead of `let`",
855 &source[binding_span]
856 )],
857 ),
858 InvalidAssignmentType::Other => (None, vec![]),
859 };
860
861 ParseError {
862 message: "invalid left-hand side of assignment".into(),
863 labels: core::iter::once((span, "cannot assign to this expression".into()))
864 .chain(extra_label)
865 .collect(),
866 notes,
867 }
868 }
869 Error::ReservedKeyword(name_span) => ParseError {
870 message: format!("name `{}` is a reserved keyword", &source[name_span]),
871 labels: vec![(
872 name_span,
873 format!("definition of `{}`", &source[name_span]).into(),
874 )],
875 notes: vec![],
876 },
877 Error::Redefinition { previous, current } => ParseError {
878 message: format!("redefinition of `{}`", &source[current]),
879 labels: vec![
880 (
881 current,
882 format!("redefinition of `{}`", &source[current]).into(),
883 ),
884 (
885 previous,
886 format!("previous definition of `{}`", &source[previous]).into(),
887 ),
888 ],
889 notes: vec![],
890 },
891 Error::RecursiveDeclaration { ident, usage } => ParseError {
892 message: format!("declaration of `{}` is recursive", &source[ident]),
893 labels: vec![(ident, "".into()), (usage, "uses itself here".into())],
894 notes: vec![],
895 },
896 Error::CyclicDeclaration { ident, ref path } => ParseError {
897 message: format!("declaration of `{}` is cyclic", &source[ident]),
898 labels: path
899 .iter()
900 .enumerate()
901 .flat_map(|(i, &(ident, usage))| {
902 [
903 (ident, "".into()),
904 (
905 usage,
906 if i == path.len() - 1 {
907 "ending the cycle".into()
908 } else {
909 format!("uses `{}`", &source[ident]).into()
910 },
911 ),
912 ]
913 })
914 .collect(),
915 notes: vec![],
916 },
917 Error::InvalidSwitchSelector { span } => ParseError {
918 message: "invalid `switch` selector".to_string(),
919 labels: vec![(
920 span,
921 "`switch` selector must be a scalar integer"
922 .into(),
923 )],
924 notes: vec![],
925 },
926 Error::InvalidSwitchCase { span } => ParseError {
927 message: "invalid `switch` case selector value".to_string(),
928 labels: vec![(
929 span,
930 "`switch` case selector must be a scalar integer const expression"
931 .into(),
932 )],
933 notes: vec![],
934 },
935 Error::SwitchCaseTypeMismatch { span } => ParseError {
936 message: "invalid `switch` case selector value".to_string(),
937 labels: vec![(
938 span,
939 "`switch` case selector must have the same type as the `switch` selector expression"
940 .into(),
941 )],
942 notes: vec![],
943 },
944 Error::CalledEntryPoint(span) => ParseError {
945 message: "entry point cannot be called".to_string(),
946 labels: vec![(span, "entry point cannot be called".into())],
947 notes: vec![],
948 },
949 Error::CalledLocalDecl(span) => ParseError {
950 message: "local declaration cannot be called".to_string(),
951 labels: vec![(span, "local declaration cannot be called".into())],
952 notes: vec![],
953 },
954 Error::WrongArgumentCount {
955 span,
956 ref expected,
957 found,
958 } => ParseError {
959 message: format!(
960 "wrong number of arguments: expected {}, found {}",
961 if expected.len() < 2 {
962 format!("{}", expected.start)
963 } else {
964 format!("{}..{}", expected.start, expected.end)
965 },
966 found
967 ),
968 labels: vec![(span, "wrong number of arguments".into())],
969 notes: vec![],
970 },
971 Error::TooManyArguments {
972 ref function,
973 call_span,
974 arg_span,
975 max_arguments,
976 } => ParseError {
977 message: format!("too many arguments passed to `{function}`"),
978 labels: vec![
979 (call_span, "".into()),
980 (arg_span, format!("unexpected argument #{}", max_arguments + 1).into())
981 ],
982 notes: vec![
983 format!("The `{function}` function accepts at most {max_arguments} argument(s)")
984 ],
985 },
986 Error::WrongArgumentType {
987 ref function,
988 call_span,
989 arg_span,
990 arg_index,
991 ref arg_ty,
992 ref allowed,
993 } => {
994 let message = format!(
995 "wrong type passed as argument #{} to `{function}`",
996 arg_index + 1,
997 );
998 let labels = vec![
999 (call_span, "".into()),
1000 (arg_span, format!("argument #{} has type `{arg_ty}`", arg_index + 1).into())
1001 ];
1002
1003 let mut notes = vec![];
1004 notes.push(format!("`{function}` accepts the following types for argument #{}:", arg_index + 1));
1005 notes.extend(allowed.iter().map(|ty| format!("allowed type: {ty}")));
1006
1007 ParseError { message, labels, notes }
1008 },
1009 Error::InconsistentArgumentType {
1010 ref function,
1011 call_span,
1012 arg_span,
1013 arg_index,
1014 ref arg_ty,
1015 inconsistent_span,
1016 inconsistent_index,
1017 ref inconsistent_ty,
1018 ref allowed
1019 } => {
1020 let message = format!(
1021 "inconsistent type passed as argument #{} to `{function}`",
1022 arg_index + 1,
1023 );
1024 let labels = vec![
1025 (call_span, "".into()),
1026 (arg_span, format!("argument #{} has type {arg_ty}", arg_index + 1).into()),
1027 (inconsistent_span, format!(
1028 "this argument has type {inconsistent_ty}, which constrains subsequent arguments"
1029 ).into()),
1030 ];
1031 let mut notes = vec![
1032 format!("Because argument #{} has type {inconsistent_ty}, only the following types", inconsistent_index + 1),
1033 format!("(or types that automatically convert to them) are accepted for argument #{}:", arg_index + 1),
1034 ];
1035 notes.extend(allowed.iter().map(|ty| format!("allowed type: {ty}")));
1036
1037 ParseError { message, labels, notes }
1038 }
1039 Error::FunctionReturnsVoid(span) => ParseError {
1040 message: "function does not return any value".to_string(),
1041 labels: vec![(span, "".into())],
1042 notes: vec![
1043 "perhaps you meant to call the function in a separate statement?".into(),
1044 ],
1045 },
1046 Error::FunctionMustUseUnused(call) => ParseError {
1047 message: "unused return value from function annotated with @must_use".into(),
1048 labels: vec![(call, "".into())],
1049 notes: vec![
1050 format!(
1051 "function '{}' is declared with `@must_use` attribute",
1052 &source[call],
1053 ),
1054 "use a phony assignment or declare a value using the function call as the initializer".into(),
1055 ],
1056 },
1057 Error::FunctionMustUseReturnsVoid(attr, signature) => ParseError {
1058 message: "function annotated with @must_use but does not return any value".into(),
1059 labels: vec![
1060 (attr, "".into()),
1061 (signature, "".into()),
1062 ],
1063 notes: vec![
1064 "declare a return type or remove the attribute".into(),
1065 ],
1066 },
1067 Error::InvalidWorkGroupUniformLoad(span) => ParseError {
1068 message: "incorrect type passed to workgroupUniformLoad".into(),
1069 labels: vec![(span, "".into())],
1070 notes: vec!["passed type must be a workgroup pointer".into()],
1071 },
1072 Error::Internal(message) => ParseError {
1073 message: "internal WGSL front end error".to_string(),
1074 labels: vec![],
1075 notes: vec![message.into()],
1076 },
1077 Error::ExpectedConstExprConcreteIntegerScalar(span) => ParseError {
1078 message: concat!(
1079 "must be a const-expression that ",
1080 "resolves to a concrete integer scalar (`u32` or `i32`)"
1081 )
1082 .to_string(),
1083 labels: vec![(span, "must resolve to `u32` or `i32`".into())],
1084 notes: vec![],
1085 },
1086 Error::ExpectedNonNegative(span) => ParseError {
1087 message: "must be non-negative (>= 0)".to_string(),
1088 labels: vec![(span, "must be non-negative".into())],
1089 notes: vec![],
1090 },
1091 Error::ExpectedPositiveArrayLength(span) => ParseError {
1092 message: "array element count must be positive (> 0)".to_string(),
1093 labels: vec![(span, "must be positive".into())],
1094 notes: vec![],
1095 },
1096 Error::ConstantEvaluatorError(ref e, span) => ParseError {
1097 message: e.to_string(),
1098 labels: vec![(span, "see msg".into())],
1099 notes: vec![],
1100 },
1101 Error::MissingWorkgroupSize(span) => ParseError {
1102 message: "workgroup size is missing on compute shader entry point".to_string(),
1103 labels: vec![(
1104 span,
1105 "must be paired with a `@workgroup_size` attribute".into(),
1106 )],
1107 notes: vec![],
1108 },
1109 Error::AutoConversion(ref error) => {
1110 let AutoConversionError {
1112 dest_span,
1113 ref dest_type,
1114 source_span,
1115 ref source_type,
1116 } = **error;
1117 ParseError {
1118 message: format!(
1119 "automatic conversions cannot convert `{source_type}` to `{dest_type}`"
1120 ),
1121 labels: vec![
1122 (
1123 dest_span,
1124 format!("a value of type {dest_type} is required here").into(),
1125 ),
1126 (
1127 source_span,
1128 format!("this expression has type {source_type}").into(),
1129 ),
1130 ],
1131 notes: vec![],
1132 }
1133 }
1134 Error::AutoConversionLeafScalar(ref error) => {
1135 let AutoConversionLeafScalarError {
1136 dest_span,
1137 ref dest_scalar,
1138 source_span,
1139 ref source_type,
1140 } = **error;
1141 ParseError {
1142 message: format!(
1143 "automatic conversions cannot convert elements of `{source_type}` to `{dest_scalar}`"
1144 ),
1145 labels: vec![
1146 (
1147 dest_span,
1148 format!(
1149 "a value with elements of type {dest_scalar} is required here"
1150 )
1151 .into(),
1152 ),
1153 (
1154 source_span,
1155 format!("this expression has type {source_type}").into(),
1156 ),
1157 ],
1158 notes: vec![],
1159 }
1160 }
1161 Error::ConcretizationFailed(ref error) => {
1162 let ConcretizationFailedError {
1163 expr_span,
1164 ref expr_type,
1165 ref concretization_preferences,
1166 } = **error;
1167 ParseError {
1168 message: "failed to convert expression to a concrete type".to_string(),
1169 labels: vec![(
1170 expr_span,
1171 format!("this expression has type {expr_type}").into(),
1172 )],
1173 notes: concretization_preferences
1174 .iter()
1175 .map(|&(ref scalar, ref err)|
1176 format!("the expression couldn't be converted to have {scalar} scalar type: {err}")
1177 )
1178 .collect(),
1179 }
1180 }
1181 Error::ExceededLimitForNestedBraces { span, limit } => ParseError {
1182 message: "brace nesting limit reached".into(),
1183 labels: vec![(span, "limit reached at this brace".into())],
1184 notes: vec![format!("nesting limit is currently set to {limit}")],
1185 },
1186 Error::PipelineConstantIDValue(span) => ParseError {
1187 message: "pipeline constant ID must be between 0 and 65535 inclusive".to_string(),
1188 labels: vec![(span, "must be between 0 and 65535 inclusive".into())],
1189 notes: vec![],
1190 },
1191 Error::NotBool(span) => ParseError {
1192 message: "must be a const-expression that resolves to a `bool`".to_string(),
1193 labels: vec![(span, "must resolve to `bool`".into())],
1194 notes: vec![],
1195 },
1196 Error::ConstAssertFailed(span) => ParseError {
1197 message: "`const_assert` failure".to_string(),
1198 labels: vec![(span, "evaluates to `false`".into())],
1199 notes: vec![],
1200 },
1201 Error::DirectiveAfterFirstGlobalDecl { directive_span } => ParseError {
1202 message: "expected global declaration, but found a global directive".into(),
1203 labels: vec![(
1204 directive_span,
1205 "written after first global declaration".into(),
1206 )],
1207 notes: vec![concat!(
1208 "global directives are only allowed before global declarations; ",
1209 "maybe hoist this closer to the top of the shader module?"
1210 )
1211 .into()],
1212 },
1213 Error::EnableExtensionNotYetImplemented { kind, span } => ParseError {
1214 message: format!(
1215 "the `{}` enable-extension is not yet supported",
1216 EnableExtension::Unimplemented(kind).to_ident()
1217 ),
1218 labels: vec![(
1219 span,
1220 concat!(
1221 "this enable-extension specifies standard functionality ",
1222 "which is not yet implemented in Naga"
1223 )
1224 .into(),
1225 )],
1226 notes: vec![format!(
1227 concat!(
1228 "Let Naga maintainers know that you ran into this at ",
1229 "<https://github.com/gfx-rs/wgpu/issues/{}>, ",
1230 "so they can prioritize it!"
1231 ),
1232 kind.tracking_issue_num()
1233 )],
1234 },
1235 Error::EnableExtensionNotEnabled { kind, span } => ParseError {
1236 message: format!("the `{}` enable extension is not enabled", kind.to_ident()),
1237 labels: vec![(
1238 span,
1239 format!(
1240 concat!(
1241 "the `{}` \"Enable Extension\" is needed for this functionality, ",
1242 "but it is not currently enabled."
1243 ),
1244 kind.to_ident()
1245 )
1246 .into(),
1247 )],
1248 notes: if let EnableExtension::Unimplemented(kind) = kind {
1249 vec![format!(
1250 concat!(
1251 "This \"Enable Extension\" is not yet implemented. ",
1252 "Let Naga maintainers know that you ran into this at ",
1253 "<https://github.com/gfx-rs/wgpu/issues/{}>, ",
1254 "so they can prioritize it!"
1255 ),
1256 kind.tracking_issue_num()
1257 )]
1258 } else {
1259 vec![
1260 format!(
1261 "You can enable this extension by adding `enable {};` at the top of the shader, before any other items.",
1262 kind.to_ident()
1263 ),
1264 ]
1265 },
1266 },
1267 Error::EnableExtensionNotSupported { kind, span } => ParseError {
1268 message: format!(
1269 "the `{}` extension is not supported in the current environment",
1270 kind.to_ident()
1271 ),
1272 labels: vec![(
1273 span,
1274 "unsupported enable-extension".into(),
1275 )],
1276 notes: vec![],
1277 },
1278 Error::LanguageExtensionNotYetImplemented { kind, span } => ParseError {
1279 message: format!(
1280 "the `{}` language extension is not yet supported",
1281 LanguageExtension::Unimplemented(kind).to_ident()
1282 ),
1283 labels: vec![(span, "".into())],
1284 notes: vec![format!(
1285 concat!(
1286 "Let Naga maintainers know that you ran into this at ",
1287 "<https://github.com/gfx-rs/wgpu/issues/{}>, ",
1288 "so they can prioritize it!"
1289 ),
1290 kind.tracking_issue_num()
1291 )],
1292 },
1293 Error::DiagnosticInvalidSeverity {
1294 severity_control_name_span,
1295 } => ParseError {
1296 message: "invalid `diagnostic(…)` severity".into(),
1297 labels: vec![(
1298 severity_control_name_span,
1299 "not a valid severity level".into(),
1300 )],
1301 notes: vec![concat!(
1302 "See available severities at ",
1303 "<https://www.w3.org/TR/WGSL/#diagnostic-severity>."
1304 )
1305 .into()],
1306 },
1307 Error::DiagnosticDuplicateTriggeringRule(ConflictingDiagnosticRuleError {
1308 triggering_rule_spans,
1309 }) => {
1310 let [first_span, second_span] = triggering_rule_spans;
1311 ParseError {
1312 message: "found conflicting `diagnostic(…)` rule(s)".into(),
1313 labels: vec![
1314 (first_span, "first rule".into()),
1315 (second_span, "second rule".into()),
1316 ],
1317 notes: vec![
1318 concat!(
1319 "Multiple `diagnostic(…)` rules with the same rule name ",
1320 "conflict unless they are directives and the severity is the same.",
1321 )
1322 .into(),
1323 "You should delete the rule you don't want.".into(),
1324 ],
1325 }
1326 }
1327 Error::DiagnosticAttributeNotYetImplementedAtParseSite {
1328 site_name_plural,
1329 ref spans,
1330 } => ParseError {
1331 message: "`@diagnostic(…)` attribute(s) not yet implemented".into(),
1332 labels: {
1333 let mut spans = spans.iter().cloned();
1334 let first = spans
1335 .next()
1336 .map(|span| {
1337 (
1338 span,
1339 format!("can't use this on {site_name_plural} (yet)").into(),
1340 )
1341 })
1342 .expect("internal error: diag. attr. rejection on empty map");
1343 core::iter::once(first)
1344 .chain(spans.map(|span| (span, "".into())))
1345 .collect()
1346 },
1347 notes: vec![format!(concat!(
1348 "Let Naga maintainers know that you ran into this at ",
1349 "<https://github.com/gfx-rs/wgpu/issues/5320>, ",
1350 "so they can prioritize it!"
1351 ))],
1352 },
1353 Error::DiagnosticAttributeNotSupported { on_what, ref spans } => {
1354 let intended_diagnostic_directive = match on_what {
1357 DiagnosticAttributeNotSupportedPosition::SemicolonInModulePosition => true,
1358 DiagnosticAttributeNotSupportedPosition::Other { .. } => false,
1359 };
1360 let on_what_plural = match on_what {
1361 DiagnosticAttributeNotSupportedPosition::SemicolonInModulePosition => {
1362 "semicolons"
1363 }
1364 DiagnosticAttributeNotSupportedPosition::Other { display_plural } => {
1365 display_plural
1366 }
1367 };
1368 ParseError {
1369 message: format!(
1370 "`@diagnostic(…)` attribute(s) on {on_what_plural} are not supported",
1371 ),
1372 labels: spans
1373 .iter()
1374 .cloned()
1375 .map(|span| (span, "".into()))
1376 .collect(),
1377 notes: vec![
1378 concat!(
1379 "`@diagnostic(…)` attributes are only permitted on `fn`s, ",
1380 "some statements, and `switch`/`loop` bodies."
1381 )
1382 .into(),
1383 {
1384 if intended_diagnostic_directive {
1385 concat!(
1386 "If you meant to declare a diagnostic filter that ",
1387 "applies to the entire module, move this line to ",
1388 "the top of the file and remove the `@` symbol."
1389 )
1390 .into()
1391 } else {
1392 concat!(
1393 "These attributes are well-formed, ",
1394 "you likely just need to move them."
1395 )
1396 .into()
1397 }
1398 },
1399 ],
1400 }
1401 }
1402 Error::SelectUnexpectedArgumentType { arg_span, ref arg_type } => ParseError {
1403 message: "unexpected argument type for `select` call".into(),
1404 labels: vec![(arg_span, format!("this value of type {arg_type}").into())],
1405 notes: vec!["expected a scalar or a `vecN` of scalars".into()],
1406 },
1407 Error::SelectRejectAndAcceptHaveNoCommonType {
1408 reject_span,
1409 ref reject_type,
1410 accept_span,
1411 ref accept_type,
1412 } => ParseError {
1413 message: "type mismatch for reject and accept values in `select` call".into(),
1414 labels: vec![
1415 (reject_span, format!("reject value of type {reject_type}").into()),
1416 (accept_span, format!("accept value of type {accept_type}").into()),
1417 ],
1418 notes: vec![],
1419 },
1420 Error::ExpectedGlobalVariable { name_span } => ParseError {
1421 message: "expected global variable".to_string(),
1422 labels: vec![(name_span, "variable used here".into())],
1423 notes: vec![],
1424 },
1425 Error::StructMemberTooLarge { member_name_span } => ParseError {
1426 message: "struct member is too large".into(),
1427 labels: vec![(member_name_span, "this member exceeds the maximum size".into())],
1428 notes: vec![format!(
1429 "the maximum size is {} bytes",
1430 crate::valid::MAX_TYPE_SIZE
1431 )],
1432 },
1433 Error::TypeTooLarge { span } => ParseError {
1434 message: "type is too large".into(),
1435 labels: vec![(span, "this type exceeds the maximum size".into())],
1436 notes: vec![format!(
1437 "the maximum size is {} bytes",
1438 crate::valid::MAX_TYPE_SIZE
1439 )],
1440 },
1441 Error::UnderspecifiedCooperativeMatrix => ParseError {
1442 message: "cooperative matrix constructor is underspecified".into(),
1443 labels: vec![],
1444 notes: vec![format!("must be F32")],
1445 },
1446 Error::InvalidCooperativeLoadType(span) => ParseError {
1447 message: "cooperative load should have a generic type for coop_mat".into(),
1448 labels: vec![(span, "type needs the coop_mat<...>".into())],
1449 notes: vec![format!("must be a valid cooperative type")],
1450 },
1451 Error::UnsupportedCooperativeScalar(span) => ParseError {
1452 message: "cooperative scalar type is not supported".into(),
1453 labels: vec![(span, "type needs the scalar type specified".into())],
1454 notes: vec![format!("must be F32")],
1455 },
1456 Error::UnexpectedIdentForEnumerant(ident_span) => ParseError {
1457 message: format!(
1458 "identifier `{}` resolves to a declaration",
1459 &source[ident_span]
1460 ),
1461 labels: vec![(ident_span, "needs to resolve to a predeclared enumerant".into())],
1462 notes: vec![],
1463 },
1464 Error::UnexpectedExprForEnumerant(expr_span) => ParseError {
1465 message: "unexpected expression".to_string(),
1466 labels: vec![(expr_span, "needs to be an identifier resolving to a predeclared enumerant".into())],
1467 notes: vec![],
1468 },
1469 Error::UnusedArgsForTemplate(ref expr_spans) => ParseError {
1470 message: "unused expressions for template".to_string(),
1471 labels: expr_spans.iter().cloned().map(|span| -> (_, _){ (span, "unused".into()) }).collect(),
1472 notes: vec![],
1473 },
1474 Error::UnexpectedTemplate(span) => ParseError {
1475 message: "unexpected template".to_string(),
1476 labels: vec![(span, "expected identifier".into())],
1477 notes: vec![],
1478 },
1479 Error::MissingTemplateArg {
1480 span,
1481 description: arg,
1482 } => ParseError {
1483 message: format!(
1484 "`{}` needs a template argument specified: {arg}",
1485 &source[span]
1486 ),
1487 labels: vec![(span, "is missing a template argument".into())],
1488 notes: vec![],
1489 },
1490 Error::UnexpectedExprForTypeExpression(expr_span) => ParseError {
1491 message: "unexpected expression".to_string(),
1492 labels: vec![(expr_span, "needs to be an identifier resolving to a type declaration (alias or struct) or predeclared type(-generator)".into())],
1493 notes: vec![],
1494 },
1495 Error::MissingIncomingPayload(span) => ParseError {
1496 message: "incoming payload is missing on a `closest_hit`, `any_hit` or `miss` shader entry point".to_string(),
1497 labels: vec![(
1498 span,
1499 "must be paired with a `@incoming_payload` attribute".into(),
1500 )],
1501 notes: vec![],
1502 },
1503 }
1504 }
1505}