use crate::error::CompilerError;
use ariadne::{Config, Source};
mod errors;
mod errors_advanced;
mod internal_codes;
fn colour_enabled() -> bool {
std::env::var_os("NO_COLOR").is_none_or(|v| v.is_empty())
}
#[must_use]
pub fn report_error(error: &CompilerError, source: &str, filename: &str) -> String {
let with_colour = colour_enabled();
if !with_colour {
yansi::disable();
}
let mut output = Vec::new();
let report =
build_error_report(error, filename).with_config(Config::default().with_color(with_colour));
let render = report
.finish()
.write((filename, Source::from(source)), &mut output);
if !with_colour {
yansi::enable();
}
if let Err(write_error) = render {
return format!("failed to render error: {write_error}\n{error}");
}
String::from_utf8_lossy(&output).into_owned()
}
pub(crate) type ReportBuilder<'a> = ariadne::ReportBuilder<'a, (&'a str, std::ops::Range<usize>)>;
#[expect(
clippy::too_many_lines,
reason = "exhaustive match over ~60 CompilerError variants — each arm dispatches to a per-variant builder"
)]
fn build_error_report<'a>(error: &'a CompilerError, filename: &'a str) -> ReportBuilder<'a> {
let span = error.span();
match error {
CompilerError::ParseError { message, .. } => errors::parse_error(filename, span, message),
CompilerError::UndefinedType { name, .. } => errors::undefined_type(filename, span, name),
CompilerError::TraitUsedAsValueType { trait_name, .. } => {
errors::trait_used_as_value_type(filename, span, trait_name)
}
CompilerError::DuplicateDefinition { name, .. } => {
errors::duplicate_definition(filename, span, name)
}
CompilerError::TypeMismatch {
expected, found, ..
} => errors::type_mismatch(filename, span, expected, found),
CompilerError::ModuleNotFound { name, .. } => {
errors::module_not_found(filename, span, name)
}
CompilerError::CircularImport { cycle, .. } => {
errors::circular_import(filename, span, cycle)
}
CompilerError::CircularDependency { cycle, .. } => {
errors::circular_dependency(filename, span, cycle)
}
CompilerError::MissingTraitField {
field, trait_name, ..
} => errors_advanced::missing_trait_field(filename, span, field, trait_name),
CompilerError::TraitFieldTypeMismatch {
field,
trait_name,
expected,
actual,
..
} => errors_advanced::trait_field_type_mismatch(
filename, span, field, trait_name, expected, actual,
),
CompilerError::InvalidBinaryOp {
op,
left_type,
right_type,
..
} => errors::invalid_binary_op(filename, span, op, left_type, right_type),
CompilerError::ForLoopNotArray { actual, .. } => {
errors::for_loop_not_array(filename, span, actual)
}
CompilerError::ArrayDestructuringNotArray { actual, .. } => {
errors::array_destructuring_not_array(filename, span, actual)
}
CompilerError::StructDestructuringNotStruct { actual, .. } => {
errors::struct_destructuring_not_struct(filename, span, actual)
}
CompilerError::InvalidIfCondition { actual, .. } => {
errors::invalid_if_condition(filename, span, actual)
}
CompilerError::MatchNotEnum { actual, .. } => {
errors::match_not_enum(filename, span, actual)
}
CompilerError::NonExhaustiveMatch { missing, .. } => {
errors::non_exhaustive_match(filename, span, missing)
}
CompilerError::DuplicateMatchArm { variant, .. } => {
errors::duplicate_match_arm(filename, span, variant)
}
CompilerError::PrivateImport { name, .. } => errors::private_import(filename, span, name),
CompilerError::ImportItemNotFound {
item,
module,
available,
..
} => errors::import_item_not_found(filename, span, item, module, available),
CompilerError::NotATrait {
name, actual_kind, ..
} => errors::not_a_trait(filename, span, name, actual_kind),
CompilerError::UnknownEnumVariant {
variant, enum_name, ..
} => errors::unknown_enum_variant(filename, span, variant, enum_name),
CompilerError::VariantArityMismatch {
variant,
expected,
actual,
..
} => errors::variant_arity_mismatch(filename, span, variant, *expected, *actual),
CompilerError::InvalidCharacter { character, .. } => {
errors::invalid_character(filename, span, *character)
}
CompilerError::UnterminatedString { .. } => errors::unterminated_string(filename, span),
CompilerError::UnterminatedBlockComment { .. } => {
errors::unterminated_block_comment(filename, span)
}
CompilerError::InvalidUnicodeEscape { value, .. } => {
errors::invalid_unicode_escape(filename, span, value)
}
CompilerError::InvalidNumber { value, .. } => errors::invalid_number(filename, span, value),
CompilerError::UnexpectedToken {
expected, found, ..
} => errors::unexpected_token(filename, span, expected, found),
CompilerError::UnexpectedEof { .. } => errors::unexpected_eof(filename, span),
CompilerError::UndefinedReference { name, .. } => {
errors::undefined_reference(filename, span, name)
}
CompilerError::PrimitiveRedefinition { name, .. } => {
errors::primitive_redefinition(filename, span, name)
}
CompilerError::UndefinedTrait { name, .. } => errors::undefined_trait(filename, span, name),
CompilerError::ModuleReadError { path, error, .. } => {
errors::module_read_error(filename, span, path, error)
}
CompilerError::MissingField {
field, type_name, ..
} => errors_advanced::missing_field(filename, span, field, type_name),
CompilerError::UnknownField {
field, type_name, ..
} => errors_advanced::unknown_field(filename, span, field, type_name),
CompilerError::AssignmentToImmutable { .. } => {
errors_advanced::assignment_to_immutable(filename, span)
}
CompilerError::PositionalArgInStruct {
struct_name,
position,
..
} => errors_advanced::positional_arg_in_struct(filename, span, struct_name, *position),
CompilerError::EnumVariantWithoutData {
variant, enum_name, ..
} => errors_advanced::enum_variant_without_data(filename, span, variant, enum_name),
CompilerError::EnumVariantRequiresData {
variant, enum_name, ..
} => errors_advanced::enum_variant_requires_data(filename, span, variant, enum_name),
CompilerError::MutabilityMismatch { param, .. } => {
errors_advanced::mutability_mismatch(filename, span, param)
}
CompilerError::UseAfterSink { name, .. } => {
errors_advanced::use_after_sink(filename, span, name)
}
CompilerError::GenericArityMismatch {
name,
expected,
actual,
..
} => errors_advanced::generic_arity_mismatch(filename, span, name, *expected, *actual),
CompilerError::GenericConstraintViolation {
arg, constraint, ..
} => errors_advanced::generic_constraint_violation(filename, span, arg, constraint),
CompilerError::OutOfScopeTypeParameter { param, .. } => {
errors_advanced::out_of_scope_type_parameter(filename, span, param)
}
CompilerError::MissingGenericArguments { name, .. } => {
errors_advanced::missing_generic_arguments(filename, span, name)
}
CompilerError::DuplicateGenericParam { param, .. } => {
errors_advanced::duplicate_generic_param(filename, span, param)
}
CompilerError::ExternFnWithBody { function, .. } => {
errors_advanced::extern_fn_with_body(filename, span, function)
}
CompilerError::RegularFnWithoutBody { function, .. } => {
errors_advanced::regular_fn_without_body(filename, span, function)
}
CompilerError::ExternImplWithBody { name, .. } => {
errors_advanced::extern_impl_with_body(filename, span, name)
}
CompilerError::RequiredParamAfterDefault {
function, param, ..
} => errors_advanced::required_param_after_default(filename, span, function, param),
CompilerError::NilAssignedToNonOptional { expected, .. } => {
errors_advanced::nil_assigned_to_non_optional(filename, span, expected)
}
CompilerError::OptionalUsedAsNonOptional {
actual, expected, ..
} => errors_advanced::optional_used_as_non_optional(filename, span, actual, expected),
CompilerError::MissingTraitMethod {
method, trait_name, ..
} => errors_advanced::missing_trait_method(filename, span, method, trait_name),
CompilerError::TraitMethodSignatureMismatch {
method,
trait_name,
expected,
actual,
..
} => errors_advanced::trait_method_signature_mismatch(
filename, span, method, trait_name, expected, actual,
),
CompilerError::FunctionReturnTypeMismatch {
function,
expected,
actual,
..
} => errors_advanced::function_return_type_mismatch(
filename, span, function, expected, actual,
),
CompilerError::AmbiguousCall { function, .. } => {
errors_advanced::ambiguous_call(filename, span, function)
}
CompilerError::NoMatchingOverload { function, .. } => {
errors_advanced::no_matching_overload(filename, span, function)
}
CompilerError::CannotInferEnumType { variant, .. } => {
errors_advanced::cannot_infer_enum_type(filename, span, variant)
}
CompilerError::ExpressionDepthExceeded { .. } => {
errors_advanced::expression_depth_exceeded(filename, span)
}
CompilerError::TooManyDefinitions { kind, .. } => {
errors_advanced::too_many_definitions(filename, span, kind)
}
CompilerError::VisibilityViolation { name, .. } => {
errors_advanced::visibility_violation(filename, span, name)
}
CompilerError::ClosureCaptureEscapesLocalBinding { binding, .. } => {
errors_advanced::closure_capture_escapes_local_binding(filename, span, binding)
}
CompilerError::InternalError { detail, .. } => {
errors_advanced::internal_error(filename, span, detail)
}
CompilerError::NumericOverflow {
written, target, ..
} => errors::numeric_overflow(filename, span, written, *target),
}
}
#[must_use]
pub fn report_errors(errors: &[CompilerError], source: &str, filename: &str) -> String {
errors
.iter()
.map(|error| report_error(error, source, filename))
.collect::<Vec<_>>()
.join("\n")
}