Skip to content

Commit bb30652

Browse files
committed
MFH
2 parents a7c7d79 + 9d21030 commit bb30652

14 files changed

+173
-58
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ jobs:
1111
if: "!contains(github.event.head_commit.message, 'skip ci')"
1212
name: PHP ${{ matrix.php-versions }} on ${{ matrix.os }}
1313
runs-on: ${{ matrix.os }}
14-
continue-on-error: ${{ matrix.php-versions >= '8.4' }}
14+
continue-on-error: ${{ matrix.php-versions >= '8.5' }}
1515
strategy:
1616
fail-fast: false
1717
matrix:
18-
php-versions: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4']
18+
php-versions: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5']
1919
os: [ubuntu-latest, windows-latest]
2020

2121
steps:

ChangeLog.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@ XP Compiler ChangeLog
33

44
## ?.?.? / ????-??-??
55

6+
## 9.4.0 / 2025-04-05
7+
8+
* Merged PR #184: Add support for final properties added in PHP 8.4, see
9+
https://wiki.php.net/rfc/property-hooks; including parameter promotion,
10+
see https://wiki.php.net/rfc/final_promotion
11+
(@thekid)
12+
13+
## 9.3.3 / 2025-03-02
14+
15+
* Fixed callable new syntax when using a variable or expression, e.g.
16+
`new $class(...)`. See also https://github.com/php/php-src/issues/12336
17+
(@thekid)
18+
619
## 9.3.2 / 2024-11-02
720

