use super::*;
pub(in super)
enum Input {
TypePath(TypePath),
TypeImpl(TypeImplTrait),
Item(Item),
}
pub(in super)
fn Gat<Error : SynError> (
input: Input,
) -> ::core::result::Result<TokenStream2, Error>
{
let TypePath { qself, mut path } = {
impl Parse for Input {
fn parse (input: ParseStream<'_>)
-> Result<Input>
{
if input.peek(Token![<]).not() {
let ref fork = input.fork();
if let ty_impl @ Ok(_) = fork.parse().map(Input::TypeImpl) {
::syn::parse::discouraged::Speculative::advance_to(input, fork);
return ty_impl;
}
let ref fork = input.fork();
if let item @ Ok(_) = fork.parse().map(Input::Item) {
::syn::parse::discouraged::Speculative::advance_to(input, fork);
return item;
}
}
input.parse().map(Input::TypePath)
}
}
match input {
| Input::TypePath(it) => it,
| Input::TypeImpl(mut it) => {
handle_trait_bounds(&mut it.bounds);
return Ok(utils::mb_file_expanded(it.into_token_stream()));
},
| Input::Item(item) => return Ok(utils::mb_file_expanded(
adjugate::adjugate(parse::Nothing, item)
.into_token_stream()
)),
}
};
let qself = match qself {
| None => bail! {
"expected `<`" => path.segments.first().unwrap()
},
| Some(QSelf { as_token: None, gt_token, .. }) => bail! {
"expected `as`" => gt_token
},
| Some(it) => it,
};
let pos = qself.position;
assert!(path.segments.len() > pos);
if let Some(Pair::Punctuated(_, p)) = path.segments.pairs().nth(pos) {
bail! {
"nested associated paths are not supported" => p,
}
}
debug_assert!(path.segments.len() == pos + 1);
let mut last_segment = mem::replace(
path.segments.last_mut().unwrap(),
parse_quote!(T), );
let trait_ =
path.segments
.iter_mut()
.nth(pos.checked_sub(1).unwrap())
.unwrap()
;
let generics = match last_segment.arguments {
| PathArguments::None { .. } => bail! {
"missing lifetime generics" => last_segment.ident,
},
| PathArguments::Parenthesized { .. } => bail! {
"expected `<`" => last_segment.arguments,
},
| PathArguments::AngleBracketed(AngleBracketedGenericArguments {
ref mut args,
..
}) => {
args
},
};
last_segment.ident =
combine_trait_name_and_assoc_type(&trait_.ident, &last_segment.ident)
;
match trait_.arguments {
| PathArguments::None { .. } => {},
| PathArguments::Parenthesized { .. } => bail! {
"expected `<`" => trait_.arguments
},
| PathArguments::AngleBracketed(AngleBracketedGenericArguments {
ref mut args,
..
}) => {
generics.extend(mem::take(args));
},
}
*trait_ = last_segment;
Ok(TypePath { qself: Some(qself), path }.into_token_stream())
}
type TraitBounds = Punctuated<TypeParamBound, Token![+]>;
pub(in crate)
fn handle_trait_bounds (
trait_bounds: &mut TraitBounds,
)
{
let mut extra_bounds = vec![];
trait_bounds
.iter_mut()
.filter_map(|it| match it {
| TypeParamBound::Trait(trait_bound) => Some(trait_bound),
| _ => None,
})
.for_each(|trait_bound| {
let Trait @ _ = trait_bound.path.segments.last_mut().unwrap();
let generics = match Trait.arguments {
| PathArguments::AngleBracketed(ref mut it) => it,
| _ => return,
};
let mut to_drain = vec![];
let mut bindings = vec![];
struct GatBinding {
ident: Ident,
lifetimes: Punctuated<Lifetime, Token![,]>,
eq_token: Token![=],
ty: Type,
}
generics.args.iter().enumerate().for_each(|(i, arg)| match arg {
| GenericArgument::Type(Type::Verbatim(tokens)) => {
impl Parse for GatBinding {
fn parse (input: ParseStream<'_>)
-> Result<GatBinding>
{
Ok(GatBinding {
ident: input.parse()?,
lifetimes: {
let _: Token![<] = input.parse()?;
let mut it = Punctuated::new();
while let Some(lt) = input.parse()? {
it.push_value(lt);
if let Some(p) = input.parse()? {
it.push_punct(p);
} else {
break;
}
}
let _: Token![>] = input.parse()?;
it
},
eq_token: input.parse()?,
ty: input.parse()?,
})
}
}
if let Ok(binding) = parse2::<GatBinding>(tokens.clone()) {
to_drain.push(i);
bindings.push(binding);
}
},
| _ => {},
});
if to_drain.is_empty().not() {
generics.args =
mem::take(&mut generics.args)
.into_iter()
.enumerate()
.filter_map(|(i, arg)| {
to_drain.contains(&i).not().then(|| arg)
})
.collect()
;
for GatBinding {
ident: Assoc @ _,
lifetimes: gat_lifetimes,
eq_token: eq_,
ty,
}
in bindings
{
let generics =
match trait_bound
.path
.segments
.last()
.unwrap()
.arguments
{
| PathArguments::AngleBracketed(ref it) => it,
| _ => return,
}
;
let each_generic_lt =
generics.args.iter().filter(|it| matches!(it,
GenericArgument::Lifetime { .. }
))
;
let each_generic_ty_or_const =
generics.args.iter().filter(|it| matches!(it,
GenericArgument::Type { .. } |
GenericArgument::Const { .. }
))
;
let mut trait_bound = trait_bound.clone();
let last_segment = trait_bound.path.segments.last_mut().unwrap();
let Trait_Assoc = combine_trait_name_and_assoc_type(
&last_segment.ident,
&Assoc,
);
*last_segment = parse_quote!(
#Trait_Assoc<
#(#each_generic_lt ,)*
#gat_lifetimes,
#(#each_generic_ty_or_const ,)*
T #eq_ #ty,
>
);
extra_bounds.push(trait_bound);
}
}
})
;
trait_bounds.extend(
extra_bounds.into_iter().map(TypeParamBound::Trait)
);
}
pub(in super)
trait SynError : Sized {
fn new (_: Span, _: &str)
-> Self
;
fn new_spanned (_: &dyn ToTokens, _: &str)
-> Self
;
}
impl SynError for () {
fn new (_: Span, _: &str)
{}
fn new_spanned (_: &dyn ToTokens, _: &str)
{}
}
impl SynError for ::syn::Error {
fn new (s: Span, m: &str)
-> Self
{
Self::new(s, m)
}
fn new_spanned (s: &dyn ToTokens, m: &str)
-> Self
{
Self::new_spanned(s, m)
}
}