1use crate::front::wgsl::parse::directive::enable_extension::{
2 EnableExtension, UnimplementedEnableExtension,
3};
4use crate::front::wgsl::parse::directive::language_extension::{
5 LanguageExtension, UnimplementedLanguageExtension,
6};
7use crate::front::wgsl::parse::directive::{DirectiveKind, UnimplementedDirectiveKind};
8use crate::front::wgsl::parse::lexer::Token;
9use crate::front::wgsl::Scalar;
10use crate::proc::{Alignment, ConstantEvaluatorError, ResolveError};
11use crate::{SourceLocation, Span};
12use codespan_reporting::diagnostic::{Diagnostic, Label};
13use codespan_reporting::files::SimpleFile;
14use codespan_reporting::term;
15use std::borrow::Cow;
16use std::ops::Range;
17use termcolor::{ColorChoice, NoColor, StandardStream};
18use thiserror::Error;
19
20#[cfg(test)]
21use std::mem::size_of;
22
23#[derive(Clone, Debug)]
24pub struct ParseError {
25 message: String,
26 labels: Vec<(Span, Cow<'static, str>)>,
28 notes: Vec<String>,
29}
30
31impl ParseError {
32 pub fn labels(&self) -> impl ExactSizeIterator<Item = (Span, &str)> + '_ {
33 self.labels
34 .iter()
35 .map(|&(span, ref msg)| (span, msg.as_ref()))
36 }
37
38 pub fn message(&self) -> &str {
39 &self.message
40 }
41
42 fn diagnostic(&self) -> Diagnostic<()> {
43 let diagnostic = Diagnostic::error()
44 .with_message(self.message.to_string())
45 .with_labels(
46 self.labels
47 .iter()
48 .filter_map(|label| label.0.to_range().map(|range| (label, range)))
49 .map(|(label, range)| {
50 Label::primary((), range).with_message(label.1.to_string())
51 })
52 .collect(),
53 )
54 .with_notes(
55 self.notes
56 .iter()
57 .map(|note| format!("note: {note}"))
58 .collect(),
59 );
60 diagnostic
61 }
62
63 pub fn emit_to_stderr(&self, source: &str) {
65 self.emit_to_stderr_with_path(source, "wgsl")
66 }
67
68 pub fn emit_to_stderr_with_path<P>(&self, source: &str, path: P)
70 where
71 P: AsRef<std::path::Path>,
72 {
73 let path = path.as_ref().display().to_string();
74 let files = SimpleFile::new(path, source);
75 let config = term::Config::default();
76 let writer = StandardStream::stderr(ColorChoice::Auto);
77 term::emit(&mut writer.lock(), &config, &files, &self.diagnostic())
78 .expect("cannot write error");
79 }
80
81 pub fn emit_to_string(&self, source: &str) -> String {
83 self.emit_to_string_with_path(source, "wgsl")
84 }
85
86 pub fn emit_to_string_with_path<P>(&self, source: &str, path: P) -> String
88 where
89 P: AsRef<std::path::Path>,
90 {
91 let path = path.as_ref().display().to_string();
92 let files = SimpleFile::new(path, source);
93 let config = term::Config::default();
94 let mut writer = NoColor::new(Vec::new());
95 term::emit(&mut writer, &config, &files, &self.diagnostic()).expect("cannot write error");
96 String::from_utf8(writer.into_inner()).unwrap()
97 }
98
99 pub fn location(&self, source: &str) -> Option<SourceLocation> {
101 self.labels.first().map(|label| label.0.location(source))
102 }
103}
104
105impl std::fmt::Display for ParseError {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 write!(f, "{}", self.message)
108 }
109}
110
111impl std::error::Error for ParseError {
112 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
113 None
114 }
115}
116
117#[derive(Copy, Clone, Debug, PartialEq)]
118pub enum ExpectedToken<'a> {
119 Token(Token<'a>),
120 Identifier,
121 AfterIdentListComma,
122 AfterIdentListArg,
123 PrimaryExpression,
125 Assignment,
127 SwitchItem,
129 WorkgroupSizeSeparator,
131 GlobalItem,
133 Type,
135 Variable,
137 Function,
139}
140
141#[derive(Clone, Copy, Debug, Error, PartialEq)]
142pub enum NumberError {
143 #[error("invalid numeric literal format")]
144 Invalid,
145 #[error("numeric literal not representable by target type")]
146 NotRepresentable,
147 #[error("unimplemented f16 type")]
148 UnimplementedF16,
149}
150
151#[derive(Copy, Clone, Debug, PartialEq)]
152pub enum InvalidAssignmentType {
153 Other,
154 Swizzle,
155 ImmutableBinding(Span),
156}
157
158#[derive(Clone, Debug)]
159pub(crate) enum Error<'a> {
160 Unexpected(Span, ExpectedToken<'a>),
161 UnexpectedComponents(Span),
162 UnexpectedOperationInConstContext(Span),
163 BadNumber(Span, NumberError),
164 BadMatrixScalarKind(Span, Scalar),
165 BadAccessor(Span),
166 BadTexture(Span),
167 BadTypeCast {
168 span: Span,
169 from_type: Box<str>,
170 to_type: Box<str>,
171 },
172 BadTextureSampleType {
173 span: Span,
174 scalar: Scalar,
175 },
176 BadIncrDecrReferenceType(Span),
177 InvalidResolve(ResolveError),
178 InvalidForInitializer(Span),
179 InvalidBreakIf(Span),
181 InvalidGatherComponent(Span),
182 InvalidConstructorComponentType(Span, i32),
183 InvalidIdentifierUnderscore(Span),
184 ReservedIdentifierPrefix(Span),
185 UnknownAddressSpace(Span),
186 RepeatedAttribute(Span),
187 UnknownAttribute(Span),
188 UnknownBuiltin(Span),
189 UnknownAccess(Span),
190 UnknownIdent(Span, &'a str),
191 UnknownScalarType(Span),
192 UnknownType(Span),
193 UnknownStorageFormat(Span),
194 UnknownConservativeDepth(Span),
195 UnknownEnableExtension(Span, &'a str),
196 UnknownLanguageExtension(Span, &'a str),
197 SizeAttributeTooLow(Span, u32),
198 AlignAttributeTooLow(Span, Alignment),
199 NonPowerOfTwoAlignAttribute(Span),
200 InconsistentBinding(Span),
201 TypeNotConstructible(Span),
202 TypeNotInferable(Span),
203 InitializationTypeMismatch {
204 name: Span,
205 expected: Box<str>,
206 got: Box<str>,
207 },
208 DeclMissingTypeAndInit(Span),
209 MissingAttribute(&'static str, Span),
210 InvalidAtomicPointer(Span),
211 InvalidAtomicOperandType(Span),
212 InvalidRayQueryPointer(Span),
213 Pointer(&'static str, Span),
214 NotPointer(Span),
215 NotReference(&'static str, Span),
216 InvalidAssignment {
217 span: Span,
218 ty: InvalidAssignmentType,
219 },
220 ReservedKeyword(Span),
221 Redefinition {
223 previous: Span,
225
226 current: Span,
228 },
229 RecursiveDeclaration {
231 ident: Span,
233
234 usage: Span,
236 },
237 CyclicDeclaration {
240 ident: Span,
242
243 path: Box<[(Span, Span)]>,
250 },
251 InvalidSwitchValue {
252 uint: bool,
253 span: Span,
254 },
255 CalledEntryPoint(Span),
256 WrongArgumentCount {
257 span: Span,
258 expected: Range<u32>,
259 found: u32,
260 },
261 FunctionReturnsVoid(Span),
262 InvalidWorkGroupUniformLoad(Span),
263 Internal(&'static str),
264 ExpectedConstExprConcreteIntegerScalar(Span),
265 ExpectedNonNegative(Span),
266 ExpectedPositiveArrayLength(Span),
267 MissingWorkgroupSize(Span),
268 ConstantEvaluatorError(Box<ConstantEvaluatorError>, Span),
269 AutoConversion(Box<AutoConversionError>),
270 AutoConversionLeafScalar(Box<AutoConversionLeafScalarError>),
271 ConcretizationFailed(Box<ConcretizationFailedError>),
272 ExceededLimitForNestedBraces {
273 span: Span,
274 limit: u8,
275 },
276 PipelineConstantIDValue(Span),
277 NotBool(Span),
278 ConstAssertFailed(Span),
279 DirectiveNotYetImplemented {
280 kind: UnimplementedDirectiveKind,
281 span: Span,
282 },
283 DirectiveAfterFirstGlobalDecl {
284 directive_span: Span,
285 },
286 EnableExtensionNotYetImplemented {
287 kind: UnimplementedEnableExtension,
288 span: Span,
289 },
290 EnableExtensionNotEnabled {
291 kind: EnableExtension,
292 span: Span,
293 },
294 LanguageExtensionNotYetImplemented {
295 kind: UnimplementedLanguageExtension,
296 span: Span,
297 },
298}
299
300#[derive(Clone, Debug)]
301pub(crate) struct AutoConversionError {
302 pub dest_span: Span,
303 pub dest_type: Box<str>,
304 pub source_span: Span,
305 pub source_type: Box<str>,
306}
307
308#[derive(Clone, Debug)]
309pub(crate) struct AutoConversionLeafScalarError {
310 pub dest_span: Span,
311 pub dest_scalar: Box<str>,
312 pub source_span: Span,
313 pub source_type: Box<str>,
314}
315
316#[derive(Clone, Debug)]
317pub(crate) struct ConcretizationFailedError {
318 pub expr_span: Span,
319 pub expr_type: Box<str>,
320 pub scalar: Box<str>,
321 pub inner: ConstantEvaluatorError,
322}
323
324impl<'a> Error<'a> {
325 #[cold]
326 #[inline(never)]
327 pub(crate) fn as_parse_error(&self, source: &'a str) -> ParseError {
328 match *self {
329 Error::Unexpected(unexpected_span, expected) => {
330 let expected_str = match expected {
331 ExpectedToken::Token(token) => match token {
332 Token::Separator(c) => format!("'{c}'"),
333 Token::Paren(c) => format!("'{c}'"),
334 Token::Attribute => "@".to_string(),
335 Token::Number(_) => "number".to_string(),
336 Token::Word(s) => s.to_string(),
337 Token::Operation(c) => format!("operation ('{c}')"),
338 Token::LogicalOperation(c) => format!("logical operation ('{c}')"),
339 Token::ShiftOperation(c) => format!("bitshift ('{c}{c}')"),
340 Token::AssignmentOperation(c) if c == '<' || c == '>' => {
341 format!("bitshift ('{c}{c}=')")
342 }
343 Token::AssignmentOperation(c) => format!("operation ('{c}=')"),
344 Token::IncrementOperation => "increment operation".to_string(),
345 Token::DecrementOperation => "decrement operation".to_string(),
346 Token::Arrow => "->".to_string(),
347 Token::Unknown(c) => format!("unknown ('{c}')"),
348 Token::Trivia => "trivia".to_string(),
349 Token::End => "end".to_string(),
350 },
351 ExpectedToken::Identifier => "identifier".to_string(),
352 ExpectedToken::PrimaryExpression => "expression".to_string(),
353 ExpectedToken::Assignment => "assignment or increment/decrement".to_string(),
354 ExpectedToken::SwitchItem => concat!(
355 "switch item ('case' or 'default') or a closing curly bracket ",
356 "to signify the end of the switch statement ('}')"
357 )
358 .to_string(),
359 ExpectedToken::WorkgroupSizeSeparator => {
360 "workgroup size separator (',') or a closing parenthesis".to_string()
361 }
362 ExpectedToken::GlobalItem => concat!(
363 "global item ('struct', 'const', 'var', 'alias', ';', 'fn') ",
364 "or the end of the file"
365 )
366 .to_string(),
367 ExpectedToken::Type => "type".to_string(),
368 ExpectedToken::Variable => "variable access".to_string(),
369 ExpectedToken::Function => "function name".to_string(),
370 ExpectedToken::AfterIdentListArg => {
371 "next argument, trailing comma, or end of list (',' or ';')".to_string()
372 }
373 ExpectedToken::AfterIdentListComma => {
374 "next argument or end of list (';')".to_string()
375 }
376 };
377 ParseError {
378 message: format!(
379 "expected {}, found '{}'",
380 expected_str, &source[unexpected_span],
381 ),
382 labels: vec![(unexpected_span, format!("expected {expected_str}").into())],
383 notes: vec![],
384 }
385 }
386 Error::UnexpectedComponents(bad_span) => ParseError {
387 message: "unexpected components".to_string(),
388 labels: vec![(bad_span, "unexpected components".into())],
389 notes: vec![],
390 },
391 Error::UnexpectedOperationInConstContext(span) => ParseError {
392 message: "this operation is not supported in a const context".to_string(),
393 labels: vec![(span, "operation not supported here".into())],
394 notes: vec![],
395 },
396 Error::BadNumber(bad_span, ref err) => ParseError {
397 message: format!("{}: `{}`", err, &source[bad_span],),
398 labels: vec![(bad_span, err.to_string().into())],
399 notes: vec![],
400 },
401 Error::BadMatrixScalarKind(span, scalar) => ParseError {
402 message: format!(
403 "matrix scalar type must be floating-point, but found `{}`",
404 scalar.to_wgsl()
405 ),
406 labels: vec![(span, "must be floating-point (e.g. `f32`)".into())],
407 notes: vec![],
408 },
409 Error::BadAccessor(accessor_span) => ParseError {
410 message: format!("invalid field accessor `{}`", &source[accessor_span],),
411 labels: vec![(accessor_span, "invalid accessor".into())],
412 notes: vec![],
413 },
414 Error::UnknownIdent(ident_span, ident) => ParseError {
415 message: format!("no definition in scope for identifier: '{ident}'"),
416 labels: vec![(ident_span, "unknown identifier".into())],
417 notes: vec![],
418 },
419 Error::UnknownScalarType(bad_span) => ParseError {
420 message: format!("unknown scalar type: '{}'", &source[bad_span]),
421 labels: vec![(bad_span, "unknown scalar type".into())],
422 notes: vec!["Valid scalar types are f32, f64, i32, u32, bool".into()],
423 },
424 Error::BadTextureSampleType { span, scalar } => ParseError {
425 message: format!(
426 "texture sample type must be one of f32, i32 or u32, but found {}",
427 scalar.to_wgsl()
428 ),
429 labels: vec![(span, "must be one of f32, i32 or u32".into())],
430 notes: vec![],
431 },
432 Error::BadIncrDecrReferenceType(span) => ParseError {
433 message: concat!(
434 "increment/decrement operation requires ",
435 "reference type to be one of i32 or u32"
436 )
437 .to_string(),
438 labels: vec![(span, "must be a reference type of i32 or u32".into())],
439 notes: vec![],
440 },
441 Error::BadTexture(bad_span) => ParseError {
442 message: format!(
443 "expected an image, but found '{}' which is not an image",
444 &source[bad_span]
445 ),
446 labels: vec![(bad_span, "not an image".into())],
447 notes: vec![],
448 },
449 Error::BadTypeCast {
450 span,
451 ref from_type,
452 ref to_type,
453 } => {
454 let msg = format!("cannot cast a {from_type} to a {to_type}");
455 ParseError {
456 message: msg.clone(),
457 labels: vec![(span, msg.into())],
458 notes: vec![],
459 }
460 }
461 Error::InvalidResolve(ref resolve_error) => ParseError {
462 message: resolve_error.to_string(),
463 labels: vec![],
464 notes: vec![],
465 },
466 Error::InvalidForInitializer(bad_span) => ParseError {
467 message: format!(
468 "for(;;) initializer is not an assignment or a function call: '{}'",
469 &source[bad_span]
470 ),
471 labels: vec![(bad_span, "not an assignment or function call".into())],
472 notes: vec![],
473 },
474 Error::InvalidBreakIf(bad_span) => ParseError {
475 message: "A break if is only allowed in a continuing block".to_string(),
476 labels: vec![(bad_span, "not in a continuing block".into())],
477 notes: vec![],
478 },
479 Error::InvalidGatherComponent(bad_span) => ParseError {
480 message: format!(
481 "textureGather component '{}' doesn't exist, must be 0, 1, 2, or 3",
482 &source[bad_span]
483 ),
484 labels: vec![(bad_span, "invalid component".into())],
485 notes: vec![],
486 },
487 Error::InvalidConstructorComponentType(bad_span, component) => ParseError {
488 message: format!("invalid type for constructor component at index [{component}]"),
489 labels: vec![(bad_span, "invalid component type".into())],
490 notes: vec![],
491 },
492 Error::InvalidIdentifierUnderscore(bad_span) => ParseError {
493 message: "Identifier can't be '_'".to_string(),
494 labels: vec![(bad_span, "invalid identifier".into())],
495 notes: vec![
496 "Use phony assignment instead ('_ =' notice the absence of 'let' or 'var')"
497 .to_string(),
498 ],
499 },
500 Error::ReservedIdentifierPrefix(bad_span) => ParseError {
501 message: format!(
502 "Identifier starts with a reserved prefix: '{}'",
503 &source[bad_span]
504 ),
505 labels: vec![(bad_span, "invalid identifier".into())],
506 notes: vec![],
507 },
508 Error::UnknownAddressSpace(bad_span) => ParseError {
509 message: format!("unknown address space: '{}'", &source[bad_span]),
510 labels: vec![(bad_span, "unknown address space".into())],
511 notes: vec![],
512 },
513 Error::RepeatedAttribute(bad_span) => ParseError {
514 message: format!("repeated attribute: '{}'", &source[bad_span]),
515 labels: vec![(bad_span, "repeated attribute".into())],
516 notes: vec![],
517 },
518 Error::UnknownAttribute(bad_span) => ParseError {
519 message: format!("unknown attribute: '{}'", &source[bad_span]),
520 labels: vec![(bad_span, "unknown attribute".into())],
521 notes: vec![],
522 },
523 Error::UnknownBuiltin(bad_span) => ParseError {
524 message: format!("unknown builtin: '{}'", &source[bad_span]),
525 labels: vec![(bad_span, "unknown builtin".into())],
526 notes: vec![],
527 },
528 Error::UnknownAccess(bad_span) => ParseError {
529 message: format!("unknown access: '{}'", &source[bad_span]),
530 labels: vec![(bad_span, "unknown access".into())],
531 notes: vec![],
532 },
533 Error::UnknownStorageFormat(bad_span) => ParseError {
534 message: format!("unknown storage format: '{}'", &source[bad_span]),
535 labels: vec![(bad_span, "unknown storage format".into())],
536 notes: vec![],
537 },
538 Error::UnknownConservativeDepth(bad_span) => ParseError {
539 message: format!("unknown conservative depth: '{}'", &source[bad_span]),
540 labels: vec![(bad_span, "unknown conservative depth".into())],
541 notes: vec![],
542 },
543 Error::UnknownType(bad_span) => ParseError {
544 message: format!("unknown type: '{}'", &source[bad_span]),
545 labels: vec![(bad_span, "unknown type".into())],
546 notes: vec![],
547 },
548 Error::UnknownEnableExtension(span, word) => ParseError {
549 message: format!("unknown enable-extension `{}`", word),
550 labels: vec![(span, "".into())],
551 notes: vec![
552 "See available extensions at <https://www.w3.org/TR/WGSL/#enable-extension>."
553 .into(),
554 ],
555 },
556 Error::UnknownLanguageExtension(span, name) => ParseError {
557 message: format!("unknown language extension `{name}`"),
558 labels: vec![(span, "".into())],
559 notes: vec![concat!(
560 "See available extensions at ",
561 "<https://www.w3.org/TR/WGSL/#language-extensions-sec>."
562 )
563 .into()],
564 },
565 Error::SizeAttributeTooLow(bad_span, min_size) => ParseError {
566 message: format!("struct member size must be at least {min_size}"),
567 labels: vec![(bad_span, format!("must be at least {min_size}").into())],
568 notes: vec![],
569 },
570 Error::AlignAttributeTooLow(bad_span, min_align) => ParseError {
571 message: format!("struct member alignment must be at least {min_align}"),
572 labels: vec![(bad_span, format!("must be at least {min_align}").into())],
573 notes: vec![],
574 },
575 Error::NonPowerOfTwoAlignAttribute(bad_span) => ParseError {
576 message: "struct member alignment must be a power of 2".to_string(),
577 labels: vec![(bad_span, "must be a power of 2".into())],
578 notes: vec![],
579 },
580 Error::InconsistentBinding(span) => ParseError {
581 message: "input/output binding is not consistent".to_string(),
582 labels: vec![(span, "input/output binding is not consistent".into())],
583 notes: vec![],
584 },
585 Error::TypeNotConstructible(span) => ParseError {
586 message: format!("type `{}` is not constructible", &source[span]),
587 labels: vec![(span, "type is not constructible".into())],
588 notes: vec![],
589 },
590 Error::TypeNotInferable(span) => ParseError {
591 message: "type can't be inferred".to_string(),
592 labels: vec![(span, "type can't be inferred".into())],
593 notes: vec![],
594 },
595 Error::InitializationTypeMismatch {
596 name,
597 ref expected,
598 ref got,
599 } => ParseError {
600 message: format!(
601 "the type of `{}` is expected to be `{}`, but got `{}`",
602 &source[name], expected, got,
603 ),
604 labels: vec![(name, format!("definition of `{}`", &source[name]).into())],
605 notes: vec![],
606 },
607 Error::DeclMissingTypeAndInit(name_span) => ParseError {
608 message: format!(
609 "declaration of `{}` needs a type specifier or initializer",
610 &source[name_span]
611 ),
612 labels: vec![(name_span, "needs a type specifier or initializer".into())],
613 notes: vec![],
614 },
615 Error::MissingAttribute(name, name_span) => ParseError {
616 message: format!(
617 "variable `{}` needs a '{}' attribute",
618 &source[name_span], name
619 ),
620 labels: vec![(
621 name_span,
622 format!("definition of `{}`", &source[name_span]).into(),
623 )],
624 notes: vec![],
625 },
626 Error::InvalidAtomicPointer(span) => ParseError {
627 message: "atomic operation is done on a pointer to a non-atomic".to_string(),
628 labels: vec![(span, "atomic pointer is invalid".into())],
629 notes: vec![],
630 },
631 Error::InvalidAtomicOperandType(span) => ParseError {
632 message: "atomic operand type is inconsistent with the operation".to_string(),
633 labels: vec![(span, "atomic operand type is invalid".into())],
634 notes: vec![],
635 },
636 Error::InvalidRayQueryPointer(span) => ParseError {
637 message: "ray query operation is done on a pointer to a non-ray-query".to_string(),
638 labels: vec![(span, "ray query pointer is invalid".into())],
639 notes: vec![],
640 },
641 Error::NotPointer(span) => ParseError {
642 message: "the operand of the `*` operator must be a pointer".to_string(),
643 labels: vec![(span, "expression is not a pointer".into())],
644 notes: vec![],
645 },
646 Error::NotReference(what, span) => ParseError {
647 message: format!("{what} must be a reference"),
648 labels: vec![(span, "expression is not a reference".into())],
649 notes: vec![],
650 },
651 Error::InvalidAssignment { span, ty } => {
652 let (extra_label, notes) = match ty {
653 InvalidAssignmentType::Swizzle => (
654 None,
655 vec![
656 "WGSL does not support assignments to swizzles".into(),
657 "consider assigning each component individually".into(),
658 ],
659 ),
660 InvalidAssignmentType::ImmutableBinding(binding_span) => (
661 Some((binding_span, "this is an immutable binding".into())),
662 vec![format!(
663 "consider declaring '{}' with `var` instead of `let`",
664 &source[binding_span]
665 )],
666 ),
667 InvalidAssignmentType::Other => (None, vec![]),
668 };
669
670 ParseError {
671 message: "invalid left-hand side of assignment".into(),
672 labels: std::iter::once((span, "cannot assign to this expression".into()))
673 .chain(extra_label)
674 .collect(),
675 notes,
676 }
677 }
678 Error::Pointer(what, span) => ParseError {
679 message: format!("{what} must not be a pointer"),
680 labels: vec![(span, "expression is a pointer".into())],
681 notes: vec![],
682 },
683 Error::ReservedKeyword(name_span) => ParseError {
684 message: format!("name `{}` is a reserved keyword", &source[name_span]),
685 labels: vec![(
686 name_span,
687 format!("definition of `{}`", &source[name_span]).into(),
688 )],
689 notes: vec![],
690 },
691 Error::Redefinition { previous, current } => ParseError {
692 message: format!("redefinition of `{}`", &source[current]),
693 labels: vec![
694 (
695 current,
696 format!("redefinition of `{}`", &source[current]).into(),
697 ),
698 (
699 previous,
700 format!("previous definition of `{}`", &source[previous]).into(),
701 ),
702 ],
703 notes: vec![],
704 },
705 Error::RecursiveDeclaration { ident, usage } => ParseError {
706 message: format!("declaration of `{}` is recursive", &source[ident]),
707 labels: vec![(ident, "".into()), (usage, "uses itself here".into())],
708 notes: vec![],
709 },
710 Error::CyclicDeclaration { ident, ref path } => ParseError {
711 message: format!("declaration of `{}` is cyclic", &source[ident]),
712 labels: path
713 .iter()
714 .enumerate()
715 .flat_map(|(i, &(ident, usage))| {
716 [
717 (ident, "".into()),
718 (
719 usage,
720 if i == path.len() - 1 {
721 "ending the cycle".into()
722 } else {
723 format!("uses `{}`", &source[ident]).into()
724 },
725 ),
726 ]
727 })
728 .collect(),
729 notes: vec![],
730 },
731 Error::InvalidSwitchValue { uint, span } => ParseError {
732 message: "invalid switch value".to_string(),
733 labels: vec![(
734 span,
735 if uint {
736 "expected unsigned integer"
737 } else {
738 "expected signed integer"
739 }
740 .into(),
741 )],
742 notes: vec![if uint {
743 format!("suffix the integer with a `u`: '{}u'", &source[span])
744 } else {
745 let span = span.to_range().unwrap();
746 format!(
747 "remove the `u` suffix: '{}'",
748 &source[span.start..span.end - 1]
749 )
750 }],
751 },
752 Error::CalledEntryPoint(span) => ParseError {
753 message: "entry point cannot be called".to_string(),
754 labels: vec![(span, "entry point cannot be called".into())],
755 notes: vec![],
756 },
757 Error::WrongArgumentCount {
758 span,
759 ref expected,
760 found,
761 } => ParseError {
762 message: format!(
763 "wrong number of arguments: expected {}, found {}",
764 if expected.len() < 2 {
765 format!("{}", expected.start)
766 } else {
767 format!("{}..{}", expected.start, expected.end)
768 },
769 found
770 ),
771 labels: vec![(span, "wrong number of arguments".into())],
772 notes: vec![],
773 },
774 Error::FunctionReturnsVoid(span) => ParseError {
775 message: "function does not return any value".to_string(),
776 labels: vec![(span, "".into())],
777 notes: vec![
778 "perhaps you meant to call the function in a separate statement?".into(),
779 ],
780 },
781 Error::InvalidWorkGroupUniformLoad(span) => ParseError {
782 message: "incorrect type passed to workgroupUniformLoad".into(),
783 labels: vec![(span, "".into())],
784 notes: vec!["passed type must be a workgroup pointer".into()],
785 },
786 Error::Internal(message) => ParseError {
787 message: "internal WGSL front end error".to_string(),
788 labels: vec![],
789 notes: vec![message.into()],
790 },
791 Error::ExpectedConstExprConcreteIntegerScalar(span) => ParseError {
792 message: concat!(
793 "must be a const-expression that ",
794 "resolves to a concrete integer scalar (u32 or i32)"
795 )
796 .to_string(),
797 labels: vec![(span, "must resolve to u32 or i32".into())],
798 notes: vec![],
799 },
800 Error::ExpectedNonNegative(span) => ParseError {
801 message: "must be non-negative (>= 0)".to_string(),
802 labels: vec![(span, "must be non-negative".into())],
803 notes: vec![],
804 },
805 Error::ExpectedPositiveArrayLength(span) => ParseError {
806 message: "array element count must be positive (> 0)".to_string(),
807 labels: vec![(span, "must be positive".into())],
808 notes: vec![],
809 },
810 Error::ConstantEvaluatorError(ref e, span) => ParseError {
811 message: e.to_string(),
812 labels: vec![(span, "see msg".into())],
813 notes: vec![],
814 },
815 Error::MissingWorkgroupSize(span) => ParseError {
816 message: "workgroup size is missing on compute shader entry point".to_string(),
817 labels: vec![(
818 span,
819 "must be paired with a @workgroup_size attribute".into(),
820 )],
821 notes: vec![],
822 },
823 Error::AutoConversion(ref error) => {
824 let AutoConversionError {
826 dest_span,
827 ref dest_type,
828 source_span,
829 ref source_type,
830 } = **error;
831 ParseError {
832 message: format!(
833 "automatic conversions cannot convert `{}` to `{}`",
834 source_type, dest_type
835 ),
836 labels: vec![
837 (
838 dest_span,
839 format!("a value of type {dest_type} is required here").into(),
840 ),
841 (
842 source_span,
843 format!("this expression has type {source_type}").into(),
844 ),
845 ],
846 notes: vec![],
847 }
848 }
849 Error::AutoConversionLeafScalar(ref error) => {
850 let AutoConversionLeafScalarError {
851 dest_span,
852 ref dest_scalar,
853 source_span,
854 ref source_type,
855 } = **error;
856 ParseError {
857 message: format!(
858 "automatic conversions cannot convert elements of `{}` to `{}`",
859 source_type, dest_scalar
860 ),
861 labels: vec![
862 (
863 dest_span,
864 format!(
865 "a value with elements of type {} is required here",
866 dest_scalar
867 )
868 .into(),
869 ),
870 (
871 source_span,
872 format!("this expression has type {source_type}").into(),
873 ),
874 ],
875 notes: vec![],
876 }
877 }
878 Error::ConcretizationFailed(ref error) => {
879 let ConcretizationFailedError {
880 expr_span,
881 ref expr_type,
882 ref scalar,
883 ref inner,
884 } = **error;
885 ParseError {
886 message: format!("failed to convert expression to a concrete type: {inner}"),
887 labels: vec![(
888 expr_span,
889 format!("this expression has type {expr_type}").into(),
890 )],
891 notes: vec![format!(
892 "the expression should have been converted to have {} scalar type",
893 scalar
894 )],
895 }
896 }
897 Error::ExceededLimitForNestedBraces { span, limit } => ParseError {
898 message: "brace nesting limit reached".into(),
899 labels: vec![(span, "limit reached at this brace".into())],
900 notes: vec![format!("nesting limit is currently set to {limit}")],
901 },
902 Error::PipelineConstantIDValue(span) => ParseError {
903 message: "pipeline constant ID must be between 0 and 65535 inclusive".to_string(),
904 labels: vec![(span, "must be between 0 and 65535 inclusive".into())],
905 notes: vec![],
906 },
907 Error::NotBool(span) => ParseError {
908 message: "must be a const-expression that resolves to a bool".to_string(),
909 labels: vec![(span, "must resolve to bool".into())],
910 notes: vec![],
911 },
912 Error::ConstAssertFailed(span) => ParseError {
913 message: "const_assert failure".to_string(),
914 labels: vec![(span, "evaluates to false".into())],
915 notes: vec![],
916 },
917 Error::DirectiveNotYetImplemented { kind, span } => ParseError {
918 message: format!(
919 "the `{}` directive is not yet implemented",
920 DirectiveKind::Unimplemented(kind).to_ident()
921 ),
922 labels: vec![(
923 span,
924 "this global directive is standard, but not yet implemented".into(),
925 )],
926 notes: vec![format!(
927 concat!(
928 "Let Naga maintainers know that you ran into this at ",
929 "<https://github.com/gfx-rs/wgpu/issues/{}>, ",
930 "so they can prioritize it!"
931 ),
932 kind.tracking_issue_num()
933 )],
934 },
935 Error::DirectiveAfterFirstGlobalDecl { directive_span } => ParseError {
936 message: "expected global declaration, but found a global directive".into(),
937 labels: vec![(
938 directive_span,
939 "written after first global declaration".into(),
940 )],
941 notes: vec![concat!(
942 "global directives are only allowed before global declarations; ",
943 "maybe hoist this closer to the top of the shader module?"
944 )
945 .into()],
946 },
947 Error::EnableExtensionNotYetImplemented { kind, span } => ParseError {
948 message: format!(
949 "the `{}` enable-extension is not yet supported",
950 EnableExtension::Unimplemented(kind).to_ident()
951 ),
952 labels: vec![(
953 span,
954 concat!(
955 "this enable-extension specifies standard functionality ",
956 "which is not yet implemented in Naga"
957 )
958 .into(),
959 )],
960 notes: vec![format!(
961 concat!(
962 "Let Naga maintainers know that you ran into this at ",
963 "<https://github.com/gfx-rs/wgpu/issues/{}>, ",
964 "so they can prioritize it!"
965 ),
966 kind.tracking_issue_num()
967 )],
968 },
969 Error::EnableExtensionNotEnabled { kind, span } => ParseError {
970 message: format!("`{}` enable-extension is not enabled", kind.to_ident()),
971 labels: vec![(
972 span,
973 format!(
974 concat!(
975 "the `{}` enable-extension is needed for this functionality, ",
976 "but it is not currently enabled"
977 ),
978 kind.to_ident()
979 )
980 .into(),
981 )],
982 notes: if let EnableExtension::Unimplemented(kind) = kind {
983 vec![format!(
984 concat!(
985 "This enable-extension is not yet implemented. ",
986 "Let Naga maintainers know that you ran into this at ",
987 "<https://github.com/gfx-rs/wgpu/issues/{}>, ",
988 "so they can prioritize it!"
989 ),
990 kind.tracking_issue_num()
991 )]
992 } else {
993 vec![]
994 },
995 },
996 Error::LanguageExtensionNotYetImplemented { kind, span } => ParseError {
997 message: format!(
998 "the `{}` language extension is not yet supported",
999 LanguageExtension::Unimplemented(kind).to_ident()
1000 ),
1001 labels: vec![(span, "".into())],
1002 notes: vec![format!(
1003 concat!(
1004 "Let Naga maintainers know that you ran into this at ",
1005 "<https://github.com/gfx-rs/wgpu/issues/{}>, ",
1006 "so they can prioritize it!"
1007 ),
1008 kind.tracking_issue_num()
1009 )],
1010 },
1011 }
1012 }
1013}
1014
1015#[test]
1016fn test_error_size() {
1017 assert!(size_of::<Error<'_>>() <= 48);
1018}