Skip to content

Add true as a type #8326

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

Merged
merged 2 commits into from
Jun 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--TEST--
true type cannot take part in an intersection type
--FILE--
<?php

function foo(): true&Iterator {}

?>
--EXPECTF--
Fatal error: Type true cannot be part of an intersection type in %s on line %d
28 changes: 28 additions & 0 deletions Zend/tests/type_declarations/literal_types/false_no_coercion.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
No coercion should be applied to type false
--FILE--
<?php

function test(false $v) { var_dump($v); }

try {
test(0);
} catch (\TypeError $e) {
echo $e->getMessage(), \PHP_EOL;
}
try {
test('');
} catch (\TypeError $e) {
echo $e->getMessage(), \PHP_EOL;
}
try {
test([]);
} catch (\TypeError $e) {
echo $e->getMessage(), \PHP_EOL;
}

?>
--EXPECTF--
test(): Argument #1 ($v) must be of type false, int given, called in %s on line %d
test(): Argument #1 ($v) must be of type false, string given, called in %s on line %d
test(): Argument #1 ($v) must be of type false, array given, called in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
--TEST--
No coercion should be applied to type false even if it's an overide
--FILE--
<?php

class P {
public function foo($v): array|bool {
return $v;
}
}

class C {
public function foo($v): array|false {
return $v;
}
}

$p = new P();
$c = new C();

var_dump($p->foo(0));
try {
var_dump($c->foo(0));
} catch (\TypeError $e) {
echo $e->getMessage(), \PHP_EOL;
}

?>
--EXPECT--
bool(false)
C::foo(): Return value must be of type array|false, int returned
14 changes: 14 additions & 0 deletions Zend/tests/type_declarations/literal_types/false_standalone.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
False can be used as a standalone type
--FILE--
<?php

function test(false $v): false {
return $v;
}

var_dump(test(false));

?>
--EXPECT--
bool(false)
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ False can be used as a standalone type even with implicit nullability
--FILE--
<?php

function test(false $v = null) {}
function test(false $v = null) { return $v; }

var_dump(test(false));
var_dump(test(null));
?>
===DONE===
--EXPECT--
===DONE===
bool(false)
NULL
34 changes: 34 additions & 0 deletions Zend/tests/type_declarations/literal_types/true_no_coercion.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--TEST--
No coercion should be applied to type true
--FILE--
<?php

function test(true $v) { var_dump($v); }

try {
test(1);
} catch (\TypeError $e) {
echo $e->getMessage(), \PHP_EOL;
}
try {
test('1');
} catch (\TypeError $e) {
echo $e->getMessage(), \PHP_EOL;
}
try {
test([1]);
} catch (\TypeError $e) {
echo $e->getMessage(), \PHP_EOL;
}
try {
test(new stdClass());
} catch (\TypeError $e) {
echo $e->getMessage(), \PHP_EOL;
}

?>
--EXPECTF--
test(): Argument #1 ($v) must be of type true, int given, called in %s on line %d
test(): Argument #1 ($v) must be of type true, string given, called in %s on line %d
test(): Argument #1 ($v) must be of type true, array given, called in %s on line %d
test(): Argument #1 ($v) must be of type true, stdClass given, called in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
--TEST--
No coercion should be applied to type true even if it's an overide
--FILE--
<?php

class P {
public function foo($v): array|bool {
return $v;
}
}

class C {
public function foo($v): array|true {
return $v;
}
}

$p = new P();
$c = new C();

var_dump($p->foo(1));
try {
var_dump($c->foo(1));
} catch (\TypeError $e) {
echo $e->getMessage(), \PHP_EOL;
}

?>
--EXPECT--
bool(true)
C::foo(): Return value must be of type array|true, int returned
14 changes: 14 additions & 0 deletions Zend/tests/type_declarations/literal_types/true_standalone.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
true can be used as a standalone type
--FILE--
<?php

function test(true $v): true {
return $v;
}

var_dump(test(true));

?>
--EXPECT--
bool(true)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
true can be used as a standalone type even with implicit nullability
--FILE--
<?php

function test(true $v = null) { return $v; }

var_dump(test(true));
var_dump(test(null));
?>
--EXPECT--
bool(true)
NULL
19 changes: 19 additions & 0 deletions Zend/tests/type_declarations/typed_properties_112.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
Test typed properties allow true
--FILE--
<?php
class Foo {
public true $value;
}

$foo = new Foo();

try {
$foo->value = false;
} catch (\TypeError $e) {
echo $e->getMessage();
}

?>
--EXPECT--
Cannot assign bool to property Foo::$value of type true
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--TEST--
Using both bool and true in a union
--FILE--
<?php

function test(): bool|true {
}

?>
--EXPECTF--
Fatal error: Duplicate type true is redundant in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--TEST--
Using both false and true in a union instead of bool
--FILE--
<?php

function test(): false|true {
}

?>
--EXPECTF--
Fatal error: Type contains both true and false, bool should be used instead in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--TEST--
Using both true and false in a union instead of bool
--FILE--
<?php

function test(): true|false {
}

