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