Repository navigation
Infer literal types for word date format characters - #6838
Conversation
The `a`, `A`, `S`, `D`, `l`, `M`, and `F` format characters of `date()`,
`date_format()`, and `DateTimeInterface::format()` now produce unions of
their possible values, like the numeric single-character formats already do.
PHP formats these characters from hard-coded English tables, so the values
do not depend on the locale.
The final `union()` with `non-empty-string` in `getTypeFromFormatType()` is
removed, since it would otherwise widen these literal unions (and any other
non-numeric constant result, such as `date(' ')`) to `non-empty-string`.
A non-empty format yielding a non-empty result is already guaranteed: a
non-constant format is handled by the `non-empty-string` branch above, and
every type built for a constant non-empty format is itself non-empty.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The "S" date format returns English ordinal suffixes, and typos reports the "nd" string literal as a misspelling of "and". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
This pull request has been marked as ready for review. |
|
//cc @SanderMuller |
Co-authored-by: Markus Staab <maggus.staab@googlemail.com>
SanderMuller
left a comment
There was a problem hiding this comment.
Looks good to me. I checked it on 6bf825f.
- The seven unions match what PHP returns. I collected every
date()andformat()value fora A S D l M F, hourly over two years plus years 1 and 9999. The sets are the same under the C, fr_FR, de_DE and ja_JP locales, on PHP 7.4 and 8.5. bug-15537.phpanddate-format.phpfail with the base helper and pass with this one.- Removing the
non-empty-stringwidening only makes types narrower. With the base helper,date(' ')anddate($b ? ' ' : '-')givenon-empty-string. With this branch they give' 'and' '|'-'. A non-empty non-constant format still givesnon-empty-string, andY,d,uand0give the same types as before. make tests,make phpstanand phpcs pass. The class is not shadowed by Turbo.- nextras/orm also fails on #6861 with the same two Nette DI errors, so it is not from this PR.
Performance: I timed a synthetic file with 200 functions and 4000 date format calls, 10 interleaved rounds, user CPU medians. When the calls are only evaluated, the analysis takes 2.07 s instead of 2.02 s. When the results are concatenated, it takes 2.53 s instead of 2.24 s. Most of that is the concat of the new unions, which already happens today for small numeric unions such as date('L') . date('N'). A real-world codebase of about 35000 files has 62 calls with these format characters, so I expect no measurable difference in practice.
|
-> found a way arround it after that we are ready to go |
|
thank you! |
The
a,A,S,D,l,M, andFformat characters ofdate(),date_format(), andDateTimeInterface::format()now produce unions of their possible values, alongside the numeric single-character formats added in #721. PHP formats these characters from hard-coded English tables inext/date/php_date.c, so the values do not depend on the locale.a'am'|'pm'A'AM'|'PM'S'nd'|'rd'|'st'|'th'D'Fri'|'Mon'|'Sat'|'Sun'|'Thu'|'Tue'|'Wed'l'Friday'|'Monday'|'Saturday'|'Sunday'|'Thursday'|'Tuesday'|'Wednesday'M'Apr'|'Aug'|'Dec'|'Feb'|'Jan'|'Jul'|'Jun'|'Mar'|'May'|'Nov'|'Oct'|'Sep'F'April'|'August'|'December'|'February'|'January'|'July'|'June'|'March'|'May'|'November'|'October'|'September'Removal of the
non-empty-stringwideningAdding the cases alone is not enough:
getTypeFromFormatType()ended withwhich widens any non-numeric constant result to
non-empty-string, so the new unions came out asnon-empty-string. The same happens today for formats without format characters, e.g.date(' ')isnon-empty-stringrather than' '.This block was added in #2888 for phpstan/phpstan#10468 (a non-empty format should give a non-empty result). That guarantee does not depend on it:
count($types) === 0branch, which already returnsnon-empty-stringfor anon-empty-stringformat.buildReturnTypeFromFormat()returns is already non-empty: the explicit cases,ConstantStringType($date),numeric-string, andnon-falsy-string.So the block is removed rather than worked around. The
bug-10468.phpandbug-6613.phptests still pass.Tests
nsrt/bug-15537.phpis the reproducer from the issue. It fails before this change (non-falsy-stringfor every assertion) and passes after.nsrt/date-format.phpexpectednon-falsy-stringforD; it now expects the weekday union.Closes phpstan/phpstan#15537
🤖 Generated with Claude Code