[T] is called a slice - a dynamically sized type (DST). The T can be anything - it doesn’t have to be a trait. A [u8] is byte slice, for example.
Your list of unsized vs sized types above is correct.
Usually you write trait Foo: Sized if you’re relying the size of any implementing type to be known at compile time (the very definition of being Sized). So a method taking self can only be called if the type is Sized. Likewise, a method taking Self as a parameter has the same restriction - you must know its size statically (compile time) to pass it on the stack.
These days you don’t see Sized as a requirement on the trait as much. Instead, methods that need a Sized requirement are bound to require Sized but the rest of the trait isn’t. For example:
trait Foo {
fn dont_need_sized(&self);
fn need_sized(self) -> Self where Self: Sized;
}
Foo is object safe but need_sized won’t be available to call on a trait object of that type.
There are several restrictions for a trait to be object safe - not using Self is but one of them. When you create a trait object, the underlying type is erased. So a method taking Self is invalid because by definition we don’t know that type anymore - all we know is it implements the trait but not its exact type (which is what Self is).
Bar itself becomes an unsized type (a DST). You don’t see these often. They’re valid to define but harder to actually use.
The latter is trying to put an unsized lvalue (named binding) on the stack - can’t be done because compiler doesn’t know how much space it occupies. So if you tried to do the same thing with Bar you’d get a compiler error for the same reason.
I can get into more details on any of these but cutting here as I’m on mobile
. Feel free to ask more questions.