@@ -548,23 +548,26 @@ public function equals(SimpleType $other): bool {
548
548
class Type {
549
549
/** @var SimpleType[] */
550
550
public $ types ;
551
+ /** @var bool */
552
+ public $ isIntersection = false ;
551
553
552
554
public static function fromNode (Node $ node ): Type {
553
- if ($ node instanceof Node \UnionType) {
555
+ if ($ node instanceof Node \UnionType || $ node instanceof Node \IntersectionType ) {
554
556
$ nestedTypeObjects = array_map (['Type ' , 'fromNode ' ], $ node ->types );
555
557
$ types = [];
556
558
foreach ($ nestedTypeObjects as $ typeObject ) {
557
559
array_push ($ types , ...$ typeObject ->types );
558
560
}
559
- return new Type ($ types );
561
+ return new Type ($ types, ( $ node instanceof Node \IntersectionType) );
560
562
}
561
563
562
564
if ($ node instanceof Node \NullableType) {
563
565
return new Type (
564
566
[
565
567
...Type::fromNode ($ node ->type )->types ,
566
568
SimpleType::null (),
567
- ]
569
+ ],
570
+ false
568
571
);
569
572
}
570
573
@@ -573,18 +576,20 @@ public static function fromNode(Node $node): Type {
573
576
[
574
577
SimpleType::fromString ("Traversable " ),
575
578
ArrayType::createGenericArray (),
576
- ]
579
+ ],
580
+ false
577
581
);
578
582
}
579
583
580
- return new Type ([SimpleType::fromNode ($ node )]);
584
+ return new Type ([SimpleType::fromNode ($ node )], false );
581
585
}
582
586
583
587
public static function fromString (string $ typeString ): self {
584
588
$ typeString .= "| " ;
585
589
$ simpleTypes = [];
586
590
$ simpleTypeOffset = 0 ;
587
591
$ inArray = false ;
592
+ $ isIntersection = false ;
588
593
589
594
$ typeStringLength = strlen ($ typeString );
590
595
for ($ i = 0 ; $ i < $ typeStringLength ; $ i ++) {
@@ -604,7 +609,8 @@ public static function fromString(string $typeString): self {
604
609
continue ;
605
610
}
606
611
607
- if ($ char === "| " ) {
612
+ if ($ char === "| " || $ char === "& " ) {
613
+ $ isIntersection = ($ char === "& " );
608
614
$ simpleTypeName = trim (substr ($ typeString , $ simpleTypeOffset , $ i - $ simpleTypeOffset ));
609
615
610
616
$ simpleTypes [] = SimpleType::fromString ($ simpleTypeName );
@@ -613,14 +619,15 @@ public static function fromString(string $typeString): self {
613
619
}
614
620
}
615
621
616
- return new Type ($ simpleTypes );
622
+ return new Type ($ simpleTypes, $ isIntersection );
617
623
}
618
624
619
625
/**
620
626
* @param SimpleType[] $types
621
627
*/
622
- private function __construct (array $ types ) {
628
+ private function __construct (array $ types, bool $ isIntersection ) {
623
629
$ this ->types = $ types ;
630
+ $ this ->isIntersection = $ isIntersection ;
624
631
}
625
632
626
633
public function isScalar (): bool {
@@ -650,7 +657,8 @@ public function getWithoutNull(): Type {
650
657
function (SimpleType $ type ) {
651
658
return !$ type ->isNull ();
652
659
}
653
- )
660
+ ),
661
+ false
654
662
);
655
663
}
656
664
@@ -683,6 +691,7 @@ public function toOptimizerTypeMask(): string {
683
691
$ optimizerTypes = [];
684
692
685
693
foreach ($ this ->types as $ type ) {
694
+ // TODO Support for toOptimizerMask for intersection
686
695
$ optimizerTypes [] = $ type ->toOptimizerTypeMask ();
687
696
}
688
697
@@ -711,8 +720,9 @@ public function toOptimizerTypeMaskForArrayValue(): string {
711
720
712
721
public function getTypeForDoc (DOMDocument $ doc ): DOMElement {
713
722
if (count ($ this ->types ) > 1 ) {
723
+ $ typeSort = $ this ->isIntersection ? "intersection " : "union " ;
714
724
$ typeElement = $ doc ->createElement ('type ' );
715
- $ typeElement ->setAttribute ("class " , " union " );
725
+ $ typeElement ->setAttribute ("class " , $ typeSort );
716
726
717
727
foreach ($ this ->types as $ type ) {
718
728
$ unionTypeElement = $ doc ->createElement ('type ' , $ type ->name );
@@ -755,7 +765,8 @@ public function __toString() {
755
765
return 'mixed ' ;
756
766
}
757
767
758
- return implode ('| ' , array_map (
768
+ $ char = $ this ->isIntersection ? '& ' : '| ' ;
769
+ return implode ($ char , array_map (
759
770
function ($ type ) { return $ type ->name ; },
760
771
$ this ->types )
761
772
);
@@ -2237,7 +2248,11 @@ public function getDeclaration(iterable $allConstInfos): string {
2237
2248
2238
2249
$ typeMaskCode = $ this ->type ->toArginfoType ()->toTypeMask ();
2239
2250
2240
- $ code .= "\tzend_type property_ {$ propertyName }_type = ZEND_TYPE_INIT_UNION(property_ {$ propertyName }_type_list, $ typeMaskCode); \n" ;
2251
+ if ($ this ->type ->isIntersection ) {
2252
+ $ code .= "\tzend_type property_ {$ propertyName }_type = ZEND_TYPE_INIT_INTERSECTION(property_ {$ propertyName }_type_list, $ typeMaskCode); \n" ;
2253
+ } else {
2254
+ $ code .= "\tzend_type property_ {$ propertyName }_type = ZEND_TYPE_INIT_UNION(property_ {$ propertyName }_type_list, $ typeMaskCode); \n" ;
2255
+ }
2241
2256
$ typeCode = "property_ {$ propertyName }_type " ;
2242
2257
} else {
2243
2258
$ escapedClassName = $ arginfoType ->classTypes [0 ]->toEscapedName ();
0 commit comments