function populateSubtree(that, quadKey, request) {
  const tileInfo = that._tileInfo;
  let q = quadKey;
  let t = tileInfo[q];
  // If we have tileInfo make sure sure it is not a node with a subtree that's not loaded
  if (defined(t) && (!t.hasSubtree() || t.hasChildren())) {
    return t;
  }

  while (t === undefined && q.length > 1) {
    q = q.substring(0, q.length - 1);
    t = tileInfo[q];
  }

  let subtreeRequest;
  const subtreePromises = that._subtreePromises;
  let promise = subtreePromises[q];
  if (defined(promise)) {
    return promise.then(function () {
      // Recursively call this in case we need multiple subtree requests
      subtreeRequest = new Request({
        throttle: request.throttle,
        throttleByServer: request.throttleByServer,
        type: request.type,
        priorityFunction: request.priorityFunction,
      });
      return populateSubtree(that, quadKey, subtreeRequest);
    });
  }

  // t is either
  //   null so one of its parents was a leaf node, so this tile doesn't exist
  //   exists but doesn't have a subtree to request
  //   undefined so no parent exists - this shouldn't ever happen once the provider is ready
  if (!defined(t) || !t.hasSubtree()) {
    return Promise.reject(
      new RuntimeError(`Couldn't load metadata for tile ${quadKey}`),
    );
  }

  // We need to split up the promise here because when will execute syncronously if getQuadTreePacket
  //  is already resolved (like in the tests), so subtreePromises will never get cleared out.
  //  Only the initial request will also remove the promise from subtreePromises.
  promise = that.getQuadTreePacket(q, t.cnodeVersion, request);
  if (!defined(promise)) {
    return undefined;
  }
  subtreePromises[q] = promise;

  return promise
    .then(function () {
      // Recursively call this in case we need multiple subtree requests
      subtreeRequest = new Request({
        throttle: request.throttle,
        throttleByServer: request.throttleByServer,
        type: request.type,
        priorityFunction: request.priorityFunction,
      });
      return populateSubtree(that, quadKey, subtreeRequest);
    })
    .finally(function () {
      delete subtreePromises[q];
    });
}
Populates the metadata subtree down to the specified tile.

@param {number} x The tile X coordinate.
@param {number} y The tile Y coordinate.
@param {number} level The tile level.
@param {Request} [request] The request object. Intended for internal use only.

@returns {Promise<GoogleEarthEnterpriseTileInformation>} A promise that resolves to the tile info for the requested quad key

@private