naga/front/wgsl/
error.rs

1//! Formatting WGSL front end error messages.
2
3use 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    // The first span should be the primary span, and the other ones should be complementary.
34    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    /// Emits a summary of the error to standard error stream.
71    #[cfg(feature = "stderr")]
72    pub fn emit_to_stderr(&self, source: &str) {
73        self.emit_to_stderr_with_path(source, "wgsl")
74    }
75
76    /// Emits a summary of the error to standard error stream.
77    #[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    /// Emits a summary of the error to a string.
99    pub fn emit_to_string(&self, source: &str) -> String {
100        self.emit_to_string_with_path(source, "wgsl")
101    }
102
103    /// Emits a summary of the error to a string.
104    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    /// Returns a [`SourceLocation`] for the first label in the error message.
119    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    /// Expected: constant, parenthesized expression, identifier
139    PrimaryExpression,
140    /// Expected: assignment, increment/decrement expression
141    Assignment,
142    /// Expected: 'case', 'default', '}'
143    SwitchItem,
144    /// Expected: ',', ')'
145    WorkgroupSizeSeparator,
146    /// Expected: 'struct', 'let', 'var', 'type', ';', 'fn', eof
147    GlobalItem,
148    /// Expected a type.
149    Type,
150    /// Access of `var`, `let`, `const`.
151    Variable,
152    /// Access of a function
153    Function,
154    /// The `diagnostic` identifier of the `@diagnostic(…)` attribute.
155    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    /// A break if appeared outside of a continuing block
196    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 of an identifier (used for both module-scope and local redefinitions).
240    Redefinition {
241        /// Span of the identifier in the previous definition.
242        previous: Span,
243
244        /// Span of the identifier in the new definition.
245        current: Span,
246    },
247    /// A declaration refers to itself directly.
248    RecursiveDeclaration {
249        /// The location of the name of the declaration.
250        ident: Span,
251
252        /// The point at which it is used.
253        usage: Span,
254    },
255    /// A declaration refers to itself indirectly, through one or more other
256    /// definitions.
257    CyclicDeclaration {
258        /// The location of the name of some declaration in the cycle.
259        ident: Span,
260
261        /// The edges of the cycle of references.
262        ///
263        /// Each `(decl, reference)` pair indicates that the declaration whose
264        /// name is `decl` has an identifier at `reference` whose definition is
265        /// the next declaration in the cycle. The last pair's `reference` is
266        /// the same identifier as `ident`, above.
267        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    /// No overload of this function accepts this many arguments.
285    TooManyArguments {
286        /// The name of the function being called.
287        function: String,
288
289        /// The function name in the call expression.
290        call_span: Span,
291
292        /// The first argument that is unacceptable.
293        arg_span: Span,
294
295        /// Maximum number of arguments accepted by any overload of
296        /// this function.
297        max_arguments: u32,
298    },
299    /// A value passed to a builtin function has a type that is not
300    /// accepted by any overload of the function.
301    WrongArgumentType {
302        /// The name of the function being called.
303        function: String,
304
305        /// The function name in the call expression.
306        call_span: Span,
307
308        /// The first argument whose type is unacceptable.
309        arg_span: Span,
310
311        /// The index of the first argument whose type is unacceptable.
312        arg_index: u32,
313
314        /// That argument's actual type.
315        arg_ty: String,
316
317        /// The set of argument types that would have been accepted for
318        /// this argument, given the prior arguments.
319        allowed: Vec<String>,
320    },
321    /// A value passed to a builtin function has a type that is not
322    /// accepted, given the earlier arguments' types.
323    InconsistentArgumentType {
324        /// The name of the function being called.
325        function: String,
326
327        /// The function name in the call expression.
328        call_span: Span,
329
330        /// The first unacceptable argument.
331        arg_span: Span,
332
333        /// The index of the first unacceptable argument.
334        arg_index: u32,
335
336        /// The actual type of the first unacceptable argument.
337        arg_ty: String,
338
339        /// The prior argument whose type made the `arg_span` argument
340        /// unacceptable.
341        inconsistent_span: Span,
342
343        /// The index of the `inconsistent_span` argument.
344        inconsistent_index: u32,
345
346        /// The type of the `inconsistent_span` argument.
347        inconsistent_ty: String,
348
349        /// The types that would have been accepted instead of the
350        /// first unacceptable argument.
351        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/// Used for diagnostic refinement in [`Error::DiagnosticAttributeNotSupported`].
431#[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                // destructuring ensures all fields are handled
1088                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                // In this case the user may have intended to create a global diagnostic filter directive,
1320                // so display a note to them suggesting the correct syntax.
1321                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}