//! defines `ValueObj` (used in the compiler, VM). //! //! コンパイラ、VM等で使われる(データも保持した)値オブジェクトを定義する use std::cmp::Ordering; use std::fmt; use std::hash::{Hash, Hasher}; use std::ops::{Add, Deref, Div, Mul, Neg, Rem, Sub}; use std::sync::Arc; use erg_common::consts::DEBUG_MODE; use erg_common::dict::Dict; use erg_common::error::{ErrorCore, ErrorKind, Location}; use erg_common::fresh::FRESH_GEN; use erg_common::io::Input; use erg_common::python_util::PythonVersion; use erg_common::serialize::*; use erg_common::set::Set; use erg_common::traits::LimitedDisplay; use erg_common::{dict, fmt_iter, log, switch_lang}; use erg_common::{ArcArray, Str}; use erg_parser::ast::{ConstArgs, ConstExpr}; use crate::context::eval::type_from_token_kind; use crate::context::Context; use self::value_set::inner_class; use super::codeobj::{tuple_into_bytes, CodeObj}; use super::constructors::{dict_t, list_t, refinement, set_t, tuple_t, unsized_list_t}; use super::free::{Constraint, FreeTyVar, HasLevel}; use super::typaram::{OpKind, TyParam}; use super::{ConstSubr, Field, HasType, Predicate, SharedFrees, Type}; use super::{CONTAINER_OMIT_THRESHOLD, GENERIC_LEVEL, STR_OMIT_THRESHOLD}; pub struct EvalValueError { pub core: Box, pub value: Option, } impl From for EvalValueError { fn from(core: ErrorCore) -> Self { Self { core: Box::new(core), value: None, } } } impl From for ErrorCore { fn from(err: EvalValueError) -> Self { *err.core } } impl EvalValueError { pub fn feature_error(_input: Input, loc: Location, name: &str, caused_by: String) -> Self { Self::from(ErrorCore::new( vec![], format!("{name} is not supported yet: {caused_by}"), 0, ErrorKind::FeatureError, loc, )) } } pub type EvalValueResult = Result; #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct ClassTypeObj { pub t: Type, pub base: Option>, pub impls: Option>, pub inited: bool, } impl ClassTypeObj { pub fn new(t: Type, base: Option, impls: Option, inited: bool) -> Self { Self { t, base: base.map(Box::new), impls: impls.map(Box::new), inited, } } } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct InheritedTypeObj { pub t: Type, pub sup: Box, pub impls: Option>, pub additional: Option>, } impl InheritedTypeObj { pub fn new(t: Type, sup: TypeObj, impls: Option, additional: Option) -> Self { Self { t, sup: Box::new(sup), impls: impls.map(Box::new), additional: additional.map(Box::new), } } } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct TraitTypeObj { pub t: Type, pub requires: Box, pub impls: Option>, pub inited: bool, } impl TraitTypeObj { pub fn new(t: Type, requires: TypeObj, impls: Option, inited: bool) -> Self { Self { t, requires: Box::new(requires), impls: impls.map(Box::new), inited, } } } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct SubsumedTypeObj { pub t: Type, pub sup: Box, pub impls: Option>, pub additional: Option>, } impl SubsumedTypeObj { pub fn new(t: Type, sup: TypeObj, impls: Option, additional: Option) -> Self { Self { t, sup: Box::new(sup), impls: impls.map(Box::new), additional: additional.map(Box::new), } } } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct UnionTypeObj { pub t: Type, pub lhs: Box, pub rhs: Box, } impl UnionTypeObj { pub fn new(t: Type, lhs: TypeObj, rhs: TypeObj) -> Self { Self { t, lhs: Box::new(lhs), rhs: Box::new(rhs), } } } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct IntersectionTypeObj { pub t: Type, pub lhs: Box, pub rhs: Box, } impl IntersectionTypeObj { pub fn new(t: Type, lhs: TypeObj, rhs: TypeObj) -> Self { Self { t, lhs: Box::new(lhs), rhs: Box::new(rhs), } } } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct StructuralTypeObj { pub t: Type, pub base: Box, } impl StructuralTypeObj { pub fn new(t: Type, base: TypeObj) -> Self { Self { t, base: Box::new(base), } } } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct PatchObj { pub t: Type, pub base: Box, pub impls: Option>, } impl PatchObj { pub fn new(t: Type, base: TypeObj, impls: Option) -> Self { Self { t, base: Box::new(base), impls: impls.map(Box::new), } } } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum GenTypeObj { Class(ClassTypeObj), Subclass(InheritedTypeObj), Trait(TraitTypeObj), Subtrait(SubsumedTypeObj), Structural(StructuralTypeObj), Union(UnionTypeObj), Intersection(IntersectionTypeObj), Patch(PatchObj), } impl fmt::Display for GenTypeObj { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if DEBUG_MODE { write!(f, "<")?; } self.typ().fmt(f)?; if DEBUG_MODE { write!(f, ">")?; } Ok(()) } } impl LimitedDisplay for GenTypeObj { fn limited_fmt(&self, f: &mut W, limit: isize) -> std::fmt::Result { if DEBUG_MODE { write!(f, "<")?; } self.typ().limited_fmt(f, limit)?; if DEBUG_MODE { write!(f, ">")?; } Ok(()) } } impl GenTypeObj { pub fn class(t: Type, require: Option, impls: Option, inited: bool) -> Self { GenTypeObj::Class(ClassTypeObj::new(t, require, impls, inited)) } pub fn inherited( t: Type, sup: TypeObj, impls: Option, additional: Option, ) -> Self { GenTypeObj::Subclass(InheritedTypeObj::new(t, sup, impls, additional)) } pub fn trait_(t: Type, require: TypeObj, impls: Option, inited: bool) -> Self { GenTypeObj::Trait(TraitTypeObj::new(t, require, impls, inited)) } pub fn patch(t: Type, base: TypeObj, impls: Option) -> Self { GenTypeObj::Patch(PatchObj::new(t, base, impls)) } pub fn subsumed( t: Type, sup: TypeObj, impls: Option, additional: Option, ) -> Self { GenTypeObj::Subtrait(SubsumedTypeObj::new(t, sup, impls, additional)) } pub fn union(t: Type, lhs: TypeObj, rhs: TypeObj) -> Self { GenTypeObj::Union(UnionTypeObj::new(t, lhs, rhs)) } pub fn intersection(t: Type, lhs: TypeObj, rhs: TypeObj) -> Self { GenTypeObj::Intersection(IntersectionTypeObj::new(t, lhs, rhs)) } pub fn structural(t: Type, type_: TypeObj) -> Self { GenTypeObj::Structural(StructuralTypeObj::new(t, type_)) } pub const fn is_inited(&self) -> bool { match self { Self::Class(class) => class.inited, Self::Trait(trait_) => trait_.inited, _ => true, } } pub fn base_or_sup(&self) -> Option<&TypeObj> { match self { Self::Class(class) => class.base.as_ref().map(AsRef::as_ref), Self::Subclass(subclass) => Some(subclass.sup.as_ref()), Self::Trait(trait_) => Some(trait_.requires.as_ref()), Self::Subtrait(subtrait) => Some(subtrait.sup.as_ref()), Self::Structural(type_) => Some(type_.base.as_ref()), Self::Patch(patch) => Some(patch.base.as_ref()), _ => None, } } pub fn impls(&self) -> Option<&TypeObj> { match self { Self::Class(class) => class.impls.as_ref().map(|x| x.as_ref()), Self::Subclass(subclass) => subclass.impls.as_ref().map(|x| x.as_ref()), Self::Subtrait(subtrait) => subtrait.impls.as_ref().map(|x| x.as_ref()), Self::Patch(patch) => patch.impls.as_ref().map(|x| x.as_ref()), _ => None, } } pub fn impls_mut(&mut self) -> Option<&mut Option>> { match self { Self::Class(class) => Some(&mut class.impls), Self::Subclass(subclass) => Some(&mut subclass.impls), Self::Subtrait(subtrait) => Some(&mut subtrait.impls), Self::Patch(patch) => Some(&mut patch.impls), _ => None, } } pub fn additional(&self) -> Option<&TypeObj> { match self { Self::Subclass(subclass) => subclass.additional.as_ref().map(|x| x.as_ref()), Self::Subtrait(subtrait) => subtrait.additional.as_ref().map(|x| x.as_ref()), _ => None, } } pub fn meta_type(&self) -> Type { match self { Self::Class(_) | Self::Subclass(_) => Type::ClassType, Self::Trait(_) | Self::Subtrait(_) => Type::TraitType, Self::Patch(_) => Type::Patch, Self::Structural(_) => Type::Type, _ => Type::Type, } } pub fn typ(&self) -> &Type { match self { Self::Class(class) => &class.t, Self::Subclass(subclass) => &subclass.t, Self::Trait(trait_) => &trait_.t, Self::Subtrait(subtrait) => &subtrait.t, Self::Structural(struct_) => &struct_.t, Self::Union(union_) => &union_.t, Self::Intersection(intersection) => &intersection.t, Self::Patch(patch) => &patch.t, } } pub fn typ_mut(&mut self) -> &mut Type { match self { Self::Class(class) => &mut class.t, Self::Subclass(subclass) => &mut subclass.t, Self::Trait(trait_) => &mut trait_.t, Self::Subtrait(subtrait) => &mut subtrait.t, Self::Structural(struct_) => &mut struct_.t, Self::Union(union_) => &mut union_.t, Self::Intersection(intersection) => &mut intersection.t, Self::Patch(patch) => &mut patch.t, } } pub fn into_typ(self) -> Type { match self { Self::Class(class) => class.t, Self::Subclass(subclass) => subclass.t, Self::Trait(trait_) => trait_.t, Self::Subtrait(subtrait) => subtrait.t, Self::Structural(struct_) => struct_.t, Self::Union(union_) => union_.t, Self::Intersection(intersection) => intersection.t, Self::Patch(patch) => patch.t, } } pub fn map_t(&mut self, f: impl FnOnce(Type) -> Type) { *self.typ_mut() = f(std::mem::take(self.typ_mut())); } pub fn map_tp(&mut self, f: &mut impl FnMut(TyParam) -> TyParam, tvs: &SharedFrees) { *self.typ_mut() = std::mem::take(self.typ_mut()).map_tp(f, tvs); } pub fn try_map_t(&mut self, f: impl FnOnce(Type) -> Result) -> Result<(), E> { *self.typ_mut() = f(std::mem::take(self.typ_mut()))?; Ok(()) } pub fn try_map_tp( &mut self, f: &mut impl FnMut(TyParam) -> Result, tvs: &SharedFrees, ) -> Result<(), E> { *self.typ_mut() = std::mem::take(self.typ_mut()).try_map_tp(f, tvs)?; Ok(()) } } #[derive(Clone, Debug, Eq)] pub enum TypeObj { Builtin { t: Type, meta_t: Type }, Generated(GenTypeObj), } impl PartialEq for TypeObj { fn eq(&self, other: &Self) -> bool { self.typ() == other.typ() } } impl Hash for TypeObj { fn hash(&self, state: &mut H) { self.typ().hash(state); } } impl fmt::Display for TypeObj { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.limited_fmt(f, ::DEFAULT_LIMIT) } } impl LimitedDisplay for TypeObj { fn limited_fmt(&self, f: &mut W, limit: isize) -> std::fmt::Result { match self { TypeObj::Builtin { t, .. } => { if DEBUG_MODE { write!(f, "") } else { t.limited_fmt(f, limit - 1) } } TypeObj::Generated(t) => { if DEBUG_MODE { write!(f, "") } else { t.limited_fmt(f, limit - 1) } } } } } impl TypeObj { pub fn builtin_type(t: Type) -> Self { TypeObj::Builtin { t, meta_t: Type::Type, } } pub fn builtin_trait(t: Type) -> Self { TypeObj::Builtin { t, meta_t: Type::TraitType, } } pub const fn is_inited(&self) -> bool { match self { Self::Builtin { .. } => true, Self::Generated(gen) => gen.is_inited(), } } pub fn typ(&self) -> &Type { match self { TypeObj::Builtin { t, .. } => t, TypeObj::Generated(t) => t.typ(), } } pub fn typ_mut(&mut self) -> &mut Type { match self { TypeObj::Builtin { t, .. } => t, TypeObj::Generated(t) => t.typ_mut(), } } pub fn into_typ(self) -> Type { match self { TypeObj::Builtin { t, .. } => t, TypeObj::Generated(t) => t.into_typ(), } } pub fn contains_intersec(&self, other: &Type) -> bool { match self { TypeObj::Builtin { t, .. } => t.contains_intersec(other), TypeObj::Generated(t) => t.typ().contains_intersec(other), } } pub fn map_t(&mut self, f: impl FnOnce(Type) -> Type) { match self { TypeObj::Builtin { t, .. } => *t = f(std::mem::take(t)), TypeObj::Generated(t) => t.map_t(f), } } pub fn map_tp(&mut self, f: &mut impl FnMut(TyParam) -> TyParam, tvs: &SharedFrees) { match self { TypeObj::Builtin { t, .. } => *t = std::mem::take(t).map_tp(f, tvs), TypeObj::Generated(t) => t.map_tp(f, tvs), } } pub fn mapped_t(mut self, f: impl FnOnce(Type) -> Type) -> Self { self.map_t(f); self } pub fn mapped_tp(mut self, f: &mut impl FnMut(TyParam) -> TyParam, tvs: &SharedFrees) -> Self { self.map_tp(f, tvs); self } pub fn try_map_t(&mut self, f: &mut impl FnMut(Type) -> Result) -> Result<(), E> { match self { TypeObj::Builtin { t, .. } => { *t = f(std::mem::take(t))?; Ok(()) } TypeObj::Generated(t) => t.try_map_t(f), } } pub fn try_mapped_t( mut self, f: &mut impl FnMut(Type) -> Result, ) -> Result { self.try_map_t(f)?; Ok(self) } pub fn try_map_tp( &mut self, f: &mut impl FnMut(TyParam) -> Result, tvs: &SharedFrees, ) -> Result<(), E> { match self { TypeObj::Builtin { t, .. } => { *t = std::mem::take(t).try_map_tp(f, tvs)?; Ok(()) } TypeObj::Generated(t) => t.try_map_tp(f, tvs), } } pub fn try_mapped_tp( mut self, f: &mut impl FnMut(TyParam) -> Result, tvs: &SharedFrees, ) -> Result { self.try_map_tp(f, tvs)?; Ok(self) } } #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] pub struct Float(f64); impl fmt::Display for Float { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) } } impl Eq for Float {} #[allow(clippy::derive_ord_xor_partial_ord)] impl Ord for Float { fn cmp(&self, other: &Self) -> Ordering { self.0.partial_cmp(&other.0).unwrap() } } // HACK: impl Hash for Float { fn hash(&self, state: &mut H) { self.0.to_bits().hash(state); } } impl Deref for Float { type Target = f64; fn deref(&self) -> &Self::Target { &self.0 } } impl Neg for Float { type Output = Self; fn neg(self) -> Self { Self(-self.0) } } impl Add for Float { type Output = Self; fn add(self, other: Self) -> Self { Self(self.0 + other.0) } } impl Sub for Float { type Output = Self; fn sub(self, other: Self) -> Self { Self(self.0 - other.0) } } impl Mul for Float { type Output = Self; fn mul(self, other: Self) -> Self { Self(self.0 * other.0) } } impl Div for Float { type Output = Self; fn div(self, other: Self) -> Self { Self(self.0 / other.0) } } impl Rem for Float { type Output = Self; fn rem(self, other: Self) -> Self { Self(self.0 % other.0) } } /// 値オブジェクト /// コンパイル時評価ができ、シリアライズも可能(Typeなどはシリアライズ不可) #[derive(Clone, Default, Hash)] pub enum ValueObj { Int(i32), Nat(u64), Float(Float), Str(Str), Bool(bool), List(ArcArray), UnsizedList(Box), Set(Set), Dict(Dict), Tuple(ArcArray), Record(Dict), DataClass { name: Str, fields: Dict, }, Code(Box), Subr(ConstSubr), Type(TypeObj), None, Ellipsis, NotImplemented, NegInf, /// different from `Float.Inf` Inf, #[default] Failure, // placeholder for illegal values } #[macro_export] macro_rules! mono_value_pattern { () => { $crate::ty::ValueObj::Int(_) | $crate::ty::ValueObj::Nat(_) | $crate::ty::ValueObj::Float(_) | $crate::ty::ValueObj::Inf | $crate::ty::ValueObj::NegInf | $crate::ty::ValueObj::Bool(_) | $crate::ty::ValueObj::Str(_) | $crate::ty::ValueObj::Code(_) | $crate::ty::ValueObj::None | $crate::ty::ValueObj::NotImplemented | $crate::ty::ValueObj::Ellipsis | $crate::ty::ValueObj::Failure }; (-Failure) => { $crate::ty::ValueObj::Int(_) | $crate::ty::ValueObj::Nat(_) | $crate::ty::ValueObj::Float(_) | $crate::ty::ValueObj::Inf | $crate::ty::ValueObj::NegInf | $crate::ty::ValueObj::Bool(_) | $crate::ty::ValueObj::Str(_) | $crate::ty::ValueObj::Code(_) | $crate::ty::ValueObj::None | $crate::ty::ValueObj::NotImplemented | $crate::ty::ValueObj::Ellipsis }; } impl fmt::Debug for ValueObj { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Int(i) => { if DEBUG_MODE { write!(f, "Int({i})") } else { write!(f, "{i}") } } Self::Nat(n) => { if DEBUG_MODE { write!(f, "Nat({n})") } else { write!(f, "{n}") } } Self::Float(fl) => { // In Rust, .0 is shown omitted. if fl.fract() < 1e-10 { write!(f, "{fl:.1}")?; } else { write!(f, "{fl}")?; } if DEBUG_MODE { write!(f, "f64")?; } Ok(()) } Self::Str(s) => write!(f, "\"{}\"", s.escape()), Self::Bool(b) => { if *b { write!(f, "True") } else { write!(f, "False") } } Self::List(lis) => write!(f, "[{}]", fmt_iter(lis.iter())), Self::UnsizedList(elem) => write!(f, "[{elem}; _]"), Self::Dict(dict) => { write!(f, "{{")?; for (i, (k, v)) in dict.iter().enumerate() { if i != 0 { write!(f, ", ")?; } write!(f, "{k}: {v}")?; } write!(f, "}}") } Self::Tuple(tup) => write!(f, "({})", fmt_iter(tup.iter())), Self::Set(st) => write!(f, "{{{}}}", fmt_iter(st.iter())), Self::Code(code) => write!(f, "{code}"), Self::Record(rec) => { write!(f, "{{")?; for (i, (k, v)) in rec.iter().enumerate() { if i != 0 { write!(f, "; ")?; } write!(f, "{k} = {v}")?; } write!(f, "}}") } Self::DataClass { name, fields } => { write!(f, "{name} {{")?; for (i, (k, v)) in fields.iter().enumerate() { if i != 0 { write!(f, "; ")?; } write!(f, "{k} = {v}")?; } write!(f, "}}") } Self::Subr(subr) => subr.fmt(f), Self::Type(t) => t.fmt(f), Self::None => write!(f, "None"), Self::Ellipsis => write!(f, "Ellipsis"), Self::NotImplemented => write!(f, "NotImplemented"), Self::NegInf => write!(f, "-Inf"), Self::Inf => write!(f, "Inf"), Self::Failure => write!(f, ""), } } } impl fmt::Display for ValueObj { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Int(i) => { if DEBUG_MODE { write!(f, "Int({i})") } else { write!(f, "{i}") } } Self::Nat(n) => { if DEBUG_MODE { write!(f, "Nat({n})") } else { write!(f, "{n}") } } Self::Float(fl) => { // In Rust, .0 is shown omitted. if fl.fract() < 1e-10 { write!(f, "{fl:.1}")?; } else { write!(f, "{fl}")?; } if DEBUG_MODE { write!(f, "f64")?; } Ok(()) } Self::Str(s) => write!(f, "\"{}\"", s.escape()), Self::Bool(b) => { if *b { write!(f, "True") } else { write!(f, "False") } } Self::List(lis) => write!(f, "[{}]", fmt_iter(lis.iter())), Self::UnsizedList(elem) => write!(f, "[{elem}; _]"), Self::Dict(dict) => { write!(f, "{{")?; for (i, (k, v)) in dict.iter().enumerate() { if i != 0 { write!(f, ", ")?; } write!(f, "{k}: {v}")?; } write!(f, "}}") } Self::Tuple(tup) => write!(f, "({})", fmt_iter(tup.iter())), Self::Set(st) => write!(f, "{{{}}}", fmt_iter(st.iter())), Self::Code(code) => write!(f, "{code}"), Self::Record(rec) => { write!(f, "{{")?; for (i, (k, v)) in rec.iter().enumerate() { if i != 0 { write!(f, "; ")?; } write!(f, "{k} = {v}")?; } write!(f, "}}") } Self::DataClass { name, fields } => { write!(f, "{name} {{")?; for (i, (k, v)) in fields.iter().enumerate() { if i != 0 { write!(f, "; ")?; } write!(f, "{k} = {v}")?; } write!(f, "}}") } Self::Subr(subr) => subr.fmt(f), Self::Type(t) => t.fmt(f), Self::None => write!(f, "None"), Self::Ellipsis => write!(f, "Ellipsis"), Self::NotImplemented => write!(f, "NotImplemented"), Self::NegInf => write!(f, "-Inf"), Self::Inf => write!(f, "Inf"), Self::Failure => write!(f, ""), } } } impl LimitedDisplay for ValueObj { fn limited_fmt(&self, f: &mut W, limit: isize) -> std::fmt::Result { if limit == 0 { return write!(f, "..."); } match self { Self::Str(s) => { if limit.is_positive() && s.len() >= STR_OMIT_THRESHOLD { write!(f, "\"(...)\"") } else { write!(f, "\"{}\"", s.escape()) } } Self::List(lis) => { write!(f, "[")?; for (i, item) in lis.iter().enumerate() { if i != 0 { write!(f, ", ")?; } if limit.is_positive() && i >= CONTAINER_OMIT_THRESHOLD { write!(f, "...")?; break; } item.limited_fmt(f, limit - 1)?; } write!(f, "]") } Self::Dict(dict) => { write!(f, "{{")?; for (i, (k, v)) in dict.iter().enumerate() { if i != 0 { write!(f, ", ")?; } if limit.is_positive() && i >= CONTAINER_OMIT_THRESHOLD { write!(f, "...")?; break; } k.limited_fmt(f, limit - 1)?; write!(f, ": ")?; v.limited_fmt(f, limit - 1)?; } write!(f, "}}") } Self::Tuple(tup) => { write!(f, "(")?; for (i, item) in tup.iter().enumerate() { if i != 0 { write!(f, ", ")?; } if limit.is_positive() && i >= CONTAINER_OMIT_THRESHOLD { write!(f, "...")?; break; } item.limited_fmt(f, limit - 1)?; } write!(f, ")") } Self::Set(st) => { write!(f, "{{")?; for (i, item) in st.iter().enumerate() { if i != 0 { write!(f, ", ")?; } if limit.is_positive() && i >= CONTAINER_OMIT_THRESHOLD { write!(f, "...")?; break; } item.limited_fmt(f, limit - 1)?; } write!(f, "}}") } Self::Record(rec) => { write!(f, "{{")?; for (i, (field, v)) in rec.iter().enumerate() { if i != 0 { write!(f, "; ")?; } if limit.is_positive() && i >= CONTAINER_OMIT_THRESHOLD { write!(f, "...")?; break; } write!(f, "{field} = ")?; v.limited_fmt(f, limit - 1)?; } if rec.is_empty() { write!(f, "=")?; } write!(f, "}}") } Self::DataClass { name, fields } => { write!(f, "{name} {{")?; for (i, (field, v)) in fields.iter().enumerate() { if i != 0 { write!(f, "; ")?; } if limit.is_positive() && i >= CONTAINER_OMIT_THRESHOLD { write!(f, "...")?; break; } write!(f, "{field} = ")?; v.limited_fmt(f, limit - 1)?; } if fields.is_empty() { write!(f, "=")?; } write!(f, "}}") } Self::Type(typ) => typ.limited_fmt(f, limit), _ => write!(f, "{self}"), } } } impl PartialEq for ValueObj { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Int(i1), Self::Int(i2)) => i1 == i2, (Self::Nat(n1), Self::Nat(n2)) => n1 == n2, (Self::Int(i), Self::Nat(n)) | (Self::Nat(n), Self::Int(i)) => *i as u64 == *n, (Self::Float(f1), Self::Float(f2)) => f1 == f2, (Self::Str(s1), Self::Str(s2)) => s1 == s2, (Self::Bool(b1), Self::Bool(b2)) => b1 == b2, (Self::List(l1), Self::List(l2)) => l1 == l2, (Self::UnsizedList(l1), Self::UnsizedList(l2)) => l1 == l2, (Self::Set(s1), Self::Set(s2)) => s1.linear_eq(s2), (Self::Dict(d1), Self::Dict(d2)) => d1.linear_eq(d2), (Self::Tuple(t1), Self::Tuple(t2)) => t1 == t2, (Self::Record(r1), Self::Record(r2)) => r1 == r2, ( Self::DataClass { name: n1, fields: f1, }, Self::DataClass { name: n2, fields: f2, }, ) => n1 == n2 && f1 == f2, (Self::Code(c1), Self::Code(c2)) => c1 == c2, (Self::Subr(s1), Self::Subr(s2)) => s1 == s2, (Self::Type(t1), Self::Type(t2)) => t1 == t2, (Self::None, Self::None) | (Self::Ellipsis, Self::Ellipsis) | (Self::NotImplemented, Self::NotImplemented) | (Self::NegInf, Self::NegInf) | (Self::Inf, Self::Inf) | (Self::Failure, Self::Failure) => true, _ => false, } } } impl Eq for ValueObj {} impl Neg for ValueObj { type Output = Self; #[inline] fn neg(self) -> Self { match self { Self::Int(i) => Self::Int(-i), Self::Nat(n) => Self::Int(-(n as i32)), Self::Float(fl) => Self::Float(-fl), Self::Inf => Self::NegInf, Self::NegInf => Self::Inf, other => panic!("cannot negate {other}"), } } } impl HasLevel for ValueObj { fn level(&self) -> Option { match self { Self::Type(t) => t.typ().level(), Self::List(tps) | Self::Tuple(tps) => tps.iter().filter_map(|tp| tp.level()).min(), Self::UnsizedList(tp) => tp.level(), Self::Dict(tps) => tps .iter() .map(|(k, v)| { k.level() .unwrap_or(GENERIC_LEVEL) .min(v.level().unwrap_or(GENERIC_LEVEL)) }) .min(), Self::Record(rec) | Self::DataClass { fields: rec, .. } => rec .iter() .map(|(_, v)| v.level().unwrap_or(GENERIC_LEVEL)) .min(), Self::Subr(subr) => subr.sig_t().level(), Self::Set(tps) => tps.iter().filter_map(|tp| tp.level()).min(), mono_value_pattern!() => None, } } fn set_level(&self, level: usize) { match self { Self::Type(t) => t.typ().set_level(level), Self::Dict(tps) => { for (k, v) in tps.iter() { k.set_level(level); v.set_level(level); } } Self::Record(rec) | Self::DataClass { fields: rec, .. } => { for (_, v) in rec.iter() { v.set_level(level); } } Self::List(tps) => { for tp in tps.iter() { tp.set_level(level); } } Self::UnsizedList(tp) => tp.set_level(level), Self::Tuple(tps) => { for tp in tps.iter() { tp.set_level(level); } } Self::Set(tps) => { for tp in tps.iter() { tp.set_level(level); } } Self::Subr(subr) => subr.sig_t().set_level(level), mono_value_pattern!() => {} } } } impl From for ValueObj { fn from(item: i32) -> Self { if item >= 0 { ValueObj::Nat(item as u64) } else { ValueObj::Int(item) } } } impl From for ValueObj { fn from(item: u64) -> Self { ValueObj::Nat(item) } } impl From for ValueObj { fn from(item: usize) -> Self { ValueObj::Nat(item as u64) } } impl From for ValueObj { fn from(item: f64) -> Self { ValueObj::Float(Float(item)) } } impl From<&str> for ValueObj { fn from(item: &str) -> Self { ValueObj::Str(Str::rc(item)) } } impl From for ValueObj { fn from(item: Str) -> Self { ValueObj::Str(item) } } impl From for ValueObj { fn from(item: String) -> Self { ValueObj::Str(item.into()) } } impl From for ValueObj { fn from(item: bool) -> Self { ValueObj::Bool(item) } } impl From for ValueObj { fn from(item: CodeObj) -> Self { ValueObj::Code(Box::new(item)) } } impl> From> for ValueObj { fn from(item: Vec) -> Self { ValueObj::List(ArcArray::from( &item.into_iter().map(Into::into).collect::>()[..], )) } } impl> From<[V; N]> for ValueObj { fn from(item: [V; N]) -> Self { ValueObj::List(ArcArray::from(&item.map(Into::into)[..])) } } impl TryFrom<&ValueObj> for f64 { type Error = (); fn try_from(val: &ValueObj) -> Result { match val { ValueObj::Int(i) => Ok(*i as f64), ValueObj::Nat(n) => Ok(*n as f64), ValueObj::Float(f) => Ok(**f), ValueObj::Inf => Ok(f64::INFINITY), ValueObj::NegInf => Ok(f64::NEG_INFINITY), ValueObj::Bool(b) => Ok(if *b { 1.0 } else { 0.0 }), _ => Err(()), } } } impl TryFrom<&ValueObj> for usize { type Error = (); fn try_from(val: &ValueObj) -> Result { match val { ValueObj::Int(i) => usize::try_from(*i).map_err(|_| ()), ValueObj::Nat(n) => usize::try_from(*n).map_err(|_| ()), ValueObj::Float(f) => Ok(**f as usize), ValueObj::Bool(b) => Ok(if *b { 1 } else { 0 }), _ => Err(()), } } } impl<'a> TryFrom<&'a ValueObj> for &'a Type { type Error = (); fn try_from(val: &'a ValueObj) -> Result { match val { ValueObj::Type(t) => match t { TypeObj::Builtin { t, .. } => Ok(t), TypeObj::Generated(gen) => Ok(gen.typ()), }, _ => Err(()), } } } impl HasType for ValueObj { fn ref_t(&self) -> &Type { panic!("cannot get reference of the const") } fn ref_mut_t(&mut self) -> Option<&mut Type> { None } /// その要素だけの集合型を返す、クラスが欲しい場合は.classで #[inline] fn t(&self) -> Type { let name = FRESH_GEN.fresh_varname(); let pred = Predicate::eq(name.clone(), TyParam::Value(self.clone())); refinement(name, self.class(), pred) } fn signature_t(&self) -> Option<&Type> { None } fn signature_mut_t(&mut self) -> Option<&mut Type> { None } } impl ValueObj { pub const fn builtin_class(t: Type) -> Self { ValueObj::Type(TypeObj::Builtin { t, meta_t: Type::ClassType, }) } pub const fn builtin_trait(t: Type) -> Self { ValueObj::Type(TypeObj::Builtin { t, meta_t: Type::TraitType, }) } pub fn builtin_type(t: Type) -> Self { ValueObj::Type(TypeObj::Builtin { t, meta_t: Type::Type, }) } pub const fn gen_t(gen: GenTypeObj) -> Self { ValueObj::Type(TypeObj::Generated(gen)) } /// closed range (..) pub fn range(start: Self, end: Self) -> Self { Self::DataClass { name: "Range".into(), fields: dict! { Field::private("start".into()) => start, Field::private("end".into()) => end, Field::private("step".into()) => Self::None, }, } } pub fn tuple>(elems: Vec) -> Self { ValueObj::Tuple(ArcArray::from( &elems.into_iter().map(Into::into).collect::>()[..], )) } pub const fn is_none(&self) -> bool { matches!(self, Self::None) } // TODO: add Complex pub const fn is_num(&self) -> bool { matches!( self, Self::Float(_) | Self::Int(_) | Self::Nat(_) | Self::Bool(_) | Self::Inf | Self::NegInf ) } pub const fn is_float(&self) -> bool { matches!( self, Self::Float(_) | Self::Int(_) | Self::Nat(_) | Self::Bool(_) ) } pub const fn is_int(&self) -> bool { matches!(self, Self::Int(_) | Self::Nat(_) | Self::Bool(_)) } pub const fn is_nat(&self) -> bool { matches!(self, Self::Nat(_) | Self::Bool(_)) } pub const fn is_bool(&self) -> bool { matches!(self, Self::Bool(_)) } pub const fn is_true(&self) -> bool { matches!(self, Self::Bool(true)) } pub const fn is_false(&self) -> bool { matches!(self, Self::Bool(false)) } pub const fn is_str(&self) -> bool { matches!(self, Self::Str(_)) } pub const fn is_type(&self) -> bool { matches!(self, Self::Type(_)) } pub const fn is_inited(&self) -> bool { match self { Self::Type(t) => t.is_inited(), _ => true, } } pub fn is_complete(&self) -> bool { match self { Self::List(elems) => elems.iter().all(Self::is_complete), Self::Tuple(elems) => elems.iter().all(Self::is_complete), Self::Set(st) => st.iter().all(Self::is_complete), Self::Dict(dict) => dict.iter().all(|(k, v)| k.is_complete() && v.is_complete()), Self::Record(rec) => rec.iter().all(|(_, v)| v.is_complete()), Self::DataClass { fields, .. } => fields.iter().all(|(_, v)| v.is_complete()), // TODO: Self::Type(t) => !t.typ().is_failure(), Self::Failure => false, _ => true, } } pub const fn is_container(&self) -> bool { matches!( self, Self::List(_) | Self::UnsizedList(_) | Self::Set(_) | Self::Dict(_) | Self::Tuple(_) | Self::Record(_) ) } pub fn from_str(t: Type, mut content: Str) -> Option { match t { Type::Int => content.replace('_', "").parse::().ok().map(Self::Int), Type::Nat => { let content = content .trim_start_matches('-') // -0 -> 0 .replace('_', ""); if content.len() <= 1 { return content.parse::().ok().map(Self::Nat); } match &content[0..=1] { pre @ ("0b" | "0B") => { let content = content.trim_start_matches(pre); u64::from_str_radix(content, 2).ok().map(Self::Nat) } pre @ ("0o" | "0O") => { let content = content.trim_start_matches(pre); u64::from_str_radix(content, 8).ok().map(Self::Nat) } pre @ ("0x" | "0X") => { let content = content.trim_start_matches(pre); u64::from_str_radix(content, 16).ok().map(Self::Nat) } _ => content.parse::().ok().map(Self::Nat), } } Type::Float => content.replace('_', "").parse::().ok().map(Self::from), // TODO: Type::Ratio => content.replace('_', "").parse::().ok().map(Self::from), Type::Str => { if &content[..] == "\"\"" { Some(Self::Str(Str::from(""))) } else { if content.get(..3) == Some("\"\"\"") { content = Str::rc(&content[3..]); } else if content.get(..1) == Some("\"") { content = Str::rc(&content[1..]); } if content.len() >= 3 && content.get(content.len() - 3..) == Some("\"\"\"") { content = Str::rc(&content[..content.len() - 3]); } else if content.len() >= 1 && content.get(content.len() - 1..) == Some("\"") { content = Str::rc(&content[..content.len() - 1]); } Some(Self::Str(content)) } } Type::Bool => Some(Self::Bool(&content[..] == "True")), Type::NoneType => Some(Self::None), Type::Ellipsis => Some(Self::Ellipsis), Type::NotImplementedType => Some(Self::NotImplemented), Type::Inf => Some(Self::Inf), Type::NegInf => Some(Self::NegInf), _ => { log!(err "{t} {content}"); None } } } pub fn into_bytes(self, python_ver: PythonVersion) -> Vec { match self { Self::Int(i) => [vec![DataTypePrefix::Int32 as u8], i.to_le_bytes().to_vec()].concat(), // TODO: Natとしてシリアライズ Self::Nat(n) => [ vec![DataTypePrefix::Int32 as u8], (n as i32).to_le_bytes().to_vec(), ] .concat(), Self::Float(f) => [ vec![DataTypePrefix::BinFloat as u8], f.to_le_bytes().to_vec(), ] .concat(), Self::Str(s) => str_into_bytes(s, false), Self::Bool(true) => vec![DataTypePrefix::True as u8], Self::Bool(false) => vec![DataTypePrefix::False as u8], Self::List(elems) | Self::Tuple(elems) => tuple_into_bytes(&elems, python_ver), Self::None => { vec![DataTypePrefix::None as u8] } Self::Code(c) => c.into_bytes(python_ver), // Dict other => { panic!( "{}", switch_lang!( "japanese" => format!("このオブジェクトはシリアライズできません: {other}"), "simplified_chinese" => format!("此对象无法序列化: {other}"), "traditional_chinese" => format!("此對象無法序列化: {other}"), "english" => format!("this object cannot be serialized: {other}"), ) ) } } } pub fn from_const_expr(expr: ConstExpr) -> Self { let ConstExpr::Lit(lit) = expr else { todo!() }; let t = type_from_token_kind(lit.token.kind); ValueObj::from_str(t, lit.token.content).unwrap() } pub fn tuple_from_const_args(args: ConstArgs) -> Self { Self::Tuple(Arc::from(&Self::vec_from_const_args(args)[..])) } pub fn vec_from_const_args(args: ConstArgs) -> Vec { args.deconstruct() .0 .into_iter() .map(|elem| Self::from_const_expr(elem.expr)) .collect::>() } pub fn class(&self) -> Type { match self { Self::Int(_) => Type::Int, Self::Nat(_) => Type::Nat, Self::Float(_) => Type::Float, Self::Str(_) => Type::Str, Self::Bool(_) => Type::Bool, Self::List(lis) => list_t( // REVIEW: Never? lis.iter() .next() .map(|elem| elem.class()) .unwrap_or(Type::Never), TyParam::value(lis.len()), ), Self::UnsizedList(elem) => unsized_list_t(elem.class()), Self::Dict(dict) => { let tp = dict .iter() .map(|(k, v)| (TyParam::t(k.class()), TyParam::t(v.class()))); dict_t(TyParam::Dict(tp.collect())) } Self::Tuple(tup) => tuple_t(tup.iter().map(|v| v.class()).collect()), Self::Set(st) => set_t(inner_class(st), TyParam::value(st.len())), Self::Code(_) => Type::Code, Self::Record(rec) => { Type::Record(rec.iter().map(|(k, v)| (k.clone(), v.class())).collect()) } Self::DataClass { name, .. } => Type::Mono(name.clone()), Self::Subr(subr) => subr.sig_t().clone(), Self::Type(t_obj) => match t_obj { TypeObj::Builtin { meta_t, .. } => meta_t.clone(), TypeObj::Generated(gen_t) => gen_t.meta_type(), }, Self::None => Type::NoneType, Self::Ellipsis => Type::Ellipsis, Self::NotImplemented => Type::NotImplementedType, Self::Inf => Type::Inf, Self::NegInf => Type::NegInf, Self::Failure => Type::Failure, } } pub fn as_int(&self) -> Option { match self { Self::Int(i) => Some(*i), Self::Nat(n) => i32::try_from(*n).ok(), Self::Bool(b) => Some(if *b { 1 } else { 0 }), Self::Float(f) if f.round() == **f => Some(**f as i32), _ => None, } } pub fn as_float(&self) -> Option { match self { Self::Int(i) => Some(*i as f64), Self::Nat(n) => Some(*n as f64), Self::Bool(b) => Some(if *b { 1.0 } else { 0.0 }), Self::Float(f) => Some(**f), _ => None, } } pub fn as_str(&self) -> Option<&Str> { match self { Self::Str(s) => Some(s), _ => None, } } pub fn try_binary(self, other: Self, op: OpKind) -> Option { match op { OpKind::Add => self.try_add(other), OpKind::Sub => self.try_sub(other), OpKind::Mul => self.try_mul(other), OpKind::Div => self.try_div(other), OpKind::Lt => self.try_lt(other), OpKind::Gt => self.try_gt(other), OpKind::Le => self.try_le(other), OpKind::Ge => self.try_ge(other), OpKind::Eq => self.try_eq(other), OpKind::Ne => self.try_ne(other), _ => None, } } pub fn try_cmp(&self, other: &Self) -> Option { if self == other { return Some(Ordering::Equal); } match (self, other) { (Self::NegInf, Self::Inf) => Some(Ordering::Less), (Self::Inf, Self::NegInf) => Some(Ordering::Greater), // REVIEW: 等しいとみなしてよいのか? (Self::Inf, Self::Inf) | (Self::NegInf, Self::NegInf) => Some(Ordering::Equal), (l, r) if l.is_num() && r.is_num() => { f64::try_from(l).ok()?.partial_cmp(&f64::try_from(r).ok()?) } (Self::Inf, n) | (n, Self::NegInf) if n.is_num() => Some(Ordering::Greater), (n, Self::Inf) | (Self::NegInf, n) if n.is_num() => Some(Ordering::Less), (Self::Str(l), Self::Str(r)) => Some(l.cmp(r)), /* (Self::PlusEpsilon(l), r) => l.try_cmp(r) .map(|o| if matches!(o, Ordering::Equal) { Ordering::Less } else { o }), (l, Self::PlusEpsilon(r)) => l.try_cmp(r) .map(|o| if matches!(o, Ordering::Equal) { Ordering::Greater } else { o }), */ (_s, _o) => { if let Some(ValueObj::Bool(b)) = _s.clone().try_eq(_o.clone()) { if b { Some(Ordering::Equal) } else { None } } else { None } } } } // REVIEW: allow_divergenceオプションを付けるべきか? pub fn try_add(self, other: Self) -> Option { match (self, other) { (Self::Int(l), Self::Int(r)) => Some(Self::Int(l + r)), (Self::Nat(l), Self::Nat(r)) => Some(Self::Nat(l + r)), (Self::Float(l), Self::Float(r)) => Some(Self::Float(l + r)), (Self::Int(l), Self::Nat(r)) => Some(Self::from(l + r as i32)), (Self::Nat(l), Self::Int(r)) => Some(Self::Int(l as i32 + r)), (Self::Float(l), Self::Nat(r)) => Some(Self::from(*l - r as f64)), (Self::Int(l), Self::Float(r)) => Some(Self::from(l as f64 - *r)), (Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 - *r)), (Self::Float(l), Self::Int(r)) => Some(Self::from(*l - r as f64)), (Self::Str(l), Self::Str(r)) => Some(Self::Str(Str::from(format!("{l}{r}")))), (Self::List(l), Self::List(r)) => { let lis = Arc::from([l, r].concat()); Some(Self::List(lis)) } (Self::Dict(l), Self::Dict(r)) => Some(Self::Dict(l.concat(r))), (inf @ (Self::Inf | Self::NegInf), _) | (_, inf @ (Self::Inf | Self::NegInf)) => { Some(inf) } _ => None, } } pub fn try_sub(self, other: Self) -> Option { match (self, other) { (Self::Int(l), Self::Int(r)) => Some(Self::Int(l - r)), (Self::Nat(l), Self::Nat(r)) => Some(Self::Int(l as i32 - r as i32)), (Self::Float(l), Self::Float(r)) => Some(Self::Float(l - r)), (Self::Int(l), Self::Nat(r)) => Some(Self::from(l - r as i32)), (Self::Nat(l), Self::Int(r)) => Some(Self::from(l as i32 - r)), (Self::Float(l), Self::Nat(r)) => Some(Self::from(*l - r as f64)), (Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 - *r)), (Self::Float(l), Self::Int(r)) => Some(Self::from(*l - r as f64)), (Self::Int(l), Self::Float(r)) => Some(Self::from(l as f64 - *r)), (inf @ (Self::Inf | Self::NegInf), other) | (other, inf @ (Self::Inf | Self::NegInf)) if other != Self::Inf && other != Self::NegInf => { Some(inf) } _ => None, } } pub fn try_mul(self, other: Self) -> Option { match (self, other) { (Self::Int(l), Self::Int(r)) => Some(Self::from(l * r)), (Self::Nat(l), Self::Nat(r)) => Some(Self::Nat(l * r)), (Self::Float(l), Self::Float(r)) => Some(Self::Float(l * r)), (Self::Int(l), Self::Nat(r)) => Some(Self::Int(l * r as i32)), (Self::Nat(l), Self::Int(r)) => Some(Self::Int(l as i32 * r)), (Self::Float(l), Self::Nat(r)) => Some(Self::from(*l * r as f64)), (Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 * *r)), (Self::Float(l), Self::Int(r)) => Some(Self::from(*l * r as f64)), (Self::Int(l), Self::Float(r)) => Some(Self::from(l as f64 * *r)), (Self::Str(l), Self::Nat(r)) => Some(Self::Str(Str::from(l.repeat(r as usize)))), (inf @ (Self::Inf | Self::NegInf), _) | (_, inf @ (Self::Inf | Self::NegInf)) => { Some(inf) } _ => None, } } pub fn try_div(self, other: Self) -> Option { match (self, other) { (Self::Int(l), Self::Int(r)) => Some(Self::from(l as f64 / r as f64)), (Self::Nat(l), Self::Nat(r)) => Some(Self::from(l as f64 / r as f64)), (Self::Float(l), Self::Float(r)) => Some(Self::Float(l / r)), (Self::Int(l), Self::Nat(r)) => Some(Self::from(l as f64 / r as f64)), (Self::Nat(l), Self::Int(r)) => Some(Self::from(l as f64 / r as f64)), (Self::Float(l), Self::Nat(r)) => Some(Self::from(*l / r as f64)), (Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 / *r)), (Self::Float(l), Self::Int(r)) => Some(Self::from(*l / r as f64)), (Self::Int(l), Self::Float(r)) => Some(Self::from(l as f64 / *r)), // TODO: x/±Inf = 0 _ => None, } } pub fn try_floordiv(self, other: Self) -> Option { match (self, other) { (Self::Int(l), Self::Int(r)) => Some(Self::Int(l / r)), (Self::Nat(l), Self::Nat(r)) => Some(Self::Nat(l / r)), (Self::Float(l), Self::Float(r)) => Some(Self::from((l / r).floor())), (Self::Int(l), Self::Nat(r)) => Some(Self::Int(l / r as i32)), (Self::Nat(l), Self::Int(r)) => Some(Self::Int(l as i32 / r)), (Self::Float(l), Self::Nat(r)) => Some(Self::from((*l / r as f64).floor())), (Self::Nat(l), Self::Float(r)) => Some(Self::from((l as f64 / *r).floor())), (Self::Float(l), Self::Int(r)) => Some(Self::from((*l / r as f64).floor())), (Self::Int(l), Self::Float(r)) => Some(Self::from((l as f64 / *r).floor())), // TODO: x//±Inf = 0 _ => None, } } pub fn try_pow(self, other: Self) -> Option { match (self, other) { (Self::Int(l), Self::Int(r)) => Some(Self::Int(l.pow(r.try_into().ok()?))), (Self::Nat(l), Self::Nat(r)) => Some(Self::Nat(l.pow(r.try_into().ok()?))), (Self::Float(l), Self::Float(r)) => Some(Self::from(l.powf(*r))), (Self::Int(l), Self::Nat(r)) => Some(Self::Int(l.pow(r.try_into().ok()?))), (Self::Nat(l), Self::Int(r)) => Some(Self::Nat(l.pow(r.try_into().ok()?))), (Self::Float(l), Self::Nat(r)) => Some(Self::from(l.powf(r as f64))), (Self::Nat(l), Self::Float(r)) => Some(Self::from((l as f64).powf(*r))), (Self::Float(l), Self::Int(r)) => Some(Self::from(l.powi(r))), (Self::Int(l), Self::Float(r)) => Some(Self::from((l as f64).powf(*r))), _ => None, } } pub fn try_mod(self, other: Self) -> Option { match (self, other) { (Self::Int(l), Self::Int(r)) => Some(Self::Int(l % r)), (Self::Nat(l), Self::Nat(r)) => Some(Self::Nat(l % r)), (Self::Float(l), Self::Float(r)) => Some(Self::Float(l % r)), (Self::Int(l), Self::Nat(r)) => Some(Self::Int(l % r as i32)), (Self::Nat(l), Self::Int(r)) => Some(Self::Int(l as i32 % r)), (Self::Float(l), Self::Nat(r)) => Some(Self::from(*l % r as f64)), (Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 % *r)), (Self::Float(l), Self::Int(r)) => Some(Self::from(*l % r as f64)), (Self::Int(l), Self::Float(r)) => Some(Self::from(l as f64 % *r)), _ => None, } } pub fn try_gt(self, other: Self) -> Option { match (self, other) { (Self::Int(l), Self::Int(r)) => Some(Self::from(l > r)), (Self::Nat(l), Self::Nat(r)) => Some(Self::from(l > r)), (Self::Float(l), Self::Float(r)) => Some(Self::from(l > r)), (Self::Int(l), Self::Nat(r)) => Some(Self::from(l > r as i32)), (Self::Nat(l), Self::Int(r)) => Some(Self::from(l as i32 > r)), (Self::Float(l), Self::Nat(r)) => Some(Self::from(*l > r as f64)), (Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 > *r)), (Self::Float(l), Self::Int(r)) => Some(Self::from(*l > r as f64)), (Self::Int(l), Self::Float(r)) => Some(Self::from(l as f64 > *r)), (Self::Inf, Self::Inf) | (Self::NegInf, Self::NegInf) => Some(Self::Bool(false)), (Self::Inf, Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_)) | (Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_), Self::NegInf) => { Some(Self::Bool(true)) } (Self::NegInf, Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_)) | (Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_), Self::Inf) => { Some(Self::Bool(false)) } _ => None, } } pub fn try_ge(self, other: Self) -> Option { match (self, other) { (Self::Int(l), Self::Int(r)) => Some(Self::from(l >= r)), (Self::Nat(l), Self::Nat(r)) => Some(Self::from(l >= r)), (Self::Float(l), Self::Float(r)) => Some(Self::from(l >= r)), (Self::Int(l), Self::Nat(r)) => Some(Self::from(l >= r as i32)), (Self::Nat(l), Self::Int(r)) => Some(Self::from(l as i32 >= r)), (Self::Float(l), Self::Nat(r)) => Some(Self::from(*l >= r as f64)), (Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 >= *r)), (Self::Float(l), Self::Int(r)) => Some(Self::from(*l >= r as f64)), (Self::Int(l), Self::Float(r)) => Some(Self::from(l as f64 >= *r)), (Self::Inf, Self::Inf) | (Self::NegInf, Self::NegInf) => Some(Self::Bool(true)), (Self::Inf, Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_)) | (Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_), Self::NegInf) => { Some(Self::Bool(true)) } (Self::NegInf, Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_)) | (Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_), Self::Inf) => { Some(Self::Bool(false)) } _ => None, } } pub fn try_lt(self, other: Self) -> Option { match (self, other) { (Self::Int(l), Self::Int(r)) => Some(Self::from(l < r)), (Self::Nat(l), Self::Nat(r)) => Some(Self::from(l < r)), (Self::Float(l), Self::Float(r)) => Some(Self::from(l < r)), (Self::Int(l), Self::Nat(r)) => Some(Self::from(l < r as i32)), (Self::Nat(l), Self::Int(r)) => Some(Self::from((l as i32) < r)), (Self::Float(l), Self::Nat(r)) => Some(Self::from(*l < r as f64)), (Self::Nat(l), Self::Float(r)) => Some(Self::from((l as f64) < *r)), (Self::Float(l), Self::Int(r)) => Some(Self::from(*l < r as f64)), (Self::Int(l), Self::Float(r)) => Some(Self::from((l as f64) < *r)), (Self::Inf, Self::Inf) | (Self::NegInf, Self::NegInf) => Some(Self::Bool(false)), (Self::Inf, Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_)) | (Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_), Self::NegInf) => { Some(Self::Bool(false)) } (Self::NegInf, Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_)) | (Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_), Self::Inf) => { Some(Self::Bool(true)) } _ => None, } } pub fn try_le(self, other: Self) -> Option { match (self, other) { (Self::Int(l), Self::Int(r)) => Some(Self::from(l <= r)), (Self::Nat(l), Self::Nat(r)) => Some(Self::from(l <= r)), (Self::Float(l), Self::Float(r)) => Some(Self::from(l <= r)), (Self::Int(l), Self::Nat(r)) => Some(Self::from(l <= r as i32)), (Self::Nat(l), Self::Int(r)) => Some(Self::from((l as i32) <= r)), (Self::Float(l), Self::Nat(r)) => Some(Self::from(*l <= r as f64)), (Self::Nat(l), Self::Float(r)) => Some(Self::from((l as f64) <= *r)), (Self::Float(l), Self::Int(r)) => Some(Self::from(*l <= r as f64)), (Self::Int(l), Self::Float(r)) => Some(Self::from((l as f64) <= *r)), (Self::Inf, Self::Inf) | (Self::NegInf, Self::NegInf) => Some(Self::Bool(true)), (Self::Inf, Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_)) | (Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_), Self::NegInf) => { Some(Self::Bool(false)) } (Self::NegInf, Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_)) | (Self::Nat(_) | Self::Int(_) | Self::Float(_) | Self::Bool(_), Self::Inf) => { Some(Self::Bool(true)) } _ => None, } } pub fn try_eq(self, other: Self) -> Option { match (self, other) { (Self::Int(l), Self::Int(r)) => Some(Self::from(l == r)), (Self::Nat(l), Self::Nat(r)) => Some(Self::from(l == r)), (Self::Float(l), Self::Float(r)) => Some(Self::from(l == r)), (Self::Int(l), Self::Nat(r)) => Some(Self::from(l == r as i32)), (Self::Nat(l), Self::Int(r)) => Some(Self::from(l as i32 == r)), (Self::Float(l), Self::Nat(r)) => Some(Self::from(*l == r as f64)), (Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 == *r)), (Self::Float(l), Self::Int(r)) => Some(Self::from(*l == r as f64)), (Self::Int(l), Self::Float(r)) => Some(Self::from(l as f64 == *r)), (Self::Str(l), Self::Str(r)) => Some(Self::from(l == r)), (Self::Bool(l), Self::Bool(r)) => Some(Self::from(l == r)), (Self::Type(l), Self::Type(r)) => Some(Self::from(l == r)), (Self::Inf, Self::Inf) | (Self::NegInf, Self::NegInf) => Some(Self::Bool(true)), // TODO: _ => None, } } pub fn try_ne(self, other: Self) -> Option { match (self, other) { (Self::Int(l), Self::Int(r)) => Some(Self::from(l != r)), (Self::Nat(l), Self::Nat(r)) => Some(Self::from(l != r)), (Self::Float(l), Self::Float(r)) => Some(Self::from(l != r)), (Self::Int(l), Self::Nat(r)) => Some(Self::from(l != r as i32)), (Self::Nat(l), Self::Int(r)) => Some(Self::from(l as i32 != r)), (Self::Float(l), Self::Nat(r)) => Some(Self::from(*l != r as f64)), (Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 != *r)), (Self::Float(l), Self::Int(r)) => Some(Self::from(*l != r as f64)), (Self::Int(l), Self::Float(r)) => Some(Self::from(l as f64 != *r)), (Self::Str(l), Self::Str(r)) => Some(Self::from(l != r)), (Self::Bool(l), Self::Bool(r)) => Some(Self::from(l != r)), (Self::Type(l), Self::Type(r)) => Some(Self::from(l != r)), (Self::Inf, Self::Inf) | (Self::NegInf, Self::NegInf) => Some(Self::Bool(false)), _ => None, } } pub fn try_or(self, other: Self) -> Option { match (self, other) { (Self::Bool(l), Self::Bool(r)) => Some(Self::from(l || r)), _ => None, } } pub fn try_get_attr(&self, attr: &Field) -> Option { match self { Self::Type(typ) => match typ { TypeObj::Builtin { t: builtin, .. } => { log!(err "TODO: {builtin}{attr}"); None } TypeObj::Generated(gen) => match gen.typ() { Type::Record(rec) => { let t = rec.get(attr)?; Some(ValueObj::builtin_type(t.clone())) } _ => None, }, }, Self::Record(rec) => { let v = rec.get(attr)?; Some(v.clone()) } _ => None, } } pub fn as_type(&self, ctx: &Context) -> Option { match self { Self::Type(t) => Some(t.clone()), other => ctx .convert_value_into_type(other.clone()) .ok() .map(TypeObj::builtin_type), } } pub fn map_t(self, f: &mut impl FnMut(Type) -> Type) -> Self { match self { ValueObj::Type(obj) => ValueObj::Type(obj.mapped_t(f)), ValueObj::List(lis) => ValueObj::List(lis.iter().map(|v| v.clone().map_t(f)).collect()), ValueObj::Tuple(tup) => { ValueObj::Tuple(tup.iter().map(|v| v.clone().map_t(f)).collect()) } ValueObj::Set(st) => ValueObj::Set(st.into_iter().map(|v| v.map_t(f)).collect()), ValueObj::Dict(dict) => ValueObj::Dict( dict.into_iter() .map(|(k, v)| (k.map_t(f), v.map_t(f))) .collect(), ), ValueObj::Record(rec) => { ValueObj::Record(rec.into_iter().map(|(k, v)| (k, v.map_t(f))).collect()) } ValueObj::DataClass { name, fields } => ValueObj::DataClass { name, fields: fields.into_iter().map(|(k, v)| (k, v.map_t(f))).collect(), }, ValueObj::UnsizedList(elem) => ValueObj::UnsizedList(Box::new(elem.map_t(f))), ValueObj::Subr(_) => self, mono_value_pattern!() => self, } } pub fn try_map_t(self, f: &mut impl FnMut(Type) -> Result) -> Result { match self { ValueObj::Type(obj) => Ok(ValueObj::Type(obj.try_mapped_t(f)?)), ValueObj::List(lis) => Ok(ValueObj::List( lis.iter() .map(|v| v.clone().try_map_t(f)) .collect::, _>>()?, )), ValueObj::Tuple(tup) => Ok(ValueObj::Tuple( tup.iter() .map(|v| v.clone().try_map_t(f)) .collect::, _>>()?, )), ValueObj::Set(st) => Ok(ValueObj::Set( st.into_iter() .map(|v| v.try_map_t(f)) .collect::, _>>()?, )), ValueObj::Dict(dict) => Ok(ValueObj::Dict( dict.into_iter() .map(|(k, v)| Ok((k.try_map_t(f)?, v.try_map_t(f)?))) .collect::, _>>()?, )), ValueObj::Record(rec) => Ok(ValueObj::Record( rec.into_iter() .map(|(k, v)| Ok((k, v.try_map_t(f)?))) .collect::, _>>()?, )), ValueObj::DataClass { name, fields } => Ok(ValueObj::DataClass { name, fields: fields .into_iter() .map(|(k, v)| Ok((k, v.try_map_t(f)?))) .collect::, _>>()?, }), ValueObj::UnsizedList(elem) => Ok(ValueObj::UnsizedList(Box::new(elem.try_map_t(f)?))), // TODO: ValueObj::Subr(_) => Ok(self), mono_value_pattern!() => Ok(self), } } pub fn map_tp(self, f: &mut impl FnMut(TyParam) -> TyParam, tvs: &SharedFrees) -> Self { match self { ValueObj::Type(obj) => ValueObj::Type(obj.mapped_tp(f, tvs)), ValueObj::List(lis) => { ValueObj::List(lis.iter().map(|v| v.clone().map_tp(f, tvs)).collect()) } ValueObj::Tuple(tup) => { ValueObj::Tuple(tup.iter().map(|v| v.clone().map_tp(f, tvs)).collect()) } ValueObj::Set(st) => ValueObj::Set(st.into_iter().map(|v| v.map_tp(f, tvs)).collect()), ValueObj::Dict(dict) => ValueObj::Dict( dict.into_iter() .map(|(k, v)| (k.map_tp(f, tvs), v.map_tp(f, tvs))) .collect(), ), ValueObj::Record(rec) => ValueObj::Record( rec.into_iter() .map(|(k, v)| (k, v.map_tp(f, tvs))) .collect(), ), ValueObj::DataClass { name, fields } => ValueObj::DataClass { name, fields: fields .into_iter() .map(|(k, v)| (k, v.map_tp(f, tvs))) .collect(), }, ValueObj::UnsizedList(elem) => ValueObj::UnsizedList(Box::new(elem.map_tp(f, tvs))), ValueObj::Subr(_) => self, mono_value_pattern!() => self, } } pub fn try_map_tp( self, f: &mut impl FnMut(TyParam) -> Result, tvs: &SharedFrees, ) -> Result { match self { ValueObj::Type(obj) => Ok(ValueObj::Type(obj.try_mapped_tp(f, tvs)?)), ValueObj::List(lis) => Ok(ValueObj::List( lis.iter() .map(|v| v.clone().try_map_tp(f, tvs)) .collect::, _>>()?, )), ValueObj::Tuple(tup) => Ok(ValueObj::Tuple( tup.iter() .map(|v| v.clone().try_map_tp(f, tvs)) .collect::, _>>()?, )), ValueObj::Set(st) => Ok(ValueObj::Set( st.into_iter() .map(|v| v.try_map_tp(f, tvs)) .collect::, _>>()?, )), ValueObj::Dict(dict) => Ok(ValueObj::Dict( dict.into_iter() .map(|(k, v)| Ok((k.try_map_tp(f, tvs)?, v.try_map_tp(f, tvs)?))) .collect::, _>>()?, )), ValueObj::Record(rec) => Ok(ValueObj::Record( rec.into_iter() .map(|(k, v)| Ok((k, v.try_map_tp(f, tvs)?))) .collect::, _>>()?, )), ValueObj::DataClass { name, fields } => Ok(ValueObj::DataClass { name, fields: fields .into_iter() .map(|(k, v)| Ok((k, v.try_map_tp(f, tvs)?))) .collect::, _>>()?, }), ValueObj::UnsizedList(elem) => { Ok(ValueObj::UnsizedList(Box::new(elem.try_map_tp(f, tvs)?))) } ValueObj::Subr(_) => Ok(self), mono_value_pattern!() => Ok(self), } } pub fn replace_t(self, target: &Type, to: &Type, tvs: &SharedFrees) -> Self { self.map_t(&mut |t| t._replace(target, to, tvs)) } pub fn replace_tp(self, target: &TyParam, to: &TyParam, tvs: &SharedFrees) -> Self { self.map_t(&mut |t| t._replace_tp(target, to, tvs)) } pub fn contains(&self, val: &ValueObj) -> bool { match self { ValueObj::List(lis) => lis.iter().any(|v| v.contains(val)), ValueObj::Tuple(tup) => tup.iter().any(|v| v.contains(val)), ValueObj::Set(st) => st.iter().any(|v| v.contains(val)), ValueObj::Dict(dict) => dict.iter().any(|(k, v)| k.contains(val) || v.contains(val)), ValueObj::Record(rec) => rec.iter().any(|(_, v)| v.contains(val)), ValueObj::DataClass { fields, .. } => fields.iter().any(|(_, v)| v.contains(val)), ValueObj::UnsizedList(elem) => elem.contains(val), ValueObj::Type(t) => t.typ().contains_value(val), ValueObj::Subr(_) => self == val, mono_value_pattern!() => self == val, } } pub fn contains_type(&self, target: &Type) -> bool { match self { Self::Type(t) => t.typ().contains_type(target), Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.contains_type(target)), Self::UnsizedList(elem) => elem.contains_type(target), Self::Set(ts) => ts.iter().any(|t| t.contains_type(target)), Self::Dict(ts) => ts .iter() .any(|(k, v)| k.contains_type(target) || v.contains_type(target)), Self::Record(rec) | Self::DataClass { fields: rec, .. } => { rec.iter().any(|(_, tp)| tp.contains_type(target)) } Self::Subr(_) => false, mono_value_pattern!() => false, } } pub fn contains_tp(&self, target: &TyParam) -> bool { match self { Self::Type(t) => t.typ().contains_tp(target), Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.contains_tp(target)), Self::UnsizedList(elem) => elem.contains_tp(target), Self::Set(ts) => ts.iter().any(|t| t.contains_tp(target)), Self::Dict(ts) => ts .iter() .any(|(k, v)| k.contains_tp(target) || v.contains_tp(target)), Self::Record(rec) | Self::DataClass { fields: rec, .. } => { rec.iter().any(|(_, tp)| tp.contains_tp(target)) } Self::Subr(_) => false, mono_value_pattern!() => false, } } pub fn has_type_satisfies(&self, f: impl Fn(&Type) -> bool + Copy) -> bool { match self { Self::Type(t) => f(t.typ()), Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.has_type_satisfies(f)), Self::UnsizedList(elem) => elem.has_type_satisfies(f), Self::Set(ts) => ts.iter().any(|t| t.has_type_satisfies(f)), Self::Dict(ts) => ts .iter() .any(|(k, v)| k.has_type_satisfies(f) || v.has_type_satisfies(f)), Self::Record(rec) | Self::DataClass { fields: rec, .. } => { rec.iter().any(|(_, tp)| tp.has_type_satisfies(f)) } Self::Subr(_) => false, mono_value_pattern!() => false, } } pub fn has_unbound_var(&self) -> bool { match self { Self::Type(t) => t.typ().has_unbound_var(), Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.has_unbound_var()), Self::UnsizedList(elem) => elem.has_unbound_var(), Self::Set(ts) => ts.iter().any(|t| t.has_unbound_var()), Self::Dict(ts) => ts .iter() .any(|(k, v)| k.has_unbound_var() || v.has_unbound_var()), Self::Record(rec) | Self::DataClass { fields: rec, .. } => { rec.iter().any(|(_, tp)| tp.has_unbound_var()) } Self::Subr(_) => false, mono_value_pattern!() => false, } } pub fn has_undoable_linked_var(&self) -> bool { match self { Self::Type(t) => t.typ().has_undoable_linked_var(), Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.has_undoable_linked_var()), Self::UnsizedList(elem) => elem.has_undoable_linked_var(), Self::Set(ts) => ts.iter().any(|t| t.has_undoable_linked_var()), Self::Dict(ts) => ts .iter() .any(|(k, v)| k.has_undoable_linked_var() || v.has_undoable_linked_var()), Self::Record(rec) | Self::DataClass { fields: rec, .. } => { rec.iter().any(|(_, tp)| tp.has_undoable_linked_var()) } Self::Subr(_) => false, mono_value_pattern!() => false, } } pub fn has_qvar(&self) -> bool { match self { Self::Type(t) => t.typ().has_qvar(), Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.has_qvar()), Self::UnsizedList(elem) => elem.has_qvar(), Self::Set(ts) => ts.iter().any(|t| t.has_qvar()), Self::Dict(ts) => ts.iter().any(|(k, v)| k.has_qvar() || v.has_qvar()), Self::Record(rec) | Self::DataClass { fields: rec, .. } => { rec.iter().any(|(_, tp)| tp.has_qvar()) } Self::Subr(_) => false, mono_value_pattern!() => false, } } pub fn contains_tvar(&self, target: &FreeTyVar) -> bool { match self { Self::Type(t) => t.typ().contains_tvar(target), Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.contains_tvar(target)), Self::UnsizedList(elem) => elem.contains_tvar(target), Self::Set(ts) => ts.iter().any(|t| t.contains_tvar(target)), Self::Dict(ts) => ts .iter() .any(|(k, v)| k.contains_tvar(target) || v.contains_tvar(target)), Self::Record(rec) | Self::DataClass { fields: rec, .. } => { rec.iter().any(|(_, tp)| tp.contains_tvar(target)) } Self::Subr(_) => false, mono_value_pattern!() => false, } } pub fn qvars(&self) -> Set<(Str, Constraint)> { match self { Self::Type(t) => t.typ().qvars(), Self::List(ts) | Self::Tuple(ts) => ts.iter().flat_map(|t| t.qvars()).collect(), Self::UnsizedList(elem) => elem.qvars(), Self::Set(ts) => ts.iter().flat_map(|t| t.qvars()).collect(), Self::Dict(ts) => ts .iter() .flat_map(|(k, v)| k.qvars().concat(v.qvars())) .collect(), Self::Record(rec) | Self::DataClass { fields: rec, .. } => { rec.iter().flat_map(|(_, tp)| tp.qvars()).collect() } Self::Subr(_) => Set::new(), mono_value_pattern!() => Set::new(), } } pub fn typarams(&self) -> Vec { match self { Self::Type(t) => t.typ().typarams(), _ => Vec::new(), } } pub fn contained_ts(&self) -> Set { match self { Self::Type(t) => t.typ().contained_ts(), Self::List(ts) | Self::Tuple(ts) => ts.iter().flat_map(|t| t.contained_ts()).collect(), Self::UnsizedList(elem) => elem.contained_ts(), Self::Set(ts) => ts.iter().flat_map(|t| t.contained_ts()).collect(), Self::Dict(ts) => ts .iter() .flat_map(|(k, v)| k.contained_ts().concat(v.contained_ts())) .collect(), Self::Record(rec) | Self::DataClass { fields: rec, .. } => { rec.iter().flat_map(|(_, tp)| tp.contained_ts()).collect() } Self::Subr(_) => Set::new(), mono_value_pattern!() => Set::new(), } } pub fn dereference(&mut self) { *self = std::mem::take(self).map_t(&mut |mut t| { t.dereference(); t }); } pub fn variables(&self) -> Set { match self { Self::Type(t) => t.typ().variables(), Self::List(ts) | Self::Tuple(ts) => ts.iter().flat_map(|t| t.variables()).collect(), Self::UnsizedList(elem) => elem.variables(), Self::Set(ts) => ts.iter().flat_map(|t| t.variables()).collect(), Self::Dict(ts) => ts .iter() .flat_map(|(k, v)| k.variables().concat(v.variables())) .collect(), Self::Record(rec) | Self::DataClass { fields: rec, .. } => { rec.iter().flat_map(|(_, tp)| tp.variables()).collect() } Self::Subr(_) => Set::new(), mono_value_pattern!() => Set::new(), } } } pub mod value_set { use crate::ty::{Type, ValueObj}; use erg_common::set::Set; // false -> SyntaxError pub fn is_homogeneous(set: &Set) -> bool { if let Some(first) = set.iter().next() { let l_first = first.class(); // `Set` iteration order is guaranteed (if not changed) set.iter().skip(1).all(|c| c.class() == l_first) } else { true } } pub fn inner_class(set: &Set) -> Type { set.iter() .next() .map(|elem| elem.class()) .unwrap_or(Type::Never) } pub fn max(set: &Set) -> Option { if !is_homogeneous(set) { return None; } set.iter().max_by(|x, y| x.try_cmp(y).unwrap()).cloned() } pub fn min(set: &Set) -> Option { if !is_homogeneous(set) { return None; } set.iter().min_by(|x, y| x.try_cmp(y).unwrap()).cloned() } }