mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-03 22:14:37 +00:00
chore: add Predicate::{map_t, map_tp}
This commit is contained in:
parent
837414929c
commit
7a960f2cbb
8 changed files with 333 additions and 74 deletions
|
@ -1968,15 +1968,17 @@ impl Context {
|
||||||
TyParam::erased(t)
|
TyParam::erased(t)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TyParam::Value(ValueObj::Type(mut t)) => {
|
TyParam::Value(val) => {
|
||||||
match t.try_map_t(|t| self.eval_t_params(t, self.level, &())) {
|
match val
|
||||||
Ok(_) => {}
|
.clone()
|
||||||
|
.try_map_t(&mut |t| self.eval_t_params(t, self.level, &()))
|
||||||
|
{
|
||||||
|
Ok(val) => TyParam::Value(val),
|
||||||
Err((_t, es)) => {
|
Err((_t, es)) => {
|
||||||
errs.extend(es);
|
errs.extend(es);
|
||||||
*t.typ_mut() = _t;
|
TyParam::Value(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TyParam::Value(ValueObj::Type(t))
|
|
||||||
}
|
}
|
||||||
TyParam::ProjCall { obj, attr, args } => {
|
TyParam::ProjCall { obj, attr, args } => {
|
||||||
match self.eval_proj_call(*obj, attr, args, &()) {
|
match self.eval_proj_call(*obj, attr, args, &()) {
|
||||||
|
@ -1994,7 +1996,6 @@ impl Context {
|
||||||
return Err((TyParam::Failure, errs));
|
return Err((TyParam::Failure, errs));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TyParam::Value(_) => p.clone(),
|
|
||||||
other => {
|
other => {
|
||||||
errs.push(EvalError::feature_error(
|
errs.push(EvalError::feature_error(
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
|
|
|
@ -45,9 +45,7 @@ impl Generalizer {
|
||||||
fn generalize_tp(&mut self, free: TyParam, uninit: bool) -> TyParam {
|
fn generalize_tp(&mut self, free: TyParam, uninit: bool) -> TyParam {
|
||||||
match free {
|
match free {
|
||||||
TyParam::Type(t) => TyParam::t(self.generalize_t(*t, uninit)),
|
TyParam::Type(t) => TyParam::t(self.generalize_t(*t, uninit)),
|
||||||
TyParam::Value(ValueObj::Type(t)) => {
|
TyParam::Value(val) => TyParam::Value(val.map_t(&mut |t| self.generalize_t(t, uninit))),
|
||||||
TyParam::t(self.generalize_t(t.into_typ(), uninit))
|
|
||||||
}
|
|
||||||
TyParam::FreeVar(fv) if fv.is_generalized() => TyParam::FreeVar(fv),
|
TyParam::FreeVar(fv) if fv.is_generalized() => TyParam::FreeVar(fv),
|
||||||
TyParam::FreeVar(fv) if fv.is_linked() => {
|
TyParam::FreeVar(fv) if fv.is_linked() => {
|
||||||
let tp = fv.crack().clone();
|
let tp = fv.crack().clone();
|
||||||
|
@ -328,9 +326,8 @@ impl Generalizer {
|
||||||
fn generalize_pred(&mut self, pred: Predicate, uninit: bool) -> Predicate {
|
fn generalize_pred(&mut self, pred: Predicate, uninit: bool) -> Predicate {
|
||||||
match pred {
|
match pred {
|
||||||
Predicate::Const(_) | Predicate::Failure => pred,
|
Predicate::Const(_) | Predicate::Failure => pred,
|
||||||
Predicate::Value(ValueObj::Type(mut typ)) => {
|
Predicate::Value(val) => {
|
||||||
*typ.typ_mut() = self.generalize_t(mem::take(typ.typ_mut()), uninit);
|
Predicate::Value(val.map_t(&mut |t| self.generalize_t(t, uninit)))
|
||||||
Predicate::Value(ValueObj::Type(typ))
|
|
||||||
}
|
}
|
||||||
Predicate::Call {
|
Predicate::Call {
|
||||||
receiver,
|
receiver,
|
||||||
|
@ -348,7 +345,6 @@ impl Generalizer {
|
||||||
let receiver = self.generalize_tp(receiver, uninit);
|
let receiver = self.generalize_tp(receiver, uninit);
|
||||||
Predicate::attr(receiver, name)
|
Predicate::attr(receiver, name)
|
||||||
}
|
}
|
||||||
Predicate::Value(_) => pred,
|
|
||||||
Predicate::GeneralEqual { lhs, rhs } => {
|
Predicate::GeneralEqual { lhs, rhs } => {
|
||||||
let lhs = self.generalize_pred(*lhs, uninit);
|
let lhs = self.generalize_pred(*lhs, uninit);
|
||||||
let rhs = self.generalize_pred(*rhs, uninit);
|
let rhs = self.generalize_pred(*rhs, uninit);
|
||||||
|
|
|
@ -578,15 +578,15 @@ impl Context {
|
||||||
let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?;
|
let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?;
|
||||||
Ok(TyParam::t(t))
|
Ok(TyParam::t(t))
|
||||||
}
|
}
|
||||||
TyParam::Value(ValueObj::Type(t)) => {
|
TyParam::Value(val) => {
|
||||||
let t = self.instantiate_t_inner(t.into_typ(), tmp_tv_cache, loc)?;
|
let val = val.try_map_t(&mut |t| self.instantiate_t_inner(t, tmp_tv_cache, loc))?;
|
||||||
Ok(TyParam::t(t))
|
Ok(TyParam::Value(val))
|
||||||
}
|
}
|
||||||
TyParam::Erased(t) => {
|
TyParam::Erased(t) => {
|
||||||
let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?;
|
let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?;
|
||||||
Ok(TyParam::Erased(Box::new(t)))
|
Ok(TyParam::Erased(Box::new(t)))
|
||||||
}
|
}
|
||||||
p @ (TyParam::Value(_) | TyParam::Mono(_) | TyParam::FreeVar(_)) => Ok(p),
|
p @ (TyParam::Mono(_) | TyParam::FreeVar(_)) => Ok(p),
|
||||||
other => {
|
other => {
|
||||||
type_feature_error!(
|
type_feature_error!(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -317,6 +317,22 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
(ValueObj::Set(sub), ValueObj::Set(sup)) => {
|
||||||
|
if sub.len() == 1 && sup.len() == 1 {
|
||||||
|
let sub = sub.iter().next().unwrap();
|
||||||
|
let sup = sup.iter().next().unwrap();
|
||||||
|
self.sub_unify_value(sub, sup)?;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(TyCheckErrors::from(TyCheckError::feature_error(
|
||||||
|
self.ctx.cfg.input.clone(),
|
||||||
|
line!() as usize,
|
||||||
|
self.loc.loc(),
|
||||||
|
&format!("unifying {sub} and {sup}"),
|
||||||
|
self.ctx.caused_by(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
(ValueObj::Record(sub), ValueObj::Record(sup)) => {
|
(ValueObj::Record(sub), ValueObj::Record(sup)) => {
|
||||||
for (sub_k, sub_v) in sub.iter() {
|
for (sub_k, sub_v) in sub.iter() {
|
||||||
if let Some(sup_v) = sup.get(sub_k) {
|
if let Some(sup_v) = sup.get(sub_k) {
|
||||||
|
|
|
@ -303,7 +303,7 @@ impl TryFrom<Type> for SubrType {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
fn try_from(t: Type) -> Result<Self, ()> {
|
fn try_from(t: Type) -> Result<Self, ()> {
|
||||||
match t {
|
match t {
|
||||||
Type::FreeVar(fv) if fv.is_linked() => Self::try_from(fv.crack().clone()),
|
Type::FreeVar(fv) if fv.is_linked() => Self::try_from(fv.unwrap_linked()),
|
||||||
Type::Subr(st) => Ok(st),
|
Type::Subr(st) => Ok(st),
|
||||||
Type::Quantified(quant) => SubrType::try_from(*quant),
|
Type::Quantified(quant) => SubrType::try_from(*quant),
|
||||||
Type::Refinement(refine) => Self::try_from(*refine.t),
|
Type::Refinement(refine) => Self::try_from(*refine.t),
|
||||||
|
@ -2829,8 +2829,9 @@ impl Type {
|
||||||
Self::Poly { params, .. } => params.iter().any(|tp| tp.contains_type(target)),
|
Self::Poly { params, .. } => params.iter().any(|tp| tp.contains_type(target)),
|
||||||
Self::Quantified(t) => t.contains_type(target),
|
Self::Quantified(t) => t.contains_type(target),
|
||||||
Self::Subr(subr) => subr.contains_type(target),
|
Self::Subr(subr) => subr.contains_type(target),
|
||||||
// TODO: preds
|
Self::Refinement(refine) => {
|
||||||
Self::Refinement(refine) => refine.t.contains_type(target),
|
refine.t.contains_type(target) || refine.pred.contains_t(target)
|
||||||
|
}
|
||||||
Self::Structural(ty) => ty.contains_type(target),
|
Self::Structural(ty) => ty.contains_type(target),
|
||||||
Self::Proj { lhs, .. } => lhs.contains_type(target),
|
Self::Proj { lhs, .. } => lhs.contains_type(target),
|
||||||
Self::ProjCall { lhs, args, .. } => {
|
Self::ProjCall { lhs, args, .. } => {
|
||||||
|
@ -2929,7 +2930,9 @@ impl Type {
|
||||||
Self::Poly { params, .. } => params.iter().any(|tp| tp.contains_type(self)),
|
Self::Poly { params, .. } => params.iter().any(|tp| tp.contains_type(self)),
|
||||||
Self::Quantified(t) => t.contains_type(self),
|
Self::Quantified(t) => t.contains_type(self),
|
||||||
Self::Subr(subr) => subr.contains_type(self),
|
Self::Subr(subr) => subr.contains_type(self),
|
||||||
Self::Refinement(refine) => refine.t.contains_type(self),
|
Self::Refinement(refine) => {
|
||||||
|
refine.t.contains_type(self) || refine.pred.contains_t(self)
|
||||||
|
}
|
||||||
Self::Structural(ty) => ty.contains_type(self),
|
Self::Structural(ty) => ty.contains_type(self),
|
||||||
Self::Proj { lhs, .. } => lhs.contains_type(self),
|
Self::Proj { lhs, .. } => lhs.contains_type(self),
|
||||||
Self::ProjCall { lhs, args, .. } => {
|
Self::ProjCall { lhs, args, .. } => {
|
||||||
|
@ -3235,7 +3238,7 @@ impl Type {
|
||||||
/// ```
|
/// ```
|
||||||
pub fn into_refinement(self) -> RefinementType {
|
pub fn into_refinement(self) -> RefinementType {
|
||||||
match self {
|
match self {
|
||||||
Type::FreeVar(fv) if fv.is_linked() => fv.crack().clone().into_refinement(),
|
Type::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().into_refinement(),
|
||||||
Type::Nat => {
|
Type::Nat => {
|
||||||
let var = FRESH_GEN.fresh_varname();
|
let var = FRESH_GEN.fresh_varname();
|
||||||
RefinementType::new(
|
RefinementType::new(
|
||||||
|
@ -3289,7 +3292,7 @@ impl Type {
|
||||||
|
|
||||||
pub fn deconstruct_refinement(self) -> Result<(Str, Type, Predicate), Type> {
|
pub fn deconstruct_refinement(self) -> Result<(Str, Type, Predicate), Type> {
|
||||||
match self {
|
match self {
|
||||||
Type::FreeVar(fv) if fv.is_linked() => fv.crack().clone().deconstruct_refinement(),
|
Type::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().deconstruct_refinement(),
|
||||||
Type::Refinement(r) => Ok(r.deconstruct()),
|
Type::Refinement(r) => Ok(r.deconstruct()),
|
||||||
_ => Err(self),
|
_ => Err(self),
|
||||||
}
|
}
|
||||||
|
@ -3993,6 +3996,7 @@ impl Type {
|
||||||
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().eliminate_recursion(target),
|
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().eliminate_recursion(target),
|
||||||
Self::Refinement(mut refine) => {
|
Self::Refinement(mut refine) => {
|
||||||
refine.t = Box::new(refine.t.eliminate_recursion(target));
|
refine.t = Box::new(refine.t.eliminate_recursion(target));
|
||||||
|
refine.pred = Box::new(refine.pred.map_t(&mut |t| t.eliminate_recursion(target)));
|
||||||
Self::Refinement(refine)
|
Self::Refinement(refine)
|
||||||
}
|
}
|
||||||
Self::Record(mut rec) => {
|
Self::Record(mut rec) => {
|
||||||
|
@ -4138,7 +4142,7 @@ impl Type {
|
||||||
self = to.clone();
|
self = to.clone();
|
||||||
}
|
}
|
||||||
match self {
|
match self {
|
||||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().clone()._replace(target, to),
|
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked()._replace(target, to),
|
||||||
Self::FreeVar(fv) => {
|
Self::FreeVar(fv) => {
|
||||||
let fv_clone = fv.deep_clone();
|
let fv_clone = fv.deep_clone();
|
||||||
if let Some((sub, sup)) = fv_clone.get_subsup() {
|
if let Some((sub, sup)) = fv_clone.get_subsup() {
|
||||||
|
@ -4157,6 +4161,7 @@ impl Type {
|
||||||
}
|
}
|
||||||
Self::Refinement(mut refine) => {
|
Self::Refinement(mut refine) => {
|
||||||
refine.t = Box::new(refine.t._replace(target, to));
|
refine.t = Box::new(refine.t._replace(target, to));
|
||||||
|
refine.pred = Box::new(refine.pred._replace_t(target, to));
|
||||||
Self::Refinement(refine)
|
Self::Refinement(refine)
|
||||||
}
|
}
|
||||||
Self::Record(mut rec) => {
|
Self::Record(mut rec) => {
|
||||||
|
@ -4224,7 +4229,7 @@ impl Type {
|
||||||
|
|
||||||
fn _replace_tp(self, target: &TyParam, to: &TyParam) -> Type {
|
fn _replace_tp(self, target: &TyParam, to: &TyParam) -> Type {
|
||||||
match self {
|
match self {
|
||||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().clone()._replace_tp(target, to),
|
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked()._replace_tp(target, to),
|
||||||
Self::FreeVar(fv) => {
|
Self::FreeVar(fv) => {
|
||||||
let fv_clone = fv.deep_clone();
|
let fv_clone = fv.deep_clone();
|
||||||
if let Some((sub, sup)) = fv_clone.get_subsup() {
|
if let Some((sub, sup)) = fv_clone.get_subsup() {
|
||||||
|
@ -4245,7 +4250,7 @@ impl Type {
|
||||||
}
|
}
|
||||||
Self::Refinement(mut refine) => {
|
Self::Refinement(mut refine) => {
|
||||||
refine.t = Box::new(refine.t._replace_tp(target, to));
|
refine.t = Box::new(refine.t._replace_tp(target, to));
|
||||||
// refine.pred = refine.pred.replace_tp(target, to);
|
refine.pred = Box::new(refine.pred._replace_tp(target, to));
|
||||||
Self::Refinement(refine)
|
Self::Refinement(refine)
|
||||||
}
|
}
|
||||||
Self::Record(mut rec) => {
|
Self::Record(mut rec) => {
|
||||||
|
@ -4328,7 +4333,7 @@ impl Type {
|
||||||
}
|
}
|
||||||
Self::Refinement(mut refine) => {
|
Self::Refinement(mut refine) => {
|
||||||
refine.t = Box::new(refine.t.map_tp(f));
|
refine.t = Box::new(refine.t.map_tp(f));
|
||||||
// refine.pred = refine.pred.replace_tp(target, to);
|
refine.pred = Box::new(refine.pred.map_tp(f));
|
||||||
Self::Refinement(refine)
|
Self::Refinement(refine)
|
||||||
}
|
}
|
||||||
Self::Record(mut rec) => {
|
Self::Record(mut rec) => {
|
||||||
|
@ -4387,7 +4392,7 @@ impl Type {
|
||||||
|
|
||||||
fn replace_param(self, target: &str, to: &str) -> Self {
|
fn replace_param(self, target: &str, to: &str) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().clone().replace_param(target, to),
|
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().replace_param(target, to),
|
||||||
Self::Refinement(mut refine) => {
|
Self::Refinement(mut refine) => {
|
||||||
*refine.t = refine.t.replace_param(target, to);
|
*refine.t = refine.t.replace_param(target, to);
|
||||||
Self::Refinement(refine)
|
Self::Refinement(refine)
|
||||||
|
@ -4412,11 +4417,16 @@ impl Type {
|
||||||
/// TyParam::Value(ValueObj::Type(_)) => TyParam::Type
|
/// TyParam::Value(ValueObj::Type(_)) => TyParam::Type
|
||||||
pub fn normalize(self) -> Self {
|
pub fn normalize(self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().clone().normalize(),
|
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().normalize(),
|
||||||
Self::Poly { name, params } => {
|
Self::Poly { name, params } => {
|
||||||
let params = params.into_iter().map(|tp| tp.normalize()).collect();
|
let params = params.into_iter().map(|tp| tp.normalize()).collect();
|
||||||
Self::Poly { name, params }
|
Self::Poly { name, params }
|
||||||
}
|
}
|
||||||
|
Self::Refinement(mut refine) => {
|
||||||
|
refine.t = Box::new(refine.t.normalize());
|
||||||
|
refine.pred = Box::new(refine.pred.map_t(&mut |t| t.normalize()));
|
||||||
|
Self::Refinement(refine)
|
||||||
|
}
|
||||||
Self::Subr(mut subr) => {
|
Self::Subr(mut subr) => {
|
||||||
for nd in subr.non_default_params.iter_mut() {
|
for nd in subr.non_default_params.iter_mut() {
|
||||||
*nd.typ_mut() = std::mem::take(nd.typ_mut()).normalize();
|
*nd.typ_mut() = std::mem::take(nd.typ_mut()).normalize();
|
||||||
|
@ -4738,7 +4748,10 @@ impl Type {
|
||||||
fv.update_init();
|
fv.update_init();
|
||||||
}
|
}
|
||||||
// TODO: T(:> X, <: Y).dereference()
|
// TODO: T(:> X, <: Y).dereference()
|
||||||
Self::Refinement(refine) => refine.t.dereference(),
|
Self::Refinement(refine) => {
|
||||||
|
refine.t.dereference();
|
||||||
|
refine.pred.dereference();
|
||||||
|
}
|
||||||
Self::Ref(t) => {
|
Self::Ref(t) => {
|
||||||
t.dereference();
|
t.dereference();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,9 @@ use erg_common::{fmt_option, set, Str};
|
||||||
use super::free::{Constraint, HasLevel};
|
use super::free::{Constraint, HasLevel};
|
||||||
use super::typaram::TyParam;
|
use super::typaram::TyParam;
|
||||||
use super::value::ValueObj;
|
use super::value::ValueObj;
|
||||||
|
use super::Type;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
|
||||||
pub enum Predicate {
|
pub enum Predicate {
|
||||||
Value(ValueObj), // True/False
|
Value(ValueObj), // True/False
|
||||||
Const(Str),
|
Const(Str),
|
||||||
|
@ -63,6 +64,7 @@ pub enum Predicate {
|
||||||
Or(Box<Predicate>, Box<Predicate>),
|
Or(Box<Predicate>, Box<Predicate>),
|
||||||
And(Box<Predicate>, Box<Predicate>),
|
And(Box<Predicate>, Box<Predicate>),
|
||||||
Not(Box<Predicate>),
|
Not(Box<Predicate>),
|
||||||
|
#[default]
|
||||||
Failure,
|
Failure,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -860,7 +862,7 @@ impl Predicate {
|
||||||
|
|
||||||
pub fn contains_value(&self, value: &ValueObj) -> bool {
|
pub fn contains_value(&self, value: &ValueObj) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Value(v) => v == value,
|
Self::Value(v) => v.contains(value),
|
||||||
Self::Const(_) => false,
|
Self::Const(_) => false,
|
||||||
Self::Call { receiver, args, .. } => {
|
Self::Call { receiver, args, .. } => {
|
||||||
receiver.contains_value(value) || args.iter().any(|a| a.contains_value(value))
|
receiver.contains_value(value) || args.iter().any(|a| a.contains_value(value))
|
||||||
|
@ -886,8 +888,7 @@ impl Predicate {
|
||||||
|
|
||||||
pub fn contains_tp(&self, tp: &TyParam) -> bool {
|
pub fn contains_tp(&self, tp: &TyParam) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Value(_) | Self::Failure => false,
|
Self::Value(v) => v.contains_tp(tp),
|
||||||
Self::Const(_) => false,
|
|
||||||
Self::Call { receiver, args, .. } => {
|
Self::Call { receiver, args, .. } => {
|
||||||
receiver.contains_tp(tp) || args.iter().any(|a| a.contains_tp(tp))
|
receiver.contains_tp(tp) || args.iter().any(|a| a.contains_tp(tp))
|
||||||
}
|
}
|
||||||
|
@ -902,67 +903,159 @@ impl Predicate {
|
||||||
| Self::GeneralNotEqual { lhs, rhs } => lhs.contains_tp(tp) || rhs.contains_tp(tp),
|
| 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::And(lhs, rhs) | Self::Or(lhs, rhs) => lhs.contains_tp(tp) || rhs.contains_tp(tp),
|
||||||
Self::Not(pred) => pred.contains_tp(tp),
|
Self::Not(pred) => pred.contains_tp(tp),
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replace_tp(self, target: &TyParam, to: &TyParam) -> Self {
|
pub fn contains_t(&self, t: &Type) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Value(_) | Self::Failure => self,
|
Self::Value(v) => v.contains_type(t),
|
||||||
|
Self::Call { receiver, args, .. } => {
|
||||||
|
receiver.contains_type(t) || args.iter().any(|a| a.contains_type(t))
|
||||||
|
}
|
||||||
|
Self::Attr { receiver, .. } => receiver.contains_type(t),
|
||||||
|
Self::Equal { rhs, .. }
|
||||||
|
| Self::GreaterEqual { rhs, .. }
|
||||||
|
| Self::LessEqual { rhs, .. }
|
||||||
|
| Self::NotEqual { rhs, .. } => rhs.contains_type(t),
|
||||||
|
Self::GeneralEqual { lhs, rhs }
|
||||||
|
| Self::GeneralLessEqual { lhs, rhs }
|
||||||
|
| Self::GeneralGreaterEqual { lhs, rhs }
|
||||||
|
| Self::GeneralNotEqual { lhs, rhs } => lhs.contains_t(t) || rhs.contains_t(t),
|
||||||
|
Self::And(lhs, rhs) | Self::Or(lhs, rhs) => lhs.contains_t(t) || rhs.contains_t(t),
|
||||||
|
Self::Not(pred) => pred.contains_t(t),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _replace_tp(self, target: &TyParam, to: &TyParam) -> Self {
|
||||||
|
self.map_tp(|tp| tp._replace(target, to))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn replace_tp(self, target: &TyParam, to: &TyParam) -> Self {
|
||||||
|
self.map_tp(|tp| tp.replace(target, to))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _replace_t(self, target: &Type, to: &Type) -> Self {
|
||||||
|
self.map_t(&mut |t| t._replace(target, to))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dereference(&mut self) {
|
||||||
|
*self = std::mem::take(self).map_t(&mut |mut t| {
|
||||||
|
t.dereference();
|
||||||
|
t
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_t(self, f: &mut impl FnMut(Type) -> Type) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Value(val) => Self::Value(val.map_t(f)),
|
||||||
Self::Const(_) => self,
|
Self::Const(_) => self,
|
||||||
Self::Call {
|
Self::Call {
|
||||||
receiver,
|
receiver,
|
||||||
args,
|
args,
|
||||||
name,
|
name,
|
||||||
} => Self::Call {
|
} => Self::Call {
|
||||||
receiver: receiver.replace(target, to),
|
receiver: receiver.map_t(f),
|
||||||
args: args.into_iter().map(|a| a.replace(target, to)).collect(),
|
args: args.into_iter().map(|a| a.map_t(f)).collect(),
|
||||||
name,
|
name,
|
||||||
},
|
},
|
||||||
Self::Attr { receiver, name } => Self::Attr {
|
Self::Attr { receiver, name } => Self::Attr {
|
||||||
receiver: receiver.replace(target, to),
|
receiver: receiver.map_t(f),
|
||||||
name,
|
name,
|
||||||
},
|
},
|
||||||
Self::Equal { lhs, rhs } => Self::Equal {
|
Self::Equal { lhs, rhs } => Self::Equal {
|
||||||
lhs,
|
lhs,
|
||||||
rhs: rhs.replace(target, to),
|
rhs: rhs.map_t(f),
|
||||||
},
|
},
|
||||||
Self::GreaterEqual { lhs, rhs } => Self::GreaterEqual {
|
Self::GreaterEqual { lhs, rhs } => Self::GreaterEqual {
|
||||||
lhs,
|
lhs,
|
||||||
rhs: rhs.replace(target, to),
|
rhs: rhs.map_t(f),
|
||||||
},
|
},
|
||||||
Self::LessEqual { lhs, rhs } => Self::LessEqual {
|
Self::LessEqual { lhs, rhs } => Self::LessEqual {
|
||||||
lhs,
|
lhs,
|
||||||
rhs: rhs.replace(target, to),
|
rhs: rhs.map_t(f),
|
||||||
},
|
},
|
||||||
Self::NotEqual { lhs, rhs } => Self::NotEqual {
|
Self::NotEqual { lhs, rhs } => Self::NotEqual {
|
||||||
lhs,
|
lhs,
|
||||||
rhs: rhs.replace(target, to),
|
rhs: rhs.map_t(f),
|
||||||
},
|
},
|
||||||
Self::GeneralEqual { lhs, rhs } => Self::GeneralEqual {
|
Self::GeneralEqual { lhs, rhs } => Self::GeneralEqual {
|
||||||
lhs: Box::new(lhs.replace_tp(target, to)),
|
lhs: Box::new(lhs.map_t(f)),
|
||||||
rhs: Box::new(rhs.replace_tp(target, to)),
|
rhs: Box::new(rhs.map_t(f)),
|
||||||
},
|
},
|
||||||
Self::GeneralLessEqual { lhs, rhs } => Self::GeneralLessEqual {
|
Self::GeneralLessEqual { lhs, rhs } => Self::GeneralLessEqual {
|
||||||
lhs: Box::new(lhs.replace_tp(target, to)),
|
lhs: Box::new(lhs.map_t(f)),
|
||||||
rhs: Box::new(rhs.replace_tp(target, to)),
|
rhs: Box::new(rhs.map_t(f)),
|
||||||
},
|
},
|
||||||
Self::GeneralGreaterEqual { lhs, rhs } => Self::GeneralGreaterEqual {
|
Self::GeneralGreaterEqual { lhs, rhs } => Self::GeneralGreaterEqual {
|
||||||
lhs: Box::new(lhs.replace_tp(target, to)),
|
lhs: Box::new(lhs.map_t(f)),
|
||||||
rhs: Box::new(rhs.replace_tp(target, to)),
|
rhs: Box::new(rhs.map_t(f)),
|
||||||
},
|
},
|
||||||
Self::GeneralNotEqual { lhs, rhs } => Self::GeneralNotEqual {
|
Self::GeneralNotEqual { lhs, rhs } => Self::GeneralNotEqual {
|
||||||
lhs: Box::new(lhs.replace_tp(target, to)),
|
lhs: Box::new(lhs.map_t(f)),
|
||||||
rhs: Box::new(rhs.replace_tp(target, to)),
|
rhs: Box::new(rhs.map_t(f)),
|
||||||
},
|
},
|
||||||
Self::And(lhs, rhs) => Self::And(
|
Self::And(lhs, rhs) => Self::And(Box::new(lhs.map_t(f)), Box::new(rhs.map_t(f))),
|
||||||
Box::new(lhs.replace_tp(target, to)),
|
Self::Or(lhs, rhs) => Self::Or(Box::new(lhs.map_t(f)), Box::new(rhs.map_t(f))),
|
||||||
Box::new(rhs.replace_tp(target, to)),
|
Self::Not(pred) => Self::Not(Box::new(pred.map_t(f))),
|
||||||
),
|
_ => self,
|
||||||
Self::Or(lhs, rhs) => Self::Or(
|
}
|
||||||
Box::new(lhs.replace_tp(target, to)),
|
}
|
||||||
Box::new(rhs.replace_tp(target, to)),
|
|
||||||
),
|
pub fn map_tp(self, f: impl Fn(TyParam) -> TyParam + Copy) -> Self {
|
||||||
Self::Not(pred) => Self::Not(Box::new(pred.replace_tp(target, to))),
|
match self {
|
||||||
|
Self::Value(val) => Self::Value(val.map_tp(f)),
|
||||||
|
Self::Const(_) => self,
|
||||||
|
Self::Call {
|
||||||
|
receiver,
|
||||||
|
args,
|
||||||
|
name,
|
||||||
|
} => Self::Call {
|
||||||
|
receiver: receiver.map(f),
|
||||||
|
args: args.into_iter().map(|a| a.map(f)).collect(),
|
||||||
|
name,
|
||||||
|
},
|
||||||
|
Self::Attr { receiver, name } => Self::Attr {
|
||||||
|
receiver: receiver.map(f),
|
||||||
|
name,
|
||||||
|
},
|
||||||
|
Self::Equal { lhs, rhs } => Self::Equal {
|
||||||
|
lhs,
|
||||||
|
rhs: rhs.map(f),
|
||||||
|
},
|
||||||
|
Self::GreaterEqual { lhs, rhs } => Self::GreaterEqual {
|
||||||
|
lhs,
|
||||||
|
rhs: rhs.map(f),
|
||||||
|
},
|
||||||
|
Self::LessEqual { lhs, rhs } => Self::LessEqual {
|
||||||
|
lhs,
|
||||||
|
rhs: rhs.map(f),
|
||||||
|
},
|
||||||
|
Self::NotEqual { lhs, rhs } => Self::NotEqual {
|
||||||
|
lhs,
|
||||||
|
rhs: rhs.map(f),
|
||||||
|
},
|
||||||
|
Self::GeneralEqual { lhs, rhs } => Self::GeneralEqual {
|
||||||
|
lhs: Box::new(lhs.map_tp(f)),
|
||||||
|
rhs: Box::new(rhs.map_tp(f)),
|
||||||
|
},
|
||||||
|
Self::GeneralLessEqual { lhs, rhs } => Self::GeneralLessEqual {
|
||||||
|
lhs: Box::new(lhs.map_tp(f)),
|
||||||
|
rhs: Box::new(rhs.map_tp(f)),
|
||||||
|
},
|
||||||
|
Self::GeneralGreaterEqual { lhs, rhs } => Self::GeneralGreaterEqual {
|
||||||
|
lhs: Box::new(lhs.map_tp(f)),
|
||||||
|
rhs: Box::new(rhs.map_tp(f)),
|
||||||
|
},
|
||||||
|
Self::GeneralNotEqual { lhs, rhs } => Self::GeneralNotEqual {
|
||||||
|
lhs: Box::new(lhs.map_tp(f)),
|
||||||
|
rhs: Box::new(rhs.map_tp(f)),
|
||||||
|
},
|
||||||
|
Self::And(lhs, rhs) => Self::And(Box::new(lhs.map_tp(f)), Box::new(rhs.map_tp(f))),
|
||||||
|
Self::Or(lhs, rhs) => Self::Or(Box::new(lhs.map_tp(f)), Box::new(rhs.map_tp(f))),
|
||||||
|
Self::Not(pred) => Self::Not(Box::new(pred.map_tp(f))),
|
||||||
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1913,6 +1913,61 @@ impl TyParam {
|
||||||
self_ => self_,
|
self_ => self_,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn map_t(self, f: &mut impl FnMut(Type) -> Type) -> TyParam {
|
||||||
|
match self {
|
||||||
|
TyParam::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().map_t(f),
|
||||||
|
TyParam::App { name, args } => {
|
||||||
|
let new_args = args.into_iter().map(|tp| tp.map_t(f)).collect::<Vec<_>>();
|
||||||
|
TyParam::app(name, new_args)
|
||||||
|
}
|
||||||
|
TyParam::BinOp { op, lhs, rhs } => TyParam::bin(op, lhs.map_t(f), rhs.map_t(f)),
|
||||||
|
TyParam::UnaryOp { op, val } => TyParam::unary(op, val.map_t(f)),
|
||||||
|
TyParam::UnsizedList(elem) => TyParam::unsized_list(elem.map_t(f)),
|
||||||
|
TyParam::List(tps) => TyParam::List(tps.into_iter().map(|tp| tp.map_t(f)).collect()),
|
||||||
|
TyParam::Tuple(tps) => TyParam::Tuple(tps.into_iter().map(|tp| tp.map_t(f)).collect()),
|
||||||
|
TyParam::Set(tps) => TyParam::Set(tps.into_iter().map(|tp| tp.map_t(f)).collect()),
|
||||||
|
TyParam::Dict(tps) => {
|
||||||
|
let new_tps = tps
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| (k.map_t(f), v.map_t(f)))
|
||||||
|
.collect();
|
||||||
|
TyParam::Dict(new_tps)
|
||||||
|
}
|
||||||
|
TyParam::Record(rec) => {
|
||||||
|
let new_rec = rec.into_iter().map(|(k, v)| (k, v.map_t(f))).collect();
|
||||||
|
TyParam::Record(new_rec)
|
||||||
|
}
|
||||||
|
TyParam::DataClass { name, fields } => {
|
||||||
|
let new_fields = fields.into_iter().map(|(k, v)| (k, v.map_t(f))).collect();
|
||||||
|
TyParam::DataClass {
|
||||||
|
name,
|
||||||
|
fields: new_fields,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TyParam::Lambda(lambda) => {
|
||||||
|
let new_body = lambda.body.into_iter().map(|tp| tp.map_t(f)).collect();
|
||||||
|
TyParam::Lambda(TyParamLambda {
|
||||||
|
body: new_body,
|
||||||
|
..lambda
|
||||||
|
})
|
||||||
|
}
|
||||||
|
TyParam::Proj { obj, attr } => TyParam::Proj {
|
||||||
|
obj: Box::new(obj.map_t(f)),
|
||||||
|
attr,
|
||||||
|
},
|
||||||
|
TyParam::ProjCall { obj, attr, args } => {
|
||||||
|
let new_args = args.into_iter().map(|tp| tp.map_t(f)).collect::<Vec<_>>();
|
||||||
|
TyParam::ProjCall {
|
||||||
|
obj: Box::new(obj.map_t(f)),
|
||||||
|
attr,
|
||||||
|
args: new_args,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TyParam::Value(val) => TyParam::Value(val.map_t(f)),
|
||||||
|
self_ => self_,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
|
|
@ -374,7 +374,11 @@ impl GenTypeObj {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_t(&mut self, f: impl FnOnce(Type) -> Type) {
|
pub fn map_t(&mut self, f: impl FnOnce(Type) -> Type) {
|
||||||
*self.typ_mut() = f(self.typ().clone());
|
*self.typ_mut() = f(std::mem::take(self.typ_mut()));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_tp(&mut self, f: impl Fn(TyParam) -> TyParam + Copy) {
|
||||||
|
*self.typ_mut() = std::mem::take(self.typ_mut()).map_tp(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_map_t<E>(&mut self, f: impl FnOnce(Type) -> Result<Type, E>) -> Result<(), E> {
|
pub fn try_map_t<E>(&mut self, f: impl FnOnce(Type) -> Result<Type, E>) -> Result<(), E> {
|
||||||
|
@ -484,16 +488,28 @@ impl TypeObj {
|
||||||
|
|
||||||
pub fn map_t(&mut self, f: impl FnOnce(Type) -> Type) {
|
pub fn map_t(&mut self, f: impl FnOnce(Type) -> Type) {
|
||||||
match self {
|
match self {
|
||||||
TypeObj::Builtin { t, .. } => *t = f(t.clone()),
|
TypeObj::Builtin { t, .. } => *t = f(std::mem::take(t)),
|
||||||
TypeObj::Generated(t) => t.map_t(f),
|
TypeObj::Generated(t) => t.map_t(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn map_tp(&mut self, f: impl Fn(TyParam) -> TyParam + Copy) {
|
||||||
|
match self {
|
||||||
|
TypeObj::Builtin { t, .. } => *t = std::mem::take(t).map_tp(f),
|
||||||
|
TypeObj::Generated(t) => t.map_tp(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mapped_t(mut self, f: impl FnOnce(Type) -> Type) -> Self {
|
pub fn mapped_t(mut self, f: impl FnOnce(Type) -> Type) -> Self {
|
||||||
self.map_t(f);
|
self.map_t(f);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mapped_tp(mut self, f: impl Fn(TyParam) -> TyParam + Copy) -> Self {
|
||||||
|
self.map_tp(f);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn try_map_t<E>(&mut self, f: impl FnOnce(Type) -> Result<Type, E>) -> Result<(), E> {
|
pub fn try_map_t<E>(&mut self, f: impl FnOnce(Type) -> Result<Type, E>) -> Result<(), E> {
|
||||||
match self {
|
match self {
|
||||||
TypeObj::Builtin { t, .. } => {
|
TypeObj::Builtin { t, .. } => {
|
||||||
|
@ -503,6 +519,11 @@ impl TypeObj {
|
||||||
TypeObj::Generated(t) => t.try_map_t(f),
|
TypeObj::Generated(t) => t.try_map_t(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn try_mapped_t<E>(mut self, f: impl FnOnce(Type) -> Result<Type, E>) -> Result<Self, E> {
|
||||||
|
self.try_map_t(f)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 値オブジェクト
|
/// 値オブジェクト
|
||||||
|
@ -1618,29 +1639,93 @@ impl ValueObj {
|
||||||
ValueObj::Tuple(tup) => {
|
ValueObj::Tuple(tup) => {
|
||||||
ValueObj::Tuple(tup.iter().map(|v| v.clone().map_t(f)).collect())
|
ValueObj::Tuple(tup.iter().map(|v| v.clone().map_t(f)).collect())
|
||||||
}
|
}
|
||||||
ValueObj::Set(st) => ValueObj::Set(st.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(
|
ValueObj::Dict(dict) => ValueObj::Dict(
|
||||||
dict.iter()
|
dict.into_iter()
|
||||||
.map(|(k, v)| (k.clone().map_t(f), v.clone().map_t(f)))
|
.map(|(k, v)| (k.map_t(f), v.map_t(f)))
|
||||||
.collect(),
|
|
||||||
),
|
|
||||||
ValueObj::Record(rec) => ValueObj::Record(
|
|
||||||
rec.iter()
|
|
||||||
.map(|(k, v)| (k.clone(), v.clone().map_t(f)))
|
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
|
ValueObj::Record(rec) => {
|
||||||
|
ValueObj::Record(rec.into_iter().map(|(k, v)| (k, v.map_t(f))).collect())
|
||||||
|
}
|
||||||
ValueObj::DataClass { name, fields } => ValueObj::DataClass {
|
ValueObj::DataClass { name, fields } => ValueObj::DataClass {
|
||||||
name,
|
name,
|
||||||
fields: fields
|
fields: fields.into_iter().map(|(k, v)| (k, v.map_t(f))).collect(),
|
||||||
.iter()
|
|
||||||
.map(|(k, v)| (k.clone(), v.clone().map_t(f)))
|
|
||||||
.collect(),
|
|
||||||
},
|
},
|
||||||
ValueObj::UnsizedList(elem) => ValueObj::UnsizedList(Box::new(elem.clone().map_t(f))),
|
ValueObj::UnsizedList(elem) => ValueObj::UnsizedList(Box::new(elem.clone().map_t(f))),
|
||||||
self_ => self_,
|
self_ => self_,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn try_map_t<E>(self, f: &mut impl FnMut(Type) -> Result<Type, E>) -> Result<Self, E> {
|
||||||
|
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::<Result<Arc<_>, _>>()?,
|
||||||
|
)),
|
||||||
|
ValueObj::Tuple(tup) => Ok(ValueObj::Tuple(
|
||||||
|
tup.iter()
|
||||||
|
.map(|v| v.clone().try_map_t(f))
|
||||||
|
.collect::<Result<Arc<_>, _>>()?,
|
||||||
|
)),
|
||||||
|
ValueObj::Set(st) => Ok(ValueObj::Set(
|
||||||
|
st.into_iter()
|
||||||
|
.map(|v| v.try_map_t(f))
|
||||||
|
.collect::<Result<Set<_>, _>>()?,
|
||||||
|
)),
|
||||||
|
ValueObj::Dict(dict) => Ok(ValueObj::Dict(
|
||||||
|
dict.into_iter()
|
||||||
|
.map(|(k, v)| Ok((k.try_map_t(f)?, v.try_map_t(f)?)))
|
||||||
|
.collect::<Result<Dict<_, _>, _>>()?,
|
||||||
|
)),
|
||||||
|
ValueObj::Record(rec) => Ok(ValueObj::Record(
|
||||||
|
rec.into_iter()
|
||||||
|
.map(|(k, v)| Ok((k, v.try_map_t(f)?)))
|
||||||
|
.collect::<Result<Dict<_, _>, _>>()?,
|
||||||
|
)),
|
||||||
|
ValueObj::DataClass { name, fields } => Ok(ValueObj::DataClass {
|
||||||
|
name,
|
||||||
|
fields: fields
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| Ok((k, v.try_map_t(f)?)))
|
||||||
|
.collect::<Result<Dict<_, _>, _>>()?,
|
||||||
|
}),
|
||||||
|
ValueObj::UnsizedList(elem) => {
|
||||||
|
Ok(ValueObj::UnsizedList(Box::new(elem.clone().try_map_t(f)?)))
|
||||||
|
}
|
||||||
|
self_ => Ok(self_),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_tp(self, f: impl Fn(TyParam) -> TyParam + Copy) -> Self {
|
||||||
|
match self {
|
||||||
|
ValueObj::Type(obj) => ValueObj::Type(obj.mapped_tp(f)),
|
||||||
|
ValueObj::List(lis) => {
|
||||||
|
ValueObj::List(lis.iter().map(|v| v.clone().map_tp(f)).collect())
|
||||||
|
}
|
||||||
|
ValueObj::Tuple(tup) => {
|
||||||
|
ValueObj::Tuple(tup.iter().map(|v| v.clone().map_tp(f)).collect())
|
||||||
|
}
|
||||||
|
ValueObj::Set(st) => ValueObj::Set(st.into_iter().map(|v| v.map_tp(f)).collect()),
|
||||||
|
ValueObj::Dict(dict) => ValueObj::Dict(
|
||||||
|
dict.into_iter()
|
||||||
|
.map(|(k, v)| (k.map_tp(f), v.map_tp(f)))
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
ValueObj::Record(rec) => {
|
||||||
|
ValueObj::Record(rec.into_iter().map(|(k, v)| (k, v.map_tp(f))).collect())
|
||||||
|
}
|
||||||
|
ValueObj::DataClass { name, fields } => ValueObj::DataClass {
|
||||||
|
name,
|
||||||
|
fields: fields.into_iter().map(|(k, v)| (k, v.map_tp(f))).collect(),
|
||||||
|
},
|
||||||
|
ValueObj::UnsizedList(elem) => ValueObj::UnsizedList(Box::new(elem.clone().map_tp(f))),
|
||||||
|
self_ => self_,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn replace_t(self, target: &Type, to: &Type) -> Self {
|
pub fn replace_t(self, target: &Type, to: &Type) -> Self {
|
||||||
self.map_t(&mut |t| t._replace(target, to))
|
self.map_t(&mut |t| t._replace(target, to))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue