Skip to content

Commit a286529

Browse files
committed
Support instantiation of concrete generic classes
1 parent 1b326db commit a286529

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1009
-541
lines changed

Zend/tests/generics/generic_param_with_over_types.phpt

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,56 @@ try {
5454
echo $e->getMessage(), "\n";
5555
}
5656

57+
echo "\n";
58+
59+
class ConcreteTest4<T> {
60+
public ?T $prop;
61+
public function method(?T $param) {
62+
var_dump($param);
63+
}
64+
}
65+
66+
$obj = new ConcreteTest4<array>;
67+
$obj->method([]);
68+
$obj->method(null);
69+
try {
70+
$obj->method("string");
71+
} catch (TypeError $e) {
72+
echo $e->getMessage(), "\n";
73+
}
74+
75+
echo "\n";
76+
77+
class ConcreteTest5<T> {
78+
public T|int $prop;
79+
public function method(T|int $param) {
80+
var_dump($param);
81+
}
82+
}
83+
84+
$obj = new ConcreteTest5<array>;
85+
$obj->method([]);
86+
$obj->method(42);
87+
$obj->method("42");
88+
89+
echo "\n";
90+
91+
class ConcreteTest6<T> {
92+
public T|stdClass $prop;
93+
public function method(T|stdClass $param) {
94+
var_dump($param);
95+
}
96+
}
97+
98+
$obj = new ConcreteTest6<array>;
99+
$obj->method([]);
100+
$obj->method(new stdClass);
101+
try {
102+
$obj->method("string");
103+
} catch (TypeError $e) {
104+
echo $e->getMessage(), "\n";
105+
}
106+
57107
?>
58108
--EXPECTF--
59109
array(0) {
@@ -71,3 +121,19 @@ array(0) {
71121
object(stdClass)#3 (0) {
72122
}
73123
AbstractTest3::method(): Argument #1 ($param) must be of type T|stdClass (where T = array), string given, called in %s on line %d
124+
125+
array(0) {
126+
}
127+
NULL
128+
ConcreteTest4::method(): Argument #1 ($param) must be of type ?T (where T = array), string given, called in %s on line %d
129+
130+
array(0) {
131+
}
132+
int(42)
133+
int(42)
134+
135+
array(0) {
136+
}
137+
object(stdClass)#3 (0) {
138+
}
139+
ConcreteTest6::method(): Argument #1 ($param) must be of type T|stdClass (where T = array), string given, called in %s on line %d

