mirror of
https://github.com/phabelio/PHP-Parser.git
synced 2024-11-26 20:14:46 +01:00
Add support for union types
We definitely need to introduce a general "Type" abstraction in the next major version.
This commit is contained in:
parent
5b1cd2e4f2
commit
664c10121e
@ -461,6 +461,7 @@ parameter:
|
||||
type_expr:
|
||||
type { $$ = $1; }
|
||||
| '?' type { $$ = Node\NullableType[$2]; }
|
||||
| union_type { $$ = Node\UnionType[$1]; }
|
||||
;
|
||||
|
||||
type:
|
||||
@ -469,6 +470,11 @@ type:
|
||||
| T_CALLABLE { $$ = Node\Identifier['callable']; }
|
||||
;
|
||||
|
||||
union_type:
|
||||
type '|' type { init($1, $3); }
|
||||
| union_type '|' type { push($1, $3); }
|
||||
;
|
||||
|
||||
optional_type:
|
||||
/* empty */ { $$ = null; }
|
||||
| type_expr { $$ = $1; }
|
||||
|
@ -17,7 +17,7 @@ class ArrowFunction extends Expr implements FunctionLike
|
||||
/** @var Node\Param[] */
|
||||
public $params = [];
|
||||
|
||||
/** @var null|Node\Identifier|Node\Name|Node\NullableType */
|
||||
/** @var null|Node\Identifier|Node\Name|Node\NullableType|Node\UnionType */
|
||||
public $returnType;
|
||||
|
||||
/** @var Expr */
|
||||
|
@ -16,7 +16,7 @@ class Closure extends Expr implements FunctionLike
|
||||
public $params;
|
||||
/** @var ClosureUse[] use()s */
|
||||
public $uses;
|
||||
/** @var null|Node\Identifier|Node\Name|Node\NullableType Return type */
|
||||
/** @var null|Node\Identifier|Node\Name|Node\NullableType|Node\UnionType Return type */
|
||||
public $returnType;
|
||||
/** @var Node\Stmt[] Statements */
|
||||
public $stmts;
|
||||
|
@ -23,7 +23,7 @@ interface FunctionLike extends Node
|
||||
/**
|
||||
* Get the declared return type or null
|
||||
*
|
||||
* @return null|Identifier|Node\Name|Node\NullableType
|
||||
* @return null|Identifier|Node\Name|Node\NullableType|Node\UnionType
|
||||
*/
|
||||
public function getReturnType();
|
||||
|
||||
|
@ -6,7 +6,7 @@ use PhpParser\NodeAbstract;
|
||||
|
||||
class Param extends NodeAbstract
|
||||
{
|
||||
/** @var null|Identifier|Name|NullableType Type declaration */
|
||||
/** @var null|Identifier|Name|NullableType|UnionType Type declaration */
|
||||
public $type;
|
||||
/** @var bool Whether parameter is passed by reference */
|
||||
public $byRef;
|
||||
@ -20,12 +20,12 @@ class Param extends NodeAbstract
|
||||
/**
|
||||
* Constructs a parameter node.
|
||||
*
|
||||
* @param Expr\Variable|Expr\Error $var Parameter variable
|
||||
* @param null|Expr $default Default value
|
||||
* @param null|string|Identifier|Name|NullableType $type Type declaration
|
||||
* @param bool $byRef Whether is passed by reference
|
||||
* @param bool $variadic Whether this is a variadic argument
|
||||
* @param array $attributes Additional attributes
|
||||
* @param Expr\Variable|Expr\Error $var Parameter variable
|
||||
* @param null|Expr $default Default value
|
||||
* @param null|string|Identifier|Name|NullableType|UnionType $type Type declaration
|
||||
* @param bool $byRef Whether is passed by reference
|
||||
* @param bool $variadic Whether this is a variadic argument
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(
|
||||
$var, Expr $default = null, $type = null,
|
||||
|
@ -15,7 +15,7 @@ class ClassMethod extends Node\Stmt implements FunctionLike
|
||||
public $name;
|
||||
/** @var Node\Param[] Parameters */
|
||||
public $params;
|
||||
/** @var null|Node\Identifier|Node\Name|Node\NullableType Return type */
|
||||
/** @var null|Node\Identifier|Node\Name|Node\NullableType|Node\UnionType Return type */
|
||||
public $returnType;
|
||||
/** @var Node\Stmt[]|null Statements */
|
||||
public $stmts;
|
||||
|
@ -16,7 +16,7 @@ class Function_ extends Node\Stmt implements FunctionLike
|
||||
public $name;
|
||||
/** @var Node\Param[] Parameters */
|
||||
public $params;
|
||||
/** @var null|Node\Identifier|Node\Name|Node\NullableType Return type */
|
||||
/** @var null|Node\Identifier|Node\Name|Node\NullableType|Node\UnionType Return type */
|
||||
public $returnType;
|
||||
/** @var Node\Stmt[] Statements */
|
||||
public $stmts;
|
||||
|
@ -6,6 +6,7 @@ use PhpParser\Node;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\NullableType;
|
||||
use PhpParser\Node\UnionType;
|
||||
|
||||
class Property extends Node\Stmt
|
||||
{
|
||||
@ -13,16 +14,16 @@ class Property extends Node\Stmt
|
||||
public $flags;
|
||||
/** @var PropertyProperty[] Properties */
|
||||
public $props;
|
||||
/** @var null|Identifier|Name|NullableType Type declaration */
|
||||
/** @var null|Identifier|Name|NullableType|UnionType Type declaration */
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* Constructs a class property list node.
|
||||
*
|
||||
* @param int $flags Modifiers
|
||||
* @param PropertyProperty[] $props Properties
|
||||
* @param array $attributes Additional attributes
|
||||
* @param null|string|Identifier|Name|NullableType $type Type declaration
|
||||
* @param int $flags Modifiers
|
||||
* @param PropertyProperty[] $props Properties
|
||||
* @param array $attributes Additional attributes
|
||||
* @param null|string|Identifier|Name|NullableType|UnionType $type Type declaration
|
||||
*/
|
||||
public function __construct(int $flags, array $props, array $attributes = [], $type = null) {
|
||||
$this->attributes = $attributes;
|
||||
|
30
lib/PhpParser/Node/UnionType.php
Normal file
30
lib/PhpParser/Node/UnionType.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node;
|
||||
|
||||
use PhpParser\NodeAbstract;
|
||||
|
||||
class UnionType extends NodeAbstract
|
||||
{
|
||||
/** @var (Identifier|Name)[] Types */
|
||||
public $types;
|
||||
|
||||
/**
|
||||
* Constructs a union 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 'UnionType';
|
||||
}
|
||||
}
|
@ -162,12 +162,18 @@ class NameResolver extends NodeVisitorAbstract
|
||||
}
|
||||
|
||||
private function resolveType($node) {
|
||||
if ($node instanceof Name) {
|
||||
return $this->resolveClassName($node);
|
||||
}
|
||||
if ($node instanceof Node\NullableType) {
|
||||
$node->type = $this->resolveType($node->type);
|
||||
return $node;
|
||||
}
|
||||
if ($node instanceof Name) {
|
||||
return $this->resolveClassName($node);
|
||||
if ($node instanceof Node\UnionType) {
|
||||
foreach ($node->types as &$type) {
|
||||
$type = $this->resolveType($type);
|
||||
}
|
||||
return $node;
|
||||
}
|
||||
return $node;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -656,6 +656,8 @@ abstract class ParserAbstract implements Parser
|
||||
'iterable' => true,
|
||||
'void' => true,
|
||||
'object' => true,
|
||||
'null' => true,
|
||||
'false' => true,
|
||||
];
|
||||
|
||||
if (!$name->isUnqualified()) {
|
||||
|
@ -37,6 +37,10 @@ class Standard extends PrettyPrinterAbstract
|
||||
return '?' . $this->p($node->type);
|
||||
}
|
||||
|
||||
protected function pUnionType(Node\UnionType $node) {
|
||||
return $this->pImplode($node->types, '|');
|
||||
}
|
||||
|
||||
protected function pIdentifier(Node\Identifier $node) {
|
||||
return $node->name;
|
||||
}
|
||||
|
@ -1295,6 +1295,7 @@ abstract class PrettyPrinterAbstract
|
||||
//'Expr_ShellExec->parts' => '', // TODO These need to be treated more carefully
|
||||
//'Scalar_Encapsed->parts' => '',
|
||||
'Stmt_Catch->types' => '|',
|
||||
'UnionType->types' => '|',
|
||||
'Stmt_If->elseifs' => ' ',
|
||||
'Stmt_TryCatch->catches' => ' ',
|
||||
|
||||
@ -1396,6 +1397,7 @@ abstract class PrettyPrinterAbstract
|
||||
* Stmt_TraitUseAdaptation_Precedence->insteadof
|
||||
* Stmt_Unset->vars
|
||||
* Stmt_Use->uses
|
||||
* UnionType->types
|
||||
*/
|
||||
|
||||
/* TODO
|
||||
|
@ -94,13 +94,6 @@ namespace Baz {
|
||||
C;
|
||||
E;
|
||||
K;
|
||||
|
||||
class ClassWithTypeProperties
|
||||
{
|
||||
public float $php = 7.4;
|
||||
public ?Foo $person;
|
||||
protected static ?bool $probability;
|
||||
}
|
||||
}
|
||||
EOC;
|
||||
$expectedCode = <<<'EOC'
|
||||
@ -169,12 +162,6 @@ namespace Baz {
|
||||
\Y\T\B\C;
|
||||
\Y\T\D\E;
|
||||
\Z\T\K;
|
||||
class ClassWithTypeProperties
|
||||
{
|
||||
public float $php = 7.4;
|
||||
public ?\Baz\Foo $person;
|
||||
protected static ?bool $probability;
|
||||
}
|
||||
}
|
||||
EOC;
|
||||
|
||||
@ -210,6 +197,14 @@ 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;
|
||||
}
|
||||
|
||||
class ClassWithTypeProperties {
|
||||
public float $php = 7.4;
|
||||
public ?Foo $person;
|
||||
protected static ?bool $probability;
|
||||
public A|B|int $prop;
|
||||
}
|
||||
|
||||
function f(A $a) : A {}
|
||||
@ -252,6 +247,14 @@ class A extends \NS\B implements \NS\C, \NS\D
|
||||
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;
|
||||
}
|
||||
class ClassWithTypeProperties
|
||||
{
|
||||
public float $php = 7.4;
|
||||
public ?\NS\Foo $person;
|
||||
protected static ?bool $probability;
|
||||
public \NS\A|\NS\B|int $prop;
|
||||
}
|
||||
function f(\NS\A $a) : \NS\A
|
||||
{
|
||||
|
@ -306,4 +306,14 @@ $stmts[0]->expr->expr->items[] = new Expr\ArrayItem(new Scalar\LNumber(24));
|
||||
$array = [
|
||||
1, 2,
|
||||
3, 24,
|
||||
];
|
||||
];
|
||||
-----
|
||||
<?php
|
||||
function test(): A
|
||||
|B {}
|
||||
-----
|
||||
$stmts[0]->returnType->types[] = new Node\Name('C');
|
||||
-----
|
||||
<?php
|
||||
function test(): A
|
||||
|B|C {}
|
@ -38,4 +38,15 @@ function foo(
|
||||
$b,
|
||||
$x,
|
||||
$y
|
||||
) {}
|
||||
) {}
|
||||
-----
|
||||
<?php
|
||||
function test(): A
|
||||
|B
|
||||
|C {}
|
||||
-----
|
||||
array_pop($stmts[0]->returnType->types);
|
||||
-----
|
||||
<?php
|
||||
function test(): A
|
||||
|B {}
|
92
test/code/parser/stmt/function/unionTypes.test
Normal file
92
test/code/parser/stmt/function/unionTypes.test
Normal file
@ -0,0 +1,92 @@
|
||||
Union types
|
||||
-----
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public A|iterable|null $prop;
|
||||
}
|
||||
|
||||
function test(A|B $a): int|false {}
|
||||
-----
|
||||
!!php7
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Test
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
flags: MODIFIER_PUBLIC (1)
|
||||
type: UnionType(
|
||||
types: array(
|
||||
0: Name(
|
||||
parts: array(
|
||||
0: A
|
||||
)
|
||||
)
|
||||
1: Identifier(
|
||||
name: iterable
|
||||
)
|
||||
2: Identifier(
|
||||
name: null
|
||||
)
|
||||
)
|
||||
)
|
||||
props: array(
|
||||
0: Stmt_PropertyProperty(
|
||||
name: VarLikeIdentifier(
|
||||
name: prop
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
1: Stmt_Function(
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: test
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
type: UnionType(
|
||||
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: UnionType(
|
||||
types: array(
|
||||
0: Identifier(
|
||||
name: int
|
||||
)
|
||||
1: Identifier(
|
||||
name: false
|
||||
)
|
||||
)
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
)
|
18
test/code/prettyPrinter/stmt/union_types.test
Normal file
18
test/code/prettyPrinter/stmt/union_types.test
Normal file
@ -0,0 +1,18 @@
|
||||
Union types
|
||||
-----
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public A|iterable|null $prop;
|
||||
}
|
||||
|
||||
function test(A|B $a): int|false {}
|
||||
-----
|
||||
!!php7
|
||||
class Test
|
||||
{
|
||||
public A|iterable|null $prop;
|
||||
}
|
||||
function test(A|B $a) : int|false
|
||||
{
|
||||
}
|
Loading…
Reference in New Issue
Block a user