Skip to content

perf(compiler): infer closure parameter types from declarations and call sites - #100

Closed
yuan-dian wants to merge 5 commits into
swoole:masterfrom
yuan-dian:perf/closure-param-type-inference
Closed

perf(compiler): infer closure parameter types from declarations and call sites#100
yuan-dian wants to merge 5 commits into
swoole:masterfrom
yuan-dian:perf/closure-param-type-inference

Conversation

@yuan-dian

Copy link
Copy Markdown
Contributor

Summary

Add closure parameter type inference to the TypePHP compiler. When closure parameters have PHP type declarations or can be inferred from single call-site literal arguments, the compiler now generates native C++ types (php::Int, php::Float, php::Bool, php::Str, php::Array) instead of php::Var. This eliminates runtime type checks and enables native C++ arithmetic, resulting in significant performance improvements.

Performance

Benchmark Before After Speedup
fn($x)(42) 64ms 5ms 12.8x
fn($x)(3.14) 64ms 7ms 9.1x
fn($x)(true) 64ms 6ms 10.7x
fn($x)(-42) 64ms 5ms 12.8x
fn($x)(1===2) 64ms 6ms 10.7x
fn($x)("a"."b") 64ms 7ms 9.1x
fn(int $x)(42) 76ms 5ms 15.2x

What's Changed

Phase 1: Type Declaration Inference

PHP type hints on closure parameters are used to generate native C++ types:

$fn = fn(int $a) => $a + 1;    // php::Int a
$fn = fn(float $a) => $a * 2;  // php::Float a
$fn = fn(bool $a) => !$a;      // php::Bool a
$fn = fn(string $a) => $a;     // php::Str a
$fn = fn(array $a) => $a;      // php::Array a

Phase 2: Call-Site Literal Inference

When a closure is called exactly once with literal arguments, the parameter type is inferred:

$fn = fn($x) => $x + 1;
$fn(42);        // php::Int x
$fn(-3.14);     // php::Float x
$fn(true);      // php::Bool x
$fn([1, 2, 3]); // php::Array x

Edge Cases Handled

  • Unary operators: -42php::Int, +3.14php::Float
  • Boolean expressions: 1 === 2, true || false, $obj instanceof Foophp::Bool
  • String concatenation: "hello" . "world"php::Str (both operands must be strings)
  • Multiple call sites: Falls back to php::Var when types conflict across calls

Bug Fix

Fixed a variable name collision in Translator.php where the foreach loop variable $name overwrote the function's native C++ name, causing incorrect output for functions with closures.

Files Changed

File Changes
src/Analysis/LocalClosureAnalyzer.php +100/-2 — inferParamTypes(), detectArgType(), call-site tracking
src/Generator/ClosureGenerator.php +36/-2 — Use inferred types, skip redundant type checks
src/Translator.php +6/-1 — Wire analyzer output, fix $name collision
phpunit/code/closure-param-type.php +113 — 17 test scenarios
phpunit/src/ClosureParamTypeTest.php +110 — 6 unit tests
phpunit/src/LocalClosureCodegenTest.php +2/-1 — Updated assertion
tests/compiler/closure/closure-param-type-inference.phpt +81 — Integration test

Test Coverage

OK (6 tests, 20 assertions)
  • testTypeHintParametersUseNativeCppTypes — Verifies type-hinted params generate native types
  • testCallSiteInferredParametersUseNativeCppTypes — Verifies literal call-site inference
  • testMultiCallClosureRemainsPhpVar — Verifies fallback to php::Var for multiple calls
  • testUnaryMinusInfersNativeType — Verifies -42php::Int, -3.14php::Float
  • testBooleanExpressionsInferBoolType — Verifies comparison/logical ops → php::Bool
  • testConcatStringInference — Verifies string concat → php::Str

…all sites

* perf(compiler): use PHP type hints to narrow native local closure parameters to php::Int/Float/Bool/Str/Array

* perf(compiler): infer closure parameter types from single call-site literal arguments

* perf(compiler): skip redundant runtime type checks when parameter is already a native C++ type

* fix(compiler): prevent closure variable names from overwriting function C++ names in Translator
* test(compiler): verify type hint parameters use native C++ types (php::Int/Float/Bool/Str/Array)

* test(compiler): verify call-site literal inference narrows closure parameters

* test(compiler): verify multi-call closures remain php::Var when types conflict

* test(compiler): update LocalClosureCodegenTest for php::Int parameter change
* Handle UnaryMinus/UnaryPlus wrapping numeric literals (-42, +3.14)

* Add boolean expression inference (&&, ||, !, ===, !==, ==, !=, <, <=, >, >=, <=>, instanceof)

* Add string concatenation inference when both operands are strings
@yuan-dian

yuan-dian commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Close, wait for all problems to be solved and resubmit PR.

@yuan-dian yuan-dian closed this Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant