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 pub(crate) fn as_parse_error(&self, source: &'a str) -> ParseError {
529 match *self {
530 Error::Unexpected(unexpected_span, expected) => {
531 let expected_str = match expected {
532 ExpectedToken::Token(token) => match token {
533 Token::Separator(c) => format!("`{c}`"),
534 Token::Paren(c) => format!("`{c}`"),
535 Token::Attribute => "@".to_string(),
536 Token::Number(_) => "number".to_string(),
537 Token::Word(s) => s.to_string(),
538 Token::Operation(c) => format!("operation (`{c}`)"),
539 Token::LogicalOperation(c) => format!("logical operation (`{c}`)"),
540 Token::ShiftOperation(c) => format!("bitshift (`{c}{c}`)"),
541 Token::AssignmentOperation(c) if c == '<' || c == '>' => {
542 format!("bitshift (`{c}{c}=`)")
543 }
544 Token::AssignmentOperation(c) => format!("operation (`{c}=`)"),
545 Token::IncrementOperation => "increment operation".to_string(),
546 Token::DecrementOperation => "decrement operation".to_string(),
547 Token::Arrow => "->".to_string(),
548 Token::TemplateArgsStart => "template args start".to_string(),
549 Token::TemplateArgsEnd => "template args end".to_string(),
550 Token::Unknown(c) => format!("unknown (`{c}`)"),
551 Token::Trivia => "trivia".to_string(),
552 Token::DocComment(s) => format!("doc comment ('{s}')"),
553 Token::ModuleDocComment(s) => format!("module doc comment ('{s}')"),
554 Token::End => "end".to_string(),
555 Token::UnterminatedBlockComment(s) => format!("unterminated doc comment ('{s}'")
556 },
557 ExpectedToken::Identifier => "identifier".to_string(),
558 ExpectedToken::LhsExpression => "LHS expression (identifier component_or_swizzle_specifier?, (`lhs_expression`) component_or_swizzle_specifier?, &`lhs_expression`, *`lhs_expression`)".to_string(),
559 ExpectedToken::PrimaryExpression => "expression".to_string(),
560 ExpectedToken::Assignment => "assignment or increment/decrement".to_string(),
561 ExpectedToken::SwitchItem => concat!(
562 "switch item (`case` or `default`) or a closing curly bracket ",
563 "to signify the end of the switch statement (`}`)"
564 )
565 .to_string(),
566 ExpectedToken::WorkgroupSizeSeparator => {
567 "workgroup size separator (`,`) or a closing parenthesis".to_string()
568 }
569 ExpectedToken::GlobalItem => concat!(
570 "global item (`struct`, `const`, `var`, `alias`, ",
571 "`fn`, `diagnostic`, `enable`, `requires`, `;`) ",
572 "or the end of the file"
573 )
574 .to_string(),
575 ExpectedToken::Variable => "variable access".to_string(),
576 ExpectedToken::Function => "function name".to_string(),
577 ExpectedToken::AfterIdentListArg => {
578 "next argument, trailing comma, or end of list (`,` or `;`)".to_string()
579 }
580 ExpectedToken::AfterIdentListComma => {
581 "next argument or end of list (`;`)".to_string()
582 }
583 ExpectedToken::DiagnosticAttribute => {
584 "the `diagnostic` attribute identifier".to_string()
585 }
586 ExpectedToken::Statement => "statement".to_string(),
587 ExpectedToken::ForInit => "for loop initializer statement (`var`/`let`/`const` declaration, assignment, `i++`/`i--` statement, function call)".to_string(),
588 ExpectedToken::ForUpdate => "for loop update statement (assignment, `i++`/`i--` statement, function call)".to_string(),
589 };
590 ParseError {
591 message: format!(
592 "expected {}, found {:?}",
593 expected_str, &source[unexpected_span],
594 ),
595 labels: vec![(unexpected_span, format!("expected {expected_str}").into())],
596 notes: vec![],
597 }
598 }
599 Error::UnexpectedComponents(bad_span) => ParseError {
600 message: "unexpected components".to_string(),
601 labels: vec![(bad_span, "unexpected components".into())],
602 notes: vec![],
603 },
604 Error::UnexpectedOperationInConstContext(span) => ParseError {
605 message: "this operation is not supported in a const context".to_string(),
606 labels: vec![(span, "operation not supported here".into())],
607 notes: vec![],
608 },
609 Error::BadNumber(bad_span, ref err) => ParseError {
610 message: format!("{}: `{}`", err, &source[bad_span],),
611 labels: vec![(bad_span, err.to_string().into())],
612 notes: vec![],
613 },
614 Error::BadMatrixScalarKind(span, scalar) => ParseError {
615 message: format!(
616 "matrix scalar type must be floating-point, but found `{}`",
617 scalar.to_wgsl_for_diagnostics()
618 ),
619 labels: vec![(span, "must be floating-point (e.g. `f32`)".into())],
620 notes: vec![],
621 },
622 Error::BadAccessor(accessor_span) => ParseError {
623 message: format!("invalid field accessor `{}`", &source[accessor_span],),
624 labels: vec![(accessor_span, "invalid accessor".into())],
625 notes: vec![],
626 },
627 Error::UnknownIdent(ident_span, ident) => ParseError {
628 message: format!("no definition in scope for identifier: `{ident}`"),
629 labels: vec![(ident_span, "unknown identifier".into())],
630 notes: vec![],
631 },
632 Error::UnknownScalarType(bad_span) => ParseError {
633 message: format!("unknown scalar type: `{}`", &source[bad_span]),
634 labels: vec![(bad_span, "unknown scalar type".into())],
635 notes: vec!["Valid scalar types are f32, f64, i32, u32, bool".into()],
636 },
637 Error::NotStorageTexture(bad_span) => ParseError {
638 message: "textureStore can only be applied to storage textures".to_string(),
639 labels: vec![(bad_span, "not a storage texture".into())],
640 notes: vec![],
641 },
642 Error::BadTextureSampleType { span, scalar } => ParseError {
643 message: format!(
644 "texture sample type must be one of f32, i32 or u32, but found {}",
645 scalar.to_wgsl_for_diagnostics()
646 ),
647 labels: vec![(span, "must be one of f32, i32 or u32".into())],
648 notes: vec![],
649 },
650 Error::BadIncrDecrReferenceType(span) => ParseError {
651 message: concat!(
652 "increment/decrement operation requires ",
653 "reference type to be one of i32 or u32"
654 )
655 .to_string(),
656 labels: vec![(span, "must be a reference type of i32 or u32".into())],
657 notes: vec![],
658 },
659 Error::BadTexture(bad_span) => ParseError {
660 message: format!(
661 "expected an image, but found `{}` which is not an image",
662 &source[bad_span]
663 ),
664 labels: vec![(bad_span, "not an image".into())],
665 notes: vec![],
666 },
667 Error::BadTypeCast {
668 span,
669 ref from_type,
670 ref to_type,
671 } => {
672 let msg = format!("cannot cast a {from_type} to a {to_type}");
673 ParseError {
674 message: msg.clone(),
675 labels: vec![(span, msg.into())],
676 notes: vec![],
677 }
678 }
679 Error::InvalidResolve(ref resolve_error) => ParseError {
680 message: resolve_error.to_string(),
681 labels: vec![],
682 notes: vec![],
683 },
684 Error::InvalidBreakIf(bad_span) => ParseError {
685 message: "A break if is only allowed in a continuing block".to_string(),
686 labels: vec![(bad_span, "not in a continuing block".into())],
687 notes: vec![],
688 },
689 Error::InvalidGatherComponent(bad_span) => ParseError {
690 message: format!(
691 "textureGather component `{}` doesn't exist, must be 0, 1, 2, or 3",
692 &source[bad_span]
693 ),
694 labels: vec![(bad_span, "invalid component".into())],
695 notes: vec![],
696 },
697 Error::InvalidConstructorComponentType(bad_span, component) => ParseError {
698 message: format!("invalid type for constructor component at index [{component}]"),
699 labels: vec![(bad_span, "invalid component type".into())],
700 notes: vec![],
701 },
702 Error::InvalidIdentifierUnderscore(bad_span) => ParseError {
703 message: "Identifier can't be `_`".to_string(),
704 labels: vec![(bad_span, "invalid identifier".into())],
705 notes: vec![
706 "Use phony assignment instead (`_ =` notice the absence of `let` or `var`)"
707 .to_string(),
708 ],
709 },
710 Error::ReservedIdentifierPrefix(bad_span) => ParseError {
711 message: format!(
712 "Identifier starts with a reserved prefix: `{}`",
713 &source[bad_span]
714 ),
715 labels: vec![(bad_span, "invalid identifier".into())],
716 notes: vec![],
717 },
718 Error::UnknownAddressSpace(bad_span) => ParseError {
719 message: format!("unknown address space: `{}`", &source[bad_span]),
720 labels: vec![(bad_span, "unknown address space".into())],
721 notes: vec![],
722 },
723 Error::InvalidLocalVariableAddressSpace(bad_span) => ParseError {
724 message: format!("invalid address space for local variable: `{}`", &source[bad_span]),
725 labels: vec![(bad_span, "local variables can only use 'function' address space".into())],
726 notes: vec![],
727 },
728 Error::UnknownRayFlag(bad_span) => ParseError {
729 message: format!("unknown ray flag: `{}`", &source[bad_span]),
730 labels: vec![(bad_span, "unknown ray flag".into())],
731 notes: vec![],
732 },
733 Error::RepeatedAttribute(bad_span) => ParseError {
734 message: format!("repeated attribute: `{}`", &source[bad_span]),
735 labels: vec![(bad_span, "repeated attribute".into())],
736 notes: vec![],
737 },
738 Error::UnknownAttribute(bad_span) => ParseError {
739 message: format!("unknown attribute: `{}`", &source[bad_span]),
740 labels: vec![(bad_span, "unknown attribute".into())],
741 notes: vec![],
742 },
743 Error::UnknownBuiltin(bad_span) => ParseError {
744 message: format!("unknown builtin: `{}`", &source[bad_span]),
745 labels: vec![(bad_span, "unknown builtin".into())],
746 notes: vec![],
747 },
748 Error::UnknownAccess(bad_span) => ParseError {
749 message: format!("unknown access: `{}`", &source[bad_span]),
750 labels: vec![(bad_span, "unknown access".into())],
751 notes: vec![],
752 },
753 Error::UnknownStorageFormat(bad_span) => ParseError {
754 message: format!("unknown storage format: `{}`", &source[bad_span]),
755 labels: vec![(bad_span, "unknown storage format".into())],
756 notes: vec![],
757 },
758 Error::UnknownConservativeDepth(bad_span) => ParseError {
759 message: format!("unknown conservative depth: `{}`", &source[bad_span]),
760 labels: vec![(bad_span, "unknown conservative depth".into())],
761 notes: vec![],
762 },
763 Error::UnknownEnableExtension(span, word) => ParseError {
764 message: format!("unknown enable-extension `{word}`"),
765 labels: vec![(span, "".into())],
766 notes: vec![
767 "See available extensions at <https://www.w3.org/TR/WGSL/#enable-extension>."
768 .into(),
769 ],
770 },
771 Error::UnknownLanguageExtension(span, name) => ParseError {
772 message: format!("unknown language extension `{name}`"),
773 labels: vec![(span, "".into())],
774 notes: vec![concat!(
775 "See available extensions at ",
776 "<https://www.w3.org/TR/WGSL/#language-extensions-sec>."
777 )
778 .into()],
779 },
780 Error::UnknownDiagnosticRuleName(span) => ParseError {
781 message: format!("unknown `diagnostic(…)` rule name `{}`", &source[span]),
782 labels: vec![(span, "not a valid diagnostic rule name".into())],
783 notes: vec![concat!(
784 "See available trigger rules at ",
785 "<https://www.w3.org/TR/WGSL/#filterable-triggering-rules>."
786 )
787 .into()],
788 },
789 Error::SizeAttributeTooLow(bad_span, min_size) => ParseError {
790 message: format!("struct member size must be at least {min_size}"),
791 labels: vec![(bad_span, format!("must be at least {min_size}").into())],
792 notes: vec![],
793 },
794 Error::SizeAttributeRequiresFixedFootprint(bad_span) => ParseError {
795 message: "@size attribute requires a type with creation-fixed footprint".to_string(),
796 labels: vec![(bad_span, "type does not have creation-fixed footprint".into())],
797 notes: vec![],
798 },
799 Error::AlignAttributeTooLow(bad_span, min_align) => ParseError {
800 message: format!("struct member alignment must be at least {min_align}"),
801 labels: vec![(bad_span, format!("must be at least {min_align}").into())],
802 notes: vec![],
803 },
804 Error::NonPowerOfTwoAlignAttribute(bad_span) => ParseError {
805 message: "struct member alignment must be a power of 2".to_string(),
806 labels: vec![(bad_span, "must be a power of 2".into())],
807 notes: vec![],
808 },
809 Error::InconsistentBinding(span) => ParseError {
810 message: "input/output binding is not consistent".to_string(),
811 labels: vec![(span, "input/output binding is not consistent".into())],
812 notes: vec![],
813 },
814 Error::TypeNotConstructible(span) => ParseError {
815 message: format!("type `{}` is not constructible", &source[span]),
816 labels: vec![(span, "type is not constructible".into())],
817 notes: vec![],
818 },
819 Error::TypeNotInferable(span) => ParseError {
820 message: "type can't be inferred".to_string(),
821 labels: vec![(span, "type can't be inferred".into())],
822 notes: vec![],
823 },
824 Error::InitializationTypeMismatch {
825 name,
826 ref expected,
827 ref got,
828 } => ParseError {
829 message: format!(
830 "the type of `{}` is expected to be `{}`, but got `{}`",
831 &source[name], expected, got,
832 ),
833 labels: vec![(name, format!("definition of `{}`", &source[name]).into())],
834 notes: vec![],
835 },
836 Error::DeclMissingTypeAndInit(name_span) => ParseError {
837 message: format!(
838 "declaration of `{}` needs a type specifier or initializer",
839 &source[name_span]
840 ),
841 labels: vec![(name_span, "needs a type specifier or initializer".into())],
842 notes: vec![],
843 },
844 Error::MissingAttribute(name, name_span) => ParseError {
845 message: format!(
846 "variable `{}` needs a '{}' attribute",
847 &source[name_span], name
848 ),
849 labels: vec![(
850 name_span,
851 format!("definition of `{}`", &source[name_span]).into(),
852 )],
853 notes: vec![],
854 },
855 Error::InvalidAddrOfOperand(span) => ParseError {
856 message: "cannot take the address of a vector component".to_string(),
857 labels: vec![(span, "invalid operand for address-of".into())],
858 notes: vec![],
859 },
860 Error::InvalidAtomicPointer(span) => ParseError {
861 message: "atomic operation is done on a pointer to a non-atomic".to_string(),
862 labels: vec![(span, "atomic pointer is invalid".into())],
863 notes: vec![],
864 },
865 Error::InvalidAtomicOperandType(span) => ParseError {
866 message: "atomic operand type is inconsistent with the operation".to_string(),
867 labels: vec![(span, "atomic operand type is invalid".into())],
868 notes: vec![],
869 },
870 Error::InvalidAtomicAccess(span) => ParseError {
871 message: "atomic variables cannot be accessed directly; use atomic built-in functions".to_string(),
872 labels: vec![(span, "direct access to atomic variable is not allowed".into())],
873 notes: vec![],
874 },
875 Error::InvalidRayQueryPointer(span) => ParseError {
876 message: "ray query operation is done on a pointer to a non-ray-query".to_string(),
877 labels: vec![(span, "ray query pointer is invalid".into())],
878 notes: vec![],
879 },
880 Error::NotPointer(span) => ParseError {
881 message: "the operand of the `*` operator must be a pointer".to_string(),
882 labels: vec![(span, "expression is not a pointer".into())],
883 notes: vec![],
884 },
885 Error::NotReference(what, span) => ParseError {
886 message: format!("{what} must be a reference"),
887 labels: vec![(span, "expression is not a reference".into())],
888 notes: vec![],
889 },
890 Error::InvalidAssignment { span, ty } => {
891 let (extra_label, notes) = match ty {
892 InvalidAssignmentType::Swizzle => (
893 None,
894 vec![
895 "WGSL does not support assignments to swizzles".into(),
896 "consider assigning each component individually".into(),
897 ],
898 ),
899 InvalidAssignmentType::ImmutableBinding(binding_span) => (
900 Some((binding_span, "this is an immutable binding".into())),
901 vec![format!(
902 "consider declaring `{}` with `var` instead of `let`",
903 &source[binding_span]
904 )],
905 ),
906 InvalidAssignmentType::Other => (None, vec![]),
907 };
908
909 ParseError {
910 message: "invalid left-hand side of assignment".into(),
911 labels: core::iter::once((span, "cannot assign to this expression".into()))
912 .chain(extra_label)
913 .collect(),
914 notes,
915 }
916 }
917 Error::ReservedKeyword(name_span) => ParseError {
918 message: format!("name `{}` is a reserved keyword", &source[name_span]),
919 labels: vec![(
920 name_span,
921 format!("definition of `{}`", &source[name_span]).into(),
922 )],
923 notes: vec![],
924 },
925 Error::Redefinition { previous, current } => ParseError {
926 message: format!("redefinition of `{}`", &source[current]),
927 labels: vec![
928 (
929 current,
930 format!("redefinition of `{}`", &source[current]).into(),
931 ),
932 (
933 previous,
934 format!("previous definition of `{}`", &source[previous]).into(),
935 ),
936 ],
937 notes: vec![],
938 },
939 Error::RecursiveDeclaration { ident, usage } => ParseError {
940 message: format!("declaration of `{}` is recursive", &source[ident]),
941 labels: vec![(ident, "".into()), (usage, "uses itself here".into())],
942 notes: vec![],
943 },
944 Error::CyclicDeclaration { ident, ref path } => ParseError {
945 message: format!("declaration of `{}` is cyclic", &source[ident]),
946 labels: path
947 .iter()
948 .enumerate()
949 .flat_map(|(i, &(ident, usage))| {
950 [
951 (ident, "".into()),
952 (
953 usage,
954 if i == path.len() - 1 {
955 "ending the cycle".into()
956 } else {
957 format!("uses `{}`", &source[ident]).into()
958 },
959 ),
960 ]
961 })
962 .collect(),
963 notes: vec![],
964 },
965 Error::InvalidSwitchSelector { span } => ParseError {
966 message: "invalid `switch` selector".to_string(),
967 labels: vec![(
968 span,
969 "`switch` selector must be a scalar integer"
970 .into(),
971 )],
972 notes: vec![],
973 },
974 Error::InvalidSwitchCase { span } => ParseError {
975 message: "invalid `switch` case selector value".to_string(),
976 labels: vec![(
977 span,
978 "`switch` case selector must be a scalar integer const expression"
979 .into(),
980 )],
981 notes: vec![],
982 },
983 Error::SwitchCaseTypeMismatch { span } => ParseError {
984 message: "invalid `switch` case selector value".to_string(),
985 labels: vec![(
986 span,
987 "`switch` case selector must have the same type as the `switch` selector expression"
988 .into(),
989 )],
990 notes: vec![],
991 },
992 Error::CalledEntryPoint(span) => ParseError {
993 message: "entry point cannot be called".to_string(),
994 labels: vec![(span, "entry point cannot be called".into())],
995 notes: vec![],
996 },
997 Error::CalledLocalDecl(span) => ParseError {
998 message: "local declaration cannot be called".to_string(),
999 labels: vec![(span, "local declaration cannot be called".into())],
1000 notes: vec![],
1001 },
1002 Error::WrongArgumentCount {
1003 span,
1004 ref expected,
1005 found,
1006 } => ParseError {
1007 message: format!(
1008 "wrong number of arguments: expected {}, found {}",
1009 if expected.len() < 2 {
1010 format!("{}", expected.start)
1011 } else {
1012 format!("{}..{}", expected.start, expected.end)
1013 },
1014 found
1015 ),
1016 labels: vec![(span, "wrong number of arguments".into())],
1017 notes: vec![],
1018 },
1019 Error::TooManyArguments {
1020 ref function,
1021 call_span,
1022 arg_span,
1023 max_arguments,
1024 } => ParseError {
1025 message: format!("too many arguments passed to `{function}`"),
1026 labels: vec![
1027 (call_span, "".into()),
1028 (arg_span, format!("unexpected argument #{}", max_arguments + 1).into())
1029 ],
1030 notes: vec![
1031 format!("The `{function}` function accepts at most {max_arguments} argument(s)")
1032 ],
1033 },
1034 Error::WrongArgumentType {
1035 ref function,
1036 call_span,
1037 arg_span,
1038 arg_index,
1039 ref arg_ty,
1040 ref allowed,
1041 } => {
1042 let message = format!(
1043 "wrong type passed as argument #{} to `{function}`",
1044 arg_index + 1,
1045 );
1046 let labels = vec![
1047 (call_span, "".into()),
1048 (arg_span, format!("argument #{} has type `{arg_ty}`", arg_index + 1).into())
1049 ];
1050
1051 let mut notes = vec![];
1052 notes.push(format!("`{function}` accepts the following types for argument #{}:", arg_index + 1));
1053 notes.extend(allowed.iter().map(|ty| format!("allowed type: {ty}")));
1054
1055 ParseError { message, labels, notes }
1056 },
1057 Error::InconsistentArgumentType {
1058 ref function,
1059 call_span,
1060 arg_span,
1061 arg_index,
1062 ref arg_ty,
1063 inconsistent_span,
1064 inconsistent_index,
1065 ref inconsistent_ty,
1066 ref allowed
1067 } => {
1068 let message = format!(
1069 "inconsistent type passed as argument #{} to `{function}`",
1070 arg_index + 1,
1071 );
1072 let labels = vec![
1073 (call_span, "".into()),
1074 (arg_span, format!("argument #{} has type {arg_ty}", arg_index + 1).into()),
1075 (inconsistent_span, format!(
1076 "this argument has type {inconsistent_ty}, which constrains subsequent arguments"
1077 ).into()),
1078 ];
1079 let mut notes = vec![
1080 format!("Because argument #{} has type {inconsistent_ty}, only the following types", inconsistent_index + 1),
1081 format!("(or types that automatically convert to them) are accepted for argument #{}:", arg_index + 1),
1082 ];
1083 notes.extend(allowed.iter().map(|ty| format!("allowed type: {ty}")));
1084
1085 ParseError { message, labels, notes }
1086 }
1087 Error::FunctionReturnsVoid(span) => ParseError {
1088 message: "function does not return any value".to_string(),
1089 labels: vec![(span, "".into())],
1090 notes: vec![
1091 "perhaps you meant to call the function in a separate statement?".into(),
1092 ],
1093 },
1094 Error::FunctionMustUseUnused(call) => ParseError {
1095 message: "unused return value from function annotated with @must_use".into(),
1096 labels: vec![(call, "".into())],
1097 notes: vec![
1098 format!(
1099 "function '{}' is declared with `@must_use` attribute",
1100 &source[call],
1101 ),
1102 "use a phony assignment or declare a value using the function call as the initializer".into(),
1103 ],
1104 },
1105 Error::FunctionMustUseReturnsVoid(attr, signature) => ParseError {
1106 message: "function annotated with @must_use but does not return any value".into(),
1107 labels: vec![
1108 (attr, "".into()),
1109 (signature, "".into()),
1110 ],
1111 notes: vec![
1112 "declare a return type or remove the attribute".into(),
1113 ],
1114 },
1115 Error::FunctionMustUseOnNonFunction(attr) => ParseError {
1116 message: "attribute `@must_use` is only valid on function declarations".into(),
1117 labels: vec![(attr, "".into())],
1118 notes: vec![
1119 "place `@must_use` on a function declaration with a return type".into(),
1120 ],
1121 },
1122 Error::InvalidWorkGroupUniformLoad(span) => ParseError {
1123 message: "incorrect type passed to workgroupUniformLoad".into(),
1124 labels: vec![(span, "".into())],
1125 notes: vec!["passed type must be a workgroup pointer".into()],
1126 },
1127 Error::Internal(message) => ParseError {
1128 message: "internal WGSL front end error".to_string(),
1129 labels: vec![],
1130 notes: vec![message.into()],
1131 },
1132 Error::ExpectedConstExprConcreteIntegerScalar(span) => ParseError {
1133 message: concat!(
1134 "must be a const-expression that ",
1135 "resolves to a concrete integer scalar (`u32` or `i32`)"
1136 )
1137 .to_string(),
1138 labels: vec![(span, "must resolve to `u32` or `i32`".into())],
1139 notes: vec![],
1140 },
1141 Error::ExpectedNonNegative(span) => ParseError {
1142 message: "must be non-negative (>= 0)".to_string(),
1143 labels: vec![(span, "must be non-negative".into())],
1144 notes: vec![],
1145 },
1146 Error::ExpectedPositiveArrayLength(span) => ParseError {
1147 message: "array element count must be positive (> 0)".to_string(),
1148 labels: vec![(span, "must be positive".into())],
1149 notes: vec![],
1150 },
1151 Error::ConstantEvaluatorError(ref e, span) => ParseError {
1152 message: e.to_string(),
1153 labels: vec![(span, "see msg".into())],
1154 notes: vec![],
1155 },
1156 Error::MissingWorkgroupSize(span) => ParseError {
1157 message: "workgroup size is missing on compute shader entry point".to_string(),
1158 labels: vec![(
1159 span,
1160 "must be paired with a `@workgroup_size` attribute".into(),
1161 )],
1162 notes: vec![],
1163 },
1164 Error::AutoConversion(ref error) => {
1165 let AutoConversionError {
1167 dest_span,
1168 ref dest_type,
1169 source_span,
1170 ref source_type,
1171 } = **error;
1172 ParseError {
1173 message: format!(
1174 "automatic conversions cannot convert `{source_type}` to `{dest_type}`"
1175 ),
1176 labels: vec![
1177 (
1178 dest_span,
1179 format!("a value of type {dest_type} is required here").into(),
1180 ),
1181 (
1182 source_span,
1183 format!("this expression has type {source_type}").into(),
1184 ),
1185 ],
1186 notes: vec![],
1187 }
1188 }
1189 Error::AutoConversionLeafScalar(ref error) => {
1190 let AutoConversionLeafScalarError {
1191 dest_span,
1192 ref dest_scalar,
1193 source_span,
1194 ref source_type,
1195 } = **error;
1196 ParseError {
1197 message: format!(
1198 "automatic conversions cannot convert elements of `{source_type}` to `{dest_scalar}`"
1199 ),
1200 labels: vec![
1201 (
1202 dest_span,
1203 format!(
1204 "a value with elements of type {dest_scalar} is required here"
1205 )
1206 .into(),
1207 ),
1208 (
1209 source_span,
1210 format!("this expression has type {source_type}").into(),
1211 ),
1212 ],
1213 notes: vec![],
1214 }
1215 }
1216 Error::ConcretizationFailed(ref error) => {
1217 let ConcretizationFailedError {
1218 expr_span,
1219 ref expr_type,
1220 ref concretization_preferences,
1221 } = **error;
1222 ParseError {
1223 message: "failed to convert expression to a concrete type".to_string(),
1224 labels: vec![(
1225 expr_span,
1226 format!("this expression has type {expr_type}").into(),
1227 )],
1228 notes: concretization_preferences
1229 .iter()
1230 .map(|&(ref scalar, ref err)|
1231 format!("the expression couldn't be converted to have {scalar} scalar type: {err}")
1232 )
1233 .collect(),
1234 }
1235 }
1236 Error::ExceededLimitForNestedBraces { span, limit } => ParseError {
1237 message: "brace nesting limit reached".into(),
1238 labels: vec![(span, "limit reached at this brace".into())],
1239 notes: vec![format!("nesting limit is currently set to {limit}")],
1240 },
1241 Error::PipelineConstantIDValue(span) => ParseError {
1242 message: "pipeline constant ID must be between 0 and 65535 inclusive".to_string(),
1243 labels: vec![(span, "must be between 0 and 65535 inclusive".into())],
1244 notes: vec![],
1245 },
1246 Error::NotBool(span) => ParseError {
1247 message: "must be a const-expression that resolves to a `bool`".to_string(),
1248 labels: vec![(span, "must resolve to `bool`".into())],
1249 notes: vec![],
1250 },
1251 Error::ConstAssertFailed(span) => ParseError {
1252 message: "`const_assert` failure".to_string(),
1253 labels: vec![(span, "evaluates to `false`".into())],
1254 notes: vec![],
1255 },
1256 Error::DirectiveAfterFirstGlobalDecl { directive_span } => ParseError {
1257 message: "expected global declaration, but found a global directive".into(),
1258 labels: vec![(
1259 directive_span,
1260 "written after first global declaration".into(),
1261 )],
1262 notes: vec![concat!(
1263 "global directives are only allowed before global declarations; ",
1264 "maybe hoist this closer to the top of the shader module?"
1265 )
1266 .into()],
1267 },
1268 Error::EnableExtensionNotYetImplemented { kind, span } => ParseError {
1269 message: format!(
1270 "the `{}` enable-extension is not yet supported",
1271 EnableExtension::Unimplemented(kind).to_ident()
1272 ),
1273 labels: vec![(
1274 span,
1275 concat!(
1276 "this enable-extension specifies standard functionality ",
1277 "which is not yet implemented in Naga"
1278 )
1279 .into(),
1280 )],
1281 notes: vec![format!(
1282 concat!(
1283 "Let Naga maintainers know that you ran into this at ",
1284 "<https://github.com/gfx-rs/wgpu/issues/{}>, ",
1285 "so they can prioritize it!"
1286 ),
1287 kind.tracking_issue_num()
1288 )],
1289 },
1290 Error::EnableExtensionNotEnabled { kind, span } => ParseError {
1291 message: format!("the `{}` enable extension is not enabled", kind.to_ident()),
1292 labels: vec![(
1293 span,
1294 format!(
1295 concat!(
1296 "the `{}` \"Enable Extension\" is needed for this functionality, ",
1297 "but it is not currently enabled."
1298 ),
1299 kind.to_ident()
1300 )
1301 .into(),
1302 )],
1303 notes: if let EnableExtension::Unimplemented(kind) = kind {
1304 vec![format!(
1305 concat!(
1306 "This \"Enable Extension\" is not yet implemented. ",
1307 "Let Naga maintainers know that you ran into this at ",
1308 "<https://github.com/gfx-rs/wgpu/issues/{}>, ",
1309 "so they can prioritize it!"
1310 ),
1311 kind.tracking_issue_num()
1312 )]
1313 } else {
1314 vec![
1315 format!(
1316 "You can enable this extension by adding `enable {};` at the top of the shader, before any other items.",
1317 kind.to_ident()
1318 ),
1319 ]
1320 },
1321 },
1322 Error::EnableExtensionNotSupported { kind, span } => ParseError {
1323 message: format!(
1324 "the `{}` extension is not supported in the current environment",
1325 kind.to_ident()
1326 ),
1327 labels: vec![(
1328 span,
1329 "unsupported enable-extension".into(),
1330 )],
1331 notes: vec![],
1332 },
1333 Error::LanguageExtensionNotYetImplemented { kind, span } => ParseError {
1334 message: format!(
1335 "the `{}` language extension is not yet supported",
1336 LanguageExtension::Unimplemented(kind).to_ident()
1337 ),
1338 labels: vec![(span, "".into())],
1339 notes: vec![format!(
1340 concat!(
1341 "Let Naga maintainers know that you ran into this at ",
1342 "<https://github.com/gfx-rs/wgpu/issues/{}>, ",
1343 "so they can prioritize it!"
1344 ),
1345 kind.tracking_issue_num()
1346 )],
1347 },
1348 Error::DiagnosticInvalidSeverity {
1349 severity_control_name_span,
1350 } => ParseError {
1351 message: "invalid `diagnostic(…)` severity".into(),
1352 labels: vec![(
1353 severity_control_name_span,
1354 "not a valid severity level".into(),
1355 )],
1356 notes: vec![concat!(
1357 "See available severities at ",
1358 "<https://www.w3.org/TR/WGSL/#diagnostic-severity>."
1359 )
1360 .into()],
1361 },
1362 Error::DiagnosticDuplicateTriggeringRule(ConflictingDiagnosticRuleError {
1363 triggering_rule_spans,
1364 }) => {
1365 let [first_span, second_span] = triggering_rule_spans;
1366 ParseError {
1367 message: "found conflicting `diagnostic(…)` rule(s)".into(),
1368 labels: vec![
1369 (first_span, "first rule".into()),
1370 (second_span, "second rule".into()),
1371 ],
1372 notes: vec![
1373 concat!(
1374 "Multiple `diagnostic(…)` rules with the same rule name ",
1375 "conflict unless they are directives and the severity is the same.",
1376 )
1377 .into(),
1378 "You should delete the rule you don't want.".into(),
1379 ],
1380 }
1381 }
1382 Error::DiagnosticAttributeNotYetImplementedAtParseSite {
1383 site_name_plural,
1384 ref spans,
1385 } => ParseError {
1386 message: "`@diagnostic(…)` attribute(s) not yet implemented".into(),
1387 labels: {
1388 let mut spans = spans.iter().cloned();
1389 let first = spans
1390 .next()
1391 .map(|span| {
1392 (
1393 span,
1394 format!("can't use this on {site_name_plural} (yet)").into(),
1395 )
1396 })
1397 .expect("internal error: diag. attr. rejection on empty map");
1398 core::iter::once(first)
1399 .chain(spans.map(|span| (span, "".into())))
1400 .collect()
1401 },
1402 notes: vec![format!(concat!(
1403 "Let Naga maintainers know that you ran into this at ",
1404 "<https://github.com/gfx-rs/wgpu/issues/5320>, ",
1405 "so they can prioritize it!"
1406 ))],
1407 },
1408 Error::DiagnosticAttributeNotSupported { on_what, ref spans } => {
1409 let intended_diagnostic_directive = match on_what {
1412 DiagnosticAttributeNotSupportedPosition::SemicolonInModulePosition => true,
1413 DiagnosticAttributeNotSupportedPosition::Other { .. } => false,
1414 };
1415 let on_what_plural = match on_what {
1416 DiagnosticAttributeNotSupportedPosition::SemicolonInModulePosition => {
1417 "semicolons"
1418 }
1419 DiagnosticAttributeNotSupportedPosition::Other { display_plural } => {
1420 display_plural
1421 }
1422 };
1423 ParseError {
1424 message: format!(
1425 "`@diagnostic(…)` attribute(s) on {on_what_plural} are not supported",
1426 ),
1427 labels: spans
1428 .iter()
1429 .cloned()
1430 .map(|span| (span, "".into()))
1431 .collect(),
1432 notes: vec![
1433 concat!(
1434 "`@diagnostic(…)` attributes are only permitted on `fn`s, ",
1435 "some statements, and `switch`/`loop` bodies."
1436 )
1437 .into(),
1438 {
1439 if intended_diagnostic_directive {
1440 concat!(
1441 "If you meant to declare a diagnostic filter that ",
1442 "applies to the entire module, move this line to ",
1443 "the top of the file and remove the `@` symbol."
1444 )
1445 .into()
1446 } else {
1447 concat!(
1448 "These attributes are well-formed, ",
1449 "you likely just need to move them."
1450 )
1451 .into()
1452 }
1453 },
1454 ],
1455 }
1456 }
1457 Error::SelectUnexpectedArgumentType { arg_span, ref arg_type } => ParseError {
1458 message: "unexpected argument type for `select` call".into(),
1459 labels: vec![(arg_span, format!("this value of type {arg_type}").into())],
1460 notes: vec!["expected a scalar or a `vecN` of scalars".into()],
1461 },
1462 Error::SelectRejectAndAcceptHaveNoCommonType {
1463 reject_span,
1464 ref reject_type,
1465 accept_span,
1466 ref accept_type,
1467 } => ParseError {
1468 message: "type mismatch for reject and accept values in `select` call".into(),
1469 labels: vec![
1470 (reject_span, format!("reject value of type {reject_type}").into()),
1471 (accept_span, format!("accept value of type {accept_type}").into()),
1472 ],
1473 notes: vec![],
1474 },
1475 Error::ExpectedGlobalVariable { name_span } => ParseError {
1476 message: "expected global variable".to_string(),
1477 labels: vec![(name_span, "variable used here".into())],
1478 notes: vec![],
1479 },
1480 Error::StructMemberTooLarge { member_name_span } => ParseError {
1481 message: "struct member is too large".into(),
1482 labels: vec![(member_name_span, "this member exceeds the maximum size".into())],
1483 notes: vec![format!(
1484 "the maximum size is {} bytes",
1485 crate::valid::MAX_TYPE_SIZE
1486 )],
1487 },
1488 Error::TypeTooLarge { span } => ParseError {
1489 message: "type is too large".into(),
1490 labels: vec![(span, "this type exceeds the maximum size".into())],
1491 notes: vec![format!(
1492 "the maximum size is {} bytes",
1493 crate::valid::MAX_TYPE_SIZE
1494 )],
1495 },
1496 Error::UnderspecifiedCooperativeMatrix => ParseError {
1497 message: "cooperative matrix constructor is underspecified".into(),
1498 labels: vec![],
1499 notes: vec![format!("must be F32")],
1500 },
1501 Error::InvalidCooperativeLoadType(span) => ParseError {
1502 message: "cooperative load should have a generic type for coop_mat".into(),
1503 labels: vec![(span, "type needs the coop_mat<...>".into())],
1504 notes: vec![format!("must be a valid cooperative type")],
1505 },
1506 Error::UnsupportedCooperativeScalar(span) => ParseError {
1507 message: "cooperative scalar type is not supported".into(),
1508 labels: vec![(span, "type needs the scalar type specified".into())],
1509 notes: vec![format!("must be F32")],
1510 },
1511 Error::UnexpectedIdentForEnumerant(ident_span) => ParseError {
1512 message: format!(
1513 "identifier `{}` resolves to a declaration",
1514 &source[ident_span]
1515 ),
1516 labels: vec![(ident_span, "needs to resolve to a predeclared enumerant".into())],
1517 notes: vec![],
1518 },
1519 Error::UnexpectedExprForEnumerant(expr_span) => ParseError {
1520 message: "unexpected expression".to_string(),
1521 labels: vec![(expr_span, "needs to be an identifier resolving to a predeclared enumerant".into())],
1522 notes: vec![],
1523 },
1524 Error::UnusedArgsForTemplate(ref expr_spans) => ParseError {
1525 message: "unused expressions for template".to_string(),
1526 labels: expr_spans.iter().cloned().map(|span| -> (_, _){ (span, "unused".into()) }).collect(),
1527 notes: vec![],
1528 },
1529 Error::UnexpectedTemplate(span) => ParseError {
1530 message: "unexpected template".to_string(),
1531 labels: vec![(span, "expected identifier".into())],
1532 notes: vec![],
1533 },
1534 Error::MissingTemplateArg {
1535 span,
1536 description: arg,
1537 } => ParseError {
1538 message: format!(
1539 "`{}` needs a template argument specified: {arg}",
1540 &source[span]
1541 ),
1542 labels: vec![(span, "is missing a template argument".into())],
1543 notes: vec![],
1544 },
1545 Error::UnexpectedExprForTypeExpression(expr_span) => ParseError {
1546 message: "unexpected expression".to_string(),
1547 labels: vec![(expr_span, "needs to be an identifier resolving to a type declaration (alias or struct) or predeclared type(-generator)".into())],
1548 notes: vec![],
1549 },
1550 Error::MissingIncomingPayload(span) => ParseError {
1551 message: "incoming payload is missing on a `closest_hit`, `any_hit` or `miss` shader entry point".to_string(),
1552 labels: vec![(
1553 span,
1554 "must be paired with a `@incoming_payload` attribute".into(),
1555 )],
1556 notes: vec![],
1557 },
1558 Error::UnterminatedBlockComment(span) => ParseError {
1559 message: "unterminated block comment".to_string(),
1560 labels: vec![(
1561 span,
1562 "must be closed with `*/`".into(),
1563 )],
1564 notes: vec![],
1565 }
1566 }
1567 }
1568}