Skip to content

Commit ab9a07b

Browse files
morrisonlevinikic
authored andcommitted
Support more type decl locations for variance
1 parent 581bc1b commit ab9a07b

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
@@ -5221,12 +5221,72 @@ void zend_compile_declare(zend_ast *ast) /* {{{ */
52215221
}
52225222
/* }}} */
52235223

5224+
static zend_ast **_ast_find(zend_ast **begin, zend_ast **end,
5225+
zend_bool (*pred)(zend_ast *)) {
5226+
for (; begin < end; ++begin)
5227+
if (pred(*begin))
5228+
return begin;
5229+
return begin;
5230+
}
5231+
5232+
static zend_bool _is_type_decl(zend_ast *ast) {
5233+
return ast && ast->kind == ZEND_AST_CLASS;
5234+
}
5235+
5236+
static zend_bool _is_not_decl_stmt(zend_ast *ast) {
5237+
if (ast) {
5238+
/* todo: what else should be considered a decl stmt? */
5239+
switch (ast->kind) {
5240+
case ZEND_AST_CLASS:
5241+
case ZEND_AST_CONST_DECL:
5242+
case ZEND_AST_FUNC_DECL:
5243+
return 0;
5244+
5245+
default:
5246+
return 1;
5247+
}
5248+
}
5249+
5250+
/* todo: why are these sometimes null? */
5251+
return 0;
5252+
}
5253+
52245254
void zend_compile_stmt_list(zend_ast *ast) /* {{{ */
52255255
{
5226-
zend_ast_list *list = zend_ast_get_list(ast);
5227-
uint32_t i;
5228-
for (i = 0; i < list->children; ++i) {
5229-
zend_compile_stmt(list->child[i]);
5256+
zend_ast_list *const list = zend_ast_get_list(ast);
5257+
zend_ast ** const begin = list->child;
5258+
zend_ast ** const end = begin + list->children;
5259+
zend_ast **first_decl = _ast_find(begin, end, &_is_type_decl);
5260+
zend_ast **p;
5261+
5262+
/* Compile opcodes before first type decl */
5263+
for (p = begin; p < first_decl; ++p) {
5264+
zend_compile_stmt(*p);
5265+
}
5266+
5267+
/* Compile decl stmts */
5268+
while (first_decl != end) {
5269+
zend_ast **last_decl = _ast_find(first_decl, end, &_is_not_decl_stmt);
5270+
HashTable unverified_types;
5271+
HashTable *prev_unverified_types;
5272+
_backup_unverified_variance_types(&unverified_types, &prev_unverified_types);
5273+
5274+
for (p = first_decl; p < last_decl; ++p) {
5275+
zend_compile_stmt(*p);
5276+
}
5277+
5278+
_compile_verify_variance(&unverified_types);
5279+
5280+
zend_hash_destroy(&unverified_types);
5281+
CG(unverified_types) = prev_unverified_types;
5282+
5283+
/* There can be non-consecutive type decls, so continue searching */
5284+
first_decl = _ast_find(last_decl, end, &_is_type_decl);
5285+
5286+
/* Compile any stmts between the two type decls (or the end) */
5287+
for (p = last_decl; p < first_decl; ++p) {
5288+
zend_compile_stmt(*p);
5289+
}
52305290
}
52315291
}
52325292
/* }}} */
@@ -6343,7 +6403,7 @@ zend_op *zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
63436403
if (CG(unverified_types)) {
63446404
zend_hash_add_empty_element(CG(unverified_types), lcname);
63456405
} else {
6346-
// todo: figure out why it's null; need a caller (somewhere) to initialize, emit, and destroy the unverified types
6406+
ZEND_ASSERT(0 && "todo: find out why this is null");
63476407
}
63486408
}
63496409

@@ -8178,36 +8238,6 @@ void zend_const_expr_to_zval(zval *result, zend_ast *ast) /* {{{ */
81788238
}
81798239
/* }}} */
81808240

