]> granicus.if.org Git - php/commitdiff
Implement nullable return types.
authorDmitry Stogov <dmitry@zend.com>
Wed, 6 Apr 2016 15:24:34 +0000 (18:24 +0300)
committerLevi Morrison <levim@php.net>
Thu, 5 May 2016 15:34:16 +0000 (09:34 -0600)
Zend/tests/return_types/030.phpt [new file with mode: 0644]
Zend/tests/return_types/031.phpt [new file with mode: 0644]
Zend/tests/return_types/032.phpt [new file with mode: 0644]
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_inheritance.c
Zend/zend_language_parser.y

diff --git a/Zend/tests/return_types/030.phpt b/Zend/tests/return_types/030.phpt
new file mode 100644 (file)
index 0000000..d1ceac8
--- /dev/null
@@ -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
diff --git a/Zend/tests/return_types/031.phpt b/Zend/tests/return_types/031.phpt
new file mode 100644 (file)
index 0000000..91ee2f8
--- /dev/null
@@ -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
\ No newline at end of file
diff --git a/Zend/tests/return_types/032.phpt b/Zend/tests/return_types/032.phpt
new file mode 100644 (file)
index 0000000..00790b5
--- /dev/null
@@ -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
index 50bcb3b7ad46910d3e8c06f35ef1b767f2736306..fe81aadcf8930d893ff8755dfd9265561cf4d773 100644 (file)
@@ -4906,6 +4906,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++;
index f52d22a3846085986a6d8e62c3394c759dc65415..1f6f49e2157dd773bf0e9e6036163918d260ffef 100644 (file)
@@ -836,6 +836,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
index 42283f94dca2b8609a6258a4495e362622c59302..df7dbfd63eea773611488af3de583911086f49d4 100644 (file)
@@ -344,6 +344,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;
 }
@@ -506,6 +510,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);
@@ -590,7 +597,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 {
index 4722846ce7f5bf5a42b54d7835156a07f135e2f1..c995e5fd4dee9cfcb774d519d2d6691fbcb46c0d 100644 (file)
@@ -656,6 +656,7 @@ type:
 return_type:
                /* empty */     { $$ = NULL; }
        |       ':' type        { $$ = $2; }
+       |       ':' '?' type    { $$ = $3; $$->attr |= ZEND_TYPE_NULLABLE; }
 ;
 
 argument_list: