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