Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement nullable return types. #1851

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 23 additions & 0 deletions Zend/tests/return_types/030.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
Nullable return value
--FILE--
<?php
function foo($x) : ?array {
return $x;
}

foo([]);
echo "ok\n";
foo(null);
echo "ok\n";
foo(0);
?>
--EXPECTF--
ok
ok

Fatal error: Uncaught TypeError: Return value of foo() must be of the type array, integer returned in %s030.php:3
Stack trace:
#0 %s030.php(10): foo(0)
#1 {main}
thrown in %s030.php on line 3
14 changes: 14 additions & 0 deletions Zend/tests/return_types/031.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
Nullable return type inheritance rules (non-nullable and nullable)
--FILE--
<?php
class A {
function foo(): int {}
}
class B extends A {
function foo(): ?int {}
}
?>
DONE
--EXPECTF--
Fatal error: Declaration of B::foo(): ?int must be compatible with A::foo(): int in %s031.php on line 7
14 changes: 14 additions & 0 deletions Zend/tests/return_types/032.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
Nullable return type inheritance rules (nullable and non-nullable)
--FILE--
<?php
class A {
function foo(): ?int {}
}
class B extends A {
function foo(): int {}
}
?>
DONE
--EXPECT--
DONE
5 changes: 5 additions & 0 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -4844,6 +4844,11 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */
arg_infos->allow_null = 0;
arg_infos->class_name = NULL;

if (return_type_ast->attr & ZEND_TYPE_NULLABLE) {
arg_infos->allow_null = 1;
return_type_ast->attr &= ~ZEND_TYPE_NULLABLE;
}

zend_compile_typename(return_type_ast, arg_infos);

arg_infos++;
Expand Down
2 changes: 2 additions & 0 deletions Zend/zend_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,8 @@ ZEND_API void zend_assert_valid_class_name(const zend_string *const_name);
#define ZEND_NAME_NOT_FQ 1
#define ZEND_NAME_RELATIVE 2

#define ZEND_TYPE_NULLABLE (1<<8)

/* var status for backpatching */
#define BP_VAR_R 0
#define BP_VAR_W 1
Expand Down
10 changes: 9 additions & 1 deletion Zend/zend_inheritance.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,10 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
if (!zend_do_perform_type_hint_check(fe, fe->common.arg_info - 1, proto, proto->common.arg_info - 1)) {
return 0;
}

if (fe->common.arg_info[-1].allow_null && !proto->common.arg_info[-1].allow_null) {
return 0;
}
}
return 1;
}
Expand Down Expand Up @@ -503,6 +507,9 @@ static ZEND_COLD zend_string *zend_get_function_declaration(const zend_function

if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
smart_str_appends(&str, ": ");
if (fptr->common.arg_info[-1].allow_null) {
smart_str_appendc(&str, '?');
}
zend_append_type_hint(&str, fptr, fptr->common.arg_info - 1, 1);
}
smart_str_0(&str);
Expand Down Expand Up @@ -585,7 +592,8 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function *
error_verb = "must";
} else if ((parent->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) &&
(!(child->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
!zend_do_perform_type_hint_check(child, child->common.arg_info - 1, parent, parent->common.arg_info - 1))) {
!zend_do_perform_type_hint_check(child, child->common.arg_info - 1, parent, parent->common.arg_info - 1) ||
(child->common.arg_info[-1].allow_null && !parent->common.arg_info[-1].allow_null))) {
error_level = E_COMPILE_ERROR;
error_verb = "must";
} else {
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_language_parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@ type:
return_type:
/* empty */ { $$ = NULL; }
| ':' type { $$ = $2; }
| ':' '?' type { $$ = $3; $$->attr |= ZEND_TYPE_NULLABLE; }
;

argument_list:
Expand Down