821
* Fixed empty match expressions and match expressions with default

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"require" : {
99
"xp-framework/core": "^12.0 | ^11.6 | ^10.16",
1010
"xp-framework/reflection": "^3.2 | ^2.15",
11-
"xp-framework/ast": "dev-feature/pipelines as 11.4.0",
11+
"xp-framework/ast": "dev-feature/pipelines as 11.6.0",
1212
"php" : ">=7.4.0"
1313
},
1414
"require-dev" : {

src/main/php/lang/ast/emit/AsymmetricVisibility.class.php

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,8 @@ trait AsymmetricVisibility {
2020
use VisibilityChecks;
2121

2222
protected function emitProperty($result, $property) {
23-
static $lookup= [
24-
'public' => MODIFIER_PUBLIC,
25-
'protected' => MODIFIER_PROTECTED,
26-
'private' => MODIFIER_PRIVATE,
27-
'static' => MODIFIER_STATIC,
28-
'final' => MODIFIER_FINAL,
29-
'abstract' => MODIFIER_ABSTRACT,
30-
'readonly' => MODIFIER_READONLY,
31-
'public(set)' => 0x1000000,
32-
'protected(set)' => 0x0000800,
33-
'private(set)' => 0x0001000,
34-
];
35-
3623
$scope= $result->codegen->scope[0];
37-
$modifiers= 0;
38-
foreach ($property->modifiers as $name) {
39-
$modifiers|= $lookup[$name];
40-
}
24+
$modifiers= Modifiers::bits($property->modifiers);
4125

4226
// Declare checks for private(set) and protected(set), folding declarations
4327
// like `[visibility] [visibility](set)` to just the visibility itself.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php namespace lang\ast\emit;
2+
3+
/**
4+
* When property hooks were introduced into PHP 8.4, it also added a mechanism
5+
* for properties to be declared as final. For other PHP versions, emit without
6+
* final modifier, store `final` in xp::$meta
7+
*
8+
* @see https://wiki.php.net/rfc/property-hooks
9+
* @test lang.ast.unittest.emit.MembersTest
10+
*/
11+
trait FinalProperties {
12+
13+
protected function emitProperty($result, $property) {
14+
$property->modifiers= array_diff($property->modifiers, ['final']);
15+
parent::emitProperty($result, $property);
16+
$result->codegen->scope[0]->meta[self::PROPERTY][$property->name][DETAIL_ARGUMENTS]= [MODIFIER_FINAL];
17+
}
18+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php namespace lang\ast\emit;
2+
3+
class Modifiers {
4+
const LOOKUP= [
5+
'public' => MODIFIER_PUBLIC,
6+
'protected' => MODIFIER_PROTECTED,
7+
'private' => MODIFIER_PRIVATE,
8+
'static' => MODIFIER_STATIC,
9+
'final' => MODIFIER_FINAL,
10+
'abstract' => MODIFIER_ABSTRACT,
11+
'readonly' => 0x0080, // XP 10.13: MODIFIER_READONLY
12+
'public(set)' => 0x1000000,
13+
'protected(set)' => 0x0000800,
14+
'private(set)' => 0x0001000,
15+
];
16+
17+
/**
18+
* Converts modifiers to a bit set
19+
*
20+
* @param string[] $modifiers
21+
* @return int
22+
*/
23+
public static function bits($modifiers) {
24+
$bits= 0;
25+
foreach ($modifiers as $name) {
26+
$bits|= self::LOOKUP[$name];
27+
}
28+
return $bits;
29+
}
30+
}

src/main/php/lang/ast/emit/PHP.class.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,13 +1098,11 @@ protected function emitCallable($result, $callable) {
10981098

10991099
protected function emitCallableNew($result, $callable) {
11001100
$t= $result->temp();
1101-
$result->out->write("function(...{$t}) { return ");
1101+
$result->out->write("fn(...{$t}) => ");
11021102

11031103
$callable->type->arguments= [new UnpackExpression(new Variable(substr($t, 1)), $callable->line)];
11041104
$this->emitOne($result, $callable->type);
11051105
$callable->type->arguments= null;
1106-
1107-
$result->out->write("; }");
11081106
}
11091107

11101108
protected function emitInvoke($result, $invoke) {

src/main/php/lang/ast/emit/PropertyHooks.class.php

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -71,25 +71,8 @@ protected function withScopeCheck($modifiers, $nodes) {
7171
}
7272

7373
protected function emitProperty($result, $property) {
74-
static $lookup= [
75-
'public' => MODIFIER_PUBLIC,
76-
'protected' => MODIFIER_PROTECTED,
77-
'private' => MODIFIER_PRIVATE,
78-
'static' => MODIFIER_STATIC,
79-
'final' => MODIFIER_FINAL,
80-
'abstract' => MODIFIER_ABSTRACT,
81-
'readonly' => MODIFIER_READONLY,
82-
'public(set)' => 0x1000000,
83-
'protected(set)' => 0x0000800,
84-
'private(set)' => 0x0001000,
85-
];
86-
87-
// Emit XP meta information for the reflection API
8874
$scope= $result->codegen->scope[0];
89-
$modifiers= 0;
90-
foreach ($property->modifiers as $name) {
91-
$modifiers|= $lookup[$name];
92-
}
75+
$modifiers= Modifiers::bits($property->modifiers);
9376

9477
// Derive modifiers for private(set) and protected(set), folding declarations
9578
// like `[visibility] [visibility](set)` to just the visibility itself.

src/main/php/lang/ast/emit/ReadonlyProperties.class.php

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,8 @@ trait ReadonlyProperties {
2222
use VisibilityChecks;
2323

2424
protected function emitProperty($result, $property) {
25-
static $lookup= [
26-
'public' => MODIFIER_PUBLIC,
27-
'protected' => MODIFIER_PROTECTED,
28-
'private' => MODIFIER_PRIVATE,
29-
'static' => MODIFIER_STATIC,
30-
'final' => MODIFIER_FINAL,
31-
'abstract' => MODIFIER_ABSTRACT,
32-
'readonly' => 0x0080, // XP 10.13: MODIFIER_READONLY
33-
];
34-
35-
if (!in_array('readonly', $property->modifiers)) return parent::emitProperty($result, $property);
36-
3725
$scope= $result->codegen->scope[0];
38-
$modifiers= 0;
39-
foreach ($property->modifiers as $name) {
40-
$modifiers|= $lookup[$name];
41-
}
26+
$modifiers= Modifiers::bits($property->modifiers);
4227
$scope->meta[self::PROPERTY][$property->name]= [
4328
DETAIL_RETURNS => $property->type ? $property->type->name() : 'var',
4429
DETAIL_ANNOTATIONS => $property->annotations,

src/main/php/lang/ast/emit/RewriteProperties.class.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
use ReflectionProperty;
44

55
trait RewriteProperties {
6-
use PropertyHooks, ReadonlyProperties, AsymmetricVisibility {
6+
use PropertyHooks, FinalProperties, ReadonlyProperties, AsymmetricVisibility {
77
PropertyHooks::emitProperty as emitPropertyHooks;
8+
FinalProperties::emitProperty as emitFinalProperties;
89
ReadonlyProperties::emitProperty as emitReadonlyProperties;
910
AsymmetricVisibility::emitProperty as emitAsymmetricVisibility;
1011
}
@@ -17,6 +18,11 @@ protected function emitProperty($result, $property) {
1718
array_intersect($property->modifiers, ['private(set)', 'protected(set)', 'public(set)'])
1819
) {
1920
return $this->emitAsymmetricVisibility($result, $property);
21+
} else if (
22+
$this->targetVersion < 80400 &&
23+
in_array('final', $property->modifiers)
24+
) {
25+
return $this->emitFinalProperties($result, $property);
2026
} else if (
2127
$this->targetVersion < 80100 &&
2228
in_array('readonly', $property->modifiers)

0 commit comments

Comments
 (0)