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