doFoldSsaType folded a statically type-known is_int()/is_float()/
is_bool() call to the literal `true`, discarding the argument entirely.
With `function f(): int`, `if (is_int(f()))` compiled to `if (true)`
and f() was never invoked — its side effects silently vanished.
Fold to a bare `true` only for plain variables and scalar literals;
for any other argument emit `((void)(expr), true)` so the operand is
still evaluated, mirroring how genIsNull already handles native scalar
operands.
The flag checks that translate `break N` / `continue N` were emitted only
at the end of each enclosing loop body. After the inner construct exited
with the countdown flag set, every trailing statement of the enclosing
body still executed before the check ran:
foreach ([1] as $x) {
foreach ([1] as $y) { break 2; }
echo "leaked"; // ran in compiled output, not in PHP
}
The native (int-typed) switch path was worse: its check sat inside the
do-while(0) wrapper, decrementing the flag a second time for the switch
level the C++ `break` had already exited. A `break 2` from a native
switch inside a loop therefore never exited the loop at all.
Emit the propagation check immediately after every nested loop / switch
statement instead, from the statement dispatcher, and drop the dead
end-of-body emissions. The check now also distinguishes the enclosing
construct: when it sits inside a switch, a continue that lands on the
switch level lowers to `break`, matching PHP's continue-targets-switch
semantics.
parseBreak/parseContinue now reject levels exceeding the number of
enclosing breakable constructs - the same compile-time validation PHP
performs (`Cannot 'break' 2 levels`) - which the countdown scheme
relies on to terminate at an enclosing construct.
The continue-2-while scenario in break-continue-level.phpt encoded the
old leaked behavior: its `$i++` after the inner loop only ran because of
the misplaced check; standard PHP loops forever on it. The counter now
advances before the inner loop.
- Updated swoole/phpx dependency from ~2.6.4 to ~2.6.6
- Bumped project version from 0.6.6 to 0.6.7 in project.yml
- Updated file version from 0.6.6.1112 to 0.6.7.1112 in project.yml
- Updated product version from 0.6.6 to 0.6.7 in project.yml
- Updated VERSION constant from '0.6.6' to '0.6.7' in Translator.php
The flag checks that translate `break N` / `continue N` were emitted only
at the end of each enclosing loop body. After the inner construct exited
with the countdown flag set, every trailing statement of the enclosing
body still executed before the check ran:
foreach ([1] as $x) {
foreach ([1] as $y) { break 2; }
echo "leaked"; // ran in compiled output, not in PHP
}
The native (int-typed) switch path was worse: its check sat inside the
do-while(0) wrapper, decrementing the flag a second time for the switch
level the C++ `break` had already exited. A `break 2` from a native
switch inside a loop therefore never exited the loop at all.
Emit the propagation check immediately after every nested loop / switch
statement instead, from the statement dispatcher, and drop the dead
end-of-body emissions. The check now also distinguishes the enclosing
construct: when it sits inside a switch, a continue that lands on the
switch level lowers to `break`, matching PHP's continue-targets-switch
semantics.
parseBreak/parseContinue now reject levels exceeding the number of
enclosing breakable constructs - the same compile-time validation PHP
performs (`Cannot 'break' 2 levels`) - which the countdown scheme
relies on to terminate at an enclosing construct.
The continue-2-while scenario in break-continue-level.phpt encoded the
old leaked behavior: its `$i++` after the inner loop only ran because of
the misplaced check; standard PHP loops forever on it. The counter now
advances before the inner loop.
- Updated swoole/phpx dependency from ~2.6.4 to ~2.6.6
- Bumped project version from 0.6.6 to 0.6.7 in project.yml
- Updated file version from 0.6.6.1112 to 0.6.7.1112 in project.yml
- Updated product version from 0.6.6 to 0.6.7 in project.yml
- Updated VERSION constant from '0.6.6' to '0.6.7' in Translator.php
- Add useImportAliases property to track import aliases by type domain
- Implement registerUseImportAlias method with duplicate detection logic
- Update use declaration processing to utilize import alias registration
- Make class and function aliases case-insensitive while constants remain case-sensitive
- Add comprehensive test coverage for import alias domain isolation
- Include negative test cases for duplicate alias detection across domains
- Move AST name resolution earlier in preprocessing steps
- Add proper error handling for PHP parser errors during traversal
- Removed unnecessary null check for left and right types in binary operation detection
- Eliminated redundant null check for closure statements before global collection
- Simplified type checking logic by relying on subsequent primitive type validation
- Improved code flow by removing early returns that were masking actual logic
- Update project.yml version from 0.1.0 to 0.6.6
- Update project.yml file-version from 0.6.5.1112 to 0.6.6.1112
- Update project.yml product-version from 0.6.5 to 0.6.6
- Update Translator.php VERSION constant from 0.6.5 to 0.6.6
When generating arginfo for union/intersection types with 2+ class types,
the ZEND_TYPE_INIT_CLASS macro was using toEscapedName() which preserves
backslashes (e.g. yuandian\\Database\\Db\\Expression\\Raw), but
C identifiers cannot contain backslashes.
This caused compilation errors like:
error: stray '\' in program
Fix: use toVarEscapedName() which replaces namespace separators with
underscores, consistent with the single-class-type branch (line 2901).
- Updated file-version in project.yml from 0.6.3.1112 to 0.6.5.1112
- Updated product-version in project.yml from 0.6.3 to 0.6.5
- Updated VERSION constant in Translator.php from 0.6.1 to 0.6.5
- Remove TYPEPHP_PROJECT_NAME and TYPEPHP_RUNTIME_EXPORTS from common compile options
- Add dedicated getProjectRuntimeEntryCompileCommandOptions method for project-specific defines
- Update testEmbeddedCompileOptionsPassProjectNameForModuleAccessor to reflect new behavior
- Create new testProjectRuntimeEntryHasTargetDefineWithoutPchOrObjectCache
- Add testProjectIndependentMiscObjectsUseSharedCacheScope and testProjectIndependentMiscObjectCacheSurvivesTargetNameChange
- Update composer.json to use swoole/phpx ~2.6.4
- Modify object file caching logic to handle project-specific vs shared misc objects
- Add isProjectRuntimeEntryFile helper method for determining cache scope
- Update compileFile method to use source-specific compile options
- Handle different PHPX runtime source file layouts during embed mode builds
- Replace zend_string_init with zend_string_init_interned for persistent property defaults
- Use ZVAL_INTERNED_STR instead of ZVAL_STR for interned string values
- Add test case to verify persistent string metadata uses non-refcounted interned zval
- Reduce parallel test jobs from 8 to 4 to accommodate compiler test requirements
- Removed CLAUDE.md guidance file for Claude Code usage
- Removed code reuse improvement plan documentation
- Removed encapsulation review documentation
- Updated composer.json to specify phpstan version constraint
- Fixed namespace issues in Extractor.php exception handling
- Renamed main function in bin/extractor.php to avoid conflicts
- Updated LICENSE to standard GPL format