From bc23f9d045a384bfabc05958be1aff27bec9bcd9 Mon Sep 17 00:00:00 2001 From: Shunsuke Shibayama Date: Wed, 19 Jun 2024 01:35:18 +0900 Subject: [PATCH] chore: improve `Type::replace_failure` --- crates/erg_compiler/ty/mod.rs | 237 ++++++++++++++++++++++++++-- crates/erg_compiler/ty/predicate.rs | 108 +++++++++++++ crates/erg_compiler/ty/typaram.rs | 76 +++++++-- crates/erg_compiler/ty/value.rs | 60 +++++++ 4 files changed, 454 insertions(+), 27 deletions(-) diff --git a/crates/erg_compiler/ty/mod.rs b/crates/erg_compiler/ty/mod.rs index a70624c3..cd631476 100644 --- a/crates/erg_compiler/ty/mod.rs +++ b/crates/erg_compiler/ty/mod.rs @@ -510,6 +510,21 @@ impl SubrType { || self.return_t.contains_tp(target) } + pub fn contains_value(&self, target: &ValueObj) -> bool { + self.non_default_params + .iter() + .any(|pt| pt.typ().contains_value(target)) + || self + .var_params + .as_ref() + .map_or(false, |pt| pt.typ().contains_value(target)) + || self.default_params.iter().any(|pt| { + pt.typ().contains_value(target) + || pt.default_typ().is_some_and(|t| t.contains_value(target)) + }) + || self.return_t.contains_value(target) + } + pub fn qvars(&self) -> Set<(Str, Constraint)> { let mut qvars = Set::new(); for pt in self.non_default_params.iter() { @@ -779,10 +794,36 @@ impl SubrType { *default = std::mem::take(default)._replace(target, to); } } + if let Some(kw_var) = self.kw_var_params.as_mut() { + *kw_var.as_mut().typ_mut() = + std::mem::take(kw_var.as_mut().typ_mut())._replace(target, to); + } self.return_t = Box::new(self.return_t._replace(target, to)); self } + pub fn _replace_tp(mut self, target: &TyParam, to: &TyParam) -> Self { + for nd in self.non_default_params.iter_mut() { + *nd.typ_mut() = std::mem::take(nd.typ_mut())._replace_tp(target, to); + } + if let Some(var) = self.var_params.as_mut() { + *var.as_mut().typ_mut() = + std::mem::take(var.as_mut().typ_mut())._replace_tp(target, to); + } + for d in self.default_params.iter_mut() { + *d.typ_mut() = std::mem::take(d.typ_mut())._replace_tp(target, to); + if let Some(default) = d.default_typ_mut() { + *default = std::mem::take(default)._replace_tp(target, to); + } + } + if let Some(kw_var) = self.kw_var_params.as_mut() { + *kw_var.as_mut().typ_mut() = + std::mem::take(kw_var.as_mut().typ_mut())._replace_tp(target, to); + } + self.return_t = Box::new(self.return_t._replace_tp(target, to)); + self + } + pub fn replace_params(mut self, target_and_to: Vec<(Str, Str)>) -> Self { for (target, to) in target_and_to { for nd in self.non_default_params.iter_mut() { @@ -2138,6 +2179,24 @@ impl Type { Self::Structural(Box::new(self)) } + pub fn bounded(sub: Type, sup: Type) -> Self { + Self::Bounded { + sub: Box::new(sub), + sup: Box::new(sup), + } + } + + pub fn into_ref(self) -> Self { + Self::Ref(Box::new(self)) + } + + pub fn into_ref_mut(self, after: Option) -> Self { + Self::RefMut { + before: Box::new(self), + after: after.map(Box::new), + } + } + pub fn is_mono_value_class(&self) -> bool { match self { Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_mono_value_class(), @@ -2704,8 +2763,9 @@ impl Type { Self::Poly { params, .. } => params.iter().any(|tp| tp.contains_tp(target)), Self::Quantified(t) => t.contains_tp(target), Self::Subr(subr) => subr.contains_tp(target), - // TODO: preds - Self::Refinement(refine) => refine.t.contains_tp(target), + Self::Refinement(refine) => { + refine.t.contains_tp(target) || refine.pred.contains_tp(target) + } Self::Structural(ty) => ty.contains_tp(target), Self::Proj { lhs, .. } => lhs.contains_tp(target), Self::ProjCall { lhs, args, .. } => { @@ -2724,6 +2784,41 @@ impl Type { } } + pub fn contains_value(&self, target: &ValueObj) -> bool { + match self { + Self::FreeVar(fv) if fv.is_linked() => fv.crack().contains_value(target), + Self::Record(rec) => rec.iter().any(|(_, t)| t.contains_value(target)), + Self::NamedTuple(rec) => rec.iter().any(|(_, t)| t.contains_value(target)), + Self::Poly { params, .. } => params.iter().any(|tp| tp.contains_value(target)), + Self::Quantified(t) => t.contains_value(target), + Self::Subr(subr) => subr.contains_value(target), + Self::Refinement(refine) => { + refine.t.contains_value(target) || refine.pred.contains_value(target) + } + Self::Structural(ty) => ty.contains_value(target), + Self::Proj { lhs, .. } => lhs.contains_value(target), + Self::ProjCall { lhs, args, .. } => { + lhs.contains_value(target) || args.iter().any(|t| t.contains_value(target)) + } + Self::And(lhs, rhs) => lhs.contains_value(target) || rhs.contains_value(target), + Self::Or(lhs, rhs) => lhs.contains_value(target) || rhs.contains_value(target), + Self::Not(t) => t.contains_value(target), + Self::Ref(t) => t.contains_value(target), + Self::RefMut { before, after } => { + before.contains_value(target) + || after.as_ref().map_or(false, |t| t.contains_value(target)) + } + Self::Bounded { sub, sup } => sub.contains_value(target) || sup.contains_value(target), + _ => false, + } + } + + pub fn contains_failure(&self) -> bool { + self.contains_tp(&TyParam::Failure) + || self.contains_type(&Type::Failure) + || self.contains_value(&ValueObj::Failure) + } + pub fn is_recursive(&self) -> bool { match self { Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_recursive(), @@ -3768,11 +3863,11 @@ impl Type { } /// ```erg - /// (Failure -> Int).replace_failure() == (Obj -> Int) - /// (Int -> Failure).replace_failure() == (Int -> Never) - /// List(Failure, 3).replace_failure() == List(Never, 3) + /// (Failure -> Int).replace_failure_type() == (Obj -> Int) + /// (Int -> Failure).replace_failure_type() == (Int -> Never) + /// List(Failure, 3).replace_failure_type() == List(Never, 3) /// ``` - pub fn replace_failure(&self) -> Type { + pub fn replace_failure_type(&self) -> Type { match self { Self::Quantified(quant) => quant.replace_failure().quantify(), Self::Subr(subr) => { @@ -3821,6 +3916,21 @@ impl Type { } } + /// ```erg + /// Int.replace_failure() == Int + /// K(Failure).replace_failure() == K(Never) + /// {}.replace_failure() == Never + /// K().replace_failure() == Never + /// ``` + pub fn replace_failure(&self) -> Type { + let self_ = self.replace_failure_type(); + if self_.contains_failure() { + Self::Never + } else { + self_ + } + } + fn _replace(mut self, target: &Type, to: &Type) -> Type { if self.structural_eq(target) { self = to.clone(); @@ -3910,6 +4020,92 @@ impl Type { } } + fn _replace_tp(self, target: &TyParam, to: &TyParam) -> Type { + match self { + Self::FreeVar(fv) if fv.is_linked() => fv.crack().clone()._replace_tp(target, to), + Self::FreeVar(fv) => { + let fv_clone = fv.deep_clone(); + if let Some((sub, sup)) = fv_clone.get_subsup() { + fv.dummy_link(); + fv_clone.dummy_link(); + let sub = sub._replace_tp(target, to); + let sup = sup._replace_tp(target, to); + fv.undo(); + fv_clone.undo(); + fv_clone.update_constraint(Constraint::new_sandwiched(sub, sup), true); + } else if let Some(ty) = fv_clone.get_type() { + fv_clone.update_constraint( + Constraint::new_type_of(ty._replace_tp(target, to)), + true, + ); + } + Self::FreeVar(fv_clone) + } + Self::Refinement(mut refine) => { + refine.t = Box::new(refine.t._replace_tp(target, to)); + // refine.pred = refine.pred.replace_tp(target, to); + Self::Refinement(refine) + } + Self::Record(mut rec) => { + for v in rec.values_mut() { + *v = std::mem::take(v)._replace_tp(target, to); + } + Self::Record(rec) + } + Self::NamedTuple(mut r) => { + for (_, v) in r.iter_mut() { + *v = std::mem::take(v)._replace_tp(target, to); + } + Self::NamedTuple(r) + } + Self::Subr(subr) => Self::Subr(subr._replace_tp(target, to)), + Self::Callable { param_ts, return_t } => { + let param_ts = param_ts + .into_iter() + .map(|t| t._replace_tp(target, to)) + .collect(); + let return_t = Box::new(return_t._replace_tp(target, to)); + Self::Callable { param_ts, return_t } + } + Self::Quantified(quant) => quant._replace_tp(target, to).quantify(), + Self::Poly { name, params } => { + let params = params + .into_iter() + .map(|tp| tp._replace(target, to)) + .collect(); + Self::Poly { name, params } + } + Self::Ref(t) => Self::Ref(Box::new(t._replace_tp(target, to))), + Self::RefMut { before, after } => Self::RefMut { + before: Box::new(before._replace_tp(target, to)), + after: after.map(|t| Box::new(t._replace_tp(target, to))), + }, + Self::And(l, r) => l._replace_tp(target, to) & r._replace_tp(target, to), + Self::Or(l, r) => l._replace_tp(target, to) | r._replace_tp(target, to), + Self::Not(ty) => !ty._replace_tp(target, to), + Self::Proj { lhs, rhs } => lhs._replace_tp(target, to).proj(rhs), + Self::ProjCall { + lhs, + attr_name, + args, + } => { + let args = args.into_iter().map(|tp| tp._replace(target, to)).collect(); + proj_call(lhs._replace(target, to), attr_name, args) + } + Self::Structural(ty) => ty._replace_tp(target, to).structuralize(), + Self::Guard(guard) => Self::Guard(GuardType::new( + guard.namespace, + guard.target.clone(), + guard.to._replace_tp(target, to), + )), + Self::Bounded { sub, sup } => Self::Bounded { + sub: Box::new(sub._replace_tp(target, to)), + sup: Box::new(sup._replace_tp(target, to)), + }, + other => other, + } + } + fn replace_param(self, target: &str, to: &str) -> Self { match self { Self::FreeVar(fv) if fv.is_linked() => fv.crack().clone().replace_param(target, to), @@ -4415,23 +4611,43 @@ impl Type { } pub struct ReplaceTable<'t> { - rules: Vec<(&'t Type, &'t Type)>, + type_rules: Vec<(&'t Type, &'t Type)>, + tp_rules: Vec<(&'t TyParam, &'t TyParam)>, } impl<'t> ReplaceTable<'t> { pub fn make(target: &'t Type, to: &'t Type) -> Self { - let mut self_ = ReplaceTable { rules: vec![] }; + let mut self_ = ReplaceTable { + type_rules: vec![], + tp_rules: vec![], + }; self_.iterate(target, to); self_ } + pub fn make_tp(target: &'t TyParam, to: &'t TyParam) -> Self { + let mut self_ = ReplaceTable { + type_rules: vec![], + tp_rules: vec![], + }; + self_.iterate_tp(target, to); + self_ + } + pub fn replace(&self, mut ty: Type) -> Type { - for (target, to) in self.rules.iter() { + for (target, to) in self.type_rules.iter() { ty = ty._replace(target, to); } ty } + pub fn replace_tp(&self, mut tp: TyParam) -> TyParam { + for (target, to) in self.tp_rules.iter() { + tp = tp._replace(target, to); + } + tp + } + fn iterate(&mut self, target: &'t Type, to: &'t Type) { match (target, to) { ( @@ -4530,7 +4746,7 @@ impl<'t> ReplaceTable<'t> { } _ => {} } - self.rules.push((target, to)); + self.type_rules.push((target, to)); } fn iterate_tp(&mut self, target: &'t TyParam, to: &'t TyParam) { @@ -4548,6 +4764,7 @@ impl<'t> ReplaceTable<'t> { } _ => {} } + self.tp_rules.push((target, to)); } } diff --git a/crates/erg_compiler/ty/predicate.rs b/crates/erg_compiler/ty/predicate.rs index 79b6c304..697f1811 100644 --- a/crates/erg_compiler/ty/predicate.rs +++ b/crates/erg_compiler/ty/predicate.rs @@ -857,4 +857,112 @@ impl Predicate { Self::Not(pred) => pred.variables(), } } + + pub fn contains_value(&self, value: &ValueObj) -> bool { + match self { + Self::Value(v) => v == value, + Self::Const(_) => false, + Self::Call { receiver, args, .. } => { + receiver.contains_value(value) || args.iter().any(|a| a.contains_value(value)) + } + Self::Attr { receiver, .. } => receiver.contains_value(value), + Self::Equal { rhs, .. } + | Self::GreaterEqual { rhs, .. } + | Self::LessEqual { rhs, .. } + | Self::NotEqual { rhs, .. } => rhs.contains_value(value), + Self::GeneralEqual { lhs, rhs } + | Self::GeneralLessEqual { lhs, rhs } + | Self::GeneralGreaterEqual { lhs, rhs } + | Self::GeneralNotEqual { lhs, rhs } => { + lhs.contains_value(value) || rhs.contains_value(value) + } + Self::And(lhs, rhs) | Self::Or(lhs, rhs) => { + lhs.contains_value(value) || rhs.contains_value(value) + } + Self::Not(pred) => pred.contains_value(value), + Self::Failure => false, + } + } + + pub fn contains_tp(&self, tp: &TyParam) -> bool { + match self { + Self::Value(_) | Self::Failure => false, + Self::Const(_) => false, + Self::Call { receiver, args, .. } => { + receiver.contains_tp(tp) || args.iter().any(|a| a.contains_tp(tp)) + } + Self::Attr { receiver, .. } => receiver.contains_tp(tp), + Self::Equal { rhs, .. } + | Self::GreaterEqual { rhs, .. } + | Self::LessEqual { rhs, .. } + | Self::NotEqual { rhs, .. } => rhs.contains_tp(tp), + Self::GeneralEqual { lhs, rhs } + | Self::GeneralLessEqual { lhs, rhs } + | Self::GeneralGreaterEqual { lhs, rhs } + | Self::GeneralNotEqual { lhs, rhs } => lhs.contains_tp(tp) || rhs.contains_tp(tp), + Self::And(lhs, rhs) | Self::Or(lhs, rhs) => lhs.contains_tp(tp) || rhs.contains_tp(tp), + Self::Not(pred) => pred.contains_tp(tp), + } + } + + pub fn replace_tp(self, target: &TyParam, to: &TyParam) -> Self { + match self { + Self::Value(_) | Self::Failure => self, + Self::Const(_) => self, + Self::Call { + receiver, + args, + name, + } => Self::Call { + receiver: receiver.replace(target, to), + args: args.into_iter().map(|a| a.replace(target, to)).collect(), + name, + }, + Self::Attr { receiver, name } => Self::Attr { + receiver: receiver.replace(target, to), + name, + }, + Self::Equal { lhs, rhs } => Self::Equal { + lhs, + rhs: rhs.replace(target, to), + }, + Self::GreaterEqual { lhs, rhs } => Self::GreaterEqual { + lhs, + rhs: rhs.replace(target, to), + }, + Self::LessEqual { lhs, rhs } => Self::LessEqual { + lhs, + rhs: rhs.replace(target, to), + }, + Self::NotEqual { lhs, rhs } => Self::NotEqual { + lhs, + rhs: rhs.replace(target, to), + }, + Self::GeneralEqual { lhs, rhs } => Self::GeneralEqual { + lhs: Box::new(lhs.replace_tp(target, to)), + rhs: Box::new(rhs.replace_tp(target, to)), + }, + Self::GeneralLessEqual { lhs, rhs } => Self::GeneralLessEqual { + lhs: Box::new(lhs.replace_tp(target, to)), + rhs: Box::new(rhs.replace_tp(target, to)), + }, + Self::GeneralGreaterEqual { lhs, rhs } => Self::GeneralGreaterEqual { + lhs: Box::new(lhs.replace_tp(target, to)), + rhs: Box::new(rhs.replace_tp(target, to)), + }, + Self::GeneralNotEqual { lhs, rhs } => Self::GeneralNotEqual { + lhs: Box::new(lhs.replace_tp(target, to)), + rhs: Box::new(rhs.replace_tp(target, to)), + }, + Self::And(lhs, rhs) => Self::And( + Box::new(lhs.replace_tp(target, to)), + Box::new(rhs.replace_tp(target, to)), + ), + Self::Or(lhs, rhs) => Self::Or( + Box::new(lhs.replace_tp(target, to)), + Box::new(rhs.replace_tp(target, to)), + ), + Self::Not(pred) => Self::Not(Box::new(pred.replace_tp(target, to))), + } + } } diff --git a/crates/erg_compiler/ty/typaram.rs b/crates/erg_compiler/ty/typaram.rs index 9f7b21b5..9970a288 100644 --- a/crates/erg_compiler/ty/typaram.rs +++ b/crates/erg_compiler/ty/typaram.rs @@ -19,7 +19,7 @@ use super::free::{ CanbeFree, Constraint, FreeKind, FreeTyParam, FreeTyVar, HasLevel, Level, GENERIC_LEVEL, }; use super::value::ValueObj; -use super::{ConstSubr, Field, ParamTy, UserConstSubr}; +use super::{ConstSubr, Field, ParamTy, ReplaceTable, UserConstSubr}; use super::{Type, CONTAINER_OMIT_THRESHOLD}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -1324,6 +1324,41 @@ impl TyParam { } } + pub fn contains_value(&self, target: &ValueObj) -> bool { + match self { + Self::FreeVar(fv) if fv.is_linked() => fv.crack().contains_value(target), + Self::Type(t) => t.contains_value(target), + Self::Erased(t) => t.contains_value(target), + Self::Proj { obj, .. } => obj.contains_value(target), + Self::ProjCall { obj, args, .. } => { + obj.contains_value(target) || args.iter().any(|t| t.contains_value(target)) + } + Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.contains_value(target)), + Self::UnsizedList(elem) => elem.contains_value(target), + Self::Set(ts) => ts.iter().any(|t| t.contains_value(target)), + Self::Dict(ts) => ts + .iter() + .any(|(k, v)| k.contains_value(target) || v.contains_value(target)), + Self::Record(rec) | Self::DataClass { fields: rec, .. } => { + rec.iter().any(|(_, tp)| tp.contains_value(target)) + } + Self::Lambda(lambda) => lambda.body.iter().any(|tp| tp.contains_value(target)), + Self::UnaryOp { val, .. } => val.contains_value(target), + Self::BinOp { lhs, rhs, .. } => { + lhs.contains_value(target) || rhs.contains_value(target) + } + Self::App { args, .. } => args.iter().any(|p| p.contains_value(target)), + Self::Value(val) => val.contains(target), + _ => false, + } + } + + pub fn contains_failure(&self) -> bool { + self.contains_tp(&TyParam::Failure) + || self.contains_type(&Type::Failure) + || self.contains_value(&ValueObj::Failure) + } + pub fn is_recursive(&self) -> bool { match self { Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_recursive(), @@ -1592,58 +1627,63 @@ impl TyParam { } pub fn replace(self, target: &TyParam, to: &TyParam) -> TyParam { + let table = ReplaceTable::make_tp(target, to); + table.replace_tp(self) + } + + pub(crate) fn _replace(self, target: &TyParam, to: &TyParam) -> TyParam { if &self == target { return to.clone(); } match self { - TyParam::FreeVar(fv) if fv.is_linked() => fv.crack().clone().replace(target, to), + TyParam::FreeVar(fv) if fv.is_linked() => fv.crack().clone()._replace(target, to), TyParam::App { name, args } => { let new_args = args .into_iter() - .map(|arg| arg.replace(target, to)) + .map(|arg| arg._replace(target, to)) .collect::>(); TyParam::app(name, new_args) } TyParam::BinOp { op, lhs, rhs } => { - let new_lhs = lhs.replace(target, to); - let new_rhs = rhs.replace(target, to); + let new_lhs = lhs._replace(target, to); + let new_rhs = rhs._replace(target, to); TyParam::bin(op, new_lhs, new_rhs) } TyParam::UnaryOp { op, val } => { - let new_val = val.replace(target, to); + let new_val = val._replace(target, to); TyParam::unary(op, new_val) } - TyParam::UnsizedList(elem) => TyParam::unsized_list(elem.replace(target, to)), + TyParam::UnsizedList(elem) => TyParam::unsized_list(elem._replace(target, to)), TyParam::List(tps) => { - let new_tps = tps.into_iter().map(|t| t.replace(target, to)).collect(); + let new_tps = tps.into_iter().map(|t| t._replace(target, to)).collect(); TyParam::List(new_tps) } TyParam::Tuple(tps) => { - let new_tps = tps.into_iter().map(|t| t.replace(target, to)).collect(); + let new_tps = tps.into_iter().map(|t| t._replace(target, to)).collect(); TyParam::Tuple(new_tps) } TyParam::Set(tps) => { - let new_tps = tps.into_iter().map(|t| t.replace(target, to)).collect(); + let new_tps = tps.into_iter().map(|t| t._replace(target, to)).collect(); TyParam::Set(new_tps) } TyParam::Dict(tps) => { let new_tps = tps .into_iter() - .map(|(k, v)| (k.replace(target, to), v.replace(target, to))) + .map(|(k, v)| (k._replace(target, to), v._replace(target, to))) .collect(); TyParam::Dict(new_tps) } TyParam::Record(rec) => { let new_rec = rec .into_iter() - .map(|(k, v)| (k, v.replace(target, to))) + .map(|(k, v)| (k, v._replace(target, to))) .collect(); TyParam::Record(new_rec) } TyParam::DataClass { name, fields } => { let new_fields = fields .into_iter() - .map(|(k, v)| (k, v.replace(target, to))) + .map(|(k, v)| (k, v._replace(target, to))) .collect(); TyParam::DataClass { name, @@ -1654,7 +1694,7 @@ impl TyParam { let new_body = lambda .body .into_iter() - .map(|tp| tp.replace(target, to)) + .map(|tp| tp._replace(target, to)) .collect(); TyParam::Lambda(TyParamLambda { body: new_body, @@ -1662,17 +1702,17 @@ impl TyParam { }) } TyParam::Proj { obj, attr } => { - let new_obj = obj.replace(target, to); + let new_obj = obj._replace(target, to); TyParam::Proj { obj: Box::new(new_obj), attr, } } TyParam::ProjCall { obj, attr, args } => { - let new_obj = obj.replace(target, to); + let new_obj = obj._replace(target, to); let new_args = args .into_iter() - .map(|arg| arg.replace(target, to)) + .map(|arg| arg._replace(target, to)) .collect::>(); TyParam::ProjCall { obj: Box::new(new_obj), @@ -1680,6 +1720,8 @@ impl TyParam { args: new_args, } } + TyParam::Type(t) => TyParam::t(t._replace_tp(target, to)), + TyParam::Value(val) => TyParam::value(val.replace_tp(target, to)), self_ => self_, } } diff --git a/crates/erg_compiler/ty/value.rs b/crates/erg_compiler/ty/value.rs index 1c9a2551..fae3b4f8 100644 --- a/crates/erg_compiler/ty/value.rs +++ b/crates/erg_compiler/ty/value.rs @@ -1654,6 +1654,66 @@ impl ValueObj { self_ => self_, } } + + pub fn replace_tp(self, target: &TyParam, to: &TyParam) -> Self { + match self { + ValueObj::Type(obj) => ValueObj::Type(obj.mapped_t(|t| t._replace_tp(target, to))), + ValueObj::List(lis) => ValueObj::List( + lis.iter() + .map(|v| v.clone().replace_tp(target, to)) + .collect(), + ), + ValueObj::Tuple(tup) => ValueObj::Tuple( + tup.iter() + .map(|v| v.clone().replace_tp(target, to)) + .collect(), + ), + ValueObj::Set(st) => ValueObj::Set( + st.iter() + .map(|v| v.clone().replace_tp(target, to)) + .collect(), + ), + ValueObj::Dict(dict) => ValueObj::Dict( + dict.iter() + .map(|(k, v)| { + ( + k.clone().replace_tp(target, to), + v.clone().replace_tp(target, to), + ) + }) + .collect(), + ), + ValueObj::Record(rec) => ValueObj::Record( + rec.iter() + .map(|(k, v)| (k.clone(), v.clone().replace_tp(target, to))) + .collect(), + ), + ValueObj::DataClass { name, fields } => ValueObj::DataClass { + name, + fields: fields + .iter() + .map(|(k, v)| (k.clone(), v.clone().replace_tp(target, to))) + .collect(), + }, + ValueObj::UnsizedList(elem) => { + ValueObj::UnsizedList(Box::new(elem.clone().replace_tp(target, to))) + } + self_ => self_, + } + } + + 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), + _ => self == val, + } + } } pub mod value_set {