use crate::ns::*;
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum TypeConversionVariant {
FromAny,
ToAny,
BetweenNumber,
ToCovariant,
ObjectToItrfc,
ItrfcToObject,
NonNullableToNullable,
AsIsToNullable,
NullableToAsIs,
NonNullableToAsIs,
ToContravariant,
ToCovariantVector,
StringToEnum,
NumberToEnum,
FunctionToStructuralFunction,
FromTypeParameter,
ParameterizedTypeAlter,
}
pub struct TypeConversions<'a>(pub &'a SemanticHost);
impl<'a> TypeConversions<'a> {
pub fn implicit_constant(&self, value: &Thingy, target_type: &Thingy) -> Result<Option<Thingy>, DeferError> {
let from_type = value.static_type(self.0);
if &from_type == target_type {
return Ok(Some(value.clone()));
}
if !value.is::<Constant>() {
return Ok(None);
}
if value.is::<UndefinedConstant>() {
if target_type.includes_undefined(self.0)? {
return Ok(Some(self.0.factory().create_undefined_constant(target_type)));
} else if target_type.includes_null(self.0)? {
return Ok(Some(self.0.factory().create_null_constant(target_type)));
}
}
if value.is::<NullConstant>() && (target_type.includes_undefined(self.0)? || target_type.includes_null(self.0)?) {
return Ok(Some(self.0.factory().create_null_constant(target_type)));
}
let object_type = self.0.object_type().defer()?;
let target_esc_type = target_type.escape_of_nullable_or_non_nullable();
if value.is::<NumberConstant>() && (target_type.is::<AnyType>() || target_esc_type == object_type) {
return Ok(Some(self.0.factory().create_number_constant(value.number_value(), target_type)));
}
if value.is::<NumberConstant>() && self.0.numeric_types()?.contains(&target_esc_type) {
let v = value.number_value().convert_type(target_type, self.0)?;
return Ok(Some(self.0.factory().create_number_constant(v, target_type)));
}
if (target_type.is::<NullableType>() && target_type.base() == from_type.escape_of_nullable_or_non_nullable())
|| (target_type.is::<NonNullableType>() && target_type.base() == from_type.escape_of_nullable_or_non_nullable()) {
let new_k = value.clone_constant(self.0);
new_k.set_static_type(target_type.clone());
return Ok(Some(new_k));
}
Ok(None)
}
pub fn implicit(&self, value: &Thingy, target_type: &Thingy, optional: bool) -> Result<Option<Thingy>, DeferError> {
let from_type = value.static_type(self.0);
if &from_type == target_type {
return Ok(Some(value.clone()));
}
let kc = self.implicit_constant(value, target_type)?;
if kc.is_some() {
return Ok(kc);
}
if from_type.is::<AnyType>() {
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::FromAny, optional, target_type)?));
}
if target_type.is::<AnyType>() {
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::ToAny, optional, target_type)?));
}
if self.0.numeric_types()?.contains(&from_type) && self.0.numeric_types()?.contains(&target_type) {
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::BetweenNumber, optional, target_type)?));
}
let from_type_esc = from_type.escape_of_nullable_or_non_nullable();
let target_type_esc = target_type.escape_of_nullable_or_non_nullable();
if from_type_esc.is_subtype_of(&target_type_esc, self.0)? {
let both_include_null = from_type.includes_null(self.0)? && target_type.includes_null(self.0)?;
let both_dont_include_null = !from_type.includes_null(self.0)? && !target_type.includes_null(self.0)?;
if both_include_null || both_dont_include_null {
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::ToCovariant, optional, target_type)?));
}
}
let object_type = self.0.object_type().defer()?;
if target_type_esc == object_type && from_type_esc.is_interface_type_possibly_after_sub() {
let both_include_null = from_type.includes_null(self.0)? && target_type.includes_null(self.0)?;
let both_dont_include_null = !from_type.includes_null(self.0)? && !target_type.includes_null(self.0)?;
if both_include_null || both_dont_include_null {
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::ItrfcToObject, optional, target_type)?));
}
}
if target_type.is::<NullableType>() {
if from_type.is::<NonNullableType>() && from_type.base() == target_type.base() {
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::NonNullableToNullable, optional, target_type)?));
}
if from_type == target_type.base() {
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::AsIsToNullable, optional, target_type)?));
}
}
if from_type.is::<NullableType>() && target_type == &from_type.base() && target_type.includes_null(self.0)? {
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::NullableToAsIs, optional, target_type)?));
}
if from_type.is::<NonNullableType>() && target_type == &from_type.base() {
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::NonNullableToAsIs, optional, target_type)?));
}
let function_type = self.0.function_type().defer()?;
if from_type_esc == function_type && target_type_esc.is::<FunctionType>() {
let both_include_null = from_type.includes_null(self.0)? && target_type.includes_null(self.0)?;
let both_dont_include_null = !from_type.includes_null(self.0)? && !target_type.includes_null(self.0)?;
if both_include_null || both_dont_include_null {
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::FunctionToStructuralFunction, optional, target_type)?));
}
}
Ok(None)
}
pub fn explicit(&self, value: &Thingy, target_type: &Thingy, optional: bool) -> Result<Option<Thingy>, DeferError> {
let from_type = value.static_type(self.0);
if &from_type == target_type {
return Ok(Some(value.clone()));
}
let ic = self.implicit(value, target_type, optional)?;
if ic.is_some() {
return Ok(ic);
}
let from_type_esc = from_type.escape_of_nullable_or_non_nullable();
let target_type_esc = target_type.escape_of_nullable_or_non_nullable();
let object_type = self.0.object_type().defer()?;
if from_type_esc == object_type && target_type_esc.is_interface_type_possibly_after_sub() {
let both_include_null = from_type.includes_null(self.0)? && target_type.includes_null(self.0)?;
let both_dont_include_null = !from_type.includes_null(self.0)? && !target_type.includes_null(self.0)?;
if both_include_null || both_dont_include_null {
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::ObjectToItrfc, optional, target_type)?));
}
}
if from_type_esc.is_ascending_type_of(&target_type_esc, self.0)? {
let both_include_null = from_type.includes_null(self.0)? && target_type.includes_null(self.0)?;
let both_dont_include_null = !from_type.includes_null(self.0)? && !target_type.includes_null(self.0)?;
if both_include_null || both_dont_include_null {
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::ToContravariant, optional, target_type)?));
}
}
if let Some(el_subtype) = from_type_esc.vector_element_type(self.0)? {
if let Some(el_basetype) = target_type_esc.vector_element_type(self.0)? {
let asc = el_basetype.escape_of_nullable_or_non_nullable().is_ascending_type_of(&el_subtype.escape_of_nullable_or_non_nullable(), self.0)?;
let both_el_include_null = el_basetype.includes_null(self.0)? && el_subtype.includes_null(self.0)?;
let both_el_dont_include_null = !el_basetype.includes_null(self.0)? && !el_subtype.includes_null(self.0)?;
if asc && (both_el_include_null || both_el_dont_include_null) {
let both_include_null = from_type.includes_null(self.0)? && target_type.includes_null(self.0)?;
let both_dont_include_null = !from_type.includes_null(self.0)? && !target_type.includes_null(self.0)?;
if both_include_null || both_dont_include_null {
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::ToCovariantVector, optional, target_type)?));
}
}
}
}
let string_type = self.0.string_type().defer()?;
if from_type.escape_of_non_nullable() == string_type && target_type.escape_of_non_nullable().is::<EnumType>() {
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::StringToEnum, optional, target_type)?));
}
let number_type = self.0.number_type().defer()?;
if from_type == number_type && target_type.escape_of_non_nullable().is::<EnumType>() {
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::NumberToEnum, optional, target_type)?));
}
if from_type.escape_of_non_nullable().is::<TypeParameterType>() {
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::FromTypeParameter, optional, target_type)?));
}
if from_type_esc.is_parameterized_type_or_type_after_sub() && target_type_esc.is_parameterized_type_or_type_after_sub() {
let from_origin = from_type_esc.origin_or_parameterized_type_identity().unwrap();
let target_origin = target_type_esc.origin_or_parameterized_type_identity().unwrap();
let vector_type = self.0.vector_type().defer()?;
let both_include_null = from_type.includes_null(self.0)? && target_type.includes_null(self.0)?;
let both_dont_include_null = !from_type.includes_null(self.0)? && !target_type.includes_null(self.0)?;
if from_origin == target_origin && from_origin != vector_type
&& (both_include_null || both_dont_include_null)
{
return Ok(Some(self.0.factory().create_conversion_value(value, TypeConversionVariant::ParameterizedTypeAlter, optional, target_type)?));
}
}
Ok(None)
}
}