use crate::dimension::DimensionRegistryError;
use crate::ffi::ArityRange;
use crate::span::Span;
use crate::typed_ast::BinaryOperator;
use crate::{BaseRepresentation, NameResolutionError, Type};
use compact_str::CompactString;
use thiserror::Error;
use super::IncompatibleDimensionsError;
use super::substitutions::SubstitutionError;
fn format_constraint_error(constraints: &[String]) -> String {
if constraints.len() == 1 {
format!(
"Could not solve the following constraint: {}",
constraints[0]
)
} else {
let indented: Vec<_> = constraints.iter().map(|c| format!(" {c}")).collect();
format!(
"Could not solve the following constraints:\n{}\n",
indented.join("\n")
)
}
}
#[derive(Debug, Clone, Error, PartialEq, Eq)]
pub enum TypeCheckError {
#[error("Unknown identifier '{1}'.")]
UnknownIdentifier(Span, String, Option<String>),
#[error(transparent)]
IncompatibleDimensions(IncompatibleDimensionsError),
#[error("Exponents need to be dimensionless (got {1}).")]
NonScalarExponent(Span, Type),
#[error("Argument of factorial needs to be dimensionless (got {1}).")]
NonScalarFactorialArgument(Span, Type),
#[error("Unsupported expression in const-evaluation of exponent: {1}.")]
UnsupportedConstEvalExpression(Span, &'static str),
#[error("Division by zero in const. eval. expression")]
DivisionByZeroInConstEvalExpression(Span),
#[error("{0}")]
DimensionRegistryError(#[from] DimensionRegistryError),
#[error("Incompatible alternative expressions have been provided for dimension '{0}'")]
IncompatibleAlternativeDimensionExpression(
String,
Span,
BaseRepresentation,
Span,
BaseRepresentation,
),
#[error("Function or procedure '{callable_name}' called with {num_args} arguments(s), but needs {}..{}", arity.start(), arity.end())]
WrongArity {
callable_span: Span,
callable_name: String,
callable_definition_span: Option<Span>,
arity: ArityRange,
num_args: usize,
},
#[error(
"'{1}' can not be used as a type parameter because it is also an existing dimension identifier."
)]
TypeParameterNameClash(Span, String),
#[error(
"Foreign function definition (without body) '{1}' needs parameter and return type annotations."
)]
ForeignFunctionNeedsTypeAnnotations(Span, String),
#[error("Unknown foreign function (without body) '{1}'")]
UnknownForeignFunction(Span, String),
#[error("Out-of bounds or non-rational exponent value")]
NonRationalExponent(Span),
#[error("Numerical overflow in const-eval expression")]
OverflowInConstExpr(Span),
#[error("Expected dimension type, got {1} instead")]
ExpectedDimensionType(Span, Type),
#[error("Expected boolean value")]
ExpectedBool(Span),
#[error("Incompatible types in condition")]
IncompatibleTypesInCondition(Span, Type, Span, Type, Span),
#[error("Argument types in assert call must be boolean")]
IncompatibleTypeInAssert(Span, Type, Span),
#[error("Argument types in assert_eq calls must match")]
IncompatibleTypesInAssertEq(Span, Type, Span, Type, Span),
#[error("Incompatible types in {0}")]
IncompatibleTypesInAnnotation(String, Span, Type, Span, Type, Span),
#[error("Incompatible types in comparison operator")]
IncompatibleTypesInComparison(Span, Type, Span, Type, Span),
#[error("Incompatible types in operator")]
IncompatibleTypesInOperator(Span, BinaryOperator, Type, Span, Type, Span),
#[error("Incompatible types in function call: expected '{1}', got '{3}' instead")]
IncompatibleTypesInFunctionCall(Option<Span>, Type, Span, Type),
#[error("Incompatible types for struct field: expected '{1}', got '{3}' instead")]
IncompatibleTypesForStructField(Span, Type, Span, Type),
#[error("Missing a definition for dimension {1}")]
MissingDimension(Span, String),
#[error("Function references can not point to generic functions")]
NoFunctionReferenceToGenericFunction(Span),
#[error("Incompatible types in function call: expected function type, got '{1}'")]
OnlyFunctionsAndReferencesCanBeCalled(Span, Type),
#[error("Base units can not be dimensionless.")]
NoDimensionlessBaseUnit(Span, String),
#[error("Unknown struct '{1}")]
UnknownStruct(Span, String),
#[error("Wrong number of type arguments for '{type_name}': expected {expected}, got {actual}")]
WrongNumberOfTypeArguments {
span: Span,
type_name: String,
expected: usize,
actual: usize,
},
#[error("Field '{2}' does not exist in struct '{3}'")]
UnknownFieldInStructInstantiation(Span, Span, String, String),
#[error("Duplicate field '{2}' in struct definition")]
DuplicateFieldInStructDefinition(Span, Span, String),
#[error("Duplicate field '{2}' in struct instantiation")]
DuplicateFieldInStructInstantiation(Span, Span, String),
#[error("Can not access field '{2}' of non struct type '{3}'")]
FieldAccessOfNonStructType(Span, Span, String, Type),
#[error("Field '{2}' does not exist in struct '{3}'")]
UnknownFieldAccess(Span, Span, String, Type),
#[error("Missing fields in struct instantiation")]
MissingFieldsInStructInstantiation(Span, Span, Vec<(CompactString, Type)>),
#[error("Incompatible types in list: expected '{1}', got '{3}' instead")]
IncompatibleTypesInList(Span, Type, Span, Type),
#[error(transparent)]
NameResolutionError(#[from] NameResolutionError),
#[error("{}", format_constraint_error(_1))]
ConstraintSolverError(Span, Vec<String>),
#[error(
"{1}\nThis error occured while trying to infer types in the (elaborated) statement:\n {0}\n"
)]
SubstitutionError(String, SubstitutionError),
#[error("Missing dimension bound for type parameter")]
MissingDimBound(Span),
#[error(
"Type for exponentiation operation can not be inferred for this case, consider adding a type annotation for the base"
)]
ExponentiationNeedsTypeAnnotation(Span),
#[error("Derived unit definitions may not contain generic types. Use a variable instead")]
DerivedUnitDefinitionMustNotBeGeneric(Span),
#[error("Typed hole")]
TypedHoleInStatement(Span, String, String, Vec<String>),
#[error("Multiple typed holes in statement")]
MultipleTypedHoles(Span),
}
pub type Result<T> = std::result::Result<T, Box<TypeCheckError>>;