@@ -105,12 +105,13 @@ public function testArrayFlipDoesNotAssumeWhichDuplicateValueWins(): void
105105 ),
106106 ]))->resolve ();
107107 $ nativeOutcome = self ::constantArrayFromRuntime (['x ' => 'later ' ]);
108+ $ flippedResult = $ result ->flipArray ();
108109
109110 $ this ->assertTrue (
110- $ result -> flipArray () ->isSuperTypeOf ($ nativeOutcome )->yes (),
111+ $ flippedResult ->isSuperTypeOf ($ nativeOutcome )->yes (),
111112 sprintf (
112113 'Flipped inferred type %s must contain the native duplicate-value outcome %s. ' ,
113- $ result -> flipArray () ->describe (VerbosityLevel::precise ()),
114+ $ flippedResult ->describe (VerbosityLevel::precise ()),
114115 $ nativeOutcome ->describe (VerbosityLevel::precise ()),
115116 ),
116117 );
@@ -238,68 +239,6 @@ public function testBoundaryCasesContainRepresentativeNativeMergeOutcomes(): voi
238239 }
239240 }
240241
241- public function testUnusualAutoIndexStateIsNotRetainedInAConflictingShape (): void
242- {
243- $ unusualShape = new ConstantArrayType (
244- [new ConstantStringType ('fixed ' )],
245- [new StringType ()],
246- [7 ],
247- );
248-
249- $ result = (new ArrayMergeType ([
250- new ArrayType (new StringType (), new IntegerType ()),
251- $ unusualShape ,
252- ]))->resolve ();
253-
254- $ runtimeOutcome = self ::constantArrayFromRuntime (['fixed ' => 'shape ' ]);
255- $ this ->assertTrue (
256- $ result ->isSuperTypeOf ($ runtimeOutcome )->yes (),
257- 'The unusual construction metadata must not exclude the visible array_merge result. ' ,
258- );
259-
260- $ constantArrays = $ result ->getConstantArrays ();
261-
262- if ([] === $ constantArrays ) {
263- return ;
264- }
265-
266- foreach ($ constantArrays as $ constantArray ) {
267- $ this ->assertSame (
268- [0 ],
269- $ constantArray ->getNextAutoIndexes (),
270- 'array_merge creates a new array whose first available integer offset is zero. ' ,
271- );
272- }
273- }
274-
275- public function testLargeTrailingShapesUseConservativeFallback (): void
276- {
277- $ firstShapeKeyTypes = [];
278- $ firstShapeValueTypes = [];
279-
280- for ($ i = 0 ; $ i < 256 ; $ i ++) {
281- $ firstShapeKeyTypes [] = new ConstantStringType ('first ' . $ i );
282- $ firstShapeValueTypes [] = new ConstantIntegerType ($ i );
283- }
284-
285- $ result = (new ArrayMergeType ([
286- new ArrayType (new StringType (), new IntegerType ()),
287- new ConstantArrayType ($ firstShapeKeyTypes , $ firstShapeValueTypes ),
288- new ConstantArrayType (
289- [new ConstantStringType ('first0 ' ), new ConstantStringType ('last ' )],
290- [new ConstantStringType ('overwritten ' ), new ConstantStringType ('tail ' )],
291- ),
292- ]))->resolve ();
293-
294- $ this ->assertSame ([], $ result ->getConstantArrays ());
295- $ this ->assertTrue (TypeCombinator::union (
296- new IntegerType (),
297- new ConstantStringType ('overwritten ' ),
298- new ConstantStringType ('tail ' ),
299- )->equals ($ result ->getIterableValueType ()));
300- $ this ->assertTrue ($ result ->hasOffsetValueType (new ConstantStringType ('first0 ' ))->maybe ());
301- }
302-
303242 public function testMultipleTrailingShapesRemainBroadAndContainNativeOutcome (): void
304243 {
305244 $ runtimeShapes = [
@@ -338,115 +277,6 @@ public function testMultipleTrailingShapesRemainBroadAndContainNativeOutcome():
338277 )->yes ());
339278 }
340279
341- public function testDisqualifiedThirdOperandForcesConservativeFallback (): void
342- {
343- $ generic = new ArrayType (new StringType (), new IntegerType ());
344- $ validShape = new ConstantArrayType (
345- [new ConstantStringType ('fixed ' )],
346- [new StringType ()],
347- );
348- $ optionalShape = new ConstantArrayType (
349- [new ConstantStringType ('fixed ' )],
350- [new BooleanType ()],
351- [0 ],
352- [0 ],
353- );
354- $ integerShape = new ConstantArrayType (
355- [new ConstantIntegerType (7 )],
356- [new BooleanType ()],
357- [8 ],
358- );
359- $ canonicalIntegerStringShape = new ConstantArrayType (
360- [new ConstantStringType ('7 ' )],
361- [new BooleanType ()],
362- );
363- $ otherShape = new ConstantArrayType (
364- [new ConstantStringType ('other ' )],
365- [new BooleanType ()],
366- );
367- $ unusualAutoIndexShape = new ConstantArrayType (
368- [new ConstantStringType ('other ' )],
369- [new BooleanType ()],
370- [7 ],
371- );
372-
373- /**
374- * @var array<string, array{
375- * non-empty-list<Type>,
376- * non-empty-list<array<int|string, bool|int|string>>
377- * }> $scenarios
378- */
379- $ scenarios = [
380- 'optional keys ' => [
381- [$ generic , $ validShape , $ optionalShape ],
382- [['dynamic ' => 1 ], ['fixed ' => 'shape ' ], []],
383- ],
384- 'integer keys ' => [
385- [$ generic , $ validShape , $ integerShape ],
386- [['dynamic ' => 1 ], ['fixed ' => 'shape ' ], [7 => true ]],
387- ],
388- 'canonical integer string keys ' => [
389- [$ generic , $ validShape , $ canonicalIntegerStringShape ],
390- [['dynamic ' => 1 ], ['fixed ' => 'shape ' ], [7 => true ]],
391- ],
392- 'shape unions ' => [
393- [$ generic , $ validShape , new UnionType ([$ validShape , $ otherShape ])],
394- [['dynamic ' => 1 ], ['fixed ' => 'shape ' ], ['other ' => true ]],
395- ],
396- 'shape intersections ' => [
397- [$ generic , $ validShape , new IntersectionType ([$ otherShape , new NonEmptyArrayType ()])],
398- [['dynamic ' => 1 ], ['fixed ' => 'shape ' ], ['other ' => true ]],
399- ],
400- 'generic operands after shapes ' => [
401- [$ generic , $ validShape , new ArrayType (new StringType (), new BooleanType ())],
402- [['dynamic ' => 1 ], ['fixed ' => 'shape ' ], ['fixed ' => true ]],
403- ],
404- 'empty shapes ' => [
405- [$ generic , $ validShape , ConstantArrayTypeBuilder::createEmpty ()->getArray ()],
406- [['dynamic ' => 1 ], ['fixed ' => 'shape ' ], []],
407- ],
408- 'unusual auto-index metadata ' => [
409- [$ generic , $ validShape , $ unusualAutoIndexShape ],
410- [['dynamic ' => 1 ], ['fixed ' => 'shape ' ], ['other ' => true ]],
411- ],
412- ];
413-
414- if (self ::supportsUnsealedShapes ()) {
415- $ unsealedShape = new ConstantArrayType (
416- [new ConstantStringType ('other ' )],
417- [new BooleanType ()],
418- [0 ],
419- [],
420- TrinaryLogic::createNo (),
421- [new StringType (), new BooleanType ()],
422- );
423- $ scenarios ['unsealed shapes ' ] = [
424- [$ generic , $ validShape , $ unsealedShape ],
425- [['dynamic ' => 1 ], ['fixed ' => 'shape ' ], ['other ' => true , 'extra ' => false ]],
426- ];
427- }
428-
429- foreach ($ scenarios as $ name => [$ declaredTypes , $ runtimeOperands ]) {
430- $ result = (new ArrayMergeType ($ declaredTypes ))->resolve ();
431- $ this ->assertSame (
432- [],
433- $ result ->getConstantArrays (),
434- sprintf ('Scenario %s must retain the prior conservative fallback. ' , $ name ),
435- );
436-
437- $ runtimeOutcome = self ::constantArrayFromRuntime (array_merge (...$ runtimeOperands ));
438- $ this ->assertTrue (
439- $ result ->isSuperTypeOf ($ runtimeOutcome )->yes (),
440- sprintf (
441- 'Scenario %s inferred %s, which excludes native result %s. ' ,
442- $ name ,
443- $ result ->describe (VerbosityLevel::precise ()),
444- $ runtimeOutcome ->describe (VerbosityLevel::precise ()),
445- ),
446- );
447- }
448- }
449-
450280 private static function supportsUnsealedShapes (): bool
451281 {
452282 return self ::hasOptionalMethod (ConstantArrayTypeBuilder::createEmpty (), 'makeUnsealed ' );
0 commit comments