Union types, and the ones that still cannot be expressed

A method returning either a Product or an Error had no signature that said so, and the docblock describing it was checked by a static analyser and by nothing at runtime.

public function find(int $id): Product|NotFound
{
    // ...
}

// what is still not expressible in 8.0:
//   intersection types            (8.1)
//   an alias for a repeated union (never)
//   generics of any kind          (never)
//   array{sku: string, qty: int}  (docblock only, forever)

The redundant-type rule is stricter than people expect: int|int is a compile error, and so is a union containing a class and its own parent, because one is redundant. That catches genuine mistakes and occasionally rejects something written deliberately for documentation. false is allowed as a member and true is not until 8.2, which is an asymmetry with a history rather than a reason.