docs: static ResolveResult<? extends AbstractConfigValue> resolveSubstitutions(ReplaceableMergeStack replaceable,
              List<AbstractConfigValue> stack,
              ResolveContext context, ResolveSource source) throws NotPossibleToResolve {
          if (ConfigImpl.traceSubstitutionsEnabled()) {
              ConfigImpl.trace(context.depth(), "delayed merge stack has " + stack.size() + " items:");
              int count = 0;
              for (AbstractConfigValue v : stack) {
                  ConfigImpl.trace(context.depth() + 1, count + ": " + v);
                  count += 1;
              }
          }
  
          // to resolve substitutions, we need to recursively resolve
          // the stack of stuff to merge, and merge the stack so
          // we won't be a delayed merge anymore. If restrictToChildOrNull
          // is non-null, or resolve options allow partial resolves,
          // we may remain a delayed merge though.
  
          ResolveContext newContext = context;
          int count = 0;
          AbstractConfigValue merged = null;
          for (AbstractConfigValue end : stack) {
              // the end value may or may not be resolved already
  
              ResolveSource sourceForEnd;
  
              if (end instanceof ReplaceableMergeStack)
                  throw new ConfigException.BugOrBroken("A delayed merge should not contain another one: " + replaceable);
              else if (end instanceof Unmergeable) {
                  // the remainder could be any kind of value, including another
                  // ConfigDelayedMerge
                  AbstractConfigValue remainder = replaceable.makeReplacement(context, count + 1);
  
                  if (ConfigImpl.traceSubstitutionsEnabled())
                      ConfigImpl.trace(newContext.depth(), "remainder portion: " + remainder);
  
                  // If, while resolving 'end' we come back to the same
                  // merge stack, we only want to look _below_ 'end'
                  // in the stack. So we arrange to replace the
                  // ConfigDelayedMerge with a value that is only
                  // the remainder of the stack below this one.
  
                  if (ConfigImpl.traceSubstitutionsEnabled())
                      ConfigImpl.trace(newContext.depth(), "building sourceForEnd");
  
                  // we resetParents() here because we'll be resolving "end"
                  // against a root which does NOT contain "end"
                  sourceForEnd = source.replaceWithinCurrentParent((AbstractConfigValue) replaceable, remainder);
  
                  if (ConfigImpl.traceSubstitutionsEnabled())
                      ConfigImpl.trace(newContext.depth(), "  sourceForEnd before reset parents but after replace: "
                              + sourceForEnd);
  
                  sourceForEnd = sourceForEnd.resetParents();
              } else {
                  if (ConfigImpl.traceSubstitutionsEnabled())
                      ConfigImpl.trace(newContext.depth(),
                              "will resolve end against the original source with parent pushed");
  
                  sourceForEnd = source.pushParent(replaceable);
              }
  
              if (ConfigImpl.traceSubstitutionsEnabled()) {
                  ConfigImpl.trace(newContext.depth(), "sourceForEnd      =" + sourceForEnd);
              }
  
              if (ConfigImpl.traceSubstitutionsEnabled())
                  ConfigImpl.trace(newContext.depth(), "Resolving highest-priority item in delayed merge " + end
                          + " against " + sourceForEnd + " endWasRemoved=" + (source != sourceForEnd));
              ResolveResult<? extends AbstractConfigValue> result = newContext.resolve(end, sourceForEnd);
              AbstractConfigValue resolvedEnd = result.value;
              newContext = result.context;
  
              if (resolvedEnd != null) {
                  if (merged == null) {
                      merged = resolvedEnd;
                  } else {
                      if (ConfigImpl.traceSubstitutionsEnabled())
                          ConfigImpl.trace(newContext.depth() + 1, "merging " + merged + " with fallback " + resolvedEnd);
                      merged = merged.withFallback(resolvedEnd);
                  }
              }
  
              count += 1;
  
              if (ConfigImpl.traceSubstitutionsEnabled())
                  ConfigImpl.trace(newContext.depth(), "stack merged, yielding: " + merged);
          }
  
          return ResolveResult.make(newContext, merged);
      }