Skip to content

Commit b268631

Browse files
committed
Support extending from generic base classes / parent interfaces
1 parent 9110e0c commit b268631

File tree

3 files changed

+46
-1
lines changed

3 files changed

+46
-1
lines changed

ChangeLog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ XP generics for PHP - ChangeLog
33

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

6+
* Supported extending from generic base classes / parent interfaces
7+
Requires https://github.com/xp-framework/core/releases/tag/v11.4.6
8+
(@thekid)
69
* Added support for declaring and implementing generic interfaces
710
(@thekid)
811

src/main/php/lang/ast/syntax/php/Generics.class.php

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,15 @@ public function setup($language, $emitter) {
214214
if ($node->name instanceof IsGeneric) {
215215
$values= [];
216216

217+
// Rewrite if parent class is generic
218+
if ($node->parent instanceof IsGeneric) {
219+
$values[]= [
220+
new Literal("'parent'"),
221+
new Literal("'".self::components($node->parent->components)."'")
222+
];
223+
$node->parent= $node->parent->base;
224+
}
225+
217226
// Rewrite if any of the interfaces is generic
218227
$implements= [0, []];
219228
foreach ($node->implements as $i => &$interface) {
@@ -233,7 +242,22 @@ public function setup($language, $emitter) {
233242
});
234243
$emitter->transform('interface', function($codegen, $node) {
235244
if ($node->name instanceof IsGeneric) {
236-
return self::type($node, []);
245+
$values= [];
246+
247+
// Rewrite if any of the parent interfaces is generic
248+
$implements= [0, []];
249+
foreach ($node->parents as $i => &$interface) {
250+
if ($interface instanceof IsGeneric) {
251+
$implements[1][]= [null, new Literal("'".self::components($interface->components)."'")];
252+
$implements[0]= true;
253+
$interface= $interface->base;
254+
} else {
255+
$implements[1][]= [null, new Literal('null')];
256+
}
257+
}
258+
$implements[0] && $values[]= [new Literal("'extends'"), new ArrayLiteral($implements[1])];
259+
260+
return self::type($node, $values);
237261
}
238262
return $node;
239263
});

src/test/php/lang/ast/syntax/php/unittest/GenericsTest.class.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,24 @@ public function implements_generic_interface() {
4545
Assert::equals([$c], $t->newGenericType([$c])->getInterfaces()[0]->genericArguments());
4646
}
4747

48+
#[Test]
49+
public function extends_generic_base_class() {
50+
$i= $this->type('abstract class <T><E> { }');
51+
$t= $this->type('class <T><E> extends '.$i->getName().'<E> { }');
52+
53+
$c= Primitive::$STRING;
54+
Assert::equals([$c], $t->newGenericType([$c])->getParentclass()->genericArguments());
55+
}
56+
57+
#[Test]
58+
public function extends_generic_interface() {
59+
$i= $this->type('interface <T><E> { }');
60+
$t= $this->type('interface <T><E> extends '.$i->getName().'<E> { }');
61+
62+
$c= Primitive::$STRING;
63+
Assert::equals([$c], $t->newGenericType([$c])->getInterfaces()[0]->genericArguments());
64+
}
65+
4866
#[Test]
4967
public function new_creates_generic_types() {
5068
$r= $this->run('class <T><E> {

0 commit comments

Comments
 (0)