Hi all, Thanks Seifeddine for putting this together. This is an impressive piece of work, and the general approach is sound to me. Looking forward to where this discussion lands; I hope we'll reach enough consensus to merge.
Le ven. 15 mai 2026 à 13:13, Rowan Tommins [IMSoP] <[email protected]> a écrit : > On 15 May 2026 00:32:05 BST, Seifeddine Gmati <[email protected]> > wrote: > > >Generic type information currently lives in optional levels because it > >lives in optional syntax (docblocks). > > > This is, quite frankly, nonsense. > > If you write a function with no native type information, but an "@return > int" docblock, PHPStan will report an error for a missing return statement > at Level 0, and for an incorrect return statement on Level 3. > > There's no relationship between the syntax needed and the types of > analysis performed. > > > > That's the point: native syntax means the language > >did the work, and tools surface violations at whatever strictness the > >user already has configured. > > > As Daniil pointed out, SA tools analyse code with offline parsers, not by > loading and reflecting it; so the native enforcement of arity etc will > still need to be reimplemented in each tool. > > The RFC will act as a standardisation of what tools *should* enforce > around those things; but that could equally be done by agreeing a set of > conformance tests based on the existing docblock syntax. In fact, those > conformance tests would be needed whatever the syntax, if the goal is to > eliminate different handling in different tools. > > > >The actual situation is that PHP has a runtime-checked layer (what the > >engine validates) and an SA-checked layer (what tools verify). The two > >layers complement each other. Native generics formalize a part of the > >SA-checked layer that the engine can partially absorb. > > > I can agree with this framing. I think where we differ is that you see > unifying those layers in one syntax as a good thing, but I see it as a bad > thing: I think it is useful to be able to look at the code, and understand > which parts are definitely going to be enforced by the runtime-checked > layer. > I'd like to put a syntax proposal on the table that may address Rowan's concern, and that also addresses something I'm worried about independently: the migration path for existing libraries. How does a library that uses @template docblocks today migrate to native syntax without forcing a BC break on its consumers? Multiplied across the libraries out there, this is a major point of tension for the ecosystem we need to anticipate. Existing @template annotations were adoptable gradually *because* they're invisible to the engine. Native <T> syntax, as the RFC proposes it, doesn't have that property: a library cannot adopt it without bumping its minimum PHP version and pulling all its consumers with it. We've solved this exact problem once before for attributes. The #[...] syntax was deliberately designed so older PHP versions would parse it as a # line comment, which is what made the adoption across the ecosystem so smooth. The same trick is available for generics if we pick the right delimiter. Concretely, write #<...> everywhere <...> appears in the current RFC: declarations, inheritance clauses, type uses in signatures, call-site arguments. One syntax, used uniformly. Three benefits, beyond the migration story: 1. FC for free. A library can adopt native generics in source today and continue running on older PHP versions, because the engine just sees comments. No need to coordinate with the min-PHP bump. 2. The turbofish goes away. No need to disambiguate < from less-than comparison. With #<...>, the token is unique and unambiguous everywhere: at declaration, use, and call site. We get to drop a whole grammar mechanism rather than introduce one. 3. Rowan's concern is addressed typographically. Anything inside #<...> is the erased, SA-enforced layer; everything outside follows the engine's normal runtime-checked rules. For codebases that want to adopt native generics while still supporting earlier PHP versions, #<...> would need to sit at the end of a line so older parsers consume it as a # line comment. Code targeting only generics-aware PHP can write it inline. The line-break constraint is a transitional code-style cost, not a permanent property of the syntax, and it's bounded by however long libraries support pre-generics versions. WDYT? I expect Seifeddine has good reasons to prefer the current syntax. I'd like to put this on the table because the FC story it unlocks, combined with the turbofish simplification, might be worth the trade-off and might help gather a broader consensus. Cheers, Nicolas
