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