naga/front/wgsl/
error.rs

1use crate::front::wgsl::parse::lexer::Token;
2use crate::front::wgsl::Scalar;
3use crate::proc::{Alignment, ConstantEvaluatorError, ResolveError};
4use crate::{SourceLocation, Span};
5use codespan_reporting::diagnostic::{Diagnostic, Label};
6use codespan_reporting::files::SimpleFile;
7use codespan_reporting::term;
8use std::borrow::Cow;
9use std::ops::Range;
10use termcolor::{ColorChoice, NoColor, StandardStream};
11use thiserror::Error;
12
13#[derive(Clone, Debug)]
14pub struct ParseError {
15    message: String,
16    labels: Vec<(Span, Cow<'static, str>)>,
17    notes: Vec<String>,
18}
19
20impl ParseError {
21    pub fn labels(&self) -> impl ExactSizeIterator<Item = (Span, &str)> + '_ {
22        self.labels
23            .iter()
24            .map(|&(span, ref msg)| (span, msg.as_ref()))
25    }
26
27    pub fn message(&self) -> &str {
28        &self.message
29    }
30
31    fn diagnostic(&self) -> Diagnostic<()> {
32        let diagnostic = Diagnostic::error()
33            .with_message(self.message.to_string())
34            .with_labels(
35                self.labels
36                    .iter()
37                    .filter_map(|label| label.0.to_range().map(|range| (label, range)))
38                    .map(|(label, range)| {
39                        Label::primary((), range).with_message(label.1.to_string())
40                    })
41                    .collect(),
42            )
43            .with_notes(
44                self.notes
45                    .iter()
46                    .map(|note| format!("note: {note}"))
47                    .collect(),
48            );
49        diagnostic
50    }
51
52    /// Emits a summary of the error to standard error stream.
53    pub fn emit_to_stderr(&self, source: &str) {
54        self.emit_to_stderr_with_path(source, "wgsl")
55    }
56
57    /// Emits a summary of the error to standard error stream.
58    pub fn emit_to_stderr_with_path<P>(&self, source: &str, path: P)
59    where
60        P: AsRef<std::path::Path>,
61    {
62        let path = path.as_ref().display().to_string();
63        let files = SimpleFile::new(path, source);
64        let config = codespan_reporting::term::Config::default();
65        let writer = StandardStream::stderr(ColorChoice::Auto);
66        term::emit(&mut writer.lock(), &config, &files, &self.diagnostic())
67            .expect("cannot write error");
68    }
69
70    /// Emits a summary of the error to a string.
71    pub fn emit_to_string(&self, source: &str) -> String {
72        self.emit_to_string_with_path(source, "wgsl")
73    }
74
75    /// Emits a summary of the error to a string.
76    pub fn emit_to_string_with_path<P>(&self, source: &str, path: P) -> String
77    where
78        P: AsRef<std::path::Path>,
79    {
80        let path = path.as_ref().display().to_string();
81        let files = SimpleFile::new(path, source);
82        let config = codespan_reporting::term::Config::default();
83        let mut writer = NoColor::new(Vec::new());
84        term::emit(&mut writer, &config, &files, &self.diagnostic()).expect("cannot write error");
85        String::from_utf8(writer.into_inner()).unwrap()
86    }
87
88    /// Returns a [`SourceLocation`] for the first label in the error message.
89    pub fn location(&self, source: &str) -> Option<SourceLocation> {
90        self.labels.first().map(|label| label.0.location(source))
91    }
92}
93
94impl std::fmt::Display for ParseError {
95    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96        write!(f, "{}", self.message)
97    }
98}
99
100impl std::error::Error for ParseError {
101    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
102        None
103    }
104}
105
106#[derive(Copy, Clone, Debug, PartialEq)]
107pub enum ExpectedToken<'a> {
108    Token(Token<'a>),
109    Identifier,
110    /// Expected: constant, parenthesized expression, identifier
111    PrimaryExpression,
112    /// Expected: assignment, increment/decrement expression
113    Assignment,
114    /// Expected: 'case', 'default', '}'
115    SwitchItem,
116    /// Expected: ',', ')'
117    WorkgroupSizeSeparator,
118    /// Expected: 'struct', 'let', 'var', 'type', ';', 'fn', eof
119    GlobalItem,
120    /// Expected a type.
121    Type,
122    /// Access of `var`, `let`, `const`.
123    Variable,
124    /// Access of a function
125    Function,
126}
127
128#[derive(Clone, Copy, Debug, Error, PartialEq)]
129pub enum NumberError {
130    #[error("invalid numeric literal format")]
131    Invalid,
132    #[error("numeric literal not representable by target type")]
133    NotRepresentable,
134    #[error("unimplemented f16 type")]
135    UnimplementedF16,
136}
137
138#[derive(Copy, Clone, Debug, PartialEq)]
139pub enum InvalidAssignmentType {
140    Other,
141    Swizzle,
142    ImmutableBinding(Span),
143}
144
145#[derive(Clone, Debug)]
146pub enum Error<'a> {
147    Unexpected(Span, ExpectedToken<'a>),
148    UnexpectedComponents(Span),
149    UnexpectedOperationInConstContext(Span),
150    BadNumber(Span, NumberError),
151    BadMatrixScalarKind(Span, Scalar),
152    BadAccessor(Span),
153    BadTexture(Span),
154    BadTypeCast {
155        span: Span,
156        from_type: String,
157        to_type: String,
158    },
159    BadTextureSampleType {
160        span: Span,
161        scalar: Scalar,
162    },
163    BadIncrDecrReferenceType(Span),
164    InvalidResolve(ResolveError),
165    InvalidForInitializer(Span),
166    /// A break if appeared outside of a continuing block
167    InvalidBreakIf(Span),
168    InvalidGatherComponent(Span),
169    InvalidConstructorComponentType(Span, i32),
170    InvalidIdentifierUnderscore(Span),
171    ReservedIdentifierPrefix(Span),
172    UnknownAddressSpace(Span),
173    RepeatedAttribute(Span),
174    UnknownAttribute(Span),
175    UnknownBuiltin(Span),
176    UnknownAccess(Span),
177    UnknownIdent(Span, &'a str),
178    UnknownScalarType(Span),
179    UnknownType(Span),
180    UnknownStorageFormat(Span),
181    UnknownConservativeDepth(Span),
182    SizeAttributeTooLow(Span, u32),
183    AlignAttributeTooLow(Span, Alignment),
184    NonPowerOfTwoAlignAttribute(Span),
185    InconsistentBinding(Span),
186    TypeNotConstructible(Span),
187    TypeNotInferable(Span),
188    InitializationTypeMismatch {
189        name: Span,
190        expected: String,
191        got: String,
192    },
193    DeclMissingTypeAndInit(Span),
194    MissingAttribute(&'static str, Span),
195    InvalidAtomicPointer(Span),
196    InvalidAtomicOperandType(Span),
197    InvalidRayQueryPointer(Span),
198    Pointer(&'static str, Span),
199    NotPointer(Span),
200    NotReference(&'static str, Span),
201    InvalidAssignment {
202        span: Span,
203        ty: InvalidAssignmentType,
204    },
205    ReservedKeyword(Span),
206    /// Redefinition of an identifier (used for both module-scope and local redefinitions).
207    Redefinition {
208        /// Span of the identifier in the previous definition.
209        previous: Span,
210
211        /// Span of the identifier in the new definition.
212        current: Span,
213    },
214    /// A declaration refers to itself directly.
215    RecursiveDeclaration {
216        /// The location of the name of the declaration.
217        ident: Span,
218
219        /// The point at which it is used.
220        usage: Span,
221    },
222    /// A declaration refers to itself indirectly, through one or more other
223    /// definitions.
224    CyclicDeclaration {
225        /// The location of the name of some declaration in the cycle.
226        ident: Span,
227
228        /// The edges of the cycle of references.
229        ///
230        /// Each `(decl, reference)` pair indicates that the declaration whose
231        /// name is `decl` has an identifier at `reference` whose definition is
232        /// the next declaration in the cycle. The last pair's `reference` is
233        /// the same identifier as `ident`, above.
234        path: Vec<(Span, Span)>,
235    },
236    InvalidSwitchValue {
237        uint: bool,
238        span: Span,
239    },
240    CalledEntryPoint(Span),
241    WrongArgumentCount {
242        span: Span,
243        expected: Range<u32>,
244        found: u32,
245    },
246    FunctionReturnsVoid(Span),
247    InvalidWorkGroupUniformLoad(Span),
248    Internal(&'static str),
249    ExpectedConstExprConcreteIntegerScalar(Span),
250    ExpectedNonNegative(Span),
251    ExpectedPositiveArrayLength(Span),
252    MissingWorkgroupSize(Span),
253    ConstantEvaluatorError(ConstantEvaluatorError, Span),
254    AutoConversion {
255        dest_span: Span,
256        dest_type: String,
257        source_span: Span,
258        source_type: String,
259    },
260    AutoConversionLeafScalar {
261        dest_span: Span,
262        dest_scalar: String,
263        source_span: Span,
264        source_type: String,
265    },
266    ConcretizationFailed {
267        expr_span: Span,
268        expr_type: String,
269        scalar: String,
270        inner: ConstantEvaluatorError,
271    },
272    ExceededLimitForNestedBraces {
273        span: Span,
274        limit: u8,
275    },
276    PipelineConstantIDValue(Span),
277}
278
279impl<'a> Error<'a> {
280    pub(crate) fn as_parse_error(&self, source: &'a str) -> ParseError {
281        match *self {
282            Error::Unexpected(unexpected_span, expected) => {
283                let expected_str = match expected {
284                    ExpectedToken::Token(token) => {
285                        match token {
286                            Token::Separator(c) => format!("'{c}'"),
287                            Token::Paren(c) => format!("'{c}'"),
288                            Token::Attribute => "@".to_string(),
289                            Token::Number(_) => "number".to_string(),
290                            Token::Word(s) => s.to_string(),
291                            Token::Operation(c) => format!("operation ('{c}')"),
292                            Token::LogicalOperation(c) => format!("logical operation ('{c}')"),
293                            Token::ShiftOperation(c) => format!("bitshift ('{c}{c}')"),
294                            Token::AssignmentOperation(c) if c=='<' || c=='>' => format!("bitshift ('{c}{c}=')"),
295                            Token::AssignmentOperation(c) => format!("operation ('{c}=')"),
296                            Token::IncrementOperation => "increment operation".to_string(),
297                            Token::DecrementOperation => "decrement operation".to_string(),
298                            Token::Arrow => "->".to_string(),
299                            Token::Unknown(c) => format!("unknown ('{c}')"),
300                            Token::Trivia => "trivia".to_string(),
301                            Token::End => "end".to_string(),
302                        }
303                    }
304                    ExpectedToken::Identifier => "identifier".to_string(),
305                    ExpectedToken::PrimaryExpression => "expression".to_string(),
306                    ExpectedToken::Assignment => "assignment or increment/decrement".to_string(),
307                    ExpectedToken::SwitchItem => "switch item ('case' or 'default') or a closing curly bracket to signify the end of the switch statement ('}')".to_string(),
308                    ExpectedToken::WorkgroupSizeSeparator => "workgroup size separator (',') or a closing parenthesis".to_string(),
309                    ExpectedToken::GlobalItem => "global item ('struct', 'const', 'var', 'alias', ';', 'fn') or the end of the file".to_string(),
310                    ExpectedToken::Type => "type".to_string(),
311                    ExpectedToken::Variable => "variable access".to_string(),
312                    ExpectedToken::Function => "function name".to_string(),
313                };
314                ParseError {
315                    message: format!(
316                        "expected {}, found '{}'",
317                        expected_str, &source[unexpected_span],
318                    ),
319                    labels: vec![(unexpected_span, format!("expected {expected_str}").into())],
320                    notes: vec![],
321                }
322            }
323            Error::UnexpectedComponents(bad_span) => ParseError {
324                message: "unexpected components".to_string(),
325                labels: vec![(bad_span, "unexpected components".into())],
326                notes: vec![],
327            },
328            Error::UnexpectedOperationInConstContext(span) => ParseError {
329                message: "this operation is not supported in a const context".to_string(),
330                labels: vec![(span, "operation not supported here".into())],
331                notes: vec![],
332            },
333            Error::BadNumber(bad_span, ref err) => ParseError {
334                message: format!("{}: `{}`", err, &source[bad_span],),
335                labels: vec![(bad_span, err.to_string().into())],
336                notes: vec![],
337            },
338            Error::BadMatrixScalarKind(span, scalar) => ParseError {
339                message: format!(
340                    "matrix scalar type must be floating-point, but found `{}`",
341                    scalar.to_wgsl()
342                ),
343                labels: vec![(span, "must be floating-point (e.g. `f32`)".into())],
344                notes: vec![],
345            },
346            Error::BadAccessor(accessor_span) => ParseError {
347                message: format!("invalid field accessor `{}`", &source[accessor_span],),
348                labels: vec![(accessor_span, "invalid accessor".into())],
349                notes: vec![],
350            },
351            Error::UnknownIdent(ident_span, ident) => ParseError {
352                message: format!("no definition in scope for identifier: '{ident}'"),
353                labels: vec![(ident_span, "unknown identifier".into())],
354                notes: vec![],
355            },
356            Error::UnknownScalarType(bad_span) => ParseError {
357                message: format!("unknown scalar type: '{}'", &source[bad_span]),
358                labels: vec![(bad_span, "unknown scalar type".into())],
359                notes: vec!["Valid scalar types are f32, f64, i32, u32, bool".into()],
360            },
361            Error::BadTextureSampleType { span, scalar } => ParseError {
362                message: format!(
363                    "texture sample type must be one of f32, i32 or u32, but found {}",
364                    scalar.to_wgsl()
365                ),
366                labels: vec![(span, "must be one of f32, i32 or u32".into())],
367                notes: vec![],
368            },
369            Error::BadIncrDecrReferenceType(span) => ParseError {
370                message:
371                    "increment/decrement operation requires reference type to be one of i32 or u32"
372                        .to_string(),
373                labels: vec![(span, "must be a reference type of i32 or u32".into())],
374                notes: vec![],
375            },
376            Error::BadTexture(bad_span) => ParseError {
377                message: format!(
378                    "expected an image, but found '{}' which is not an image",
379                    &source[bad_span]
380                ),
381                labels: vec![(bad_span, "not an image".into())],
382                notes: vec![],
383            },
384            Error::BadTypeCast {
385                span,
386                ref from_type,
387                ref to_type,
388            } => {
389                let msg = format!("cannot cast a {from_type} to a {to_type}");
390                ParseError {
391                    message: msg.clone(),
392                    labels: vec![(span, msg.into())],
393                    notes: vec![],
394                }
395            }
396            Error::InvalidResolve(ref resolve_error) => ParseError {
397                message: resolve_error.to_string(),
398                labels: vec![],
399                notes: vec![],
400            },
401            Error::InvalidForInitializer(bad_span) => ParseError {
402                message: format!(
403                    "for(;;) initializer is not an assignment or a function call: '{}'",
404                    &source[bad_span]
405                ),
406                labels: vec![(bad_span, "not an assignment or function call".into())],
407                notes: vec![],
408            },
409            Error::InvalidBreakIf(bad_span) => ParseError {
410                message: "A break if is only allowed in a continuing block".to_string(),
411                labels: vec![(bad_span, "not in a continuing block".into())],
412                notes: vec![],
413            },
414            Error::InvalidGatherComponent(bad_span) => ParseError {
415                message: format!(
416                    "textureGather component '{}' doesn't exist, must be 0, 1, 2, or 3",
417                    &source[bad_span]
418                ),
419                labels: vec![(bad_span, "invalid component".into())],
420                notes: vec![],
421            },
422            Error::InvalidConstructorComponentType(bad_span, component) => ParseError {
423                message: format!("invalid type for constructor component at index [{component}]"),
424                labels: vec![(bad_span, "invalid component type".into())],
425                notes: vec![],
426            },
427            Error::InvalidIdentifierUnderscore(bad_span) => ParseError {
428                message: "Identifier can't be '_'".to_string(),
429                labels: vec![(bad_span, "invalid identifier".into())],
430                notes: vec![
431                    "Use phony assignment instead ('_ =' notice the absence of 'let' or 'var')"
432                        .to_string(),
433                ],
434            },
435            Error::ReservedIdentifierPrefix(bad_span) => ParseError {
436                message: format!(
437                    "Identifier starts with a reserved prefix: '{}'",
438                    &source[bad_span]
439                ),
440                labels: vec![(bad_span, "invalid identifier".into())],
441                notes: vec![],
442            },
443            Error::UnknownAddressSpace(bad_span) => ParseError {
444                message: format!("unknown address space: '{}'", &source[bad_span]),
445                labels: vec![(bad_span, "unknown address space".into())],
446                notes: vec![],
447            },
448            Error::RepeatedAttribute(bad_span) => ParseError {
449                message: format!("repeated attribute: '{}'", &source[bad_span]),
450                labels: vec![(bad_span, "repeated attribute".into())],
451                notes: vec![],
452            },
453            Error::UnknownAttribute(bad_span) => ParseError {
454                message: format!("unknown attribute: '{}'", &source[bad_span]),
455                labels: vec![(bad_span, "unknown attribute".into())],
456                notes: vec![],
457            },
458            Error::UnknownBuiltin(bad_span) => ParseError {
459                message: format!("unknown builtin: '{}'", &source[bad_span]),
460                labels: vec![(bad_span, "unknown builtin".into())],
461                notes: vec![],
462            },
463            Error::UnknownAccess(bad_span) => ParseError {
464                message: format!("unknown access: '{}'", &source[bad_span]),
465                labels: vec![(bad_span, "unknown access".into())],
466                notes: vec![],
467            },
468            Error::UnknownStorageFormat(bad_span) => ParseError {
469                message: format!("unknown storage format: '{}'", &source[bad_span]),
470                labels: vec![(bad_span, "unknown storage format".into())],
471                notes: vec![],
472            },
473            Error::UnknownConservativeDepth(bad_span) => ParseError {
474                message: format!("unknown conservative depth: '{}'", &source[bad_span]),
475                labels: vec![(bad_span, "unknown conservative depth".into())],
476                notes: vec![],
477            },
478            Error::UnknownType(bad_span) => ParseError {
479                message: format!("unknown type: '{}'", &source[bad_span]),
480                labels: vec![(bad_span, "unknown type".into())],
481                notes: vec![],
482            },
483            Error::SizeAttributeTooLow(bad_span, min_size) => ParseError {
484                message: format!("struct member size must be at least {min_size}"),
485                labels: vec![(bad_span, format!("must be at least {min_size}").into())],
486                notes: vec![],
487            },
488            Error::AlignAttributeTooLow(bad_span, min_align) => ParseError {
489                message: format!("struct member alignment must be at least {min_align}"),
490                labels: vec![(bad_span, format!("must be at least {min_align}").into())],
491                notes: vec![],
492            },
493            Error::NonPowerOfTwoAlignAttribute(bad_span) => ParseError {
494                message: "struct member alignment must be a power of 2".to_string(),
495                labels: vec![(bad_span, "must be a power of 2".into())],
496                notes: vec![],
497            },
498            Error::InconsistentBinding(span) => ParseError {
499                message: "input/output binding is not consistent".to_string(),
500                labels: vec![(span, "input/output binding is not consistent".into())],
501                notes: vec![],
502            },
503            Error::TypeNotConstructible(span) => ParseError {
504                message: format!("type `{}` is not constructible", &source[span]),
505                labels: vec![(span, "type is not constructible".into())],
506                notes: vec![],
507            },
508            Error::TypeNotInferable(span) => ParseError {
509                message: "type can't be inferred".to_string(),
510                labels: vec![(span, "type can't be inferred".into())],
511                notes: vec![],
512            },
513            Error::InitializationTypeMismatch { name, ref expected, ref got } => {
514                ParseError {
515                    message: format!(
516                        "the type of `{}` is expected to be `{}`, but got `{}`",
517                        &source[name], expected, got,
518                    ),
519                    labels: vec![(
520                        name,
521                        format!("definition of `{}`", &source[name]).into(),
522                    )],
523                    notes: vec![],
524                }
525            }
526            Error::DeclMissingTypeAndInit(name_span) => ParseError {
527                message: format!("declaration of `{}` needs a type specifier or initializer", &source[name_span]),
528                labels: vec![(
529                    name_span,
530                    "needs a type specifier or initializer".into(),
531                )],
532                notes: vec![],
533            },
534            Error::MissingAttribute(name, name_span) => ParseError {
535                message: format!(
536                    "variable `{}` needs a '{}' attribute",
537                    &source[name_span], name
538                ),
539                labels: vec![(
540                    name_span,
541                    format!("definition of `{}`", &source[name_span]).into(),
542                )],
543                notes: vec![],
544            },
545            Error::InvalidAtomicPointer(span) => ParseError {
546                message: "atomic operation is done on a pointer to a non-atomic".to_string(),
547                labels: vec![(span, "atomic pointer is invalid".into())],
548                notes: vec![],
549            },
550            Error::InvalidAtomicOperandType(span) => ParseError {
551                message: "atomic operand type is inconsistent with the operation".to_string(),
552                labels: vec![(span, "atomic operand type is invalid".into())],
553                notes: vec![],
554            },
555            Error::InvalidRayQueryPointer(span) => ParseError {
556                message: "ray query operation is done on a pointer to a non-ray-query".to_string(),
557                labels: vec![(span, "ray query pointer is invalid".into())],
558                notes: vec![],
559            },
560            Error::NotPointer(span) => ParseError {
561                message: "the operand of the `*` operator must be a pointer".to_string(),
562                labels: vec![(span, "expression is not a pointer".into())],
563                notes: vec![],
564            },
565            Error::NotReference(what, span) => ParseError {
566                message: format!("{what} must be a reference"),
567                labels: vec![(span, "expression is not a reference".into())],
568                notes: vec![],
569            },
570            Error::InvalidAssignment { span, ty } => {
571                let (extra_label, notes) = match ty {
572                    InvalidAssignmentType::Swizzle => (
573                        None,
574                        vec![
575                            "WGSL does not support assignments to swizzles".into(),
576                            "consider assigning each component individually".into(),
577                        ],
578                    ),
579                    InvalidAssignmentType::ImmutableBinding(binding_span) => (
580                        Some((binding_span, "this is an immutable binding".into())),
581                        vec![format!(
582                            "consider declaring '{}' with `var` instead of `let`",
583                            &source[binding_span]
584                        )],
585                    ),
586                    InvalidAssignmentType::Other => (None, vec![]),
587                };
588
589                ParseError {
590                    message: "invalid left-hand side of assignment".into(),
591                    labels: std::iter::once((span, "cannot assign to this expression".into()))
592                        .chain(extra_label)
593                        .collect(),
594                    notes,
595                }
596            }
597            Error::Pointer(what, span) => ParseError {
598                message: format!("{what} must not be a pointer"),
599                labels: vec![(span, "expression is a pointer".into())],
600                notes: vec![],
601            },
602            Error::ReservedKeyword(name_span) => ParseError {
603                message: format!("name `{}` is a reserved keyword", &source[name_span]),
604                labels: vec![(
605                    name_span,
606                    format!("definition of `{}`", &source[name_span]).into(),
607                )],
608                notes: vec![],
609            },
610            Error::Redefinition { previous, current } => ParseError {
611                message: format!("redefinition of `{}`", &source[current]),
612                labels: vec![
613                    (
614                        current,
615                        format!("redefinition of `{}`", &source[current]).into(),
616                    ),
617                    (
618                        previous,
619                        format!("previous definition of `{}`", &source[previous]).into(),
620                    ),
621                ],
622                notes: vec![],
623            },
624            Error::RecursiveDeclaration { ident, usage } => ParseError {
625                message: format!("declaration of `{}` is recursive", &source[ident]),
626                labels: vec![(ident, "".into()), (usage, "uses itself here".into())],
627                notes: vec![],
628            },
629            Error::CyclicDeclaration { ident, ref path } => ParseError {
630                message: format!("declaration of `{}` is cyclic", &source[ident]),
631                labels: path
632                    .iter()
633                    .enumerate()
634                    .flat_map(|(i, &(ident, usage))| {
635                        [
636                            (ident, "".into()),
637                            (
638                                usage,
639                                if i == path.len() - 1 {
640                                    "ending the cycle".into()
641                                } else {
642                                    format!("uses `{}`", &source[ident]).into()
643                                },
644                            ),
645                        ]
646                    })
647                    .collect(),
648                notes: vec![],
649            },
650            Error::InvalidSwitchValue { uint, span } => ParseError {
651                message: "invalid switch value".to_string(),
652                labels: vec![(
653                    span,
654                    if uint {
655                        "expected unsigned integer"
656                    } else {
657                        "expected signed integer"
658                    }
659                    .into(),
660                )],
661                notes: vec![if uint {
662                    format!("suffix the integer with a `u`: '{}u'", &source[span])
663                } else {
664                    let span = span.to_range().unwrap();
665                    format!(
666                        "remove the `u` suffix: '{}'",
667                        &source[span.start..span.end - 1]
668                    )
669                }],
670            },
671            Error::CalledEntryPoint(span) => ParseError {
672                message: "entry point cannot be called".to_string(),
673                labels: vec![(span, "entry point cannot be called".into())],
674                notes: vec![],
675            },
676            Error::WrongArgumentCount {
677                span,
678                ref expected,
679                found,
680            } => ParseError {
681                message: format!(
682                    "wrong number of arguments: expected {}, found {}",
683                    if expected.len() < 2 {
684                        format!("{}", expected.start)
685                    } else {
686                        format!("{}..{}", expected.start, expected.end)
687                    },
688                    found
689                ),
690                labels: vec![(span, "wrong number of arguments".into())],
691                notes: vec![],
692            },
693            Error::FunctionReturnsVoid(span) => ParseError {
694                message: "function does not return any value".to_string(),
695                labels: vec![(span, "".into())],
696                notes: vec![
697                    "perhaps you meant to call the function in a separate statement?".into(),
698                ],
699            },
700            Error::InvalidWorkGroupUniformLoad(span) => ParseError {
701                message: "incorrect type passed to workgroupUniformLoad".into(),
702                labels: vec![(span, "".into())],
703                notes: vec!["passed type must be a workgroup pointer".into()],
704            },
705            Error::Internal(message) => ParseError {
706                message: "internal WGSL front end error".to_string(),
707                labels: vec![],
708                notes: vec![message.into()],
709            },
710            Error::ExpectedConstExprConcreteIntegerScalar(span) => ParseError {
711                message: "must be a const-expression that resolves to a concrete integer scalar (u32 or i32)".to_string(),
712                labels: vec![(span, "must resolve to u32 or i32".into())],
713                notes: vec![],
714            },
715            Error::ExpectedNonNegative(span) => ParseError {
716                message: "must be non-negative (>= 0)".to_string(),
717                labels: vec![(span, "must be non-negative".into())],
718                notes: vec![],
719            },
720            Error::ExpectedPositiveArrayLength(span) => ParseError {
721                message: "array element count must be positive (> 0)".to_string(),
722                labels: vec![(span, "must be positive".into())],
723                notes: vec![],
724            },
725            Error::ConstantEvaluatorError(ref e, span) => ParseError {
726                message: e.to_string(),
727                labels: vec![(span, "see msg".into())],
728                notes: vec![],
729            },
730            Error::MissingWorkgroupSize(span) => ParseError {
731                message: "workgroup size is missing on compute shader entry point".to_string(),
732                labels: vec![(
733                    span,
734                    "must be paired with a @workgroup_size attribute".into(),
735                )],
736                notes: vec![],
737            },
738            Error::AutoConversion { dest_span, ref dest_type, source_span, ref source_type } => ParseError {
739                message: format!("automatic conversions cannot convert `{source_type}` to `{dest_type}`"),
740                labels: vec![
741                    (
742                        dest_span,
743                        format!("a value of type {dest_type} is required here").into(),
744                    ),
745                    (
746                        source_span,
747                        format!("this expression has type {source_type}").into(),
748                    )
749                ],
750                notes: vec![],
751            },
752            Error::AutoConversionLeafScalar { dest_span, ref dest_scalar, source_span, ref source_type } => ParseError {
753                message: format!("automatic conversions cannot convert elements of `{source_type}` to `{dest_scalar}`"),
754                labels: vec![
755                    (
756                        dest_span,
757                        format!("a value with elements of type {dest_scalar} is required here").into(),
758                    ),
759                    (
760                        source_span,
761                        format!("this expression has type {source_type}").into(),
762                    )
763                ],
764                notes: vec![],
765            },
766            Error::ConcretizationFailed { expr_span, ref expr_type, ref scalar, ref inner } => ParseError {
767                message: format!("failed to convert expression to a concrete type: {}", inner),
768                labels: vec![
769                    (
770                        expr_span,
771                        format!("this expression has type {}", expr_type).into(),
772                    )
773                ],
774                notes: vec![
775                    format!("the expression should have been converted to have {} scalar type", scalar),
776                ]
777            },
778            Error::ExceededLimitForNestedBraces { span, limit } => ParseError {
779                message: "brace nesting limit reached".into(),
780                labels: vec![(span, "limit reached at this brace".into())],
781                notes: vec![
782                    format!("nesting limit is currently set to {limit}"),
783                ],
784            },
785            Error::PipelineConstantIDValue(span) => ParseError {
786                message: "pipeline constant ID must be between 0 and 65535 inclusive".to_string(),
787                labels: vec![(
788                    span,
789                    "must be between 0 and 65535 inclusive".into(),
790                )],
791                notes: vec![],
792            },
793        }
794    }
795}