Skip to main content

luaur_analysis/functions/
error_to_string.rs

1use alloc::string::String;
2use core::fmt::Write;
3
4use crate::functions::to_string_to_string_alt_c::to_string_type_id;
5use crate::functions::to_string_to_string_alt_d::to_string_type_pack_id;
6use crate::functions::to_string_type_function_error::to_string_type_function_error;
7use luaur_ast::functions::to_string_ast_alt_b::to_string_ast_expr_binary_op;
8
9use crate::records::ambiguous_function_call::AmbiguousFunctionCall;
10use crate::records::built_in_type_function_error::BuiltInTypeFunctionError;
11use crate::records::cannot_assign_to_never::CannotAssignToNever;
12use crate::records::cannot_call_non_function::CannotCallNonFunction;
13use crate::records::cannot_check_dynamic_string_format_calls::CannotCheckDynamicStringFormatCalls;
14use crate::records::cannot_compare_unrelated_types::CannotCompareUnrelatedTypes;
15use crate::records::cannot_extend_table::CannotExtendTable;
16use crate::records::cannot_infer_binary_operation::CannotInferBinaryOperation;
17use crate::records::checked_function_call_error::CheckedFunctionCallError;
18use crate::records::checked_function_incorrect_args::CheckedFunctionIncorrectArgs;
19use crate::records::code_too_complex::CodeTooComplex;
20use crate::records::constraint_solving_incomplete_error::ConstraintSolvingIncompleteError;
21use crate::records::count_mismatch::CountMismatch;
22use crate::records::deprecated_api_used::DeprecatedApiUsed;
23use crate::records::duplicate_generic_parameter::DuplicateGenericParameter;
24use crate::records::duplicate_type_definition::DuplicateTypeDefinition;
25use crate::records::dynamic_property_lookup_on_extern_types_unsafe::DynamicPropertyLookupOnExternTypesUnsafe;
26use crate::records::explicit_function_annotation_recommended::ExplicitFunctionAnnotationRecommended;
27use crate::records::extra_information::ExtraInformation;
28use crate::records::function_does_not_take_self::FunctionDoesNotTakeSelf;
29use crate::records::function_exits_without_returning::FunctionExitsWithoutReturning;
30use crate::records::function_requires_self::FunctionRequiresSelf;
31use crate::records::generic_bounds_mismatch::GenericBoundsMismatch;
32use crate::records::generic_error::GenericError;
33use crate::records::generic_type_count_mismatch::GenericTypeCountMismatch;
34use crate::records::generic_type_pack_count_mismatch::GenericTypePackCountMismatch;
35use crate::records::illegal_require::IllegalRequire;
36use crate::records::incorrect_generic_parameter_count::IncorrectGenericParameterCount;
37use crate::records::instantiate_generics_on_non_function::InstantiateGenericsOnNonFunction;
38use crate::records::internal_error::InternalError;
39use crate::records::missing_properties::MissingProperties;
40use crate::records::missing_union_property::MissingUnionProperty;
41use crate::records::module_has_cyclic_dependency::ModuleHasCyclicDependency;
42use crate::records::multiple_nonviable_overloads::MultipleNonviableOverloads;
43use crate::records::non_strict_function_definition_error::NonStrictFunctionDefinitionError;
44use crate::records::normalization_too_complex::NormalizationTooComplex;
45use crate::records::not_a_table::NotATable;
46use crate::records::occurs_check_failed::OccursCheckFailed;
47use crate::records::only_tables_can_have_methods::OnlyTablesCanHaveMethods;
48use crate::records::optional_value_access::OptionalValueAccess;
49use crate::records::pack_where_clause_needed::PackWhereClauseNeeded;
50use crate::records::property_access_violation::PropertyAccessViolation;
51use crate::records::recursive_restraint_violation::RecursiveRestraintViolation;
52use crate::records::reserved_identifier::ReservedIdentifier;
53use crate::records::swapped_generic_type_parameter::SwappedGenericTypeParameter;
54use crate::records::syntax_error::SyntaxError;
55use crate::records::type_instantiation_count_mismatch::TypeInstantiationCountMismatch;
56use crate::records::type_mismatch::TypeMismatch;
57use crate::records::type_pack_mismatch::TypePackMismatch;
58use crate::records::types_are_unrelated::TypesAreUnrelated;
59use crate::records::unapplied_type_function::UnappliedTypeFunction;
60use crate::records::unexpected_array_like_table_item::UnexpectedArrayLikeTableItem;
61use crate::records::unexpected_type_in_subtyping::UnexpectedTypeInSubtyping;
62use crate::records::unexpected_type_pack_in_subtyping::UnexpectedTypePackInSubtyping;
63use crate::records::unification_too_complex::UnificationTooComplex;
64use crate::records::uninhabited_type_function::UninhabitedTypeFunction;
65use crate::records::uninhabited_type_pack_function::UninhabitedTypePackFunction;
66use crate::records::unknown_prop_but_found_like_prop::UnknownPropButFoundLikeProp;
67use crate::records::unknown_property::UnknownProperty;
68use crate::records::unknown_require::UnknownRequire;
69use crate::records::unknown_symbol::UnknownSymbol;
70use crate::records::user_defined_type_function_error::UserDefinedTypeFunctionError;
71use crate::records::where_clause_needed::WhereClauseNeeded;
72
73use crate::enums::interesting_edge_case::InterestingEdgeCase;
74use crate::enums::reason::Reason;
75
76/// C++ `errorToString<T>` is an `if constexpr` switch over the concrete error
77/// type. Rust models the per-type compile-time dispatch with a trait
78/// implemented once per error record; the generic function delegates to it.
79pub trait ErrorToString {
80    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result;
81}
82
83pub fn error_to_string<T: ErrorToString>(stream: &mut dyn Write, err: &T) -> core::fmt::Result {
84    err.error_to_string_impl(stream)
85}
86
87impl ErrorToString for TypeMismatch {
88    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
89        write!(
90            stream,
91            "TypeMismatch {{ {}, {} }}",
92            to_string_type_id(self.wanted_type),
93            to_string_type_id(self.given_type)
94        )
95    }
96}
97
98impl ErrorToString for UnknownSymbol {
99    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
100        write!(
101            stream,
102            "UnknownSymbol {{ {} , context {} }}",
103            self.name, self.context as i32
104        )
105    }
106}
107
108impl ErrorToString for UnknownProperty {
109    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
110        write!(
111            stream,
112            "UnknownProperty {{ {}, key = {} }}",
113            to_string_type_id(self.table),
114            self.key
115        )
116    }
117}
118
119impl ErrorToString for NotATable {
120    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
121        write!(stream, "NotATable {{ {} }}", to_string_type_id(self.ty))
122    }
123}
124
125impl ErrorToString for CannotExtendTable {
126    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
127        write!(
128            stream,
129            "CannotExtendTable {{ {}, context {}, prop \"{}\" }}",
130            to_string_type_id(self.table_type),
131            self.context as i32,
132            self.prop
133        )
134    }
135}
136
137impl ErrorToString for CannotCompareUnrelatedTypes {
138    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
139        write!(
140            stream,
141            "CannotCompareUnrelatedTypes {{ {}, {}, op '{}' }}",
142            to_string_type_id(self.left),
143            to_string_type_id(self.right),
144            to_string_ast_expr_binary_op(self.op)
145        )
146    }
147}
148
149impl ErrorToString for OnlyTablesCanHaveMethods {
150    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
151        write!(
152            stream,
153            "OnlyTablesCanHaveMethods {{ {} }}",
154            to_string_type_id(self.table_type)
155        )
156    }
157}
158
159impl ErrorToString for DuplicateTypeDefinition {
160    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
161        write!(stream, "DuplicateTypeDefinition {{ {} }}", self.name)
162    }
163}
164
165impl ErrorToString for CountMismatch {
166    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
167        write!(
168            stream,
169            "CountMismatch {{ expected {}, got {}, context {} }}",
170            self.expected, self.actual, self.context as i32
171        )
172    }
173}
174
175impl ErrorToString for FunctionDoesNotTakeSelf {
176    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
177        write!(stream, "FunctionDoesNotTakeSelf {{ }}")
178    }
179}
180
181impl ErrorToString for FunctionRequiresSelf {
182    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
183        write!(stream, "FunctionRequiresSelf {{ }}")
184    }
185}
186
187impl ErrorToString for OccursCheckFailed {
188    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
189        write!(stream, "OccursCheckFailed {{ }}")
190    }
191}
192
193impl ErrorToString for UnknownRequire {
194    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
195        write!(stream, "UnknownRequire {{ {} }}", self.module_path)
196    }
197}
198
199impl ErrorToString for IncorrectGenericParameterCount {
200    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
201        write!(
202            stream,
203            "IncorrectGenericParameterCount {{ name = {}",
204            self.name
205        )?;
206
207        if !self.type_fun.type_params.is_empty() || !self.type_fun.type_pack_params.is_empty() {
208            write!(stream, "<")?;
209            let mut first = true;
210            for param in &self.type_fun.type_params {
211                if first {
212                    first = false;
213                } else {
214                    write!(stream, ", ")?;
215                }
216
217                write!(stream, "{}", to_string_type_id(param.ty))?;
218            }
219
220            for param in &self.type_fun.type_pack_params {
221                if first {
222                    first = false;
223                } else {
224                    write!(stream, ", ")?;
225                }
226
227                write!(stream, "{}", to_string_type_pack_id(param.tp))?;
228            }
229
230            write!(stream, ">")?;
231        }
232
233        write!(
234            stream,
235            ", typeFun = {}, actualCount = {} }}",
236            to_string_type_id(self.type_fun.r#type),
237            self.actual_parameters
238        )
239    }
240}
241
242impl ErrorToString for SyntaxError {
243    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
244        write!(stream, "SyntaxError {{ {} }}", self.message)
245    }
246}
247
248impl ErrorToString for CodeTooComplex {
249    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
250        write!(stream, "CodeTooComplex {{}}")
251    }
252}
253
254impl ErrorToString for UnificationTooComplex {
255    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
256        write!(stream, "UnificationTooComplex {{}}")
257    }
258}
259
260impl ErrorToString for UnknownPropButFoundLikeProp {
261    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
262        write!(
263            stream,
264            "UnknownPropButFoundLikeProp {{ key = '{}', suggested = {{ ",
265            self.key
266        )?;
267
268        let mut first = true;
269        for name in &self.candidates {
270            if first {
271                first = false;
272            } else {
273                write!(stream, ", ")?;
274            }
275
276            write!(stream, "'{}'", name)?;
277        }
278
279        write!(stream, " }}, table = {} }} ", to_string_type_id(self.table))
280    }
281}
282
283impl ErrorToString for GenericError {
284    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
285        write!(stream, "GenericError {{ {} }}", self.message)
286    }
287}
288
289impl ErrorToString for InternalError {
290    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
291        write!(stream, "InternalError {{ {} }}", self.message)
292    }
293}
294
295impl ErrorToString for ConstraintSolvingIncompleteError {
296    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
297        write!(stream, "ConstraintSolvingIncompleteError {{}}")
298    }
299}
300
301impl ErrorToString for CannotCallNonFunction {
302    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
303        write!(
304            stream,
305            "CannotCallNonFunction {{ {} }}",
306            to_string_type_id(self.ty)
307        )
308    }
309}
310
311impl ErrorToString for ExtraInformation {
312    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
313        write!(stream, "ExtraInformation {{ {} }}", self.message)
314    }
315}
316
317impl ErrorToString for DeprecatedApiUsed {
318    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
319        write!(
320            stream,
321            "DeprecatedApiUsed {{ {}, useInstead = {} }}",
322            self.symbol, self.use_instead
323        )
324    }
325}
326
327impl ErrorToString for ModuleHasCyclicDependency {
328    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
329        write!(stream, "ModuleHasCyclicDependency {{")?;
330
331        let mut first = true;
332        for name in &self.cycle {
333            if first {
334                first = false;
335            } else {
336                write!(stream, ", ")?;
337            }
338
339            write!(stream, "{}", name)?;
340        }
341
342        write!(stream, "}}")
343    }
344}
345
346impl ErrorToString for IllegalRequire {
347    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
348        write!(
349            stream,
350            "IllegalRequire {{ {}, reason = {} }}",
351            self.moduleName, self.reason
352        )
353    }
354}
355
356impl ErrorToString for FunctionExitsWithoutReturning {
357    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
358        write!(
359            stream,
360            "FunctionExitsWithoutReturning {{{}}}",
361            to_string_type_pack_id(self.expected_return_type)
362        )
363    }
364}
365
366impl ErrorToString for DuplicateGenericParameter {
367    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
368        write!(
369            stream,
370            "DuplicateGenericParameter {{ {} }}",
371            self.parameterName
372        )
373    }
374}
375
376impl ErrorToString for CannotInferBinaryOperation {
377    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
378        let suggested = self.suggested_to_annotate.as_deref().unwrap_or("");
379        write!(
380            stream,
381            "CannotInferBinaryOperation {{ op = {}, suggested = '{}', kind {}}}",
382            to_string_ast_expr_binary_op(self.op),
383            suggested,
384            self.kind as i32
385        )
386    }
387}
388
389impl ErrorToString for MissingProperties {
390    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
391        write!(
392            stream,
393            "MissingProperties {{ superType = '{}', subType = '{}', properties = {{ ",
394            to_string_type_id(self.super_type),
395            to_string_type_id(self.sub_type)
396        )?;
397
398        let mut first = true;
399        for name in &self.properties {
400            if first {
401                first = false;
402            } else {
403                write!(stream, ", ")?;
404            }
405
406            write!(stream, "'{}'", name)?;
407        }
408
409        write!(stream, " }}, context {} }} ", self.context as i32)
410    }
411}
412
413impl ErrorToString for SwappedGenericTypeParameter {
414    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
415        write!(
416            stream,
417            "SwappedGenericTypeParameter {{ name = '{}', kind = {} }}",
418            self.name, self.kind as i32
419        )
420    }
421}
422
423impl ErrorToString for OptionalValueAccess {
424    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
425        write!(
426            stream,
427            "OptionalValueAccess {{ optional = '{}' }}",
428            to_string_type_id(self.optional)
429        )
430    }
431}
432
433impl ErrorToString for MissingUnionProperty {
434    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
435        write!(
436            stream,
437            "MissingUnionProperty {{ type = '{}', missing = {{ ",
438            to_string_type_id(self.r#type)
439        )?;
440
441        let mut first = true;
442        for ty in &self.missing {
443            if first {
444                first = false;
445            } else {
446                write!(stream, ", ")?;
447            }
448
449            write!(stream, "'{}'", to_string_type_id(*ty))?;
450        }
451
452        write!(stream, " }}, key = '{}' }}", self.key)
453    }
454}
455
456impl ErrorToString for TypesAreUnrelated {
457    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
458        write!(
459            stream,
460            "TypesAreUnrelated {{ left = '{}', right = '{}' }}",
461            to_string_type_id(self.left),
462            to_string_type_id(self.right)
463        )
464    }
465}
466
467impl ErrorToString for NormalizationTooComplex {
468    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
469        write!(stream, "NormalizationTooComplex {{ }}")
470    }
471}
472
473impl ErrorToString for TypePackMismatch {
474    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
475        write!(
476            stream,
477            "TypePackMismatch {{ wanted = '{}', given = '{}' }}",
478            to_string_type_pack_id(self.wanted_tp),
479            to_string_type_pack_id(self.given_tp)
480        )
481    }
482}
483
484impl ErrorToString for DynamicPropertyLookupOnExternTypesUnsafe {
485    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
486        write!(
487            stream,
488            "DynamicPropertyLookupOnExternTypesUnsafe {{ {} }}",
489            to_string_type_id(self.ty)
490        )
491    }
492}
493
494impl ErrorToString for UninhabitedTypeFunction {
495    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
496        write!(
497            stream,
498            "UninhabitedTypeFunction {{ {} }}",
499            to_string_type_id(self.ty)
500        )
501    }
502}
503
504impl ErrorToString for ExplicitFunctionAnnotationRecommended {
505    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
506        let mut rec_args = String::from("[");
507        for (s, t) in &self.recommended_args {
508            rec_args.push_str(" ");
509            rec_args.push_str(s);
510            rec_args.push_str(": ");
511            rec_args.push_str(&to_string_type_id(*t));
512        }
513        rec_args.push_str(" ]");
514        write!(
515            stream,
516            "ExplicitFunctionAnnotationRecommended {{ recommendedReturn = '{}', recommendedArgs = {}}}",
517            to_string_type_id(self.recommended_return),
518            rec_args
519        )
520    }
521}
522
523impl ErrorToString for UninhabitedTypePackFunction {
524    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
525        write!(
526            stream,
527            "UninhabitedTypePackFunction {{ {} }}",
528            to_string_type_pack_id(self.tp)
529        )
530    }
531}
532
533impl ErrorToString for WhereClauseNeeded {
534    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
535        write!(
536            stream,
537            "WhereClauseNeeded {{ {} }}",
538            to_string_type_id(self.ty)
539        )
540    }
541}
542
543impl ErrorToString for PackWhereClauseNeeded {
544    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
545        write!(
546            stream,
547            "PackWhereClauseNeeded {{ {} }}",
548            to_string_type_pack_id(self.tp)
549        )
550    }
551}
552
553impl ErrorToString for CheckedFunctionCallError {
554    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
555        write!(
556            stream,
557            "CheckedFunctionCallError {{ expected = '{}', passed = '{}', checkedFunctionName = {}, argumentIndex = {} }}",
558            to_string_type_id(self.expected),
559            to_string_type_id(self.passed),
560            self.checkedFunctionName,
561            self.argumentIndex
562        )
563    }
564}
565
566impl ErrorToString for NonStrictFunctionDefinitionError {
567    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
568        write!(
569            stream,
570            "NonStrictFunctionDefinitionError {{ functionName = '{}', argument = '{}', argumentType = '{}' }}",
571            self.function_name,
572            self.argument,
573            to_string_type_id(self.argument_type)
574        )
575    }
576}
577
578impl ErrorToString for PropertyAccessViolation {
579    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
580        write!(
581            stream,
582            "PropertyAccessViolation {{ table = {}, prop = '{}', context = {} }}",
583            to_string_type_id(self.table),
584            self.key,
585            self.context as i32
586        )
587    }
588}
589
590impl ErrorToString for CheckedFunctionIncorrectArgs {
591    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
592        write!(
593            stream,
594            "CheckedFunction {{  functionName = '{}, expected = {}, actual = {}}}",
595            self.functionName, self.expected, self.actual
596        )
597    }
598}
599
600impl ErrorToString for UnexpectedTypeInSubtyping {
601    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
602        write!(
603            stream,
604            "UnexpectedTypeInSubtyping {{  ty = '{}' }}",
605            to_string_type_id(self.ty)
606        )
607    }
608}
609
610impl ErrorToString for UnexpectedTypePackInSubtyping {
611    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
612        write!(
613            stream,
614            "UnexpectedTypePackInSubtyping {{  tp = '{}' }}",
615            to_string_type_pack_id(self.tp)
616        )
617    }
618}
619
620impl ErrorToString for UserDefinedTypeFunctionError {
621    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
622        write!(
623            stream,
624            "UserDefinedTypeFunctionError {{ {} }}",
625            self.message
626        )
627    }
628}
629
630impl ErrorToString for BuiltInTypeFunctionError {
631    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
632        write!(
633            stream,
634            "BuiltInTypeFunctionError {{ {} }}",
635            to_string_type_function_error(&self.error)
636        )
637    }
638}
639
640impl ErrorToString for ReservedIdentifier {
641    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
642        write!(stream, "ReservedIdentifier {{ {} }}", self.name)
643    }
644}
645
646impl ErrorToString for CannotAssignToNever {
647    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
648        write!(
649            stream,
650            "CannotAssignToNever {{ rvalueType = '{}', reason = '",
651            to_string_type_id(self.rhsType)
652        )?;
653
654        // C++: stream << err.reason; (operator<< for CannotAssignToNever::Reason)
655        match self.reason {
656            Reason::PropertyNarrowed => write!(stream, "PropertyNarrowed")?,
657            #[allow(unreachable_patterns)]
658            _ => write!(stream, "UnknownReason")?,
659        }
660
661        write!(stream, "', cause = {{ ")?;
662
663        let mut first = true;
664        for ty in &self.cause {
665            if first {
666                first = false;
667            } else {
668                write!(stream, ", ")?;
669            }
670
671            write!(stream, "'{}'", to_string_type_id(*ty))?;
672        }
673
674        write!(stream, " }} }} ")
675    }
676}
677
678impl ErrorToString for UnexpectedArrayLikeTableItem {
679    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
680        write!(stream, "UnexpectedArrayLikeTableItem {{}}")
681    }
682}
683
684impl ErrorToString for CannotCheckDynamicStringFormatCalls {
685    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
686        write!(stream, "CannotCheckDynamicStringFormatCalls {{}}")
687    }
688}
689
690impl ErrorToString for GenericTypeCountMismatch {
691    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
692        write!(
693            stream,
694            "GenericTypeCountMismatch {{ subTyGenericCount = {}, superTyGenericCount = {} }}",
695            self.sub_ty_generic_count, self.super_ty_generic_count
696        )
697    }
698}
699
700impl ErrorToString for GenericTypePackCountMismatch {
701    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
702        write!(
703            stream,
704            "GenericTypePackCountMismatch {{ subTyGenericPackCount = {}, superTyGenericPackCount = {} }}",
705            self.subTyGenericPackCount, self.superTyGenericPackCount
706        )
707    }
708}
709
710impl ErrorToString for MultipleNonviableOverloads {
711    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
712        write!(
713            stream,
714            "MultipleNonviableOverloads {{ attemptedArgCount = {} }}",
715            self.attempted_arg_count
716        )
717    }
718}
719
720impl ErrorToString for RecursiveRestraintViolation {
721    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
722        write!(stream, "RecursiveRestraintViolation")
723    }
724}
725
726impl ErrorToString for GenericBoundsMismatch {
727    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
728        write!(
729            stream,
730            "GenericBoundsMismatch {{ genericName = {}, lowerBounds = [",
731            self.generic_name
732        )?;
733        for i in 0..self.lower_bounds.len() {
734            if i > 0 {
735                write!(stream, ", ")?;
736            }
737            write!(stream, "{}", to_string_type_id(self.lower_bounds[i]))?;
738        }
739        write!(stream, "], upperBounds = [")?;
740        for i in 0..self.upper_bounds.len() {
741            if i > 0 {
742                write!(stream, ", ")?;
743            }
744            write!(stream, "{}", to_string_type_id(self.upper_bounds[i]))?;
745        }
746        write!(stream, "] }}")
747    }
748}
749
750impl ErrorToString for InstantiateGenericsOnNonFunction {
751    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
752        write!(
753            stream,
754            "InstantiateGenericsOnNonFunctionInstantiateGenericsOnNonFunction {{ interestingEdgeCase = "
755        )?;
756
757        // C++: stream << err.interestingEdgeCase; (operator<< for InterestingEdgeCase)
758        match self.interesting_edge_case {
759            InterestingEdgeCase::None => write!(stream, "None")?,
760            InterestingEdgeCase::MetatableCall => write!(stream, "MetatableCall")?,
761            InterestingEdgeCase::Intersection => write!(stream, "Intersection")?,
762            #[allow(unreachable_patterns)]
763            _ => {
764                luaur_common::LUAU_ASSERT!(false);
765                write!(stream, "Unknown")?;
766            }
767        }
768
769        write!(stream, " }}")
770    }
771}
772
773impl ErrorToString for TypeInstantiationCountMismatch {
774    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
775        let function_name = self.functionName.as_deref().unwrap_or("<unknown>");
776        write!(
777            stream,
778            "TypeInstantiationCountMismatch {{ functionName = {}, functionType = {}, providedTypes = {}, maximumTypes = {}, providedTypePacks = {}, maximumTypePacks = {} }}",
779            function_name,
780            to_string_type_id(self.functionType),
781            self.providedTypes,
782            self.maximumTypes,
783            self.providedTypePacks,
784            self.maximumTypePacks
785        )
786    }
787}
788
789impl ErrorToString for UnappliedTypeFunction {
790    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
791        write!(stream, "UnappliedTypeFunction {{}}")
792    }
793}
794
795impl ErrorToString for AmbiguousFunctionCall {
796    fn error_to_string_impl(&self, stream: &mut dyn Write) -> core::fmt::Result {
797        write!(
798            stream,
799            "AmbiguousFunctionCall {{ {}, {} }}",
800            to_string_type_id(self.function),
801            to_string_type_pack_id(self.arguments)
802        )
803    }
804}