private static @NotNull NodeToUpdate trieDescend(@NotNull NewVirtualFileSystem fs,
                                          @NotNull NewVirtualFileSystem currentFS,
                                          @NotNull List<String> names,
                                          @Nullable NewVirtualFile fsRoot,
                                          @NotNull FilePartNode currentNode,
                                          @NotNull FilePartNode parentNode) {
    VirtualFile NEVER_TRIED_TO_FIND = NullVirtualFile.INSTANCE;
    // we try to never call file.findChild() until absolutely necessary, because it's expensive;
    // instead, rely on string name matching as long as possible
    VirtualFile currentFile = NEVER_TRIED_TO_FIND;
    for (int i = names.size() - 1; i >= 0; i--) {
      String name = names.get(i);
      currentFS = enterJar(fs, currentFS, name);

      int index = currentNode.binarySearchChildByName(name);
      if (index >= 0) {
        parentNode = currentNode;
        currentNode = currentNode.children[index];
        //noinspection UseVirtualFileEquals
        currentFile = currentFile == NEVER_TRIED_TO_FIND || currentFile == null ? currentFile : currentFile.findChild(name);
        continue;
      }

      // create and insert new node
      // first, have to check if the file root/names(end)/.../names[i] exists
      // if yes, create nameId-based FilePartNode (for faster search and memory efficiency),
      // if not, create temp UrlPartNode which will be replaced with FPPN when the real file is created
      //noinspection UseVirtualFileEquals
      if (currentFile == NEVER_TRIED_TO_FIND) {
        fsRoot = findRoot(fs, names, fsRoot);
        currentFile = fsRoot == null ? null : findFileFromRoot(fsRoot, currentFS, names, i);
      }
      else {
        currentFile = currentFile == null ? null : findChildThroughJar(currentFile, name, currentFS);
      }

      // check that found child name is the same as the one we were looking for
      // otherwise it may be the 8.3 abbreviation, which we should expand and look again
      //noinspection UseVirtualFileEquals
      if (currentFile != null && currentFile != NEVER_TRIED_TO_FIND && !currentFile.getName().equals(name)) {
        name = currentFile.getName();
        index = currentNode.binarySearchChildByName(name);
        if (index >= 0) {
          parentNode = currentNode;
          currentNode = currentNode.children[index];
          continue;
        }
      }

      FilePartNode child = createNode(currentFS, currentNode, currentFile, name);

      currentNode.children = ArrayUtil.insert(currentNode.children, -index - 1, child);
      parentNode = currentNode;
      currentNode = child;
    }
    return new NodeToUpdate(parentNode, currentNode);
  }
private static @NotNull NodeToUpdate trieDescend(@NotNull NewVirtualFileSystem fs,
                                          @NotNull NewVirtualFileSystem currentFS,
                                          @NotNull List<String> names,
                                          @Nullable NewVirtualFile fsRoot,
                                          @NotNull FilePartNode currentNode,
                                          @NotNull FilePartNode parentNode)