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