Skip to content

Commit

Permalink
Fix checks for property hooks emulation with asymmetric visibility
Browse files Browse the repository at this point in the history
  • Loading branch information
thekid committed Sep 1, 2024
1 parent 2a95ebb commit f37388f
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 8 deletions.
2 changes: 2 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ XP Compiler ChangeLog

## 9.3.0 / 2024-08-31

* Fixed checks for property hooks emulation with asymmetric visibility
(@thekid)
* Added PHP 8.4 emitter which natively emits property hooks and asymmetric
visibility syntax. This is integration-tested with PHP 8.4.0 Beta 4.
See https://github.com/php/php-src/blob/php-8.4.0beta4/NEWS
Expand Down
35 changes: 27 additions & 8 deletions src/main/php/lang/ast/emit/PropertyHooks.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,16 @@ protected function withScopeCheck($modifiers, $nodes) {

protected function emitProperty($result, $property) {
static $lookup= [
'public' => MODIFIER_PUBLIC,
'protected' => MODIFIER_PROTECTED,
'private' => MODIFIER_PRIVATE,
'static' => MODIFIER_STATIC,
'final' => MODIFIER_FINAL,
'abstract' => MODIFIER_ABSTRACT,
'readonly' => MODIFIER_READONLY,
'public' => MODIFIER_PUBLIC,
'protected' => MODIFIER_PROTECTED,
'private' => MODIFIER_PRIVATE,
'static' => MODIFIER_STATIC,
'final' => MODIFIER_FINAL,
'abstract' => MODIFIER_ABSTRACT,
'readonly' => MODIFIER_READONLY,
'public(set)' => 0x1000000,
'protected(set)' => 0x0000800,
'private(set)' => 0x0001000,
];

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

// Derive modifiers for private(set) and protected(set), folding declarations
// like `[visibility] [visibility](set)` to just the visibility itself.
if ($modifiers & 0x1000000) {
$check= null;
$modifiers&= ~0x1000000;
$write= MODIFIER_PUBLIC;
} else if ($modifiers & 0x0000800) {
$modifiers & MODIFIER_PROTECTED && $modifiers&= ~0x0000800;
$write= MODIFIER_PROTECTED;
} else if ($modifiers & 0x0001000) {
$modifiers & MODIFIER_PRIVATE && $modifiers&= ~0x0001000;
$write= MODIFIER_PRIVATE;
} else {
$write= $modifiers;
}

$scope->meta[self::PROPERTY][$property->name]= [
DETAIL_RETURNS => $property->type ? $property->type->name() : 'var',
DETAIL_ANNOTATIONS => $property->annotations,
Expand Down Expand Up @@ -137,7 +156,7 @@ protected function emitProperty($result, $property) {
)],
null // $hook->annotations
));
$set= $this->withScopeCheck($modifiers, [new InvokeExpression(
$set= $this->withScopeCheck($write, [new InvokeExpression(
new InstanceExpression(new Variable('this'), new Literal($method)),
[new Variable('value')]
)]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,22 @@ public function same_modifier_for_get_and_set($modifier) {
$t->property('fixture')->toString()
);
}

#[Test]
public function interaction_with_hooks() {
$t= $this->declare('class %T {
public private(set) string $fixture {
get => $this->fixture;
set => strtolower($value);
}
public function rename($name) {
$this->fixture= $name;
return $this;
}
}');

Assert::throws(Error::class, fn() => $t->newInstance()->fixture= 'Changed');
Assert::equals('changed', $t->newInstance()->rename('Changed')->fixture);
}
}

0 comments on commit f37388f

Please sign in to comment.