Hi Rob, > Tested on your PR branch [...] But the entry-side check accepts the string, contradicting the same sentence's claim that those checks read substituted parameter types.
Good find. That's a bug in the implementation. I'll fix it before the RFC moves to voting. > I'm a bit confused. In your earlier email you said that tools currently can't converge on simple generics correctness [...] but say that this will force them to converge. The convergence claim is about what happens once the language defines a specific semantics, not about tools agreeing on their own. Today, tools disagree because each tool must invent a semantics for docblock generics, and the invented semantics differ. Once PHP defines the diamond-merge rule (or any other semantic the engine enforces), tools have a single specification to conform to. The convergence isn't "tools deciding to agree"; it's "tools matching the language's behavior, the same way they match the language's behavior for scalar types, union types, intersection types, and every other type-system feature that shipped through this same process." The Mago bug is evidence for the convergence claim, not against it. The bug exists because there was no authoritative specification for the behavior; Mago, PHPStan, and Psalm each made different choices. Under the RFC, there is one specification (link-time diamond merge produces the parameter-union, return-intersection signature), and tools will conform to it because the language enforces it. > Box<A&B>'s internal value flow is observationally identical to Box<A|B>'s, or Box<mixed>'s -- all accept and produce values satisfying the bound. The static subtyping relationship is real and enforced at link-time parametric LSP. It's invisible at runtime. Correct, and this is the trade bound erasure makes. The engine enforces the bound; the parametric refinement is enforced at the SA layer. It's the same trade-off already in effect for every `@template` annotation in production PHP code today: the engine doesn't enforce the parametric relationship, the SA tools do. > What I don't see addressed anywhere is the new-user case: a developer who's never seen generics encounters <T> in production code, writes their own, runs it, gets no runtime feedback when their value-level intuition diverges from the underlying expectations without using a tool. For genuinely new developers, the path is the same as for every other feature: documentation explains what generics do, the same way it explains classes, inheritance, functions, types, and so on. Someone new won't be familiar with every single feature of PHP *except* generics. Either: 1. They know OOP in general: meaning they have already encountered generics in Java, Scala, Kotlin, C#, or a similar language (which uses type erasure). 2. They're genuinely new to programming; generics are no harder than any other feature they'll need to learn from documentation. > 200k files is a drop in the bucket when you've worked on PHP repos spanning millions of files. I've worked on multi-million-line PHP codebases that used `@template` (or native erased generics in HackLang) extensively and strictly. The number is a lower bound from public GitHub search, not a ceiling. Add private codebases at Slack, Quizlet, Vimeo, and 100s of major companies running PHP at scale, and the count grows significantly. The 200k figure is evidence of widespread adoption, not the totality of it. Cheers, Seifeddine.
