Skip to content

Commit 9d3a948

Browse files
committed
Support more type decl locations for variance
1 parent 7e4a3bd commit 9d3a948

File tree

2 files changed

+91
-40
lines changed

2 files changed

+91
-40
lines changed

Zend/zend_compile.c

Lines changed: 65 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5349,12 +5349,72 @@ void zend_compile_declare(zend_ast *ast) /* {{{ */
53495349
}
53505350
/* }}} */
53515351

5352+
static zend_ast **_ast_find(zend_ast **begin, zend_ast **end,
5353+
zend_bool (*pred)(zend_ast *)) {
5354+
for (; begin < end; ++begin)
5355+
if (pred(*begin))
5356+
return begin;
5357+
return begin;
5358+
}
5359+
5360+
static zend_bool _is_type_decl(zend_ast *ast) {
5361+
return ast && ast->kind == ZEND_AST_CLASS;
5362+
}
5363+
5364+
static zend_bool _is_not_decl_stmt(zend_ast *ast) {
5365+
if (ast) {
5366+
/* todo: what else should be considered a decl stmt? */
5367+
switch (ast->kind) {
5368+
case ZEND_AST_CLASS:
5369+
case ZEND_AST_CONST_DECL:
5370+
case ZEND_AST_FUNC_DECL:
5371+
return 0;
5372+
5373+
default:
5374+
return 1;
5375+
}
5376+
}
5377+
5378+
/* todo: why are these sometimes null? */
5379+
return 0;
5380+
}
5381+
53525382
void zend_compile_stmt_list(zend_ast *ast) /* {{{ */
53535383
{
5354-
zend_ast_list *list = zend_ast_get_list(ast);
5355-
uint32_t i;
5356-
for (i = 0; i < list->children; ++i) {
5357-
zend_compile_stmt(list->child[i]);
5384+
zend_ast_list *const list = zend_ast_get_list(ast);
5385+
zend_ast ** const begin = list->child;
5386+
zend_ast ** const end = begin + list->children;
5387+
zend_ast **first_decl = _ast_find(begin, end, &_is_type_decl);
5388+
zend_ast **p;
5389+
5390+
/* Compile opcodes before first type decl */
5391+
for (p = begin; p < first_decl; ++p) {
5392+
zend_compile_stmt(*p);
5393+
}
5394+
5395+
/* Compile decl stmts */
5396+
while (first_decl != end) {
5397+
zend_ast **last_decl = _ast_find(first_decl, end, &_is_not_decl_stmt);
5398+
HashTable unverified_types;
5399+
HashTable *prev_unverified_types;
5400+
_backup_unverified_variance_types(&unverified_types, &prev_unverified_types);
5401+
5402+
for (p = first_decl; p < last_decl; ++p) {
5403+
zend_compile_stmt(*p);
5404+
}
5405+
5406+
_compile_verify_variance(&unverified_types);
5407+
5408+
zend_hash_destroy(&unverified_types);
5409+
CG(unverified_types) = prev_unverified_types;
5410+
5411+
/* There can be non-consecutive type decls, so continue searching */
5412+
first_decl = _ast_find(last_decl, end, &_is_type_decl);
5413+
5414+
/* Compile any stmts between the two type decls (or the end) */
5415+
for (p = last_decl; p < first_decl; ++p) {
5416+
zend_compile_stmt(*p);
5417+
}
53585418
}
53595419
}
53605420
/* }}} */
@@ -6401,7 +6461,7 @@ void zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
64016461
if (CG(unverified_types)) {
64026462
zend_hash_add_empty_element(CG(unverified_types), lcname);
64036463
} else {
6404-
// todo: figure out why it's null; need a caller (somewhere) to initialize, emit, and destroy the unverified types
6464+
ZEND_ASSERT(0 && "todo: find out why this is null");
64056465
}
64066466
}
64076467

@@ -8082,36 +8142,6 @@ void zend_const_expr_to_zval(zval *result, zend_ast *ast) /* {{{ */
80828142
}
80838143
/* }}} */
80848144

