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