Skip to content

Resolve relative class type at compile time #11460

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
86d8f35
Add tests for relative class types
Girgias Jun 16, 2023
6006c31
Resolve relative types at compile time when possible
Girgias Jun 16, 2023
d18d306
Support for resolving self/parent/static in ReflectionType
Girgias Jun 14, 2023
f640603
Resolve trait relative class types when added to a class
Girgias Jun 18, 2023
9894438
More tests
Girgias Jun 24, 2023
18c6501
Only allocate new arg_infos if types are being resolved
Girgias Jun 24, 2023
560b1d6
Only allocate new zend_type_list if types are being resolved
Girgias Jun 24, 2023
08648dd
Address minor review comments
Girgias Jun 27, 2023
ebfb5af
Drop return for engine compiler error bail
Girgias Jun 27, 2023
c9a39aa
Change function name
Girgias Jul 25, 2023
274f10b
Add eval test
Girgias Jul 25, 2023
8969b8d
Add test in multiple distinct unrelated classes
Girgias Jul 25, 2023
6c4f630
Do not preserve BC for self/parent and always resolve when possible
Girgias Feb 28, 2024
d67ba9a
Add tests and try to resolve bound closure
Girgias Feb 29, 2024
f40e9bf
Solve bound closure
Girgias Mar 8, 2024
eb3c7e8
Fix resolution for closures by propagating Closure object
Girgias Apr 15, 2024
41ef059
Fix memory leak when calling constructor manually
Girgias Apr 15, 2024
118ca1c
Remove self/parent as known zend_strings
Girgias Apr 15, 2024
c0a2da3
Address review comments
Girgias Apr 16, 2024
3f275c4
Remove object copy which is not need anymore
Girgias Apr 16, 2024
aa79d51
Add more tests
Girgias Apr 17, 2024
62095c4
Add test failing assertion about memory being freed
Girgias Apr 17, 2024
5bea1b0
[skip-ci] W.I.P. changes to try and fix test
Girgias Apr 17, 2024
8fc28e9
[skip-ci] More test and assertion to try to figure out wth is going on
Girgias Apr 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Zend/tests/magic_methods_021.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Foo2 {
}

class Foo3 {
public static function __set_state(array $data): Foo3|self {}
public static function __set_state(array $data): Foo3|Foo2 {}
}

?>
Expand Down
File renamed without changes.
14 changes: 14 additions & 0 deletions Zend/tests/traits/trait_parent_type_in_class_no_parent.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
Cannot use a trait which references parent as a type in a class with no parent, single type
--FILE--
<?php
trait TraitExample {
public function bar(): parent { return parent::class; }
}

class A {
use TraitExample;
}
?>
--EXPECTF--
Fatal error: Cannot use trait which has "parent" as a type when current class scope has no parent in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
Cannot use a trait which references parent as a type in a class with no parent, nullable type
--FILE--
<?php
trait TraitExample {
public function bar(): ?parent { return parent::class; }
}

class A {
use TraitExample;
}
?>
--EXPECTF--
Fatal error: Cannot use trait which has "parent" as a type when current class scope has no parent in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
Cannot use a trait which references parent as a type in a class with no parent, union type
--FILE--
<?php
trait TraitExample {
public function bar(): int|parent { return parent::class; }
}

class A {
use TraitExample;
}
?>
--EXPECTF--
Fatal error: Cannot use trait which has "parent" as a type when current class scope has no parent in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
Cannot use a trait which references parent as a type in a class with no parent, DNF type
--FILE--
<?php
trait TraitExample {
public function bar(): (X&Y)|parent { return parent::class; }
}

class A {
use TraitExample;
}
?>
--EXPECTF--
Fatal error: Cannot use trait which has "parent" as a type when current class scope has no parent in %s on line %d
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
--TEST--
parent type cannot take part in an intersection type
parent type cannot take part in an intersection type when unresolved
--FILE--
<?php

class A {}

