Skip to content

Commit dd46be2

Browse files
committed
Fix redeclaration of method, and other issues
1 parent 9257164 commit dd46be2

12 files changed

+263
-50
lines changed

Zend/tests/type_declarations/abstract_generics/extended_interface_redeclares_method.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ interface I<T> {
77
public function foo(T $param): int;
88
}
99

10-
interface J<S> extends I<S> {
11-
public function foo(S $param): int;
10+
interface J extends I<float> {
11+
public function foo(float $param): int;
1212
}
1313

1414
?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Abstract generic type behaviour in extended interface which redeclares method generic type contravariant
3+
--FILE--
4+
<?php
5+
6+
interface I<T> {
7+
public function foo(T $param): int;
8+
}
9+
10+
interface J<S> extends I<S> {
11+
public function foo(S $param): int;
12+
}
13+
14+
?>
15+
DONE
16+
--EXPECT--
17+
DONE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Abstract generic type behaviour in extended interface which redeclares method generic type covariant
3+
--FILE--
4+
<?php
5+
6+
interface I<T> {
7+
public function foo(int $param): T;
8+
}
9+
10+
interface J<S> extends I<S> {
11+
public function foo(int $param): S;
12+
}
13+
14+
?>
15+
DONE
16+
--EXPECT--
17+
DONE
18+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Redeclaring a method that has a concrete type into a generic type (contravariance)
3+
--FILE--
4+
<?php
5+
6+
interface I {
7+
public function foo(int $param): int;
8+
}
9+
10+
interface J<S> extends I {
11+
public function foo(S $param): int;
12+
}
13+
14+
?>
15+
DONE
16+
--EXPECTF--
17+
Fatal error: Declaration of J<S : mixed>::foo(<S> $param): int must be compatible with I::foo(int $param): int %s on line %d
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Redeclaring a method that has a concrete type into a generic type (covariance)
3+
--FILE--
4+
<?php
5+
6+
interface I {
7+
public function foo(int $param): int;
8+
}
9+
10+
interface J<S> extends I {
11+
public function foo(int $param): S;
12+
}
13+
14+
?>
15+
DONE
16+
--EXPECTF--
17+
Fatal error: Declaration of J<S : mixed>::foo(int $param): <S> must be compatible with I::foo(int $param): int %s on line %d
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Abstract generic type behaviour in extended interface which redeclares method but does not use bound generic type (contravariance)
3+
--FILE--
4+
<?php
5+
6+
interface I<T> {
7+
public function foo(T $param): int;
8+
}
9+
10+
interface J<S> extends I<S> {
11+
public function foo(int $param): int;
12+
}
13+
14+
?>
15+
DONE
16+
--EXPECTF--
17+
Fatal error: Declaration of J<S : mixed>::foo(int $param): int must be compatible with I<T : <S>>::foo(<T : <S>> $param): int %s on line %d
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Abstract generic type behaviour in extended interface which redeclares method but does not use bound generic type (covariance)
3+
--FILE--
4+
<?php
5+
6+
interface I<T> {
7+
public function foo(int $param): T;
8+
}
9+
10+
interface J<S> extends I<S> {
11+
public function foo(int $param): int;
12+
}
13+
14+
?>
15+
DONE
16+
--EXPECTF--
17+
Fatal error: Declaration of J<S : mixed>::foo(int $param): int must be compatible with I<T : <S>>::foo(int $param): <T : <S>> in %s on line %d

Zend/tests/type_declarations/abstract_generics/multiple_abstract_generic_type-error.phpt renamed to Zend/tests/type_declarations/abstract_generics/variance/multiple_abstract_generic_type-error.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ class C implements I<string, int> {
2020

2121
?>
2222
--EXPECTF--
23-
Fatal error: Declaration of C::set(int $key, string $value): void must be compatible with I::set(<K : string> $key, <V : int> $value): void in %s on line %d
23+
Fatal error: Declaration of C::set(int $key, string $value): void must be compatible with I<K : string, V : int>::set(<K : string> $key, <V : int> $value): void in %s on line %d

Zend/zend_compile.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,7 +1389,7 @@ static zend_string *add_type_string(zend_string *type, zend_string *new_type, bo
13891389
return result;
13901390
}
13911391

1392-
static zend_string *resolve_class_name(zend_string *name, zend_class_entry *scope) {
1392+
static zend_string *resolve_class_name(zend_string *name, const zend_class_entry *scope) {
13931393
if (scope) {
13941394
if (zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_SELF))) {
13951395
name = scope->name;
@@ -1409,7 +1409,7 @@ static zend_string *resolve_class_name(zend_string *name, zend_class_entry *scop
14091409
}
14101410

14111411
static zend_string *add_intersection_type(zend_string *str,
1412-
const zend_type_list *intersection_type_list, zend_class_entry *scope,
1412+
const zend_type_list *intersection_type_list, const zend_class_entry *scope,
14131413
bool is_bracketed)
14141414
{
14151415
const zend_type *single_type;
@@ -1434,11 +1434,21 @@ static zend_string *add_intersection_type(zend_string *str,
14341434
return str;
14351435
}
14361436

1437-
static zend_string* resolve_bound_generic_type(zend_string *type_name, zend_class_entry *scope, const HashTable *bound_types) {
1437+
static zend_string* resolve_bound_generic_type(zend_string *type_name, const zend_class_entry *scope, const HashTable *bound_types) {
1438+
if (bound_types == NULL) {
1439+
const size_t len = ZSTR_LEN(type_name) + strlen("<>");
1440+
zend_string *result = zend_string_alloc(len, 0);
1441+
ZSTR_VAL(result)[0] = '<';
1442+
memcpy(ZSTR_VAL(result) + strlen("<"), ZSTR_VAL(type_name), ZSTR_LEN(type_name));
1443+
ZSTR_VAL(result)[len-1] = '>';
1444+
ZSTR_VAL(result)[len] = '\0';
1445+
return result;
1446+
}
1447+
14381448
const zend_type *constraint = zend_hash_find_ptr(bound_types, type_name);
14391449
ZEND_ASSERT(constraint != NULL);
14401450

1441-
zend_string *constraint_type_str = zend_type_to_string_resolved(*constraint, scope, /* need the bound types? */NULL);
1451+
zend_string *constraint_type_str = zend_type_to_string_resolved(*constraint, scope, NULL);
14421452

14431453
size_t len = ZSTR_LEN(type_name) + ZSTR_LEN(constraint_type_str) + strlen("< : >");
14441454
zend_string *result = zend_string_alloc(len, 0);
@@ -1456,7 +1466,7 @@ static zend_string* resolve_bound_generic_type(zend_string *type_name, zend_clas
14561466
return result;
14571467
}
14581468

1459-
zend_string *zend_type_to_string_resolved(const zend_type type, zend_class_entry *scope, const HashTable *bound_types_to_scope) {
1469+
zend_string *zend_type_to_string_resolved(const zend_type type, const zend_class_entry *scope, const HashTable *bound_types_to_scope) {
14601470
zend_string *str = NULL;
14611471

14621472
/* Pure intersection type */
@@ -7042,7 +7052,8 @@ static zend_type zend_compile_single_typename(zend_ast *ast)
70427052
for (uint32_t generic_param_index = 0; generic_param_index < ce->num_generic_parameters; generic_param_index++) {
70437053
const zend_generic_parameter *generic_param = &ce->generic_parameters[generic_param_index];
70447054
if (zend_string_equals(type_name, generic_param->name)) {
7045-
return (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(type_name), /* allow null */ false, _ZEND_TYPE_GENERIC_PARAM_NAME_BIT);
7055+
// TODO Add ZEND_TYPE_INIT_GENERIC() macro that takes an index
7056+
return (zend_type) ZEND_TYPE_INIT_PTR(zend_string_copy(type_name), _ZEND_TYPE_GENERIC_PARAM_NAME_BIT, /* allow null */ false, 0);
70467057
}
70477058
}
70487059
}

Zend/zend_compile.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1014,7 +1014,7 @@ int ZEND_FASTCALL zendlex(zend_parser_stack_elem *elem);
10141014

10151015
void zend_assert_valid_class_name(const zend_string *const_name, const char *type);
10161016

1017-
zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scope, const HashTable *bound_types_to_scope);
1017+
zend_string *zend_type_to_string_resolved(zend_type type, const zend_class_entry *scope, const HashTable *bound_types_to_scope);
10181018
ZEND_API zend_string *zend_type_to_string(zend_type type);
10191019

10201020
/* BEGIN: OPCODES */

0 commit comments

Comments
 (0)