checkKeyInternal = (val, check) => {
  const checkIt = child => checkKey(child, check);

  const passStyle = passStyleOf(val);
  switch (passStyle) {
    case 'remotable': {
      // A remotable is a ScalarKey but not an Atom, so we pick it up here.
      return true;
    }
    case 'copyRecord': {
      // A copyRecord is a key iff all its children are keys
      return Object.values(val).every(checkIt);
    }
    case 'copyArray': {
      // A copyArray is a key iff all its children are keys
      return val.every(checkIt);
    }
    case 'tagged': {
      const tag = getTag(val);
      switch (tag) {
        case 'copySet': {
          return checkCopySet(val, check);
        }
        case 'copyBag': {
          return checkCopyBag(val, check);
        }
        case 'copyMap': {
          return (
            checkCopyMap(val, check) &&
            // For a copyMap to be a key, all its keys and values must
            // be keys. Keys already checked by `checkCopyMap` since
            // that's a copyMap requirement in general.
            everyCopyMapValue(val, checkIt)
          );
        }
        default: {
          return (
            check !== identChecker &&
            check(false, X`A passable tagged ${q(tag)} is not a key: ${val}`)
          );
        }
      }
    }
    case 'error':
    case 'promise': {
      return check(false, X`A ${q(passStyle)} cannot be a key`);
    }
    default: {
      // Unexpected tags are just non-keys, but an unexpected passStyle
      // is always an error.
      throw Fail`unexpected passStyle ${q(passStyle)}: ${val}`;
    }
  }
}
`checkKeyInternal` is only called if `val` is Passable but is not an Atom.

@param {any} val
@param {Checker} check
@returns {boolean}