class B extends A {
trait T {
public function foo(): parent&Iterator {}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
--TEST--
self type cannot take part in an intersection type
self type cannot take part in an intersection type when unresolved
--FILE--
<?php

class A {
trait T {
public function foo(): self&Iterator {}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
parent/self type can take part in an intersection type if it is resolvable at compile time
--FILE--
<?php

class A {}

class B extends A {
public function foo(): parent&Iterator {}
}

class C extends A {
public function foo(): self&Iterator {}
}

?>
==DONE==
--EXPECT--
==DONE==
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--TEST--
Cannot use parent type outside a class
--FILE--
<?php

function foo($x): parent {};

?>
--EXPECTF--
Fatal error: Cannot use "parent" when no class scope is active in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--TEST--
Cannot use self type outside a class
--FILE--
<?php

function foo($x): self {};

?>
--EXPECTF--
Fatal error: Cannot use "self" when no class scope is active in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--TEST--
Cannot use static type outside a class
--FILE--
<?php

function foo($x): static {};

?>
--EXPECTF--
Fatal error: Cannot use "static" when no class scope is active in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
Relative class types can be used for closures as it may be bound to a class
--FILE--
<?php

$fn1 = function($x): self {};
$fn2 = function($x): parent {};
$fn3 = function($x): static {};

?>
DONE
--EXPECT--
DONE
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--TEST--
Eval Class definition should not leak memory when using compiled traits
--FILE--
<?php

trait TraitCompiled {
public function bar(): self { return new self; }
}

const EVAL_CODE = <<<'CODE'
class A {
use TraitCompiled;
}
CODE;

eval(EVAL_CODE);

$a1 = new A();
$a2 = $a1->bar();
var_dump($a2);

?>
DONE
--EXPECT--
object(A)#2 (0) {
}
DONE
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--TEST--
Eval code should not leak memory when using traits
--FILE--
<?php

const EVAL_CODE = <<<'CODE'
trait TraitEval {
public function bar(): self { return new self; }
}
CODE;

eval(EVAL_CODE);

class A {
use TraitEval;
}

$a1 = new A();
$a2 = $a1->bar();
var_dump($a2);

?>
DONE
--EXPECT--
object(A)#2 (0) {
}
DONE
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
Duplicate parent type
--FILE--
<?php

class Foo {
public function method(array $data) {}
}
class Bar extends Foo {
public function method(array $data): parent|parent {}
}

?>
--EXPECTF--
Fatal error: Duplicate type Foo is redundant in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--TEST--
Duplicate self type
--FILE--
<?php

class Foo {
public function method(array $data): self|self {}
}

?>
--EXPECTF--
Fatal error: Duplicate type Foo is redundant in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--TEST--
Duplicate static type
--FILE--
<?php

class Foo {
public function method(array $data): static|static {}
}

?>
--EXPECTF--
Fatal error: Duplicate type static is redundant in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--TEST--
Relative class type self resolving to an existing entry (after variation)
--FILE--
<?php

class Foo {
public function method(array $data): Foo|self {}
}

?>
--EXPECTF--
Fatal error: Duplicate type Foo is redundant in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--TEST--
Relative class type self resolving to an existing entry (before variation)
--FILE--
<?php

class Foo {
public function method(array $data): self|Foo {}
}

?>
--EXPECTF--
Fatal error: Duplicate type Foo is redundant in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
Relative class type parent resolving to an existing entry (after variation)
--FILE--
<?php

class Foo {
public function method(array $data) {}
}
class Bar extends Foo {
public function method(array $data): Foo|parent {}
}

?>
--EXPECTF--
Fatal error: Duplicate type Foo is redundant in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
Relative class type parent resolving to an existing entry (before variation)
--FILE--
<?php

class Foo {
public function method(array $data) {}
}
class Bar extends Foo {
public function method(array $data): parent|Foo {}
}

?>
--EXPECTF--
Fatal error: Duplicate type Foo is redundant in %s on line %d
Loading
Loading