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