2121import java .io .IOException ;
2222import java .util .ArrayList ;
2323import java .util .Collections ;
24+ import java .util .EnumSet ;
2425import java .util .List ;
2526import java .util .Random ;
2627
@@ -1544,7 +1545,10 @@ public void randomizedClassInterfaceModuleDispatchMatchesAllBackends() {
15441545 public void randomizedGenericTupleDispatchMatchesJassAndLua () {
15451546 Random random = new Random (0x71A9D15CL );
15461547 for (int caseIndex = 0 ; caseIndex < 8 ; caseIndex ++) {
1547- List <String > source = genericTupleDispatchCase (random , caseIndex );
1548+ EnumSet <GenericDispatchShape > covered = EnumSet .noneOf (GenericDispatchShape .class );
1549+ List <String > source = genericTupleDispatchCase (random , covered );
1550+ assertEquals ("dispatch fuzz case must cover every semantic specialization shape" ,
1551+ EnumSet .allOf (GenericDispatchShape .class ), covered );
15481552 String [] lines = source .toArray (new String [0 ]);
15491553 try {
15501554 test ().executeProg ().lines (lines );
@@ -1565,6 +1569,17 @@ public void randomizedGenericTupleDispatchMatchesJassAndLua() {
15651569 }
15661570 }
15671571
1572+ private enum GenericDispatchShape {
1573+ TUPLE_INT ,
1574+ TUPLE_TEXT ,
1575+ NESTED_TUPLE_INT ,
1576+ NESTED_TUPLE_TEXT ,
1577+ CLASS_PREDICATE ,
1578+ OTHER_CLASS_PREDICATE ,
1579+ OTHER_CLASS_PREDICATE_SECOND_TYPE ,
1580+ CLASS_IMPLEMENTATION
1581+ }
1582+
15681583 /** A user method beginning with {@code destroy} is ordinary virtual dispatch, not lifecycle
15691584 * destruction. The lifecycle slot is identified from the generated OnDestroy function. */
15701585 @ Test
@@ -1592,7 +1607,8 @@ public void ordinaryDestroyNamedMethodDoesNotUseLifecycleDispatchSlot() throws I
15921607 assertFalse (dispatchBody .contains (".__wurst_destroy" ));
15931608 }
15941609
1595- private List <String > genericTupleDispatchCase (Random random , int caseIndex ) {
1610+ private List <String > genericTupleDispatchCase (Random random ,
1611+ EnumSet <GenericDispatchShape > covered ) {
15961612 List <String > source = new ArrayList <>();
15971613 Collections .addAll (source ,
15981614 "package Test" ,
@@ -1636,46 +1652,59 @@ private List<String> genericTupleDispatchCase(Random random, int caseIndex) {
16361652 " int successes = 0" );
16371653
16381654 int expected = 0 ;
1655+ List <GenericDispatchShape > shapes = new ArrayList <>(
1656+ EnumSet .allOf (GenericDispatchShape .class ));
1657+ Collections .shuffle (shapes , random );
16391658 for (int i = 0 ; i < 16 ; i ++) {
16401659 int value = random .nextInt (100 ) + 1 ;
1641- switch (random .nextInt (7 )) {
1642- case 0 -> {
1660+ GenericDispatchShape shape = i < shapes .size ()
1661+ ? shapes .get (i )
1662+ : shapes .get (random .nextInt (shapes .size ()));
1663+ covered .add (shape );
1664+ switch (shape ) {
1665+ case TUPLE_INT -> {
16431666 source .add (" let value" + i + " = new Box<PairInt>(PairInt(" + value + ", " + (value + 1 ) + "))" );
16441667 source .add (" if value" + i + ".matches(x -> x.a == " + value + ")" );
16451668 source .add (" successes++" );
16461669 source .add (" destroy value" + i );
16471670 }
1648- case 1 -> {
1671+ case TUPLE_TEXT -> {
16491672 source .add (" let value" + i + " = new Box<PairText>(PairText(\" v" + value + "\" , " + value + "))" );
16501673 source .add (" if value" + i + ".matches(x -> x.a == \" v" + value + "\" )" );
16511674 source .add (" successes++" );
16521675 source .add (" destroy value" + i );
16531676 }
1654- case 2 -> {
1677+ case NESTED_TUPLE_INT -> {
16551678 source .add (" let value" + i + " = new Nested<PairInt>(PairInt(" + value + ", " + (value + 2 ) + "))" );
16561679 source .add (" if value" + i + ".matches(x -> x.b == " + (value + 2 ) + ")" );
16571680 source .add (" successes++" );
16581681 source .add (" destroy value" + i );
16591682 }
1660- case 3 -> {
1683+ case NESTED_TUPLE_TEXT -> {
1684+ source .add (" let value" + i + " = new Nested<PairText>(PairText(\" v" + value + "\" , " + value + "))" );
1685+ source .add (" if value" + i + ".matches(x -> x.a == \" v" + value + "\" )" );
1686+ source .add (" successes++" );
1687+ source .add (" destroy value" + i );
1688+ }
1689+ case CLASS_PREDICATE -> {
16611690 source .add (" let value" + i + " = new Box<Foo>(new Foo())" );
16621691 source .add (" if value" + i + ".matches(x -> x != null)" );
16631692 source .add (" successes++" );
16641693 source .add (" destroy value" + i );
16651694 }
1666- case 4 -> {
1695+ case OTHER_CLASS_PREDICATE -> {
16671696 source .add (" let value" + i + " = new OtherBox<Foo>(new Foo())" );
16681697 source .add (" if value" + i + ".matches(x -> x != null)" );
16691698 source .add (" successes++" );
16701699 source .add (" destroy value" + i );
16711700 }
1672- case 5 -> {
1701+ case OTHER_CLASS_PREDICATE_SECOND_TYPE -> {
16731702 source .add (" let value" + i + " = new OtherBox<Bar>(new Bar())" );
16741703 source .add (" if value" + i + ".matches(x -> x != null)" );
16751704 source .add (" successes++" );
16761705 source .add (" destroy value" + i );
16771706 }
1678- default -> {
1707+ case CLASS_IMPLEMENTATION -> {
16791708 source .add (" let value" + i + " = new Box<Foo>(new Foo())" );
16801709 source .add (" if value" + i + ".matches(new FooPredicate())" );
16811710 source .add (" successes++" );
0 commit comments