Zend/tests/generics/type_params_in_types.phpt

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ class ConcreteIntDefaulted extends AbstractDefaulted {
2929
class ConcreteStringDefaulted extends AbstractDefaulted<string> {
3030
}
3131

32+
class ConcretePassthru<T> {
33+
public function method(T $param) {
34+
var_dump($param);
35+
}
36+
}
37+
38+
class ConcreteDefaulted<T=int> {
39+
public function method(T $param) {
40+
var_dump($param);
41+
}
42+
}
43+
3244
function test(AbstractTest<int> $test) {
3345
$test->method(42);
3446
}
@@ -63,6 +75,40 @@ try {
6375
echo $e->getMessage(), "\n";
6476
}
6577

78+
function test4(ConcretePassthru<int> $test) {
79+
$test->method(42);
80+
}
81+
82+
test4(new ConcretePassthru<int>);
83+
try {
84+
test4(new ConcretePassthru<string>);
85+
} catch (TypeError $e) {
86+
echo $e->getMessage(), "\n";
87+
}
88+
89+
function test5(ConcreteDefaulted $test) {
90+
$test->method(42);
91+
}
92+
93+
function test6(ConcreteDefaulted<int> $test) {
94+
$test->method(42);
95+
}
96+
97+
test5(new ConcreteDefaulted);
98+
test5(new ConcreteDefaulted<int>);
99+
test6(new ConcreteDefaulted);
100+
test6(new ConcreteDefaulted<int>);
101+
try {
102+
test5(new ConcreteDefaulted<string>);
103+
} catch (TypeError $e) {
104+
echo $e->getMessage(), "\n";
105+
}
106+
try {
107+
test6(new ConcreteDefaulted<string>);
108+
} catch (TypeError $e) {
109+
echo $e->getMessage(), "\n";
110+
}
111+
66112
?>
67113
--EXPECTF--
68114
int(42)
@@ -73,3 +119,11 @@ int(42)
73119
int(42)
74120
test2(): Argument #1 ($test) must be of type AbstractDefaulted, ConcreteStringDefaulted given, called in %s on line %d
75121
test3(): Argument #1 ($test) must be of type AbstractDefaulted<int>, ConcreteStringDefaulted given, called in %s on line %d
122+
int(42)
123+
test4(): Argument #1 ($test) must be of type ConcretePassthru<int>, ConcretePassthru given, called in %s on line %d
124+
int(42)
125+
int(42)
126+
int(42)
127+
int(42)
128+
test5(): Argument #1 ($test) must be of type ConcreteDefaulted, ConcreteDefaulted given, called in %s on line %d
129+
test6(): Argument #1 ($test) must be of type ConcreteDefaulted<int>, ConcreteDefaulted given, called in %s on line %d
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
--TEST--
2+
Test instantiation of class with unbound params
3+
--FILE--
4+
<?php
5+
6+
class Test1<T> {
7+
public function method(T $param) {
8+
var_dump($param);
9+
}
10+
}
11+
12+
class Test2<T,U> {
13+
public function method(T $t, U $u) {
14+
var_dump($t, $u);
15+
}
16+
}
17+
18+
class Test3<T=int> {
19+
public function method(T $param) {
20+
var_dump($param);
21+
}
22+
}
23+
24+
class AbstractTest4<T,U> {
25+
public function method1(T $t, U $u) {
26+
var_dump($t, $u);
27+
}
28+
}
29+
30+
class Test4<T> extends AbstractTest4<T,string> {
31+
public function method2(T $param) {
32+
var_dump($param);
33+
}
34+
}
35+
36+
$test = new Test1<int>();
37+
$test->method(42);
38+
try {
39+
$test->method([]);
40+
} catch (TypeError $e) {
41+
echo $e->getMessage(), "\n";
42+
}
43+
44+
echo "\n";
45+
46+
$test = new Test2<int,string>();
47+
$test->method(42,'hello');
48+
try {
49+
$test->method([],'hello');
50+
} catch (TypeError $e) {
51+
echo $e->getMessage(), "\n";
52+
}
53+
try {
54+
$test->method(42,[]);
55+
} catch (TypeError $e) {
56+
echo $e->getMessage(), "\n";
57+
}
58+
59+
echo "\n";
60+
61+
$test = new Test3();
62+
$test->method(42);
63+
try {
64+
$test->method([]);
65+
} catch (TypeError $e) {
66+
echo $e->getMessage(), "\n";
67+
}
68+
69+
echo "\n";
70+
71+
$test = new Test3<string>();
72+
$test->method('hello');
73+
try {
74+
$test->method([]);
75+
} catch (TypeError $e) {
76+
echo $e->getMessage(), "\n";
77+
}
78+
79+
echo "\n";
80+
81+
$test = new Test4<int>();
82+
$test->method1(42, 'hello');
83+
$test->method2(42);
84+
try {
85+
$test->method1([], 'hello');
86+
} catch (TypeError $e) {
87+
echo $e->getMessage(), "\n";
88+
}
89+
try {
90+
$test->method1(42,[]);
91+
} catch (TypeError $e) {
92+
echo $e->getMessage(), "\n";
93+
}
94+
try {
95+
$test->method2([]);
96+
} catch (TypeError $e) {
97+
echo $e->getMessage(), "\n";
98+
}
99+
--EXPECTF--
100+
int(42)
101+
Test1::method(): Argument #1 ($param) must be of type T (where T = int), array given, called in %s on line %d
102+
103+
int(42)
104+
string(5) "hello"
105+
Test2::method(): Argument #1 ($t) must be of type T (where T = int), array given, called in %s on line %d
106+
Test2::method(): Argument #2 ($u) must be of type U (where U = string), array given, called in %s on line %d
107+
108+
int(42)
109+
Test3::method(): Argument #1 ($param) must be of type T (where T = int), array given, called in %s on line %d
110+
111+
string(5) "hello"
112+
Test3::method(): Argument #1 ($param) must be of type T (where T = string), array given, called in %s on line %d
113+
114+
int(42)
115+
string(5) "hello"
116+
int(42)
117+
AbstractTest4::method1(): Argument #1 ($t) must be of type T (where T = int), array given, called in %s on line %d
118+
AbstractTest4::method1(): Argument #2 ($u) must be of type U (where U = string), array given, called in %s on line %d
119+
Test4::method2(): Argument #1 ($param) must be of type T (where T = int), array given, called in %s on line %d

Zend/zend.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "zend_exceptions.h"
2727
#include "zend_builtin_functions.h"
2828
#include "zend_ini.h"
29+
#include "zend_types.h"
2930
#include "zend_vm.h"
3031
#include "zend_dtrace.h"
3132
#include "zend_virtual_cwd.h"
@@ -556,13 +557,13 @@ static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent) /*
556557
smart_str_appends(buf, ZSTR_VAL(class_name));
557558
zend_string_release_ex(class_name, 0);
558559

559-
if (!(zobj->ce->ce_flags & ZEND_ACC_ENUM)) {
560+
if (!(OBJ_CE(zobj)->ce_flags & ZEND_ACC_ENUM)) {
560561
smart_str_appends(buf, " Object\n");
561562
} else {
562563
smart_str_appends(buf, " Enum");
563-
if (zobj->ce->enum_backing_type != IS_UNDEF) {
564+
if (OBJ_CE(zobj)->enum_backing_type != IS_UNDEF) {
564565
smart_str_appendc(buf, ':');
565-
smart_str_appends(buf, zend_get_type_by_const(zobj->ce->enum_backing_type));
566+
smart_str_appends(buf, zend_get_type_by_const(OBJ_CE(zobj)->enum_backing_type));
566567
}
567568
smart_str_appendc(buf, '\n');
568569
}

0 commit comments

Comments
 (0)