@@ -827,30 +827,33 @@ private boolean exhausts(JCExpression selector, List<JCCase> cases) {
827827 }
828828 }
829829 Set <PatternDescription > patterns = patternSet ;
830- boolean genericPatternsExpanded = false ;
830+ boolean useHashes = true ;
831831 try {
832832 boolean repeat = true ;
833833 while (repeat ) {
834834 Set <PatternDescription > updatedPatterns ;
835835 updatedPatterns = reduceBindingPatterns (selector .type , patterns );
836- updatedPatterns = reduceNestedPatterns (updatedPatterns );
836+ updatedPatterns = reduceNestedPatterns (updatedPatterns , useHashes );
837837 updatedPatterns = reduceRecordPatterns (updatedPatterns );
838838 updatedPatterns = removeCoveredRecordPatterns (updatedPatterns );
839839 repeat = !updatedPatterns .equals (patterns );
840840 if (checkCovered (selector .type , patterns )) {
841841 return true ;
842842 }
843- if (!repeat && ! genericPatternsExpanded ) {
843+ if (!repeat ) {
844844 //there may be situation like:
845- //class B extends S1, S2
845+ //class B permits S1, S2
846846 //patterns: R(S1, B), R(S2, S2)
847- //this should be joined to R(B, S2),
847+ //this might be joined to R(B, S2), as B could be rewritten to S2
848848 //but hashing in reduceNestedPatterns will not allow that
849- //attempt to once expand all types to their transitive permitted types,
850- //on all depth of nesting:
851- updatedPatterns = expandGenericPatterns (updatedPatterns );
852- genericPatternsExpanded = true ;
853- repeat = !updatedPatterns .equals (patterns );
849+ //disable the use of hashing, and use subtyping in
850+ //reduceNestedPatterns to handle situations like this:
851+ repeat = useHashes ;
852+ useHashes = false ;
853+ } else {
854+ //if a reduction happened, make sure hashing in reduceNestedPatterns
855+ //is enabled, as the hashing speeds up the process significantly:
856+ useHashes = true ;
854857 }
855858 patterns = updatedPatterns ;
856859 }
@@ -1023,8 +1026,15 @@ private List<ClassSymbol> baseClasses(TypeSymbol root) {
10231026 * simplify the pattern. If that succeeds, the original found sub-set
10241027 * of patterns is replaced with a new set of patterns of the form:
10251028 * $record($prefix$, $resultOfReduction, $suffix$)
1029+ *
1030+ * useHashes: when true, patterns will be subject to exact equivalence;
1031+ * when false, two binding patterns will be considered equivalent
1032+ * if one of them is more generic than the other one;
1033+ * when false, the processing will be significantly slower,
1034+ * as pattern hashes cannot be used to speed up the matching process
10261035 */
1027- private Set <PatternDescription > reduceNestedPatterns (Set <PatternDescription > patterns ) {
1036+ private Set <PatternDescription > reduceNestedPatterns (Set <PatternDescription > patterns ,
1037+ boolean useHashes ) {
10281038 /* implementation note:
10291039 * finding a sub-set of patterns that only differ in a single
10301040 * column is time-consuming task, so this method speeds it up by:
@@ -1049,13 +1059,13 @@ private Set<PatternDescription> reduceNestedPatterns(Set<PatternDescription> pat
10491059 mismatchingCandidate < nestedPatternsCount ;
10501060 mismatchingCandidate ++) {
10511061 int mismatchingCandidateFin = mismatchingCandidate ;
1052- var groupByHashes =
1062+ var groupEquivalenceCandidates =
10531063 current
10541064 .stream ()
10551065 //error recovery, ignore patterns with incorrect number of nested patterns:
10561066 .filter (pd -> pd .nested .length == nestedPatternsCount )
1057- .collect (groupingBy (pd -> pd .hashCode (mismatchingCandidateFin )));
1058- for (var candidates : groupByHashes .values ()) {
1067+ .collect (groupingBy (pd -> useHashes ? pd .hashCode (mismatchingCandidateFin ) : 0 ));
1068+ for (var candidates : groupEquivalenceCandidates .values ()) {
10591069 var candidatesArr = candidates .toArray (RecordPattern []::new );
10601070
10611071 for (int firstCandidate = 0 ;
@@ -1076,24 +1086,35 @@ private Set<PatternDescription> reduceNestedPatterns(Set<PatternDescription> pat
10761086 RecordPattern rpOther = candidatesArr [nextCandidate ];
10771087 if (rpOne .recordType .tsym == rpOther .recordType .tsym ) {
10781088 for (int i = 0 ; i < rpOne .nested .length ; i ++) {
1079- if (i != mismatchingCandidate &&
1080- !rpOne .nested [i ].equals (rpOther .nested [i ])) {
1081- continue NEXT_PATTERN ;
1089+ if (i != mismatchingCandidate ) {
1090+ if (!rpOne .nested [i ].equals (rpOther .nested [i ])) {
1091+ if (useHashes ||
1092+ //when not using hashes,
1093+ //check if rpOne.nested[i] is
1094+ //a subtype of rpOther.nested[i]:
1095+ !(rpOne .nested [i ] instanceof BindingPattern bpOne ) ||
1096+ !(rpOther .nested [i ] instanceof BindingPattern bpOther ) ||
1097+ !types .isSubtype (types .erasure (bpOne .type ), types .erasure (bpOther .type ))) {
1098+ continue NEXT_PATTERN ;
1099+ }
1100+ }
10821101 }
10831102 }
10841103 join .append (rpOther );
10851104 }
10861105 }
10871106
10881107 var nestedPatterns = join .stream ().map (rp -> rp .nested [mismatchingCandidateFin ]).collect (Collectors .toSet ());
1089- var updatedPatterns = reduceNestedPatterns (nestedPatterns );
1108+ var updatedPatterns = reduceNestedPatterns (nestedPatterns , useHashes );
10901109
10911110 updatedPatterns = reduceRecordPatterns (updatedPatterns );
10921111 updatedPatterns = removeCoveredRecordPatterns (updatedPatterns );
10931112 updatedPatterns = reduceBindingPatterns (rpOne .fullComponentTypes ()[mismatchingCandidateFin ], updatedPatterns );
10941113
10951114 if (!nestedPatterns .equals (updatedPatterns )) {
1096- current .removeAll (join );
1115+ if (useHashes ) {
1116+ current .removeAll (join );
1117+ }
10971118
10981119 for (PatternDescription nested : updatedPatterns ) {
10991120 PatternDescription [] newNested =
@@ -1169,40 +1190,6 @@ private PatternDescription reduceRecordPattern(PatternDescription pattern) {
11691190 return pattern ;
11701191 }
11711192
1172- private Set <PatternDescription > expandGenericPatterns (Set <PatternDescription > patterns ) {
1173- var newPatterns = new HashSet <PatternDescription >(patterns );
1174- boolean modified ;
1175- do {
1176- modified = false ;
1177- for (PatternDescription pd : patterns ) {
1178- if (pd instanceof RecordPattern rpOne ) {
1179- for (int i = 0 ; i < rpOne .nested .length ; i ++) {
1180- Set <PatternDescription > toExpand = Set .of (rpOne .nested [i ]);
1181- Set <PatternDescription > expanded = expandGenericPatterns (toExpand );
1182- if (expanded != toExpand ) {
1183- expanded .removeAll (toExpand );
1184- for (PatternDescription exp : expanded ) {
1185- PatternDescription [] newNested = Arrays .copyOf (rpOne .nested , rpOne .nested .length );
1186- newNested [i ] = exp ;
1187- modified |= newPatterns .add (new RecordPattern (rpOne .recordType (), rpOne .fullComponentTypes (), newNested ));
1188- }
1189- }
1190- }
1191- } else if (pd instanceof BindingPattern bp ) {
1192- Set <Symbol > permittedSymbols = allPermittedSubTypes (bp .type .tsym , cs -> true );
1193-
1194- if (!permittedSymbols .isEmpty ()) {
1195- for (Symbol permitted : permittedSymbols ) {
1196- //TODO infer.instantiatePatternType(selectorType, csym); (?)
1197- modified |= newPatterns .add (new BindingPattern (permitted .type ));
1198- }
1199- }
1200- }
1201- }
1202- } while (modified );
1203- return newPatterns ;
1204- }
1205-
12061193 private Set <PatternDescription > removeCoveredRecordPatterns (Set <PatternDescription > patterns ) {
12071194 Set <Symbol > existingBindings = patterns .stream ()
12081195 .filter (pd -> pd instanceof BindingPattern )
0 commit comments