8085-
static zend_bool _is_type_decl(zend_ast *ast) {
8086-
return ast && ast->kind == ZEND_AST_CLASS;
8087-
}
8088-
8089-
static zend_bool _is_not_decl_stmt(zend_ast *ast) {
8090-
if (ast) {
8091-
/* todo: what else should be considered a decl stmt? */
8092-
switch (ast->kind) {
8093-
case ZEND_AST_CLASS:
8094-
case ZEND_AST_CONST_DECL:
8095-
case ZEND_AST_FUNC_DECL:
8096-
return 0;
8097-
8098-
default:
8099-
return 1;
8100-
}
8101-
}
8102-
8103-
/* todo: why are these sometimes null? */
8104-
return 0;
8105-
}
8106-
8107-
static zend_ast **_ast_find(zend_ast **begin, zend_ast **end,
8108-
zend_bool (*pred)(zend_ast *)) {
8109-
for (; begin < end; ++begin)
8110-
if (pred(*begin))
8111-
return begin;
8112-
return begin;
8113-
}
8114-
81158145
/* Same as compile_stmt, but with early binding */
81168146
void zend_compile_top_stmt(zend_ast *ast) /* {{{ */
81178147
{

Zend/zend_inheritance.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ static
357357
_inheritance_status zend_do_perform_implementation_check(const zend_function *fe, const zend_function *proto) /* {{{ */
358358
{
359359
uint32_t i, num_args;
360+
_inheritance_status status;
360361

361362
/* If it's a user function then arg_info == NULL means we don't have any parameters but
362363
* we still need to do the arg number checks. We are only willing to ignore this for internal
@@ -412,24 +413,45 @@ _inheritance_status zend_do_perform_implementation_check(const zend_function *fe
412413
}
413414
}
414415

416+
status = INHERITANCE_SUCCESS;
417+
415418
for (i = 0; i < num_args; i++) {
416419
zend_arg_info *fe_arg_info = &fe->common.arg_info[i];
417420
zend_arg_info *proto_arg_info = (i < proto->common.num_args)
418421
? &proto->common.arg_info[i]
419422
: &proto->common.arg_info[proto->common.num_args];
420423

421-
if (!_check_inherited_parameter_type(fe, fe_arg_info, proto, proto_arg_info)) {
424+
_inheritance_status local_status =
425+
_check_inherited_parameter_type(fe, fe_arg_info, proto, proto_arg_info);
426+
if (local_status == INHERITANCE_ERROR) {
422427
return INHERITANCE_ERROR;
428+
} else if (local_status == INHERITANCE_UNRESOLVED) {
429+
status = INHERITANCE_UNRESOLVED;
423430
}
424431
}
425432

426433
/* Check return type compatibility, but only if the prototype already specifies
427434
* a return type. Adding a new return type is always valid. */
428435
if (proto->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
429-
return _check_inherited_return_type(
430-
fe, fe->common.arg_info - 1, proto, proto->common.arg_info - 1);
436+
_inheritance_status local_result =
437+
_check_inherited_return_type(fe, fe->common.arg_info - 1,
438+
proto, proto->common.arg_info - 1);
439+
if (local_result == INHERITANCE_ERROR) {
440+
return INHERITANCE_ERROR;
441+
} else if (local_result == INHERITANCE_UNRESOLVED) {
442+
status = INHERITANCE_UNRESOLVED;
443+
}
431444
}
432-
return INHERITANCE_SUCCESS;
445+
446+
/*
447+
if (status == INHERITANCE_UNRESOLVED && CG(unverified_types)) {
448+
zend_string *key = zend_string_tolower(fe->common.scope->name);
449+
zend_hash_add_empty_element(CG(unverified_types), key);
450+
zend_string_release(key);
451+
}
452+
*/
453+
454+
return status;
433455
}
434456
/* }}} */
435457

@@ -2103,7 +2125,6 @@ ZEND_API void zend_verify_variance(zend_class_entry *ce)
21032125

21042126
if (check < 0) {
21052127
_inheritance_runtime_error_msg(child, parent);
2106-
// todo: what to do with errors, not warnings?
21072128
continue;
21082129
}
21092130
}

0 commit comments

Comments
 (0)