Skip to content

Generics experimentation #3

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

Closed
wants to merge 13 commits into from
2 changes: 1 addition & 1 deletion Zend/tests/bug77530.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ echo (2)::class;

?>
--EXPECTF--
Fatal error: Illegal class name in %s on line %d
Fatal error: Cannot use ::class with dynamic class name in %s on line %d
20 changes: 20 additions & 0 deletions Zend/tests/generics/basic.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--TEST--
Basic generic class declaration
--FILE--
<?php

interface I<T> {
}

class C<T> {
}

final class F<T> {
}

trait T<P> {
}

?>
--EXPECT--

11 changes: 11 additions & 0 deletions Zend/tests/generics/duplicate_generic_param.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--TEST--
Duplicate generic parameter name
--FILE--
<?php

class Test<T, T> {
}

?>
--EXPECTF--
Fatal error: Duplicate generic parameter T in %s on line %d
73 changes: 73 additions & 0 deletions Zend/tests/generics/generic_param_with_over_types.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
--TEST--
Combining a generic parameter with other types
--FILE--
<?php

abstract class AbstractTest1<T> {
public ?T $prop;
public function method(?T $param) {
var_dump($param);
}
}
class ConcreteTest1 extends AbstractTest1<array> {}

$obj = new ConcreteTest1;
$obj->method([]);
$obj->method(null);
try {
$obj->method("string");
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}

echo "\n";

abstract class AbstractTest2<T> {
public T|int $prop;
public function method(T|int $param) {
var_dump($param);
}
}
class ConcreteTest2 extends AbstractTest2<array> {}

$obj = new ConcreteTest2;
$obj->method([]);
$obj->method(42);
$obj->method("42");

echo "\n";

abstract class AbstractTest3<T> {
public T|stdClass $prop;
public function method(T|stdClass $param) {
var_dump($param);
}
}
class ConcreteTest3 extends AbstractTest3<array> {}

$obj = new ConcreteTest3;
$obj->method([]);
$obj->method(new stdClass);
try {
$obj->method("string");
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECTF--
array(0) {
}
NULL
Argument 1 passed to AbstractTest1::method() must be of type ?T (where T = array), string given, called in %s on line %d

array(0) {
}
int(42)
int(42)

array(0) {
}
object(stdClass)#3 (0) {
}
Argument 1 passed to AbstractTest3::method() must be of type T|stdClass (where TODO), string given, called in %s on line %d
66 changes: 66 additions & 0 deletions Zend/tests/generics/inheritance_bind_parent_param.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
--TEST--
Bind direct parent parameter during inheritance
--FILE--
<?php

abstract class WithParam<T> {
public T $prop;

public function method(T $param) {
var_dump($param);
}
}

class ConcreteInt extends WithParam<int> {
}

class ConcreteStdClass extends WithParam<stdClass> {
}

class ConcreteSelf extends WithParam<self> {
}

$obj = new ConcreteInt;
$obj->method(42);
$obj->prop = 42;
var_dump($obj->prop);

try {
$obj->method("string");
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
$obj->prop = "string";
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}

$obj = new ConcreteStdClass;
$obj->method(new stdClass);
//$obj->prop = new stdClass;
try {
$obj->method("string");
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}

/* TODO: This broke -- "self" resolves to WithParam here.
$obj = new ConcreteSelf;
$obj->method($obj);
try {
$obj->method(new stdClass);
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
*/

?>
--EXPECTF--
int(42)
int(42)
Argument 1 passed to WithParam::method() must be of type T (where T = int), string given, called in %s on line %d
Cannot assign string to property WithParam::$prop of type T
object(stdClass)#1 (0) {
}
Argument 1 passed to WithParam::method() must be of type T (where T = stdClass), string given, called in %s on line %d
87 changes: 87 additions & 0 deletions Zend/tests/generics/inheritance_bind_parent_param_2.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
--TEST--
Bind multiple parent parameters during inheritance
--FILE--
<?php

abstract class WithParams<T1, T2> {
public function method(T1 $param1, T2 $param2) {
var_dump($param1);
var_dump($param2);
}
}

abstract class WithSameParam<T> extends WithParams<T, T> {
public function method2(T $param) {
var_dump($param);
}
}

