Skip to content

Commit

Permalink
Implement Parameter Type Widening RFC
Browse files Browse the repository at this point in the history
  • Loading branch information
kelunik committed Jan 15, 2017
1 parent 3e27401 commit 430f972
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 26 deletions.
3 changes: 1 addition & 2 deletions Zend/tests/objects_009.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,5 @@ class test3 extends test {

echo "Done\n";
?>
--EXPECTF--
Warning: Declaration of test3::foo($arg) should be compatible with test::foo(Test $arg) in %s on line %d
--EXPECTF--
Done
34 changes: 34 additions & 0 deletions Zend/tests/type_declarations/parameter_type_variance.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--TEST--
Parameter variance with no type
--FILE--
<?php

class Foo {
function testParentClass(Foo $foo) {}
function testBothClass(Foo $foo) {}
function testChildClass($foo) {}
function testNoneClass($foo) {}

function testParentBuiltin(int $foo) {}
function testBothBuiltin(int $foo) {}
function testChildBuiltin($foo) {}
function testNoneBuiltin($foo) {}
}

class Bar extends Foo {
function testParentClass($foo) {}
function testBothClass(Foo $foo) {}
function testChildClass(Foo $foo) {}
function testNoneClass($foo) {}

function testParentBuiltin($foo) {}
function testBothBuiltin(int $foo) {}
function testChildBuiltin(int $foo) {}
function testNoneBuiltin($foo) {}
}

?>
--EXPECTF--
Warning: Declaration of Bar::testChildClass(Foo $foo) should be compatible with Foo::testChildClass($foo) in %s on line %d

Warning: Declaration of Bar::testChildBuiltin(int $foo) should be compatible with Foo::testChildBuiltin($foo) in %s on line %d
25 changes: 15 additions & 10 deletions Zend/zend_inheritance.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,23 +172,28 @@ static zend_always_inline zend_bool zend_iterable_compatibility_check(zend_arg_i
if (ZEND_TYPE_CODE(arg_info->type) == IS_ARRAY) {
return 1;
}

if (ZEND_TYPE_IS_CLASS(arg_info->type) && zend_string_equals_literal_ci(ZEND_TYPE_NAME(arg_info->type), "Traversable")) {
return 1;
}

return 0;
}
/* }}} */

static int zend_do_perform_type_hint_check(const zend_function *fe, zend_arg_info *fe_arg_info, const zend_function *proto, zend_arg_info *proto_arg_info) /* {{{ */
{
if (ZEND_LOG_XOR(ZEND_TYPE_IS_CLASS(fe_arg_info->type), ZEND_TYPE_IS_CLASS(proto_arg_info->type))) {
/* Only one has a type declaration and the other one doesn't */
if (!ZEND_TYPE_IS_SET(fe_arg_info->type)) {
/* Child with no type is always compatible */
return 1;
}

if (!ZEND_TYPE_IS_SET(proto_arg_info->type)) {
/* Child defines a type, but parent doesn't, violates LSP */
return 0;
}

if (ZEND_TYPE_IS_CLASS(fe_arg_info->type)) {
if (ZEND_TYPE_IS_CLASS(fe_arg_info->type) && ZEND_TYPE_IS_CLASS(proto_arg_info->type)) {
zend_string *fe_class_name, *proto_class_name;
const char *class_name;

Expand Down Expand Up @@ -237,7 +242,7 @@ static int zend_do_perform_type_hint_check(const zend_function *fe, zend_arg_inf
zend_string_release(proto_class_name);
zend_string_release(fe_class_name);
} else if (ZEND_TYPE_CODE(fe_arg_info->type) != ZEND_TYPE_CODE(proto_arg_info->type)) {
/* Incompatible type */
/* Incompatible built-in types */
return 0;
}

Expand Down Expand Up @@ -312,15 +317,15 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
} else {
proto_arg_info = &proto->common.arg_info[proto->common.num_args];
}

if (!zend_do_perform_type_hint_check(fe, fe_arg_info, proto, proto_arg_info)) {
switch (ZEND_TYPE_CODE(fe_arg_info->type)) {
case IS_ITERABLE:
if (!zend_iterable_compatibility_check(proto_arg_info)) {
return 0;
}
break;

default:
return 0;
}
Expand All @@ -345,15 +350,15 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
if (!(fe->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
return 0;
}

if (!zend_do_perform_type_hint_check(fe, fe->common.arg_info - 1, proto, proto->common.arg_info - 1)) {
switch (ZEND_TYPE_CODE(proto->common.arg_info[-1].type)) {
case IS_ITERABLE:
if (!zend_iterable_compatibility_check(fe->common.arg_info - 1)) {
return 0;
}
break;

default:
return 0;
}
Expand Down
2 changes: 2 additions & 0 deletions run_002_tmp.fixture
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
stdin
data
14 changes: 0 additions & 14 deletions tests/classes/type_hinting_005b.phpt

This file was deleted.

0 comments on commit 430f972

Please sign in to comment.