Skip to content

Commit f37388f

Browse files
committed
Fix checks for property hooks emulation with asymmetric visibility
1 parent 2a95ebb commit f37388f

File tree

3 files changed

+47
-8
lines changed

3 files changed

+47
-8
lines changed

ChangeLog.md

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ XP Compiler ChangeLog
55

66
## 9.3.0 / 2024-08-31
77

8+
* Fixed checks for property hooks emulation with asymmetric visibility
9+
(@thekid)
810
* Added PHP 8.4 emitter which natively emits property hooks and asymmetric
911
visibility syntax. This is integration-tested with PHP 8.4.0 Beta 4.
1012
See https://github.com/php/php-src/blob/php-8.4.0beta4/NEWS

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

+27-8
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,16 @@ protected function withScopeCheck($modifiers, $nodes) {
7272

7373
protected function emitProperty($result, $property) {
7474
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,
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,
8285
];
8386

8487
// Emit XP meta information for the reflection API
@@ -88,6 +91,22 @@ protected function emitProperty($result, $property) {
8891
$modifiers|= $lookup[$name];
8992
}
9093

94+
// Derive modifiers for private(set) and protected(set), folding declarations
95+
// like `[visibility] [visibility](set)` to just the visibility itself.
96+
if ($modifiers & 0x1000000) {
97+
$check= null;
98+
$modifiers&= ~0x1000000;
99+
$write= MODIFIER_PUBLIC;
100+
} else if ($modifiers & 0x0000800) {
101+
$modifiers & MODIFIER_PROTECTED && $modifiers&= ~0x0000800;
102+
$write= MODIFIER_PROTECTED;
103+
} else if ($modifiers & 0x0001000) {
104+
$modifiers & MODIFIER_PRIVATE && $modifiers&= ~0x0001000;
105+
$write= MODIFIER_PRIVATE;
106+
} else {
107+
$write= $modifiers;
108+
}
109+
91110
$scope->meta[self::PROPERTY][$property->name]= [
92111
DETAIL_RETURNS => $property->type ? $property->type->name() : 'var',
93112
DETAIL_ANNOTATIONS => $property->annotations,
@@ -137,7 +156,7 @@ protected function emitProperty($result, $property) {
137156
)],
138157
null // $hook->annotations
139158
));
140-
$set= $this->withScopeCheck($modifiers, [new InvokeExpression(
159+
$set= $this->withScopeCheck($write, [new InvokeExpression(
141160
new InstanceExpression(new Variable('this'), new Literal($method)),
142161
[new Variable('value')]
143162
)]);

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

+18
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,22 @@ public function same_modifier_for_get_and_set($modifier) {
123123
$t->property('fixture')->toString()
124124
);
125125
}
126+
127+
#[Test]
128+
public function interaction_with_hooks() {
129+
$t= $this->declare('class %T {
130+
public private(set) string $fixture {
131+
get => $this->fixture;
132+
set => strtolower($value);
133+
}
134+
135+
public function rename($name) {
136+
$this->fixture= $name;
137+
return $this;
138+
}
139+
}');
140+
141+
Assert::throws(Error::class, fn() => $t->newInstance()->fixture= 'Changed');
142+
Assert::equals('changed', $t->newInstance()->rename('Changed')->fixture);
143+
}
126144
}

0 commit comments

Comments
 (0)