1use crate::span::Span;
14use rustc_hash::FxHashSet as HashSet;
15use std::borrow::Cow;
16use std::fmt;
17use thiserror::Error;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
48pub struct ErrorCode(pub u16);
49
50impl ErrorCode {
51 pub const UNEXPECTED_CHARACTER: Self = Self(1);
55 pub const INVALID_INTEGER: Self = Self(2);
56 pub const INVALID_STRING_ESCAPE: Self = Self(3);
57 pub const UNTERMINATED_STRING: Self = Self(4);
58 pub const INVALID_FLOAT: Self = Self(5);
59 pub const EMPTY_CHAR_LIT: Self = Self(6);
60 pub const UNTERMINATED_CHAR_LIT: Self = Self(7);
61 pub const MULTI_CHAR_LIT: Self = Self(8);
62 pub const INVALID_CHAR_ESCAPE: Self = Self(9);
63 pub const INVALID_UNICODE_ESCAPE: Self = Self(10);
64
65 pub const UNEXPECTED_TOKEN: Self = Self(100);
69 pub const UNEXPECTED_EOF: Self = Self(101);
70 pub const PARSE_ERROR: Self = Self(102);
71
72 pub const NO_MAIN_FUNCTION: Self = Self(200);
76 pub const UNDEFINED_VARIABLE: Self = Self(201);
77 pub const UNDEFINED_FUNCTION: Self = Self(202);
78 pub const ASSIGN_TO_IMMUTABLE: Self = Self(203);
79 pub const UNKNOWN_TYPE: Self = Self(204);
80 pub const USE_AFTER_MOVE: Self = Self(205);
81 pub const TYPE_MISMATCH: Self = Self(206);
82 pub const WRONG_ARGUMENT_COUNT: Self = Self(207);
83
84 pub const MISSING_FIELDS: Self = Self(400);
88 pub const UNKNOWN_FIELD: Self = Self(401);
89 pub const DUPLICATE_FIELD: Self = Self(402);
90 pub const COPY_STRUCT_NON_COPY_FIELD: Self = Self(403);
91 pub const RESERVED_TYPE_NAME: Self = Self(404);
92 pub const DUPLICATE_TYPE_DEFINITION: Self = Self(405);
93 pub const LINEAR_VALUE_NOT_CONSUMED: Self = Self(406);
94 pub const LINEAR_STRUCT_COPY: Self = Self(407);
95 pub const DUPLICATE_METHOD: Self = Self(410);
96 pub const DERIVE_DIRECT_FIELD_ACCESS: Self = Self(440);
97 pub const DERIVE_NOT_A_DERIVE: Self = Self(441);
98 pub const UNKNOWN_DIRECTIVE: Self = Self(442);
99 pub const UNDEFINED_METHOD: Self = Self(411);
100 pub const PRIVATE_FIELD: Self = Self(443);
101 pub const UNDEFINED_ASSOC_FN: Self = Self(412);
102 pub const METHOD_CALL_ON_NON_STRUCT: Self = Self(413);
103 pub const METHOD_CALLED_AS_ASSOC_FN: Self = Self(414);
104 pub const ASSOC_FN_CALLED_AS_METHOD: Self = Self(415);
105 pub const DUPLICATE_DESTRUCTOR: Self = Self(416);
106 pub const DESTRUCTOR_UNKNOWN_TYPE: Self = Self(417);
107 pub const DUPLICATE_CONSTANT: Self = Self(418);
108 pub const CONST_EXPR_NOT_SUPPORTED: Self = Self(434);
109 pub const DUPLICATE_VARIANT: Self = Self(419);
110 pub const UNKNOWN_VARIANT: Self = Self(420);
111 pub const UNKNOWN_ENUM_TYPE: Self = Self(421);
112 pub const FIELD_WRONG_ORDER: Self = Self(422);
113 pub const FIELD_ACCESS_ON_NON_STRUCT: Self = Self(423);
114 pub const INVALID_ASSIGNMENT_TARGET: Self = Self(424);
115 pub const INOUT_NON_LVALUE: Self = Self(425);
116 pub const INOUT_EXCLUSIVE_ACCESS: Self = Self(426);
117 pub const BORROW_NON_LVALUE: Self = Self(427);
118 pub const MUTATE_BORROWED_VALUE: Self = Self(428);
119 pub const MOVE_OUT_OF_BORROW: Self = Self(429);
120 pub const BORROW_INOUT_CONFLICT: Self = Self(430);
121 pub const INOUT_KEYWORD_MISSING: Self = Self(431);
122 pub const BORROW_KEYWORD_MISSING: Self = Self(432);
123 pub const EMPTY_STRUCT: Self = Self(433);
124 pub const REFERENCE_ESCAPES_FUNCTION: Self = Self(434);
125
126 pub const BREAK_OUTSIDE_LOOP: Self = Self(500);
130 pub const CONTINUE_OUTSIDE_LOOP: Self = Self(501);
131 pub const INTRINSIC_REQUIRES_CHECKED: Self = Self(502);
132 pub const UNCHECKED_CALL_REQUIRES_CHECKED: Self = Self(503);
133 pub const UNCHECKED_DESTRUCTOR: Self = Self(504);
135 pub const EXTERN_FN_MISSING_UNCHECKED: Self = Self(505);
137 pub const INTERFACE_METHOD_UNCHECKED_MISMATCH: Self = Self(506);
139
140 pub const NON_EXHAUSTIVE_MATCH: Self = Self(600);
144 pub const EMPTY_MATCH: Self = Self(601);
145 pub const INVALID_MATCH_TYPE: Self = Self(602);
146
147 pub const UNKNOWN_INTRINSIC: Self = Self(700);
151 pub const INTRINSIC_WRONG_ARG_COUNT: Self = Self(701);
152 pub const INTRINSIC_TYPE_MISMATCH: Self = Self(702);
153 pub const IMPORT_REQUIRES_STRING_LITERAL: Self = Self(703);
154 pub const MODULE_NOT_FOUND: Self = Self(704);
155 pub const STD_LIB_NOT_FOUND: Self = Self(705);
156 pub const PRIVATE_MEMBER_ACCESS: Self = Self(706);
157 pub const UNKNOWN_MODULE_MEMBER: Self = Self(707);
158
159 pub const LITERAL_OUT_OF_RANGE: Self = Self(800);
163 pub const CANNOT_NEGATE_UNSIGNED: Self = Self(801);
164 pub const CHAINED_COMPARISON: Self = Self(802);
165
166 pub const INDEX_ON_NON_ARRAY: Self = Self(900);
170 pub const ARRAY_LENGTH_MISMATCH: Self = Self(901);
171 pub const INDEX_OUT_OF_BOUNDS: Self = Self(902);
172 pub const TYPE_ANNOTATION_REQUIRED: Self = Self(903);
173 pub const MOVE_OUT_OF_INDEX: Self = Self(904);
174
175 pub const LINK_ERROR: Self = Self(1000);
179 pub const UNSUPPORTED_TARGET: Self = Self(1001);
180
181 pub const PREVIEW_FEATURE_REQUIRED: Self = Self(1100);
185
186 pub const C_FFI: Self = Self(1500);
191
192 pub const INTERFACE_METHOD_MISSING: Self = Self(1400);
196 pub const INTERFACE_METHOD_SIGNATURE_MISMATCH: Self = Self(1401);
197
198 pub const REFUTABLE_PATTERN_IN_LET: Self = Self(1300);
203
204 pub const COMPTIME_EVALUATION_FAILED: Self = Self(1200);
208 pub const COMPTIME_ARG_NOT_CONST: Self = Self(1201);
209 pub const COMPTIME_USER_ERROR: Self = Self(1202);
210
211 pub const INVALID_LANG_ITEM: Self = Self(1300);
215
216 pub const INTERNAL_ERROR: Self = Self(9000);
220 pub const INTERNAL_CODEGEN_ERROR: Self = Self(9001);
221}
222
223impl fmt::Display for ErrorCode {
224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225 write!(f, "E{:04}", self.0)
226 }
227}
228
229#[derive(Debug, Clone, PartialEq, Eq)]
284pub struct MissingFieldsError {
285 pub struct_name: String,
286 pub missing_fields: Vec<String>,
287}
288
289#[derive(Debug, Clone, PartialEq, Eq)]
291pub struct CloneStructNonCopyFieldError {
292 pub struct_name: String,
293 pub field_name: String,
294 pub field_type: String,
295}
296
297#[derive(Debug, Clone, PartialEq, Eq)]
307pub struct PostureMismatchError {
308 pub host_kind: &'static str,
309 pub host_name: String,
310 pub declared_posture: &'static str,
311 pub member_kind: &'static str,
312 pub member_name: String,
313 pub member_type: String,
314 pub member_posture: &'static str,
315}
316
317#[derive(Debug, Clone, PartialEq, Eq)]
319pub struct IntrinsicTypeMismatchError {
320 pub name: String,
321 pub expected: String,
322 pub found: String,
323}
324
325#[derive(Debug, Clone, PartialEq, Eq)]
327pub struct FieldWrongOrderError {
328 pub struct_name: String,
329 pub expected_field: String,
330 pub found_field: String,
331}
332
333#[derive(Debug, Clone, PartialEq, Eq)]
338pub struct InterfaceMethodUncheckedMismatchError {
339 pub type_name: String,
340 pub interface_name: String,
341 pub method_name: String,
342 pub expected_unchecked: bool,
343 pub actual_unchecked: bool,
344}
345
346#[derive(
362 Debug,
363 Clone,
364 Copy,
365 PartialEq,
366 Eq,
367 Hash,
368 strum::Display,
369 strum::EnumString,
370 strum::EnumIter,
371 strum::IntoStaticStr,
372)]
373#[non_exhaustive]
374#[strum(serialize_all = "snake_case")]
375pub enum PreviewFeature {
376 TestInfra,
379}
380
381#[derive(Debug, Clone, PartialEq, Eq)]
383pub struct InterfaceMethodMissingData {
384 pub type_name: String,
385 pub interface_name: String,
386 pub method_name: String,
387 pub expected_signature: String,
388}
389
390#[derive(Debug, Clone, PartialEq, Eq)]
392pub struct InterfaceMethodSignatureMismatchData {
393 pub type_name: String,
394 pub interface_name: String,
395 pub method_name: String,
396 pub expected_signature: String,
397 pub found_signature: String,
398}
399
400impl PreviewFeature {
401 pub fn name(&self) -> &'static str {
403 (*self).into()
404 }
405
406 pub fn adr(&self) -> &'static str {
408 match *self {
409 PreviewFeature::TestInfra => "ADR-0005",
410 }
411 }
412
413 pub fn all() -> Vec<PreviewFeature> {
415 use strum::IntoEnumIterator;
416 PreviewFeature::iter().collect()
417 }
418
419 pub fn all_names() -> String {
421 let names: Vec<&'static str> = Self::all().iter().map(|f| f.name()).collect();
422 if names.is_empty() {
423 "(none)".to_string()
424 } else {
425 names.join(", ")
426 }
427 }
428}
429
430pub type PreviewFeatures = HashSet<PreviewFeature>;
432
433#[derive(Debug, Clone)]
442pub struct Label {
443 pub message: String,
445 pub span: Span,
447}
448
449impl Label {
450 pub fn new(message: impl Into<String>, span: Span) -> Self {
452 Self {
453 message: message.into(),
454 span,
455 }
456 }
457}
458
459#[derive(Debug, Clone)]
464pub struct Note(pub String);
465
466impl Note {
467 pub fn new(message: impl Into<String>) -> Self {
469 Self(message.into())
470 }
471}
472
473impl std::fmt::Display for Note {
474 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
475 write!(f, "{}", self.0)
476 }
477}
478
479#[derive(Debug, Clone)]
484pub struct Help(pub String);
485
486impl Help {
487 pub fn new(message: impl Into<String>) -> Self {
489 Self(message.into())
490 }
491}
492
493impl std::fmt::Display for Help {
494 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
495 write!(f, "{}", self.0)
496 }
497}
498
499#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
504pub enum Applicability {
505 MachineApplicable,
509
510 MaybeIncorrect,
515
516 HasPlaceholders,
521
522 #[default]
527 Unspecified,
528}
529
530impl std::fmt::Display for Applicability {
531 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
532 match self {
533 Applicability::MachineApplicable => write!(f, "MachineApplicable"),
534 Applicability::MaybeIncorrect => write!(f, "MaybeIncorrect"),
535 Applicability::HasPlaceholders => write!(f, "HasPlaceholders"),
536 Applicability::Unspecified => write!(f, "Unspecified"),
537 }
538 }
539}
540
541#[derive(Debug, Clone)]
546pub struct Suggestion {
547 pub message: String,
549 pub span: Span,
551 pub replacement: String,
553 pub applicability: Applicability,
555}
556
557impl Suggestion {
558 pub fn new(message: impl Into<String>, span: Span, replacement: impl Into<String>) -> Self {
560 Self {
561 message: message.into(),
562 span,
563 replacement: replacement.into(),
564 applicability: Applicability::Unspecified,
565 }
566 }
567
568 pub fn machine_applicable(
570 message: impl Into<String>,
571 span: Span,
572 replacement: impl Into<String>,
573 ) -> Self {
574 Self {
575 message: message.into(),
576 span,
577 replacement: replacement.into(),
578 applicability: Applicability::MachineApplicable,
579 }
580 }
581
582 pub fn maybe_incorrect(
584 message: impl Into<String>,
585 span: Span,
586 replacement: impl Into<String>,
587 ) -> Self {
588 Self {
589 message: message.into(),
590 span,
591 replacement: replacement.into(),
592 applicability: Applicability::MaybeIncorrect,
593 }
594 }
595
596 pub fn with_placeholders(
598 message: impl Into<String>,
599 span: Span,
600 replacement: impl Into<String>,
601 ) -> Self {
602 Self {
603 message: message.into(),
604 span,
605 replacement: replacement.into(),
606 applicability: Applicability::HasPlaceholders,
607 }
608 }
609
610 pub fn with_applicability(mut self, applicability: Applicability) -> Self {
612 self.applicability = applicability;
613 self
614 }
615}
616
617#[derive(Debug, Clone, Default)]
622pub struct Diagnostic {
623 pub labels: Vec<Label>,
625 pub notes: Vec<Note>,
627 pub helps: Vec<Help>,
629 pub suggestions: Vec<Suggestion>,
631}
632
633impl Diagnostic {
634 pub fn new() -> Self {
636 Self::default()
637 }
638
639 pub fn is_empty(&self) -> bool {
641 self.labels.is_empty()
642 && self.notes.is_empty()
643 && self.helps.is_empty()
644 && self.suggestions.is_empty()
645 }
646}
647
648#[derive(Debug, Clone)]
668#[must_use = "compiler diagnostics should not be ignored"]
669pub struct DiagnosticWrapper<K> {
670 pub kind: K,
672 span: Option<Span>,
673 diagnostic: Box<Diagnostic>,
674}
675
676impl<K> DiagnosticWrapper<K> {
677 #[inline]
679 pub fn new(kind: K, span: Span) -> Self {
680 Self {
681 kind,
682 span: Some(span),
683 diagnostic: Box::new(Diagnostic::new()),
684 }
685 }
686
687 #[inline]
692 pub fn without_span(kind: K) -> Self {
693 Self {
694 kind,
695 span: None,
696 diagnostic: Box::new(Diagnostic::new()),
697 }
698 }
699
700 #[inline]
702 pub fn has_span(&self) -> bool {
703 self.span.is_some()
704 }
705
706 #[inline]
708 pub fn span(&self) -> Option<Span> {
709 self.span
710 }
711
712 #[inline]
714 pub fn diagnostic(&self) -> &Diagnostic {
715 &self.diagnostic
716 }
717
718 #[inline]
722 pub fn with_label(mut self, message: impl Into<String>, span: Span) -> Self {
723 self.diagnostic.labels.push(Label::new(message, span));
724 self
725 }
726
727 #[inline]
731 pub fn with_note(mut self, message: impl Into<String>) -> Self {
732 self.diagnostic.notes.push(Note::new(message));
733 self
734 }
735
736 #[inline]
740 pub fn with_help(mut self, message: impl Into<String>) -> Self {
741 self.diagnostic.helps.push(Help::new(message));
742 self
743 }
744
745 #[inline]
749 pub fn with_suggestion(mut self, suggestion: Suggestion) -> Self {
750 self.diagnostic.suggestions.push(suggestion);
751 self
752 }
753}
754
755impl<K: fmt::Display> fmt::Display for DiagnosticWrapper<K> {
756 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
757 write!(f, "{}", self.kind)
758 }
759}
760
761impl<K: fmt::Display + fmt::Debug> std::error::Error for DiagnosticWrapper<K> {}
762
763pub type CompileError = DiagnosticWrapper<ErrorKind>;
780
781fn format_argument_count(expected: usize, found: usize) -> String {
784 if expected == 1 {
785 format!("expected {} argument, found {}", expected, found)
786 } else {
787 format!("expected {} arguments, found {}", expected, found)
788 }
789}
790
791fn format_missing_witnesses(missing: &[String]) -> String {
792 if missing.is_empty() {
793 return String::new();
794 }
795 let list = missing
796 .iter()
797 .map(|w| format!("`{}`", w))
798 .collect::<Vec<_>>()
799 .join(", ");
800 if missing.len() == 1 {
801 format!(": pattern {} not covered", list)
802 } else {
803 format!(": patterns {} not covered", list)
804 }
805}
806
807fn format_missing_fields(err: &MissingFieldsError) -> String {
808 if err.missing_fields.len() == 1 {
809 format!(
810 "missing field '{}' in struct '{}'",
811 err.missing_fields[0], err.struct_name
812 )
813 } else {
814 let fields = err
815 .missing_fields
816 .iter()
817 .map(|f| format!("'{}'", f))
818 .collect::<Vec<_>>()
819 .join(", ");
820 format!("missing fields {} in struct '{}'", fields, err.struct_name)
821 }
822}
823
824fn format_intrinsic_arg_count(name: &str, expected: usize, found: usize) -> String {
825 if expected == 1 {
826 format!(
827 "intrinsic '@{}' expects {} argument, found {}",
828 name, expected, found
829 )
830 } else {
831 format!(
832 "intrinsic '@{}' expects {} arguments, found {}",
833 name, expected, found
834 )
835 }
836}
837
838fn format_array_length_mismatch(expected: u64, found: u64) -> String {
839 if expected == 1 {
840 format!(
841 "expected array of {} element, found {} elements",
842 expected, found
843 )
844 } else {
845 format!(
846 "expected array of {} elements, found {} elements",
847 expected, found
848 )
849 }
850}
851
852#[derive(Debug, Clone, PartialEq, Eq, Error)]
854pub enum ErrorKind {
855 #[error("unexpected character: {0}")]
857 UnexpectedCharacter(char),
858 #[error("invalid integer literal")]
859 InvalidInteger,
860 #[error("invalid floating-point literal")]
861 InvalidFloat,
862 #[error("invalid escape sequence: \\{0}")]
863 InvalidStringEscape(char),
864 #[error("unterminated string literal")]
865 UnterminatedString,
866 #[error("empty char literal")]
868 EmptyCharLit,
869 #[error("unterminated char literal")]
871 UnterminatedCharLit,
872 #[error("char literal must contain exactly one Unicode scalar value")]
874 MultiCharLit,
875 #[error("invalid char escape sequence")]
877 InvalidCharEscape,
878 #[error("invalid unicode escape: not a valid Unicode scalar value")]
880 InvalidUnicodeEscape,
881
882 #[error("expected {expected}, found {found}")]
884 UnexpectedToken {
885 expected: Cow<'static, str>,
886 found: Cow<'static, str>,
887 },
888 #[error("unexpected end of file, expected {expected}")]
889 UnexpectedEof { expected: Cow<'static, str> },
890 #[error("{0}")]
894 ParseError(String),
895
896 #[error("{0}")]
901 CFfi(String),
902
903 #[error("no main function found")]
905 NoMainFunction,
906 #[error("undefined variable '{0}'")]
907 UndefinedVariable(String),
908 #[error("undefined function '{0}'")]
909 UndefinedFunction(String),
910 #[error("cannot assign to immutable variable '{0}'")]
911 AssignToImmutable(String),
912 #[error("unknown type '{0}'")]
913 UnknownType(String),
914 #[error("use of moved value '{0}'")]
916 UseAfterMove(String),
917 #[error("cannot move field `{field}` out of `{type_name}`")]
919 CannotMoveField { type_name: String, field: String },
920 #[error("type mismatch: expected {expected}, found {found}")]
921 TypeMismatch { expected: String, found: String },
922 #[error("{}", format_argument_count(*.expected, *.found))]
923 WrongArgumentCount { expected: usize, found: usize },
924
925 #[error("{}", format_missing_fields(.0))]
927 MissingFields(Box<MissingFieldsError>),
928 #[error("unknown field '{field_name}' in struct '{struct_name}'")]
929 UnknownField {
930 struct_name: String,
931 field_name: String,
932 },
933 #[error("field '{field_name}' of '{struct_name}' is private")]
936 PrivateField {
937 struct_name: String,
938 field_name: String,
939 },
940 #[error("duplicate field '{field_name}' in struct '{struct_name}'")]
941 DuplicateField {
942 struct_name: String,
943 field_name: String,
944 },
945 #[error("missing field `{field}` in destructuring of `{struct_name}`")]
947 MissingFieldInDestructure { struct_name: String, field: String },
948 #[error("empty struct is not allowed")]
950 EmptyStruct,
951 #[error("anonymous enum must have at least one variant")]
953 EmptyAnonEnum,
954 #[error("cannot define type `{type_name}`: name is reserved for built-in type")]
956 ReservedTypeName { type_name: String },
957 #[error("duplicate type definition: `{type_name}` is already defined")]
959 DuplicateTypeDefinition { type_name: String },
960 #[error("linear value '{0}' must be consumed but was dropped")]
962 LinearValueNotConsumed(String),
963 #[error("linear struct '{0}' cannot be marked `@derive(Copy)`")]
965 LinearStructCopy(String),
966 #[error("linear struct '{0}' cannot be marked `@derive(Clone)`")]
968 LinearStructClone(String),
969 #[error("@derive(Clone) on struct '{struct_name}' requires every field to be Copy in v1; field '{field_name}' has type '{field_type}' which is not Copy. Hand-write `fn clone(self: Ref(Self)) -> Self` instead.", struct_name = .0.struct_name, field_name = .0.field_name, field_type = .0.field_type)]
971 CloneStructNonCopyField(Box<CloneStructNonCopyFieldError>),
972 #[error(
974 "{declared_posture} {host_kind} '{host_name}' contains {member_posture} {member_kind} '{member_name}' of type '{member_type}'",
975 declared_posture = .0.declared_posture,
976 host_kind = .0.host_kind,
977 host_name = .0.host_name,
978 member_posture = .0.member_posture,
979 member_kind = .0.member_kind,
980 member_name = .0.member_name,
981 member_type = .0.member_type,
982 )]
983 PostureMismatch(Box<PostureMismatchError>),
984 #[error("unknown directive `@{name}`{}", note.as_deref().map(|n| format!("; {n}")).unwrap_or_default())]
988 UnknownDirective { name: String, note: Option<String> },
989 #[error("unknown marker `{name}`{}", note.as_deref().map(|n| format!("; {n}")).unwrap_or_default())]
991 UnknownMarker { name: String, note: Option<String> },
992 #[error("marker `{marker}` is not applicable to {item_kind}")]
995 MarkerNotApplicable {
996 marker: String,
997 item_kind: &'static str,
998 },
999 #[error(
1002 "conflicting thread-safety markers on type `{type_name}`: at most one of `unsend`, `checked_send`, `checked_sync` may be applied"
1003 )]
1004 ConflictingThreadSafetyMarkers { type_name: String },
1005 #[error(
1008 "@spawn argument of type `{arg_type}` is not Send (classified as Unsend); the spawned thread cannot take ownership across thread boundaries"
1009 )]
1010 SpawnArgNotSend { arg_type: String },
1011 #[error(
1013 "@spawn function `{fn_name}` returns `{ret_type}`, which is not Send (classified as Unsend); the join site cannot transfer the result back across the thread boundary"
1014 )]
1015 SpawnReturnNotSend { fn_name: String, ret_type: String },
1016 #[error(
1019 "@spawn argument of type `{arg_type}` is a reference; the spawned thread outlives the caller's scope so references cannot be passed across — move ownership instead"
1020 )]
1021 SpawnArgIsRef { arg_type: String },
1022 #[error(
1025 "@spawn argument of type `{arg_type}` is Linear; linear values cannot be transferred across threads in the v1 spawn surface"
1026 )]
1027 SpawnArgIsLinear { arg_type: String },
1028 #[error("@spawn function `{fn_name}` must take exactly one parameter; found {arity}")]
1032 SpawnFunctionWrongArity { fn_name: String, arity: usize },
1033 #[error("@spawn first argument must be a top-level function name; `{name}` did not resolve")]
1037 SpawnFunctionNotFound { name: String },
1038 #[error("duplicate method '{method_name}' for type '{type_name}'")]
1040 DuplicateMethod {
1041 type_name: String,
1042 method_name: String,
1043 },
1044 #[error(
1048 "direct field access on `self` is not allowed in `derive {derive_name}`; use `@field(self, \"...\")` because the host type is not known at derive-definition time"
1049 )]
1050 DeriveDirectFieldAccess {
1051 derive_name: String,
1052 method_name: String,
1053 },
1054 #[error("expected a `derive` item, found {found} `{name}`")]
1056 DeriveNotADerive {
1057 name: String,
1059 found: String,
1061 },
1062 #[error("no method named '{method_name}' found for type '{type_name}'")]
1064 UndefinedMethod {
1065 type_name: String,
1066 method_name: String,
1067 },
1068 #[error("no associated function named '{function_name}' found for type '{type_name}'")]
1070 UndefinedAssocFn {
1071 type_name: String,
1072 function_name: String,
1073 },
1074 #[error("no method named '{method_name}' on type '{found}'")]
1076 MethodCallOnNonStruct { found: String, method_name: String },
1077 #[error(
1079 "'{type_name}::{method_name}' is a method, not an associated function; use receiver.{method_name}() syntax"
1080 )]
1081 MethodCalledAsAssocFn {
1082 type_name: String,
1083 method_name: String,
1084 },
1085 #[error(
1087 "'{function_name}' is an associated function, not a method; use {type_name}::{function_name}() syntax"
1088 )]
1089 AssocFnCalledAsMethod {
1090 type_name: String,
1091 function_name: String,
1092 },
1093
1094 #[error("duplicate destructor for type '{type_name}'")]
1097 DuplicateDestructor { type_name: String },
1098 #[error("unknown type '{type_name}' in destructor")]
1100 DestructorUnknownType { type_name: String },
1101 #[error("invalid `fn __drop` on type '{type_name}': {reason}")]
1104 InvalidInlineDrop { type_name: String, reason: String },
1105
1106 #[error("duplicate {kind} '{name}'")]
1109 DuplicateConstant { name: String, kind: String },
1110 #[error("{expr_kind} is not supported in const context")]
1112 ConstExprNotSupported { expr_kind: String },
1113
1114 #[error("duplicate variant '{variant_name}' in enum '{enum_name}'")]
1116 DuplicateVariant {
1117 enum_name: String,
1118 variant_name: String,
1119 },
1120 #[error("unknown variant '{variant_name}' in enum '{enum_name}'")]
1121 UnknownVariant {
1122 enum_name: String,
1123 variant_name: String,
1124 },
1125 #[error("unknown enum type '{0}'")]
1126 UnknownEnumType(String),
1127 #[error("struct '{struct_name}' fields must be initialized in declaration order: expected '{expected_field}', found '{found_field}'", struct_name = .0.struct_name, expected_field = .0.expected_field, found_field = .0.found_field)]
1128 FieldWrongOrder(Box<FieldWrongOrderError>),
1129 #[error("field access on non-struct type '{found}'")]
1130 FieldAccessOnNonStruct { found: String },
1131 #[error("invalid assignment target")]
1132 InvalidAssignmentTarget,
1133 #[error("inout argument must be an lvalue (variable, field, or array element)")]
1135 InoutNonLvalue,
1136 #[error("cannot pass same variable '{variable}' to multiple inout parameters")]
1138 InoutExclusiveAccess { variable: String },
1139 #[error("borrow argument must be a variable, field, or array element")]
1141 BorrowNonLvalue,
1142 #[error("cannot mutate borrowed value '{variable}'")]
1144 MutateBorrowedValue { variable: String },
1145 #[error("cannot move out of borrowed value '{variable}'")]
1147 MoveOutOfBorrow { variable: String },
1148 #[error("cannot borrow '{variable}' while it is mutably borrowed (inout)")]
1150 BorrowInoutConflict { variable: String },
1151 #[error("argument to inout parameter must use 'inout' keyword")]
1153 InoutKeywordMissing,
1154 #[error("argument to borrow parameter must use 'borrow' keyword")]
1156 BorrowKeywordMissing,
1157 #[error("reference type `{type_name}` cannot escape the function it was constructed in")]
1160 ReferenceEscapesFunction { type_name: String },
1161
1162 #[error("'break' outside of loop")]
1164 BreakOutsideLoop,
1165 #[error(
1166 "'break' in for-in loop over array with non-Copy element type '{element_type}' would leak un-iterated elements"
1167 )]
1168 BreakInConsumingForLoop { element_type: String },
1169 #[error("'continue' outside of loop")]
1170 ContinueOutsideLoop,
1171
1172 #[error("intrinsic '@{0}' can only be used inside a `checked` block")]
1174 IntrinsicRequiresChecked(String),
1175 #[error("call to unchecked function '{0}' can only be used inside a `checked` block")]
1176 UncheckedCallRequiresChecked(String),
1177 #[error(
1181 "`@mark(unchecked)` is not allowed on `fn __drop`; drop glue runs implicitly at scope exit and cannot be gated by `checked {{ }}`"
1182 )]
1183 UncheckedDestructor,
1184 #[error(
1187 "extern fn `{fn_name}` in `link_extern(\"{library}\")` must be declared `@mark(unchecked) fn …`; FFI imports are unverified from the Gruel side"
1188 )]
1189 ExternFnMissingUnchecked { fn_name: String, library: String },
1190 #[error(
1195 "method `{method_name}` on type `{type_name}` does not conform to interface `{interface_name}`: interface declares it as {} but implementor declares it as {}",
1196 if .0.expected_unchecked { "`@mark(unchecked)`" } else { "checked" },
1197 if .0.actual_unchecked { "`@mark(unchecked)`" } else { "checked" },
1198 method_name = .0.method_name,
1199 type_name = .0.type_name,
1200 interface_name = .0.interface_name,
1201 )]
1202 InterfaceMethodUncheckedMismatch(Box<InterfaceMethodUncheckedMismatchError>),
1203
1204 #[error("match is not exhaustive{}", format_missing_witnesses(.missing))]
1211 NonExhaustiveMatch { missing: Vec<String> },
1212 #[error("match expression has no arms")]
1213 EmptyMatch,
1214 #[error("cannot match on type '{0}', expected integer, bool, or enum")]
1215 InvalidMatchType(String),
1216
1217 #[error("unknown intrinsic '@{0}'")]
1219 UnknownIntrinsic(String),
1220 #[error("{}", format_intrinsic_arg_count(name, *.expected, *.found))]
1221 IntrinsicWrongArgCount {
1222 name: String,
1223 expected: usize,
1224 found: usize,
1225 },
1226 #[error("intrinsic '@{name}' expects {expected}, found {found}", name = .0.name, expected = .0.expected, found = .0.found)]
1227 IntrinsicTypeMismatch(Box<IntrinsicTypeMismatchError>),
1228
1229 #[error("@import requires a string literal argument")]
1231 ImportRequiresStringLiteral,
1232 #[error("cannot find module '{path}'")]
1233 ModuleNotFound {
1234 path: String,
1235 candidates: Vec<String>,
1237 },
1238 #[error("standard library not found")]
1239 StdLibNotFound,
1240 #[error("{item_kind} `{name}` is private")]
1241 PrivateMemberAccess { item_kind: String, name: String },
1242 #[error("module `{module_name}` has no member `{member_name}`")]
1243 UnknownModuleMember {
1244 module_name: String,
1245 member_name: String,
1246 },
1247
1248 #[error("literal value {value} is out of range for type '{ty}'")]
1250 LiteralOutOfRange { value: u64, ty: String },
1251
1252 #[error("cannot apply unary operator `-` to type '{0}'")]
1254 CannotNegateUnsigned(String),
1255 #[error("comparison operators cannot be chained")]
1256 ChainedComparison,
1257
1258 #[error("cannot index into non-array type '{found}'")]
1260 IndexOnNonArray { found: String },
1261 #[error("{}", format_array_length_mismatch(*.expected, *.found))]
1262 ArrayLengthMismatch { expected: u64, found: u64 },
1263 #[error("index out of bounds: the length is {length} but the index is {index}")]
1264 IndexOutOfBounds { index: i64, length: u64 },
1265 #[error("type annotation required for empty array")]
1266 TypeAnnotationRequired,
1267 #[error("cannot move out of indexed position: element type '{element_type}' is not Copy")]
1269 MoveOutOfIndex { element_type: String },
1270
1271 #[error("link error: {0}")]
1273 LinkError(String),
1274
1275 #[error("unsupported target: {0}")]
1277 UnsupportedTarget(String),
1278
1279 #[error("{what} requires preview feature `{}`", .feature.name())]
1281 PreviewFeatureRequired {
1282 feature: PreviewFeature,
1283 what: String,
1284 },
1285
1286 #[error(
1289 "type `{}` does not conform to interface `{}`: missing method `{}`",
1290 .0.type_name,
1291 .0.interface_name,
1292 .0.method_name
1293 )]
1294 InterfaceMethodMissing(Box<InterfaceMethodMissingData>),
1295 #[error(
1298 "type `{}` does not conform to interface `{}`: method `{}` has the wrong signature",
1299 .0.type_name,
1300 .0.interface_name,
1301 .0.method_name
1302 )]
1303 InterfaceMethodSignatureMismatch(Box<InterfaceMethodSignatureMismatchData>),
1304
1305 #[error("refutable pattern in let binding: matches only a subset of possible values")]
1307 RefutablePatternInLet,
1308
1309 #[error("comptime evaluation failed: {reason}")]
1311 ComptimeEvaluationFailed { reason: String },
1312
1313 #[error("comptime parameter requires a compile-time known value")]
1314 ComptimeArgNotConst { param_name: String },
1315
1316 #[error("{0}")]
1317 ComptimeUserError(String),
1318
1319 #[error("invalid `@lang` directive: {reason}")]
1322 InvalidLangItem { reason: String },
1323
1324 #[error("internal compiler error: {0}")]
1326 InternalError(String),
1327
1328 #[error("internal codegen error: {0}")]
1330 InternalCodegenError(String),
1331}
1332
1333impl ErrorKind {
1334 pub fn code(&self) -> ErrorCode {
1339 match self {
1340 ErrorKind::UnexpectedCharacter(_) => ErrorCode::UNEXPECTED_CHARACTER,
1342 ErrorKind::InvalidInteger => ErrorCode::INVALID_INTEGER,
1343 ErrorKind::InvalidFloat => ErrorCode::INVALID_FLOAT,
1344 ErrorKind::InvalidStringEscape(_) => ErrorCode::INVALID_STRING_ESCAPE,
1345 ErrorKind::UnterminatedString => ErrorCode::UNTERMINATED_STRING,
1346 ErrorKind::EmptyCharLit => ErrorCode::EMPTY_CHAR_LIT,
1347 ErrorKind::UnterminatedCharLit => ErrorCode::UNTERMINATED_CHAR_LIT,
1348 ErrorKind::MultiCharLit => ErrorCode::MULTI_CHAR_LIT,
1349 ErrorKind::InvalidCharEscape => ErrorCode::INVALID_CHAR_ESCAPE,
1350 ErrorKind::InvalidUnicodeEscape => ErrorCode::INVALID_UNICODE_ESCAPE,
1351
1352 ErrorKind::UnexpectedToken { .. } => ErrorCode::UNEXPECTED_TOKEN,
1354 ErrorKind::UnexpectedEof { .. } => ErrorCode::UNEXPECTED_EOF,
1355 ErrorKind::ParseError(_) => ErrorCode::PARSE_ERROR,
1356
1357 ErrorKind::NoMainFunction => ErrorCode::NO_MAIN_FUNCTION,
1359 ErrorKind::UndefinedVariable(_) => ErrorCode::UNDEFINED_VARIABLE,
1360 ErrorKind::UndefinedFunction(_) => ErrorCode::UNDEFINED_FUNCTION,
1361 ErrorKind::AssignToImmutable(_) => ErrorCode::ASSIGN_TO_IMMUTABLE,
1362 ErrorKind::UnknownType(_) => ErrorCode::UNKNOWN_TYPE,
1363 ErrorKind::UseAfterMove(_) => ErrorCode::USE_AFTER_MOVE,
1364 ErrorKind::CannotMoveField { .. } => ErrorCode::USE_AFTER_MOVE,
1365 ErrorKind::TypeMismatch { .. } => ErrorCode::TYPE_MISMATCH,
1366 ErrorKind::WrongArgumentCount { .. } => ErrorCode::WRONG_ARGUMENT_COUNT,
1367
1368 ErrorKind::MissingFields(_) => ErrorCode::MISSING_FIELDS,
1370 ErrorKind::MissingFieldInDestructure { .. } => ErrorCode::MISSING_FIELDS,
1371 ErrorKind::UnknownField { .. } => ErrorCode::UNKNOWN_FIELD,
1372 ErrorKind::PrivateField { .. } => ErrorCode::PRIVATE_FIELD,
1373 ErrorKind::DuplicateField { .. } => ErrorCode::DUPLICATE_FIELD,
1374 ErrorKind::EmptyStruct => ErrorCode::EMPTY_STRUCT,
1375 ErrorKind::EmptyAnonEnum => ErrorCode::EMPTY_STRUCT, ErrorKind::ReservedTypeName { .. } => ErrorCode::RESERVED_TYPE_NAME,
1377 ErrorKind::DuplicateTypeDefinition { .. } => ErrorCode::DUPLICATE_TYPE_DEFINITION,
1378 ErrorKind::LinearValueNotConsumed(_) => ErrorCode::LINEAR_VALUE_NOT_CONSUMED,
1379 ErrorKind::LinearStructCopy(_) => ErrorCode::LINEAR_STRUCT_COPY,
1380 ErrorKind::LinearStructClone(_) => ErrorCode::LINEAR_STRUCT_COPY,
1381 ErrorKind::CloneStructNonCopyField { .. } => ErrorCode::COPY_STRUCT_NON_COPY_FIELD,
1382 ErrorKind::PostureMismatch { .. } => ErrorCode::COPY_STRUCT_NON_COPY_FIELD,
1383 ErrorKind::UnknownDirective { .. } => ErrorCode::UNKNOWN_DIRECTIVE,
1384 ErrorKind::UnknownMarker { .. } => ErrorCode::UNKNOWN_DIRECTIVE,
1385 ErrorKind::MarkerNotApplicable { .. } => ErrorCode::UNKNOWN_DIRECTIVE,
1386 ErrorKind::ConflictingThreadSafetyMarkers { .. } => ErrorCode::UNKNOWN_DIRECTIVE,
1387 ErrorKind::SpawnArgNotSend { .. } => ErrorCode::UNKNOWN_DIRECTIVE,
1388 ErrorKind::SpawnReturnNotSend { .. } => ErrorCode::UNKNOWN_DIRECTIVE,
1389 ErrorKind::SpawnArgIsRef { .. } => ErrorCode::UNKNOWN_DIRECTIVE,
1390 ErrorKind::SpawnArgIsLinear { .. } => ErrorCode::UNKNOWN_DIRECTIVE,
1391 ErrorKind::SpawnFunctionWrongArity { .. } => ErrorCode::UNKNOWN_DIRECTIVE,
1392 ErrorKind::SpawnFunctionNotFound { .. } => ErrorCode::UNKNOWN_DIRECTIVE,
1393 ErrorKind::DuplicateMethod { .. } => ErrorCode::DUPLICATE_METHOD,
1394 ErrorKind::DeriveDirectFieldAccess { .. } => ErrorCode::DERIVE_DIRECT_FIELD_ACCESS,
1395 ErrorKind::DeriveNotADerive { .. } => ErrorCode::DERIVE_NOT_A_DERIVE,
1396 ErrorKind::UndefinedMethod { .. } => ErrorCode::UNDEFINED_METHOD,
1397 ErrorKind::UndefinedAssocFn { .. } => ErrorCode::UNDEFINED_ASSOC_FN,
1398 ErrorKind::MethodCallOnNonStruct { .. } => ErrorCode::METHOD_CALL_ON_NON_STRUCT,
1399 ErrorKind::MethodCalledAsAssocFn { .. } => ErrorCode::METHOD_CALLED_AS_ASSOC_FN,
1400 ErrorKind::AssocFnCalledAsMethod { .. } => ErrorCode::ASSOC_FN_CALLED_AS_METHOD,
1401 ErrorKind::DuplicateDestructor { .. } => ErrorCode::DUPLICATE_DESTRUCTOR,
1402 ErrorKind::DestructorUnknownType { .. } => ErrorCode::DESTRUCTOR_UNKNOWN_TYPE,
1403 ErrorKind::InvalidInlineDrop { .. } => ErrorCode::DUPLICATE_DESTRUCTOR,
1404 ErrorKind::DuplicateConstant { .. } => ErrorCode::DUPLICATE_CONSTANT,
1405 ErrorKind::ConstExprNotSupported { .. } => ErrorCode::CONST_EXPR_NOT_SUPPORTED,
1406 ErrorKind::DuplicateVariant { .. } => ErrorCode::DUPLICATE_VARIANT,
1407 ErrorKind::UnknownVariant { .. } => ErrorCode::UNKNOWN_VARIANT,
1408 ErrorKind::UnknownEnumType(_) => ErrorCode::UNKNOWN_ENUM_TYPE,
1409 ErrorKind::FieldWrongOrder(_) => ErrorCode::FIELD_WRONG_ORDER,
1410 ErrorKind::FieldAccessOnNonStruct { .. } => ErrorCode::FIELD_ACCESS_ON_NON_STRUCT,
1411 ErrorKind::InvalidAssignmentTarget => ErrorCode::INVALID_ASSIGNMENT_TARGET,
1412 ErrorKind::InoutNonLvalue => ErrorCode::INOUT_NON_LVALUE,
1413 ErrorKind::InoutExclusiveAccess { .. } => ErrorCode::INOUT_EXCLUSIVE_ACCESS,
1414 ErrorKind::BorrowNonLvalue => ErrorCode::BORROW_NON_LVALUE,
1415 ErrorKind::MutateBorrowedValue { .. } => ErrorCode::MUTATE_BORROWED_VALUE,
1416 ErrorKind::MoveOutOfBorrow { .. } => ErrorCode::MOVE_OUT_OF_BORROW,
1417 ErrorKind::BorrowInoutConflict { .. } => ErrorCode::BORROW_INOUT_CONFLICT,
1418 ErrorKind::InoutKeywordMissing => ErrorCode::INOUT_KEYWORD_MISSING,
1419 ErrorKind::BorrowKeywordMissing => ErrorCode::BORROW_KEYWORD_MISSING,
1420 ErrorKind::ReferenceEscapesFunction { .. } => ErrorCode::REFERENCE_ESCAPES_FUNCTION,
1421
1422 ErrorKind::BreakOutsideLoop => ErrorCode::BREAK_OUTSIDE_LOOP,
1424 ErrorKind::BreakInConsumingForLoop { .. } => ErrorCode::BREAK_OUTSIDE_LOOP,
1425 ErrorKind::ContinueOutsideLoop => ErrorCode::CONTINUE_OUTSIDE_LOOP,
1426 ErrorKind::IntrinsicRequiresChecked(_) => ErrorCode::INTRINSIC_REQUIRES_CHECKED,
1427 ErrorKind::UncheckedCallRequiresChecked(_) => {
1428 ErrorCode::UNCHECKED_CALL_REQUIRES_CHECKED
1429 }
1430 ErrorKind::UncheckedDestructor => ErrorCode::UNCHECKED_DESTRUCTOR,
1431 ErrorKind::ExternFnMissingUnchecked { .. } => ErrorCode::EXTERN_FN_MISSING_UNCHECKED,
1432 ErrorKind::InterfaceMethodUncheckedMismatch(_) => {
1433 ErrorCode::INTERFACE_METHOD_UNCHECKED_MISMATCH
1434 }
1435
1436 ErrorKind::NonExhaustiveMatch { .. } => ErrorCode::NON_EXHAUSTIVE_MATCH,
1438 ErrorKind::EmptyMatch => ErrorCode::EMPTY_MATCH,
1439 ErrorKind::InvalidMatchType(_) => ErrorCode::INVALID_MATCH_TYPE,
1440
1441 ErrorKind::UnknownIntrinsic(_) => ErrorCode::UNKNOWN_INTRINSIC,
1443 ErrorKind::IntrinsicWrongArgCount { .. } => ErrorCode::INTRINSIC_WRONG_ARG_COUNT,
1444 ErrorKind::IntrinsicTypeMismatch(_) => ErrorCode::INTRINSIC_TYPE_MISMATCH,
1445 ErrorKind::ImportRequiresStringLiteral => ErrorCode::IMPORT_REQUIRES_STRING_LITERAL,
1446 ErrorKind::ModuleNotFound { .. } => ErrorCode::MODULE_NOT_FOUND,
1447 ErrorKind::StdLibNotFound => ErrorCode::STD_LIB_NOT_FOUND,
1448 ErrorKind::PrivateMemberAccess { .. } => ErrorCode::PRIVATE_MEMBER_ACCESS,
1449 ErrorKind::UnknownModuleMember { .. } => ErrorCode::UNKNOWN_MODULE_MEMBER,
1450
1451 ErrorKind::LiteralOutOfRange { .. } => ErrorCode::LITERAL_OUT_OF_RANGE,
1453 ErrorKind::CannotNegateUnsigned(_) => ErrorCode::CANNOT_NEGATE_UNSIGNED,
1454 ErrorKind::ChainedComparison => ErrorCode::CHAINED_COMPARISON,
1455
1456 ErrorKind::IndexOnNonArray { .. } => ErrorCode::INDEX_ON_NON_ARRAY,
1458 ErrorKind::ArrayLengthMismatch { .. } => ErrorCode::ARRAY_LENGTH_MISMATCH,
1459 ErrorKind::IndexOutOfBounds { .. } => ErrorCode::INDEX_OUT_OF_BOUNDS,
1460 ErrorKind::TypeAnnotationRequired => ErrorCode::TYPE_ANNOTATION_REQUIRED,
1461 ErrorKind::MoveOutOfIndex { .. } => ErrorCode::MOVE_OUT_OF_INDEX,
1462
1463 ErrorKind::LinkError(_) => ErrorCode::LINK_ERROR,
1465 ErrorKind::UnsupportedTarget(_) => ErrorCode::UNSUPPORTED_TARGET,
1466
1467 ErrorKind::PreviewFeatureRequired { .. } => ErrorCode::PREVIEW_FEATURE_REQUIRED,
1469 ErrorKind::InterfaceMethodMissing { .. } => ErrorCode::INTERFACE_METHOD_MISSING,
1470 ErrorKind::InterfaceMethodSignatureMismatch { .. } => {
1471 ErrorCode::INTERFACE_METHOD_SIGNATURE_MISMATCH
1472 }
1473
1474 ErrorKind::RefutablePatternInLet => ErrorCode::REFUTABLE_PATTERN_IN_LET,
1476
1477 ErrorKind::ComptimeEvaluationFailed { .. } => ErrorCode::COMPTIME_EVALUATION_FAILED,
1479 ErrorKind::ComptimeArgNotConst { .. } => ErrorCode::COMPTIME_ARG_NOT_CONST,
1480 ErrorKind::ComptimeUserError(_) => ErrorCode::COMPTIME_USER_ERROR,
1481 ErrorKind::InvalidLangItem { .. } => ErrorCode::INVALID_LANG_ITEM,
1482
1483 ErrorKind::CFfi(_) => ErrorCode::C_FFI,
1485
1486 ErrorKind::InternalError(_) => ErrorCode::INTERNAL_ERROR,
1488 ErrorKind::InternalCodegenError(_) => ErrorCode::INTERNAL_CODEGEN_ERROR,
1489 }
1490 }
1491}
1492
1493impl CompileError {
1494 #[inline]
1496 pub fn at(kind: ErrorKind, pos: u32) -> Self {
1497 Self {
1498 kind,
1499 span: Some(Span::point(pos)),
1500 diagnostic: Box::new(Diagnostic::new()),
1501 }
1502 }
1503
1504 pub fn use_after_move(name: impl Into<String>, use_span: Span, moved_span: Span) -> Self {
1507 Self::new(ErrorKind::UseAfterMove(name.into()), use_span)
1508 .with_label("value moved here", moved_span)
1509 }
1510
1511 pub fn type_mismatch(
1513 expected: impl Into<String>,
1514 found: impl Into<String>,
1515 span: Span,
1516 ) -> Self {
1517 Self::new(
1518 ErrorKind::TypeMismatch {
1519 expected: expected.into(),
1520 found: found.into(),
1521 },
1522 span,
1523 )
1524 }
1525}
1526
1527pub type CompileResult<T> = Result<T, CompileError>;
1529
1530#[derive(Debug, Clone)]
1562pub struct CompileErrors {
1563 errors: Vec<CompileError>,
1564}
1565
1566impl CompileErrors {
1567 pub fn new() -> Self {
1569 Self { errors: Vec::new() }
1570 }
1571
1572 pub fn from_error(error: CompileError) -> Self {
1574 Self {
1575 errors: vec![error],
1576 }
1577 }
1578
1579 pub fn push(&mut self, error: CompileError) {
1581 self.errors.push(error);
1582 }
1583
1584 pub fn extend(&mut self, other: CompileErrors) {
1586 self.errors.extend(other.errors);
1587 }
1588
1589 pub fn is_empty(&self) -> bool {
1591 self.errors.is_empty()
1592 }
1593
1594 pub fn len(&self) -> usize {
1596 self.errors.len()
1597 }
1598
1599 pub fn first(&self) -> Option<&CompileError> {
1601 self.errors.first()
1602 }
1603
1604 pub fn iter(&self) -> impl Iterator<Item = &CompileError> {
1606 self.errors.iter()
1607 }
1608
1609 pub fn as_slice(&self) -> &[CompileError] {
1611 &self.errors
1612 }
1613
1614 pub fn into_result(self) -> Result<(), CompileErrors> {
1618 if self.is_empty() { Ok(()) } else { Err(self) }
1619 }
1620
1621 pub fn into_result_with<T>(self, value: T) -> Result<T, CompileErrors> {
1629 if self.is_empty() {
1630 Ok(value)
1631 } else {
1632 Err(self)
1633 }
1634 }
1635}
1636
1637impl Default for CompileErrors {
1638 fn default() -> Self {
1639 Self::new()
1640 }
1641}
1642
1643impl IntoIterator for CompileErrors {
1644 type Item = CompileError;
1645 type IntoIter = std::vec::IntoIter<CompileError>;
1646
1647 fn into_iter(self) -> Self::IntoIter {
1648 self.errors.into_iter()
1649 }
1650}
1651
1652impl From<CompileError> for CompileErrors {
1653 fn from(error: CompileError) -> Self {
1654 Self::from_error(error)
1655 }
1656}
1657
1658impl From<Vec<CompileError>> for CompileErrors {
1659 fn from(errors: Vec<CompileError>) -> Self {
1660 Self { errors }
1661 }
1662}
1663
1664impl From<CompileErrors> for CompileError {
1665 fn from(errors: CompileErrors) -> Self {
1670 debug_assert!(
1671 !errors.is_empty(),
1672 "converting empty CompileErrors to CompileError"
1673 );
1674 errors.errors.into_iter().next().unwrap_or_else(|| {
1675 CompileError::without_span(ErrorKind::InternalError(
1676 "empty error collection converted to single error".into(),
1677 ))
1678 })
1679 }
1680}
1681
1682impl fmt::Display for CompileErrors {
1683 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1684 match self.errors.len() {
1685 0 => write!(f, "no errors"),
1686 1 => write!(f, "{}", self.errors[0]),
1687 n => write!(
1688 f,
1689 "{} (and {} more error{})",
1690 self.errors[0],
1691 n - 1,
1692 if n == 2 { "" } else { "s" }
1693 ),
1694 }
1695 }
1696}
1697
1698impl std::error::Error for CompileErrors {}
1699
1700pub type MultiErrorResult<T> = Result<T, CompileErrors>;
1702
1703pub trait OptionExt<T> {
1720 fn ok_or_compile_error(self, kind: ErrorKind, span: Span) -> CompileResult<T>;
1722}
1723
1724impl<T> OptionExt<T> for Option<T> {
1725 #[inline]
1726 fn ok_or_compile_error(self, kind: ErrorKind, span: Span) -> CompileResult<T> {
1727 self.ok_or_else(|| CompileError::new(kind, span))
1728 }
1729}
1730
1731#[derive(Debug, Clone, PartialEq, Eq, Error)]
1733pub enum WarningKind {
1734 #[error("unused variable '{0}'")]
1736 UnusedVariable(String),
1737 #[error("unused function '{0}'")]
1739 UnusedFunction(String),
1740 #[error("unreachable code")]
1742 UnreachableCode,
1743 #[error("unreachable pattern '{0}'")]
1745 UnreachablePattern(String),
1746 #[error("comptime debug statement present — remove before release")]
1748 ComptimeDbgPresent(String),
1749}
1750
1751pub type CompileWarning = DiagnosticWrapper<WarningKind>;
1761
1762impl WarningKind {
1763 pub fn unused_variable_name(&self) -> Option<&str> {
1765 match self {
1766 WarningKind::UnusedVariable(name) => Some(name),
1767 _ => None,
1768 }
1769 }
1770
1771 pub fn format_with_line(&self, line_number: Option<usize>) -> String {
1777 match (self, line_number) {
1778 (WarningKind::UnusedVariable(name), Some(line)) => {
1779 format!("unused variable '{}' (line {})", name, line)
1780 }
1781 (WarningKind::UnusedFunction(name), Some(line)) => {
1782 format!("unused function '{}' (line {})", name, line)
1783 }
1784 _ => self.to_string(),
1785 }
1786 }
1787}
1788
1789#[cfg(test)]
1790mod tests {
1791 use super::*;
1792
1793 #[test]
1794 fn test_error_with_span() {
1795 let span = Span::new(10, 20);
1796 let error = CompileError::new(ErrorKind::InvalidInteger, span);
1797
1798 assert!(error.has_span());
1799 assert_eq!(error.span(), Some(span));
1800 assert_eq!(error.to_string(), "invalid integer literal");
1801 }
1802
1803 #[test]
1804 fn test_error_without_span() {
1805 let error = CompileError::without_span(ErrorKind::NoMainFunction);
1806
1807 assert!(!error.has_span());
1808 assert_eq!(error.span(), None);
1809 assert_eq!(error.to_string(), "no main function found");
1810 }
1811
1812 #[test]
1813 fn test_error_at_position() {
1814 let error = CompileError::at(ErrorKind::InvalidInteger, 42);
1815
1816 assert!(error.has_span());
1817 assert_eq!(error.span(), Some(Span::point(42)));
1818 }
1819
1820 #[test]
1821 fn test_error_messages() {
1822 let cases: Vec<(ErrorKind, &str)> = vec![
1823 (
1824 ErrorKind::UnexpectedCharacter('@'),
1825 "unexpected character: @",
1826 ),
1827 (
1828 ErrorKind::UnexpectedToken {
1829 expected: Cow::Borrowed("identifier"),
1830 found: Cow::Borrowed("'+'"),
1831 },
1832 "expected identifier, found '+'",
1833 ),
1834 (
1835 ErrorKind::UnexpectedEof {
1836 expected: Cow::Borrowed("'}'"),
1837 },
1838 "unexpected end of file, expected '}'",
1839 ),
1840 (
1841 ErrorKind::ParseError("custom parse error".into()),
1842 "custom parse error",
1843 ),
1844 (
1845 ErrorKind::UndefinedVariable("foo".into()),
1846 "undefined variable 'foo'",
1847 ),
1848 (
1849 ErrorKind::UndefinedFunction("bar".into()),
1850 "undefined function 'bar'",
1851 ),
1852 (
1853 ErrorKind::AssignToImmutable("x".into()),
1854 "cannot assign to immutable variable 'x'",
1855 ),
1856 (ErrorKind::UnknownType("Foo".into()), "unknown type 'Foo'"),
1857 (
1858 ErrorKind::TypeMismatch {
1859 expected: "i32".into(),
1860 found: "bool".into(),
1861 },
1862 "type mismatch: expected i32, found bool",
1863 ),
1864 (
1865 ErrorKind::WrongArgumentCount {
1866 expected: 1,
1867 found: 3,
1868 },
1869 "expected 1 argument, found 3",
1870 ),
1871 (
1872 ErrorKind::WrongArgumentCount {
1873 expected: 2,
1874 found: 0,
1875 },
1876 "expected 2 arguments, found 0",
1877 ),
1878 (
1879 ErrorKind::LinkError("undefined symbol".into()),
1880 "link error: undefined symbol",
1881 ),
1882 ];
1883 for (kind, expected) in cases {
1884 let error = CompileError::without_span(kind);
1885 assert_eq!(error.to_string(), expected);
1886 }
1887 }
1888
1889 #[test]
1890 fn test_error_kind_equality() {
1891 assert_eq!(ErrorKind::InvalidInteger, ErrorKind::InvalidInteger);
1892 assert_eq!(ErrorKind::NoMainFunction, ErrorKind::NoMainFunction);
1893 assert_ne!(ErrorKind::InvalidInteger, ErrorKind::NoMainFunction);
1894 }
1895
1896 #[test]
1897 fn test_error_implements_std_error() {
1898 fn assert_error<T: std::error::Error>() {}
1899 assert_error::<CompileError>();
1900 }
1901
1902 #[test]
1907 fn test_diagnostic_empty_by_default() {
1908 let diag = Diagnostic::new();
1909 assert!(diag.is_empty());
1910 assert!(diag.labels.is_empty());
1911 assert!(diag.notes.is_empty());
1912 assert!(diag.helps.is_empty());
1913 assert!(diag.suggestions.is_empty());
1914 }
1915
1916 #[test]
1917 fn test_diagnostic_not_empty() {
1918 let mut diag = Diagnostic::new();
1920 diag.labels.push(Label::new("test", Span::new(0, 10)));
1921 assert!(!diag.is_empty());
1922
1923 let mut diag = Diagnostic::new();
1925 diag.notes.push(Note::new("test note"));
1926 assert!(!diag.is_empty());
1927
1928 let mut diag = Diagnostic::new();
1930 diag.helps.push(Help::new("test help"));
1931 assert!(!diag.is_empty());
1932
1933 let mut diag = Diagnostic::new();
1935 diag.suggestions
1936 .push(Suggestion::new("try this", Span::new(0, 10), "replacement"));
1937 assert!(!diag.is_empty());
1938 }
1939
1940 #[test]
1941 fn test_label_creation() {
1942 let span = Span::new(10, 20);
1943 let label = Label::new("expected type here", span);
1944 assert_eq!(label.message, "expected type here");
1945 assert_eq!(label.span, span);
1946 }
1947
1948 #[test]
1949 fn test_note_display() {
1950 let note = Note::new("types must match exactly");
1951 assert_eq!(note.to_string(), "types must match exactly");
1952 }
1953
1954 #[test]
1955 fn test_help_display() {
1956 let help = Help::new("consider adding a type annotation");
1957 assert_eq!(help.to_string(), "consider adding a type annotation");
1958 }
1959
1960 #[test]
1961 fn test_suggestion_creation() {
1962 let span = Span::new(10, 20);
1963 let suggestion = Suggestion::new("try this fix", span, "new_code");
1964 assert_eq!(suggestion.message, "try this fix");
1965 assert_eq!(suggestion.span, span);
1966 assert_eq!(suggestion.replacement, "new_code");
1967 assert_eq!(suggestion.applicability, Applicability::Unspecified);
1968 }
1969
1970 #[test]
1971 fn test_suggestion_machine_applicable() {
1972 let span = Span::new(0, 5);
1973 let suggestion = Suggestion::machine_applicable("rename variable", span, "new_name");
1974 assert_eq!(suggestion.applicability, Applicability::MachineApplicable);
1975 }
1976
1977 #[test]
1978 fn test_suggestion_maybe_incorrect() {
1979 let span = Span::new(0, 5);
1980 let suggestion = Suggestion::maybe_incorrect("try adding mut", span, "mut x");
1981 assert_eq!(suggestion.applicability, Applicability::MaybeIncorrect);
1982 }
1983
1984 #[test]
1985 fn test_suggestion_with_placeholders() {
1986 let span = Span::new(0, 5);
1987 let suggestion = Suggestion::with_placeholders("add type annotation", span, ": <type>");
1988 assert_eq!(suggestion.applicability, Applicability::HasPlaceholders);
1989 }
1990
1991 #[test]
1992 fn test_suggestion_with_applicability() {
1993 let span = Span::new(0, 5);
1994 let suggestion = Suggestion::new("fix", span, "new_code")
1995 .with_applicability(Applicability::MachineApplicable);
1996 assert_eq!(suggestion.applicability, Applicability::MachineApplicable);
1997 }
1998
1999 #[test]
2000 fn test_applicability_display() {
2001 assert_eq!(
2002 Applicability::MachineApplicable.to_string(),
2003 "MachineApplicable"
2004 );
2005 assert_eq!(Applicability::MaybeIncorrect.to_string(), "MaybeIncorrect");
2006 assert_eq!(
2007 Applicability::HasPlaceholders.to_string(),
2008 "HasPlaceholders"
2009 );
2010 assert_eq!(Applicability::Unspecified.to_string(), "Unspecified");
2011 }
2012
2013 #[test]
2014 fn test_applicability_default() {
2015 assert_eq!(Applicability::default(), Applicability::Unspecified);
2016 }
2017
2018 #[test]
2019 fn test_error_with_suggestion() {
2020 let span = Span::new(10, 20);
2021 let error =
2022 CompileError::new(ErrorKind::AssignToImmutable("x".to_string()), span).with_suggestion(
2023 Suggestion::machine_applicable("add mut", Span::new(4, 5), "mut x"),
2024 );
2025
2026 let diag = error.diagnostic();
2027 assert_eq!(diag.suggestions.len(), 1);
2028 assert_eq!(diag.suggestions[0].message, "add mut");
2029 assert_eq!(diag.suggestions[0].replacement, "mut x");
2030 assert_eq!(
2031 diag.suggestions[0].applicability,
2032 Applicability::MachineApplicable
2033 );
2034 }
2035
2036 #[test]
2037 fn test_error_with_label() {
2038 let span = Span::new(10, 20);
2039 let label_span = Span::new(0, 5);
2040 let error = CompileError::new(
2041 ErrorKind::TypeMismatch {
2042 expected: "i32".to_string(),
2043 found: "bool".to_string(),
2044 },
2045 span,
2046 )
2047 .with_label("expected because of this", label_span);
2048
2049 let diag = error.diagnostic();
2050 assert_eq!(diag.labels.len(), 1);
2051 assert_eq!(diag.labels[0].message, "expected because of this");
2052 assert_eq!(diag.labels[0].span, label_span);
2053 }
2054
2055 #[test]
2056 fn test_error_with_note() {
2057 let span = Span::new(10, 20);
2058 let error = CompileError::new(
2059 ErrorKind::TypeMismatch {
2060 expected: "i32".to_string(),
2061 found: "bool".to_string(),
2062 },
2063 span,
2064 )
2065 .with_note("if and else branches must have compatible types");
2066
2067 let diag = error.diagnostic();
2068 assert_eq!(diag.notes.len(), 1);
2069 assert_eq!(
2070 diag.notes[0].to_string(),
2071 "if and else branches must have compatible types"
2072 );
2073 }
2074
2075 #[test]
2076 fn test_error_with_help() {
2077 let span = Span::new(10, 20);
2078 let error = CompileError::new(ErrorKind::AssignToImmutable("x".to_string()), span)
2079 .with_help("consider making `x` mutable: `let mut x`");
2080
2081 let diag = error.diagnostic();
2082 assert_eq!(diag.helps.len(), 1);
2083 assert_eq!(
2084 diag.helps[0].to_string(),
2085 "consider making `x` mutable: `let mut x`"
2086 );
2087 }
2088
2089 #[test]
2090 fn test_error_with_multiple_diagnostics() {
2091 let span = Span::new(10, 20);
2092 let label_span = Span::new(0, 5);
2093 let error = CompileError::new(
2094 ErrorKind::TypeMismatch {
2095 expected: "i32".to_string(),
2096 found: "bool".to_string(),
2097 },
2098 span,
2099 )
2100 .with_label("then branch is here", label_span)
2101 .with_note("if and else branches must have compatible types")
2102 .with_help("consider using a type conversion");
2103
2104 let diag = error.diagnostic();
2105 assert_eq!(diag.labels.len(), 1);
2106 assert_eq!(diag.notes.len(), 1);
2107 assert_eq!(diag.helps.len(), 1);
2108 }
2109
2110 #[test]
2111 fn test_error_diagnostic_empty_by_default() {
2112 let span = Span::new(10, 20);
2113 let error = CompileError::new(ErrorKind::InvalidInteger, span);
2114 assert!(error.diagnostic().is_empty());
2115 }
2116
2117 #[test]
2118 fn test_warning_with_help() {
2119 let span = Span::new(10, 20);
2120 let warning = CompileWarning::new(WarningKind::UnusedVariable("foo".to_string()), span)
2121 .with_help("if this is intentional, prefix it with an underscore: `_foo`");
2122
2123 let diag = warning.diagnostic();
2124 assert_eq!(diag.helps.len(), 1);
2125 assert_eq!(
2126 diag.helps[0].to_string(),
2127 "if this is intentional, prefix it with an underscore: `_foo`"
2128 );
2129 }
2130
2131 #[test]
2132 fn test_warning_with_label_and_note() {
2133 let span = Span::new(20, 25);
2134 let diverging_span = Span::new(10, 18);
2135 let warning = CompileWarning::new(WarningKind::UnreachableCode, span)
2136 .with_label(
2137 "any code following this expression is unreachable",
2138 diverging_span,
2139 )
2140 .with_note("this warning occurs because the preceding expression diverges");
2141
2142 let diag = warning.diagnostic();
2143 assert_eq!(diag.labels.len(), 1);
2144 assert_eq!(diag.labels[0].span, diverging_span);
2145 assert_eq!(diag.notes.len(), 1);
2146 }
2147
2148 #[test]
2149 fn test_warning_diagnostic_empty_by_default() {
2150 let span = Span::new(10, 20);
2151 let warning = CompileWarning::new(WarningKind::UnreachableCode, span);
2152 assert!(warning.diagnostic().is_empty());
2153 }
2154
2155 #[test]
2160 fn test_preview_feature_test_infra() {
2161 let feature: PreviewFeature = "test_infra".parse().unwrap();
2162 assert_eq!(feature, PreviewFeature::TestInfra);
2163 assert_eq!(feature.name(), "test_infra");
2164 assert_eq!(feature.adr(), "ADR-0005");
2165 }
2166
2167 #[test]
2168 fn test_preview_feature_from_str_unknown() {
2169 assert!("unknown".parse::<PreviewFeature>().is_err());
2170 assert!("".parse::<PreviewFeature>().is_err());
2171 }
2172
2173 #[test]
2174 fn test_preview_feature_all_contains_test_infra() {
2175 assert!(PreviewFeature::all().contains(&PreviewFeature::TestInfra));
2176 }
2177
2178 #[test]
2179 fn test_preview_feature_all_names() {
2180 let names = PreviewFeature::all_names();
2181 assert_eq!(names, "test_infra");
2183 }
2184
2185 #[test]
2190 fn test_option_ext_some() {
2191 let span = Span::new(10, 20);
2192 let result: CompileResult<i32> =
2193 Some(42).ok_or_compile_error(ErrorKind::InvalidInteger, span);
2194 assert!(result.is_ok());
2195 assert_eq!(result.unwrap(), 42);
2196 }
2197
2198 #[test]
2199 fn test_option_ext_none() {
2200 let span = Span::new(10, 20);
2201 let result: CompileResult<i32> = None.ok_or_compile_error(ErrorKind::InvalidInteger, span);
2202 assert!(result.is_err());
2203 let error = result.unwrap_err();
2204 assert_eq!(error.span(), Some(span));
2205 assert!(matches!(error.kind, ErrorKind::InvalidInteger));
2206 }
2207
2208 #[test]
2209 fn test_option_ext_with_complex_error() {
2210 let span = Span::new(5, 15);
2211 let result: CompileResult<String> =
2212 None.ok_or_compile_error(ErrorKind::UndefinedVariable("foo".to_string()), span);
2213 assert!(result.is_err());
2214 let error = result.unwrap_err();
2215 assert_eq!(error.to_string(), "undefined variable 'foo'");
2216 }
2217
2218 #[test]
2223 fn test_compile_errors_new_is_empty() {
2224 let errors = CompileErrors::new();
2225 assert!(errors.is_empty());
2226 assert_eq!(errors.len(), 0);
2227 }
2228
2229 #[test]
2230 fn test_compile_errors_from_error() {
2231 let error = CompileError::without_span(ErrorKind::InvalidInteger);
2232 let errors = CompileErrors::from_error(error);
2233 assert!(!errors.is_empty());
2234 assert_eq!(errors.len(), 1);
2235 }
2236
2237 #[test]
2238 fn test_compile_errors_push() {
2239 let mut errors = CompileErrors::new();
2240 errors.push(CompileError::without_span(ErrorKind::InvalidInteger));
2241 errors.push(CompileError::without_span(ErrorKind::NoMainFunction));
2242 assert_eq!(errors.len(), 2);
2243 }
2244
2245 #[test]
2246 fn test_compile_errors_extend() {
2247 let mut errors1 = CompileErrors::new();
2248 errors1.push(CompileError::without_span(ErrorKind::InvalidInteger));
2249
2250 let mut errors2 = CompileErrors::new();
2251 errors2.push(CompileError::without_span(ErrorKind::NoMainFunction));
2252 errors2.push(CompileError::without_span(ErrorKind::BreakOutsideLoop));
2253
2254 errors1.extend(errors2);
2255 assert_eq!(errors1.len(), 3);
2256 }
2257
2258 #[test]
2259 fn test_compile_errors_first() {
2260 let mut errors = CompileErrors::new();
2261 assert!(errors.first().is_none());
2262
2263 errors.push(CompileError::without_span(ErrorKind::InvalidInteger));
2264 errors.push(CompileError::without_span(ErrorKind::NoMainFunction));
2265
2266 let first = errors.first().unwrap();
2267 assert!(matches!(first.kind, ErrorKind::InvalidInteger));
2268 }
2269
2270 #[test]
2271 fn test_compile_errors_iter() {
2272 let mut errors = CompileErrors::new();
2273 errors.push(CompileError::without_span(ErrorKind::InvalidInteger));
2274 errors.push(CompileError::without_span(ErrorKind::NoMainFunction));
2275
2276 let kinds: Vec<_> = errors.iter().map(|e| &e.kind).collect();
2277 assert_eq!(kinds.len(), 2);
2278 }
2279
2280 #[test]
2281 fn test_compile_errors_into_result_empty() {
2282 let errors = CompileErrors::new();
2283 assert!(errors.into_result().is_ok());
2284 }
2285
2286 #[test]
2287 fn test_compile_errors_into_result_non_empty() {
2288 let mut errors = CompileErrors::new();
2289 errors.push(CompileError::without_span(ErrorKind::InvalidInteger));
2290 assert!(errors.into_result().is_err());
2291 }
2292
2293 #[test]
2294 fn test_compile_errors_into_result_with() {
2295 let errors = CompileErrors::new();
2296 let result = errors.into_result_with(42);
2297 assert_eq!(result.unwrap(), 42);
2298
2299 let mut errors = CompileErrors::new();
2300 errors.push(CompileError::without_span(ErrorKind::InvalidInteger));
2301 let result = errors.into_result_with(42);
2302 assert!(result.is_err());
2303 }
2304
2305 #[test]
2306 fn test_compile_errors_from_single_error() {
2307 let error = CompileError::without_span(ErrorKind::InvalidInteger);
2308 let errors: CompileErrors = error.into();
2309 assert_eq!(errors.len(), 1);
2310 }
2311
2312 #[test]
2313 fn test_compile_errors_to_single_error() {
2314 let mut errors = CompileErrors::new();
2315 errors.push(CompileError::without_span(ErrorKind::InvalidInteger));
2316 errors.push(CompileError::without_span(ErrorKind::NoMainFunction));
2317
2318 let error: CompileError = errors.into();
2319 assert!(matches!(error.kind, ErrorKind::InvalidInteger));
2321 }
2322
2323 #[test]
2327 #[cfg_attr(debug_assertions, ignore)]
2328 fn test_empty_compile_errors_to_single_error() {
2329 let empty = CompileErrors::new();
2332 let error: CompileError = empty.into();
2333
2334 match &error.kind {
2336 ErrorKind::InternalError(msg) => {
2337 assert!(msg.contains("empty error collection"));
2338 }
2339 other => panic!("expected InternalError, got {:?}", other),
2340 }
2341 }
2342
2343 #[test]
2344 fn test_compile_errors_display_empty() {
2345 let errors = CompileErrors::new();
2346 assert_eq!(errors.to_string(), "no errors");
2347 }
2348
2349 #[test]
2350 fn test_compile_errors_display_single() {
2351 let errors =
2352 CompileErrors::from_error(CompileError::without_span(ErrorKind::InvalidInteger));
2353 assert_eq!(errors.to_string(), "invalid integer literal");
2354 }
2355
2356 #[test]
2357 fn test_compile_errors_display_multiple() {
2358 let mut errors = CompileErrors::new();
2359 errors.push(CompileError::without_span(ErrorKind::InvalidInteger));
2360 errors.push(CompileError::without_span(ErrorKind::NoMainFunction));
2361 assert_eq!(
2362 errors.to_string(),
2363 "invalid integer literal (and 1 more error)"
2364 );
2365
2366 errors.push(CompileError::without_span(ErrorKind::BreakOutsideLoop));
2367 assert_eq!(
2368 errors.to_string(),
2369 "invalid integer literal (and 2 more errors)"
2370 );
2371 }
2372
2373 #[test]
2378 fn test_error_code_display() {
2379 assert_eq!(ErrorCode::TYPE_MISMATCH.to_string(), "E0206");
2380 assert_eq!(ErrorCode::UNDEFINED_VARIABLE.to_string(), "E0201");
2381 assert_eq!(ErrorCode::INTERNAL_ERROR.to_string(), "E9000");
2382 assert_eq!(ErrorCode(1).to_string(), "E0001");
2383 assert_eq!(ErrorCode(42).to_string(), "E0042");
2384 assert_eq!(ErrorCode(1234).to_string(), "E1234");
2385 }
2386
2387 #[test]
2388 fn test_error_kind_codes() {
2389 let cases: Vec<(ErrorKind, ErrorCode)> = vec![
2390 (
2392 ErrorKind::UnexpectedCharacter('@'),
2393 ErrorCode::UNEXPECTED_CHARACTER,
2394 ),
2395 (ErrorKind::InvalidInteger, ErrorCode::INVALID_INTEGER),
2396 (ErrorKind::InvalidFloat, ErrorCode::INVALID_FLOAT),
2397 (
2398 ErrorKind::InvalidStringEscape('n'),
2399 ErrorCode::INVALID_STRING_ESCAPE,
2400 ),
2401 (
2402 ErrorKind::UnterminatedString,
2403 ErrorCode::UNTERMINATED_STRING,
2404 ),
2405 (
2407 ErrorKind::UnexpectedToken {
2408 expected: "identifier".into(),
2409 found: "+".into(),
2410 },
2411 ErrorCode::UNEXPECTED_TOKEN,
2412 ),
2413 (
2414 ErrorKind::UnexpectedEof {
2415 expected: "}".into(),
2416 },
2417 ErrorCode::UNEXPECTED_EOF,
2418 ),
2419 (
2420 ErrorKind::ParseError("custom error".into()),
2421 ErrorCode::PARSE_ERROR,
2422 ),
2423 (ErrorKind::NoMainFunction, ErrorCode::NO_MAIN_FUNCTION),
2425 (
2426 ErrorKind::UndefinedVariable("x".into()),
2427 ErrorCode::UNDEFINED_VARIABLE,
2428 ),
2429 (
2430 ErrorKind::UndefinedFunction("foo".into()),
2431 ErrorCode::UNDEFINED_FUNCTION,
2432 ),
2433 (
2434 ErrorKind::TypeMismatch {
2435 expected: "i32".into(),
2436 found: "bool".into(),
2437 },
2438 ErrorCode::TYPE_MISMATCH,
2439 ),
2440 (ErrorKind::BreakOutsideLoop, ErrorCode::BREAK_OUTSIDE_LOOP),
2442 (
2443 ErrorKind::ContinueOutsideLoop,
2444 ErrorCode::CONTINUE_OUTSIDE_LOOP,
2445 ),
2446 (
2448 ErrorKind::InternalError("bug".into()),
2449 ErrorCode::INTERNAL_ERROR,
2450 ),
2451 (
2452 ErrorKind::InternalCodegenError("codegen bug".into()),
2453 ErrorCode::INTERNAL_CODEGEN_ERROR,
2454 ),
2455 ];
2456 for (kind, expected_code) in cases {
2457 assert_eq!(kind.code(), expected_code, "wrong code for: {kind}");
2458 }
2459 }
2460
2461 #[test]
2462 fn test_error_code_equality() {
2463 assert_eq!(ErrorCode::TYPE_MISMATCH, ErrorCode(206));
2464 assert_ne!(ErrorCode::TYPE_MISMATCH, ErrorCode::UNDEFINED_VARIABLE);
2465 }
2466
2467 #[test]
2468 fn test_error_code_hash() {
2469 use rustc_hash::FxHashSet as HashSet;
2470 let mut set = HashSet::default();
2471 set.insert(ErrorCode::TYPE_MISMATCH);
2472 set.insert(ErrorCode::UNDEFINED_VARIABLE);
2473 assert_eq!(set.len(), 2);
2474 assert!(set.contains(&ErrorCode::TYPE_MISMATCH));
2475 }
2476
2477 #[test]
2482 fn test_error_kind_size() {
2483 let size = std::mem::size_of::<ErrorKind>();
2485
2486 assert!(
2495 size <= 64,
2496 "ErrorKind is {} bytes, exceeds 64-byte limit. \
2497 Consider boxing large variants (≥ 72 bytes / 3+ Strings). \
2498 See the boxing policy documentation above ErrorKind.",
2499 size
2500 );
2501 }
2502
2503 #[test]
2504 fn test_error_kind_variant_sizes() {
2505 use std::mem::size_of;
2506
2507 println!("String: {} bytes", size_of::<String>());
2509 println!("Vec<String>: {} bytes", size_of::<Vec<String>>());
2510 println!(
2511 "Cow<'static, str>: {} bytes",
2512 size_of::<Cow<'static, str>>()
2513 );
2514
2515 println!("TypeMismatch data: {} bytes", size_of::<(String, String)>());
2517 println!("UnknownField data: {} bytes", size_of::<(String, String)>());
2518 println!(
2519 "DuplicateField data: {} bytes",
2520 size_of::<(String, String)>()
2521 );
2522 println!(
2523 "ModuleNotFound data: {} bytes",
2524 size_of::<(String, Vec<String>)>()
2525 );
2526
2527 println!(
2529 "MissingFieldsError: {} bytes",
2530 size_of::<MissingFieldsError>()
2531 );
2532 println!(
2533 "IntrinsicTypeMismatchError: {} bytes",
2534 size_of::<IntrinsicTypeMismatchError>()
2535 );
2536 println!(
2537 "FieldWrongOrderError: {} bytes",
2538 size_of::<FieldWrongOrderError>()
2539 );
2540 }
2541}