1pub mod builders;
17
18use crate::types::{TypeId, Visibility};
19use std::sync::Arc;
20use tsz_binder::SymbolId;
21use tsz_common::interner::Atom;
22
23pub trait SubtypeTracer {
51 fn on_mismatch(&mut self, reason: impl FnOnce() -> SubtypeFailureReason) -> bool;
67}
68
69pub trait DynSubtypeTracer {
74 fn on_mismatch_dyn(&mut self, reason: SubtypeFailureReason) -> bool;
84}
85
86impl<T: SubtypeTracer> DynSubtypeTracer for T {
88 fn on_mismatch_dyn(&mut self, reason: SubtypeFailureReason) -> bool {
89 self.on_mismatch(|| reason)
90 }
91}
92
93#[derive(Clone, Debug, PartialEq)]
104pub enum SubtypeFailureReason {
105 MissingProperty {
107 property_name: Atom,
108 source_type: TypeId,
109 target_type: TypeId,
110 },
111 MissingProperties {
113 property_names: Vec<Atom>,
114 source_type: TypeId,
115 target_type: TypeId,
116 },
117 PropertyTypeMismatch {
119 property_name: Atom,
120 source_property_type: TypeId,
121 target_property_type: TypeId,
122 nested_reason: Option<Box<Self>>,
123 },
124 OptionalPropertyRequired { property_name: Atom },
126 ReadonlyPropertyMismatch { property_name: Atom },
128 PropertyVisibilityMismatch {
130 property_name: Atom,
131 source_visibility: Visibility,
132 target_visibility: Visibility,
133 },
134 PropertyNominalMismatch { property_name: Atom },
136 ReturnTypeMismatch {
138 source_return: TypeId,
139 target_return: TypeId,
140 nested_reason: Option<Box<Self>>,
141 },
142 ParameterTypeMismatch {
144 param_index: usize,
145 source_param: TypeId,
146 target_param: TypeId,
147 },
148 TooManyParameters {
150 source_count: usize,
151 target_count: usize,
152 },
153 TupleElementMismatch {
155 source_count: usize,
156 target_count: usize,
157 },
158 TupleElementTypeMismatch {
160 index: usize,
161 source_element: TypeId,
162 target_element: TypeId,
163 },
164 ArrayElementMismatch {
166 source_element: TypeId,
167 target_element: TypeId,
168 },
169 IndexSignatureMismatch {
171 index_kind: &'static str, source_value_type: TypeId,
173 target_value_type: TypeId,
174 },
175 MissingIndexSignature { index_kind: &'static str },
177 NoUnionMemberMatches {
179 source_type: TypeId,
180 target_union_members: Vec<TypeId>,
181 },
182 NoIntersectionMemberMatches {
184 source_type: TypeId,
185 target_type: TypeId,
186 },
187 NoCommonProperties {
189 source_type: TypeId,
190 target_type: TypeId,
191 },
192 TypeMismatch {
194 source_type: TypeId,
195 target_type: TypeId,
196 },
197 IntrinsicTypeMismatch {
199 source_type: TypeId,
200 target_type: TypeId,
201 },
202 LiteralTypeMismatch {
204 source_type: TypeId,
205 target_type: TypeId,
206 },
207 ErrorType {
209 source_type: TypeId,
210 target_type: TypeId,
211 },
212 RecursionLimitExceeded,
214 ParameterCountMismatch {
216 source_count: usize,
217 target_count: usize,
218 },
219 ExcessProperty {
221 property_name: Atom,
222 target_type: TypeId,
223 },
224}
225
226#[derive(Clone, Copy, Debug, PartialEq, Eq)]
228pub enum DiagnosticSeverity {
229 Error,
230 Warning,
231 Suggestion,
232 Message,
233}
234
235#[derive(Clone, Debug)]
244pub enum DiagnosticArg {
245 Type(TypeId),
247 Symbol(SymbolId),
249 Atom(Atom),
251 String(Arc<str>),
253 Number(usize),
255}
256
257macro_rules! impl_from_diagnostic_arg {
258 ($($source:ty => $variant:ident),* $(,)?) => {
259 $(impl From<$source> for DiagnosticArg {
260 fn from(v: $source) -> Self { Self::$variant(v) }
261 })*
262 };
263}
264
265impl_from_diagnostic_arg! {
266 TypeId => Type,
267 SymbolId => Symbol,
268 Atom => Atom,
269 usize => Number,
270}
271
272impl From<&str> for DiagnosticArg {
273 fn from(s: &str) -> Self {
274 Self::String(s.into())
275 }
276}
277
278impl From<String> for DiagnosticArg {
279 fn from(s: String) -> Self {
280 Self::String(s.into())
281 }
282}
283
284#[derive(Clone, Debug)]
289pub struct PendingDiagnostic {
290 pub code: u32,
292 pub args: Vec<DiagnosticArg>,
294 pub span: Option<SourceSpan>,
296 pub severity: DiagnosticSeverity,
298 pub related: Vec<Self>,
300}
301
302impl PendingDiagnostic {
303 pub const fn error(code: u32, args: Vec<DiagnosticArg>) -> Self {
305 Self {
306 code,
307 args,
308 span: None,
309 severity: DiagnosticSeverity::Error,
310 related: Vec::new(),
311 }
312 }
313
314 pub fn with_span(mut self, span: SourceSpan) -> Self {
316 self.span = Some(span);
317 self
318 }
319
320 pub fn with_related(mut self, related: Self) -> Self {
322 self.related.push(related);
323 self
324 }
325}
326
327#[derive(Clone, Debug, PartialEq, Eq)]
329pub struct SourceSpan {
330 pub start: u32,
332 pub length: u32,
334 pub file: Arc<str>,
336}
337
338impl SourceSpan {
339 pub fn new(file: impl Into<Arc<str>>, start: u32, length: u32) -> Self {
340 Self {
341 start,
342 length,
343 file: file.into(),
344 }
345 }
346}
347
348#[derive(Clone, Debug)]
350pub struct RelatedInformation {
351 pub span: SourceSpan,
352 pub message: String,
353}
354
355#[derive(Clone, Debug)]
357pub struct TypeDiagnostic {
358 pub message: String,
360 pub code: u32,
362 pub severity: DiagnosticSeverity,
364 pub span: Option<SourceSpan>,
366 pub related: Vec<RelatedInformation>,
368}
369
370impl TypeDiagnostic {
371 pub fn error(message: impl Into<String>, code: u32) -> Self {
373 Self {
374 message: message.into(),
375 code,
376 severity: DiagnosticSeverity::Error,
377 span: None,
378 related: Vec::new(),
379 }
380 }
381
382 pub fn with_span(mut self, span: SourceSpan) -> Self {
384 self.span = Some(span);
385 self
386 }
387
388 pub fn with_related(mut self, span: SourceSpan, message: impl Into<String>) -> Self {
390 self.related.push(RelatedInformation {
391 span,
392 message: message.into(),
393 });
394 self
395 }
396}
397
398pub mod codes {
408 use tsz_common::diagnostics::diagnostic_codes as dc;
409
410 pub use dc::ARGUMENT_OF_TYPE_IS_NOT_ASSIGNABLE_TO_PARAMETER_OF_TYPE as ARG_NOT_ASSIGNABLE;
412 pub use dc::CANNOT_ASSIGN_TO_BECAUSE_IT_IS_A_READ_ONLY_PROPERTY as READONLY_PROPERTY;
413 pub use dc::OBJECT_LITERAL_MAY_ONLY_SPECIFY_KNOWN_PROPERTIES_AND_DOES_NOT_EXIST_IN_TYPE as EXCESS_PROPERTY;
414 pub use dc::PROPERTY_IS_MISSING_IN_TYPE_BUT_REQUIRED_IN_TYPE as PROPERTY_MISSING;
415 pub use dc::PROPERTY_IS_PRIVATE_AND_ONLY_ACCESSIBLE_WITHIN_CLASS as PROPERTY_VISIBILITY_MISMATCH;
416 pub use dc::PROPERTY_IS_PROTECTED_AND_ONLY_ACCESSIBLE_THROUGH_AN_INSTANCE_OF_CLASS_THIS_IS_A as PROPERTY_NOMINAL_MISMATCH;
417 pub use dc::TYPE_HAS_NO_PROPERTIES_IN_COMMON_WITH_TYPE as NO_COMMON_PROPERTIES;
418 pub use dc::TYPE_IS_MISSING_THE_FOLLOWING_PROPERTIES_FROM_TYPE as MISSING_PROPERTIES;
419 pub use dc::TYPE_IS_NOT_ASSIGNABLE_TO_TYPE as TYPE_NOT_ASSIGNABLE;
420
421 pub use dc::INDEX_SIGNATURE_FOR_TYPE_IS_MISSING_IN_TYPE as MISSING_INDEX_SIGNATURE;
422 pub use dc::TYPES_OF_PROPERTY_ARE_INCOMPATIBLE as PROPERTY_TYPE_MISMATCH;
423
424 pub use dc::CANNOT_FIND_NAME;
426 pub use dc::CANNOT_FIND_NAME_DO_YOU_NEED_TO_CHANGE_YOUR_TARGET_LIBRARY_TRY_CHANGING_THE_LIB as CANNOT_FIND_NAME_TARGET_LIB;
427 pub use dc::CANNOT_FIND_NAME_DO_YOU_NEED_TO_CHANGE_YOUR_TARGET_LIBRARY_TRY_CHANGING_THE_LIB_2 as CANNOT_FIND_NAME_DOM;
428 pub use dc::CANNOT_FIND_NAME_DO_YOU_NEED_TO_INSTALL_TYPE_DEFINITIONS_FOR_A_TEST_RUNNER_TRY_N as CANNOT_FIND_NAME_TEST_RUNNER;
429 pub use dc::CANNOT_FIND_NAME_DO_YOU_NEED_TO_INSTALL_TYPE_DEFINITIONS_FOR_NODE_TRY_NPM_I_SAVE as CANNOT_FIND_NAME_NODE;
430 pub use dc::EXPECTED_ARGUMENTS_BUT_GOT as ARG_COUNT_MISMATCH;
431 pub use dc::PROPERTY_DOES_NOT_EXIST_ON_TYPE as PROPERTY_NOT_EXIST;
432 pub use dc::PROPERTY_DOES_NOT_EXIST_ON_TYPE_DID_YOU_MEAN as PROPERTY_NOT_EXIST_DID_YOU_MEAN;
433 pub use dc::THE_THIS_CONTEXT_OF_TYPE_IS_NOT_ASSIGNABLE_TO_METHODS_THIS_OF_TYPE as THIS_TYPE_MISMATCH;
434 pub use dc::THIS_EXPRESSION_IS_NOT_CALLABLE as NOT_CALLABLE;
435
436 pub use dc::FUNCTION_EXPRESSION_WHICH_LACKS_RETURN_TYPE_ANNOTATION_IMPLICITLY_HAS_AN_RETURN as IMPLICIT_ANY_RETURN_FUNCTION_EXPRESSION;
440 pub use dc::MEMBER_IMPLICITLY_HAS_AN_TYPE as IMPLICIT_ANY_MEMBER;
441 pub use dc::PARAMETER_IMPLICITLY_HAS_AN_TYPE as IMPLICIT_ANY_PARAMETER;
442 pub use dc::VARIABLE_IMPLICITLY_HAS_AN_TYPE as IMPLICIT_ANY;
443 pub use dc::WHICH_LACKS_RETURN_TYPE_ANNOTATION_IMPLICITLY_HAS_AN_RETURN_TYPE as IMPLICIT_ANY_RETURN;
444}
445
446pub(crate) fn cannot_find_name_code(name: &str) -> u32 {
455 match name {
456 "require" | "exports" | "module" | "process" | "Buffer" | "__filename" | "__dirname" => {
458 codes::CANNOT_FIND_NAME_NODE
459 }
460 "describe" | "suite" | "it" | "test" => codes::CANNOT_FIND_NAME_TEST_RUNNER,
462 "Promise" | "Symbol" | "Map" | "Set" | "Reflect" | "Iterator" | "AsyncIterator"
464 | "SharedArrayBuffer" => codes::CANNOT_FIND_NAME_TARGET_LIB,
465 "document" | "console" => codes::CANNOT_FIND_NAME_DOM,
467 _ => codes::CANNOT_FIND_NAME,
469 }
470}
471
472pub fn get_message_template(code: u32) -> &'static str {
482 tsz_common::diagnostics::get_message_template(code).unwrap_or("Unknown diagnostic")
483}
484
485pub struct PendingDiagnosticBuilder;
494
495impl SubtypeFailureReason {
500 pub const fn diagnostic_code(&self) -> u32 {
506 match self {
507 Self::MissingProperty { .. } | Self::OptionalPropertyRequired { .. } => {
508 codes::PROPERTY_MISSING
509 }
510 Self::MissingProperties { .. } => codes::MISSING_PROPERTIES,
511 Self::PropertyTypeMismatch { .. } => codes::PROPERTY_TYPE_MISMATCH,
512 Self::ReadonlyPropertyMismatch { .. } => codes::READONLY_PROPERTY,
513 Self::PropertyVisibilityMismatch { .. } => codes::PROPERTY_VISIBILITY_MISMATCH,
514 Self::PropertyNominalMismatch { .. } => codes::PROPERTY_NOMINAL_MISMATCH,
515 Self::ReturnTypeMismatch { .. }
516 | Self::ParameterTypeMismatch { .. }
517 | Self::TupleElementMismatch { .. }
518 | Self::TupleElementTypeMismatch { .. }
519 | Self::ArrayElementMismatch { .. }
520 | Self::IndexSignatureMismatch { .. }
521 | Self::MissingIndexSignature { .. }
522 | Self::NoUnionMemberMatches { .. }
523 | Self::NoIntersectionMemberMatches { .. }
524 | Self::TypeMismatch { .. }
525 | Self::IntrinsicTypeMismatch { .. }
526 | Self::LiteralTypeMismatch { .. }
527 | Self::ErrorType { .. }
528 | Self::RecursionLimitExceeded
529 | Self::ParameterCountMismatch { .. } => codes::TYPE_NOT_ASSIGNABLE,
530 Self::TooManyParameters { .. } => codes::ARG_COUNT_MISMATCH,
531 Self::NoCommonProperties { .. } => codes::NO_COMMON_PROPERTIES,
532 Self::ExcessProperty { .. } => codes::EXCESS_PROPERTY,
533 }
534 }
535
536 pub fn to_diagnostic(&self, source: TypeId, target: TypeId) -> PendingDiagnostic {
541 match self {
542 Self::MissingProperty {
543 property_name,
544 source_type,
545 target_type,
546 } => PendingDiagnostic::error(
547 codes::PROPERTY_MISSING,
548 vec![
549 (*property_name).into(),
550 (*source_type).into(),
551 (*target_type).into(),
552 ],
553 ),
554
555 Self::MissingProperties {
556 property_names: _,
557 source_type,
558 target_type,
559 } => PendingDiagnostic::error(
560 codes::MISSING_PROPERTIES,
561 vec![(*source_type).into(), (*target_type).into()],
562 ),
563
564 Self::PropertyTypeMismatch {
565 property_name,
566 source_property_type,
567 target_property_type,
568 nested_reason,
569 } => {
570 let mut diag = PendingDiagnostic::error(
572 codes::TYPE_NOT_ASSIGNABLE,
573 vec![source.into(), target.into()],
574 );
575
576 let elaboration = PendingDiagnostic::error(
578 codes::PROPERTY_TYPE_MISMATCH,
579 vec![(*property_name).into()],
580 );
581 diag = diag.with_related(elaboration);
582
583 if let Some(nested) = nested_reason {
585 let nested_diag =
586 nested.to_diagnostic(*source_property_type, *target_property_type);
587 diag = diag.with_related(nested_diag);
588 }
589
590 diag
591 }
592
593 Self::OptionalPropertyRequired { property_name } => {
594 PendingDiagnostic::error(
596 codes::TYPE_NOT_ASSIGNABLE,
597 vec![source.into(), target.into()],
598 )
599 .with_related(PendingDiagnostic::error(
600 codes::PROPERTY_MISSING, vec![(*property_name).into(), source.into(), target.into()],
602 ))
603 }
604
605 Self::ReadonlyPropertyMismatch { property_name } => PendingDiagnostic::error(
606 codes::TYPE_NOT_ASSIGNABLE,
607 vec![source.into(), target.into()],
608 )
609 .with_related(PendingDiagnostic::error(
610 codes::READONLY_PROPERTY,
611 vec![(*property_name).into()],
612 )),
613
614 Self::PropertyVisibilityMismatch {
615 property_name,
616 source_visibility,
617 target_visibility,
618 } => {
619 PendingDiagnostic::error(
621 codes::TYPE_NOT_ASSIGNABLE,
622 vec![source.into(), target.into()],
623 )
624 .with_related(PendingDiagnostic::error(
625 codes::PROPERTY_VISIBILITY_MISMATCH,
626 vec![
627 (*property_name).into(),
628 format!("{source_visibility:?}").into(),
629 format!("{target_visibility:?}").into(),
630 ],
631 ))
632 }
633
634 Self::PropertyNominalMismatch { property_name } => {
635 PendingDiagnostic::error(
637 codes::TYPE_NOT_ASSIGNABLE,
638 vec![source.into(), target.into()],
639 )
640 .with_related(PendingDiagnostic::error(
641 codes::PROPERTY_NOMINAL_MISMATCH,
642 vec![(*property_name).into()],
643 ))
644 }
645
646 Self::ReturnTypeMismatch {
647 source_return,
648 target_return,
649 nested_reason,
650 } => {
651 let mut diag = PendingDiagnostic::error(
652 codes::TYPE_NOT_ASSIGNABLE,
653 vec![source.into(), target.into()],
654 );
655
656 let return_diag = PendingDiagnostic::error(
658 codes::TYPE_NOT_ASSIGNABLE,
659 vec![(*source_return).into(), (*target_return).into()],
660 );
661 diag = diag.with_related(return_diag);
662
663 if let Some(nested) = nested_reason {
664 let nested_diag = nested.to_diagnostic(*source_return, *target_return);
665 diag = diag.with_related(nested_diag);
666 }
667
668 diag
669 }
670
671 Self::ParameterTypeMismatch {
672 param_index: _,
673 source_param,
674 target_param,
675 } => PendingDiagnostic::error(
676 codes::TYPE_NOT_ASSIGNABLE,
677 vec![source.into(), target.into()],
678 )
679 .with_related(PendingDiagnostic::error(
680 codes::TYPE_NOT_ASSIGNABLE,
681 vec![(*source_param).into(), (*target_param).into()],
682 )),
683
684 Self::TooManyParameters {
685 source_count,
686 target_count,
687 } => PendingDiagnostic::error(
688 codes::ARG_COUNT_MISMATCH,
689 vec![(*target_count).into(), (*source_count).into()],
690 ),
691
692 Self::TupleElementMismatch {
693 source_count,
694 target_count,
695 } => PendingDiagnostic::error(
696 codes::TYPE_NOT_ASSIGNABLE,
697 vec![source.into(), target.into()],
698 )
699 .with_related(PendingDiagnostic::error(
700 codes::ARG_COUNT_MISMATCH,
701 vec![(*target_count).into(), (*source_count).into()],
702 )),
703
704 Self::TupleElementTypeMismatch {
705 index: _,
706 source_element,
707 target_element,
708 }
709 | Self::ArrayElementMismatch {
710 source_element,
711 target_element,
712 } => PendingDiagnostic::error(
713 codes::TYPE_NOT_ASSIGNABLE,
714 vec![source.into(), target.into()],
715 )
716 .with_related(PendingDiagnostic::error(
717 codes::TYPE_NOT_ASSIGNABLE,
718 vec![(*source_element).into(), (*target_element).into()],
719 )),
720
721 Self::IndexSignatureMismatch {
722 index_kind: _,
723 source_value_type,
724 target_value_type,
725 } => PendingDiagnostic::error(
726 codes::TYPE_NOT_ASSIGNABLE,
727 vec![source.into(), target.into()],
728 )
729 .with_related(PendingDiagnostic::error(
730 codes::TYPE_NOT_ASSIGNABLE,
731 vec![(*source_value_type).into(), (*target_value_type).into()],
732 )),
733
734 Self::MissingIndexSignature { index_kind } => PendingDiagnostic::error(
735 codes::TYPE_NOT_ASSIGNABLE,
736 vec![source.into(), target.into()],
737 )
738 .with_related(PendingDiagnostic::error(
739 codes::MISSING_INDEX_SIGNATURE,
740 vec![index_kind.to_string().into(), source.into()],
741 )),
742
743 Self::NoUnionMemberMatches {
744 source_type,
745 target_union_members,
746 } => {
747 const UNION_MEMBER_DIAGNOSTIC_LIMIT: usize = 3;
748 let mut diag = PendingDiagnostic::error(
749 codes::TYPE_NOT_ASSIGNABLE,
750 vec![(*source_type).into(), target.into()],
751 );
752 for member in target_union_members
753 .iter()
754 .take(UNION_MEMBER_DIAGNOSTIC_LIMIT)
755 {
756 diag.related.push(PendingDiagnostic::error(
757 codes::TYPE_NOT_ASSIGNABLE,
758 vec![(*source_type).into(), (*member).into()],
759 ));
760 }
761 diag
762 }
763
764 Self::NoIntersectionMemberMatches {
765 source_type,
766 target_type,
767 }
768 | Self::TypeMismatch {
769 source_type,
770 target_type,
771 }
772 | Self::IntrinsicTypeMismatch {
773 source_type,
774 target_type,
775 }
776 | Self::LiteralTypeMismatch {
777 source_type,
778 target_type,
779 }
780 | Self::ErrorType {
781 source_type,
782 target_type,
783 } => PendingDiagnostic::error(
784 codes::TYPE_NOT_ASSIGNABLE,
785 vec![(*source_type).into(), (*target_type).into()],
786 ),
787
788 Self::NoCommonProperties {
789 source_type,
790 target_type,
791 } => PendingDiagnostic::error(
792 codes::NO_COMMON_PROPERTIES,
793 vec![(*source_type).into(), (*target_type).into()],
794 ),
795
796 Self::RecursionLimitExceeded => {
797 PendingDiagnostic::error(
799 codes::TYPE_NOT_ASSIGNABLE,
800 vec![source.into(), target.into()],
801 )
802 }
803
804 Self::ParameterCountMismatch {
805 source_count: _,
806 target_count: _,
807 } => {
808 PendingDiagnostic::error(
810 codes::TYPE_NOT_ASSIGNABLE,
811 vec![source.into(), target.into()],
812 )
813 }
814
815 Self::ExcessProperty {
816 property_name,
817 target_type,
818 } => {
819 PendingDiagnostic::error(
821 codes::EXCESS_PROPERTY,
822 vec![(*property_name).into(), (*target_type).into()],
823 )
824 }
825 }
826 }
827}
828
829impl PendingDiagnosticBuilder {
830 pub fn argument_not_assignable(arg_type: TypeId, param_type: TypeId) -> PendingDiagnostic {
832 PendingDiagnostic::error(
833 codes::ARG_NOT_ASSIGNABLE,
834 vec![arg_type.into(), param_type.into()],
835 )
836 }
837
838 pub fn argument_count_mismatch(expected: usize, got: usize) -> PendingDiagnostic {
840 PendingDiagnostic::error(codes::ARG_COUNT_MISMATCH, vec![expected.into(), got.into()])
841 }
842}
843
844#[cfg(test)]
845impl PendingDiagnosticBuilder {
846 pub fn type_not_assignable(source: TypeId, target: TypeId) -> PendingDiagnostic {
848 PendingDiagnostic::error(
849 codes::TYPE_NOT_ASSIGNABLE,
850 vec![source.into(), target.into()],
851 )
852 }
853
854 pub fn property_missing(prop_name: &str, source: TypeId, target: TypeId) -> PendingDiagnostic {
856 PendingDiagnostic::error(
857 codes::PROPERTY_MISSING,
858 vec![prop_name.into(), source.into(), target.into()],
859 )
860 }
861
862 pub fn property_not_exist(prop_name: &str, type_id: TypeId) -> PendingDiagnostic {
864 PendingDiagnostic::error(
865 codes::PROPERTY_NOT_EXIST,
866 vec![prop_name.into(), type_id.into()],
867 )
868 }
869
870 pub fn cannot_find_name(name: &str) -> PendingDiagnostic {
872 let code = cannot_find_name_code(name);
873 PendingDiagnostic::error(code, vec![name.into()])
874 }
875
876 pub fn not_callable(type_id: TypeId) -> PendingDiagnostic {
878 PendingDiagnostic::error(codes::NOT_CALLABLE, vec![type_id.into()])
879 }
880
881 pub fn this_type_mismatch(expected_this: TypeId, actual_this: TypeId) -> PendingDiagnostic {
882 PendingDiagnostic::error(
883 codes::THIS_TYPE_MISMATCH,
884 vec![actual_this.into(), expected_this.into()],
885 )
886 }
887
888 pub fn readonly_property(prop_name: &str) -> PendingDiagnostic {
890 PendingDiagnostic::error(codes::READONLY_PROPERTY, vec![prop_name.into()])
891 }
892
893 pub fn excess_property(prop_name: &str, target: TypeId) -> PendingDiagnostic {
895 PendingDiagnostic::error(
896 codes::EXCESS_PROPERTY,
897 vec![prop_name.into(), target.into()],
898 )
899 }
900}
901
902#[cfg(test)]
903use crate::types::*;
904
905#[cfg(test)]
906#[path = "../../tests/diagnostics_tests.rs"]
907mod tests;