Gat!() { /* proc-macro */ }
Expand description
Refer to a <Type as Trait>::Assoc<…>
type.
Or express Trait<Assoc<…> = …>
constraints.
Indeed, the GATs defined by #[gat]
, when outside of a
#[gat]
-annotated item (or a
#[apply(Gat!)]
-annotated one), cannot be accessed through
the expected <Type as Trait>::Assoc<…>
path directly.
In order to work around that limitation, wrapping such paths inside
invocations to this very Gat!
macro will avoid the issue:
Examples
#[macro_use]
extern crate nougat;
#[gat]
trait LendingIterator {
type Item<'next>
where
Self : 'next,
;
fn next(&mut self)
-> Option<Self::Item<'_>>
;
}
fn first_item<I : LendingIterator> (
iter: &'_ mut I,
) -> Option< Gat!(<I as LendingIterator>::Item<'_>) >
{
iter.next()
}
But if you need to annotate a bunch of types like that within the same item
(e.g., function, (inline) module), you can, instead, directly
#[apply(Gat!)]
to that item to automagically get
Gat!
applied to each and every such type occurrence:
#[macro_use]
extern crate nougat;
#[gat]
trait LendingIterator {
type Item<'next>
where
Self : 'next,
;
fn next(&mut self)
-> Option<Self::Item<'_>>
;
}
#[apply(Gat!)]
fn first_item<I : LendingIterator> (
iter: &'_ mut I,
) -> Option< <I as LendingIterator>::Item<'_> >
{
iter.next()
}
Tip: use type aliases!
Granted, the usage of Gat!
may make some signature more heavyweight,
but the truth is that <Type as Trait>::Assoc<…>
, even without a Gat!
macro around it, is already quite a mouthful.
And as with any “mouthful type”, the trick is to factor out common patterns with a (generic) type alias.
So it is heavily advisable that GAT-using library authors quickly get in the habit of defining and using them:
type Item<'lt, I /* : LendingIterator */> = Gat!(<I as LendingIterator>::Item<'lt>);
-
#[macro_use] extern crate nougat; #[gat] trait LendingIterator { type Item<'next> where Self : 'next, ; fn next(&mut self) -> Option<Self::Item<'_>>; } type Item<'lt, I> = Gat!(<I as LendingIterator>::Item<'lt>); // Look ma, no macros! fn first_item<I: LendingIterator>(iter: &mut I) -> Option<Item<'_, I>> { iter.next() }
Remarks
Neither Trait::Assoc<…>
nor Type::Assoc<…>
paths will work, even when
the compiler would have enough information to figure out that we are talking
of <Type as Trait>
, since macros, such as this one, don’t have access to
that compiler resolution information, only to syntactical paths.
The only hard-coded exception to this rule is when inside a
#[gat]
trait definition or implementation: there, not only
is Gat!
automagically applied where applicable, the Self::Assoc<…>
types
also become <Self as Trait>::Assoc<…>
.