Skip to content

Commit 581bc1b

Browse files
morrisonlevinikic
authored andcommitted
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 0ad3f8d commit 581bc1b

8 files changed

+143
-133
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 & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8186,8 +8186,9 @@ static zend_bool _is_not_decl_stmt(zend_ast *ast) {
81868186
if (ast) {
81878187
/* todo: what else should be considered a decl stmt? */
81888188
switch (ast->kind) {
8189-
case ZEND_AST_FUNC_DECL:
81908189
case ZEND_AST_CLASS:
8190+
case ZEND_AST_CONST_DECL:
8191+
case ZEND_AST_FUNC_DECL:
81918192
return 0;
81928193

81938194
default:
@@ -8215,11 +8216,10 @@ void zend_compile_top_stmt(zend_ast *ast) /* {{{ */
82158216
}
82168217

82178218
if (ast->kind == ZEND_AST_STMT_LIST) {
8218-
zend_ast_list *list = zend_ast_get_list(ast);
8219-
zend_ast **begin = list->child;
8220-
zend_ast **end = begin + list->children;
8219+
zend_ast_list *const list = zend_ast_get_list(ast);
8220+
zend_ast ** const begin = list->child;
8221+
zend_ast ** const end = begin + list->children;
82218222
zend_ast **first_decl = _ast_find(begin, end, &_is_type_decl);
8222-
zend_ast **last_decl = _ast_find(first_decl, end, &_is_not_decl_stmt);
82238223
zend_ast **p;
82248224

82258225
/* Compile opcodes before first type decl */
@@ -8228,7 +8228,8 @@ void zend_compile_top_stmt(zend_ast *ast) /* {{{ */
82288228
}
82298229

82308230
/* Compile decl stmts */
8231-
{
8231+
while (first_decl != end) {
8232+
zend_ast **last_decl = _ast_find(first_decl, end, &_is_not_decl_stmt);
82328233
HashTable unverified_types;
82338234
HashTable *prev_unverified_types;
82348235
_backup_unverified_variance_types(&unverified_types, &prev_unverified_types);
@@ -8241,12 +8242,14 @@ void zend_compile_top_stmt(zend_ast *ast) /* {{{ */
82418242

82428243
zend_hash_destroy(&unverified_types);
82438244
CG(unverified_types) = prev_unverified_types;
8244-
}
82458245

8246-
/* Compile remainder */
8247-
/* todo: loop to catch any non-consecutive type declarations */
8248-
for (p = last_decl; p < end; ++p) {
8249-
zend_compile_top_stmt(*p);
8246+
/* There can be non-consecutive type decls, so continue searching */
8247+
first_decl = _ast_find(last_decl, end, &_is_type_decl);
8248+
8249+
/* Compile any stmts between the two type decls (or the end) */
8250+
for (p = last_decl; p < first_decl; ++p) {
8251+
zend_compile_top_stmt(*p);
8252+
}
82508253
}
82518254
return;
82528255
}

0 commit comments

Comments
 (0)