?>
--EXPECTF--
Fatal error: Type contains both true and false, bool should be used instead in %s on line %d
11 changes: 0 additions & 11 deletions Zend/tests/type_declarations/union_types/standalone_false.phpt

This file was deleted.

8 changes: 8 additions & 0 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ typedef struct _builtin_type_info {

static const builtin_type_info builtin_types[] = {
{ZEND_STRL("null"), IS_NULL},
{ZEND_STRL("true"), IS_TRUE},
{ZEND_STRL("false"), IS_FALSE},
{ZEND_STRL("int"), IS_LONG},
{ZEND_STRL("float"), IS_DOUBLE},
Expand Down Expand Up @@ -1246,6 +1247,8 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_BOOL), /* is_intersection */ false);
} else if (type_mask & MAY_BE_FALSE) {
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_FALSE), /* is_intersection */ false);
} else if (type_mask & MAY_BE_TRUE) {
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_TRUE), /* is_intersection */ false);
}
if (type_mask & MAY_BE_VOID) {
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_VOID), /* is_intersection */ false);
Expand Down Expand Up @@ -6226,6 +6229,11 @@ static zend_type zend_compile_typename(
zend_error_noreturn(E_COMPILE_ERROR,
"Duplicate type %s is redundant", ZSTR_VAL(overlap_type_str));
}
if ( ((ZEND_TYPE_PURE_MASK(type) & MAY_BE_TRUE) && (single_type_mask == MAY_BE_FALSE))
|| ((ZEND_TYPE_PURE_MASK(type) & MAY_BE_FALSE) && (single_type_mask == MAY_BE_TRUE)) ) {
zend_error_noreturn(E_COMPILE_ERROR,
"Type contains both true and false, bool should be used instead");
}
ZEND_TYPE_FULL_MASK(type) |= ZEND_TYPE_PURE_MASK(single_type);
ZEND_TYPE_FULL_MASK(single_type) &= ~_ZEND_TYPE_MAY_BE_MASK;

Expand Down
1 change: 1 addition & 0 deletions Zend/zend_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,7 @@ EMPTY_SWITCH_DEFAULT_CASE()
_(ZEND_STR_VOID, "void") \
_(ZEND_STR_NEVER, "never") \
_(ZEND_STR_FALSE, "false") \
_(ZEND_STR_TRUE, "true") \
_(ZEND_STR_NULL_LOWERCASE, "null") \
_(ZEND_STR_MIXED, "mixed") \
_(ZEND_STR_TRAVERSABLE, "Traversable") \
Expand Down
2 changes: 2 additions & 0 deletions ext/reflection/php_reflection.c
Original file line number Diff line number Diff line change
Expand Up @@ -3151,6 +3151,8 @@ ZEND_METHOD(ReflectionUnionType, getTypes)
}
if ((type_mask & MAY_BE_BOOL) == MAY_BE_BOOL) {
append_type_mask(return_value, MAY_BE_BOOL);
} else if (type_mask & MAY_BE_TRUE) {
append_type_mask(return_value, MAY_BE_TRUE);
} else if (type_mask & MAY_BE_FALSE) {
append_type_mask(return_value, MAY_BE_FALSE);
}
Expand Down
2 changes: 2 additions & 0 deletions ext/reflection/tests/ReflectionType_possible_types.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ $functions = [
function(): callable {},
function(): null {},
function(): false {},
function(): true {},
function(): StdClass {}
];

Expand All @@ -32,4 +33,5 @@ string(5) "array"
string(8) "callable"
string(4) "null"
string(5) "false"
string(4) "true"
string(8) "StdClass"
28 changes: 28 additions & 0 deletions ext/reflection/tests/union_types.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ function test1(): X|Y|int|float|false|null { }
function test2(): X|iterable|bool { }
function test3(): null|false { }
function test4(): ?false { }
function test5(): X|iterable|true { }
function test6(): null|true { }
function test7(): ?true { }

class Test {
public X|Y|int $prop;
Expand All @@ -33,6 +36,9 @@ dumpType((new ReflectionFunction('test1'))->getReturnType());
dumpType((new ReflectionFunction('test2'))->getReturnType());
dumpBCType((new ReflectionFunction('test3'))->getReturnType());
dumpBCType((new ReflectionFunction('test4'))->getReturnType());
dumpType((new ReflectionFunction('test5'))->getReturnType());
dumpBCType((new ReflectionFunction('test6'))->getReturnType());
dumpBCType((new ReflectionFunction('test7'))->getReturnType());

$rc = new ReflectionClass(Test::class);
$rp = $rc->getProperty('prop');
Expand Down Expand Up @@ -97,6 +103,28 @@ Type ?false:
Name: false
String: ?false
Allows Null: true
Type X|Traversable|array|true:
Allows null: false
Name: X
String: X
Allows Null: false
Name: Traversable
String: Traversable
Allows Null: false
Name: array
String: array
Allows Null: false
Name: true
String: true
Allows Null: false
Type ?true:
Name: true
String: ?true
Allows Null: true
Type ?true:
Name: true
String: ?true
Allows Null: true
Type X|Y|int:
Allows null: false
Name: X
Expand Down