Skip to content

Commit a0892eb

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 ad67313 commit a0892eb

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
@@ -3959,7 +3959,6 @@ void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type) /* {{
39593959
}
39603960
/* }}} */
39613961

3962-
39633962
static
39643963
void _backup_unverified_variance_types(HashTable *unverified_types,
39653964
HashTable **prev_unverified_types)
@@ -8138,8 +8137,9 @@ static zend_bool _is_not_decl_stmt(zend_ast *ast) {
81388137
if (ast) {
81398138
/* todo: what else should be considered a decl stmt? */
81408139
switch (ast->kind) {
8141-
case ZEND_AST_FUNC_DECL:
81428140
case ZEND_AST_CLASS:
8141+
case ZEND_AST_CONST_DECL:
8142+
case ZEND_AST_FUNC_DECL:
81438143
return 0;
81448144

81458145
default:
@@ -8167,11 +8167,10 @@ void zend_compile_top_stmt(zend_ast *ast) /* {{{ */
81678167
}
81688168

81698169
if (ast->kind == ZEND_AST_STMT_LIST) {
8170-
zend_ast_list *list = zend_ast_get_list(ast);
8171-
zend_ast **begin = list->child;
8172-
zend_ast **end = begin + list->children;
8170+
zend_ast_list *const list = zend_ast_get_list(ast);
8171+
zend_ast ** const begin = list->child;
8172+
zend_ast ** const end = begin + list->children;
81738173
zend_ast **first_decl = _ast_find(begin, end, &_is_type_decl);
8174-
zend_ast **last_decl = _ast_find(first_decl, end, &_is_not_decl_stmt);
81758174
zend_ast **p;
81768175

81778176
/* Compile opcodes before first type decl */
@@ -8180,7 +8179,8 @@ void zend_compile_top_stmt(zend_ast *ast) /* {{{ */
81808179
}
81818180

81828181
/* Compile decl stmts */
8183-
{
8182+
while (first_decl != end) {
8183+
zend_ast **last_decl = _ast_find(first_decl, end, &_is_not_decl_stmt);
81848184
HashTable unverified_types;
81858185
HashTable *prev_unverified_types;
81868186
_backup_unverified_variance_types(&unverified_types, &prev_unverified_types);
@@ -8193,12 +8193,14 @@ void zend_compile_top_stmt(zend_ast *ast) /* {{{ */
81938193

81948194
zend_hash_destroy(&unverified_types);
81958195
CG(unverified_types) = prev_unverified_types;
8196-
}
81978196

8198-
/* Compile remainder */
8199-
/* todo: loop to catch any non-consecutive type declarations */
8200-
for (p = last_decl; p < end; ++p) {
8201-
zend_compile_top_stmt(*p);
8197+
/* There can be non-consecutive type decls, so continue searching */
8198+
first_decl = _ast_find(last_decl, end, &_is_type_decl);
8199+
8200+
/* Compile any stmts between the two type decls (or the end) */
8201+
for (p = last_decl; p < first_decl; ++p) {
8202+
zend_compile_top_stmt(*p);
8203+
}
82028204
}
82038205
return;
82048206
}

0 commit comments

Comments
 (0)