pub(crate) mod apply_tuple;
use quote::{quote, quote_spanned};
use crate::apply::apply_tuple::map_range;
use crate::ast::*;
use proc_macro2::Span;
pub(crate) fn err_ty(msg: &str) -> Ty {
Ty::new(
proc_macro2::Span::call_site(),
TyKind::Error(TyError(quote! { compile_error!(#msg); })),
)
}
pub(crate) fn err_ty_at(msg: &str, span: Span) -> Ty {
let ts = quote_spanned!(span => compile_error!(#msg););
Ty::new(span, TyKind::Error(TyError(ts)))
}
pub(crate) fn check_expand_limit(what: &str, len: usize) -> Option<Ty> {
(len > MAX_EXPAND).then(|| {
err_ty(&format!(
"batch-impl: `{}` expands to {} items (limit {}); likely exponential/range/Cartesian typo",
what, len, MAX_EXPAND
))
})
}
pub(crate) trait Apply: Clone + Into<TyKind> {
fn is_type_param(&self) -> bool {
false
}
fn apply(self, o: Ty, span: Span) -> Ty {
match o.kind {
TyKind::Array(arr) => {
let result: Vec<Ty> =
arr.0.into_iter().map(|e| self.clone().apply(e, span)).collect();
if let Some(e) = check_expand_limit(
"list chain expansion",
result.iter().map(count_leaves).sum(),
) {
return e;
}
Ty::new(span, TyKind::Array(TyArray(result)))
}
TyKind::Group(g) => self.apply(*g.0, span),
TyKind::WithCode(wc) => match wc.0 {
Some(inner) => Ty::new(
span,
TyKind::WithCode(TyWithCode(
Ty::new(span, self.clone().into()).apply(*inner).into(),
wc.1,
)),
),
None => Ty::new(
span,
TyKind::WithCode(TyWithCode(
Some(Box::new(Ty::new(span, self.into()))),
wc.1,
)),
),
},
TyKind::WithWhere(ww) => match ww.0 {
Some(inner) => Ty::new(
span,
TyKind::WithWhere(TyWithWhere(
Ty::new(span, self.clone().into()).apply(*inner).into(),
ww.1,
)),
),
None => Ty::new(
span,
TyKind::WithWhere(TyWithWhere(
Some(Box::new(Ty::new(span, self.into()))),
ww.1,
)),
),
},
TyKind::WithType(wt) if self.is_type_param() => {
self.apply_help(Ty::new(o.span, TyKind::WithType(wt)), span)
}
TyKind::WithType(wt) => Ty::new(
span,
TyKind::WithType(TyWithType(
wt.0,
Ty::new(span, self.clone().into()).apply(*wt.1).into(),
)),
),
TyKind::Error(e) => Ty::new(span, TyKind::Error(e)),
TyKind::Range(TyRange { start, end, inclusive }) => {
map_range(start, end, inclusive, span, |n| {
Ty::new(span, self.clone().into())
.apply(Ty::new(span, TyKind::Num(TyNum(n))))
})
}
other => self.apply_help(Ty::new(o.span, other), span),
}
}
fn apply_help(self, o: Ty, span: Span) -> Ty;
}
impl Ty {
pub(crate) fn apply(self, o: Ty) -> Ty {
let Ty { span, kind } = self;
kind.apply(o, span)
}
}
impl Apply for TyKind {
fn is_type_param(&self) -> bool {
matches!(self, TyKind::TypeParam(_))
}
fn apply_help(self, o: Ty, span: Span) -> Ty {
match self {
TyKind::WithPrefix(wp) => wp.apply_help(o, span),
TyKind::Primitive(p) => p.apply_help(o, span),
TyKind::Generic(g) => g.apply_help(o, span),
TyKind::Trait(t) => t.apply_help(o, span),
TyKind::Array(a) => a.apply_help(o, span),
TyKind::Tuple(t) => t.apply_help(o, span),
TyKind::Group(g) => g.apply_help(o, span),
TyKind::Fn(f) => f.apply_help(o, span),
TyKind::WithAttr(w) => w.apply_help(o, span),
TyKind::WithTrait(wt) => wt.apply_help(o, span),
TyKind::WithType(wt) => wt.apply_help(o, span),
TyKind::WithCode(wc) => wc.apply_help(o, span),
TyKind::WithWhere(ww) => ww.apply_help(o, span),
TyKind::TypeParam(t) => t.apply_help(o, span),
TyKind::Num(n) => n.apply_help(o, span),
TyKind::Range(r) => r.apply_help(o, span),
TyKind::PrimitiveArray(pa) => pa.apply_help(o, span),
TyKind::Error(e) => Ty::new(span, TyKind::Error(e)),
}
}
}
impl TyWithPrefix {
pub(crate) fn apply_help(self, o: Ty, span: Span) -> Ty {
match self.0 {
TyPrefix::Ref
| TyPrefix::RefMut
| TyPrefix::PtrConst
| TyPrefix::PtrMut
| TyPrefix::Unsafe => {
let inner = match self.1 {
Some(t) => t.apply(o),
None => o,
};
Ty::new(span, TyKind::WithPrefix(TyWithPrefix(self.0, inner.into())))
}
TyPrefix::SelfType => o,
}
}
}
impl TyPrimitive {
pub(crate) fn apply_help(self, o: Ty, span: Span) -> Ty {
let o_span = o.span;
match o.kind {
TyKind::TypeParam(tp) => {
Ty::new(span, TyKind::Generic(TyGeneric(self.into(), tp)))
}
_ => Ty::new(
span,
TyKind::Generic(TyGeneric(
self.into(),
TyTypeParam::single(&Ty::new(o_span, o.kind)),
)),
),
}
}
}
impl TyGeneric {
pub(crate) fn apply_help(self, o: Ty, span: Span) -> Ty {
let mut tp = self.1;
let o_span = o.span;
match o.kind {
TyKind::TypeParam(rhs) => tp.extend(rhs),
_ => tp.push_arg(&Ty::new(o_span, o.kind)),
}
Ty::new(span, TyKind::Generic(TyGeneric(self.0, tp)))
}
}
impl TyTrait {
pub(crate) fn apply_help(self, o: Ty, span: Span) -> Ty {
let o_span = o.span;
match o.kind {
TyKind::TypeParam(rhs) => {
let mut tp = self.1;
tp.extend(rhs);
Ty::new(span, TyKind::Trait(TyTrait(self.0, tp)))
}
_ => Ty::new(
span,
TyKind::WithTrait(TyWithTrait(self, Ty::new(o_span, o.kind).into())),
),
}
}
}
impl TyArray {
pub(crate) fn apply_help(self, o: Ty, span: Span) -> Ty {
let result = self.0.into_iter().map(|e| e.apply(o.clone())).collect();
Ty::new(span, TyKind::Array(TyArray(result)))
}
}