code: private JSType findObjectWithNonStringifiableKey(JSType type, Set<JSType> alreadyCheckedTypes) {
      if (alreadyCheckedTypes.contains(type)) {
        // This can happen in recursive types. Current type already being checked earlier in
        // stacktrace so now we just skip it.
        return null;
      } else {
        alreadyCheckedTypes.add(type);
      }
      if (isObjectTypeWithNonStringifiableKey(type)) {
        return type;
      }
      if (type.isUnionType()) {
        for (JSType alternateType : type.toMaybeUnionType().getAlternates()) {
          JSType result = findObjectWithNonStringifiableKey(alternateType, alreadyCheckedTypes);
          if (result != null) {
            return result;
          }
        }
      }
      if (type.isTemplatizedType()) {
        for (JSType templateType : type.toMaybeTemplatizedType().getTemplateTypes()) {
          JSType result = findObjectWithNonStringifiableKey(templateType, alreadyCheckedTypes);
          if (result != null) {
            return result;
          }
        }
      }
      if (type.isOrdinaryFunction()) {
        FunctionType function = type.toMaybeFunctionType();
        for (Node parameter : function.getParameters()) {
          JSType result =
              findObjectWithNonStringifiableKey(parameter.getJSType(), alreadyCheckedTypes);
          if (result != null) {
            return result;
          }
        }
        return findObjectWithNonStringifiableKey(function.getReturnType(), alreadyCheckedTypes);
      }
      return null;
    }
docs: Checks whether type (or one of its component if is composed type like union or templatized
  type) has Object with non-stringifiable key. For example {@code Object.<!Object, number>}.
  
  @return non-stringifiable type which is used as key or null if all there are no such types.