mirror of
https://github.com/phabelio/PHP-Parser.git
synced 2024-11-30 04:29:15 +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
|
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)
|
Version 4.12.0 (2021-07-21)
|
||||||
---------------------------
|
---------------------------
|
||||||
|
@ -561,6 +561,7 @@ type_expr:
|
|||||||
type { $$ = $1; }
|
type { $$ = $1; }
|
||||||
| '?' type { $$ = Node\NullableType[$2]; }
|
| '?' type { $$ = Node\NullableType[$2]; }
|
||||||
| union_type { $$ = Node\UnionType[$1]; }
|
| union_type { $$ = Node\UnionType[$1]; }
|
||||||
|
| intersection_type { $$ = Node\IntersectionType[$1]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
type:
|
type:
|
||||||
@ -584,10 +585,24 @@ union_type_without_static:
|
|||||||
| union_type_without_static '|' type_without_static { push($1, $3); }
|
| 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_expr_without_static:
|
||||||
type_without_static { $$ = $1; }
|
type_without_static { $$ = $1; }
|
||||||
| '?' type_without_static { $$ = Node\NullableType[$2]; }
|
| '?' type_without_static { $$ = Node\NullableType[$2]; }
|
||||||
| union_type_without_static { $$ = Node\UnionType[$1]; }
|
| union_type_without_static { $$ = Node\UnionType[$1]; }
|
||||||
|
| intersection_type_without_static { $$ = Node\IntersectionType[$1]; }
|
||||||
;
|
;
|
||||||
|
|
||||||
optional_type_without_static:
|
optional_type_without_static:
|
||||||
|
@ -5,6 +5,7 @@ namespace PhpParser;
|
|||||||
use PhpParser\Node\ComplexType;
|
use PhpParser\Node\ComplexType;
|
||||||
use PhpParser\Node\Expr;
|
use PhpParser\Node\Expr;
|
||||||
use PhpParser\Node\Identifier;
|
use PhpParser\Node\Identifier;
|
||||||
|
use PhpParser\Node\IntersectionType;
|
||||||
use PhpParser\Node\Name;
|
use PhpParser\Node\Name;
|
||||||
use PhpParser\Node\NullableType;
|
use PhpParser\Node\NullableType;
|
||||||
use PhpParser\Node\Scalar;
|
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);
|
$node->type = $this->resolveType($node->type);
|
||||||
return $node;
|
return $node;
|
||||||
}
|
}
|
||||||
if ($node instanceof Node\UnionType) {
|
if ($node instanceof Node\UnionType || $node instanceof Node\IntersectionType) {
|
||||||
foreach ($node->types as &$type) {
|
foreach ($node->types as &$type) {
|
||||||
$type = $this->resolveType($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, '|');
|
return $this->pImplode($node->types, '|');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function pIntersectionType(Node\IntersectionType $node) {
|
||||||
|
return $this->pImplode($node->types, '&');
|
||||||
|
}
|
||||||
|
|
||||||
protected function pIdentifier(Node\Identifier $node) {
|
protected function pIdentifier(Node\Identifier $node) {
|
||||||
return $node->name;
|
return $node->name;
|
||||||
}
|
}
|
||||||
|
@ -1343,6 +1343,7 @@ abstract class PrettyPrinterAbstract
|
|||||||
//'Scalar_Encapsed->parts' => '',
|
//'Scalar_Encapsed->parts' => '',
|
||||||
'Stmt_Catch->types' => '|',
|
'Stmt_Catch->types' => '|',
|
||||||
'UnionType->types' => '|',
|
'UnionType->types' => '|',
|
||||||
|
'IntersectionType->types' => '&',
|
||||||
'Stmt_If->elseifs' => ' ',
|
'Stmt_If->elseifs' => ' ',
|
||||||
'Stmt_TryCatch->catches' => ' ',
|
'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')]);
|
$unionType = new Node\UnionType([new Node\Identifier('int'), new Node\Identifier('string')]);
|
||||||
$this->assertSame($unionType, BuilderHelpers::normalizeType($unionType));
|
$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);
|
$expectedNullable = new Node\NullableType($intIdentifier);
|
||||||
$nullable = BuilderHelpers::normalizeType('?int');
|
$nullable = BuilderHelpers::normalizeType('?int');
|
||||||
$this->assertEquals($expectedNullable, $nullable);
|
$this->assertEquals($expectedNullable, $nullable);
|
||||||
|
@ -204,6 +204,7 @@ class A extends B implements C, D {
|
|||||||
interface A extends C, D {
|
interface A extends C, D {
|
||||||
public function a(A $a) : A;
|
public function a(A $a) : A;
|
||||||
public function b(A|B|int $a): A|B|int;
|
public function b(A|B|int $a): A|B|int;
|
||||||
|
public function c(A&B $a): A&B;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[X]
|
#[X]
|
||||||
@ -268,6 +269,7 @@ interface A extends \NS\C, \NS\D
|
|||||||
{
|
{
|
||||||
public function a(\NS\A $a) : \NS\A;
|
public function a(\NS\A $a) : \NS\A;
|
||||||
public function b(\NS\A|\NS\B|int $a) : \NS\A|\NS\B|int;
|
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]
|
#[\NS\X]
|
||||||
enum E : int
|
enum E : int
|
||||||
|
@ -319,6 +319,16 @@ function test(): A
|
|||||||
|B|C {}
|
|B|C {}
|
||||||
-----
|
-----
|
||||||
<?php
|
<?php
|
||||||
|
function test(): A
|
||||||
|
&B {}
|
||||||
|
-----
|
||||||
|
$stmts[0]->returnType->types[] = new Node\Name('C');
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
function test(): A
|
||||||
|
&B&C {}
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
function test() {
|
function test() {
|
||||||
if ($x) {
|
if ($x) {
|
||||||
$a;
|
$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