Skip to content

Commit 2466c6e

Browse files
authored
Merge pull request #184 from xp-framework/feature/final-properties
Add support for final properties
2 parents 02af2ea + aa8b4e7 commit 2466c6e

File tree

5 files changed

+53
-2
lines changed

5 files changed

+53
-2
lines changed

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": "^11.3",
11+
"xp-framework/ast": "^11.5",
1212
"php" : ">=7.4.0"
1313
},
1414
"require-dev" : {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php namespace lang\ast\emit;
2+
3+
trait FinalProperties {
4+
5+
protected function emitProperty($result, $property) {
6+
static $lookup= [
7+
'public' => MODIFIER_PUBLIC,
8+
'protected' => MODIFIER_PROTECTED,
9+
'private' => MODIFIER_PRIVATE,
10+
'static' => MODIFIER_STATIC,
11+
'final' => MODIFIER_FINAL,
12+
'abstract' => MODIFIER_ABSTRACT,
13+
'readonly' => 0x0080, // XP 10.13: MODIFIER_READONLY
14+
];
15+
16+
$modifiers= 0;
17+
foreach ($property->modifiers as $name) {
18+
$modifiers|= $lookup[$name];
19+
}
20+
21+
// Emit without final modifier, store `final` in xp::$meta
22+
$property->modifiers= array_diff($property->modifiers, ['final']);
23+
parent::emitProperty($result, $property);
24+
$result->codegen->scope[0]->meta[self::PROPERTY][$property->name][DETAIL_ARGUMENTS]= [MODIFIER_FINAL];
25+
}
26+
}

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)

src/test/php/lang/ast/unittest/emit/ArgumentPromotionTest.class.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* @see https://github.com/xp-framework/rfc/issues/240
1111
* @see https://docs.hhvm.com/hack/other-features/constructor-parameter-promotion
1212
* @see https://wiki.php.net/rfc/constructor_promotion (PHP 8.0)
13+
* @see https://wiki.php.net/rfc/final_prompotion
1314
* @see https://wiki.php.net/rfc/automatic_property_initialization (Declined)
1415
*/
1516
class ArgumentPromotionTest extends EmittingTest {
@@ -142,4 +143,13 @@ public function __construct(private array $list) { }
142143
}');
143144
Assert::equals('Test', $t->newInstance(['Test'])->first);
144145
}
146+
147+
#[Test]
148+
public function promoted_final() {
149+
$t= $this->declare('class %T {
150+
public function __construct(public final string $name) { }
151+
}');
152+
153+
Assert::equals(MODIFIER_PUBLIC | MODIFIER_FINAL, $t->property('name')->modifiers()->bits());
154+
}
145155
}

src/test/php/lang/ast/unittest/emit/MembersTest.class.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,4 +425,13 @@ public function run() {
425425

426426
Assert::equals('Test', $r);
427427
}
428+
429+
#[Test]
430+
public function final_property() {
431+
$t= $this->declare('class %T {
432+
public final string $fixture= "Test";
433+
}');
434+
435+
Assert::equals(MODIFIER_PUBLIC | MODIFIER_FINAL, $t->property('fixture')->modifiers()->bits());
436+
}
428437
}

0 commit comments

Comments
 (0)