@@ -628,18 +628,7 @@ private function resolveType(Expr $node): Type
628628$ leftType =$ this ->getType ($ node ->left );
629629$ rightType =$ this ->getType ($ node ->right );
630630
631- $ stringType =new StringType ();
632- $ integerType =new IntegerType ();
633- $ floatType =new FloatType ();
634- if (
635- ($ stringType ->isSuperTypeOf ($ leftType )->yes () &&$ stringType ->isSuperTypeOf ($ rightType )->yes ())
636- || ($ integerType ->isSuperTypeOf ($ leftType )->yes () &&$ integerType ->isSuperTypeOf ($ rightType )->yes ())
637- || ($ floatType ->isSuperTypeOf ($ leftType )->yes () &&$ floatType ->isSuperTypeOf ($ rightType )->yes ())
638- ) {
639- return $ this ->getType (new Expr \BinaryOp \Identical ($ node ->left ,$ node ->right ));
640- }
641-
642- return new BooleanType ();
631+ return $ this ->resolveEqualType ($ leftType ,$ rightType );
643632}
644633
645634if ($ nodeinstanceof Expr \BinaryOp \NotEqual) {
@@ -2335,7 +2324,7 @@ private function resolveType(Expr $node): Type
23352324return new MixedType ();
23362325}
23372326
2338- private function resolveIdenticalType (Type $ leftType ,Type $ rightType ):Type
2327+ private function resolveIdenticalType (Type $ leftType ,Type $ rightType ):BooleanType
23392328{
23402329$ isSuperset =$ leftType ->isSuperTypeOf ($ rightType );
23412330if ($ isSuperset ->no ()) {
@@ -2350,65 +2339,93 @@ private function resolveIdenticalType(Type $leftType, Type $rightType): Type
23502339}
23512340
23522341if ($ leftTypeinstanceof ConstantArrayType &&$ rightTypeinstanceof ConstantArrayType) {
2353- $ leftValueTypes =$ leftType ->getValueTypes ();
2354- $ rightKeyTypes =$ rightType ->getKeyTypes ();
2355- $ rightValueTypes =$ rightType ->getValueTypes ();
2356- $ hasOptional =false ;
2357- foreach ($ leftType ->getKeyTypes ()as $ i =>$ keyType ) {
2358- if (!array_key_exists ($ i ,$ rightKeyTypes )) {
2359- if ($ leftType ->isOptionalKey ($ i )) {
2360- $ hasOptional =true ;
2361- continue ;
2362- }
2363- return new ConstantBooleanType (false );
2364- }
2342+ return $ this ->resolveConstantArrayTypeComparison ($ leftType ,$ rightType ,fn ($ leftValueType ,$ rightValueType ):BooleanType =>$ this ->resolveIdenticalType ($ leftValueType ,$ rightValueType ));
2343+ }
23652344
2366- $ rightKeyType =$ rightKeyTypes [$ i ];
2367- if (!$ keyType ->equals ($ rightKeyType )) {
2368- return new ConstantBooleanType (false );
2369- }
2345+ return new BooleanType ();
2346+ }
23702347
2371- $ leftValueType =$ leftValueTypes [$ i ];
2372- $ rightValueType =$ rightValueTypes [$ i ];
2373- $ leftIdenticalToRight =$ this ->resolveIdenticalType ($ leftValueType ,$ rightValueType );
2374- if ($ leftIdenticalToRightinstanceof ConstantBooleanType) {
2375- if (!$ leftIdenticalToRight ->getValue ()) {
2376- return new ConstantBooleanType (false );
2377- }
2378- $ isLeftOptional =$ leftType ->isOptionalKey ($ i );
2379- if ($ isLeftOptional ||$ rightType ->isOptionalKey ($ i )) {
2380- $ hasOptional =true ;
2381- }
2382- continue ;
2383- }
2348+ private function resolveEqualType (Type $ leftType ,Type $ rightType ):BooleanType
2349+ {
2350+ $ stringType =new StringType ();
2351+ $ integerType =new IntegerType ();
2352+ $ floatType =new FloatType ();
2353+ if (
2354+ ($ stringType ->isSuperTypeOf ($ leftType )->yes () &&$ stringType ->isSuperTypeOf ($ rightType )->yes ())
2355+ || ($ integerType ->isSuperTypeOf ($ leftType )->yes () &&$ integerType ->isSuperTypeOf ($ rightType )->yes ())
2356+ || ($ floatType ->isSuperTypeOf ($ leftType )->yes () &&$ floatType ->isSuperTypeOf ($ rightType )->yes ())
2357+ ) {
2358+ return $ this ->resolveIdenticalType ($ leftType ,$ rightType );
2359+ }
23842360
2385- $ hasOptional =true ;
2386- }
2361+ if ($ leftTypeinstanceof ConstantArrayType &&$ rightTypeinstanceof ConstantArrayType) {
2362+ return $ this ->resolveConstantArrayTypeComparison ($ leftType ,$ rightType ,fn ($ leftValueType ,$ rightValueType ):BooleanType =>$ this ->resolveEqualType ($ leftValueType ,$ rightValueType ));
2363+ }
23872364
2388- if (!isset ($ i )) {
2389- $ i =0 ;
2390- }else {
2391- $ i ++;
2392- }
2365+ return new BooleanType ();
2366+ }
23932367
2394- $ rightKeyTypesCount =count ($ rightKeyTypes );
2395- for (;$ i <$ rightKeyTypesCount ;$ i ++) {
2396- if ($ rightType ->isOptionalKey ($ i )) {
2368+ /**
2369+ * @param callable(Type, Type): BooleanType $valueComparisonCallback
2370+ */
2371+ private function resolveConstantArrayTypeComparison (ConstantArrayType $ leftType ,ConstantArrayType $ rightType ,callable $ valueComparisonCallback ):BooleanType
2372+ {
2373+ $ leftValueTypes =$ leftType ->getValueTypes ();
2374+ $ rightKeyTypes =$ rightType ->getKeyTypes ();
2375+ $ rightValueTypes =$ rightType ->getValueTypes ();
2376+ $ hasOptional =false ;
2377+ foreach ($ leftType ->getKeyTypes ()as $ i =>$ keyType ) {
2378+ if (!array_key_exists ($ i ,$ rightKeyTypes )) {
2379+ if ($ leftType ->isOptionalKey ($ i )) {
23972380$ hasOptional =true ;
23982381continue ;
23992382}
2383+ return new ConstantBooleanType (false );
2384+ }
24002385
2386+ $ rightKeyType =$ rightKeyTypes [$ i ];
2387+ if (!$ keyType ->equals ($ rightKeyType )) {
24012388return new ConstantBooleanType (false );
24022389}
24032390
2404- if ($ hasOptional ) {
2405- return new BooleanType ();
2391+ $ leftValueType =$ leftValueTypes [$ i ];
2392+ $ rightValueType =$ rightValueTypes [$ i ];
2393+ $ leftIdenticalToRight =$ valueComparisonCallback ($ leftValueType ,$ rightValueType );
2394+ if ($ leftIdenticalToRightinstanceof ConstantBooleanType) {
2395+ if (!$ leftIdenticalToRight ->getValue ()) {
2396+ return new ConstantBooleanType (false );
2397+ }
2398+ $ isLeftOptional =$ leftType ->isOptionalKey ($ i );
2399+ if ($ isLeftOptional ||$ rightType ->isOptionalKey ($ i )) {
2400+ $ hasOptional =true ;
2401+ }
2402+ continue ;
24062403}
24072404
2408- return new ConstantBooleanType ( true ) ;
2405+ $ hasOptional = true ;
24092406}
24102407
2411- return new BooleanType ();
2408+ if (!isset ($ i )) {
2409+ $ i =0 ;
2410+ }else {
2411+ $ i ++;
2412+ }
2413+
2414+ $ rightKeyTypesCount =count ($ rightKeyTypes );
2415+ for (;$ i <$ rightKeyTypesCount ;$ i ++) {
2416+ if ($ rightType ->isOptionalKey ($ i )) {
2417+ $ hasOptional =true ;
2418+ continue ;
2419+ }
2420+
2421+ return new ConstantBooleanType (false );
2422+ }
2423+
2424+ if ($ hasOptional ) {
2425+ return new BooleanType ();
2426+ }
2427+
2428+ return new ConstantBooleanType (true );
24122429}
24132430
24142431private function resolveConcatType (Expr \BinaryOp \Concat |Expr \AssignOp \Concat $ node ):Type