php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #81268 intersection type incompatible with nullable props/returns
Submitted: 2021-07-16 15:07 UTC Modified: 2021-07-16 22:54 UTC
From: nicolasgrekas@php.net Assigned: girgias (profile)
Status: Verified Package: Scripting Engine problem
PHP Version: 8.1Git-2021-07-16 (Git) OS:
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: nicolasgrekas@php.net
New email:
PHP Version: OS:

 

 [2021-07-16 15:07 UTC] nicolasgrekas@php.net
Description:
------------
This code yields "Default value for property of type X&Y may not be null. Use the nullable type ?X&Y to allow null default value":

class Test {
    public X&Y $y = null;
}

Fine, let's add the suggested "?". But then I get "Parse error: syntax error, unexpected token "&", expecting variable".

About returning null|intersection, should this be possible?

class Test {
    function foo(): ?X&Y
    {
        return null;
    }
}

Right now it yields a syntax error.


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-07-16 15:14 UTC] girgias@php.net
An intersection type cannot be part of a union, and nullable types are a form of union types, this limitation is mentioned in the RFC, so you can't initialize the property to null, however the error message needs to be clearer so this is part bug/part feature request.

I'll have a look at this next week.
 [2021-07-16 15:14 UTC] girgias@php.net
-Status: Open +Status: Verified -Assigned To: +Assigned To: girgias
 [2021-07-16 15:17 UTC] nicolasgrekas@php.net
> this limitation is mentioned in the RFC

Actual no, it's not. That's also why I opened the bug report, in case this was overlooked.

Thanks for checking the error message, that's very much needed.
 [2021-07-16 15:25 UTC] nicolasgrekas@php.net
Note that nullable intersection types are possible, here is one
https://3v4l.org/aURFN/rfc#vgit.master

$f = function (X&Y $foo = null) {};
$r = new ReflectionParameter($f, 0);
var_dump($r->getType()->allowsNull());

Looking at the discussion at https://externals.io/message/113712, this was mostly overlooked.

I think we should allow ?X&Y as property, return and parameter types.
 [2021-07-16 15:28 UTC] girgias@php.net
I addressed this on the PR (https://github.com/php/php-src/pull/6799#issuecomment-804793443), and I don't think we should accept it, it is super ambiguous
 [2021-07-16 15:29 UTC] girgias@php.net
> https://3v4l.org/aURFN/rfc#vgit.master

I would consider that I bug in all honesty, because I forgot about PHP's peculiar implicit null handling... which I have no clue if it works properly with variances checks
 [2021-07-16 15:31 UTC] nicolasgrekas@php.net
This should be brought to php-internals IMHO.
The fact that "function (X&Y $foo = null) {};" works is going to be super useful.
But the fact that there is no type to express the type of the argument is WTF.
It would be consistent to allow ?X&Y everywhere.
 [2021-07-16 15:44 UTC] girgias@php.net
> This should be brought to php-internals IMHO.
> The fact that "function (X&Y $foo = null) {};" works is going to be super useful.

I don't deny that, but the limitation that you cannot combine union types with intersection was explicitly mentioned in the RFC. And a nullable type is a union type of T|null.


> But the fact that there is no type to express the type of the argument is WTF.

I agree that's a WTF, but that's an issue because of PHP's implicit nullable type, which should die IMHO.

> It would be consistent to allow ?X&Y everywhere.

?X&Y for means (?X)&Y which is bogus/redundant, if we allow a nullable syntax it should be ?(X&Y) but this syntax was dropped from the union type RFC because many people opposed it (https://wiki.php.net/rfc/union_types_v2#supported_types see Nullable Union types section)

So feel free to bring this up on php-internals, but I am *vehemently* against adding support for nullable intersection types, and I consider the implicit nullable type behaviour a bug. Especially that I have *no idea* if it follows LSP checks correctly as that was the *main* reason to not support mixing unions and intersections in the first place.
 [2021-07-16 16:15 UTC] me at derrabus dot de
As mentioned on the PR already: https://github.com/php/php-src/pull/6799#issuecomment-805175050

I recognize the complexity of full composite types and I agree that we might not need them (yet). But PHP has had nullable types long before it had unions. This feature has created the edge-case of a type that cannot be expressed as nullable. I suspect that maintaining that edge case is more complex than allowing nullablity again.

And if it's really just about the syntax for expressing nullability, I'm pretty convinced that we can find a decent syntax for that.

Please reconsider allowing nullable intersection types.
 [2021-07-16 22:54 UTC] girgias@php.net
I'll reconsider it for £100000.

Any syntax proposition is going to be something which was deemed confusing, is either going to be an edge case on its own, or would have lead people who voted for this RFC to vote against it (and I know this for a fact).

Proper null-ability has only existed since 7.1, and I don't see why I should add something to the language which is going to be inconsistent the moment we get composite type support, especially when the complexity of the implementation comes from the variance checks, which would be rendered even more complicated just to support this as an edge case instead of properly.

So no thank you.
 
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Thu Sep 16 11:03:37 2021 UTC