mirror of
https://github.com/phabelio/PHP-Parser.git
synced 2024-11-29 20:19:12 +01:00
Add support for intersection types
This commit is contained in:
parent
0483391aca
commit
ace6c67a8a
@ -1,7 +1,9 @@
|
||||
Version 4.12.1-dev
|
||||
------------------
|
||||
|
||||
Nothing yet.
|
||||
### Added
|
||||
|
||||
* [PHP 8.1] Added support for intersection types using a new `IntersectionType` node.
|
||||
|
||||
Version 4.12.0 (2021-07-21)
|
||||
---------------------------
|
||||
|
@ -561,6 +561,7 @@ type_expr:
|
||||
type { $$ = $1; }
|
||||
| '?' type { $$ = Node\NullableType[$2]; }
|
||||
| union_type { $$ = Node\UnionType[$1]; }
|
||||
| intersection_type { $$ = Node\IntersectionType[$1]; }
|
||||
;
|
||||
|
||||
type:
|
||||
@ -584,10 +585,24 @@ union_type_without_static:
|
||||
| union_type_without_static '|' type_without_static { push($1, $3); }
|
||||
;
|
||||
|
||||
intersection_type:
|
||||
type T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type { init($1, $3); }
|
||||
| intersection_type T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type
|
||||
{ push($1, $3); }
|
||||
;
|
||||
|
||||
intersection_type_without_static:
|
||||
type_without_static T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type_without_static
|
||||
{ init($1, $3); }
|
||||
| intersection_type_without_static T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG type_without_static
|
||||
{ push($1, $3); }
|
||||
;
|
||||
|
||||
type_expr_without_static:
|
||||
type_without_static { $$ = $1; }
|
||||
| '?' type_without_static { $$ = Node\NullableType[$2]; }
|
||||
| union_type_without_static { $$ = Node\UnionType[$1]; }
|
||||
| intersection_type_without_static { $$ = Node\IntersectionType[$1]; }
|
||||
;
|
||||
|
||||
optional_type_without_static:
|
||||
|
@ -5,6 +5,7 @@ namespace PhpParser;
|
||||
use PhpParser\Node\ComplexType;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\IntersectionType;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\NullableType;
|
||||
use PhpParser\Node\Scalar;
|
||||
|
30
lib/PhpParser/Node/IntersectionType.php
Normal file
30
lib/PhpParser/Node/IntersectionType.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node;
|
||||
|
||||
use PhpParser\NodeAbstract;
|
||||
|
||||
class IntersectionType extends ComplexType
|
||||
{
|
||||
/** @var (Identifier|Name)[] Types */
|
||||
public $types;
|
||||
|
||||
/**
|
||||
* Constructs an intersection type.
|
||||
*
|
||||
* @param (Identifier|Name)[] $types Types
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(array $types, array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->types = $types;
|
||||
}
|
||||
|
||||
public function getSubNodeNames() : array {
|
||||
return ['types'];
|
||||
}
|
||||
|
||||
public function getType() : string {
|
||||
return 'IntersectionType';
|
||||
}
|
||||
}
|
@ -189,7 +189,7 @@ class NameResolver extends NodeVisitorAbstract
|
||||
$node->type = $this->resolveType($node->type);
|
||||
return $node;
|
||||
}
|
||||
if ($node instanceof Node\UnionType) {
|
||||
if ($node instanceof Node\UnionType || $node instanceof Node\IntersectionType) {
|
||||
foreach ($node->types as &$type) {
|
||||
$type = $this->resolveType($type);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -45,6 +45,10 @@ class Standard extends PrettyPrinterAbstract
|
||||
return $this->pImplode($node->types, '|');
|
||||
}
|
||||
|
||||
protected function pIntersectionType(Node\IntersectionType $node) {
|
||||
return $this->pImplode($node->types, '&');
|
||||
}
|
||||
|
||||
protected function pIdentifier(Node\Identifier $node) {
|
||||
return $node->name;
|
||||
}
|
||||
|
@ -1343,6 +1343,7 @@ abstract class PrettyPrinterAbstract
|
||||
//'Scalar_Encapsed->parts' => '',
|
||||
'Stmt_Catch->types' => '|',
|
||||
'UnionType->types' => '|',
|
||||
'IntersectionType->types' => '&',
|
||||
'Stmt_If->elseifs' => ' ',
|
||||
'Stmt_TryCatch->catches' => ' ',
|
||||
|
||||
|
@ -140,6 +140,9 @@ class BuilderHelpersTest extends \PHPUnit\Framework\TestCase
|
||||
$unionType = new Node\UnionType([new Node\Identifier('int'), new Node\Identifier('string')]);
|
||||
$this->assertSame($unionType, BuilderHelpers::normalizeType($unionType));
|
||||
|
||||
$intersectionType = new Node\IntersectionType([new Node\Name('A'), new Node\Name('B')]);
|
||||
$this->assertSame($intersectionType, BuilderHelpers::normalizeType($intersectionType));
|
||||
|
||||
$expectedNullable = new Node\NullableType($intIdentifier);
|
||||
$nullable = BuilderHelpers::normalizeType('?int');
|
||||
$this->assertEquals($expectedNullable, $nullable);
|
||||
|
@ -204,6 +204,7 @@ class A extends B implements C, D {
|
||||
interface A extends C, D {
|
||||
public function a(A $a) : A;
|
||||
public function b(A|B|int $a): A|B|int;
|
||||
public function c(A&B $a): A&B;
|
||||
}
|
||||
|
||||
#[X]
|
||||
@ -268,6 +269,7 @@ interface A extends \NS\C, \NS\D
|
||||
{
|
||||
public function a(\NS\A $a) : \NS\A;
|
||||
public function b(\NS\A|\NS\B|int $a) : \NS\A|\NS\B|int;
|
||||
public function c(\NS\A&\NS\B $a) : \NS\A&\NS\B;
|
||||
}
|
||||
#[\NS\X]
|
||||
enum E : int
|
||||
|
@ -319,6 +319,16 @@ function test(): A
|
||||
|B|C {}
|
||||
-----
|
||||
<?php
|
||||
function test(): A
|
||||
&B {}
|
||||
-----
|
||||
$stmts[0]->returnType->types[] = new Node\Name('C');
|
||||
-----
|
||||
<?php
|
||||
function test(): A
|
||||
&B&C {}
|
||||
-----
|
||||
<?php
|
||||
function test() {
|
||||
if ($x) {
|
||||
$a;
|
||||
|
104
test/code/parser/stmt/function/intersectionTypes.test
Normal file
104
test/code/parser/stmt/function/intersectionTypes.test
Normal file
@ -0,0 +1,104 @@
|
||||
Union types
|
||||
-----
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public A&B $prop;
|
||||
}
|
||||
|
||||
function test(A&B $a): A&B {}
|
||||
-----
|
||||
!!php7
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Test
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
type: IntersectionType(
|
||||
types: array(
|
||||
0: Name(
|
||||
parts: array(
|
||||
0: A
|
||||
)
|
||||
)
|
||||
1: Name(
|
||||
parts: array(
|
||||
0: B
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
props: array(
|
||||
0: Stmt_PropertyProperty(
|
||||
name: VarLikeIdentifier(
|
||||
name: prop
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
1: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: test
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: IntersectionType(
|
||||
types: array(
|
||||
0: Name(
|
||||
parts: array(
|
||||
0: A
|
||||
)
|
||||
)
|
||||
1: Name(
|
||||
parts: array(
|
||||
0: B
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
byRef: false
|
||||
variadic: false
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
returnType: IntersectionType(
|
||||
types: array(
|
||||
0: Name(
|
||||
parts: array(
|
||||
0: A
|
||||
)
|
||||
)
|
||||
1: Name(
|
||||
parts: array(
|
||||
0: B
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
)
|
18
test/code/prettyPrinter/stmt/intersection_types.test
Normal file
18
test/code/prettyPrinter/stmt/intersection_types.test
Normal file
@ -0,0 +1,18 @@
|
||||
Union types
|
||||
-----
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public A&B $prop;
|
||||
}
|
||||
|
||||
function test(A&B $a): A&B {}
|
||||
-----
|
||||
!!php7
|
||||
class Test
|
||||
{
|
||||
public A&B $prop;
|
||||
}
|
||||
function test(A&B $a) : A&B
|
||||
{
|
||||
}
|
Loading…
Reference in New Issue
Block a user