Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
222 commits
Select commit Hold shift + click to select a range
5d04c86
feat(diagnostics): add Diagnostic value-object model for the check gate
math3usmartins Jun 17, 2026
b9e1173
feat(check): collect generic bound violations via an optional diagnos…
math3usmartins Jun 17, 2026
598a3fb
feat(check): add a validate-only pass that collects generic errors
math3usmartins Jun 17, 2026
6f86e03
refactor(check): move variance-position validation to a collectable p…
math3usmartins Jun 17, 2026
90450e8
refactor(check): make inner-variance composition collectable
math3usmartins Jun 17, 2026
c4e6815
refactor(check): run variance-position before defaults; tidy docblocks
math3usmartins Jun 17, 2026
7e85687
feat(check): add Text, JSON, and GitHub diagnostic renderers
math3usmartins Jun 17, 2026
b077a4c
test(check): pin GitHub renderer percent/carriage-return escaping
math3usmartins Jun 17, 2026
3034f64
feat(check): add the `xphp check` command with per-file parse resilience
math3usmartins Jun 17, 2026
21f855b
refactor(check): read source files outside the parse try/catch
math3usmartins Jun 17, 2026
d552742
docs: document the `xphp check` diagnostics gate
math3usmartins Jun 17, 2026
c34b0a1
docs: clarify that `xphp check` is not yet a substitute for `xphp com…
math3usmartins Jun 18, 2026
078f9d9
feat(check): collect method/function/closure-level generic errors
math3usmartins Jun 18, 2026
1892b73
test(check): cover the static-closure collect path; document new codes
math3usmartins Jun 18, 2026
d008c05
build(phpstan): raise analysis to level 9 and fix the surfaced findings
math3usmartins Jun 18, 2026
984c2fd
ci: self-test the `xphp check` gate end-to-end (+ PHAR smoke)
math3usmartins Jun 18, 2026
dfc79c0
feat(check): foundations for running PHPStan over compiled output
math3usmartins Jun 18, 2026
8e27841
feat(check): run PHPStan over representative specializations and pars…
math3usmartins Jun 18, 2026
cd721d4
feat(check): map PHPStan findings to .xphp and wire the pass into `ch…
math3usmartins Jun 18, 2026
b85392a
test(check): group the PHPStan-pass tests and split them out of test/…
math3usmartins Jun 18, 2026
8a8e24e
docs(check): document the PHPStan pass; add CI job + changelog
math3usmartins Jun 18, 2026
ed4b1c7
feat(check): machinery to detect undeclared type parameters (no-op)
math3usmartins Jun 18, 2026
1bba5b5
feat(check): flag undeclared type parameters in generic members
math3usmartins Jun 18, 2026
1a9fc6d
feat(check): extend undeclared-type detection to method-level generics
math3usmartins Jun 18, 2026
dbb4dda
feat(check): flag undeclared names in generic bounds and defaults
math3usmartins Jun 18, 2026
82a5f78
feat(check): report too many type arguments instead of silently trunc…
math3usmartins Jun 18, 2026
cc41010
fix(check): don't flag a scalar bound as an undeclared type
math3usmartins Jun 18, 2026
5bae46d
docs(changelog): record the undeclared-type and too-many-args checks
math3usmartins Jun 18, 2026
68f1911
docs: add Architecture Decision Records
math3usmartins Jun 18, 2026
263dd2d
docs(adr): correct ADR-0005 — unknown bounds are rejected, not deferred
math3usmartins Jun 18, 2026
0c6b640
docs(adr): correct three records to match the code
math3usmartins Jun 18, 2026
c5b7aba
docs: correct public docs against the code (check/PHPStan shipped, pi…
math3usmartins Jun 18, 2026
e9a3ed7
docs: correct the static-closure rejection rationale in caveats
math3usmartins Jun 18, 2026
7f8be38
feat(monomorphize): resolve generic instance methods through inheritance
math3usmartins Jun 18, 2026
747592c
feat(monomorphize): error on unresolved generic-method turbofish calls
math3usmartins Jun 18, 2026
094b6ef
feat(monomorphize): resolve static + nullsafe generic methods through…
math3usmartins Jun 18, 2026
f9dfc7a
docs: document generic-method resolution through inheritance
math3usmartins Jun 18, 2026
a9cafea
docs(roadmap): record deferred generic-completeness gaps
math3usmartins Jun 19, 2026
7513764
feat(monomorphize): allow a type-parameter-typed constructor on a var…
math3usmartins Jun 19, 2026
e43ae2b
docs(variance): make method-level variance a documented permanent bou…
math3usmartins Jun 19, 2026
0b74eb6
feat(check): recognize a `Hashable` value-equality bound
math3usmartins Jun 19, 2026
f09e2c3
docs: document covariant typed-construction + Hashable bound; changelog
math3usmartins Jun 19, 2026
d231faf
docs(adr): record variance-erased constructors and the class-level-va…
math3usmartins Jun 19, 2026
95833b6
chore: scrub internal ticket references from tracked comments
math3usmartins Jun 21, 2026
907f106
feat(monomorphize)!: emit real types for variant constructor params (…
math3usmartins Jun 21, 2026
117ca30
docs: variant constructor params are real-typed, not erased
math3usmartins Jun 21, 2026
6a6c211
test(monomorphize): move constructor-variance tests to fixtures
math3usmartins Jun 21, 2026
87e8db6
test,docs: rename ctor -> constructor and Contra -> ContraVariance
math3usmartins Jun 21, 2026
963aa42
refactor: expand ad-hoc abbreviations project-wide
math3usmartins Jun 21, 2026
c1c8b3e
docs: correct VariancePositionValidator docblock for real-typed const…
math3usmartins Jun 21, 2026
9d310db
feat(monomorphize): treat by-reference parameters as an invariant pos…
math3usmartins Jun 21, 2026
7c7a133
feat(monomorphize)!: reject `final` on a variant class instead of str…
math3usmartins Jun 21, 2026
631d466
docs: fix variance covariant example + roadmap position summary
math3usmartins Jun 21, 2026
876db57
docs: add caveat for covariant getters tripping the PHPStan pass
math3usmartins Jun 21, 2026
c8919ef
feat(variance): allow variance markers on private properties
math3usmartins Jun 21, 2026
a506e50
docs(variance): document private-property variance + PHPStan-clean test
math3usmartins Jun 21, 2026
7d1ee6b
docs(variance): correct the array-backed PHPStan caveat to match real…
math3usmartins Jun 21, 2026
d4150eb
docs(roadmap): list the shipped `Hashable` value-equality bound
math3usmartins Jun 21, 2026
0c989ca
feat(bounds): namespace the value-equality bound as `XPHP\Hashable`
math3usmartins Jun 21, 2026
d257a49
refactor(bounds): drop the special-cased value-equality bound
math3usmartins Jun 21, 2026
ad05245
docs(adr): consolidate the value-equality ADRs and fix forward-refere…
math3usmartins Jun 21, 2026
aad2b7e
feat(check): warn when a variant template's element type isn't in the…
math3usmartins Jun 21, 2026
1186f80
feat(compile): make the emit path root-aware for multi-root builds
math3usmartins Jun 22, 2026
ad62c0f
feat(config): add xphp.json manifest parser
math3usmartins Jun 22, 2026
dc2bb21
feat(config): resolve xphp.json manifests into a multi-root source set
math3usmartins Jun 22, 2026
db324f7
feat(cli): resolve compile/check sources from an xphp.json manifest
math3usmartins Jun 22, 2026
9ac12e8
docs: document the xphp.json manifest + record ADR-0017
math3usmartins Jun 22, 2026
5ee437d
feat(config): support `**` globstar for recursive include discovery
math3usmartins Jun 22, 2026
f326d87
docs: recommend the xphp.json manifest as the default project setup
math3usmartins Jun 22, 2026
a7eb060
feat(monomorphize): add Registry::substituteBound to ground bound typ…
math3usmartins Jun 22, 2026
3bf3894
feat(monomorphize): thread receiver type args through the supertype c…
math3usmartins Jun 22, 2026
bed2336
feat(monomorphize): ground a method-generic bound on an enclosing typ…
math3usmartins Jun 22, 2026
d4c7f71
test(monomorphize): pin the enclosing-param bound grounding limitations
math3usmartins Jun 23, 2026
56352a5
docs(adr): use the Fruit/Banana/Rock example vocabulary consistently
math3usmartins Jun 23, 2026
93ece6a
docs: use \Stringable instead of an invented "Named" marker in the co…
math3usmartins Jun 23, 2026
950eb1e
fix(monomorphize): check a class bound that references a sibling type…
math3usmartins Jun 23, 2026
d20cc7a
feat(monomorphize): ground a branch-merged receiver when every arm ag…
math3usmartins Jun 23, 2026
56069a7
feat(monomorphize): ground a receiver whose type comes from a method …
math3usmartins Jun 23, 2026
f0f59a7
feat(monomorphize): fail a method-generic bound that can't be proven
math3usmartins Jun 24, 2026
a822bce
feat(monomorphize): fail a turbofish call on an undeterminable receiver
math3usmartins Jun 24, 2026
c04b03e
docs: record ground-or-fail for enclosing-parameter method bounds
math3usmartins Jun 24, 2026
f11a15d
docs: catalog the two ground-or-fail diagnostics with sample code
math3usmartins Jun 24, 2026
5853249
docs: correct the forwarding "workaround" for an enclosing-bound self…
math3usmartins Jun 24, 2026
b378367
feat(monomorphize): fail a self-call that forwards a type parameter
math3usmartins Jun 24, 2026
371e31e
feat(monomorphize): detect when a method-generic bound can be erased …
math3usmartins Jun 24, 2026
4d41bc6
feat(monomorphize): lower a direct-input enclosing-bounded method by …
math3usmartins Jun 24, 2026
9252086
docs: forwarding an enclosing-bounded parameter now compiles and runs
math3usmartins Jun 24, 2026
d93d64b
docs: document the unspecializable-self-call diagnostic and erasure l…
math3usmartins Jun 24, 2026
85c9a25
test(monomorphize): runtime gates for multi-class-param and param-wid…
math3usmartins Jun 24, 2026
9dea3fc
test(monomorphize): runtime gate for a two-bounded-param erasable method
math3usmartins Jun 24, 2026
26525a8
refactor(monomorphize): gate erasable-method retention without a cont…
math3usmartins Jun 24, 2026
886f8f4
docs: bring the ADR and roadmap current with the erasure lowering
math3usmartins Jun 24, 2026
87df3ae
fix(monomorphize): keep a specialization's source parent when emittin…
math3usmartins Jun 24, 2026
e765009
refactor(monomorphize): extract the variance-subtype decision into a …
math3usmartins Jun 24, 2026
a609565
feat(monomorphize): schedule the implementer for a covariant upcast t…
math3usmartins Jun 24, 2026
5344daf
docs(monomorphize): document the covariant-interface element-method u…
math3usmartins Jun 24, 2026
4457656
docs(changelog): assemble the 0.3.0 section and backfill 0.2.1
math3usmartins Jun 24, 2026
df3bad9
fix(monomorphize): report a turbofish-less method-generic call instea…
math3usmartins Jun 25, 2026
24b5041
fix(monomorphize): report a turbofish-less generic free-function call
math3usmartins Jun 25, 2026
ad655c6
fix(monomorphize): report a turbofish-less generic closure call
math3usmartins Jun 25, 2026
b2b30f7
docs(monomorphize): document that a turbofish-less generic call is an…
math3usmartins Jun 25, 2026
9cce945
fix(monomorphize): close three edge cases in turbofish-less call dete…
math3usmartins Jun 25, 2026
37a743b
docs(changelog): record the turbofish-less generic-call diagnostic
math3usmartins Jun 25, 2026
946afb8
fix(monomorphize): include closure-template maps in the scope-snapsho…
math3usmartins Jun 25, 2026
555af5d
feat(monomorphize): emit an erased upcast member directly when inheri…
math3usmartins Jun 25, 2026
43c3601
fix(monomorphize): reject direct emission when the enclosing paramete…
math3usmartins Jun 25, 2026
29a5000
docs: document direct emission of a covariant-upcast member; ADR for …
math3usmartins Jun 25, 2026
54b3086
docs(adr): show the alias and insteadof cases that make full trait mo…
math3usmartins Jun 26, 2026
775bbbf
fix(monomorphize): emit the covariant edge for a cross-template gener…
math3usmartins Jun 26, 2026
b02bd5d
docs: document variance composing through a nested generic type-argument
math3usmartins Jun 26, 2026
e67b524
fix(monomorphize): compose variance through type-constructor args via…
math3usmartins Jun 26, 2026
b414970
fix(monomorphize): don't double-report a visible promoted constructor…
math3usmartins Jun 26, 2026
2311046
docs: document a covariant class consuming a contravariant generic
math3usmartins Jun 26, 2026
60decad
feat(monomorphize): localize the non-convergent-specialization diagno…
math3usmartins Jun 26, 2026
13050fd
docs: propose erased seams to break self-reintroducing specialization
math3usmartins Jun 29, 2026
8b6b936
test: characterize the self-reintroducing grouping boundary
math3usmartins Jun 29, 2026
61b86b0
docs: cite prior art for the erased seam and fix a stray fence
math3usmartins Jun 29, 2026
999312e
docs: accept diagnose-and-restructure for self-reintroducing speciali…
math3usmartins Jun 29, 2026
d974a51
feat(monomorphize): name every cycle class and its source file when s…
math3usmartins Jun 29, 2026
128fb64
test(monomorphize): assert the whole divergence message instead of su…
math3usmartins Jun 29, 2026
dfe9c4f
test(monomorphize): pin the exact incompatible value-list specs in th…
math3usmartins Jun 29, 2026
1a6c1fa
test(monomorphize): document why the load fatal is asserted by parts
math3usmartins Jun 29, 2026
75f3d3a
docs: document the workaround for self-reintroducing specialization
math3usmartins Jun 29, 2026
7ae3ed4
test+docs: adapt the self-reintroducing-tower characterization to eag…
math3usmartins Jun 29, 2026
e87c87d
fix(monomorphize): supply erased members across a covariant nested-ge…
math3usmartins Jun 30, 2026
91e7612
fix(monomorphize): recognize scalar type names in a generic bound leaf
math3usmartins Jun 30, 2026
3b6f8d1
fix(monomorphize): resolve scalar-aliased class names as classes in e…
math3usmartins Jun 30, 2026
b05ea8c
feat(cli): run the validation gate by default on compile
math3usmartins Jun 30, 2026
ba8e706
Merge pull request #21 from xphp-lang/feat/safe-default-compile-gate
math3usmartins Jul 5, 2026
3c9a03e
feat(variance)!: adopt Kotlin-style `out`/`in` variance markers
math3usmartins Jul 6, 2026
bf628d0
fix(variance): render diagnostics with `out`/`in` markers
math3usmartins Jul 6, 2026
29e352e
docs(variance): document `out`/`in` variance markers
math3usmartins Jul 6, 2026
4a371db
Merge pull request #22 from xphp-lang/feat/kotlin-variance-markers
math3usmartins Jul 6, 2026
2478842
feat(closure-sig): add closure-signature type representation
math3usmartins Jul 6, 2026
e957237
feat(closure-sig): parse and erase closure signature types
math3usmartins Jul 6, 2026
ed68b37
fix(closure-sig): recognize keyword types, length-preserve erasure, b…
math3usmartins Jul 6, 2026
7ed23ce
feat(closure-sig): add closure-signature conformance engine
math3usmartins Jul 6, 2026
d0d3a1c
feat(closure-sig): extract a closure literal's declared signature
math3usmartins Jul 6, 2026
ea4840d
feat(monomorphize): gate closure-literal factories against their Clos…
math3usmartins Jul 6, 2026
dc7e71f
feat(monomorphize): re-check closure factories after grounding their …
math3usmartins Jul 6, 2026
8f9e695
fix(monomorphize): accept a closure factory whose return targets a bu…
math3usmartins Jul 6, 2026
2febcea
docs: document Closure(...) signature types and conformance checking
math3usmartins Jul 6, 2026
1b57397
feat(monomorphize): variance-check union and intersection members in …
math3usmartins Jul 6, 2026
4618b75
feat(monomorphize): structure a closure literal's union/intersection/…
math3usmartins Jul 6, 2026
cb773f1
feat(monomorphize): structure flat union/intersection/nullable in tar…
math3usmartins Jul 6, 2026
f16f4e3
feat(monomorphize): ground type parameters inside union/intersection …
math3usmartins Jul 6, 2026
0158e40
test(monomorphize): pin the sub-intersection gradual-accept paths aga…
math3usmartins Jul 6, 2026
bde729f
docs: document union, intersection, and nullable members in Closure(.…
math3usmartins Jul 6, 2026
5e8a10e
docs: sharpen closure-signature DNF limitation and a code comment
math3usmartins Jul 6, 2026
af058e6
fix(monomorphize): map anonymous template markers through the byte-of…
math3usmartins Jul 6, 2026
157c992
docs(changelog): record the generic-closure marker offset fix
math3usmartins Jul 6, 2026
e67cf4b
fix(monomorphize): scan parenthesised DNF groups as single signature …
math3usmartins Jul 6, 2026
9d5a705
docs: DNF groups in closure signatures are now gradual, not unsupported
math3usmartins Jul 6, 2026
4a43de5
fix(monomorphize): resolve fully-qualified literal types absolutely i…
math3usmartins Jul 6, 2026
6f90639
docs(changelog): record the fully-qualified literal-type conformance fix
math3usmartins Jul 6, 2026
027f64a
fix(monomorphize): bind relative namespace\Foo literal types to the n…
math3usmartins Jul 6, 2026
233facc
test(monomorphize): pin the scanner shapes two equivalence claims got…
math3usmartins Jul 6, 2026
8906615
fix(monomorphize): lower array-sugar leaves inside Closure signatures…
math3usmartins Jul 6, 2026
f77704b
docs: array-sugar leaves in closure signatures lower to array
math3usmartins Jul 6, 2026
36626e4
fix(monomorphize): consume chained array sugar whole inside Closure s…
math3usmartins Jul 6, 2026
3c15c7c
fix(monomorphize): bind relative namespace\Foo names to the namespace…
math3usmartins Jul 6, 2026
9e951af
docs(changelog): record the relative-name resolution fix
math3usmartins Jul 6, 2026
22f900b
fix(monomorphize): require a declaration header before treating `) :`…
math3usmartins Jul 6, 2026
b62aba4
docs(changelog): record the return-slot detector fix
math3usmartins Jul 6, 2026
3a5dc7b
fix(monomorphize): prove non-subtyping against built-in targets for c…
math3usmartins Jul 6, 2026
598f28b
fix(monomorphize): accept keyword method names and generic clauses in…
math3usmartins Jul 6, 2026
29a1b6f
docs(changelog): record the built-in-target conformance and enum-edge…
math3usmartins Jul 6, 2026
a001201
docs: precise wording for when a built-in conformance target can reject
math3usmartins Jul 6, 2026
f2bbaa6
test(monomorphize): pin the built-in-candidate, aliased-Stringable, a…
math3usmartins Jul 6, 2026
59cf33b
test(monomorphize): pin the static use-call reject and fix two commen…
math3usmartins Jul 6, 2026
083b5c1
fix(monomorphize): preserve newlines when stripping generic clauses a…
math3usmartins Jul 7, 2026
f815bef
fix(monomorphize): anchor anonymous-closure markers at the node's tru…
math3usmartins Jul 7, 2026
1cd8b74
fix(monomorphize): match named generic markers on the declaration nam…
math3usmartins Jul 7, 2026
00ffbeb
feat(monomorphize): loud backstop for generic markers that never bind
math3usmartins Jul 7, 2026
68995a2
feat(monomorphize): resolve php-parser Names through a qualification-…
math3usmartins Jul 7, 2026
06962d2
fix(monomorphize): honor FQ and relative spellings at generic call sites
math3usmartins Jul 7, 2026
8782127
fix(monomorphize): synthesize all-defaults instantiations for FQ and …
math3usmartins Jul 7, 2026
fa3f678
fix(monomorphize): relative names are explicit class references, neve…
math3usmartins Jul 7, 2026
e42abe7
fix(monomorphize): a use-function import is never a generic declaration
math3usmartins Jul 7, 2026
46724b4
docs: record the marker-alignment and name-resolution fixes; static a…
math3usmartins Jul 7, 2026
2ec32fa
fix(monomorphize): match generic markers byte-exact, ending same-line…
math3usmartins Jul 7, 2026
89ef9ac
feat(monomorphize): reject generic closures that are never specialized
math3usmartins Jul 7, 2026
fd430cb
test(monomorphize): make the same-line sugar pin genuinely length-cha…
math3usmartins Jul 7, 2026
11e5b7f
fix(monomorphize): a non-concrete turbofish is an attempt, not an orphan
math3usmartins Jul 7, 2026
00039c8
docs: record byte-exact markers and unspecialized-closure rejection
math3usmartins Jul 7, 2026
1014cb0
fix(monomorphize): reject a bare new of a non-defaults generic
math3usmartins Jul 7, 2026
d26525d
fix(monomorphize): emit a valid forwarding closure for a turbofish FCC
math3usmartins Jul 7, 2026
65360c9
test(monomorphize): pin the turbofish-FCC forwarding-param collision …
math3usmartins Jul 7, 2026
0044f8d
docs: record the bare-new reject and the turbofish-FCC forwarding clo…
math3usmartins Jul 7, 2026
5541076
fix(monomorphize): ground inner turbofish type args on specialization
math3usmartins Jul 7, 2026
6134ec2
fix(monomorphize): report the real source line for parse-stage reject…
math3usmartins Jul 7, 2026
0b1d94d
test(monomorphize): pin the two distinct default-reject line sites
math3usmartins Jul 7, 2026
507e760
docs: record real-line reporting for parse-stage rejections in check
math3usmartins Jul 7, 2026
69f0116
fix(monomorphize): reject a generic clause on a `use` import
math3usmartins Jul 7, 2026
128f8b8
docs: record the use-import generic-clause rejection
math3usmartins Jul 8, 2026
1879de6
feat(monomorphize): function/const-aware name resolution in Namespace…
math3usmartins Jul 8, 2026
83ad529
feat(monomorphize): collect free function and const definitions
math3usmartins Jul 8, 2026
519785e
fix(monomorphize): re-qualify free functions and consts in specialize…
math3usmartins Jul 8, 2026
01272b8
fix(monomorphize): re-qualify free symbols in gap-filled and group-im…
math3usmartins Jul 8, 2026
ab0e9eb
docs: record free-symbol re-qualification in relocated specializations
math3usmartins Jul 8, 2026
5e50c5a
fix(monomorphize): reject turbofish on a dynamically-named call inste…
math3usmartins Jul 8, 2026
e22cf58
feat(monomorphize): support keyword-named generic methods
math3usmartins Jul 8, 2026
cecd0ca
refactor(monomorphize): keep the dynamic-name reject discriminator mu…
math3usmartins Jul 8, 2026
11ec5aa
docs: record dynamic-name turbofish rejection and keyword-named gener…
math3usmartins Jul 8, 2026
c4b3169
fix(monomorphize): index group-imported class members into the use-map
math3usmartins Jul 10, 2026
495a78e
docs: changelog entry for group-imported class re-qualification
math3usmartins Jul 10, 2026
f3cb880
fix(monomorphize): specialize generic-trait adaptation operands
math3usmartins Jul 10, 2026
d79bbf2
refactor(monomorphize): make the ambiguous-trait-operand remedy actio…
math3usmartins Jul 10, 2026
68cf607
docs: record generic-trait adaptation-operand specialization
math3usmartins Jul 10, 2026
6f1bcca
test: replace weak substring assertions with exact whole-value checks
math3usmartins Jul 10, 2026
1ea7c56
docs: restructure the how-it-works guide with per-stage pages and dia…
math3usmartins Jul 11, 2026
7cf448d
test: pin marker binding across multibyte identifiers and post-sugar …
math3usmartins Jul 11, 2026
0b2314a
docs: illustrate closure-signature variance with a class hierarchy
math3usmartins Jul 11, 2026
3275e74
fix(closure-types): reject a default value in a Closure(...) signatur…
math3usmartins Jul 11, 2026
a037b69
refactor(compiler): extract the fixed-point specialization loop into …
math3usmartins Jul 11, 2026
6c64596
fix(check): ground closure-signature conformance so check matches com…
math3usmartins Jul 11, 2026
d4813aa
feat(closure-types): clear diagnostics for unsupported closure-signat…
math3usmartins Jul 11, 2026
c493f07
docs: document the unsupported closure-signature positions as known l…
math3usmartins Jul 11, 2026
9634306
docs: note closure-type check/compile parity and unsupported-position…
math3usmartins Jul 11, 2026
780fcb8
docs: catalogue closure signature types and drop the roadmap Next sec…
math3usmartins Jul 12, 2026
82f760e
fix(parser): narrow startFilePos before indexing in the closure-in-ge…
math3usmartins Jul 12, 2026
234e174
Merge pull request #23 from xphp-lang/feat/closure-signature-types
math3usmartins Jul 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
47 changes: 47 additions & 0 deletions .github/workflows/ci-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,53 @@ jobs:
- name: Run PHPStan
run: make lint/phpstan

phpstan-pass:
# The `xphp check` PHPStan-integration tests (@group phpstan) shell out to a
# real phpstan binary, so they're excluded from `make test/unit` and run here.
# `composer install` provides vendor/bin/phpstan (a require-dev dependency).
name: PHPStan pass (xphp check)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup PHP 8.4
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
extensions: dom, json, mbstring, tokenizer
coverage: none
tools: composer:v2

- name: Install dependencies
uses: ramsey/composer-install@v3

- name: Run the PHPStan-pass tests
run: make test/phpstan-pass

check:
# End-to-end self-test of the `xphp check` gate: runs the real bin/xphp
# binary against the check fixtures and asserts the 0/1/2 exit contract.
# The in-process CheckCommandTest can't observe the shipped binary's
# process exit code or its rendered stdout, so this covers that gap.
name: xphp check (self-test)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup PHP 8.4
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
extensions: dom, json, mbstring, tokenizer
coverage: none
tools: composer:v2

- name: Install dependencies
uses: ramsey/composer-install@v3

- name: Run xphp check self-test
run: make test/check

infection:
name: Mutation testing
runs-on: ubuntu-latest
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ jobs:
# release fails BEFORE the asset is uploaded.
run: php dist/xphp.phar list

- name: Smoke-test `check` on the PHAR
# Exercise the released artifact as a real gate: same 0/1/2
# exit-contract assertions as CI, but against dist/xphp.phar
# instead of bin/xphp. Fails the release before upload if the
# packaged binary can't validate sources.
run: make test/check XPHP_BIN="php dist/xphp.phar"

- name: Compute SHA256 sum
# `sha256sum` outputs `<hex> <filename>`; running it from
# the dist/ directory keeps the filename relative so users
Expand Down
482 changes: 479 additions & 3 deletions CHANGELOG.md

Large diffs are not rendered by default.

23 changes: 19 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,24 @@
## Test

```bash
make test/unit # PHPUnit on the default PHP 8.4 runtime
make test/unit/php85 # only tests tagged `@group php85`; needs a PHP 8.5 runtime
make test/mutation # Infection, MSI under a 95 % gate
make test/unit # PHPUnit on the default PHP 8.4 runtime
make test/unit/php85 # only tests tagged `@group php85`; needs a PHP 8.5 runtime
make test/phpstan-pass # only tests tagged `@group phpstan` (the `xphp check` PHPStan pass)
make test/mutation # Infection, MSI under a 95 % gate
```

The supported runtime is PHP `^8.4`. Tests that exercise newer-PHP syntax
(e.g. the 8.5 pipe operator) are tagged `@group php85`; `make test/unit`
excludes them and they self-skip via `#[RequiresPhp]` off an 8.5 host. CI
runs them in a dedicated PHP 8.5 job.

The `xphp check` PHPStan-pass tests are tagged `@group phpstan` — they shell out
to a real phpstan subprocess (slow), so `make test/unit` excludes them and they
self-skip when `vendor/bin/phpstan` is absent (the same self-skip idea as
`@group php85`). CI runs them in a dedicated job; locally use `make
test/phpstan-pass`. (Not to be confused with `make lint/phpstan`, which runs
PHPStan over `src/`.)

No PHP 8.5 locally? Run them in the bundled 8.5 container:

```bash
Expand All @@ -21,4 +29,11 @@ docker compose run --rm php85 make test/unit/php85

CI gates every PR on these targets. `infection.json5` carries a curated set
of per-mutator `ignore` rules for genuinely-equivalent / defensive
mutations so the report only surfaces real test gaps.
mutations so the report only surfaces real test gaps.

## Architecture decisions

Architecturally significant decisions — the ones that are expensive to reverse —
are recorded as [Architecture Decision Records](docs/adr/README.md). When you make
such a decision, add a new ADR under `docs/adr/` (copy
[`docs/adr/0000-adr-template.md`](docs/adr/0000-adr-template.md)).
25 changes: 21 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@
# targets here.

.PHONY: test/unit
# Default runtime is PHP 8.4 (composer requires ^8.4). Tests exercising
# newer-PHP syntax are tagged `@group php85` and excluded here; they run
# on an 8.5 runtime via `make test/unit/php85`.
# Default runtime is PHP 8.4 (composer requires ^8.4). Two groups are excluded
# here: `php85` (newer-PHP syntax; runs on 8.5 via `make test/unit/php85`) and
# `phpstan` (the `xphp check` PHPStan pass, which shells out to a real phpstan
# subprocess and is slow; runs via `make test/phpstan-pass`).
test/unit:
php vendor/bin/phpunit --exclude-group php85
php vendor/bin/phpunit --exclude-group php85 --exclude-group phpstan

.PHONY: test/phpstan-pass
# The `xphp check` PHPStan-integration tests (tagged `@group phpstan`). They
# shell out to the consumer's phpstan binary and self-skip when vendor/bin/phpstan
# is absent. NOTE: distinct from `lint/phpstan`, which runs PHPStan over src/.
test/phpstan-pass:
php vendor/bin/phpunit --group phpstan

.PHONY: test/unit/php85
# Runs only the PHP 8.5-specific syntax tests (e.g. the pipe operator).
Expand All @@ -35,6 +43,15 @@ lint/phpstan:
test/mutation:
php -d memory_limit=-1 vendor/bin/infection --show-mutations=max --threads=max --min-covered-msi=95

.PHONY: test/check
# End-to-end self-test of the `check` gate: runs the real bin/xphp binary
# against the check fixtures and asserts the 0/1/2 exit contract plus that the
# text/json/github renderers all emit. Reused by release.yml against the built
# PHAR (override XPHP_BIN="php dist/xphp.phar"). Complements the in-process
# CheckCommandTest, which can't observe the shipped binary's process exit code.
test/check:
sh test/smoke/check.sh

# Humbug Box is the standard tool for compiling a Composer-managed
# PHP project into a single self-contained PHAR. Pinned to a known-
# good release (Box 4.6.6 supports PHP 8.4) so a new Box version
Expand Down
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,47 @@ compile. `dist/` holds your rewritten code; `.xphp-cache/Generated/`
holds the specialized classes. Both can be gitignored and rebuilt
in CI.

For a real project — and **required** once you consume another package's
generics — drop an `xphp.json` manifest at the project root instead of
repeating the paths on every invocation:

```json
{
"sources": ["src"],
"include": ["vendor/**"],
"target": "dist",
"cache": ".xphp-cache"
}
```

Then `compile`/`check` take no positional source — they resolve the
manifest (auto-detected in the working directory, or via `--config`):

```bash
vendor/bin/xphp compile # compiles this package + every included one
vendor/bin/xphp check
```

`include` globs auto-discover installed xphp packages (`vendor/**` finds
every one, at any depth, with no edit when you add another), so the
downstream build compiles the whole union into its own output. See
[Getting started](docs/getting-started.md#the-recommended-project-setup-an-xphpjson-manifest)
for the distribution model. The single-directory form above keeps working
unchanged.

To validate generics without emitting anything — a CI gate that reports
every bound/variance/etc. problem with a `file:line`:

```bash
vendor/bin/xphp check src # exit 1 if any error; --format=text|json|github
```

`check` runs all of xphp's generic validation (the specialization-loop guards
aside) and then, when those pass, runs **your** PHPStan over the compiled output
and maps the findings back to the `.xphp` template — one config, one gate (pass
`--no-phpstan` to skip it). You still run `compile` to emit the PHP. See
[Errors and diagnostics](docs/errors.md#xphp-check--validate-without-emitting).

## See also

- [Getting started](docs/getting-started.md) -- full walkthrough including PSR-4 details, runtime semantics, and what the generated PHP looks like
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"require": {
"php": "^8.4.0",
"nikic/php-parser": "^5.7",
"symfony/console": "^8.0"
"symfony/console": "^8.0",
"symfony/process": "^8.0"
},
"require-dev": {
"phpunit/phpunit": "^13.0",
Expand Down
132 changes: 66 additions & 66 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading