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