Vec<u32> and Vec<String> are different types. Or in generic terms, Vec<T> and Vec<U> are only the same type when T = U. There is also no Vec<..> type that means "a Vec<_> with any element type" in Rust (there are no higher kinded types).
Similarly, &'a SomeType and &'b SomeType are only the same type when 'a = 'b, and there is no &'.. SomeType that means "a reference with any lifetime".
Types with parameters (be they lifetimes or types) are sometimes called "type constructors". You have to specify concrete "values" (lifetimes, types) to the parameters to get an actual type.
With that in mind, this:
<ConcreteType as TraitWith<Concrete, Params>>::AssociatedTypeWithNoParams
is always a single type. You can't add parameters to the associated type as an implementor; that would make it mean something different at the type system level. So, no _name<'a>.
If AssociatedTypeWithNoParams is a type with a non-'static lifetime in it, it has to be a lifetime that's present in the implementing type or the parameters of the trait...
Only generics present in these places..... ..........can be used here
vvvvvvvvvvvv vvvvvvvv vvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvv
<ConcreteType as TraitWith<Concrete, Params>>::AssociatedTypeWithNoParams
...because the implementation is unique given the implementing type and trait with concrete parameters. If a non-'static lifetime were allowed, it would be unconstrained (would have to be pulled out of thin air), which is generally unsound.
Moreover, the borrow checker exploits the "no unconstrained parameters" property:
use std::any::Any;
// This compiles which is only possible if `Iter::Item: 'static`
fn example<Iter>(mut iter: Iter) -> Box<dyn Any + 'static>
where
Iter: Iterator + 'static,
{
Box::new(iter.next())
}
If the implementor meets a 'static bound, and all the trait parameters meet a 'static bound, than the only lifetime that is nameable in the (unparameterized) associated type is 'static -- which in turn means the associated type meets a 'static bound.
We required Iter: 'static and Iterator has no trait parameters, so the compiler (and code downstream from the implementation) can conclude and exploit <Iter as Iterator>::Item: 'static too.
So, no _name = &'non_static_lifetime_unseen_until_now SomeType.
Alternatively, we can think of it in terms of the method signature. As a reminder, the meaning of signatures like these:
fn foo(&mut self) -> &mut Vec<u32>;
// same thing
// fn foo<'s>(&'s mut self) -> &'s mut Vec<u32>
fn bar(&mut self) -> Self::GenericAssociatedType<'_>;
// same thing
fn bar<'s>(&'s mut self) -> Self::GenericAssociatedType<'s>;
is "the output is borrowing via the input", so "using the return type keeps the borrow of *self active". That's the property you would need to return some slice of Buffer::buffer on a Buffer method that took &mut self. Because without that borrowing relationship, you could for example move the Buffer without invalidating the returned reference -- but that means the reference is now dangling.
Going back to the std::iter::Iterator signature:
// No paramter on the associated type
type Item;
// So no free paramters over here
fn next<'s>(&'s mut self) -> Option<Self::Item>
There is no way for the lifetime 's to show up in the return type, which is what would be required to soundly return a reference to some field of Self. This is why you can drop an iterator without invalidating the items you got out of it. For example that's why you can collect() any iterator (which consumes the iterator but leaves you the items).
And (once you have internalized enough of the type system) you can tell this is the case from the method signature, because there's no borrowing relationship between the &mut self and the return type.
In other words, whenever you have a signature like this:
fn method(&mut self) -> Vec<u32>
// Or any other return type with no free lifetime parameters
The borrow of *self passed in to the method ends as soon as the method returns -- there is no way for the returned value to keep the borrow active, because that requires some lifetime relationship. Namely a relationship with &'_ mut self, and there's no where in the return type to put that lifetime.
In the case of traits like Iterator, that can be considered part of the trait contract which all downstream code can rely on (and thus which all implementors must adhere to).