Skip to content

Commit 7e4a3bd

Browse files
committed
Improve variance implementation
This work is based off Nikita's review. Notably: - Implement contravariance in terms of covariance - Improve support for non-consecutive type decls - Adds _inheritance_status enum
1 parent 039f71b commit 7e4a3bd

8 files changed

+143
-134
lines changed

Zend/tests/bug76451.phpt

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
--TEST--
2-
Aliases during inheritance type checks affected by opcache
3-
--INI--
4-
opcache.enable=1
5-
opcache.enable_cli=1
6-
opcache.optimization_level=-1
7-
--SKIPIF--
8-
<?php if (!extension_loaded('Zend OPcache') || php_sapi_name() != "cli") die("skip CLI only"); ?>
2+
Aliases during inheritance type checks (affected by opcache)
93
--FILE--
104
<?php
115
require __DIR__ . "/bug76451.inc";
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
non-consecutive type decls are still checked for variance
3+
--FILE--
4+
<?php
5+
6+
interface A {
7+
function m(): A;
8+
}
9+
10+
// "echo 'hi';" is not a declaration statement
11+
echo 'hi';
12+
13+
class B implements A {
14+
function m(): B { return $this; }
15+
}
16+
17+
echo get_class((new B())->m());
18+
?>
19+
--EXPECT--
20+
hiB
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
non-consecutive type decls are still checked for variance
3+
--FILE--
4+
<?php
5+
6+
interface A {
7+
function m(): A;
8+
}
9+
10+
// "echo 'hi';" is not a declaration statement
11+
echo 'hi';
12+
13+
class B implements A {
14+
function m(): stdClass { return $this; }
15+
}
16+
17+
echo get_class((new B())->m());
18+
?>
19+
--EXPECTF--
20+
hi
21+
Fatal error: Declaration of B::m(): stdClass must be compatible with A::m(): A in %s on line %d

Zend/tests/typehints/undefined_type_during_variance_check_04.phpt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,3 @@ class Y implements X {
1313
?>
1414
--EXPECTF--
1515
Fatal error: Declaration of Y::m(UndefinedA $z) must be compatible with X::m(stdClass $z) in %s on line %d
16-

Zend/zend_compile.c

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4086,7 +4086,6 @@ void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type) /* {{
40864086
}
40874087
/* }}} */
40884088

4089-
40904089
static
40914090
void _backup_unverified_variance_types(HashTable *unverified_types,
40924091
HashTable **prev_unverified_types)
@@ -8091,8 +8090,9 @@ static zend_bool _is_not_decl_stmt(zend_ast *ast) {
80918090
if (ast) {
80928091
/* todo: what else should be considered a decl stmt? */
80938092
switch (ast->kind) {
8094-
case ZEND_AST_FUNC_DECL:
80958093
case ZEND_AST_CLASS:
8094+
case ZEND_AST_CONST_DECL:
8095+
case ZEND_AST_FUNC_DECL:
80968096
return 0;
80978097

80988098
default:
@@ -8120,11 +8120,10 @@ void zend_compile_top_stmt(zend_ast *ast) /* {{{ */
81208120
}
81218121

81228122
if (ast->kind == ZEND_AST_STMT_LIST) {
8123-
zend_ast_list *list = zend_ast_get_list(ast);
8124-
zend_ast **begin = list->child;
8125-
zend_ast **end = begin + list->children;
8123+
zend_ast_list *const list = zend_ast_get_list(ast);
8124+
zend_ast ** const begin = list->child;
8125+
zend_ast ** const end = begin + list->children;
81268126
zend_ast **first_decl = _ast_find(begin, end, &_is_type_decl);
8127-
zend_ast **last_decl = _ast_find(first_decl, end, &_is_not_decl_stmt);
81288127
zend_ast **p;
81298128

81308129
/* Compile opcodes before first type decl */
@@ -8133,7 +8132,8 @@ void zend_compile_top_stmt(zend_ast *ast) /* {{{ */
81338132
}
81348133

81358134
/* Compile decl stmts */
8136-
{
8135+
while (first_decl != end) {
8136+
zend_ast **last_decl = _ast_find(first_decl, end, &_is_not_decl_stmt);
81378137
HashTable unverified_types;
81388138
HashTable *prev_unverified_types;
81398139
_backup_unverified_variance_types(&unverified_types, &prev_unverified_types);
@@ -8146,12 +8146,14 @@ void zend_compile_top_stmt(zend_ast *ast) /* {{{ */
81468146

81478147
zend_hash_destroy(&unverified_types);
81488148
CG(unverified_types) = prev_unverified_types;
8149-
}
81508149

8151-
/* Compile remainder */
8152-
/* todo: loop to catch any non-consecutive type declarations */
8153-
for (p = last_decl; p < end; ++p) {
8154-
zend_compile_top_stmt(*p);
8150+
/* There can be non-consecutive type decls, so continue searching */
8151+
first_decl = _ast_find(last_decl, end, &_is_type_decl);
8152+
8153+
/* Compile any stmts between the two type decls (or the end) */
8154+
for (p = last_decl; p < first_decl; ++p) {
8155+
zend_compile_top_stmt(*p);
8156+
}
81558157
}
81568158
return;
81578159
}

0 commit comments

Comments
 (0)