8181-
static zend_bool _is_type_decl(zend_ast *ast) {
8182-
return ast && ast->kind == ZEND_AST_CLASS;
8183-
}
8184-
8185-
static zend_bool _is_not_decl_stmt(zend_ast *ast) {
8186-
if (ast) {
8187-
/* todo: what else should be considered a decl stmt? */
8188-
switch (ast->kind) {
8189-
case ZEND_AST_CLASS:
8190-
case ZEND_AST_CONST_DECL:
8191-
case ZEND_AST_FUNC_DECL:
8192-
return 0;
8193-
8194-
default:
8195-
return 1;
8196-
}
8197-
}
8198-
8199-
/* todo: why are these sometimes null? */
8200-
return 0;
8201-
}
8202-
8203-
static zend_ast **_ast_find(zend_ast **begin, zend_ast **end,
8204-
zend_bool (*pred)(zend_ast *)) {
8205-
for (; begin < end; ++begin)
8206-
if (pred(*begin))
8207-
return begin;
8208-
return begin;
8209-
}
8210-
82118241
/* Same as compile_stmt, but with early binding */
82128242
void zend_compile_top_stmt(zend_ast *ast) /* {{{ */
82138243
{

Zend/zend_inheritance.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ static
367367
_inheritance_status zend_do_perform_implementation_check(const zend_function *fe, const zend_function *proto) /* {{{ */
368368
{
369369
uint32_t i, num_args;
370+
_inheritance_status status;
370371

371372
/* If it's a user function then arg_info == NULL means we don't have any parameters but
372373
* we still need to do the arg number checks. We are only willing to ignore this for internal
@@ -422,24 +423,45 @@ _inheritance_status zend_do_perform_implementation_check(const zend_function *fe
422423
}
423424
}
424425

426+
status = INHERITANCE_SUCCESS;
427+
425428
for (i = 0; i < num_args; i++) {
426429
zend_arg_info *fe_arg_info = &fe->common.arg_info[i];
427430
zend_arg_info *proto_arg_info = (i < proto->common.num_args)
428431
? &proto->common.arg_info[i]
429432
: &proto->common.arg_info[proto->common.num_args];
430433

431-
if (!_check_inherited_parameter_type(fe, fe_arg_info, proto, proto_arg_info)) {
434+
_inheritance_status local_status =
435+
_check_inherited_parameter_type(fe, fe_arg_info, proto, proto_arg_info);
436+
if (local_status == INHERITANCE_ERROR) {
432437
return INHERITANCE_ERROR;
438+
} else if (local_status == INHERITANCE_UNRESOLVED) {
439+
status = INHERITANCE_UNRESOLVED;
433440
}
434441
}
435442

436443
/* Check return type compatibility, but only if the prototype already specifies
437444
* a return type. Adding a new return type is always valid. */
438445
if (proto->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
439-
return _check_inherited_return_type(
440-
fe, fe->common.arg_info - 1, proto, proto->common.arg_info - 1);
446+
_inheritance_status local_result =
447+
_check_inherited_return_type(fe, fe->common.arg_info - 1,
448+
proto, proto->common.arg_info - 1);
449+
if (local_result == INHERITANCE_ERROR) {
450+
return INHERITANCE_ERROR;
451+
} else if (local_result == INHERITANCE_UNRESOLVED) {
452+
status = INHERITANCE_UNRESOLVED;
453+
}
441454
}
442-
return INHERITANCE_SUCCESS;
455+
456+
/*
457+
if (status == INHERITANCE_UNRESOLVED && CG(unverified_types)) {
458+
zend_string *key = zend_string_tolower(fe->common.scope->name);
459+
zend_hash_add_empty_element(CG(unverified_types), key);
460+
zend_string_release(key);
461+
}
462+
*/
463+
464+
return status;
443465
}
444466
/* }}} */
445467

@@ -2231,7 +2253,6 @@ ZEND_API void zend_verify_variance(zend_class_entry *ce)
22312253

22322254
if (check < 0) {
22332255
_inheritance_runtime_error_msg(child, parent);
2234-
// todo: what to do with errors, not warnings?
22352256
continue;
22362257
}
22372258
}

0 commit comments

Comments
 (0)