use quote::quote;
use crate::apply_tuple::map_range;
use crate::types::*;
pub(crate) fn err_ty(msg: &str) -> Ty {
Ty::Error(TyError(quote! { compile_error!(#msg); }))
}
pub(crate) trait Apply {
fn apply(self, o: Ty) -> Ty;
}
impl Apply for Ty {
fn apply(self, o: Ty) -> Ty {
match o {
Ty::Array(arr) => TyArray(
arr.0.into_iter().map(|e| self.clone().apply(e)).collect(),
)
.into(),
Ty::Group(g) => self.apply(*g.0),
Ty::WithCode(wc) => {
TyWithCode(self.apply(*wc.0).into(), wc.1).into()
},
Ty::Error(e) => e.into(),
Ty::Range(TyRange {
start,
end,
inclusive,
}) => map_range(start, end, inclusive, |n| {
self.clone().apply(TyNum(n).into())
}),
_ => match self {
Ty::Prefix(p) => p.apply(o),
Ty::Modified(m) => m.apply(o),
Ty::Unsafe(u) => u.apply(o),
Ty::Primitive(p) => p.apply(o),
Ty::Generic(g) => g.apply(o),
Ty::Trait(t) => t.apply(o),
Ty::Array(a) => a.apply(o),
Ty::Tuple(t) => t.apply(o),
Ty::Group(g) => g.apply(o),
Ty::Fn(f) => f.apply(o),
Ty::CodeBlock(b) => b.apply(o),
Ty::Attr(a) => a.apply(o),
Ty::WithAttr(w) => w.apply(o),
Ty::WithTrait(wt) => wt.apply(o),
Ty::WithType(wt) => wt.apply(o),
Ty::WithCode(wc) => wc.apply(o),
Ty::TypeParam(t) => t.apply(o),
Ty::Num(n) => n.apply(o),
Ty::Range(r) => r.apply(o),
Ty::Slice(s) => s.apply(o),
Ty::FixedArray(f) => f.apply(o),
Ty::Error(e) => e.into(),
},
}
}
}
impl Apply for TyPrefix {
fn apply(self, o: Ty) -> Ty {
match self {
TyPrefix::Ref
| TyPrefix::RefMut
| TyPrefix::PtrConst
| TyPrefix::PtrMut => TyModified(self, o.into()).into(),
TyPrefix::SelfType => o,
TyPrefix::Fn => match o {
Ty::Tuple(t) => TyFn(t.0, None).into(),
Ty::Group(t) => TyFn(vec![*t.0], None).into(),
_ => err_ty(
"batch-impl: `fn` 前缀右侧必须是元组类型,如 fn^(i32, u32)",
),
},
TyPrefix::Unsafe => TyUnsafe(o.into()).into(),
}
}
}
impl Apply for TyModified {
fn apply(self, o: Ty) -> Ty {
TyModified(self.0, self.1.apply(o).into()).into()
}
}
impl Apply for TyUnsafe {
fn apply(self, o: Ty) -> Ty {
TyUnsafe(self.0.apply(o).into()).into()
}
}
impl Apply for TyPrimitive {
fn apply(self, o: Ty) -> Ty {
match o {
Ty::TypeParam(tp) => TyGeneric(self.into(), tp).into(),
_ => TyGeneric(self.into(), TyTypeParam::single(&o)).into(),
}
}
}
impl Apply for TyGeneric {
fn apply(self, o: Ty) -> Ty {
let mut tp = self.1;
match o {
Ty::TypeParam(rhs) => tp.extend(rhs),
_ => tp.push_arg(&o),
}
TyGeneric(self.0, tp).into()
}
}
impl Apply for TyTrait {
fn apply(self, o: Ty) -> Ty {
match o {
Ty::TypeParam(rhs) => {
let mut tp = self.1;
tp.extend(rhs);
TyTrait(self.0, tp).into()
},
_ => TyWithTrait(self, o.into()).into(),
}
}
}
impl Apply for TyArray {
fn apply(self, o: Ty) -> Ty {
match o {
Ty::Array(right) => {
let mut result = vec![];
for left in self.0 {
for right_elem in &right.0 {
result
.push(left.clone().apply(right_elem.clone()));
}
}
TyArray(result).into()
},
_ => {
let result = self
.0
.into_iter()
.map(|e| e.apply(o.clone()))
.collect();
TyArray(result).into()
},
}
}
}