abstract class WithOneFixedParam<T> extends WithParams<int, T> {
public function method2(T $param) {
var_dump($param);
}
}

abstract class WithFirstNullableParam<T> extends WithParams<?T, T> {
}

class ConcreteIntInt extends WithSameParam<int> {
}

class ConcreteIntString extends WithOneFixedParam<string> {
}

class ConcreteNullableIntInt extends WithFirstNullableParam<int> {
}

$obj = new ConcreteIntInt;
$obj->method(42, 42);
$obj->method2(42);

try {
$obj->method("string", "string");
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
$obj->method2("string");
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}

echo "\n";
$obj = new ConcreteIntString;
$obj->method(42, "string");
$obj->method2("string");

try {
$obj->method("string", 42);
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
try {
$obj->method2(42);
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}

echo "\n";
$obj = new ConcreteNullableIntInt;
$obj->method(null, 42);

?>
--EXPECTF--
int(42)
int(42)
int(42)
Argument 1 passed to WithParams::method() must be of type T1 (where T1 = int), string given, called in %s on line %d
Argument 1 passed to WithSameParam::method2() must be of type T (where T = int), string given, called in %s on line %d

int(42)
string(6) "string"
string(6) "string"
Argument 1 passed to WithParams::method() must be of type T1 (where T1 = int), string given, called in %s on line %d
string(2) "42"

NULL
int(42)
30 changes: 30 additions & 0 deletions Zend/tests/generics/inheritance_bind_passthru_parent_param.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--TEST--
Bind parent parameter passed through to grandparent during inheritance
--FILE--
<?php

abstract class WithParam<T> {
public function method(T $param) {
var_dump($param);
}
}

abstract class WithParam2<T> extends WithParam<T> {
}

class Concrete extends WithParam2<int> {
}

$obj = new Concrete;
$obj->method(42);

try {
$obj->method("string");
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECTF--
int(42)
Argument 1 passed to WithParam::method() must be of type T (where T = int), string given, called in %s on line %d
49 changes: 49 additions & 0 deletions Zend/tests/generics/inheritance_default_param.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
--TEST--
Defaulted type parameters during inheritance
--FILE--
<?php

abstract class WithSimpleDefault<T1, T2 = int> {
public function method(T1 $param1, T2 $param2) {
var_dump($param1);
var_dump($param2);
}
}

class Concrete extends WithSimpleDefault<string> {
}

abstract class WithPrevParamDefault<T1, T2 = T1> {
public function method(T1 $param1, T2 $param2) {
var_dump($param1);
var_dump($param2);
}
}

class Concrete2 extends WithPrevParamDefault<string> {
}

$obj = new Concrete;
$obj->method("string", 42);
try {
$obj->method(42, "string");
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}

$obj = new Concrete2;
$obj->method("string", "string");
try {
$obj->method([], []);
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECTF--
string(6) "string"
int(42)
Argument 2 passed to WithSimpleDefault::method() must be of type T2 (where T2 = int), string given, called in %s on line %d
string(6) "string"
string(6) "string"
Argument 1 passed to WithPrevParamDefault::method() must be of type T1 (where T1 = string), array given, called in %s on line %d
16 changes: 16 additions & 0 deletions Zend/tests/generics/inheritance_signature_check.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
Validating signatures involving generic parameters
--FILE--
<?php

abstract class Test<T> {
public function method(T $param) {}
}

class Test2 extends Test<int> {
public function method(string $param) {}
}

?>
--EXPECTF--
Fatal error: Declaration of Test2::method(string $param) must be compatible with Test::method(T $param) in %s on line %d
25 changes: 25 additions & 0 deletions Zend/tests/generics/inheritance_signature_check_2.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
--TEST--
Validating signatures involving generic parameters
--FILE--
<?php

abstract class Test<T> {
public function method(T $param): T {}
}

class Test2 extends Test<int> {
public function method(int $param): int {}
}

class Test3<T> extends Test<T> {
public function method(T $param): T {}
}

class Test4<T> extends Test<T> {
public function method(?T $param): T {}
}

?>
===DONE===
--EXPECT--
===DONE===
Loading