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.