ReduceResult (@NotNull PsiElement context, @NotNull Map<ReduceResultCacheContext, ReduceResult> cache) { boolean changed = false; Map<PsiType, Set<PatternDeconstructionDescription>> byType = StreamEx.of(patterns) .select(PatternDeconstructionDescription.class) .groupingBy(t -> t.type(), Collectors.toSet()); Set<PatternDescription> toRemove = new HashSet<>(); Set<PatternDescription> toAdd = new HashSet<>(); Map<PsiType, List<PsiType>> componentCaches = new HashMap<>(); for (Map.Entry<PsiType, Set<PatternDeconstructionDescription>> entry : byType.entrySet()) { Set<PatternDeconstructionDescription> descriptions = entry.getValue(); if (descriptions.isEmpty()) { continue; } PatternDeconstructionDescription first = descriptions.iterator().next(); for (int i = 0; i < first.list().size(); i++) { MultiMap<List<PatternDescription>, PatternDeconstructionDescription> groupWithoutOneComponent = getGroupWithoutOneComponent(descriptions, i); for (Map.Entry<List<PatternDescription>, Collection<PatternDeconstructionDescription>> value : groupWithoutOneComponent.entrySet()) { Collection<PatternDeconstructionDescription> setWithOneDifferentElement = value.getValue(); if (setWithOneDifferentElement.isEmpty()) { continue; } int finalI = i; Set<PatternDescription> nestedDescriptions = setWithOneDifferentElement.stream() .map(t -> t.list().get(finalI)) .collect(Collectors.toSet()); PsiType recordType = entry.getKey(); List<PsiType> componentTypes = componentCaches.get(recordType); if (componentTypes == null) { componentTypes = getComponentTypes(context, recordType); componentCaches.put(recordType, componentTypes); } if (componentTypes == null || componentTypes.size() <= i) { continue; } LoopReduceResult result = reduceInLoop(componentTypes.get(i), context, nestedDescriptions, (set, type) -> false, cache); if (result.changed()) { changed = true; toRemove.addAll(setWithOneDifferentElement); toAdd.addAll(createPatternsFrom(i, result.patterns(), setWithOneDifferentElement.iterator().next())); } } } } if (!changed) { return new ReduceResult(patterns, changed()); } return new ReduceResult(combineResult(patterns, toRemove, toAdd), true); }